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.
21 using System.Globalization;
23 namespace FirebirdSql.Data.Common
25 internal abstract class ArrayBase
29 private ArrayDesc descriptor;
30 private string tableName;
31 private string fieldName;
32 private string rdbFieldName;
38 public ArrayDesc Descriptor
40 get { return this.descriptor; }
45 #region Abstract Properties
47 public abstract long Handle
53 public abstract IDatabase DB
59 public abstract ITransaction Transaction
69 protected ArrayBase(ArrayDesc descriptor)
71 this.tableName = descriptor.RelationName;
72 this.fieldName = descriptor.FieldName;
73 this.descriptor = descriptor;
76 protected ArrayBase(string tableName, string fieldName)
78 this.tableName = tableName;
79 this.fieldName = fieldName;
80 this.rdbFieldName = String.Empty;
85 #region Abstract Methods
87 public abstract byte[] GetSlice(int slice_length);
88 public abstract void PutSlice(System.Array source_array, int slice_length);
92 #region Protected Abstract Methods
94 protected abstract System.Array DecodeSlice(byte[] slice);
102 byte[] slice = this.GetSlice(this.GetSliceLength(true));
104 return this.DecodeSlice(slice);
107 public void Write(System.Array sourceArray)
109 this.SetDesc(sourceArray);
110 this.PutSlice(sourceArray, this.GetSliceLength(false));
113 public void SetDesc(System.Array sourceArray)
115 this.descriptor.Dimensions = (short)sourceArray.Rank;
117 for (int i = 0; i < sourceArray.Rank; i++)
119 int lb = this.descriptor.Bounds[i].LowerBound;
120 int ub = sourceArray.GetLength(i) - 1 + lb;
122 this.descriptor.Bounds[i].UpperBound = ub;
126 public void LookupBounds()
130 StatementBase lookup = this.DB.CreateStatement(this.Transaction);
132 lookup.Prepare(this.GetArrayBounds());
136 this.descriptor.Bounds = new ArrayBound[16];
139 while ((values = lookup.Fetch()) != null)
141 this.descriptor.Bounds[i].LowerBound = values[0].GetInt32();
142 this.descriptor.Bounds[i].UpperBound = values[1].GetInt32();
151 public void LookupDesc()
153 // Initializa array descriptor information
154 this.descriptor = new ArrayDesc();
156 // Create statement for retrieve information
157 StatementBase lookup = this.DB.CreateStatement(this.Transaction);
159 lookup.Prepare(this.GetArrayDesc());
162 DbValue[] values = lookup.Fetch();
163 if (values != null && values.Length > 0)
165 this.descriptor.RelationName = tableName;
166 this.descriptor.FieldName = fieldName;
167 this.descriptor.DataType = values[0].GetByte();
168 this.descriptor.Scale = values[1].GetInt16();
169 this.descriptor.Length = values[2].GetInt16();
170 this.descriptor.Dimensions = values[3].GetInt16();
171 this.descriptor.Flags = 0;
173 this.rdbFieldName = values[4].GetString().Trim();
177 throw new InvalidOperationException();
186 #region Protected Methods
188 protected int GetSliceLength(bool read)
193 for (int i = 0; i < this.descriptor.Dimensions; i++)
195 ArrayBound bound = this.descriptor.Bounds[i];
197 elements += (bound.UpperBound - bound.LowerBound) + 1;
200 length = elements * this.descriptor.Length;
202 switch (this.descriptor.DataType)
204 case IscCodes.blr_varying:
205 case IscCodes.blr_varying2:
206 length += elements * 2;
213 protected Type GetSystemType()
217 switch (this.descriptor.DataType)
219 case IscCodes.blr_text:
220 case IscCodes.blr_text2:
221 case IscCodes.blr_cstring:
222 case IscCodes.blr_cstring2:
224 systemType = typeof(System.String);
227 case IscCodes.blr_varying:
228 case IscCodes.blr_varying2:
230 systemType = typeof(System.String);
233 case IscCodes.blr_short:
235 if (this.descriptor.Scale < 0)
237 systemType = typeof(System.Decimal);
241 systemType = typeof(System.Int16);
245 case IscCodes.blr_long:
247 if (this.descriptor.Scale < 0)
249 systemType = typeof(System.Decimal);
253 systemType = typeof(System.Int32);
257 case IscCodes.blr_float:
259 systemType = typeof(System.Single);
262 case IscCodes.blr_double:
263 case IscCodes.blr_d_float:
265 systemType = typeof(System.Double);
268 case IscCodes.blr_quad:
269 case IscCodes.blr_int64:
271 if (this.descriptor.Scale < 0)
273 systemType = typeof(System.Decimal);
277 systemType = typeof(System.Int64);
281 case IscCodes.blr_timestamp:
283 systemType = typeof(System.DateTime);
286 case IscCodes.blr_sql_time:
288 systemType = typeof(System.DateTime);
291 case IscCodes.blr_sql_date:
293 systemType = typeof(System.DateTime);
297 throw new NotSupportedException("Unknown data type");
305 #region Private Methods
307 private string GetArrayDesc()
309 StringBuilder sql = new StringBuilder();
312 "SELECT Y.RDB$FIELD_TYPE, Y.RDB$FIELD_SCALE, Y.RDB$FIELD_LENGTH, Y.RDB$DIMENSIONS, X.RDB$FIELD_SOURCE " +
313 "FROM RDB$RELATION_FIELDS X, RDB$FIELDS Y " +
314 "WHERE X.RDB$FIELD_SOURCE = Y.RDB$FIELD_NAME ");
316 if (this.tableName != null && this.tableName.Length != 0)
319 CultureInfo.CurrentUICulture, " AND X.RDB$RELATION_NAME = '{0}'", tableName);
322 if (this.fieldName != null && this.fieldName.Length != 0)
325 CultureInfo.CurrentUICulture, " AND X.RDB$FIELD_NAME = '{0}'", fieldName);
328 return sql.ToString();
331 private string GetArrayBounds()
333 StringBuilder sql = new StringBuilder();
335 sql.Append("SELECT X.RDB$LOWER_BOUND, X.RDB$UPPER_BOUND FROM RDB$FIELD_DIMENSIONS X ");
337 if (this.fieldName != null && this.fieldName.Length != 0)
340 CultureInfo.CurrentUICulture, "WHERE X.RDB$FIELD_NAME = '{0}'", rdbFieldName);
343 sql.Append(" ORDER BY X.RDB$DIMENSION");
345 return sql.ToString();