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;
792 public virtual DateTimeOffset GetDateTimeOffset (int i)
794 throw new NotImplementedException ();
798 public virtual TimeSpan GetTimeSpan (int i)
800 throw new NotImplementedException ();
804 public virtual SqlChars GetSqlChars (int i)
806 throw new NotImplementedException ();
813 decimal GetDecimal (int i)
815 object value = GetValue (i);
816 if (!(value is decimal)) {
817 if (value is DBNull) throw new SqlNullValueException ();
818 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
820 return (decimal) value;
827 double GetDouble (int i)
829 object value = GetValue (i);
830 if (!(value is double)) {
831 if (value is DBNull) throw new SqlNullValueException ();
832 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
834 return (double) value;
841 Type GetFieldType (int i)
843 TdsDataColumn column;
851 if (i < 0 || i >= command.Tds.Columns.Count)
852 throw new IndexOutOfRangeException ();
854 column = command.Tds.Columns [i];
856 ctype = (TdsColumnType) column.ColumnType;
857 csize = (int) column.ColumnSize;
858 precision = (short) (column.NumericPrecision ?? 0);
859 scale = (short) (column.NumericScale ?? 0);
861 ctype = (TdsColumnType) column ["ColumnType"];
862 csize = (int) column ["ColumnSize"];
863 precision = (short) ((byte) column ["NumericPrecision"]);
864 scale = (short) ((byte) column ["NumericScale"]);
866 return GetSchemaRowFieldType (ctype, csize, precision,
874 float GetFloat (int i)
876 object value = GetValue (i);
877 if (!(value is float)) {
878 if (value is DBNull) throw new SqlNullValueException ();
879 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
881 return (float) value;
890 object value = GetValue (i);
891 if (!(value is Guid)) {
892 if (value is DBNull) throw new SqlNullValueException ();
893 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
902 short GetInt16 (int i)
904 object value = GetValue (i);
905 if (!(value is short)) {
906 if (value is DBNull) throw new SqlNullValueException ();
907 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
909 return (short) value;
918 object value = GetValue (i);
919 if (!(value is int)) {
920 if (value is DBNull) throw new SqlNullValueException ();
921 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
930 long GetInt64 (int i)
932 object value = GetValue (i);
933 if (!(value is long)) {
934 if (value is DBNull) throw new SqlNullValueException ();
935 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
944 string GetName (int i)
948 if (i < 0 || i >= command.Tds.Columns.Count)
949 throw new IndexOutOfRangeException ();
951 return (string) command.Tds.Columns[i].ColumnName;
953 return (string) command.Tds.Columns[i]["ColumnName"];
961 int GetOrdinal (string name)
966 throw new ArgumentNullException ("fieldName");
969 foreach (TdsDataColumn schema in command.Tds.Columns) {
971 colName = schema.ColumnName;
972 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
973 return (int) schema.ColumnOrdinal;
975 colName = (string) schema["ColumnName"];
976 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
977 return (int) schema["ColumnOrdinal"];
980 throw new IndexOutOfRangeException ();
987 DataTable GetSchemaTable ()
991 if (schemaTable == null)
992 schemaTable = ConstructSchemaTable ();
994 if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
1000 foreach (TdsDataColumn schema in command.Tds.Columns) {
1001 DataRow row = schemaTable.NewRow ();
1004 row [COLUMN_NAME_IDX] = GetSchemaValue (schema.ColumnName);
1005 row [COLUMN_ORDINAL_IDX] = GetSchemaValue (schema.ColumnOrdinal);
1006 row [IS_UNIQUE_IDX] = GetSchemaValue (schema.IsUnique);
1007 row [IS_AUTO_INCREMENT_IDX] = GetSchemaValue (schema.IsAutoIncrement);
1008 row [IS_ROW_VERSION_IDX] = GetSchemaValue (schema.IsRowVersion);
1009 row [IS_HIDDEN_IDX] = GetSchemaValue (schema.IsHidden);
1010 row [IS_IDENTITY_IDX] = GetSchemaValue (schema.IsIdentity);
1011 row [NUMERIC_PRECISION_IDX] = GetSchemaValue (schema.NumericPrecision);
1012 row [IS_KEY_IDX] = GetSchemaValue (schema.IsKey);
1013 row [IS_ALIASED_IDX] = GetSchemaValue (schema.IsAliased);
1014 row [IS_EXPRESSION_IDX] = GetSchemaValue (schema.IsExpression);
1015 row [IS_READ_ONLY_IDX] = GetSchemaValue (schema.IsReadOnly);
1016 row [BASE_SERVER_NAME_IDX] = GetSchemaValue (schema.BaseServerName);
1017 row [BASE_CATALOG_NAME_IDX] = GetSchemaValue (schema.BaseCatalogName);
1018 row [BASE_COLUMN_NAME_IDX] = GetSchemaValue (schema.BaseColumnName);
1019 row [BASE_SCHEMA_NAME_IDX] = GetSchemaValue (schema.BaseSchemaName);
1020 row [BASE_TABLE_NAME_IDX] = GetSchemaValue (schema.BaseTableName);
1021 row [ALLOW_DBNULL_IDX] = GetSchemaValue (schema.AllowDBNull);
1022 row [PROVIDER_SPECIFIC_TYPE_IDX] = DBNull.Value;
1023 row [DATA_TYPE_NAME_IDX] = GetSchemaValue (schema.DataTypeName);
1024 row [XML_SCHEMA_COLLCTN_DB_IDX] = DBNull.Value;
1025 row [XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX] = DBNull.Value;
1026 row [XML_SCHEMA_COLLCTN_NAME_IDX] = DBNull.Value;
1027 row [UDT_ASMBLY_QUALIFIED_NAME_IDX] = DBNull.Value;
1028 row [NON_VER_PROVIDER_TYPE_IDX] = DBNull.Value;
1029 row [IS_COLUMN_SET] = DBNull.Value;
1031 row [COLUMN_NAME_IDX] = GetSchemaValue (schema, "ColumnName");
1032 row [COLUMN_ORDINAL_IDX] = GetSchemaValue (schema, "ColumnOrdinal");
1033 row [IS_UNIQUE_IDX] = GetSchemaValue (schema, "IsUnique");
1034 row [IS_AUTO_INCREMENT_IDX] = GetSchemaValue (schema, "IsAutoIncrement");
1035 row [IS_ROW_VERSION_IDX] = GetSchemaValue (schema, "IsRowVersion");
1036 row [IS_HIDDEN_IDX] = GetSchemaValue (schema, "IsHidden");
1037 row [IS_IDENTITY_IDX] = GetSchemaValue (schema, "IsIdentity");
1038 row [IS_KEY_IDX] = GetSchemaValue (schema, "IsKey");
1039 row [IS_ALIASED_IDX] = GetSchemaValue (schema, "IsAliased");
1040 row [IS_EXPRESSION_IDX] = GetSchemaValue (schema, "IsExpression");
1041 row [IS_READ_ONLY_IDX] = GetSchemaValue (schema, "IsReadOnly");
1042 row [BASE_SERVER_NAME_IDX] = GetSchemaValue (schema, "BaseServerName");
1043 row [BASE_CATALOG_NAME_IDX] = GetSchemaValue (schema, "BaseCatalogName");
1044 row [BASE_COLUMN_NAME_IDX] = GetSchemaValue (schema, "BaseColumnName");
1045 row [BASE_SCHEMA_NAME_IDX] = GetSchemaValue (schema, "BaseSchemaName");
1046 row [BASE_TABLE_NAME_IDX] = GetSchemaValue (schema, "BaseTableName");
1047 row [ALLOW_DBNULL_IDX] = GetSchemaValue (schema, "AllowDBNull");
1049 // We don't always get the base column name.
1050 if (row [BASE_COLUMN_NAME_IDX] == DBNull.Value)
1051 row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
1053 TdsColumnType ctype;
1061 ctype = (TdsColumnType) schema.ColumnType;
1062 csize = (int) schema.ColumnSize;
1063 precision = (short) GetSchemaValue (schema.NumericPrecision);
1064 scale = (short) GetSchemaValue (schema.NumericScale);
1066 ctype = (TdsColumnType) schema ["ColumnType"];
1067 csize = (int) schema ["ColumnSize"];
1068 precision = (short) ((byte) GetSchemaValue (schema, "NumericPrecision"));
1069 scale = (short) ((byte) GetSchemaValue (schema, "NumericScale"));
1072 GetSchemaRowType (ctype, csize, precision, scale,
1073 out dbType, out fieldType, out isLong,
1076 row [COLUMN_SIZE_IDX] = csize;
1077 row [NUMERIC_PRECISION_IDX] = precision;
1078 row [NUMERIC_SCALE_IDX] = scale;
1079 row [PROVIDER_TYPE_IDX] = dbType;
1080 row [DATA_TYPE_IDX] = fieldType;
1081 row [IS_LONG_IDX] = isLong;
1083 if ((bool)row [IS_HIDDEN_IDX] == false)
1084 visibleFieldCount += 1;
1087 schemaTable.Rows.Add (row);
1092 private static object GetSchemaValue (TdsDataColumn schema, string key)
1094 object val = schema [key];
1098 return DBNull.Value;
1102 static object GetSchemaValue (object value)
1105 return DBNull.Value;
1115 SqlBinary GetSqlBinary (int i)
1117 object value = GetSqlValue (i);
1118 if (!(value is SqlBinary))
1119 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1120 return (SqlBinary) value;
1127 SqlBoolean GetSqlBoolean (int i)
1129 object value = GetSqlValue (i);
1130 if (!(value is SqlBoolean))
1131 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1132 return (SqlBoolean) value;
1139 SqlByte GetSqlByte (int i)
1141 object value = GetSqlValue (i);
1142 if (!(value is SqlByte))
1143 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1144 return (SqlByte) value;
1151 SqlDateTime GetSqlDateTime (int i)
1153 object value = GetSqlValue (i);
1154 if (!(value is SqlDateTime))
1155 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1156 return (SqlDateTime) value;
1163 SqlDecimal GetSqlDecimal (int i)
1165 object value = GetSqlValue (i);
1166 if (!(value is SqlDecimal))
1167 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1168 return (SqlDecimal) value;
1175 SqlDouble GetSqlDouble (int i)
1177 object value = GetSqlValue (i);
1178 if (!(value is SqlDouble))
1179 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1180 return (SqlDouble) value;
1187 SqlGuid GetSqlGuid (int i)
1189 object value = GetSqlValue (i);
1190 if (!(value is SqlGuid))
1191 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1192 return (SqlGuid) value;
1199 SqlInt16 GetSqlInt16 (int i)
1201 object value = GetSqlValue (i);
1202 if (!(value is SqlInt16))
1203 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1204 return (SqlInt16) value;
1211 SqlInt32 GetSqlInt32 (int i)
1213 object value = GetSqlValue (i);
1214 if (!(value is SqlInt32))
1215 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1216 return (SqlInt32) value;
1223 SqlInt64 GetSqlInt64 (int i)
1225 object value = GetSqlValue (i);
1226 if (!(value is SqlInt64))
1227 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1228 return (SqlInt64) value;
1235 SqlMoney GetSqlMoney (int i)
1237 object value = GetSqlValue (i);
1238 if (!(value is SqlMoney))
1239 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1240 return (SqlMoney) value;
1247 SqlSingle GetSqlSingle (int i)
1249 object value = GetSqlValue (i);
1250 if (!(value is SqlSingle))
1251 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1252 return (SqlSingle) value;
1259 SqlString GetSqlString (int i)
1261 object value = GetSqlValue (i);
1262 if (!(value is SqlString))
1263 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1264 return (SqlString) value;
1268 public virtual SqlXml GetSqlXml (int i)
1270 object value = GetSqlValue (i);
1271 if (!(value is SqlXml)) {
1272 if (value is DBNull) {
1273 throw new SqlNullValueException ();
1274 } else if (command.Tds.TdsVersion <= TdsVersion.tds80 && value is SqlString) {
1275 // Workaround for TDS 7/8/8.1 clients
1276 // Xml column types are supported only from Sql Server 2005 / TDS 9, however
1277 // when a TDS 7/8/8.1 client requests for Xml column data, Sql Server 2005 returns
1279 MemoryStream stream = null;
1280 if (!((SqlString) value).IsNull)
1281 stream = new MemoryStream (Encoding.Unicode.GetBytes (value.ToString()));
1282 value = new SqlXml (stream);
1284 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1287 return (SqlXml) value;
1295 object GetSqlValue (int i)
1297 object value = GetValue (i);
1298 //Console.WriteLine ("Type of value: {0}", value.GetType ());
1300 SqlDbType type = GetSchemaRowDbType (i);
1302 case SqlDbType.BigInt:
1303 if (value == DBNull.Value)
1304 return SqlInt64.Null;
1305 return (SqlInt64) ((long) value);
1306 case SqlDbType.Binary:
1307 case SqlDbType.Image:
1308 case SqlDbType.VarBinary:
1309 case SqlDbType.Timestamp:
1310 if (value == DBNull.Value)
1311 return SqlBinary.Null;
1312 return (SqlBinary) ((byte[]) value);
1314 if (value == DBNull.Value)
1315 return SqlBoolean.Null;
1316 return (SqlBoolean) ((bool) value);
1317 case SqlDbType.Char:
1318 case SqlDbType.NChar:
1319 case SqlDbType.NText:
1320 case SqlDbType.NVarChar:
1321 case SqlDbType.Text:
1322 case SqlDbType.VarChar:
1323 if (value == DBNull.Value)
1324 return SqlString.Null;
1325 return (SqlString) ((string) value);
1326 case SqlDbType.DateTime:
1327 case SqlDbType.SmallDateTime:
1328 if (value == DBNull.Value)
1329 return SqlDateTime.Null;
1330 return (SqlDateTime) ((DateTime) value);
1331 case SqlDbType.Decimal:
1332 if (value == DBNull.Value)
1333 return SqlDecimal.Null;
1334 if (value is TdsBigDecimal)
1335 return SqlDecimal.FromTdsBigDecimal ((TdsBigDecimal) value);
1337 return (SqlDecimal)((long) value);
1338 return (SqlDecimal) ((decimal) value);
1339 case SqlDbType.Float:
1340 if (value == DBNull.Value)
1341 return SqlDouble.Null;
1342 return (SqlDouble) ((double) value);
1344 if (value == DBNull.Value)
1345 return SqlInt32.Null;
1346 return (SqlInt32) ((int) value);
1347 case SqlDbType.Money:
1348 case SqlDbType.SmallMoney:
1349 if (value == DBNull.Value)
1350 return SqlMoney.Null;
1351 return (SqlMoney) ((decimal) value);
1352 case SqlDbType.Real:
1353 if (value == DBNull.Value)
1354 return SqlSingle.Null;
1355 return (SqlSingle) ((float) value);
1356 case SqlDbType.UniqueIdentifier:
1357 if (value == DBNull.Value)
1358 return SqlGuid.Null;
1359 return (SqlGuid) ((Guid) value);
1360 case SqlDbType.SmallInt:
1361 if (value == DBNull.Value)
1362 return SqlInt16.Null;
1363 return (SqlInt16) ((short) value);
1364 case SqlDbType.TinyInt:
1365 if (value == DBNull.Value)
1366 return SqlByte.Null;
1367 return (SqlByte) ((byte) value);
1370 if (value == DBNull.Value)
1371 return SqlByte.Null;
1372 return (SqlXml) value;
1376 throw new InvalidOperationException ("The type of this column is unknown.");
1383 int GetSqlValues (object[] values)
1386 EnsureDataAvailable ();
1389 throw new ArgumentNullException ("values");
1392 int columnCount = command.Tds.Columns.Count;
1393 int arrayCount = values.Length;
1395 if (arrayCount > columnCount)
1396 count = columnCount;
1400 for (int i = 0; i < count; i += 1)
1401 values [i] = GetSqlValue (i);
1410 string GetString (int i)
1412 object value = GetValue (i);
1413 if (!(value is string)) {
1414 if (value is DBNull) throw new SqlNullValueException ();
1415 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1417 return (string) value;
1424 object GetValue (int i)
1427 EnsureDataAvailable ();
1429 if (i < 0 || i >= command.Tds.Columns.Count)
1430 throw new IndexOutOfRangeException ();
1433 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
1434 return ((Tds)command.Tds).GetSequentialColumnValue (i);
1436 } catch (TdsInternalException ex) {
1437 command.Connection.Close ();
1438 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1441 return command.Tds.ColumnValues [i];
1448 int GetValues (object[] values)
1451 EnsureDataAvailable ();
1454 throw new ArgumentNullException ("values");
1456 int len = values.Length;
1457 int bigDecimalIndex = command.Tds.ColumnValues.BigDecimalIndex;
1459 // If a four-byte decimal is stored, then we can't convert to
1460 // a native type. Throw an OverflowException.
1461 if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
1462 throw new OverflowException ();
1464 command.Tds.ColumnValues.CopyTo (0, values, 0,
1465 len > command.Tds.ColumnValues.Count ? command.Tds.ColumnValues.Count : len);
1466 } catch (TdsInternalException ex) {
1467 command.Connection.Close ();
1468 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1470 return (len < FieldCount ? len : FieldCount);
1474 void IDisposable.Dispose ()
1477 GC.SuppressFinalize (this);
1482 public override IEnumerator GetEnumerator ()
1484 IEnumerator IEnumerable.GetEnumerator ()
1487 return new DbEnumerator (this);
1494 bool IsDBNull (int i)
1496 return GetValue (i) == DBNull.Value;
1507 if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0) {
1508 moreResults = false;
1515 moreResults = command.Tds.NextResult ();
1516 } catch (TdsInternalException ex) {
1517 command.Connection.Close ();
1518 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1521 command.GetOutputParameters ();
1523 // new schema - don't do anything except reset schemaTable as command.Tds.Columns is already updated
1541 if (!haveRead || readResultUsed)
1542 readResult = ReadRecord ();
1543 readResultUsed = true;
1547 internal bool ReadRecord ()
1549 readResultUsed = false;
1551 if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && haveRead)
1553 if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
1559 bool result = command.Tds.NextRow ();
1564 } catch (TdsInternalException ex) {
1565 command.Connection.Close ();
1566 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1570 void ValidateState ()
1573 throw new InvalidOperationException ("Invalid attempt to read data when reader is closed");
1576 void EnsureDataAvailable ()
1578 if (!readResult || !haveRead || !readResultUsed)
1579 throw new InvalidOperationException ("No data available.");
1582 InvalidCastException CreateGetBytesOnInvalidColumnTypeException (int ordinal)
1584 string message = string.Format (CultureInfo.InvariantCulture,
1585 "Invalid attempt to GetBytes on column '{0}'." +
1586 "The GetBytes function can only be used on " +
1587 "columns of type Text, NText, or Image.",
1589 return new InvalidCastException (message);
1592 public override Type GetProviderSpecificFieldType (int i)
1594 return (GetSqlValue (i).GetType());
1597 public override object GetProviderSpecificValue (int i)
1599 return (GetSqlValue (i));
1602 public override int GetProviderSpecificValues (object [] values)
1604 return (GetSqlValues (values));
1607 public virtual SqlBytes GetSqlBytes (int i)
1609 //object value = GetSqlValue (i);
1610 //if (!(value is SqlBinary))
1611 // throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1612 Byte[] val = (byte[])GetValue(i);
1613 SqlBytes sb = new SqlBytes (val);
1619 public override T GetFieldValue<T> (int i)
1621 throw new NotImplementedException ();
1625 public virtual XmlReader GetXmlReader (int i)
1627 throw new NotImplementedException ();
1631 #endregion // Methods