1 //------------------------------------------------------------------------------
2 // <copyright file="SqlEnums.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
9 namespace System.Data.SqlClient {
13 using System.Collections.Generic;
14 using System.ComponentModel;
15 using System.Data.Common;
16 using System.Data.OleDb;
17 using System.Data.SqlTypes;
18 using System.Diagnostics;
19 using System.Globalization;
22 using System.Data.Sql;
24 using MSS=Microsoft.SqlServer.Server;
26 internal sealed class MetaType {
27 internal readonly Type ClassType; // com+ type
28 internal readonly Type SqlType;
30 internal readonly int FixedLength; // fixed length size in bytes (-1 for variable)
31 internal readonly bool IsFixed; // true if fixed length, note that sqlchar and sqlbinary are not considered fixed length
32 internal readonly bool IsLong; // true if long
33 internal readonly bool IsPlp; // Column is Partially Length Prefixed (MAX)
34 internal readonly byte Precision; // maxium precision for numeric types // $
35 internal readonly byte Scale;
36 internal readonly byte TDSType;
37 internal readonly byte NullableType;
39 internal readonly string TypeName; // string name of this type
40 internal readonly SqlDbType SqlDbType;
41 internal readonly DbType DbType;
43 // holds count of property bytes expected for a SQLVariant structure
44 internal readonly byte PropBytes;
47 // pre-computed fields
48 internal readonly bool IsAnsiType;
49 internal readonly bool IsBinType;
50 internal readonly bool IsCharType;
51 internal readonly bool IsNCharType;
52 internal readonly bool IsSizeInCharacters;
53 internal readonly bool IsNewKatmaiType;
54 internal readonly bool IsVarTime;
56 internal readonly bool Is70Supported;
57 internal readonly bool Is80Supported;
58 internal readonly bool Is90Supported;
59 internal readonly bool Is100Supported;
61 public MetaType(byte precision, byte scale, int fixedLength, bool isFixed, bool isLong, bool isPlp, byte tdsType, byte nullableTdsType, string typeName, Type classType, Type sqlType, SqlDbType sqldbType, DbType dbType, byte propBytes) {
62 this.Precision = precision;
64 this.FixedLength = fixedLength;
65 this.IsFixed = isFixed;
68 // can we get rid of this (?just have a mapping?)
69 this.TDSType = tdsType;
70 this.NullableType = nullableTdsType;
71 this.TypeName = typeName;
72 this.SqlDbType = sqldbType;
75 this.ClassType = classType;
76 this.SqlType = sqlType;
77 this.PropBytes = propBytes;
79 IsAnsiType = _IsAnsiType(sqldbType);
80 IsBinType = _IsBinType(sqldbType);
81 IsCharType = _IsCharType(sqldbType);
82 IsNCharType = _IsNCharType(sqldbType);
83 IsSizeInCharacters = _IsSizeInCharacters(sqldbType);
84 IsNewKatmaiType = _IsNewKatmaiType(sqldbType);
85 IsVarTime = _IsVarTime(sqldbType);
87 Is70Supported = _Is70Supported(SqlDbType);
88 Is80Supported = _Is80Supported(SqlDbType);
89 Is90Supported = _Is90Supported(SqlDbType);
90 Is100Supported = _Is100Supported(SqlDbType);
93 // properties should be inlined so there should be no perf penalty for using these accessor functions
94 public int TypeId { // partial length prefixed (xml, nvarchar(max),...)
98 private static bool _IsAnsiType(SqlDbType type) {
99 return(type == SqlDbType.Char ||
100 type == SqlDbType.VarChar ||
101 type == SqlDbType.Text);
104 // is this type size expressed as count of characters or bytes?
105 private static bool _IsSizeInCharacters(SqlDbType type) {
106 return(type == SqlDbType.NChar ||
107 type == SqlDbType.NVarChar ||
108 type == SqlDbType.Xml ||
109 type == SqlDbType.NText);
112 private static bool _IsCharType(SqlDbType type) {
113 return(type == SqlDbType.NChar ||
114 type == SqlDbType.NVarChar ||
115 type == SqlDbType.NText ||
116 type == SqlDbType.Char ||
117 type == SqlDbType.VarChar ||
118 type == SqlDbType.Text ||
119 type == SqlDbType.Xml);
122 private static bool _IsNCharType(SqlDbType type) {
123 return(type == SqlDbType.NChar ||
124 type == SqlDbType.NVarChar ||
125 type == SqlDbType.NText ||
126 type == SqlDbType.Xml);
129 private static bool _IsBinType(SqlDbType type) {
130 return(type == SqlDbType.Image ||
131 type == SqlDbType.Binary ||
132 type == SqlDbType.VarBinary ||
133 type == SqlDbType.Timestamp ||
134 type == SqlDbType.Udt ||
135 (int) type == 24 /*SqlSmallVarBinary*/);
138 private static bool _Is70Supported(SqlDbType type) {
139 return((type != SqlDbType.BigInt) && ((int)type > 0) &&
140 ((int)type <= (int) SqlDbType.VarChar));
143 private static bool _Is80Supported(SqlDbType type) {
144 return((int)type >= 0 &&
145 ((int)type <= (int) SqlDbType.Variant));
148 private static bool _Is90Supported(SqlDbType type) {
149 return _Is80Supported(type) ||
150 SqlDbType.Xml == type ||
151 SqlDbType.Udt == type;
154 private static bool _Is100Supported(SqlDbType type) {
155 return _Is90Supported(type) ||
156 SqlDbType.Date == type ||
157 SqlDbType.Time == type ||
158 SqlDbType.DateTime2 == type ||
159 SqlDbType.DateTimeOffset == type;
162 private static bool _IsNewKatmaiType(SqlDbType type) {
163 return SqlDbType.Structured == type;
166 internal static bool _IsVarTime(SqlDbType type) {
167 return (type == SqlDbType.Time || type == SqlDbType.DateTime2 || type == SqlDbType.DateTimeOffset);
171 // map SqlDbType to MetaType class
173 internal static MetaType GetMetaTypeFromSqlDbType(SqlDbType target, bool isMultiValued) { // WebData 113289
175 case SqlDbType.BigInt: return MetaBigInt;
176 case SqlDbType.Binary: return MetaBinary;
177 case SqlDbType.Bit: return MetaBit;
178 case SqlDbType.Char: return MetaChar;
179 case SqlDbType.DateTime: return MetaDateTime;
180 case SqlDbType.Decimal: return MetaDecimal;
181 case SqlDbType.Float: return MetaFloat;
182 case SqlDbType.Image: return MetaImage;
183 case SqlDbType.Int: return MetaInt;
184 case SqlDbType.Money: return MetaMoney;
185 case SqlDbType.NChar: return MetaNChar;
186 case SqlDbType.NText: return MetaNText;
187 case SqlDbType.NVarChar: return MetaNVarChar;
188 case SqlDbType.Real: return MetaReal;
189 case SqlDbType.UniqueIdentifier: return MetaUniqueId;
190 case SqlDbType.SmallDateTime: return MetaSmallDateTime;
191 case SqlDbType.SmallInt: return MetaSmallInt;
192 case SqlDbType.SmallMoney: return MetaSmallMoney;
193 case SqlDbType.Text: return MetaText;
194 case SqlDbType.Timestamp: return MetaTimestamp;
195 case SqlDbType.TinyInt: return MetaTinyInt;
196 case SqlDbType.VarBinary: return MetaVarBinary;
197 case SqlDbType.VarChar: return MetaVarChar;
198 case SqlDbType.Variant: return MetaVariant;
199 case (SqlDbType)TdsEnums.SmallVarBinary: return MetaSmallVarBinary;
200 case SqlDbType.Xml: return MetaXml;
201 case SqlDbType.Udt: return MetaUdt;
202 case SqlDbType.Structured:
209 case SqlDbType.Date: return MetaDate;
210 case SqlDbType.Time: return MetaTime;
211 case SqlDbType.DateTime2: return MetaDateTime2;
212 case SqlDbType.DateTimeOffset: return MetaDateTimeOffset;
213 default: throw SQL.InvalidSqlDbType(target);
218 // map DbType to MetaType class
220 internal static MetaType GetMetaTypeFromDbType(DbType target) {
221 // if we can't map it, we need to throw
223 case DbType.AnsiString: return MetaVarChar;
224 case DbType.AnsiStringFixedLength: return MetaChar;
225 case DbType.Binary: return MetaVarBinary;
226 case DbType.Byte: return MetaTinyInt;
227 case DbType.Boolean: return MetaBit;
228 case DbType.Currency: return MetaMoney;
230 case DbType.DateTime: return MetaDateTime;
231 case DbType.Decimal: return MetaDecimal;
232 case DbType.Double: return MetaFloat;
233 case DbType.Guid: return MetaUniqueId;
234 case DbType.Int16: return MetaSmallInt;
235 case DbType.Int32: return MetaInt;
236 case DbType.Int64: return MetaBigInt;
237 case DbType.Object: return MetaVariant;
238 case DbType.Single: return MetaReal;
239 case DbType.String: return MetaNVarChar;
240 case DbType.StringFixedLength: return MetaNChar;
241 case DbType.Time: return MetaDateTime;
242 case DbType.Xml: return MetaXml;
243 case DbType.DateTime2: return MetaDateTime2;
244 case DbType.DateTimeOffset: return MetaDateTimeOffset;
245 case DbType.SByte: // unsupported
249 case DbType.VarNumeric:
250 default: throw ADP.DbTypeNotSupported(target, typeof(SqlDbType)); // no direct mapping, error out
254 internal static MetaType GetMaxMetaTypeFromMetaType(MetaType mt) {
255 // if we can't map it, we need to throw
256 switch (mt.SqlDbType) {
257 case SqlDbType.VarBinary:
258 case SqlDbType.Binary:
259 return MetaMaxVarBinary;
260 case SqlDbType.VarChar:
262 return MetaMaxVarChar;
263 case SqlDbType.NVarChar:
264 case SqlDbType.NChar:
265 return MetaMaxNVarChar;
275 // map COM+ Type to MetaType class
277 static internal MetaType GetMetaTypeFromType(Type dataType) {
278 return GetMetaTypeFromValue(dataType, null, false, true);
280 static internal MetaType GetMetaTypeFromValue(object value, bool streamAllowed=true) {
281 return GetMetaTypeFromValue(value.GetType(), value, true, streamAllowed);
284 static private MetaType GetMetaTypeFromValue(Type dataType, object value, bool inferLen, bool streamAllowed) {
285 switch (Type.GetTypeCode(dataType)) {
286 case TypeCode.Empty: throw ADP.InvalidDataType(TypeCode.Empty);
287 case TypeCode.Object:
288 if (dataType == typeof(System.Byte[])) {
289 // mdac 90455 must not default to image if inferLen is false ...
291 if (!inferLen || ((byte[]) value).Length <= TdsEnums.TYPE_SIZE_LIMIT) {
292 return MetaVarBinary;
298 else if (dataType == typeof(System.Guid)) {
301 else if (dataType == typeof(System.Object)) {
303 } // check sql types now
304 else if (dataType == typeof(SqlBinary))
305 return MetaVarBinary;
306 else if (dataType == typeof(SqlBoolean))
308 else if (dataType == typeof(SqlByte))
310 else if (dataType == typeof(SqlBytes))
311 return MetaVarBinary;
312 else if (dataType == typeof(SqlChars))
313 return MetaNVarChar; // MDAC 87587
314 else if (dataType == typeof(SqlDateTime))
316 else if (dataType == typeof(SqlDouble))
318 else if (dataType == typeof(SqlGuid))
320 else if (dataType == typeof(SqlInt16))
322 else if (dataType == typeof(SqlInt32))
324 else if (dataType == typeof(SqlInt64))
326 else if (dataType == typeof(SqlMoney))
328 else if (dataType == typeof(SqlDecimal))
330 else if (dataType == typeof(SqlSingle))
332 else if (dataType == typeof(SqlXml))
334 else if (dataType == typeof(SqlString)) {
335 return ((inferLen && !((SqlString)value).IsNull) ? PromoteStringType(((SqlString)value).Value) : MetaNVarChar); // MDAC 87587
337 else if (dataType == typeof(IEnumerable<DbDataRecord>) || dataType == typeof(DataTable)) {
339 } else if (dataType == typeof(TimeSpan)) {
342 else if (dataType == typeof(DateTimeOffset)) {
343 return MetaDateTimeOffset;
347 SqlUdtInfo attribs = SqlUdtInfo.TryGetFromType(dataType);
348 if (attribs != null) {
352 // Derived from Stream ?
353 if (typeof(Stream).IsAssignableFrom(dataType)) {
354 return MetaVarBinary;
356 // Derived from TextReader ?
357 if (typeof(TextReader).IsAssignableFrom(dataType)) {
360 // Derived from XmlReader ?
361 if (typeof(System.Xml.XmlReader).IsAssignableFrom(dataType)) {
366 throw ADP.UnknownDataType(dataType);
368 case TypeCode.DBNull: throw ADP.InvalidDataType(TypeCode.DBNull);
369 case TypeCode.Boolean: return MetaBit;
370 case TypeCode.Char: throw ADP.InvalidDataType(TypeCode.Char);
371 case TypeCode.SByte: throw ADP.InvalidDataType(TypeCode.SByte);
372 case TypeCode.Byte: return MetaTinyInt;
373 case TypeCode.Int16: return MetaSmallInt;
374 case TypeCode.UInt16: throw ADP.InvalidDataType(TypeCode.UInt16);
375 case TypeCode.Int32: return MetaInt;
376 case TypeCode.UInt32: throw ADP.InvalidDataType(TypeCode.UInt32);
377 case TypeCode.Int64: return MetaBigInt;
378 case TypeCode.UInt64: throw ADP.InvalidDataType(TypeCode.UInt64);
379 case TypeCode.Single: return MetaReal;
380 case TypeCode.Double: return MetaFloat;
381 case TypeCode.Decimal: return MetaDecimal;
382 case TypeCode.DateTime: return MetaDateTime;
383 case TypeCode.String: return (inferLen ? PromoteStringType((string)value) : MetaNVarChar);
384 default: throw ADP.UnknownDataTypeCode(dataType, Type.GetTypeCode(dataType));
388 internal static object GetNullSqlValue(Type sqlType) {
389 if (sqlType == typeof(SqlSingle)) return SqlSingle.Null;
390 else if (sqlType == typeof(SqlString)) return SqlString.Null;
391 else if (sqlType == typeof(SqlDouble)) return SqlDouble.Null;
392 else if (sqlType == typeof(SqlBinary)) return SqlBinary.Null;
393 else if (sqlType == typeof(SqlGuid)) return SqlGuid.Null;
394 else if (sqlType == typeof(SqlBoolean)) return SqlBoolean.Null;
395 else if (sqlType == typeof(SqlByte)) return SqlByte.Null;
396 else if (sqlType == typeof(SqlInt16)) return SqlInt16.Null;
397 else if (sqlType == typeof(SqlInt32)) return SqlInt32.Null;
398 else if (sqlType == typeof(SqlInt64)) return SqlInt64.Null;
399 else if (sqlType == typeof(SqlDecimal)) return SqlDecimal.Null;
400 else if (sqlType == typeof(SqlDateTime)) return SqlDateTime.Null;
401 else if (sqlType == typeof(SqlMoney)) return SqlMoney.Null;
402 else if (sqlType == typeof(SqlXml)) return SqlXml.Null;
403 else if (sqlType == typeof(object)) return DBNull.Value;
404 else if (sqlType == typeof(IEnumerable<DbDataRecord>)) return DBNull.Value;
405 else if (sqlType == typeof(DataTable)) return DBNull.Value;
406 else if (sqlType == typeof(DateTime)) return DBNull.Value;
407 else if (sqlType == typeof(TimeSpan)) return DBNull.Value;
408 else if (sqlType == typeof(DateTimeOffset)) return DBNull.Value;
410 Debug.Assert(false, "Unknown SqlType!");
415 internal static MetaType PromoteStringType(string s) {
418 if ((len << 1) > TdsEnums.TYPE_SIZE_LIMIT) {
419 return MetaVarChar; // try as var char since we can send a 8K characters
421 return MetaNVarChar; // send 4k chars, but send as unicode
424 internal static object GetComValueFromSqlVariant(object sqlVal) {
425 object comVal = null;
427 if (ADP.IsNull(sqlVal))
430 if (sqlVal is SqlSingle)
431 comVal = ((SqlSingle)sqlVal).Value;
432 else if (sqlVal is SqlString)
433 comVal = ((SqlString)sqlVal).Value;
434 else if (sqlVal is SqlDouble)
435 comVal = ((SqlDouble)sqlVal).Value;
436 else if (sqlVal is SqlBinary)
437 comVal = ((SqlBinary)sqlVal).Value;
438 else if (sqlVal is SqlGuid)
439 comVal = ((SqlGuid)sqlVal).Value;
440 else if (sqlVal is SqlBoolean)
441 comVal = ((SqlBoolean)sqlVal).Value;
442 else if (sqlVal is SqlByte)
443 comVal = ((SqlByte)sqlVal).Value;
444 else if (sqlVal is SqlInt16)
445 comVal = ((SqlInt16)sqlVal).Value;
446 else if (sqlVal is SqlInt32)
447 comVal = ((SqlInt32)sqlVal).Value;
448 else if (sqlVal is SqlInt64)
449 comVal = ((SqlInt64)sqlVal).Value;
450 else if (sqlVal is SqlDecimal)
451 comVal = ((SqlDecimal)sqlVal).Value;
452 else if (sqlVal is SqlDateTime)
453 comVal = ((SqlDateTime)sqlVal).Value;
454 else if (sqlVal is SqlMoney)
455 comVal = ((SqlMoney)sqlVal).Value;
456 else if (sqlVal is SqlXml)
457 comVal = ((SqlXml)sqlVal).Value;
460 AssertIsUserDefinedTypeInstance(sqlVal, "unknown SqlType class stored in sqlVal");
468 /// Assert that the supplied object is an instance of a SQL User-Defined Type (UDT).
470 /// <param name="sqlValue">Object instance to be tested.</param>
472 /// This method is only compiled with debug builds, and it a helper method for the GetComValueFromSqlVariant method defined in this class.
474 /// The presence of the SqlUserDefinedTypeAttribute on the object's type
475 /// is used to determine if the object is a UDT instance (if present it is a UDT, else it is not).
477 /// <exception cref="NullReferenceException">
478 /// If sqlValue is null. Callers must ensure the object is non-null.
480 [Conditional("DEBUG")]
481 private static void AssertIsUserDefinedTypeInstance(object sqlValue, string failedAssertMessage)
483 Type type = sqlValue.GetType();
484 Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute[] attributes = (Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute[])type.GetCustomAttributes(typeof(Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute), true);
486 Debug.Assert(attributes.Length > 0, failedAssertMessage);
489 // devnote: This method should not be used with SqlDbType.Date and SqlDbType.DateTime2.
490 // With these types the values should be used directly as CLR types instead of being converted to a SqlValue
491 internal static object GetSqlValueFromComVariant(object comVal) {
492 object sqlVal = null;
493 if ((null != comVal) && (DBNull.Value != comVal)) {
495 sqlVal = new SqlSingle((float)comVal);
496 else if (comVal is string)
497 sqlVal = new SqlString((string)comVal);
498 else if (comVal is double)
499 sqlVal = new SqlDouble((double)comVal);
500 else if (comVal is System.Byte[])
501 sqlVal = new SqlBinary((byte[])comVal);
502 else if (comVal is System.Char)
503 sqlVal = new SqlString(((char)comVal).ToString());
504 else if (comVal is System.Char[])
505 sqlVal = new SqlChars((System.Char[])comVal);
506 else if (comVal is System.Guid)
507 sqlVal = new SqlGuid((Guid)comVal);
508 else if (comVal is bool)
509 sqlVal = new SqlBoolean((bool)comVal);
510 else if (comVal is byte)
511 sqlVal = new SqlByte((byte)comVal);
512 else if (comVal is Int16)
513 sqlVal = new SqlInt16((Int16)comVal);
514 else if (comVal is Int32)
515 sqlVal = new SqlInt32((Int32)comVal);
516 else if (comVal is Int64)
517 sqlVal = new SqlInt64((Int64)comVal);
518 else if (comVal is Decimal)
519 sqlVal = new SqlDecimal((Decimal)comVal);
520 else if (comVal is DateTime) {
521 // devnote: Do not use with SqlDbType.Date and SqlDbType.DateTime2. See comment at top of method.
522 sqlVal = new SqlDateTime((DateTime)comVal);
523 } else if (comVal is XmlReader)
524 sqlVal = new SqlXml((XmlReader)comVal);
525 else if (comVal is TimeSpan || comVal is DateTimeOffset)
529 Debug.Assert(false, "unknown SqlType class stored in sqlVal");
535 internal static SqlDbType GetSqlDbTypeFromOleDbType(short dbType, string typeName) {
536 SqlDbType sqlType = SqlDbType.Variant;
537 switch ((OleDbType)dbType) {
538 case OleDbType.BigInt:
539 sqlType = SqlDbType.BigInt;
541 case OleDbType.Boolean:
542 sqlType = SqlDbType.Bit;
545 case OleDbType.VarChar:
546 // these guys are ambiguous - server sends over DBTYPE_STR in both cases
547 sqlType = (typeName == MetaTypeName.CHAR) ? SqlDbType.Char : SqlDbType.VarChar;
549 case OleDbType.Currency:
550 sqlType = (typeName == MetaTypeName.SMALLMONEY) ? SqlDbType.SmallMoney : SqlDbType.Money;
553 case OleDbType.DBTimeStamp:
554 case OleDbType.Filetime:
556 case MetaTypeName.SMALLDATETIME:
557 sqlType = SqlDbType.SmallDateTime;
559 case MetaTypeName.DATETIME2:
560 sqlType = SqlDbType.DateTime2;
563 sqlType = SqlDbType.DateTime;
567 case OleDbType.Decimal:
568 case OleDbType.Numeric:
569 sqlType = SqlDbType.Decimal;
571 case OleDbType.Double:
572 sqlType = SqlDbType.Float;
575 sqlType = SqlDbType.UniqueIdentifier;
577 case OleDbType.Integer:
578 sqlType = SqlDbType.Int;
580 case OleDbType.LongVarBinary:
581 sqlType = SqlDbType.Image;
583 case OleDbType.LongVarChar:
584 sqlType = SqlDbType.Text;
586 case OleDbType.LongVarWChar:
587 sqlType = SqlDbType.NText;
589 case OleDbType.Single:
590 sqlType = SqlDbType.Real;
592 case OleDbType.SmallInt:
593 case OleDbType.UnsignedSmallInt:
594 sqlType = SqlDbType.SmallInt;
596 case OleDbType.TinyInt:
597 case OleDbType.UnsignedTinyInt:
598 sqlType = SqlDbType.TinyInt;
600 case OleDbType.VarBinary:
601 case OleDbType.Binary:
602 sqlType = (typeName == MetaTypeName.BINARY) ? SqlDbType.Binary : SqlDbType.VarBinary;
604 case OleDbType.Variant:
605 sqlType = SqlDbType.Variant;
607 case OleDbType.VarWChar:
608 case OleDbType.WChar:
610 // these guys are ambiguous - server sends over DBTYPE_WSTR in both cases
611 // BSTR is always assumed to be NVARCHAR
612 sqlType = (typeName == MetaTypeName.NCHAR) ? SqlDbType.NChar : SqlDbType.NVarChar;
614 case OleDbType.DBDate: // Date
615 sqlType = SqlDbType.Date;
617 case (OleDbType)132: // Udt
618 sqlType = SqlDbType.Udt;
620 case (OleDbType)141: // Xml
621 sqlType = SqlDbType.Xml;
623 case (OleDbType)145: // Time
624 sqlType = SqlDbType.Time;
626 case (OleDbType)146: // DateTimeOffset
627 sqlType = SqlDbType.DateTimeOffset;
631 break; // no direct mapping, just use SqlDbType.Variant;
637 internal static MetaType GetSqlDataType(int tdsType, UInt32 userType, int length) {
639 case TdsEnums.SQLMONEYN: return ((4 == length) ? MetaSmallMoney : MetaMoney);
640 case TdsEnums.SQLDATETIMN: return ((4 == length) ? MetaSmallDateTime : MetaDateTime);
641 case TdsEnums.SQLINTN: return ((4 <= length) ? ((4 == length) ? MetaInt : MetaBigInt) : ((2 == length) ? MetaSmallInt : MetaTinyInt));
642 case TdsEnums.SQLFLTN: return ((4 == length) ? MetaReal : MetaFloat);
643 case TdsEnums.SQLTEXT: return MetaText;
644 case TdsEnums.SQLVARBINARY: return MetaSmallVarBinary;
645 case TdsEnums.SQLBIGVARBINARY: return MetaVarBinary;
647 case TdsEnums.SQLVARCHAR: //goto TdsEnums.SQLBIGVARCHAR;
648 case TdsEnums.SQLBIGVARCHAR: return MetaVarChar;
650 case TdsEnums.SQLBINARY: //goto TdsEnums.SQLBIGBINARY;
651 case TdsEnums.SQLBIGBINARY: return ((TdsEnums.SQLTIMESTAMP == userType) ? MetaTimestamp : MetaBinary);
653 case TdsEnums.SQLIMAGE: return MetaImage;
655 case TdsEnums.SQLCHAR: //goto TdsEnums.SQLBIGCHAR;
656 case TdsEnums.SQLBIGCHAR: return MetaChar;
658 case TdsEnums.SQLINT1: return MetaTinyInt;
660 case TdsEnums.SQLBIT: //goto TdsEnums.SQLBITN;
661 case TdsEnums.SQLBITN: return MetaBit;
663 case TdsEnums.SQLINT2: return MetaSmallInt;
664 case TdsEnums.SQLINT4: return MetaInt;
665 case TdsEnums.SQLINT8: return MetaBigInt;
666 case TdsEnums.SQLMONEY: return MetaMoney;
667 case TdsEnums.SQLDATETIME: return MetaDateTime;
668 case TdsEnums.SQLFLT8: return MetaFloat;
669 case TdsEnums.SQLFLT4: return MetaReal;
670 case TdsEnums.SQLMONEY4: return MetaSmallMoney;
671 case TdsEnums.SQLDATETIM4: return MetaSmallDateTime;
673 case TdsEnums.SQLDECIMALN: //goto TdsEnums.SQLNUMERICN;
674 case TdsEnums.SQLNUMERICN: return MetaDecimal;
676 case TdsEnums.SQLUNIQUEID: return MetaUniqueId ;
677 case TdsEnums.SQLNCHAR: return MetaNChar;
678 case TdsEnums.SQLNVARCHAR: return MetaNVarChar;
679 case TdsEnums.SQLNTEXT: return MetaNText;
680 case TdsEnums.SQLVARIANT: return MetaVariant;
681 case TdsEnums.SQLUDT: return MetaUdt;
682 case TdsEnums.SQLXMLTYPE: return MetaXml;
683 case TdsEnums.SQLTABLE: return MetaTable;
684 case TdsEnums.SQLDATE: return MetaDate;
685 case TdsEnums.SQLTIME: return MetaTime;
686 case TdsEnums.SQLDATETIME2: return MetaDateTime2;
687 case TdsEnums.SQLDATETIMEOFFSET: return MetaDateTimeOffset;
689 case TdsEnums.SQLVOID:
691 Debug.Assert(false, "Unknown type " + tdsType.ToString(CultureInfo.InvariantCulture));
692 throw SQL.InvalidSqlDbType((SqlDbType)tdsType);
696 internal static MetaType GetDefaultMetaType() {
700 // Converts an XmlReader into String
701 internal static String GetStringFromXml(XmlReader xmlreader) {
702 SqlXml sxml = new SqlXml(xmlreader);
706 private static readonly MetaType MetaBigInt = new MetaType
707 (19, 255, 8, true, false, false, TdsEnums.SQLINT8, TdsEnums.SQLINTN, MetaTypeName.BIGINT, typeof(System.Int64), typeof(SqlInt64), SqlDbType.BigInt, DbType.Int64, 0);
709 private static readonly MetaType MetaFloat = new MetaType
710 (15, 255, 8, true, false, false, TdsEnums.SQLFLT8, TdsEnums.SQLFLTN, MetaTypeName.FLOAT, typeof(System.Double), typeof(SqlDouble), SqlDbType.Float, DbType.Double, 0);
712 private static readonly MetaType MetaReal = new MetaType
713 (7, 255, 4, true, false, false, TdsEnums.SQLFLT4, TdsEnums.SQLFLTN, MetaTypeName.REAL, typeof(System.Single), typeof(SqlSingle), SqlDbType.Real, DbType.Single, 0);
715 // MetaBinary has two bytes of properties for binary and varbinary
717 private static readonly MetaType MetaBinary = new MetaType
718 (255, 255, -1, false, false, false, TdsEnums.SQLBIGBINARY, TdsEnums.SQLBIGBINARY, MetaTypeName.BINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Binary, DbType.Binary, 2);
720 // syntatic sugar for the user...timestamps are 8-byte fixed length binary columns
721 private static readonly MetaType MetaTimestamp = new MetaType
722 (255, 255, -1, false, false, false, TdsEnums.SQLBIGBINARY, TdsEnums.SQLBIGBINARY, MetaTypeName.TIMESTAMP, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Timestamp, DbType.Binary, 2);
724 internal static readonly MetaType MetaVarBinary = new MetaType
725 (255, 255, -1, false, false, false, TdsEnums.SQLBIGVARBINARY, TdsEnums.SQLBIGVARBINARY, MetaTypeName.VARBINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.VarBinary, DbType.Binary, 2);
727 internal static readonly MetaType MetaMaxVarBinary = new MetaType
728 (255, 255, -1, false, true, true, TdsEnums.SQLBIGVARBINARY, TdsEnums.SQLBIGVARBINARY, MetaTypeName.VARBINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.VarBinary, DbType.Binary, 2);
730 // HACK!!! We have an internal type for smallvarbinarys stored on TdsEnums. We
731 // store on TdsEnums instead of SqlDbType because we do not want to expose
732 // this type to the user!
733 private static readonly MetaType MetaSmallVarBinary = new MetaType
734 (255, 255, -1, false, false, false, TdsEnums.SQLVARBINARY, TdsEnums.SQLBIGBINARY, ADP.StrEmpty, typeof(System.Byte[]), typeof(SqlBinary), TdsEnums.SmallVarBinary, DbType.Binary, 2);
736 internal static readonly MetaType MetaImage = new MetaType
737 (255, 255, -1, false, true, false, TdsEnums.SQLIMAGE, TdsEnums.SQLIMAGE, MetaTypeName.IMAGE, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Image, DbType.Binary, 0);
739 private static readonly MetaType MetaBit = new MetaType
740 (255, 255, 1, true, false, false, TdsEnums.SQLBIT, TdsEnums.SQLBITN, MetaTypeName.BIT, typeof(System.Boolean), typeof(SqlBoolean), SqlDbType.Bit, DbType.Boolean, 0);
742 private static readonly MetaType MetaTinyInt = new MetaType
743 (3, 255, 1, true, false, false, TdsEnums.SQLINT1, TdsEnums.SQLINTN, MetaTypeName.TINYINT, typeof(System.Byte), typeof(SqlByte), SqlDbType.TinyInt, DbType.Byte, 0);
745 private static readonly MetaType MetaSmallInt = new MetaType
746 (5, 255, 2, true, false, false, TdsEnums.SQLINT2, TdsEnums.SQLINTN, MetaTypeName.SMALLINT, typeof(System.Int16), typeof(SqlInt16), SqlDbType.SmallInt, DbType.Int16, 0);
748 private static readonly MetaType MetaInt = new MetaType
749 (10, 255, 4, true, false, false, TdsEnums.SQLINT4, TdsEnums.SQLINTN, MetaTypeName.INT, typeof(System.Int32), typeof(SqlInt32), SqlDbType.Int, DbType.Int32, 0);
751 // MetaVariant has seven bytes of properties for MetaChar and MetaVarChar
752 // 5 byte tds collation
754 private static readonly MetaType MetaChar = new MetaType
755 (255, 255, -1, false, false, false, TdsEnums.SQLBIGCHAR, TdsEnums.SQLBIGCHAR, MetaTypeName.CHAR, typeof(System.String), typeof(SqlString), SqlDbType.Char, DbType.AnsiStringFixedLength, 7);
757 private static readonly MetaType MetaVarChar = new MetaType
758 (255, 255, -1, false, false, false, TdsEnums.SQLBIGVARCHAR, TdsEnums.SQLBIGVARCHAR, MetaTypeName.VARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.VarChar, DbType.AnsiString, 7);
760 internal static readonly MetaType MetaMaxVarChar = new MetaType
761 (255, 255, -1, false, true, true, TdsEnums.SQLBIGVARCHAR, TdsEnums.SQLBIGVARCHAR, MetaTypeName.VARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.VarChar, DbType.AnsiString, 7);
763 internal static readonly MetaType MetaText = new MetaType
764 (255, 255, -1, false, true, false, TdsEnums.SQLTEXT, TdsEnums.SQLTEXT, MetaTypeName.TEXT, typeof(System.String), typeof(SqlString), SqlDbType.Text, DbType.AnsiString, 0);
766 // MetaVariant has seven bytes of properties for MetaNChar and MetaNVarChar
767 // 5 byte tds collation
769 private static readonly MetaType MetaNChar = new MetaType
770 (255, 255, -1, false, false, false, TdsEnums.SQLNCHAR, TdsEnums.SQLNCHAR, MetaTypeName.NCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NChar, DbType.StringFixedLength, 7);
772 internal static readonly MetaType MetaNVarChar = new MetaType
773 (255, 255, -1, false, false, false, TdsEnums.SQLNVARCHAR, TdsEnums.SQLNVARCHAR, MetaTypeName.NVARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NVarChar, DbType.String, 7);
775 internal static readonly MetaType MetaMaxNVarChar = new MetaType
776 (255, 255, -1, false, true, true, TdsEnums.SQLNVARCHAR, TdsEnums.SQLNVARCHAR, MetaTypeName.NVARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NVarChar, DbType.String, 7);
778 internal static readonly MetaType MetaNText = new MetaType
779 (255, 255, -1, false, true, false, TdsEnums.SQLNTEXT, TdsEnums.SQLNTEXT, MetaTypeName.NTEXT, typeof(System.String), typeof(SqlString), SqlDbType.NText, DbType.String, 7);
781 // MetaVariant has two bytes of properties for numeric/decimal types
784 internal static readonly MetaType MetaDecimal = new MetaType
785 (38, 4, 17, true, false, false, TdsEnums.SQLNUMERICN, TdsEnums.SQLNUMERICN, MetaTypeName.DECIMAL, typeof(System.Decimal), typeof(SqlDecimal), SqlDbType.Decimal, DbType.Decimal, 2);
787 internal static readonly MetaType MetaXml = new MetaType
788 (255, 255, -1, false, true, true, TdsEnums.SQLXMLTYPE, TdsEnums.SQLXMLTYPE, MetaTypeName.XML, typeof(System.String), typeof(SqlXml), SqlDbType.Xml, DbType.Xml, 0);
790 private static readonly MetaType MetaDateTime = new MetaType
791 (23, 3, 8, true, false, false, TdsEnums.SQLDATETIME, TdsEnums.SQLDATETIMN, MetaTypeName.DATETIME, typeof(System.DateTime), typeof(SqlDateTime), SqlDbType.DateTime, DbType.DateTime, 0);
793 private static readonly MetaType MetaSmallDateTime = new MetaType
794 (16, 0, 4, true, false, false, TdsEnums.SQLDATETIM4, TdsEnums.SQLDATETIMN, MetaTypeName.SMALLDATETIME, typeof(System.DateTime), typeof(SqlDateTime), SqlDbType.SmallDateTime, DbType.DateTime, 0);
796 private static readonly MetaType MetaMoney = new MetaType
797 (19, 255, 8, true, false, false, TdsEnums.SQLMONEY, TdsEnums.SQLMONEYN, MetaTypeName.MONEY, typeof(System.Decimal), typeof(SqlMoney), SqlDbType.Money, DbType.Currency, 0);
799 private static readonly MetaType MetaSmallMoney = new MetaType
800 (10, 255, 4, true, false, false, TdsEnums.SQLMONEY4, TdsEnums.SQLMONEYN, MetaTypeName.SMALLMONEY, typeof(System.Decimal), typeof(SqlMoney), SqlDbType.SmallMoney, DbType.Currency, 0);
802 private static readonly MetaType MetaUniqueId = new MetaType
803 (255, 255, 16, true, false, false, TdsEnums.SQLUNIQUEID, TdsEnums.SQLUNIQUEID, MetaTypeName.ROWGUID, typeof(System.Guid), typeof(SqlGuid), SqlDbType.UniqueIdentifier, DbType.Guid, 0);
805 private static readonly MetaType MetaVariant = new MetaType
806 (255, 255, -1, true, false, false, TdsEnums.SQLVARIANT, TdsEnums.SQLVARIANT, MetaTypeName.VARIANT, typeof(System.Object), typeof(System.Object), SqlDbType.Variant, DbType.Object, 0);
808 internal static readonly MetaType MetaUdt = new MetaType
809 (255, 255, -1, false, false, true, TdsEnums.SQLUDT, TdsEnums.SQLUDT, MetaTypeName.UDT, typeof(System.Object), typeof(System.Object), SqlDbType.Udt, DbType.Object, 0);
811 private static readonly MetaType MetaMaxUdt = new MetaType
812 (255, 255, -1, false, true, true, TdsEnums.SQLUDT, TdsEnums.SQLUDT, MetaTypeName.UDT, typeof(System.Object), typeof(System.Object), SqlDbType.Udt, DbType.Object, 0);
814 private static readonly MetaType MetaTable = new MetaType
815 (255, 255, -1, false, false, false, TdsEnums.SQLTABLE, TdsEnums.SQLTABLE, MetaTypeName.TABLE, typeof(IEnumerable<DbDataRecord>), typeof(IEnumerable<DbDataRecord>), SqlDbType.Structured, DbType.Object, 0);
819 private static readonly MetaType MetaSUDT = new MetaType
820 (255, 255, -1, false, false, false, TdsEnums.SQLVOID, TdsEnums.SQLVOID, "", typeof(MSS.SqlDataRecord), typeof(MSS.SqlDataRecord), SqlDbType.Structured, DbType.Object, 0);
822 private static readonly MetaType MetaDate = new MetaType
823 (255, 255, 3, true, false, false, TdsEnums.SQLDATE, TdsEnums.SQLDATE, MetaTypeName.DATE, typeof(System.DateTime), typeof(System.DateTime), SqlDbType.Date, DbType.Date, 0);
825 internal static readonly MetaType MetaTime = new MetaType
826 (255, 7, -1, false, false, false, TdsEnums.SQLTIME, TdsEnums.SQLTIME, MetaTypeName.TIME, typeof(System.TimeSpan), typeof(System.TimeSpan), SqlDbType.Time, DbType.Time, 1);
828 private static readonly MetaType MetaDateTime2 = new MetaType
829 (255, 7, -1, false, false, false, TdsEnums.SQLDATETIME2, TdsEnums.SQLDATETIME2, MetaTypeName.DATETIME2, typeof(System.DateTime), typeof(System.DateTime), SqlDbType.DateTime2, DbType.DateTime2, 1);
831 internal static readonly MetaType MetaDateTimeOffset = new MetaType
832 (255, 7, -1, false, false, false, TdsEnums.SQLDATETIMEOFFSET, TdsEnums.SQLDATETIMEOFFSET, MetaTypeName.DATETIMEOFFSET, typeof(System.DateTimeOffset), typeof(System.DateTimeOffset), SqlDbType.DateTimeOffset, DbType.DateTimeOffset, 1);
834 public static TdsDateTime FromDateTime(DateTime dateTime, byte cb) {
835 SqlDateTime sqlDateTime;
836 TdsDateTime tdsDateTime = new TdsDateTime();
838 Debug.Assert(cb == 8 || cb == 4, "Invalid date time size!");
841 sqlDateTime = new SqlDateTime(dateTime);
842 tdsDateTime.time = sqlDateTime.TimeTicks;
845 // note that smalldatetime is days&minutes.
846 // Adding 30 seconds ensures proper roundup if the seconds are >= 30
847 // The AddSeconds function handles eventual carryover
848 sqlDateTime = new SqlDateTime(dateTime.AddSeconds(30));
849 tdsDateTime.time = sqlDateTime.TimeTicks / SqlDateTime.SQLTicksPerMinute;
851 tdsDateTime.days = sqlDateTime.DayTicks;
856 public static DateTime ToDateTime(int sqlDays, int sqlTime, int length) {
858 return new SqlDateTime(sqlDays, sqlTime * SqlDateTime.SQLTicksPerMinute).Value;
861 Debug.Assert(length == 8, "invalid length for DateTime");
862 return new SqlDateTime(sqlDays, sqlTime).Value;
866 internal static int GetTimeSizeFromScale(byte scale)
868 // Disable the assert here since we do not properly handle wrong Scale value on the parameter,
869 // see VSTFDEVDIV 795578 for more details.
870 // But, this assert is still valid when we receive Time/DateTime2/DateTimeOffset scale from server over TDS,
871 // so it is moved to TdsParser.CommonProcessMetaData.
872 // For new scenarios, assert and/or validate the scale value before this call!
873 // Debug.Assert(0 <= scale && scale <= 7);
885 // please leave string sorted alphabetically
886 // note that these names should only be used in the context of parameters. We always send over BIG* and nullable types for SQL Server
888 private static class MetaTypeName {
889 public const string BIGINT = "bigint";
890 public const string BINARY = "binary";
891 public const string BIT = "bit";
892 public const string CHAR = "char";
893 public const string DATETIME = "datetime";
894 public const string DECIMAL = "decimal";
895 public const string FLOAT = "float";
896 public const string IMAGE = "image";
897 public const string INT = "int";
898 public const string MONEY = "money";
899 public const string NCHAR = "nchar";
900 public const string NTEXT = "ntext";
901 public const string NVARCHAR = "nvarchar";
902 public const string REAL = "real";
903 public const string ROWGUID = "uniqueidentifier";
904 public const string SMALLDATETIME = "smalldatetime";
905 public const string SMALLINT = "smallint";
906 public const string SMALLMONEY = "smallmoney";
907 public const string TEXT = "text";
908 public const string TIMESTAMP = "timestamp";
909 public const string TINYINT = "tinyint";
910 public const string UDT = "udt";
911 public const string VARBINARY = "varbinary";
912 public const string VARCHAR = "varchar";
913 public const string VARIANT = "sql_variant";
914 public const string XML = "xml";
915 public const string TABLE = "table";
916 public const string DATE = "date";
917 public const string TIME = "time";
918 public const string DATETIME2 = "datetime2";
919 public const string DATETIMEOFFSET = "datetimeoffset";
924 // note: it is the client's responsibility to know what size date time he is working with
926 internal struct TdsDateTime {
927 public int days; // offset in days from 1/1/1900
928 // private UInt32 time; // if smalldatetime, this is # of minutes since midnight
929 // otherwise: # of 1/300th of a second since midnight