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