|
//------------------------------------------------------------------------------
// <copyright file="SqlEnums.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
namespace System.Data.SqlClient {
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Common;
using System.Data.OleDb;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
using System.IO;
using System.Data.Sql;
using MSS=Microsoft.SqlServer.Server;
internal sealed class MetaType {
internal readonly Type ClassType; // com+ type
internal readonly Type SqlType;
internal readonly int FixedLength; // fixed length size in bytes (-1 for variable)
internal readonly bool IsFixed; // true if fixed length, note that sqlchar and sqlbinary are not considered fixed length
internal readonly bool IsLong; // true if long
internal readonly bool IsPlp; // Column is Partially Length Prefixed (MAX)
internal readonly byte Precision; // maxium precision for numeric types // $
internal readonly byte Scale;
internal readonly byte TDSType;
internal readonly byte NullableType;
internal readonly string TypeName; // string name of this type
internal readonly SqlDbType SqlDbType;
internal readonly DbType DbType;
// holds count of property bytes expected for a SQLVariant structure
internal readonly byte PropBytes;
// pre-computed fields
internal readonly bool IsAnsiType;
internal readonly bool IsBinType;
internal readonly bool IsCharType;
internal readonly bool IsNCharType;
internal readonly bool IsSizeInCharacters;
internal readonly bool IsNewKatmaiType;
internal readonly bool IsVarTime;
internal readonly bool Is70Supported;
internal readonly bool Is80Supported;
internal readonly bool Is90Supported;
internal readonly bool Is100Supported;
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) {
this.Precision = precision;
this.Scale = scale;
this.FixedLength = fixedLength;
this.IsFixed = isFixed;
this.IsLong = isLong;
this.IsPlp = isPlp;
// can we get rid of this (?just have a mapping?)
this.TDSType = tdsType;
this.NullableType = nullableTdsType;
this.TypeName = typeName;
this.SqlDbType = sqldbType;
this.DbType = dbType;
this.ClassType = classType;
this.SqlType = sqlType;
this.PropBytes = propBytes;
IsAnsiType = _IsAnsiType(sqldbType);
IsBinType = _IsBinType(sqldbType);
IsCharType = _IsCharType(sqldbType);
IsNCharType = _IsNCharType(sqldbType);
IsSizeInCharacters = _IsSizeInCharacters(sqldbType);
IsNewKatmaiType = _IsNewKatmaiType(sqldbType);
IsVarTime = _IsVarTime(sqldbType);
Is70Supported = _Is70Supported(SqlDbType);
Is80Supported = _Is80Supported(SqlDbType);
Is90Supported = _Is90Supported(SqlDbType);
Is100Supported = _Is100Supported(SqlDbType);
}
// properties should be inlined so there should be no perf penalty for using these accessor functions
public int TypeId { // partial length prefixed (xml, nvarchar(max),...)
get { return 0;}
}
private static bool _IsAnsiType(SqlDbType type) {
return(type == SqlDbType.Char ||
type == SqlDbType.VarChar ||
type == SqlDbType.Text);
}
// is this type size expressed as count of characters or bytes?
private static bool _IsSizeInCharacters(SqlDbType type) {
return(type == SqlDbType.NChar ||
type == SqlDbType.NVarChar ||
type == SqlDbType.Xml ||
type == SqlDbType.NText);
}
private static bool _IsCharType(SqlDbType type) {
return(type == SqlDbType.NChar ||
type == SqlDbType.NVarChar ||
type == SqlDbType.NText ||
type == SqlDbType.Char ||
type == SqlDbType.VarChar ||
type == SqlDbType.Text ||
type == SqlDbType.Xml);
}
private static bool _IsNCharType(SqlDbType type) {
return(type == SqlDbType.NChar ||
type == SqlDbType.NVarChar ||
type == SqlDbType.NText ||
type == SqlDbType.Xml);
}
private static bool _IsBinType(SqlDbType type) {
return(type == SqlDbType.Image ||
type == SqlDbType.Binary ||
type == SqlDbType.VarBinary ||
type == SqlDbType.Timestamp ||
type == SqlDbType.Udt ||
(int) type == 24 /*SqlSmallVarBinary*/);
}
private static bool _Is70Supported(SqlDbType type) {
return((type != SqlDbType.BigInt) && ((int)type > 0) &&
((int)type <= (int) SqlDbType.VarChar));
}
private static bool _Is80Supported(SqlDbType type) {
return((int)type >= 0 &&
((int)type <= (int) SqlDbType.Variant));
}
private static bool _Is90Supported(SqlDbType type) {
return _Is80Supported(type) ||
SqlDbType.Xml == type ||
SqlDbType.Udt == type;
}
private static bool _Is100Supported(SqlDbType type) {
return _Is90Supported(type) ||
SqlDbType.Date == type ||
SqlDbType.Time == type ||
SqlDbType.DateTime2 == type ||
SqlDbType.DateTimeOffset == type;
}
private static bool _IsNewKatmaiType(SqlDbType type) {
return SqlDbType.Structured == type;
}
internal static bool _IsVarTime(SqlDbType type) {
return (type == SqlDbType.Time || type == SqlDbType.DateTime2 || type == SqlDbType.DateTimeOffset);
}
//
// map SqlDbType to MetaType class
//
internal static MetaType GetMetaTypeFromSqlDbType(SqlDbType target, bool isMultiValued) { // WebData 113289
switch(target) {
case SqlDbType.BigInt: return MetaBigInt;
case SqlDbType.Binary: return MetaBinary;
case SqlDbType.Bit: return MetaBit;
case SqlDbType.Char: return MetaChar;
case SqlDbType.DateTime: return MetaDateTime;
case SqlDbType.Decimal: return MetaDecimal;
case SqlDbType.Float: return MetaFloat;
case SqlDbType.Image: return MetaImage;
case SqlDbType.Int: return MetaInt;
case SqlDbType.Money: return MetaMoney;
case SqlDbType.NChar: return MetaNChar;
case SqlDbType.NText: return MetaNText;
case SqlDbType.NVarChar: return MetaNVarChar;
case SqlDbType.Real: return MetaReal;
case SqlDbType.UniqueIdentifier: return MetaUniqueId;
case SqlDbType.SmallDateTime: return MetaSmallDateTime;
case SqlDbType.SmallInt: return MetaSmallInt;
case SqlDbType.SmallMoney: return MetaSmallMoney;
case SqlDbType.Text: return MetaText;
case SqlDbType.Timestamp: return MetaTimestamp;
case SqlDbType.TinyInt: return MetaTinyInt;
case SqlDbType.VarBinary: return MetaVarBinary;
case SqlDbType.VarChar: return MetaVarChar;
case SqlDbType.Variant: return MetaVariant;
case (SqlDbType)TdsEnums.SmallVarBinary: return MetaSmallVarBinary;
case SqlDbType.Xml: return MetaXml;
case SqlDbType.Udt: return MetaUdt;
case SqlDbType.Structured:
if (isMultiValued) {
return MetaTable;
}
else {
return MetaSUDT;
}
case SqlDbType.Date: return MetaDate;
case SqlDbType.Time: return MetaTime;
case SqlDbType.DateTime2: return MetaDateTime2;
case SqlDbType.DateTimeOffset: return MetaDateTimeOffset;
default: throw SQL.InvalidSqlDbType(target);
}
}
//
// map DbType to MetaType class
//
internal static MetaType GetMetaTypeFromDbType(DbType target) {
// if we can't map it, we need to throw
switch (target) {
case DbType.AnsiString: return MetaVarChar;
case DbType.AnsiStringFixedLength: return MetaChar;
case DbType.Binary: return MetaVarBinary;
case DbType.Byte: return MetaTinyInt;
case DbType.Boolean: return MetaBit;
case DbType.Currency: return MetaMoney;
case DbType.Date:
case DbType.DateTime: return MetaDateTime;
case DbType.Decimal: return MetaDecimal;
case DbType.Double: return MetaFloat;
case DbType.Guid: return MetaUniqueId;
case DbType.Int16: return MetaSmallInt;
case DbType.Int32: return MetaInt;
case DbType.Int64: return MetaBigInt;
case DbType.Object: return MetaVariant;
case DbType.Single: return MetaReal;
case DbType.String: return MetaNVarChar;
case DbType.StringFixedLength: return MetaNChar;
case DbType.Time: return MetaDateTime;
case DbType.Xml: return MetaXml;
case DbType.DateTime2: return MetaDateTime2;
case DbType.DateTimeOffset: return MetaDateTimeOffset;
case DbType.SByte: // unsupported
case DbType.UInt16:
case DbType.UInt32:
case DbType.UInt64:
case DbType.VarNumeric:
default: throw ADP.DbTypeNotSupported(target, typeof(SqlDbType)); // no direct mapping, error out
}
}
internal static MetaType GetMaxMetaTypeFromMetaType(MetaType mt) {
// if we can't map it, we need to throw
switch (mt.SqlDbType) {
case SqlDbType.VarBinary:
case SqlDbType.Binary:
return MetaMaxVarBinary;
case SqlDbType.VarChar:
case SqlDbType.Char:
return MetaMaxVarChar;
case SqlDbType.NVarChar:
case SqlDbType.NChar:
return MetaMaxNVarChar;
case SqlDbType.Udt:
//
return MetaMaxUdt;
default:
return mt;
}
}
//
// map COM+ Type to MetaType class
//
static internal MetaType GetMetaTypeFromType(Type dataType) {
return GetMetaTypeFromValue(dataType, null, false, true);
}
static internal MetaType GetMetaTypeFromValue(object value, bool streamAllowed=true) {
return GetMetaTypeFromValue(value.GetType(), value, true, streamAllowed);
}
static private MetaType GetMetaTypeFromValue(Type dataType, object value, bool inferLen, bool streamAllowed) {
switch (Type.GetTypeCode(dataType)) {
case TypeCode.Empty: throw ADP.InvalidDataType(TypeCode.Empty);
case TypeCode.Object:
if (dataType == typeof(System.Byte[])) {
// mdac 90455 must not default to image if inferLen is false ...
//
if (!inferLen || ((byte[]) value).Length <= TdsEnums.TYPE_SIZE_LIMIT) {
return MetaVarBinary;
}
else {
return MetaImage;
}
}
else if (dataType == typeof(System.Guid)) {
return MetaUniqueId;
}
else if (dataType == typeof(System.Object)) {
return MetaVariant;
} // check sql types now
else if (dataType == typeof(SqlBinary))
return MetaVarBinary;
else if (dataType == typeof(SqlBoolean))
return MetaBit;
else if (dataType == typeof(SqlByte))
return MetaTinyInt;
else if (dataType == typeof(SqlBytes))
return MetaVarBinary;
else if (dataType == typeof(SqlChars))
return MetaNVarChar; // MDAC 87587
else if (dataType == typeof(SqlDateTime))
return MetaDateTime;
else if (dataType == typeof(SqlDouble))
return MetaFloat;
else if (dataType == typeof(SqlGuid))
return MetaUniqueId;
else if (dataType == typeof(SqlInt16))
return MetaSmallInt;
else if (dataType == typeof(SqlInt32))
return MetaInt;
else if (dataType == typeof(SqlInt64))
return MetaBigInt;
else if (dataType == typeof(SqlMoney))
return MetaMoney;
else if (dataType == typeof(SqlDecimal))
return MetaDecimal;
else if (dataType == typeof(SqlSingle))
return MetaReal;
else if (dataType == typeof(SqlXml))
return MetaXml;
else if (dataType == typeof(SqlString)) {
return ((inferLen && !((SqlString)value).IsNull) ? PromoteStringType(((SqlString)value).Value) : MetaNVarChar); // MDAC 87587
}
else if (dataType == typeof(IEnumerable<DbDataRecord>) || dataType == typeof(DataTable)) {
return MetaTable;
} else if (dataType == typeof(TimeSpan)) {
return MetaTime;
}
else if (dataType == typeof(DateTimeOffset)) {
return MetaDateTimeOffset;
}
else {
// UDT ?
SqlUdtInfo attribs = SqlUdtInfo.TryGetFromType(dataType);
if (attribs != null) {
return MetaUdt;
}
if (streamAllowed) {
// Derived from Stream ?
if (typeof(Stream).IsAssignableFrom(dataType)) {
return MetaVarBinary;
}
// Derived from TextReader ?
if (typeof(TextReader).IsAssignableFrom(dataType)) {
return MetaNVarChar;
}
// Derived from XmlReader ?
if (typeof(System.Xml.XmlReader).IsAssignableFrom(dataType)) {
return MetaXml;
}
}
}
throw ADP.UnknownDataType(dataType);
case TypeCode.DBNull: throw ADP.InvalidDataType(TypeCode.DBNull);
case TypeCode.Boolean: return MetaBit;
case TypeCode.Char: throw ADP.InvalidDataType(TypeCode.Char);
case TypeCode.SByte: throw ADP.InvalidDataType(TypeCode.SByte);
case TypeCode.Byte: return MetaTinyInt;
case TypeCode.Int16: return MetaSmallInt;
case TypeCode.UInt16: throw ADP.InvalidDataType(TypeCode.UInt16);
case TypeCode.Int32: return MetaInt;
case TypeCode.UInt32: throw ADP.InvalidDataType(TypeCode.UInt32);
case TypeCode.Int64: return MetaBigInt;
case TypeCode.UInt64: throw ADP.InvalidDataType(TypeCode.UInt64);
case TypeCode.Single: return MetaReal;
case TypeCode.Double: return MetaFloat;
case TypeCode.Decimal: return MetaDecimal;
case TypeCode.DateTime: return MetaDateTime;
case TypeCode.String: return (inferLen ? PromoteStringType((string)value) : MetaNVarChar);
default: throw ADP.UnknownDataTypeCode(dataType, Type.GetTypeCode(dataType));
}
}
internal static object GetNullSqlValue(Type sqlType) {
if (sqlType == typeof(SqlSingle)) return SqlSingle.Null;
else if (sqlType == typeof(SqlString)) return SqlString.Null;
else if (sqlType == typeof(SqlDouble)) return SqlDouble.Null;
else if (sqlType == typeof(SqlBinary)) return SqlBinary.Null;
else if (sqlType == typeof(SqlGuid)) return SqlGuid.Null;
else if (sqlType == typeof(SqlBoolean)) return SqlBoolean.Null;
else if (sqlType == typeof(SqlByte)) return SqlByte.Null;
else if (sqlType == typeof(SqlInt16)) return SqlInt16.Null;
else if (sqlType == typeof(SqlInt32)) return SqlInt32.Null;
else if (sqlType == typeof(SqlInt64)) return SqlInt64.Null;
else if (sqlType == typeof(SqlDecimal)) return SqlDecimal.Null;
else if (sqlType == typeof(SqlDateTime)) return SqlDateTime.Null;
else if (sqlType == typeof(SqlMoney)) return SqlMoney.Null;
else if (sqlType == typeof(SqlXml)) return SqlXml.Null;
else if (sqlType == typeof(object)) return DBNull.Value;
else if (sqlType == typeof(IEnumerable<DbDataRecord>)) return DBNull.Value;
else if (sqlType == typeof(DataTable)) return DBNull.Value;
else if (sqlType == typeof(DateTime)) return DBNull.Value;
else if (sqlType == typeof(TimeSpan)) return DBNull.Value;
else if (sqlType == typeof(DateTimeOffset)) return DBNull.Value;
else {
Debug.Assert(false, "Unknown SqlType!");
return DBNull.Value;
}
}
internal static MetaType PromoteStringType(string s) {
int len = s.Length;
if ((len << 1) > TdsEnums.TYPE_SIZE_LIMIT) {
return MetaVarChar; // try as var char since we can send a 8K characters
}
return MetaNVarChar; // send 4k chars, but send as unicode
}
internal static object GetComValueFromSqlVariant(object sqlVal) {
object comVal = null;
if (ADP.IsNull(sqlVal))
return comVal;
if (sqlVal is SqlSingle)
comVal = ((SqlSingle)sqlVal).Value;
else if (sqlVal is SqlString)
comVal = ((SqlString)sqlVal).Value;
else if (sqlVal is SqlDouble)
comVal = ((SqlDouble)sqlVal).Value;
else if (sqlVal is SqlBinary)
comVal = ((SqlBinary)sqlVal).Value;
else if (sqlVal is SqlGuid)
comVal = ((SqlGuid)sqlVal).Value;
else if (sqlVal is SqlBoolean)
comVal = ((SqlBoolean)sqlVal).Value;
else if (sqlVal is SqlByte)
comVal = ((SqlByte)sqlVal).Value;
else if (sqlVal is SqlInt16)
comVal = ((SqlInt16)sqlVal).Value;
else if (sqlVal is SqlInt32)
comVal = ((SqlInt32)sqlVal).Value;
else if (sqlVal is SqlInt64)
comVal = ((SqlInt64)sqlVal).Value;
else if (sqlVal is SqlDecimal)
comVal = ((SqlDecimal)sqlVal).Value;
else if (sqlVal is SqlDateTime)
comVal = ((SqlDateTime)sqlVal).Value;
else if (sqlVal is SqlMoney)
comVal = ((SqlMoney)sqlVal).Value;
else if (sqlVal is SqlXml)
comVal = ((SqlXml)sqlVal).Value;
else
{
AssertIsUserDefinedTypeInstance(sqlVal, "unknown SqlType class stored in sqlVal");
}
return comVal;
}
/// <summary>
/// Assert that the supplied object is an instance of a SQL User-Defined Type (UDT).
/// </summary>
/// <param name="sqlValue">Object instance to be tested.</param>
/// <remarks>
/// This method is only compiled with debug builds, and it a helper method for the GetComValueFromSqlVariant method defined in this class.
///
/// The presence of the SqlUserDefinedTypeAttribute on the object's type
/// is used to determine if the object is a UDT instance (if present it is a UDT, else it is not).
/// </remarks>
/// <exception cref="NullReferenceException">
/// If sqlValue is null. Callers must ensure the object is non-null.
/// </exception>
[Conditional("DEBUG")]
private static void AssertIsUserDefinedTypeInstance(object sqlValue, string failedAssertMessage)
{
Type type = sqlValue.GetType();
Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute[] attributes = (Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute[])type.GetCustomAttributes(typeof(Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute), true);
Debug.Assert(attributes.Length > 0, failedAssertMessage);
}
// devnote: This method should not be used with SqlDbType.Date and SqlDbType.DateTime2.
// With these types the values should be used directly as CLR types instead of being converted to a SqlValue
internal static object GetSqlValueFromComVariant(object comVal) {
object sqlVal = null;
if ((null != comVal) && (DBNull.Value != comVal)) {
if (comVal is float)
sqlVal = new SqlSingle((float)comVal);
else if (comVal is string)
sqlVal = new SqlString((string)comVal);
else if (comVal is double)
sqlVal = new SqlDouble((double)comVal);
else if (comVal is System.Byte[])
sqlVal = new SqlBinary((byte[])comVal);
else if (comVal is System.Char)
sqlVal = new SqlString(((char)comVal).ToString());
else if (comVal is System.Char[])
sqlVal = new SqlChars((System.Char[])comVal);
else if (comVal is System.Guid)
sqlVal = new SqlGuid((Guid)comVal);
else if (comVal is bool)
sqlVal = new SqlBoolean((bool)comVal);
else if (comVal is byte)
sqlVal = new SqlByte((byte)comVal);
else if (comVal is Int16)
sqlVal = new SqlInt16((Int16)comVal);
else if (comVal is Int32)
sqlVal = new SqlInt32((Int32)comVal);
else if (comVal is Int64)
sqlVal = new SqlInt64((Int64)comVal);
else if (comVal is Decimal)
sqlVal = new SqlDecimal((Decimal)comVal);
else if (comVal is DateTime) {
// devnote: Do not use with SqlDbType.Date and SqlDbType.DateTime2. See comment at top of method.
sqlVal = new SqlDateTime((DateTime)comVal);
} else if (comVal is XmlReader)
sqlVal = new SqlXml((XmlReader)comVal);
else if (comVal is TimeSpan || comVal is DateTimeOffset)
sqlVal = comVal;
#if DEBUG
else
Debug.Assert(false, "unknown SqlType class stored in sqlVal");
#endif
}
return sqlVal;
}
internal static SqlDbType GetSqlDbTypeFromOleDbType(short dbType, string typeName) {
SqlDbType sqlType = SqlDbType.Variant;
switch ((OleDbType)dbType) {
case OleDbType.BigInt:
sqlType = SqlDbType.BigInt;
break;
case OleDbType.Boolean:
sqlType = SqlDbType.Bit;
break;
case OleDbType.Char:
case OleDbType.VarChar:
// these guys are ambiguous - server sends over DBTYPE_STR in both cases
sqlType = (typeName == MetaTypeName.CHAR) ? SqlDbType.Char : SqlDbType.VarChar;
break;
case OleDbType.Currency:
sqlType = (typeName == MetaTypeName.SMALLMONEY) ? SqlDbType.SmallMoney : SqlDbType.Money;
break;
case OleDbType.Date:
case OleDbType.DBTimeStamp:
case OleDbType.Filetime:
switch (typeName) {
case MetaTypeName.SMALLDATETIME:
sqlType = SqlDbType.SmallDateTime;
break;
case MetaTypeName.DATETIME2:
sqlType = SqlDbType.DateTime2;
break;
default:
sqlType = SqlDbType.DateTime;
break;
}
break;
case OleDbType.Decimal:
case OleDbType.Numeric:
sqlType = SqlDbType.Decimal;
break;
case OleDbType.Double:
sqlType = SqlDbType.Float;
break;
case OleDbType.Guid:
sqlType = SqlDbType.UniqueIdentifier;
break;
case OleDbType.Integer:
sqlType = SqlDbType.Int;
break;
case OleDbType.LongVarBinary:
sqlType = SqlDbType.Image;
break;
case OleDbType.LongVarChar:
sqlType = SqlDbType.Text;
break;
case OleDbType.LongVarWChar:
sqlType = SqlDbType.NText;
break;
case OleDbType.Single:
sqlType = SqlDbType.Real;
break;
case OleDbType.SmallInt:
case OleDbType.UnsignedSmallInt:
sqlType = SqlDbType.SmallInt;
break;
case OleDbType.TinyInt:
case OleDbType.UnsignedTinyInt:
sqlType = SqlDbType.TinyInt;
break;
case OleDbType.VarBinary:
case OleDbType.Binary:
sqlType = (typeName == MetaTypeName.BINARY) ? SqlDbType.Binary : SqlDbType.VarBinary;
break;
case OleDbType.Variant:
sqlType = SqlDbType.Variant;
break;
case OleDbType.VarWChar:
case OleDbType.WChar:
case OleDbType.BSTR:
// these guys are ambiguous - server sends over DBTYPE_WSTR in both cases
// BSTR is always assumed to be NVARCHAR
sqlType = (typeName == MetaTypeName.NCHAR) ? SqlDbType.NChar : SqlDbType.NVarChar;
break;
case OleDbType.DBDate: // Date
sqlType = SqlDbType.Date;
break;
case (OleDbType)132: // Udt
sqlType = SqlDbType.Udt;
break;
case (OleDbType)141: // Xml
sqlType = SqlDbType.Xml;
break;
case (OleDbType)145: // Time
sqlType = SqlDbType.Time;
break;
case (OleDbType)146: // DateTimeOffset
sqlType = SqlDbType.DateTimeOffset;
break;
//
default:
break; // no direct mapping, just use SqlDbType.Variant;
}
return sqlType;
}
internal static MetaType GetSqlDataType(int tdsType, UInt32 userType, int length) {
switch (tdsType) {
case TdsEnums.SQLMONEYN: return ((4 == length) ? MetaSmallMoney : MetaMoney);
case TdsEnums.SQLDATETIMN: return ((4 == length) ? MetaSmallDateTime : MetaDateTime);
case TdsEnums.SQLINTN: return ((4 <= length) ? ((4 == length) ? MetaInt : MetaBigInt) : ((2 == length) ? MetaSmallInt : MetaTinyInt));
case TdsEnums.SQLFLTN: return ((4 == length) ? MetaReal : MetaFloat);
case TdsEnums.SQLTEXT: return MetaText;
case TdsEnums.SQLVARBINARY: return MetaSmallVarBinary;
case TdsEnums.SQLBIGVARBINARY: return MetaVarBinary;
case TdsEnums.SQLVARCHAR: //goto TdsEnums.SQLBIGVARCHAR;
case TdsEnums.SQLBIGVARCHAR: return MetaVarChar;
case TdsEnums.SQLBINARY: //goto TdsEnums.SQLBIGBINARY;
case TdsEnums.SQLBIGBINARY: return ((TdsEnums.SQLTIMESTAMP == userType) ? MetaTimestamp : MetaBinary);
case TdsEnums.SQLIMAGE: return MetaImage;
case TdsEnums.SQLCHAR: //goto TdsEnums.SQLBIGCHAR;
case TdsEnums.SQLBIGCHAR: return MetaChar;
case TdsEnums.SQLINT1: return MetaTinyInt;
case TdsEnums.SQLBIT: //goto TdsEnums.SQLBITN;
case TdsEnums.SQLBITN: return MetaBit;
case TdsEnums.SQLINT2: return MetaSmallInt;
case TdsEnums.SQLINT4: return MetaInt;
case TdsEnums.SQLINT8: return MetaBigInt;
case TdsEnums.SQLMONEY: return MetaMoney;
case TdsEnums.SQLDATETIME: return MetaDateTime;
case TdsEnums.SQLFLT8: return MetaFloat;
case TdsEnums.SQLFLT4: return MetaReal;
case TdsEnums.SQLMONEY4: return MetaSmallMoney;
case TdsEnums.SQLDATETIM4: return MetaSmallDateTime;
case TdsEnums.SQLDECIMALN: //goto TdsEnums.SQLNUMERICN;
case TdsEnums.SQLNUMERICN: return MetaDecimal;
case TdsEnums.SQLUNIQUEID: return MetaUniqueId ;
case TdsEnums.SQLNCHAR: return MetaNChar;
case TdsEnums.SQLNVARCHAR: return MetaNVarChar;
case TdsEnums.SQLNTEXT: return MetaNText;
case TdsEnums.SQLVARIANT: return MetaVariant;
case TdsEnums.SQLUDT: return MetaUdt;
case TdsEnums.SQLXMLTYPE: return MetaXml;
case TdsEnums.SQLTABLE: return MetaTable;
case TdsEnums.SQLDATE: return MetaDate;
case TdsEnums.SQLTIME: return MetaTime;
case TdsEnums.SQLDATETIME2: return MetaDateTime2;
case TdsEnums.SQLDATETIMEOFFSET: return MetaDateTimeOffset;
case TdsEnums.SQLVOID:
default:
Debug.Assert(false, "Unknown type " + tdsType.ToString(CultureInfo.InvariantCulture));
throw SQL.InvalidSqlDbType((SqlDbType)tdsType);
}// case
}
internal static MetaType GetDefaultMetaType() {
return MetaNVarChar;
}
// Converts an XmlReader into String
internal static String GetStringFromXml(XmlReader xmlreader) {
SqlXml sxml = new SqlXml(xmlreader);
return sxml.Value;
}
private static readonly MetaType MetaBigInt = new MetaType
(19, 255, 8, true, false, false, TdsEnums.SQLINT8, TdsEnums.SQLINTN, MetaTypeName.BIGINT, typeof(System.Int64), typeof(SqlInt64), SqlDbType.BigInt, DbType.Int64, 0);
private static readonly MetaType MetaFloat = new MetaType
(15, 255, 8, true, false, false, TdsEnums.SQLFLT8, TdsEnums.SQLFLTN, MetaTypeName.FLOAT, typeof(System.Double), typeof(SqlDouble), SqlDbType.Float, DbType.Double, 0);
private static readonly MetaType MetaReal = new MetaType
(7, 255, 4, true, false, false, TdsEnums.SQLFLT4, TdsEnums.SQLFLTN, MetaTypeName.REAL, typeof(System.Single), typeof(SqlSingle), SqlDbType.Real, DbType.Single, 0);
// MetaBinary has two bytes of properties for binary and varbinary
// 2 byte maxlen
private static readonly MetaType MetaBinary = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLBIGBINARY, TdsEnums.SQLBIGBINARY, MetaTypeName.BINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Binary, DbType.Binary, 2);
// syntatic sugar for the user...timestamps are 8-byte fixed length binary columns
private static readonly MetaType MetaTimestamp = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLBIGBINARY, TdsEnums.SQLBIGBINARY, MetaTypeName.TIMESTAMP, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Timestamp, DbType.Binary, 2);
internal static readonly MetaType MetaVarBinary = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLBIGVARBINARY, TdsEnums.SQLBIGVARBINARY, MetaTypeName.VARBINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.VarBinary, DbType.Binary, 2);
internal static readonly MetaType MetaMaxVarBinary = new MetaType
(255, 255, -1, false, true, true, TdsEnums.SQLBIGVARBINARY, TdsEnums.SQLBIGVARBINARY, MetaTypeName.VARBINARY, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.VarBinary, DbType.Binary, 2);
// HACK!!! We have an internal type for smallvarbinarys stored on TdsEnums. We
// store on TdsEnums instead of SqlDbType because we do not want to expose
// this type to the user!
private static readonly MetaType MetaSmallVarBinary = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLVARBINARY, TdsEnums.SQLBIGBINARY, ADP.StrEmpty, typeof(System.Byte[]), typeof(SqlBinary), TdsEnums.SmallVarBinary, DbType.Binary, 2);
internal static readonly MetaType MetaImage = new MetaType
(255, 255, -1, false, true, false, TdsEnums.SQLIMAGE, TdsEnums.SQLIMAGE, MetaTypeName.IMAGE, typeof(System.Byte[]), typeof(SqlBinary), SqlDbType.Image, DbType.Binary, 0);
private static readonly MetaType MetaBit = new MetaType
(255, 255, 1, true, false, false, TdsEnums.SQLBIT, TdsEnums.SQLBITN, MetaTypeName.BIT, typeof(System.Boolean), typeof(SqlBoolean), SqlDbType.Bit, DbType.Boolean, 0);
private static readonly MetaType MetaTinyInt = new MetaType
(3, 255, 1, true, false, false, TdsEnums.SQLINT1, TdsEnums.SQLINTN, MetaTypeName.TINYINT, typeof(System.Byte), typeof(SqlByte), SqlDbType.TinyInt, DbType.Byte, 0);
private static readonly MetaType MetaSmallInt = new MetaType
(5, 255, 2, true, false, false, TdsEnums.SQLINT2, TdsEnums.SQLINTN, MetaTypeName.SMALLINT, typeof(System.Int16), typeof(SqlInt16), SqlDbType.SmallInt, DbType.Int16, 0);
private static readonly MetaType MetaInt = new MetaType
(10, 255, 4, true, false, false, TdsEnums.SQLINT4, TdsEnums.SQLINTN, MetaTypeName.INT, typeof(System.Int32), typeof(SqlInt32), SqlDbType.Int, DbType.Int32, 0);
// MetaVariant has seven bytes of properties for MetaChar and MetaVarChar
// 5 byte tds collation
// 2 byte maxlen
private static readonly MetaType MetaChar = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLBIGCHAR, TdsEnums.SQLBIGCHAR, MetaTypeName.CHAR, typeof(System.String), typeof(SqlString), SqlDbType.Char, DbType.AnsiStringFixedLength, 7);
private static readonly MetaType MetaVarChar = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLBIGVARCHAR, TdsEnums.SQLBIGVARCHAR, MetaTypeName.VARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.VarChar, DbType.AnsiString, 7);
internal static readonly MetaType MetaMaxVarChar = new MetaType
(255, 255, -1, false, true, true, TdsEnums.SQLBIGVARCHAR, TdsEnums.SQLBIGVARCHAR, MetaTypeName.VARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.VarChar, DbType.AnsiString, 7);
internal static readonly MetaType MetaText = new MetaType
(255, 255, -1, false, true, false, TdsEnums.SQLTEXT, TdsEnums.SQLTEXT, MetaTypeName.TEXT, typeof(System.String), typeof(SqlString), SqlDbType.Text, DbType.AnsiString, 0);
// MetaVariant has seven bytes of properties for MetaNChar and MetaNVarChar
// 5 byte tds collation
// 2 byte maxlen
private static readonly MetaType MetaNChar = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLNCHAR, TdsEnums.SQLNCHAR, MetaTypeName.NCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NChar, DbType.StringFixedLength, 7);
internal static readonly MetaType MetaNVarChar = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLNVARCHAR, TdsEnums.SQLNVARCHAR, MetaTypeName.NVARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NVarChar, DbType.String, 7);
internal static readonly MetaType MetaMaxNVarChar = new MetaType
(255, 255, -1, false, true, true, TdsEnums.SQLNVARCHAR, TdsEnums.SQLNVARCHAR, MetaTypeName.NVARCHAR, typeof(System.String), typeof(SqlString), SqlDbType.NVarChar, DbType.String, 7);
internal static readonly MetaType MetaNText = new MetaType
(255, 255, -1, false, true, false, TdsEnums.SQLNTEXT, TdsEnums.SQLNTEXT, MetaTypeName.NTEXT, typeof(System.String), typeof(SqlString), SqlDbType.NText, DbType.String, 7);
// MetaVariant has two bytes of properties for numeric/decimal types
// 1 byte precision
// 1 byte scale
internal static readonly MetaType MetaDecimal = new MetaType
(38, 4, 17, true, false, false, TdsEnums.SQLNUMERICN, TdsEnums.SQLNUMERICN, MetaTypeName.DECIMAL, typeof(System.Decimal), typeof(SqlDecimal), SqlDbType.Decimal, DbType.Decimal, 2);
internal static readonly MetaType MetaXml = new MetaType
(255, 255, -1, false, true, true, TdsEnums.SQLXMLTYPE, TdsEnums.SQLXMLTYPE, MetaTypeName.XML, typeof(System.String), typeof(SqlXml), SqlDbType.Xml, DbType.Xml, 0);
private static readonly MetaType MetaDateTime = new MetaType
(23, 3, 8, true, false, false, TdsEnums.SQLDATETIME, TdsEnums.SQLDATETIMN, MetaTypeName.DATETIME, typeof(System.DateTime), typeof(SqlDateTime), SqlDbType.DateTime, DbType.DateTime, 0);
private static readonly MetaType MetaSmallDateTime = new MetaType
(16, 0, 4, true, false, false, TdsEnums.SQLDATETIM4, TdsEnums.SQLDATETIMN, MetaTypeName.SMALLDATETIME, typeof(System.DateTime), typeof(SqlDateTime), SqlDbType.SmallDateTime, DbType.DateTime, 0);
private static readonly MetaType MetaMoney = new MetaType
(19, 255, 8, true, false, false, TdsEnums.SQLMONEY, TdsEnums.SQLMONEYN, MetaTypeName.MONEY, typeof(System.Decimal), typeof(SqlMoney), SqlDbType.Money, DbType.Currency, 0);
private static readonly MetaType MetaSmallMoney = new MetaType
(10, 255, 4, true, false, false, TdsEnums.SQLMONEY4, TdsEnums.SQLMONEYN, MetaTypeName.SMALLMONEY, typeof(System.Decimal), typeof(SqlMoney), SqlDbType.SmallMoney, DbType.Currency, 0);
private static readonly MetaType MetaUniqueId = new MetaType
(255, 255, 16, true, false, false, TdsEnums.SQLUNIQUEID, TdsEnums.SQLUNIQUEID, MetaTypeName.ROWGUID, typeof(System.Guid), typeof(SqlGuid), SqlDbType.UniqueIdentifier, DbType.Guid, 0);
private static readonly MetaType MetaVariant = new MetaType
(255, 255, -1, true, false, false, TdsEnums.SQLVARIANT, TdsEnums.SQLVARIANT, MetaTypeName.VARIANT, typeof(System.Object), typeof(System.Object), SqlDbType.Variant, DbType.Object, 0);
internal static readonly MetaType MetaUdt = new MetaType
(255, 255, -1, false, false, true, TdsEnums.SQLUDT, TdsEnums.SQLUDT, MetaTypeName.UDT, typeof(System.Object), typeof(System.Object), SqlDbType.Udt, DbType.Object, 0);
private static readonly MetaType MetaMaxUdt = new MetaType
(255, 255, -1, false, true, true, TdsEnums.SQLUDT, TdsEnums.SQLUDT, MetaTypeName.UDT, typeof(System.Object), typeof(System.Object), SqlDbType.Udt, DbType.Object, 0);
private static readonly MetaType MetaTable = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLTABLE, TdsEnums.SQLTABLE, MetaTypeName.TABLE, typeof(IEnumerable<DbDataRecord>), typeof(IEnumerable<DbDataRecord>), SqlDbType.Structured, DbType.Object, 0);
//
private static readonly MetaType MetaSUDT = new MetaType
(255, 255, -1, false, false, false, TdsEnums.SQLVOID, TdsEnums.SQLVOID, "", typeof(MSS.SqlDataRecord), typeof(MSS.SqlDataRecord), SqlDbType.Structured, DbType.Object, 0);
private static readonly MetaType MetaDate = new MetaType
(255, 255, 3, true, false, false, TdsEnums.SQLDATE, TdsEnums.SQLDATE, MetaTypeName.DATE, typeof(System.DateTime), typeof(System.DateTime), SqlDbType.Date, DbType.Date, 0);
internal static readonly MetaType MetaTime = new MetaType
(255, 7, -1, false, false, false, TdsEnums.SQLTIME, TdsEnums.SQLTIME, MetaTypeName.TIME, typeof(System.TimeSpan), typeof(System.TimeSpan), SqlDbType.Time, DbType.Time, 1);
private static readonly MetaType MetaDateTime2 = new MetaType
(255, 7, -1, false, false, false, TdsEnums.SQLDATETIME2, TdsEnums.SQLDATETIME2, MetaTypeName.DATETIME2, typeof(System.DateTime), typeof(System.DateTime), SqlDbType.DateTime2, DbType.DateTime2, 1);
internal static readonly MetaType MetaDateTimeOffset = new MetaType
(255, 7, -1, false, false, false, TdsEnums.SQLDATETIMEOFFSET, TdsEnums.SQLDATETIMEOFFSET, MetaTypeName.DATETIMEOFFSET, typeof(System.DateTimeOffset), typeof(System.DateTimeOffset), SqlDbType.DateTimeOffset, DbType.DateTimeOffset, 1);
public static TdsDateTime FromDateTime(DateTime dateTime, byte cb) {
SqlDateTime sqlDateTime;
TdsDateTime tdsDateTime = new TdsDateTime();
Debug.Assert(cb == 8 || cb == 4, "Invalid date time size!");
if (cb == 8) {
sqlDateTime = new SqlDateTime(dateTime);
tdsDateTime.time = sqlDateTime.TimeTicks;
}
else {
// note that smalldatetime is days&minutes.
// Adding 30 seconds ensures proper roundup if the seconds are >= 30
// The AddSeconds function handles eventual carryover
sqlDateTime = new SqlDateTime(dateTime.AddSeconds(30));
tdsDateTime.time = sqlDateTime.TimeTicks / SqlDateTime.SQLTicksPerMinute;
}
tdsDateTime.days = sqlDateTime.DayTicks;
return tdsDateTime;
}
public static DateTime ToDateTime(int sqlDays, int sqlTime, int length) {
if (length == 4) {
return new SqlDateTime(sqlDays, sqlTime * SqlDateTime.SQLTicksPerMinute).Value;
}
else {
Debug.Assert(length == 8, "invalid length for DateTime");
return new SqlDateTime(sqlDays, sqlTime).Value;
}
}
internal static int GetTimeSizeFromScale(byte scale)
{
// Disable the assert here since we do not properly handle wrong Scale value on the parameter,
// see VSTFDEVDIV 795578 for more details.
// But, this assert is still valid when we receive Time/DateTime2/DateTimeOffset scale from server over TDS,
// so it is moved to TdsParser.CommonProcessMetaData.
// For new scenarios, assert and/or validate the scale value before this call!
// Debug.Assert(0 <= scale && scale <= 7);
if (scale <= 2)
return 3;
if (scale <= 4)
return 4;
return 5;
}
//
// please leave string sorted alphabetically
// note that these names should only be used in the context of parameters. We always send over BIG* and nullable types for SQL Server
//
private static class MetaTypeName {
public const string BIGINT = "bigint";
public const string BINARY = "binary";
public const string BIT = "bit";
public const string CHAR = "char";
public const string DATETIME = "datetime";
public const string DECIMAL = "decimal";
public const string FLOAT = "float";
public const string IMAGE = "image";
public const string INT = "int";
public const string MONEY = "money";
public const string NCHAR = "nchar";
public const string NTEXT = "ntext";
public const string NVARCHAR = "nvarchar";
public const string REAL = "real";
public const string ROWGUID = "uniqueidentifier";
public const string SMALLDATETIME = "smalldatetime";
public const string SMALLINT = "smallint";
public const string SMALLMONEY = "smallmoney";
public const string TEXT = "text";
public const string TIMESTAMP = "timestamp";
public const string TINYINT = "tinyint";
public const string UDT = "udt";
public const string VARBINARY = "varbinary";
public const string VARCHAR = "varchar";
public const string VARIANT = "sql_variant";
public const string XML = "xml";
public const string TABLE = "table";
public const string DATE = "date";
public const string TIME = "time";
public const string DATETIME2 = "datetime2";
public const string DATETIMEOFFSET = "datetimeoffset";
}
}
//
// note: it is the client's responsibility to know what size date time he is working with
//
internal struct TdsDateTime {
public int days; // offset in days from 1/1/1900
// private UInt32 time; // if smalldatetime, this is # of minutes since midnight
// otherwise: # of 1/300th of a second since midnight
public int time; //
}
}
|