2 // System.Data.SqlClient.SqlDataReader.cs
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Daniel Morgan (danmorg@sc.rr.com)
7 // Tim Coleman (tim@timcoleman.com)
9 // (C) Ximian, Inc 2002
10 // (C) Daniel Morgan 2002
11 // Copyright (C) Tim Coleman, 2002
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using Mono.Data.Tds.Protocol;
41 using System.Collections;
42 using System.ComponentModel;
44 using System.Data.Common;
45 using System.Data.SqlTypes;
46 using System.Globalization;
49 namespace System.Data.SqlClient
52 public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
54 public sealed class SqlDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
65 DataTable schemaTable;
70 int visibleFieldCount;
75 const int COLUMN_NAME_IDX = 0;
76 const int COLUMN_ORDINAL_IDX = 1;
77 const int COLUMN_SIZE_IDX = 2;
78 const int NUMERIC_PRECISION_IDX = 3;
79 const int NUMERIC_SCALE_IDX = 4;
80 const int IS_UNIQUE_IDX = 5;
81 const int IS_KEY_IDX = 6;
82 const int BASE_SERVER_NAME_IDX = 7;
83 const int BASE_CATALOG_NAME_IDX = 8;
84 const int BASE_COLUMN_NAME_IDX = 9;
85 const int BASE_SCHEMA_NAME_IDX = 10;
86 const int BASE_TABLE_NAME_IDX = 11;
87 const int DATA_TYPE_IDX = 12;
88 const int ALLOW_DBNULL_IDX = 13;
89 const int PROVIDER_TYPE_IDX = 14;
90 const int IS_ALIASED_IDX = 15;
91 const int IS_EXPRESSION_IDX = 16;
92 const int IS_IDENTITY_IDX = 17;
93 const int IS_AUTO_INCREMENT_IDX = 18;
94 const int IS_ROW_VERSION_IDX = 19;
95 const int IS_HIDDEN_IDX = 20;
96 const int IS_LONG_IDX = 21;
97 const int IS_READ_ONLY_IDX = 22;
98 const int PROVIDER_SPECIFIC_TYPE_IDX = 23;
99 const int DATA_TYPE_NAME_IDX = 24;
100 const int XML_SCHEMA_COLLCTN_DB_IDX = 25;
101 const int XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX = 26;
102 const int XML_SCHEMA_COLLCTN_NAME_IDX = 27;
103 const int UDT_ASMBLY_QUALIFIED_NAME_IDX = 28;
104 const int NON_VER_PROVIDER_TYPE_IDX = 29;
105 const int IS_COLUMN_SET = 30;
109 internal SqlDataReader (SqlCommand command)
111 this.command = command;
112 command.Tds.RecordsAffected = -1;
116 #endregion // Constructors
135 return command.Tds.Columns.Count;
144 get { return isClosed; }
151 object this [int i] {
152 get { return GetValue (i); }
159 object this [string name] {
160 get { return GetValue (GetOrdinal (name)); }
167 int RecordsAffected {
169 return command.Tds.RecordsAffected;
184 readResult = ReadRecord ();
189 public override int VisibleFieldCount {
190 get { return visibleFieldCount; }
193 protected SqlConnection Connection {
194 get { return command.Connection; }
197 protected bool IsCommandBehavior (CommandBehavior condition) {
198 return condition == command.CommandBehavior;
202 #endregion // Properties
214 // skip to end & read output parameters.
215 while (NextResult ())
218 command.CloseDataReader ();
221 private static DataTable ConstructSchemaTable ()
223 Type booleanType = typeof (bool);
224 Type stringType = typeof (string);
225 Type intType = typeof (int);
227 Type typeType = typeof (Type);
229 Type shortType = typeof (short);
231 DataTable schemaTable = new DataTable ("SchemaTable");
232 schemaTable.Columns.Add ("ColumnName", stringType);
233 schemaTable.Columns.Add ("ColumnOrdinal", intType);
234 schemaTable.Columns.Add ("ColumnSize", intType);
235 schemaTable.Columns.Add ("NumericPrecision", shortType);
236 schemaTable.Columns.Add ("NumericScale", shortType);
237 schemaTable.Columns.Add ("IsUnique", booleanType);
238 schemaTable.Columns.Add ("IsKey", booleanType);
239 schemaTable.Columns.Add ("BaseServerName", stringType);
240 schemaTable.Columns.Add ("BaseCatalogName", stringType);
241 schemaTable.Columns.Add ("BaseColumnName", stringType);
242 schemaTable.Columns.Add ("BaseSchemaName", stringType);
243 schemaTable.Columns.Add ("BaseTableName", stringType);
245 schemaTable.Columns.Add ("DataType", typeType);
247 schemaTable.Columns.Add ("DataType", typeof (object));
249 schemaTable.Columns.Add ("AllowDBNull", booleanType);
250 schemaTable.Columns.Add ("ProviderType", intType);
251 schemaTable.Columns.Add ("IsAliased", booleanType);
252 schemaTable.Columns.Add ("IsExpression", booleanType);
253 schemaTable.Columns.Add ("IsIdentity", booleanType);
254 schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
255 schemaTable.Columns.Add ("IsRowVersion", booleanType);
256 schemaTable.Columns.Add ("IsHidden", booleanType);
257 schemaTable.Columns.Add ("IsLong", booleanType);
258 schemaTable.Columns.Add ("IsReadOnly", booleanType);
260 schemaTable.Columns.Add ("ProviderSpecificDataType", typeType);
261 schemaTable.Columns.Add ("DataTypeName", stringType);
262 schemaTable.Columns.Add ("XmlSchemaCollectionDatabase", stringType);
263 schemaTable.Columns.Add ("XmlSchemaCollectionOwningSchema", stringType);
264 schemaTable.Columns.Add ("XmlSchemaCollectionName", stringType);
265 schemaTable.Columns.Add ("UdtAssemblyQualifiedName", stringType);
266 schemaTable.Columns.Add ("NonVersionedProviderType", intType);
267 schemaTable.Columns.Add ("IsColumnSet", booleanType);
273 private string GetSchemaRowTypeName (TdsColumnType ctype, int csize, short precision, short scale)
280 GetSchemaRowType (ctype, csize, precision, scale,
281 out dbType, out fieldType, out isLong,
286 private Type GetSchemaRowFieldType (TdsColumnType ctype, int csize, short precision, short scale)
293 GetSchemaRowType (ctype, csize, precision, scale,
294 out dbType, out fieldType, out isLong,
299 SqlDbType GetSchemaRowDbType (int ordinal)
302 short precision, scale;
304 TdsDataColumn column;
306 if (ordinal < 0 || ordinal >= command.Tds.Columns.Count)
307 throw new IndexOutOfRangeException ();
309 column = command.Tds.Columns [ordinal];
311 ctype = (TdsColumnType) column.ColumnType;
312 csize = (int) column.ColumnSize;
313 precision = (short) (column.NumericPrecision ?? 0);
314 scale = (short) (column.NumericScale ?? 0);
316 ctype = (TdsColumnType) column ["ColumnType"];
317 csize = (int) column ["ColumnSize"];
318 precision = (short) ((byte) column ["NumericPrecision"]);
319 scale = (short) ((byte) column ["NumericScale"]);
321 return GetSchemaRowDbType (ctype, csize, precision, scale);
324 private SqlDbType GetSchemaRowDbType (TdsColumnType ctype, int csize, short precision, short scale)
331 GetSchemaRowType (ctype, csize, precision, scale,
332 out dbType, out fieldType, out isLong,
334 return (SqlDbType) dbType;
337 private void GetSchemaRowType (TdsColumnType ctype, int csize,
338 short precision, short scale,
339 out int dbType, out Type fieldType,
340 out bool isLong, out string typeName)
343 typeName = string.Empty;
345 fieldType = typeof (Type);
348 case TdsColumnType.Int1:
349 case TdsColumnType.Int2:
350 case TdsColumnType.Int4:
351 case TdsColumnType.IntN:
352 case TdsColumnType.BigInt:
355 typeName = "tinyint";
356 dbType = (int) SqlDbType.TinyInt;
357 fieldType = typeof (byte);
361 typeName = "smallint";
362 dbType = (int) SqlDbType.SmallInt;
363 fieldType = typeof (short);
368 dbType = (int) SqlDbType.Int;
369 fieldType = typeof (int);
374 dbType = (int) SqlDbType.BigInt;
375 fieldType = typeof (long);
380 case TdsColumnType.Real:
381 case TdsColumnType.Float8:
382 case TdsColumnType.FloatN:
386 dbType = (int) SqlDbType.Real;
387 fieldType = typeof (float);
392 dbType = (int) SqlDbType.Float;
393 fieldType = typeof (double);
398 case TdsColumnType.Image :
400 dbType = (int) SqlDbType.Image;
401 fieldType = typeof (byte[]);
404 case TdsColumnType.Text :
406 dbType = (int) SqlDbType.Text;
407 fieldType = typeof (string);
410 case TdsColumnType.UniqueIdentifier :
411 typeName = "uniqueidentifier";
412 dbType = (int) SqlDbType.UniqueIdentifier;
413 fieldType = typeof (Guid);
416 case TdsColumnType.VarBinary :
417 case TdsColumnType.BigVarBinary :
418 typeName = "varbinary";
419 dbType = (int) SqlDbType.VarBinary;
420 fieldType = typeof (byte[]);
423 case TdsColumnType.VarChar :
424 case TdsColumnType.BigVarChar :
425 typeName = "varchar";
426 dbType = (int) SqlDbType.VarChar;
427 fieldType = typeof (string);
430 case TdsColumnType.Binary :
431 case TdsColumnType.BigBinary :
433 dbType = (int) SqlDbType.Binary;
434 fieldType = typeof (byte[]);
437 case TdsColumnType.Char :
438 case TdsColumnType.BigChar :
440 dbType = (int) SqlDbType.Char;
441 fieldType = typeof (string);
444 case TdsColumnType.Bit :
445 case TdsColumnType.BitN :
447 dbType = (int) SqlDbType.Bit;
448 fieldType = typeof (bool);
451 case TdsColumnType.DateTime4 :
452 case TdsColumnType.DateTime :
453 case TdsColumnType.DateTimeN :
456 typeName = "smalldatetime";
457 dbType = (int) SqlDbType.SmallDateTime;
458 fieldType = typeof (DateTime);
462 typeName = "datetime";
463 dbType = (int) SqlDbType.DateTime;
464 fieldType = typeof (DateTime);
469 case TdsColumnType.Money :
470 case TdsColumnType.MoneyN :
471 case TdsColumnType.Money4 :
474 typeName = "smallmoney";
475 dbType = (int) SqlDbType.SmallMoney;
476 fieldType = typeof (decimal);
481 dbType = (int) SqlDbType.Money;
482 fieldType = typeof (decimal);
487 case TdsColumnType.NText :
489 dbType = (int) SqlDbType.NText;
490 fieldType = typeof (string);
493 case TdsColumnType.NVarChar :
494 typeName = "nvarchar";
495 dbType = (int) SqlDbType.NVarChar;
496 fieldType = typeof (string);
499 case TdsColumnType.Decimal :
500 case TdsColumnType.Numeric :
501 // TDS 7.0 returns bigint as decimal(19,0)
502 if (precision == 19 && scale == 0) {
504 dbType = (int) SqlDbType.BigInt;
505 fieldType = typeof (long);
507 typeName = "decimal";
508 dbType = (int) SqlDbType.Decimal;
509 fieldType = typeof (decimal);
513 case TdsColumnType.NChar :
515 dbType = (int) SqlDbType.NChar;
516 fieldType = typeof (string);
519 case TdsColumnType.SmallMoney :
520 typeName = "smallmoney";
521 dbType = (int) SqlDbType.SmallMoney;
522 fieldType = typeof (decimal);
526 typeName = "variant";
527 dbType = (int) SqlDbType.Variant;
528 fieldType = typeof (object);
537 void Dispose (bool disposing)
541 if (schemaTable != null)
542 schemaTable.Dispose ();
554 bool GetBoolean (int i)
556 object value = GetValue (i);
557 if (!(value is bool)) {
558 if (value is DBNull) throw new SqlNullValueException ();
559 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
570 object value = GetValue (i);
571 if (!(value is byte)) {
572 if (value is DBNull) throw new SqlNullValueException ();
573 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
582 long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
584 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
586 EnsureDataAvailable ();
589 long len = ((Tds)command.Tds).GetSequentialColumnValue (i, dataIndex, buffer, bufferIndex, length);
591 throw CreateGetBytesOnInvalidColumnTypeException (i);
594 throw new SqlNullValueException ();
599 } catch (TdsInternalException ex) {
600 command.Connection.Close ();
601 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
605 object value = GetValue (i);
606 if (!(value is byte [])) {
607 SqlDbType type = GetSchemaRowDbType (i);
609 case SqlDbType.Image:
611 throw new SqlNullValueException ();
615 string text = value as string;
617 value = Encoding.Default.GetBytes (text);
622 throw new InvalidCastException ();
624 case SqlDbType.NText:
626 string ntext = value as string;
628 value = Encoding.Unicode.GetBytes (ntext);
633 throw new InvalidCastException ();
636 throw CreateGetBytesOnInvalidColumnTypeException (i);
641 return ((byte []) value).Length; // Return length of data
643 // Copy data into buffer
644 int availLen = (int) ( ( (byte []) value).Length - dataIndex);
645 if (availLen < length)
650 Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
651 return length; // return actual read count
654 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
661 throw new NotSupportedException ();
668 long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
670 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
672 EnsureDataAvailable ();
674 if (i < 0 || i >= command.Tds.Columns.Count)
675 throw new IndexOutOfRangeException ();
677 Encoding encoding = null;
679 TdsColumnType colType = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
681 case TdsColumnType.Text :
682 case TdsColumnType.VarChar:
683 case TdsColumnType.Char:
684 case TdsColumnType.BigVarChar:
685 encoding = Encoding.ASCII;
687 case TdsColumnType.NText :
688 case TdsColumnType.NVarChar:
689 case TdsColumnType.NChar:
690 encoding = Encoding.Unicode;
698 if (buffer == null) {
699 count = GetBytes (i,0,(byte[]) null,0,0);
704 byte[] arr = new byte [length];
705 count = GetBytes (i, dataIndex, arr, 0, length);
707 throw new InvalidCastException ("Specified cast is not valid");
709 Char[] val = encoding.GetChars (arr, 0, (int)count);
710 val.CopyTo (buffer, bufferIndex);
715 object value = GetValue (i);
718 valueBuffer = (char[])value;
719 else if (value is string)
720 valueBuffer = ((string)value).ToCharArray();
722 if (value is DBNull) throw new SqlNullValueException ();
723 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
726 if ( buffer == null ) {
727 // Return length of data
728 return valueBuffer.Length;
731 // Copy data into buffer
732 Array.Copy (valueBuffer, (int) dataIndex, buffer, bufferIndex, length);
733 return valueBuffer.Length - dataIndex;
738 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
739 public new IDataReader GetData (int i)
741 return ((IDataReader) this [i]);
749 string GetDataTypeName (int i)
751 TdsDataColumn column;
759 if (i < 0 || i >= command.Tds.Columns.Count)
760 throw new IndexOutOfRangeException ();
762 column = command.Tds.Columns [i];
764 ctype = (TdsColumnType) column.ColumnType;
765 csize = (int) column.ColumnSize;
766 precision = (short) (column.NumericPrecision ?? 0);
767 scale = (short) (column.NumericScale ?? 0);
769 ctype = (TdsColumnType) column ["ColumnType"];
770 csize = (int) column ["ColumnSize"];
771 precision = (short) ((byte) column ["NumericPrecision"]);
772 scale = (short) ((byte) column ["NumericScale"]);
774 return GetSchemaRowTypeName (ctype, csize, precision, scale);
781 DateTime GetDateTime (int i)
783 object value = GetValue (i);
784 if (!(value is DateTime)) {
785 if (value is DBNull) throw new SqlNullValueException ();
786 else throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
788 return (DateTime) value;
795 decimal GetDecimal (int i)
797 object value = GetValue (i);
798 if (!(value is decimal)) {
799 if (value is DBNull) throw new SqlNullValueException ();
800 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
802 return (decimal) value;
809 double GetDouble (int i)
811 object value = GetValue (i);
812 if (!(value is double)) {
813 if (value is DBNull) throw new SqlNullValueException ();
814 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
816 return (double) value;
823 Type GetFieldType (int i)
825 TdsDataColumn column;
833 if (i < 0 || i >= command.Tds.Columns.Count)
834 throw new IndexOutOfRangeException ();
836 column = command.Tds.Columns [i];
838 ctype = (TdsColumnType) column.ColumnType;
839 csize = (int) column.ColumnSize;
840 precision = (short) (column.NumericPrecision ?? 0);
841 scale = (short) (column.NumericScale ?? 0);
843 ctype = (TdsColumnType) column ["ColumnType"];
844 csize = (int) column ["ColumnSize"];
845 precision = (short) ((byte) column ["NumericPrecision"]);
846 scale = (short) ((byte) column ["NumericScale"]);
848 return GetSchemaRowFieldType (ctype, csize, precision,
856 float GetFloat (int i)
858 object value = GetValue (i);
859 if (!(value is float)) {
860 if (value is DBNull) throw new SqlNullValueException ();
861 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
863 return (float) value;
872 object value = GetValue (i);
873 if (!(value is Guid)) {
874 if (value is DBNull) throw new SqlNullValueException ();
875 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
884 short GetInt16 (int i)
886 object value = GetValue (i);
887 if (!(value is short)) {
888 if (value is DBNull) throw new SqlNullValueException ();
889 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
891 return (short) value;
900 object value = GetValue (i);
901 if (!(value is int)) {
902 if (value is DBNull) throw new SqlNullValueException ();
903 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
912 long GetInt64 (int i)
914 object value = GetValue (i);
915 if (!(value is long)) {
916 if (value is DBNull) throw new SqlNullValueException ();
917 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
926 string GetName (int i)
930 if (i < 0 || i >= command.Tds.Columns.Count)
931 throw new IndexOutOfRangeException ();
933 return (string) command.Tds.Columns[i].ColumnName;
935 return (string) command.Tds.Columns[i]["ColumnName"];
943 int GetOrdinal (string name)
948 throw new ArgumentNullException ("fieldName");
951 foreach (TdsDataColumn schema in command.Tds.Columns) {
953 colName = schema.ColumnName;
954 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
955 return (int) schema.ColumnOrdinal;
957 colName = (string) schema["ColumnName"];
958 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
959 return (int) schema["ColumnOrdinal"];
962 throw new IndexOutOfRangeException ();
969 DataTable GetSchemaTable ()
973 if (schemaTable == null)
974 schemaTable = ConstructSchemaTable ();
976 if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
982 foreach (TdsDataColumn schema in command.Tds.Columns) {
983 DataRow row = schemaTable.NewRow ();
986 row [COLUMN_NAME_IDX] = GetSchemaValue (schema.ColumnName);
987 row [COLUMN_ORDINAL_IDX] = GetSchemaValue (schema.ColumnOrdinal);
988 row [IS_UNIQUE_IDX] = GetSchemaValue (schema.IsUnique);
989 row [IS_AUTO_INCREMENT_IDX] = GetSchemaValue (schema.IsAutoIncrement);
990 row [IS_ROW_VERSION_IDX] = GetSchemaValue (schema.IsRowVersion);
991 row [IS_HIDDEN_IDX] = GetSchemaValue (schema.IsHidden);
992 row [IS_IDENTITY_IDX] = GetSchemaValue (schema.IsIdentity);
993 row [NUMERIC_PRECISION_IDX] = GetSchemaValue (schema.NumericPrecision);
994 row [IS_KEY_IDX] = GetSchemaValue (schema.IsKey);
995 row [IS_ALIASED_IDX] = GetSchemaValue (schema.IsAliased);
996 row [IS_EXPRESSION_IDX] = GetSchemaValue (schema.IsExpression);
997 row [IS_READ_ONLY_IDX] = GetSchemaValue (schema.IsReadOnly);
998 row [BASE_SERVER_NAME_IDX] = GetSchemaValue (schema.BaseServerName);
999 row [BASE_CATALOG_NAME_IDX] = GetSchemaValue (schema.BaseCatalogName);
1000 row [BASE_COLUMN_NAME_IDX] = GetSchemaValue (schema.BaseColumnName);
1001 row [BASE_SCHEMA_NAME_IDX] = GetSchemaValue (schema.BaseSchemaName);
1002 row [BASE_TABLE_NAME_IDX] = GetSchemaValue (schema.BaseTableName);
1003 row [ALLOW_DBNULL_IDX] = GetSchemaValue (schema.AllowDBNull);
1004 row [PROVIDER_SPECIFIC_TYPE_IDX] = DBNull.Value;
1005 row [DATA_TYPE_NAME_IDX] = GetSchemaValue (schema.DataTypeName);
1006 row [XML_SCHEMA_COLLCTN_DB_IDX] = DBNull.Value;
1007 row [XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX] = DBNull.Value;
1008 row [XML_SCHEMA_COLLCTN_NAME_IDX] = DBNull.Value;
1009 row [UDT_ASMBLY_QUALIFIED_NAME_IDX] = DBNull.Value;
1010 row [NON_VER_PROVIDER_TYPE_IDX] = DBNull.Value;
1011 row [IS_COLUMN_SET] = DBNull.Value;
1013 row [COLUMN_NAME_IDX] = GetSchemaValue (schema, "ColumnName");
1014 row [COLUMN_ORDINAL_IDX] = GetSchemaValue (schema, "ColumnOrdinal");
1015 row [IS_UNIQUE_IDX] = GetSchemaValue (schema, "IsUnique");
1016 row [IS_AUTO_INCREMENT_IDX] = GetSchemaValue (schema, "IsAutoIncrement");
1017 row [IS_ROW_VERSION_IDX] = GetSchemaValue (schema, "IsRowVersion");
1018 row [IS_HIDDEN_IDX] = GetSchemaValue (schema, "IsHidden");
1019 row [IS_IDENTITY_IDX] = GetSchemaValue (schema, "IsIdentity");
1020 row [IS_KEY_IDX] = GetSchemaValue (schema, "IsKey");
1021 row [IS_ALIASED_IDX] = GetSchemaValue (schema, "IsAliased");
1022 row [IS_EXPRESSION_IDX] = GetSchemaValue (schema, "IsExpression");
1023 row [IS_READ_ONLY_IDX] = GetSchemaValue (schema, "IsReadOnly");
1024 row [BASE_SERVER_NAME_IDX] = GetSchemaValue (schema, "BaseServerName");
1025 row [BASE_CATALOG_NAME_IDX] = GetSchemaValue (schema, "BaseCatalogName");
1026 row [BASE_COLUMN_NAME_IDX] = GetSchemaValue (schema, "BaseColumnName");
1027 row [BASE_SCHEMA_NAME_IDX] = GetSchemaValue (schema, "BaseSchemaName");
1028 row [BASE_TABLE_NAME_IDX] = GetSchemaValue (schema, "BaseTableName");
1029 row [ALLOW_DBNULL_IDX] = GetSchemaValue (schema, "AllowDBNull");
1031 // We don't always get the base column name.
1032 if (row [BASE_COLUMN_NAME_IDX] == DBNull.Value)
1033 row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
1035 TdsColumnType ctype;
1043 ctype = (TdsColumnType) schema.ColumnType;
1044 csize = (int) schema.ColumnSize;
1045 precision = (short) GetSchemaValue (schema.NumericPrecision);
1046 scale = (short) GetSchemaValue (schema.NumericScale);
1048 ctype = (TdsColumnType) schema ["ColumnType"];
1049 csize = (int) schema ["ColumnSize"];
1050 precision = (short) ((byte) GetSchemaValue (schema, "NumericPrecision"));
1051 scale = (short) ((byte) GetSchemaValue (schema, "NumericScale"));
1054 GetSchemaRowType (ctype, csize, precision, scale,
1055 out dbType, out fieldType, out isLong,
1058 row [COLUMN_SIZE_IDX] = csize;
1059 row [NUMERIC_PRECISION_IDX] = precision;
1060 row [NUMERIC_SCALE_IDX] = scale;
1061 row [PROVIDER_TYPE_IDX] = dbType;
1062 row [DATA_TYPE_IDX] = fieldType;
1063 row [IS_LONG_IDX] = isLong;
1065 if ((bool)row [IS_HIDDEN_IDX] == false)
1066 visibleFieldCount += 1;
1069 schemaTable.Rows.Add (row);
1074 private static object GetSchemaValue (TdsDataColumn schema, string key)
1076 object val = schema [key];
1080 return DBNull.Value;
1084 static object GetSchemaValue (object value)
1087 return DBNull.Value;
1097 SqlBinary GetSqlBinary (int i)
1099 object value = GetSqlValue (i);
1100 if (!(value is SqlBinary))
1101 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1102 return (SqlBinary) value;
1109 SqlBoolean GetSqlBoolean (int i)
1111 object value = GetSqlValue (i);
1112 if (!(value is SqlBoolean))
1113 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1114 return (SqlBoolean) value;
1121 SqlByte GetSqlByte (int i)
1123 object value = GetSqlValue (i);
1124 if (!(value is SqlByte))
1125 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1126 return (SqlByte) value;
1133 SqlDateTime GetSqlDateTime (int i)
1135 object value = GetSqlValue (i);
1136 if (!(value is SqlDateTime))
1137 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1138 return (SqlDateTime) value;
1145 SqlDecimal GetSqlDecimal (int i)
1147 object value = GetSqlValue (i);
1148 if (!(value is SqlDecimal))
1149 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1150 return (SqlDecimal) value;
1157 SqlDouble GetSqlDouble (int i)
1159 object value = GetSqlValue (i);
1160 if (!(value is SqlDouble))
1161 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1162 return (SqlDouble) value;
1169 SqlGuid GetSqlGuid (int i)
1171 object value = GetSqlValue (i);
1172 if (!(value is SqlGuid))
1173 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1174 return (SqlGuid) value;
1181 SqlInt16 GetSqlInt16 (int i)
1183 object value = GetSqlValue (i);
1184 if (!(value is SqlInt16))
1185 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1186 return (SqlInt16) value;
1193 SqlInt32 GetSqlInt32 (int i)
1195 object value = GetSqlValue (i);
1196 if (!(value is SqlInt32))
1197 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1198 return (SqlInt32) value;
1205 SqlInt64 GetSqlInt64 (int i)
1207 object value = GetSqlValue (i);
1208 if (!(value is SqlInt64))
1209 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1210 return (SqlInt64) value;
1217 SqlMoney GetSqlMoney (int i)
1219 object value = GetSqlValue (i);
1220 if (!(value is SqlMoney))
1221 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1222 return (SqlMoney) value;
1229 SqlSingle GetSqlSingle (int i)
1231 object value = GetSqlValue (i);
1232 if (!(value is SqlSingle))
1233 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1234 return (SqlSingle) value;
1241 SqlString GetSqlString (int i)
1243 object value = GetSqlValue (i);
1244 if (!(value is SqlString))
1245 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1246 return (SqlString) value;
1250 public virtual SqlXml GetSqlXml (int i)
1252 object value = GetSqlValue (i);
1253 if (!(value is SqlXml)) {
1254 if (value is DBNull) {
1255 throw new SqlNullValueException ();
1256 } else if (command.Tds.TdsVersion <= TdsVersion.tds80 && value is SqlString) {
1257 // Workaround for TDS 7/8/8.1 clients
1258 // Xml column types are supported only from Sql Server 2005 / TDS 9, however
1259 // when a TDS 7/8/8.1 client requests for Xml column data, Sql Server 2005 returns
1261 MemoryStream stream = null;
1262 if (!((SqlString) value).IsNull)
1263 stream = new MemoryStream (Encoding.Unicode.GetBytes (value.ToString()));
1264 value = new SqlXml (stream);
1266 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1269 return (SqlXml) value;
1277 object GetSqlValue (int i)
1279 object value = GetValue (i);
1280 //Console.WriteLine ("Type of value: {0}", value.GetType ());
1282 SqlDbType type = GetSchemaRowDbType (i);
1284 case SqlDbType.BigInt:
1285 if (value == DBNull.Value)
1286 return SqlInt64.Null;
1287 return (SqlInt64) ((long) value);
1288 case SqlDbType.Binary:
1289 case SqlDbType.Image:
1290 case SqlDbType.VarBinary:
1291 case SqlDbType.Timestamp:
1292 if (value == DBNull.Value)
1293 return SqlBinary.Null;
1294 return (SqlBinary) ((byte[]) value);
1296 if (value == DBNull.Value)
1297 return SqlBoolean.Null;
1298 return (SqlBoolean) ((bool) value);
1299 case SqlDbType.Char:
1300 case SqlDbType.NChar:
1301 case SqlDbType.NText:
1302 case SqlDbType.NVarChar:
1303 case SqlDbType.Text:
1304 case SqlDbType.VarChar:
1305 if (value == DBNull.Value)
1306 return SqlString.Null;
1307 return (SqlString) ((string) value);
1308 case SqlDbType.DateTime:
1309 case SqlDbType.SmallDateTime:
1310 if (value == DBNull.Value)
1311 return SqlDateTime.Null;
1312 return (SqlDateTime) ((DateTime) value);
1313 case SqlDbType.Decimal:
1314 if (value == DBNull.Value)
1315 return SqlDecimal.Null;
1316 if (value is TdsBigDecimal)
1317 return SqlDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
1319 return (SqlDecimal)((long) value);
1320 return (SqlDecimal) ((decimal) value);
1321 case SqlDbType.Float:
1322 if (value == DBNull.Value)
1323 return SqlDouble.Null;
1324 return (SqlDouble) ((double) value);
1326 if (value == DBNull.Value)
1327 return SqlInt32.Null;
1328 return (SqlInt32) ((int) value);
1329 case SqlDbType.Money:
1330 case SqlDbType.SmallMoney:
1331 if (value == DBNull.Value)
1332 return SqlMoney.Null;
1333 return (SqlMoney) ((decimal) value);
1334 case SqlDbType.Real:
1335 if (value == DBNull.Value)
1336 return SqlSingle.Null;
1337 return (SqlSingle) ((float) value);
1338 case SqlDbType.UniqueIdentifier:
1339 if (value == DBNull.Value)
1340 return SqlGuid.Null;
1341 return (SqlGuid) ((Guid) value);
1342 case SqlDbType.SmallInt:
1343 if (value == DBNull.Value)
1344 return SqlInt16.Null;
1345 return (SqlInt16) ((short) value);
1346 case SqlDbType.TinyInt:
1347 if (value == DBNull.Value)
1348 return SqlByte.Null;
1349 return (SqlByte) ((byte) value);
1352 if (value == DBNull.Value)
1353 return SqlByte.Null;
1354 return (SqlXml) value;
1358 throw new InvalidOperationException ("The type of this column is unknown.");
1365 int GetSqlValues (object[] values)
1368 EnsureDataAvailable ();
1371 throw new ArgumentNullException ("values");
1374 int columnCount = command.Tds.Columns.Count;
1375 int arrayCount = values.Length;
1377 if (arrayCount > columnCount)
1378 count = columnCount;
1382 for (int i = 0; i < count; i += 1)
1383 values [i] = GetSqlValue (i);
1392 string GetString (int i)
1394 object value = GetValue (i);
1395 if (!(value is string)) {
1396 if (value is DBNull) throw new SqlNullValueException ();
1397 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1399 return (string) value;
1406 object GetValue (int i)
1409 EnsureDataAvailable ();
1411 if (i < 0 || i >= command.Tds.Columns.Count)
1412 throw new IndexOutOfRangeException ();
1415 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
1416 return ((Tds)command.Tds).GetSequentialColumnValue (i);
1418 } catch (TdsInternalException ex) {
1419 command.Connection.Close ();
1420 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1423 return command.Tds.ColumnValues [i];
1430 int GetValues (object[] values)
1433 EnsureDataAvailable ();
1436 throw new ArgumentNullException ("values");
1438 int len = values.Length;
1439 int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
1441 // If a four-byte decimal is stored, then we can't convert to
1442 // a native type. Throw an OverflowException.
1443 if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
1444 throw new OverflowException ();
1446 command.Tds.ColumnValues.CopyTo (0, values, 0,
1447 len > command.Tds.ColumnValues.Count ? command.Tds.ColumnValues.Count : len);
1448 } catch (TdsInternalException ex) {
1449 command.Connection.Close ();
1450 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1452 return (len < FieldCount ? len : FieldCount);
1456 void IDisposable.Dispose ()
1459 GC.SuppressFinalize (this);
1464 public override IEnumerator GetEnumerator ()
1466 IEnumerator IEnumerable.GetEnumerator ()
1469 return new DbEnumerator (this);
1476 bool IsDBNull (int i)
1478 return GetValue (i) == DBNull.Value;
1489 if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0) {
1490 moreResults = false;
1497 moreResults = command.Tds.NextResult ();
1498 } catch (TdsInternalException ex) {
1499 command.Connection.Close ();
1500 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1503 command.GetOutputParameters ();
1505 // new schema - don't do anything except reset schemaTable as command.Tds.Columns is already updated
1523 if (!haveRead || readResultUsed)
1524 readResult = ReadRecord ();
1525 readResultUsed = true;
1529 internal bool ReadRecord ()
1531 readResultUsed = false;
1533 if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && haveRead)
1535 if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
1541 bool result = command.Tds.NextRow ();
1546 } catch (TdsInternalException ex) {
1547 command.Connection.Close ();
1548 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1552 void ValidateState ()
1555 throw new InvalidOperationException ("Invalid attempt to read data when reader is closed");
1558 void EnsureDataAvailable ()
1560 if (!readResult || !haveRead || !readResultUsed)
1561 throw new InvalidOperationException ("No data available.");
1564 InvalidCastException CreateGetBytesOnInvalidColumnTypeException (int ordinal)
1566 string message = string.Format (CultureInfo.InvariantCulture,
1567 "Invalid attempt to GetBytes on column '{0}'." +
1568 "The GetBytes function can only be used on " +
1569 "columns of type Text, NText, or Image.",
1571 return new InvalidCastException (message);
1575 public override Type GetProviderSpecificFieldType (int i)
1577 return (GetSqlValue (i).GetType());
1580 public override object GetProviderSpecificValue (int i)
1582 return (GetSqlValue (i));
1585 public override int GetProviderSpecificValues (object [] values)
1587 return (GetSqlValues (values));
1590 public virtual SqlBytes GetSqlBytes (int i)
1592 //object value = GetSqlValue (i);
1593 //if (!(value is SqlBinary))
1594 // throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1595 Byte[] val = (byte[])GetValue(i);
1596 SqlBytes sb = new SqlBytes (val);
1601 #endregion // Methods