2 * Firebird ADO.NET Data provider for .NET and Mono
4 * The contents of this file are subject to the Initial
5 * Developer's Public License Version 1.0 (the "License");
6 * you may not use this file except in compliance with the
7 * License. You may obtain a copy of the License at
8 * http://www.firebirdsql.org/index.php?op=doc&id=idpl
10 * Software distributed under the License is distributed on
11 * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
12 * express or implied. See the License for the specific
13 * language governing rights and limitations under the License.
15 * Copyright (c) 2002, 2005 Carlos Guzman Alvarez
16 * All Rights Reserved.
20 using System.Collections;
21 using System.Globalization;
24 using System.Runtime.InteropServices;
27 using FirebirdSql.Data.Common;
29 namespace FirebirdSql.Data.Embedded
31 internal sealed class FesArray : ArrayBase
36 private FesDatabase db;
37 private FesTransaction transaction;
43 public override long Handle
45 get { return this.handle; }
46 set { this.handle = value; }
49 public override IDatabase DB
51 get { return this.db; }
52 set { this.db = (FesDatabase)value; }
55 public override ITransaction Transaction
57 get { return this.transaction; }
58 set { this.transaction = (FesTransaction)value; }
65 public FesArray(ArrayDesc descriptor) : base(descriptor)
71 ITransaction transaction,
73 string fieldName) : this(db, transaction, -1, tableName, fieldName)
79 ITransaction transaction,
82 string fieldName) : base(tableName, fieldName)
84 if (!(db is FesDatabase))
86 throw new ArgumentException("Specified argument is not of GdsDatabase type.");
88 if (!(transaction is FesTransaction))
90 throw new ArgumentException("Specified argument is not of GdsTransaction type.");
92 this.db = (FesDatabase)db;
93 this.transaction = (FesTransaction)transaction;
103 public override byte[] GetSlice(int sliceLength)
105 int[] statusVector = FesConnection.GetNewStatusVector();
107 int dbHandle = this.db.Handle;
108 int trHandle = this.transaction.Handle;
110 ArrayDescMarshaler marshaler = ArrayDescMarshaler.GetInstance();
112 IntPtr arrayDesc = marshaler.MarshalManagedToNative(this.Descriptor);
114 byte[] buffer = new byte[sliceLength];
116 FbClient.isc_array_get_slice(
126 marshaler.CleanUpNativeData(ref arrayDesc);
128 FesConnection.ParseStatusVector(statusVector);
133 public override void PutSlice(System.Array sourceArray, int sliceLength)
135 int[] statusVector = FesConnection.GetNewStatusVector();
137 int dbHandle = this.db.Handle;
138 int trHandle = this.transaction.Handle;
140 ArrayDescMarshaler marshaler = ArrayDescMarshaler.GetInstance();
142 IntPtr arrayDesc = marshaler.MarshalManagedToNative(this.Descriptor);
144 // Obtain the System of type of Array elements and
146 Type systemType = this.GetSystemType();
148 byte[] buffer = new byte[sliceLength];
149 if (systemType.IsPrimitive)
151 Buffer.BlockCopy(sourceArray, 0, buffer, 0, buffer.Length);
155 buffer = this.EncodeSlice(this.Descriptor, sourceArray, sliceLength);
158 FbClient.isc_array_put_slice(
168 marshaler.CleanUpNativeData(ref arrayDesc);
170 FesConnection.ParseStatusVector(statusVector);
175 #region Protected Methods
177 protected override System.Array DecodeSlice(byte[] slice)
179 Array sliceData = null;
180 int slicePosition = 0;
182 DbDataType dbType = DbDataType.Array;
183 Type systemType = this.GetSystemType();
184 Charset charset = this.db.Charset;
185 int[] lengths = new int[this.Descriptor.Dimensions];
186 int[] lowerBounds = new int[this.Descriptor.Dimensions];
188 // Get upper and lower bounds of each dimension
189 for (int i = 0; i < this.Descriptor.Dimensions; i++)
191 lowerBounds[i] = this.Descriptor.Bounds[i].LowerBound;
192 lengths[i] = this.Descriptor.Bounds[i].UpperBound;
194 if (lowerBounds[i] == 0)
200 // Create slice arrays
201 sliceData = Array.CreateInstance(systemType, lengths, lowerBounds);
203 Array tempData = Array.CreateInstance(systemType, sliceData.Length);
206 type = TypeHelper.GetFbType(this.Descriptor.DataType);
207 dbType = TypeHelper.GetDbDataType(this.Descriptor.DataType, 0, this.Descriptor.Scale);
209 int itemLength = this.Descriptor.Length;
211 for (int i = 0; i < tempData.Length; i++)
213 if (slicePosition >= slice.Length)
220 case DbDataType.Char:
221 tempData.SetValue(charset.GetString(slice, slicePosition, itemLength), i);
224 case DbDataType.VarChar:
226 int index = slicePosition;
228 while (slice[index++] != 0)
232 tempData.SetValue(charset.GetString(slice, slicePosition, count), i);
238 case DbDataType.SmallInt:
239 tempData.SetValue(BitConverter.ToInt16(slice, slicePosition), i);
242 case DbDataType.Integer:
243 tempData.SetValue(BitConverter.ToInt32(slice, slicePosition), i);
246 case DbDataType.BigInt:
247 tempData.SetValue(BitConverter.ToInt64(slice, slicePosition), i);
250 case DbDataType.Decimal:
251 case DbDataType.Numeric:
253 object evalue = null;
257 case IscCodes.SQL_SHORT:
258 evalue = BitConverter.ToInt16(slice, slicePosition);
261 case IscCodes.SQL_LONG:
262 evalue = BitConverter.ToInt32(slice, slicePosition);
265 case IscCodes.SQL_QUAD:
266 case IscCodes.SQL_INT64:
267 evalue = BitConverter.ToInt64(slice, slicePosition);
271 decimal dvalue = TypeDecoder.DecodeDecimal(evalue, this.Descriptor.Scale, type);
273 tempData.SetValue(dvalue, i);
277 case DbDataType.Double:
278 tempData.SetValue(BitConverter.ToDouble(slice, slicePosition), i);
281 case DbDataType.Float:
282 tempData.SetValue(BitConverter.ToSingle(slice, slicePosition), i);
285 case DbDataType.Date:
287 int idate = BitConverter.ToInt32(slice, slicePosition);
289 DateTime date = TypeDecoder.DecodeDate(idate);
291 tempData.SetValue(date, i);
295 case DbDataType.Time:
297 int itime = BitConverter.ToInt32(slice, slicePosition);
299 DateTime time = TypeDecoder.DecodeTime(itime);
301 tempData.SetValue(time, i);
305 case DbDataType.TimeStamp:
307 int idate = BitConverter.ToInt32(slice, slicePosition);
308 int itime = BitConverter.ToInt32(slice, slicePosition + 4);
310 DateTime date = TypeDecoder.DecodeDate(idate);
311 DateTime time = TypeDecoder.DecodeTime(itime);
313 DateTime timestamp = new System.DateTime(
314 date.Year, date.Month, date.Day,
315 time.Hour,time.Minute, time.Second, time.Millisecond);
317 tempData.SetValue(timestamp, i);
322 slicePosition += itemLength;
325 if (systemType.IsPrimitive)
327 // For primitive types we can use System.Buffer to copy generated data to destination array
328 Buffer.BlockCopy(tempData, 0, sliceData, 0, Buffer.ByteLength(tempData));
332 sliceData = tempData;
340 #region Private Metods
342 private byte[] EncodeSlice(ArrayDesc desc, Array sourceArray, int length)
344 BinaryWriter writer = new BinaryWriter(new MemoryStream());
345 IEnumerator i = sourceArray.GetEnumerator();
346 Charset charset = this.db.Charset;
347 DbDataType dbType = DbDataType.Array;
349 int subtype = (this.Descriptor.Scale < 0) ? 2 : 0;
352 type = TypeHelper.GetFbType(this.Descriptor.DataType);
353 dbType = TypeHelper.GetDbDataType(this.Descriptor.DataType, subtype, this.Descriptor.Scale);
359 case DbDataType.Char:
361 string value = i.Current != null ? (string)i.Current : String.Empty;
362 byte[] buffer = charset.GetBytes(value);
364 writer.Write(buffer);
366 if (desc.Length > buffer.Length)
368 for (int j = buffer.Length; j < desc.Length; j++)
370 writer.Write((byte)32);
376 case DbDataType.VarChar:
378 string value = i.Current != null ? (string)i.Current : String.Empty;
380 value = value.TrimEnd();
382 byte[] buffer = charset.GetBytes(value);
383 writer.Write(buffer);
385 if (desc.Length > buffer.Length)
387 for (int j = buffer.Length; j < desc.Length; j++)
389 writer.Write((byte)0);
392 writer.Write((short)0);
396 case DbDataType.SmallInt:
397 writer.Write((short)i.Current);
400 case DbDataType.Integer:
401 writer.Write((int)i.Current);
404 case DbDataType.BigInt:
405 writer.Write((long)i.Current);
408 case DbDataType.Float:
409 writer.Write((float)i.Current);
412 case DbDataType.Double:
413 writer.Write((double)i.Current);
416 case DbDataType.Numeric:
417 case DbDataType.Decimal:
419 object numeric = TypeEncoder.EncodeDecimal((decimal)i.Current, desc.Scale, type);
423 case IscCodes.SQL_SHORT:
424 writer.Write((short)numeric);
427 case IscCodes.SQL_LONG:
428 writer.Write((int)numeric);
431 case IscCodes.SQL_QUAD:
432 case IscCodes.SQL_INT64:
433 writer.Write((long)numeric);
439 case DbDataType.Date:
440 writer.Write(TypeEncoder.EncodeDate(Convert.ToDateTime(i.Current, CultureInfo.CurrentCulture.DateTimeFormat)));
443 case DbDataType.Time:
444 writer.Write(TypeEncoder.EncodeTime(Convert.ToDateTime(i.Current, CultureInfo.CurrentCulture.DateTimeFormat)));
447 case DbDataType.TimeStamp:
448 writer.Write(TypeEncoder.EncodeDate(Convert.ToDateTime(i.Current, CultureInfo.CurrentCulture.DateTimeFormat)));
449 writer.Write(TypeEncoder.EncodeTime(Convert.ToDateTime(i.Current, CultureInfo.CurrentCulture.DateTimeFormat)));
453 throw new NotSupportedException("Unknown data type");
457 return ((MemoryStream)writer.BaseStream).ToArray();