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();