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.Threading;
42 using System.Threading.Tasks;
43 using System.Collections;
44 using System.ComponentModel;
46 using System.Data.Common;
47 using System.Data.SqlTypes;
48 using System.Globalization;
51 namespace System.Data.SqlClient
53 public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
63 DataTable schemaTable;
67 int visibleFieldCount;
71 const int COLUMN_NAME_IDX = 0;
72 const int COLUMN_ORDINAL_IDX = 1;
73 const int COLUMN_SIZE_IDX = 2;
74 const int NUMERIC_PRECISION_IDX = 3;
75 const int NUMERIC_SCALE_IDX = 4;
76 const int IS_UNIQUE_IDX = 5;
77 const int IS_KEY_IDX = 6;
78 const int BASE_SERVER_NAME_IDX = 7;
79 const int BASE_CATALOG_NAME_IDX = 8;
80 const int BASE_COLUMN_NAME_IDX = 9;
81 const int BASE_SCHEMA_NAME_IDX = 10;
82 const int BASE_TABLE_NAME_IDX = 11;
83 const int DATA_TYPE_IDX = 12;
84 const int ALLOW_DBNULL_IDX = 13;
85 const int PROVIDER_TYPE_IDX = 14;
86 const int IS_ALIASED_IDX = 15;
87 const int IS_EXPRESSION_IDX = 16;
88 const int IS_IDENTITY_IDX = 17;
89 const int IS_AUTO_INCREMENT_IDX = 18;
90 const int IS_ROW_VERSION_IDX = 19;
91 const int IS_HIDDEN_IDX = 20;
92 const int IS_LONG_IDX = 21;
93 const int IS_READ_ONLY_IDX = 22;
94 const int PROVIDER_SPECIFIC_TYPE_IDX = 23;
95 const int DATA_TYPE_NAME_IDX = 24;
96 const int XML_SCHEMA_COLLCTN_DB_IDX = 25;
97 const int XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX = 26;
98 const int XML_SCHEMA_COLLCTN_NAME_IDX = 27;
99 const int UDT_ASMBLY_QUALIFIED_NAME_IDX = 28;
100 const int NON_VER_PROVIDER_TYPE_IDX = 29;
101 const int IS_COLUMN_SET = 30;
105 internal SqlDataReader (SqlCommand command)
107 this.command = command;
108 command.Tds.RecordsAffected = -1;
112 #endregion // Constructors
127 return command.Tds.Columns.Count;
134 get { return isClosed; }
139 object this [int i] {
140 get { return GetValue (i); }
145 object this [string name] {
146 get { return GetValue (GetOrdinal (name)); }
151 int RecordsAffected {
153 return command.Tds.RecordsAffected;
166 readResult = ReadRecord ();
170 public override int VisibleFieldCount {
171 get { return visibleFieldCount; }
174 protected SqlConnection Connection {
175 get { return command.Connection; }
178 protected bool IsCommandBehavior (CommandBehavior condition) {
179 return condition == command.CommandBehavior;
182 #endregion // Properties
192 // skip to end & read output parameters.
193 while (NextResult ())
196 command.CloseDataReader ();
199 private static DataTable ConstructSchemaTable ()
201 Type booleanType = typeof (bool);
202 Type stringType = typeof (string);
203 Type intType = typeof (int);
204 Type typeType = typeof (Type);
205 Type shortType = typeof (short);
207 DataTable schemaTable = new DataTable ("SchemaTable");
208 schemaTable.Columns.Add ("ColumnName", stringType);
209 schemaTable.Columns.Add ("ColumnOrdinal", intType);
210 schemaTable.Columns.Add ("ColumnSize", intType);
211 schemaTable.Columns.Add ("NumericPrecision", shortType);
212 schemaTable.Columns.Add ("NumericScale", shortType);
213 schemaTable.Columns.Add ("IsUnique", booleanType);
214 schemaTable.Columns.Add ("IsKey", booleanType);
215 schemaTable.Columns.Add ("BaseServerName", stringType);
216 schemaTable.Columns.Add ("BaseCatalogName", stringType);
217 schemaTable.Columns.Add ("BaseColumnName", stringType);
218 schemaTable.Columns.Add ("BaseSchemaName", stringType);
219 schemaTable.Columns.Add ("BaseTableName", stringType);
220 schemaTable.Columns.Add ("DataType", typeType);
221 schemaTable.Columns.Add ("AllowDBNull", booleanType);
222 schemaTable.Columns.Add ("ProviderType", intType);
223 schemaTable.Columns.Add ("IsAliased", booleanType);
224 schemaTable.Columns.Add ("IsExpression", booleanType);
225 schemaTable.Columns.Add ("IsIdentity", booleanType);
226 schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
227 schemaTable.Columns.Add ("IsRowVersion", booleanType);
228 schemaTable.Columns.Add ("IsHidden", booleanType);
229 schemaTable.Columns.Add ("IsLong", booleanType);
230 schemaTable.Columns.Add ("IsReadOnly", booleanType);
231 schemaTable.Columns.Add ("ProviderSpecificDataType", typeType);
232 schemaTable.Columns.Add ("DataTypeName", stringType);
233 schemaTable.Columns.Add ("XmlSchemaCollectionDatabase", stringType);
234 schemaTable.Columns.Add ("XmlSchemaCollectionOwningSchema", stringType);
235 schemaTable.Columns.Add ("XmlSchemaCollectionName", stringType);
236 schemaTable.Columns.Add ("UdtAssemblyQualifiedName", stringType);
237 schemaTable.Columns.Add ("NonVersionedProviderType", intType);
238 schemaTable.Columns.Add ("IsColumnSet", booleanType);
243 private string GetSchemaRowTypeName (TdsColumnType ctype, int csize, short precision, short scale)
250 GetSchemaRowType (ctype, csize, precision, scale,
251 out dbType, out fieldType, out isLong,
256 private Type GetSchemaRowFieldType (TdsColumnType ctype, int csize, short precision, short scale)
263 GetSchemaRowType (ctype, csize, precision, scale,
264 out dbType, out fieldType, out isLong,
269 SqlDbType GetSchemaRowDbType (int ordinal)
272 short precision, scale;
274 TdsDataColumn column;
276 if (ordinal < 0 || ordinal >= command.Tds.Columns.Count)
277 throw new IndexOutOfRangeException ();
279 column = command.Tds.Columns [ordinal];
280 ctype = (TdsColumnType) column.ColumnType;
281 csize = (int) column.ColumnSize;
282 precision = (short) (column.NumericPrecision ?? 0);
283 scale = (short) (column.NumericScale ?? 0);
284 return GetSchemaRowDbType (ctype, csize, precision, scale);
287 private SqlDbType GetSchemaRowDbType (TdsColumnType ctype, int csize, short precision, short scale)
294 GetSchemaRowType (ctype, csize, precision, scale,
295 out dbType, out fieldType, out isLong,
297 return (SqlDbType) dbType;
300 private void GetSchemaRowType (TdsColumnType ctype, int csize,
301 short precision, short scale,
302 out int dbType, out Type fieldType,
303 out bool isLong, out string typeName)
306 typeName = string.Empty;
308 fieldType = typeof (Type);
311 case TdsColumnType.Int1:
312 case TdsColumnType.Int2:
313 case TdsColumnType.Int4:
314 case TdsColumnType.IntN:
315 case TdsColumnType.BigInt:
318 typeName = "tinyint";
319 dbType = (int) SqlDbType.TinyInt;
320 fieldType = typeof (byte);
324 typeName = "smallint";
325 dbType = (int) SqlDbType.SmallInt;
326 fieldType = typeof (short);
331 dbType = (int) SqlDbType.Int;
332 fieldType = typeof (int);
337 dbType = (int) SqlDbType.BigInt;
338 fieldType = typeof (long);
343 case TdsColumnType.Real:
344 case TdsColumnType.Float8:
345 case TdsColumnType.FloatN:
349 dbType = (int) SqlDbType.Real;
350 fieldType = typeof (float);
355 dbType = (int) SqlDbType.Float;
356 fieldType = typeof (double);
361 case TdsColumnType.Image :
363 dbType = (int) SqlDbType.Image;
364 fieldType = typeof (byte[]);
367 case TdsColumnType.Text :
369 dbType = (int) SqlDbType.Text;
370 fieldType = typeof (string);
373 case TdsColumnType.UniqueIdentifier :
374 typeName = "uniqueidentifier";
375 dbType = (int) SqlDbType.UniqueIdentifier;
376 fieldType = typeof (Guid);
379 case TdsColumnType.VarBinary :
380 case TdsColumnType.BigVarBinary :
381 typeName = "varbinary";
382 dbType = (int) SqlDbType.VarBinary;
383 fieldType = typeof (byte[]);
386 case TdsColumnType.VarChar :
387 case TdsColumnType.BigVarChar :
388 typeName = "varchar";
389 dbType = (int) SqlDbType.VarChar;
390 fieldType = typeof (string);
393 case TdsColumnType.Binary :
394 case TdsColumnType.BigBinary :
396 dbType = (int) SqlDbType.Binary;
397 fieldType = typeof (byte[]);
400 case TdsColumnType.Char :
401 case TdsColumnType.BigChar :
403 dbType = (int) SqlDbType.Char;
404 fieldType = typeof (string);
407 case TdsColumnType.Bit :
408 case TdsColumnType.BitN :
410 dbType = (int) SqlDbType.Bit;
411 fieldType = typeof (bool);
414 case TdsColumnType.DateTime4 :
415 case TdsColumnType.DateTime :
416 case TdsColumnType.DateTimeN :
419 typeName = "smalldatetime";
420 dbType = (int) SqlDbType.SmallDateTime;
421 fieldType = typeof (DateTime);
425 typeName = "datetime";
426 dbType = (int) SqlDbType.DateTime;
427 fieldType = typeof (DateTime);
432 case TdsColumnType.Money :
433 case TdsColumnType.MoneyN :
434 case TdsColumnType.Money4 :
437 typeName = "smallmoney";
438 dbType = (int) SqlDbType.SmallMoney;
439 fieldType = typeof (decimal);
444 dbType = (int) SqlDbType.Money;
445 fieldType = typeof (decimal);
450 case TdsColumnType.NText :
452 dbType = (int) SqlDbType.NText;
453 fieldType = typeof (string);
456 case TdsColumnType.NVarChar :
457 typeName = "nvarchar";
458 dbType = (int) SqlDbType.NVarChar;
459 fieldType = typeof (string);
462 case TdsColumnType.Decimal :
463 case TdsColumnType.Numeric :
464 // TDS 7.0 returns bigint as decimal(19,0)
465 if (precision == 19 && scale == 0) {
467 dbType = (int) SqlDbType.BigInt;
468 fieldType = typeof (long);
470 typeName = "decimal";
471 dbType = (int) SqlDbType.Decimal;
472 fieldType = typeof (decimal);
476 case TdsColumnType.NChar :
478 dbType = (int) SqlDbType.NChar;
479 fieldType = typeof (string);
482 case TdsColumnType.SmallMoney :
483 typeName = "smallmoney";
484 dbType = (int) SqlDbType.SmallMoney;
485 fieldType = typeof (decimal);
489 typeName = "variant";
490 dbType = (int) SqlDbType.Variant;
491 fieldType = typeof (object);
498 void Dispose (bool disposing)
502 if (schemaTable != null)
503 schemaTable.Dispose ();
513 bool GetBoolean (int i)
515 object value = GetValue (i);
516 if (!(value is bool)) {
517 if (value is DBNull) throw new SqlNullValueException ();
518 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
527 object value = GetValue (i);
528 if (!(value is byte)) {
529 if (value is DBNull) throw new SqlNullValueException ();
530 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
537 long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
539 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
541 EnsureDataAvailable ();
544 long len = ((Tds)command.Tds).GetSequentialColumnValue (i, dataIndex, buffer, bufferIndex, length);
546 throw CreateGetBytesOnInvalidColumnTypeException (i);
548 throw new SqlNullValueException ();
550 } catch (TdsInternalException ex) {
551 command.Connection.Close ();
552 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
556 object value = GetValue (i);
557 if (!(value is byte [])) {
558 SqlDbType type = GetSchemaRowDbType (i);
560 case SqlDbType.Image:
562 throw new SqlNullValueException ();
565 string text = value as string;
567 value = Encoding.Default.GetBytes (text);
571 case SqlDbType.NText:
572 string ntext = value as string;
574 value = Encoding.Unicode.GetBytes (ntext);
579 throw CreateGetBytesOnInvalidColumnTypeException (i);
584 return ((byte []) value).Length; // Return length of data
586 // Copy data into buffer
587 int availLen = (int) ( ( (byte []) value).Length - dataIndex);
588 if (availLen < length)
593 Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
594 return length; // return actual read count
597 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
602 throw new NotSupportedException ();
607 long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
609 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
611 EnsureDataAvailable ();
613 if (i < 0 || i >= command.Tds.Columns.Count)
614 throw new IndexOutOfRangeException ();
616 Encoding encoding = null;
618 TdsColumnType colType = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
620 case TdsColumnType.Text :
621 case TdsColumnType.VarChar:
622 case TdsColumnType.Char:
623 case TdsColumnType.BigVarChar:
624 encoding = Encoding.ASCII;
626 case TdsColumnType.NText :
627 case TdsColumnType.NVarChar:
628 case TdsColumnType.NChar:
629 encoding = Encoding.Unicode;
637 if (buffer == null) {
638 count = GetBytes (i,0,(byte[]) null,0,0);
643 byte[] arr = new byte [length];
644 count = GetBytes (i, dataIndex, arr, 0, length);
646 throw new InvalidCastException ("Specified cast is not valid");
648 Char[] val = encoding.GetChars (arr, 0, (int)count);
649 val.CopyTo (buffer, bufferIndex);
654 object value = GetValue (i);
657 valueBuffer = (char[])value;
658 else if (value is string)
659 valueBuffer = ((string)value).ToCharArray();
661 if (value is DBNull) throw new SqlNullValueException ();
662 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
665 if ( buffer == null ) {
666 // Return length of data
667 return valueBuffer.Length;
670 // Copy data into buffer
671 Array.Copy (valueBuffer, (int) dataIndex, buffer, bufferIndex, length);
672 return valueBuffer.Length - dataIndex;
679 string GetDataTypeName (int i)
681 TdsDataColumn column;
689 if (i < 0 || i >= command.Tds.Columns.Count)
690 throw new IndexOutOfRangeException ();
692 column = command.Tds.Columns [i];
693 ctype = (TdsColumnType) column.ColumnType;
694 csize = (int) column.ColumnSize;
695 precision = (short) (column.NumericPrecision ?? 0);
696 scale = (short) (column.NumericScale ?? 0);
697 return GetSchemaRowTypeName (ctype, csize, precision, scale);
702 DateTime GetDateTime (int i)
704 object value = GetValue (i);
705 if (!(value is DateTime)) {
706 if (value is DBNull) throw new SqlNullValueException ();
707 else throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
709 return (DateTime) value;
713 public virtual DateTimeOffset GetDateTimeOffset (int i)
715 throw new NotImplementedException ();
719 public virtual TimeSpan GetTimeSpan (int i)
721 throw new NotImplementedException ();
725 public virtual SqlChars GetSqlChars (int i)
727 throw new NotImplementedException ();
732 decimal GetDecimal (int i)
734 object value = GetValue (i);
735 if (!(value is decimal)) {
736 if (value is DBNull) throw new SqlNullValueException ();
737 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
739 return (decimal) value;
744 double GetDouble (int i)
746 object value = GetValue (i);
747 if (!(value is double)) {
748 if (value is DBNull) throw new SqlNullValueException ();
749 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
751 return (double) value;
756 Type GetFieldType (int i)
758 TdsDataColumn column;
766 if (i < 0 || i >= command.Tds.Columns.Count)
767 throw new IndexOutOfRangeException ();
769 column = command.Tds.Columns [i];
770 ctype = (TdsColumnType) column.ColumnType;
771 csize = (int) column.ColumnSize;
772 precision = (short) (column.NumericPrecision ?? 0);
773 scale = (short) (column.NumericScale ?? 0);
774 return GetSchemaRowFieldType (ctype, csize, precision,
780 float GetFloat (int i)
782 object value = GetValue (i);
783 if (!(value is float)) {
784 if (value is DBNull) throw new SqlNullValueException ();
785 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
787 return (float) value;
794 object value = GetValue (i);
795 if (!(value is Guid)) {
796 if (value is DBNull) throw new SqlNullValueException ();
797 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
804 short GetInt16 (int i)
806 object value = GetValue (i);
807 if (!(value is short)) {
808 if (value is DBNull) throw new SqlNullValueException ();
809 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
811 return (short) value;
818 object value = GetValue (i);
819 if (!(value is int)) {
820 if (value is DBNull) throw new SqlNullValueException ();
821 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
828 long GetInt64 (int i)
830 object value = GetValue (i);
831 if (!(value is long)) {
832 if (value is DBNull) throw new SqlNullValueException ();
833 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
840 string GetName (int i)
844 if (i < 0 || i >= command.Tds.Columns.Count)
845 throw new IndexOutOfRangeException ();
846 return (string) command.Tds.Columns[i].ColumnName;
851 int GetOrdinal (string name)
856 throw new ArgumentNullException ("fieldName");
859 foreach (TdsDataColumn schema in command.Tds.Columns) {
860 colName = schema.ColumnName;
861 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
862 return (int) schema.ColumnOrdinal;
864 throw new IndexOutOfRangeException ();
869 DataTable GetSchemaTable ()
873 if (schemaTable == null)
874 schemaTable = ConstructSchemaTable ();
876 if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
882 foreach (TdsDataColumn schema in command.Tds.Columns) {
883 DataRow row = schemaTable.NewRow ();
885 row [COLUMN_NAME_IDX] = GetSchemaValue (schema.ColumnName);
886 row [COLUMN_ORDINAL_IDX] = GetSchemaValue (schema.ColumnOrdinal);
887 row [IS_UNIQUE_IDX] = GetSchemaValue (schema.IsUnique);
888 row [IS_AUTO_INCREMENT_IDX] = GetSchemaValue (schema.IsAutoIncrement);
889 row [IS_ROW_VERSION_IDX] = GetSchemaValue (schema.IsRowVersion);
890 row [IS_HIDDEN_IDX] = GetSchemaValue (schema.IsHidden);
891 row [IS_IDENTITY_IDX] = GetSchemaValue (schema.IsIdentity);
892 row [NUMERIC_PRECISION_IDX] = GetSchemaValue (schema.NumericPrecision);
893 row [IS_KEY_IDX] = GetSchemaValue (schema.IsKey);
894 row [IS_ALIASED_IDX] = GetSchemaValue (schema.IsAliased);
895 row [IS_EXPRESSION_IDX] = GetSchemaValue (schema.IsExpression);
896 row [IS_READ_ONLY_IDX] = GetSchemaValue (schema.IsReadOnly);
897 row [BASE_SERVER_NAME_IDX] = GetSchemaValue (schema.BaseServerName);
898 row [BASE_CATALOG_NAME_IDX] = GetSchemaValue (schema.BaseCatalogName);
899 row [BASE_COLUMN_NAME_IDX] = GetSchemaValue (schema.BaseColumnName);
900 row [BASE_SCHEMA_NAME_IDX] = GetSchemaValue (schema.BaseSchemaName);
901 row [BASE_TABLE_NAME_IDX] = GetSchemaValue (schema.BaseTableName);
902 row [ALLOW_DBNULL_IDX] = GetSchemaValue (schema.AllowDBNull);
903 row [PROVIDER_SPECIFIC_TYPE_IDX] = DBNull.Value;
904 row [DATA_TYPE_NAME_IDX] = GetSchemaValue (schema.DataTypeName);
905 row [XML_SCHEMA_COLLCTN_DB_IDX] = DBNull.Value;
906 row [XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX] = DBNull.Value;
907 row [XML_SCHEMA_COLLCTN_NAME_IDX] = DBNull.Value;
908 row [UDT_ASMBLY_QUALIFIED_NAME_IDX] = DBNull.Value;
909 row [NON_VER_PROVIDER_TYPE_IDX] = DBNull.Value;
910 row [IS_COLUMN_SET] = DBNull.Value;
911 // We don't always get the base column name.
912 if (row [BASE_COLUMN_NAME_IDX] == DBNull.Value)
913 row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
922 ctype = (TdsColumnType) schema.ColumnType;
923 csize = (int) schema.ColumnSize;
924 precision = (short) GetSchemaValue (schema.NumericPrecision);
925 scale = (short) GetSchemaValue (schema.NumericScale);
927 GetSchemaRowType (ctype, csize, precision, scale,
928 out dbType, out fieldType, out isLong,
931 row [COLUMN_SIZE_IDX] = csize;
932 row [NUMERIC_PRECISION_IDX] = precision;
933 row [NUMERIC_SCALE_IDX] = scale;
934 row [PROVIDER_TYPE_IDX] = dbType;
935 row [DATA_TYPE_IDX] = fieldType;
936 row [IS_LONG_IDX] = isLong;
937 if ((bool)row [IS_HIDDEN_IDX] == false)
938 visibleFieldCount += 1;
940 schemaTable.Rows.Add (row);
945 private static object GetSchemaValue (TdsDataColumn schema, string key)
947 object val = schema [key];
954 static object GetSchemaValue (object value)
964 SqlBinary GetSqlBinary (int i)
966 object value = GetSqlValue (i);
967 if (!(value is SqlBinary))
968 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
969 return (SqlBinary) value;
974 SqlBoolean GetSqlBoolean (int i)
976 object value = GetSqlValue (i);
977 if (!(value is SqlBoolean))
978 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
979 return (SqlBoolean) value;
984 SqlByte GetSqlByte (int i)
986 object value = GetSqlValue (i);
987 if (!(value is SqlByte))
988 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
989 return (SqlByte) value;
994 SqlDateTime GetSqlDateTime (int i)
996 object value = GetSqlValue (i);
997 if (!(value is SqlDateTime))
998 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
999 return (SqlDateTime) value;
1004 SqlDecimal GetSqlDecimal (int i)
1006 object value = GetSqlValue (i);
1007 if (!(value is SqlDecimal))
1008 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1009 return (SqlDecimal) value;
1014 SqlDouble GetSqlDouble (int i)
1016 object value = GetSqlValue (i);
1017 if (!(value is SqlDouble))
1018 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1019 return (SqlDouble) value;
1024 SqlGuid GetSqlGuid (int i)
1026 object value = GetSqlValue (i);
1027 if (!(value is SqlGuid))
1028 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1029 return (SqlGuid) value;
1034 SqlInt16 GetSqlInt16 (int i)
1036 object value = GetSqlValue (i);
1037 if (!(value is SqlInt16))
1038 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1039 return (SqlInt16) value;
1044 SqlInt32 GetSqlInt32 (int i)
1046 object value = GetSqlValue (i);
1047 if (!(value is SqlInt32))
1048 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1049 return (SqlInt32) value;
1054 SqlInt64 GetSqlInt64 (int i)
1056 object value = GetSqlValue (i);
1057 if (!(value is SqlInt64))
1058 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1059 return (SqlInt64) value;
1064 SqlMoney GetSqlMoney (int i)
1066 object value = GetSqlValue (i);
1067 if (!(value is SqlMoney))
1068 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1069 return (SqlMoney) value;
1074 SqlSingle GetSqlSingle (int i)
1076 object value = GetSqlValue (i);
1077 if (!(value is SqlSingle))
1078 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1079 return (SqlSingle) value;
1084 SqlString GetSqlString (int i)
1086 object value = GetSqlValue (i);
1087 if (!(value is SqlString))
1088 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1089 return (SqlString) value;
1092 public virtual SqlXml GetSqlXml (int i)
1094 object value = GetSqlValue (i);
1095 if (!(value is SqlXml)) {
1096 if (value is DBNull) {
1097 throw new SqlNullValueException ();
1098 } else if (command.Tds.TdsVersion <= TdsVersion.tds80 && value is SqlString) {
1099 // Workaround for TDS 7/8/8.1 clients
1100 // Xml column types are supported only from Sql Server 2005 / TDS 9, however
1101 // when a TDS 7/8/8.1 client requests for Xml column data, Sql Server 2005 returns
1103 MemoryStream stream = null;
1104 if (!((SqlString) value).IsNull)
1105 stream = new MemoryStream (Encoding.Unicode.GetBytes (value.ToString()));
1106 value = new SqlXml (stream);
1108 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1111 return (SqlXml) value;
1116 object GetSqlValue (int i)
1118 object value = GetValue (i);
1119 //Console.WriteLine ("Type of value: {0}", value.GetType ());
1121 SqlDbType type = GetSchemaRowDbType (i);
1123 case SqlDbType.BigInt:
1124 if (value == DBNull.Value)
1125 return SqlInt64.Null;
1126 return (SqlInt64) ((long) value);
1127 case SqlDbType.Binary:
1128 case SqlDbType.Image:
1129 case SqlDbType.VarBinary:
1130 case SqlDbType.Timestamp:
1131 if (value == DBNull.Value)
1132 return SqlBinary.Null;
1133 return (SqlBinary) ((byte[]) value);
1135 if (value == DBNull.Value)
1136 return SqlBoolean.Null;
1137 return (SqlBoolean) ((bool) value);
1138 case SqlDbType.Char:
1139 case SqlDbType.NChar:
1140 case SqlDbType.NText:
1141 case SqlDbType.NVarChar:
1142 case SqlDbType.Text:
1143 case SqlDbType.VarChar:
1144 if (value == DBNull.Value)
1145 return SqlString.Null;
1146 return (SqlString) ((string) value);
1147 case SqlDbType.DateTime:
1148 case SqlDbType.SmallDateTime:
1149 if (value == DBNull.Value)
1150 return SqlDateTime.Null;
1151 return (SqlDateTime) ((DateTime) value);
1152 case SqlDbType.Decimal:
1153 if (value == DBNull.Value)
1154 return SqlDecimal.Null;
1155 if (value is TdsBigDecimal)
1156 return SqlDecimalExtensions.FromTdsBigDecimal ((TdsBigDecimal) value);
1158 return (SqlDecimal)((long) value);
1159 return (SqlDecimal) ((decimal) value);
1160 case SqlDbType.Float:
1161 if (value == DBNull.Value)
1162 return SqlDouble.Null;
1163 return (SqlDouble) ((double) value);
1165 if (value == DBNull.Value)
1166 return SqlInt32.Null;
1167 return (SqlInt32) ((int) value);
1168 case SqlDbType.Money:
1169 case SqlDbType.SmallMoney:
1170 if (value == DBNull.Value)
1171 return SqlMoney.Null;
1172 return (SqlMoney) ((decimal) value);
1173 case SqlDbType.Real:
1174 if (value == DBNull.Value)
1175 return SqlSingle.Null;
1176 return (SqlSingle) ((float) value);
1177 case SqlDbType.UniqueIdentifier:
1178 if (value == DBNull.Value)
1179 return SqlGuid.Null;
1180 return (SqlGuid) ((Guid) value);
1181 case SqlDbType.SmallInt:
1182 if (value == DBNull.Value)
1183 return SqlInt16.Null;
1184 return (SqlInt16) ((short) value);
1185 case SqlDbType.TinyInt:
1186 if (value == DBNull.Value)
1187 return SqlByte.Null;
1188 return (SqlByte) ((byte) value);
1190 if (value == DBNull.Value)
1191 return SqlByte.Null;
1192 return (SqlXml) value;
1195 throw new InvalidOperationException ("The type of this column is unknown.");
1200 int GetSqlValues (object[] values)
1203 EnsureDataAvailable ();
1206 throw new ArgumentNullException ("values");
1209 int columnCount = command.Tds.Columns.Count;
1210 int arrayCount = values.Length;
1212 if (arrayCount > columnCount)
1213 count = columnCount;
1217 for (int i = 0; i < count; i += 1)
1218 values [i] = GetSqlValue (i);
1225 string GetString (int i)
1227 object value = GetValue (i);
1228 if (!(value is string)) {
1229 if (value is DBNull) throw new SqlNullValueException ();
1230 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1232 return (string) value;
1237 object GetValue (int i)
1240 EnsureDataAvailable ();
1242 if (i < 0 || i >= command.Tds.Columns.Count)
1243 throw new IndexOutOfRangeException ();
1246 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
1247 return ((Tds)command.Tds).GetSequentialColumnValue (i);
1249 } catch (TdsInternalException ex) {
1250 command.Connection.Close ();
1251 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1254 return command.Tds.ColumnValues [i];
1259 int GetValues (object[] values)
1262 EnsureDataAvailable ();
1265 throw new ArgumentNullException ("values");
1267 int len = values.Length;
1268 var tds = command.Tds;
1269 int columns = Math.Min (len, tds.Columns.Count);
1271 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
1272 for (int i = 0; i < columns; ++i) {
1273 values [i] = tds.GetSequentialColumnValue (i);
1276 int bigDecimalIndex = tds.ColumnValues.BigDecimalIndex;
1278 // If a four-byte decimal is stored, then we can't convert to
1279 // a native type. Throw an OverflowException.
1280 if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
1281 throw new OverflowException ();
1283 tds.ColumnValues.CopyTo (0, values, 0, columns);
1284 } catch (TdsInternalException ex) {
1285 command.Connection.Close ();
1286 throw SqlException.FromTdsInternalException ((TdsInternalException)ex);
1294 public override IEnumerator GetEnumerator ()
1296 return new DbEnumerator (this);
1301 bool IsDBNull (int i)
1303 return GetValue (i) == DBNull.Value;
1312 if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0) {
1313 moreResults = false;
1320 moreResults = command.Tds.NextResult ();
1321 } catch (TdsInternalException ex) {
1322 command.Connection.Close ();
1323 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1326 command.GetOutputParameters ();
1328 // new schema - don't do anything except reset schemaTable as command.Tds.Columns is already updated
1344 if (!haveRead || readResultUsed)
1345 readResult = ReadRecord ();
1346 readResultUsed = true;
1350 internal bool ReadRecord ()
1352 readResultUsed = false;
1354 if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && haveRead)
1356 if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
1362 bool result = command.Tds.NextRow ();
1367 } catch (TdsInternalException ex) {
1368 command.Connection.Close ();
1369 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1373 void ValidateState ()
1376 throw new InvalidOperationException ("Invalid attempt to read data when reader is closed");
1379 void EnsureDataAvailable ()
1381 if (!readResult || !haveRead || !readResultUsed)
1382 throw new InvalidOperationException ("No data available.");
1385 InvalidCastException CreateGetBytesOnInvalidColumnTypeException (int ordinal)
1387 string message = string.Format (CultureInfo.InvariantCulture,
1388 "Invalid attempt to GetBytes on column '{0}'." +
1389 "The GetBytes function can only be used on " +
1390 "columns of type Text, NText, or Image.",
1392 return new InvalidCastException (message);
1395 public override Type GetProviderSpecificFieldType (int i)
1397 return (GetSqlValue (i).GetType());
1400 public override object GetProviderSpecificValue (int i)
1402 return (GetSqlValue (i));
1405 public override int GetProviderSpecificValues (object [] values)
1407 return (GetSqlValues (values));
1410 public virtual SqlBytes GetSqlBytes (int i)
1412 //object value = GetSqlValue (i);
1413 //if (!(value is SqlBinary))
1414 // throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1415 Byte[] val = (byte[])GetValue(i);
1416 SqlBytes sb = new SqlBytes (val);
1420 public override T GetFieldValue<T> (int i)
1422 return (T)GetValue(i);
1426 public virtual XmlReader GetXmlReader (int i)
1428 throw new NotImplementedException ();
1431 override public Task<T> GetFieldValueAsync<T> (int i, CancellationToken cancellationToken)
1433 return base.GetFieldValueAsync<T> (i, cancellationToken);
1436 override public Stream GetStream (int i)
1438 return base.GetStream (i);
1440 override public TextReader GetTextReader (int i)
1442 return base.GetTextReader (i);
1445 override public Task<bool> IsDBNullAsync (int i, CancellationToken cancellationToken)
1447 return base.IsDBNullAsync (i, cancellationToken);
1450 #endregion // Methods