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
51 public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord
61 DataTable schemaTable;
65 int visibleFieldCount;
69 const int COLUMN_NAME_IDX = 0;
70 const int COLUMN_ORDINAL_IDX = 1;
71 const int COLUMN_SIZE_IDX = 2;
72 const int NUMERIC_PRECISION_IDX = 3;
73 const int NUMERIC_SCALE_IDX = 4;
74 const int IS_UNIQUE_IDX = 5;
75 const int IS_KEY_IDX = 6;
76 const int BASE_SERVER_NAME_IDX = 7;
77 const int BASE_CATALOG_NAME_IDX = 8;
78 const int BASE_COLUMN_NAME_IDX = 9;
79 const int BASE_SCHEMA_NAME_IDX = 10;
80 const int BASE_TABLE_NAME_IDX = 11;
81 const int DATA_TYPE_IDX = 12;
82 const int ALLOW_DBNULL_IDX = 13;
83 const int PROVIDER_TYPE_IDX = 14;
84 const int IS_ALIASED_IDX = 15;
85 const int IS_EXPRESSION_IDX = 16;
86 const int IS_IDENTITY_IDX = 17;
87 const int IS_AUTO_INCREMENT_IDX = 18;
88 const int IS_ROW_VERSION_IDX = 19;
89 const int IS_HIDDEN_IDX = 20;
90 const int IS_LONG_IDX = 21;
91 const int IS_READ_ONLY_IDX = 22;
92 const int PROVIDER_SPECIFIC_TYPE_IDX = 23;
93 const int DATA_TYPE_NAME_IDX = 24;
94 const int XML_SCHEMA_COLLCTN_DB_IDX = 25;
95 const int XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX = 26;
96 const int XML_SCHEMA_COLLCTN_NAME_IDX = 27;
97 const int UDT_ASMBLY_QUALIFIED_NAME_IDX = 28;
98 const int NON_VER_PROVIDER_TYPE_IDX = 29;
99 const int IS_COLUMN_SET = 30;
103 internal SqlDataReader (SqlCommand command)
105 this.command = command;
106 command.Tds.RecordsAffected = -1;
110 #endregion // Constructors
125 return command.Tds.Columns.Count;
132 get { return isClosed; }
137 object this [int i] {
138 get { return GetValue (i); }
143 object this [string name] {
144 get { return GetValue (GetOrdinal (name)); }
149 int RecordsAffected {
151 return command.Tds.RecordsAffected;
164 readResult = ReadRecord ();
168 public override int VisibleFieldCount {
169 get { return visibleFieldCount; }
172 protected SqlConnection Connection {
173 get { return command.Connection; }
176 protected bool IsCommandBehavior (CommandBehavior condition) {
177 return condition == command.CommandBehavior;
180 #endregion // Properties
190 // skip to end & read output parameters.
191 while (NextResult ())
194 command.CloseDataReader ();
197 private static DataTable ConstructSchemaTable ()
199 Type booleanType = typeof (bool);
200 Type stringType = typeof (string);
201 Type intType = typeof (int);
202 Type typeType = typeof (Type);
203 Type shortType = typeof (short);
205 DataTable schemaTable = new DataTable ("SchemaTable");
206 schemaTable.Columns.Add ("ColumnName", stringType);
207 schemaTable.Columns.Add ("ColumnOrdinal", intType);
208 schemaTable.Columns.Add ("ColumnSize", intType);
209 schemaTable.Columns.Add ("NumericPrecision", shortType);
210 schemaTable.Columns.Add ("NumericScale", shortType);
211 schemaTable.Columns.Add ("IsUnique", booleanType);
212 schemaTable.Columns.Add ("IsKey", booleanType);
213 schemaTable.Columns.Add ("BaseServerName", stringType);
214 schemaTable.Columns.Add ("BaseCatalogName", stringType);
215 schemaTable.Columns.Add ("BaseColumnName", stringType);
216 schemaTable.Columns.Add ("BaseSchemaName", stringType);
217 schemaTable.Columns.Add ("BaseTableName", stringType);
218 schemaTable.Columns.Add ("DataType", typeType);
219 schemaTable.Columns.Add ("AllowDBNull", booleanType);
220 schemaTable.Columns.Add ("ProviderType", intType);
221 schemaTable.Columns.Add ("IsAliased", booleanType);
222 schemaTable.Columns.Add ("IsExpression", booleanType);
223 schemaTable.Columns.Add ("IsIdentity", booleanType);
224 schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
225 schemaTable.Columns.Add ("IsRowVersion", booleanType);
226 schemaTable.Columns.Add ("IsHidden", booleanType);
227 schemaTable.Columns.Add ("IsLong", booleanType);
228 schemaTable.Columns.Add ("IsReadOnly", booleanType);
229 schemaTable.Columns.Add ("ProviderSpecificDataType", typeType);
230 schemaTable.Columns.Add ("DataTypeName", stringType);
231 schemaTable.Columns.Add ("XmlSchemaCollectionDatabase", stringType);
232 schemaTable.Columns.Add ("XmlSchemaCollectionOwningSchema", stringType);
233 schemaTable.Columns.Add ("XmlSchemaCollectionName", stringType);
234 schemaTable.Columns.Add ("UdtAssemblyQualifiedName", stringType);
235 schemaTable.Columns.Add ("NonVersionedProviderType", intType);
236 schemaTable.Columns.Add ("IsColumnSet", booleanType);
241 private string GetSchemaRowTypeName (TdsColumnType ctype, int csize, short precision, short scale)
248 GetSchemaRowType (ctype, csize, precision, scale,
249 out dbType, out fieldType, out isLong,
254 private Type GetSchemaRowFieldType (TdsColumnType ctype, int csize, short precision, short scale)
261 GetSchemaRowType (ctype, csize, precision, scale,
262 out dbType, out fieldType, out isLong,
267 SqlDbType GetSchemaRowDbType (int ordinal)
270 short precision, scale;
272 TdsDataColumn column;
274 if (ordinal < 0 || ordinal >= command.Tds.Columns.Count)
275 throw new IndexOutOfRangeException ();
277 column = command.Tds.Columns [ordinal];
278 ctype = (TdsColumnType) column.ColumnType;
279 csize = (int) column.ColumnSize;
280 precision = (short) (column.NumericPrecision ?? 0);
281 scale = (short) (column.NumericScale ?? 0);
282 return GetSchemaRowDbType (ctype, csize, precision, scale);
285 private SqlDbType GetSchemaRowDbType (TdsColumnType ctype, int csize, short precision, short scale)
292 GetSchemaRowType (ctype, csize, precision, scale,
293 out dbType, out fieldType, out isLong,
295 return (SqlDbType) dbType;
298 private void GetSchemaRowType (TdsColumnType ctype, int csize,
299 short precision, short scale,
300 out int dbType, out Type fieldType,
301 out bool isLong, out string typeName)
304 typeName = string.Empty;
306 fieldType = typeof (Type);
309 case TdsColumnType.Int1:
310 case TdsColumnType.Int2:
311 case TdsColumnType.Int4:
312 case TdsColumnType.IntN:
313 case TdsColumnType.BigInt:
316 typeName = "tinyint";
317 dbType = (int) SqlDbType.TinyInt;
318 fieldType = typeof (byte);
322 typeName = "smallint";
323 dbType = (int) SqlDbType.SmallInt;
324 fieldType = typeof (short);
329 dbType = (int) SqlDbType.Int;
330 fieldType = typeof (int);
335 dbType = (int) SqlDbType.BigInt;
336 fieldType = typeof (long);
341 case TdsColumnType.Real:
342 case TdsColumnType.Float8:
343 case TdsColumnType.FloatN:
347 dbType = (int) SqlDbType.Real;
348 fieldType = typeof (float);
353 dbType = (int) SqlDbType.Float;
354 fieldType = typeof (double);
359 case TdsColumnType.Image :
361 dbType = (int) SqlDbType.Image;
362 fieldType = typeof (byte[]);
365 case TdsColumnType.Text :
367 dbType = (int) SqlDbType.Text;
368 fieldType = typeof (string);
371 case TdsColumnType.UniqueIdentifier :
372 typeName = "uniqueidentifier";
373 dbType = (int) SqlDbType.UniqueIdentifier;
374 fieldType = typeof (Guid);
377 case TdsColumnType.VarBinary :
378 case TdsColumnType.BigVarBinary :
379 typeName = "varbinary";
380 dbType = (int) SqlDbType.VarBinary;
381 fieldType = typeof (byte[]);
384 case TdsColumnType.VarChar :
385 case TdsColumnType.BigVarChar :
386 typeName = "varchar";
387 dbType = (int) SqlDbType.VarChar;
388 fieldType = typeof (string);
391 case TdsColumnType.Binary :
392 case TdsColumnType.BigBinary :
394 dbType = (int) SqlDbType.Binary;
395 fieldType = typeof (byte[]);
398 case TdsColumnType.Char :
399 case TdsColumnType.BigChar :
401 dbType = (int) SqlDbType.Char;
402 fieldType = typeof (string);
405 case TdsColumnType.Bit :
406 case TdsColumnType.BitN :
408 dbType = (int) SqlDbType.Bit;
409 fieldType = typeof (bool);
412 case TdsColumnType.DateTime4 :
413 case TdsColumnType.DateTime :
414 case TdsColumnType.DateTimeN :
417 typeName = "smalldatetime";
418 dbType = (int) SqlDbType.SmallDateTime;
419 fieldType = typeof (DateTime);
423 typeName = "datetime";
424 dbType = (int) SqlDbType.DateTime;
425 fieldType = typeof (DateTime);
430 case TdsColumnType.Money :
431 case TdsColumnType.MoneyN :
432 case TdsColumnType.Money4 :
435 typeName = "smallmoney";
436 dbType = (int) SqlDbType.SmallMoney;
437 fieldType = typeof (decimal);
442 dbType = (int) SqlDbType.Money;
443 fieldType = typeof (decimal);
448 case TdsColumnType.NText :
450 dbType = (int) SqlDbType.NText;
451 fieldType = typeof (string);
454 case TdsColumnType.NVarChar :
455 typeName = "nvarchar";
456 dbType = (int) SqlDbType.NVarChar;
457 fieldType = typeof (string);
460 case TdsColumnType.Decimal :
461 case TdsColumnType.Numeric :
462 // TDS 7.0 returns bigint as decimal(19,0)
463 if (precision == 19 && scale == 0) {
465 dbType = (int) SqlDbType.BigInt;
466 fieldType = typeof (long);
468 typeName = "decimal";
469 dbType = (int) SqlDbType.Decimal;
470 fieldType = typeof (decimal);
474 case TdsColumnType.NChar :
476 dbType = (int) SqlDbType.NChar;
477 fieldType = typeof (string);
480 case TdsColumnType.SmallMoney :
481 typeName = "smallmoney";
482 dbType = (int) SqlDbType.SmallMoney;
483 fieldType = typeof (decimal);
487 typeName = "variant";
488 dbType = (int) SqlDbType.Variant;
489 fieldType = typeof (object);
496 void Dispose (bool disposing)
500 if (schemaTable != null)
501 schemaTable.Dispose ();
511 bool GetBoolean (int i)
513 object value = GetValue (i);
514 if (!(value is bool)) {
515 if (value is DBNull) throw new SqlNullValueException ();
516 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
525 object value = GetValue (i);
526 if (!(value is byte)) {
527 if (value is DBNull) throw new SqlNullValueException ();
528 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
535 long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
537 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
539 EnsureDataAvailable ();
542 long len = ((Tds)command.Tds).GetSequentialColumnValue (i, dataIndex, buffer, bufferIndex, length);
544 throw CreateGetBytesOnInvalidColumnTypeException (i);
546 throw new SqlNullValueException ();
548 } catch (TdsInternalException ex) {
549 command.Connection.Close ();
550 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
554 object value = GetValue (i);
555 if (!(value is byte [])) {
556 SqlDbType type = GetSchemaRowDbType (i);
558 case SqlDbType.Image:
560 throw new SqlNullValueException ();
563 string text = value as string;
565 value = Encoding.Default.GetBytes (text);
569 case SqlDbType.NText:
570 string ntext = value as string;
572 value = Encoding.Unicode.GetBytes (ntext);
577 throw CreateGetBytesOnInvalidColumnTypeException (i);
582 return ((byte []) value).Length; // Return length of data
584 // Copy data into buffer
585 int availLen = (int) ( ( (byte []) value).Length - dataIndex);
586 if (availLen < length)
591 Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
592 return length; // return actual read count
595 [EditorBrowsableAttribute (EditorBrowsableState.Never)]
600 throw new NotSupportedException ();
605 long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
607 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
609 EnsureDataAvailable ();
611 if (i < 0 || i >= command.Tds.Columns.Count)
612 throw new IndexOutOfRangeException ();
614 Encoding encoding = null;
616 TdsColumnType colType = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
618 case TdsColumnType.Text :
619 case TdsColumnType.VarChar:
620 case TdsColumnType.Char:
621 case TdsColumnType.BigVarChar:
622 encoding = Encoding.ASCII;
624 case TdsColumnType.NText :
625 case TdsColumnType.NVarChar:
626 case TdsColumnType.NChar:
627 encoding = Encoding.Unicode;
635 if (buffer == null) {
636 count = GetBytes (i,0,(byte[]) null,0,0);
641 byte[] arr = new byte [length];
642 count = GetBytes (i, dataIndex, arr, 0, length);
644 throw new InvalidCastException ("Specified cast is not valid");
646 Char[] val = encoding.GetChars (arr, 0, (int)count);
647 val.CopyTo (buffer, bufferIndex);
652 object value = GetValue (i);
655 valueBuffer = (char[])value;
656 else if (value is string)
657 valueBuffer = ((string)value).ToCharArray();
659 if (value is DBNull) throw new SqlNullValueException ();
660 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
663 if ( buffer == null ) {
664 // Return length of data
665 return valueBuffer.Length;
668 // Copy data into buffer
669 Array.Copy (valueBuffer, (int) dataIndex, buffer, bufferIndex, length);
670 return valueBuffer.Length - dataIndex;
677 string GetDataTypeName (int i)
679 TdsDataColumn column;
687 if (i < 0 || i >= command.Tds.Columns.Count)
688 throw new IndexOutOfRangeException ();
690 column = command.Tds.Columns [i];
691 ctype = (TdsColumnType) column.ColumnType;
692 csize = (int) column.ColumnSize;
693 precision = (short) (column.NumericPrecision ?? 0);
694 scale = (short) (column.NumericScale ?? 0);
695 return GetSchemaRowTypeName (ctype, csize, precision, scale);
700 DateTime GetDateTime (int i)
702 object value = GetValue (i);
703 if (!(value is DateTime)) {
704 if (value is DBNull) throw new SqlNullValueException ();
705 else throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
707 return (DateTime) value;
711 public virtual DateTimeOffset GetDateTimeOffset (int i)
713 throw new NotImplementedException ();
717 public virtual TimeSpan GetTimeSpan (int i)
719 throw new NotImplementedException ();
723 public virtual SqlChars GetSqlChars (int i)
725 throw new NotImplementedException ();
730 decimal GetDecimal (int i)
732 object value = GetValue (i);
733 if (!(value is decimal)) {
734 if (value is DBNull) throw new SqlNullValueException ();
735 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
737 return (decimal) value;
742 double GetDouble (int i)
744 object value = GetValue (i);
745 if (!(value is double)) {
746 if (value is DBNull) throw new SqlNullValueException ();
747 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
749 return (double) value;
754 Type GetFieldType (int i)
756 TdsDataColumn column;
764 if (i < 0 || i >= command.Tds.Columns.Count)
765 throw new IndexOutOfRangeException ();
767 column = command.Tds.Columns [i];
768 ctype = (TdsColumnType) column.ColumnType;
769 csize = (int) column.ColumnSize;
770 precision = (short) (column.NumericPrecision ?? 0);
771 scale = (short) (column.NumericScale ?? 0);
772 return GetSchemaRowFieldType (ctype, csize, precision,
778 float GetFloat (int i)
780 object value = GetValue (i);
781 if (!(value is float)) {
782 if (value is DBNull) throw new SqlNullValueException ();
783 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
785 return (float) value;
792 object value = GetValue (i);
793 if (!(value is Guid)) {
794 if (value is DBNull) throw new SqlNullValueException ();
795 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
802 short GetInt16 (int i)
804 object value = GetValue (i);
805 if (!(value is short)) {
806 if (value is DBNull) throw new SqlNullValueException ();
807 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
809 return (short) value;
816 object value = GetValue (i);
817 if (!(value is int)) {
818 if (value is DBNull) throw new SqlNullValueException ();
819 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
826 long GetInt64 (int i)
828 object value = GetValue (i);
829 if (!(value is long)) {
830 if (value is DBNull) throw new SqlNullValueException ();
831 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
838 string GetName (int i)
842 if (i < 0 || i >= command.Tds.Columns.Count)
843 throw new IndexOutOfRangeException ();
844 return (string) command.Tds.Columns[i].ColumnName;
849 int GetOrdinal (string name)
854 throw new ArgumentNullException ("fieldName");
857 foreach (TdsDataColumn schema in command.Tds.Columns) {
858 colName = schema.ColumnName;
859 if (colName.Equals (name) || String.Compare (colName, name, true) == 0)
860 return (int) schema.ColumnOrdinal;
862 throw new IndexOutOfRangeException ();
867 DataTable GetSchemaTable ()
871 if (schemaTable == null)
872 schemaTable = ConstructSchemaTable ();
874 if (schemaTable.Rows != null && schemaTable.Rows.Count > 0)
880 foreach (TdsDataColumn schema in command.Tds.Columns) {
881 DataRow row = schemaTable.NewRow ();
883 row [COLUMN_NAME_IDX] = GetSchemaValue (schema.ColumnName);
884 row [COLUMN_ORDINAL_IDX] = GetSchemaValue (schema.ColumnOrdinal);
885 row [IS_UNIQUE_IDX] = GetSchemaValue (schema.IsUnique);
886 row [IS_AUTO_INCREMENT_IDX] = GetSchemaValue (schema.IsAutoIncrement);
887 row [IS_ROW_VERSION_IDX] = GetSchemaValue (schema.IsRowVersion);
888 row [IS_HIDDEN_IDX] = GetSchemaValue (schema.IsHidden);
889 row [IS_IDENTITY_IDX] = GetSchemaValue (schema.IsIdentity);
890 row [NUMERIC_PRECISION_IDX] = GetSchemaValue (schema.NumericPrecision);
891 row [IS_KEY_IDX] = GetSchemaValue (schema.IsKey);
892 row [IS_ALIASED_IDX] = GetSchemaValue (schema.IsAliased);
893 row [IS_EXPRESSION_IDX] = GetSchemaValue (schema.IsExpression);
894 row [IS_READ_ONLY_IDX] = GetSchemaValue (schema.IsReadOnly);
895 row [BASE_SERVER_NAME_IDX] = GetSchemaValue (schema.BaseServerName);
896 row [BASE_CATALOG_NAME_IDX] = GetSchemaValue (schema.BaseCatalogName);
897 row [BASE_COLUMN_NAME_IDX] = GetSchemaValue (schema.BaseColumnName);
898 row [BASE_SCHEMA_NAME_IDX] = GetSchemaValue (schema.BaseSchemaName);
899 row [BASE_TABLE_NAME_IDX] = GetSchemaValue (schema.BaseTableName);
900 row [ALLOW_DBNULL_IDX] = GetSchemaValue (schema.AllowDBNull);
901 row [PROVIDER_SPECIFIC_TYPE_IDX] = DBNull.Value;
902 row [DATA_TYPE_NAME_IDX] = GetSchemaValue (schema.DataTypeName);
903 row [XML_SCHEMA_COLLCTN_DB_IDX] = DBNull.Value;
904 row [XML_SCHEMA_COLLCTN_OWN_SCHEMA_IDX] = DBNull.Value;
905 row [XML_SCHEMA_COLLCTN_NAME_IDX] = DBNull.Value;
906 row [UDT_ASMBLY_QUALIFIED_NAME_IDX] = DBNull.Value;
907 row [NON_VER_PROVIDER_TYPE_IDX] = DBNull.Value;
908 row [IS_COLUMN_SET] = DBNull.Value;
909 // We don't always get the base column name.
910 if (row [BASE_COLUMN_NAME_IDX] == DBNull.Value)
911 row [BASE_COLUMN_NAME_IDX] = row [COLUMN_NAME_IDX];
920 ctype = (TdsColumnType) schema.ColumnType;
921 csize = (int) schema.ColumnSize;
922 precision = (short) GetSchemaValue (schema.NumericPrecision);
923 scale = (short) GetSchemaValue (schema.NumericScale);
925 GetSchemaRowType (ctype, csize, precision, scale,
926 out dbType, out fieldType, out isLong,
929 row [COLUMN_SIZE_IDX] = csize;
930 row [NUMERIC_PRECISION_IDX] = precision;
931 row [NUMERIC_SCALE_IDX] = scale;
932 row [PROVIDER_TYPE_IDX] = dbType;
933 row [DATA_TYPE_IDX] = fieldType;
934 row [IS_LONG_IDX] = isLong;
935 if ((bool)row [IS_HIDDEN_IDX] == false)
936 visibleFieldCount += 1;
938 schemaTable.Rows.Add (row);
943 private static object GetSchemaValue (TdsDataColumn schema, string key)
945 object val = schema [key];
952 static object GetSchemaValue (object value)
962 SqlBinary GetSqlBinary (int i)
964 object value = GetSqlValue (i);
965 if (!(value is SqlBinary))
966 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
967 return (SqlBinary) value;
972 SqlBoolean GetSqlBoolean (int i)
974 object value = GetSqlValue (i);
975 if (!(value is SqlBoolean))
976 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
977 return (SqlBoolean) value;
982 SqlByte GetSqlByte (int i)
984 object value = GetSqlValue (i);
985 if (!(value is SqlByte))
986 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
987 return (SqlByte) value;
992 SqlDateTime GetSqlDateTime (int i)
994 object value = GetSqlValue (i);
995 if (!(value is SqlDateTime))
996 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
997 return (SqlDateTime) value;
1002 SqlDecimal GetSqlDecimal (int i)
1004 object value = GetSqlValue (i);
1005 if (!(value is SqlDecimal))
1006 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1007 return (SqlDecimal) value;
1012 SqlDouble GetSqlDouble (int i)
1014 object value = GetSqlValue (i);
1015 if (!(value is SqlDouble))
1016 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1017 return (SqlDouble) value;
1022 SqlGuid GetSqlGuid (int i)
1024 object value = GetSqlValue (i);
1025 if (!(value is SqlGuid))
1026 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1027 return (SqlGuid) value;
1032 SqlInt16 GetSqlInt16 (int i)
1034 object value = GetSqlValue (i);
1035 if (!(value is SqlInt16))
1036 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1037 return (SqlInt16) value;
1042 SqlInt32 GetSqlInt32 (int i)
1044 object value = GetSqlValue (i);
1045 if (!(value is SqlInt32))
1046 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1047 return (SqlInt32) value;
1052 SqlInt64 GetSqlInt64 (int i)
1054 object value = GetSqlValue (i);
1055 if (!(value is SqlInt64))
1056 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1057 return (SqlInt64) value;
1062 SqlMoney GetSqlMoney (int i)
1064 object value = GetSqlValue (i);
1065 if (!(value is SqlMoney))
1066 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1067 return (SqlMoney) value;
1072 SqlSingle GetSqlSingle (int i)
1074 object value = GetSqlValue (i);
1075 if (!(value is SqlSingle))
1076 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1077 return (SqlSingle) value;
1082 SqlString GetSqlString (int i)
1084 object value = GetSqlValue (i);
1085 if (!(value is SqlString))
1086 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1087 return (SqlString) value;
1090 public virtual SqlXml GetSqlXml (int i)
1092 object value = GetSqlValue (i);
1093 if (!(value is SqlXml)) {
1094 if (value is DBNull) {
1095 throw new SqlNullValueException ();
1096 } else if (command.Tds.TdsVersion <= TdsVersion.tds80 && value is SqlString) {
1097 // Workaround for TDS 7/8/8.1 clients
1098 // Xml column types are supported only from Sql Server 2005 / TDS 9, however
1099 // when a TDS 7/8/8.1 client requests for Xml column data, Sql Server 2005 returns
1101 MemoryStream stream = null;
1102 if (!((SqlString) value).IsNull)
1103 stream = new MemoryStream (Encoding.Unicode.GetBytes (value.ToString()));
1104 value = new SqlXml (stream);
1106 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1109 return (SqlXml) value;
1114 object GetSqlValue (int i)
1116 object value = GetValue (i);
1117 //Console.WriteLine ("Type of value: {0}", value.GetType ());
1119 SqlDbType type = GetSchemaRowDbType (i);
1121 case SqlDbType.BigInt:
1122 if (value == DBNull.Value)
1123 return SqlInt64.Null;
1124 return (SqlInt64) ((long) value);
1125 case SqlDbType.Binary:
1126 case SqlDbType.Image:
1127 case SqlDbType.VarBinary:
1128 case SqlDbType.Timestamp:
1129 if (value == DBNull.Value)
1130 return SqlBinary.Null;
1131 return (SqlBinary) ((byte[]) value);
1133 if (value == DBNull.Value)
1134 return SqlBoolean.Null;
1135 return (SqlBoolean) ((bool) value);
1136 case SqlDbType.Char:
1137 case SqlDbType.NChar:
1138 case SqlDbType.NText:
1139 case SqlDbType.NVarChar:
1140 case SqlDbType.Text:
1141 case SqlDbType.VarChar:
1142 if (value == DBNull.Value)
1143 return SqlString.Null;
1144 return (SqlString) ((string) value);
1145 case SqlDbType.DateTime:
1146 case SqlDbType.SmallDateTime:
1147 if (value == DBNull.Value)
1148 return SqlDateTime.Null;
1149 return (SqlDateTime) ((DateTime) value);
1150 case SqlDbType.Decimal:
1151 if (value == DBNull.Value)
1152 return SqlDecimal.Null;
1153 if (value is TdsBigDecimal)
1154 return SqlDecimalExtensions.FromTdsBigDecimal ((TdsBigDecimal) value);
1156 return (SqlDecimal)((long) value);
1157 return (SqlDecimal) ((decimal) value);
1158 case SqlDbType.Float:
1159 if (value == DBNull.Value)
1160 return SqlDouble.Null;
1161 return (SqlDouble) ((double) value);
1163 if (value == DBNull.Value)
1164 return SqlInt32.Null;
1165 return (SqlInt32) ((int) value);
1166 case SqlDbType.Money:
1167 case SqlDbType.SmallMoney:
1168 if (value == DBNull.Value)
1169 return SqlMoney.Null;
1170 return (SqlMoney) ((decimal) value);
1171 case SqlDbType.Real:
1172 if (value == DBNull.Value)
1173 return SqlSingle.Null;
1174 return (SqlSingle) ((float) value);
1175 case SqlDbType.UniqueIdentifier:
1176 if (value == DBNull.Value)
1177 return SqlGuid.Null;
1178 return (SqlGuid) ((Guid) value);
1179 case SqlDbType.SmallInt:
1180 if (value == DBNull.Value)
1181 return SqlInt16.Null;
1182 return (SqlInt16) ((short) value);
1183 case SqlDbType.TinyInt:
1184 if (value == DBNull.Value)
1185 return SqlByte.Null;
1186 return (SqlByte) ((byte) value);
1188 if (value == DBNull.Value)
1189 return SqlByte.Null;
1190 return (SqlXml) value;
1193 throw new InvalidOperationException ("The type of this column is unknown.");
1198 int GetSqlValues (object[] values)
1201 EnsureDataAvailable ();
1204 throw new ArgumentNullException ("values");
1207 int columnCount = command.Tds.Columns.Count;
1208 int arrayCount = values.Length;
1210 if (arrayCount > columnCount)
1211 count = columnCount;
1215 for (int i = 0; i < count; i += 1)
1216 values [i] = GetSqlValue (i);
1223 string GetString (int i)
1225 object value = GetValue (i);
1226 if (!(value is string)) {
1227 if (value is DBNull) throw new SqlNullValueException ();
1228 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1230 return (string) value;
1235 object GetValue (int i)
1238 EnsureDataAvailable ();
1240 if (i < 0 || i >= command.Tds.Columns.Count)
1241 throw new IndexOutOfRangeException ();
1244 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
1245 return ((Tds)command.Tds).GetSequentialColumnValue (i);
1247 } catch (TdsInternalException ex) {
1248 command.Connection.Close ();
1249 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1252 return command.Tds.ColumnValues [i];
1257 int GetValues (object[] values)
1260 EnsureDataAvailable ();
1263 throw new ArgumentNullException ("values");
1265 int len = values.Length;
1266 var tds = command.Tds;
1267 int columns = Math.Min (len, tds.Columns.Count);
1269 if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
1270 for (int i = 0; i < columns; ++i) {
1271 values [i] = tds.GetSequentialColumnValue (i);
1274 int bigDecimalIndex = tds.ColumnValues.BigDecimalIndex;
1276 // If a four-byte decimal is stored, then we can't convert to
1277 // a native type. Throw an OverflowException.
1278 if (bigDecimalIndex >= 0 && bigDecimalIndex < len)
1279 throw new OverflowException ();
1281 tds.ColumnValues.CopyTo (0, values, 0, columns);
1282 } catch (TdsInternalException ex) {
1283 command.Connection.Close ();
1284 throw SqlException.FromTdsInternalException ((TdsInternalException)ex);
1292 public override IEnumerator GetEnumerator ()
1294 return new DbEnumerator (this);
1299 bool IsDBNull (int i)
1301 return GetValue (i) == DBNull.Value;
1310 if ((command.CommandBehavior & CommandBehavior.SingleResult) != 0 && resultsRead > 0) {
1311 moreResults = false;
1318 moreResults = command.Tds.NextResult ();
1319 } catch (TdsInternalException ex) {
1320 command.Connection.Close ();
1321 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1324 command.GetOutputParameters ();
1326 // new schema - don't do anything except reset schemaTable as command.Tds.Columns is already updated
1342 if (!haveRead || readResultUsed)
1343 readResult = ReadRecord ();
1344 readResultUsed = true;
1348 internal bool ReadRecord ()
1350 readResultUsed = false;
1352 if ((command.CommandBehavior & CommandBehavior.SingleRow) != 0 && haveRead)
1354 if ((command.CommandBehavior & CommandBehavior.SchemaOnly) != 0)
1360 bool result = command.Tds.NextRow ();
1365 } catch (TdsInternalException ex) {
1366 command.Connection.Close ();
1367 throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
1371 void ValidateState ()
1374 throw new InvalidOperationException ("Invalid attempt to read data when reader is closed");
1377 void EnsureDataAvailable ()
1379 if (!readResult || !haveRead || !readResultUsed)
1380 throw new InvalidOperationException ("No data available.");
1383 InvalidCastException CreateGetBytesOnInvalidColumnTypeException (int ordinal)
1385 string message = string.Format (CultureInfo.InvariantCulture,
1386 "Invalid attempt to GetBytes on column '{0}'." +
1387 "The GetBytes function can only be used on " +
1388 "columns of type Text, NText, or Image.",
1390 return new InvalidCastException (message);
1393 public override Type GetProviderSpecificFieldType (int i)
1395 return (GetSqlValue (i).GetType());
1398 public override object GetProviderSpecificValue (int i)
1400 return (GetSqlValue (i));
1403 public override int GetProviderSpecificValues (object [] values)
1405 return (GetSqlValues (values));
1408 public virtual SqlBytes GetSqlBytes (int i)
1410 //object value = GetSqlValue (i);
1411 //if (!(value is SqlBinary))
1412 // throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
1413 Byte[] val = (byte[])GetValue(i);
1414 SqlBytes sb = new SqlBytes (val);
1418 public override T GetFieldValue<T> (int i)
1420 return (T)GetValue(i);
1424 public virtual XmlReader GetXmlReader (int i)
1426 throw new NotImplementedException ();
1429 #endregion // Methods