private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col) { byte byteLen; UInt32 userType; // read user type - 4 bytes Yukon, 2 backwards if (!stateObj.TryReadUInt32(out userType)) { return false; } // read flags and set appropriate flags in structure byte flags; if (!stateObj.TryReadByte(out flags)) { return false; } col.updatability = (byte)((flags & TdsEnums.Updatability) >> 2); col.isNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable)); col.isIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity)); // read second byte of column metadata flags if (!stateObj.TryReadByte(out flags)) { return false; } byte tdsType; if (!stateObj.TryReadByte(out tdsType)) { return false; } if (tdsType == TdsEnums.SQLXMLTYPE) col.length = TdsEnums.SQL_USHORTVARMAXLEN; //Use the same length as other plp datatypes else if (IsVarTimeTds(tdsType)) col.length = 0; // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN else if (tdsType == TdsEnums.SQLDATE) { col.length = 3; } else { if (!TryGetTokenLength(tdsType, stateObj, out col.length)) { return false; } } col.metaType = MetaType.GetSqlDataType(tdsType, userType, col.length); col.type = col.metaType.SqlDbType; col.tdsType = (col.isNullable ? col.metaType.NullableType : col.metaType.TDSType); { if (TdsEnums.SQLUDT == tdsType) { throw SQL.UnsupportedFeatureAndToken(_connHandler, SqlDbType.Udt.ToString()); } if (col.length == TdsEnums.SQL_USHORTVARMAXLEN) { Debug.Assert(tdsType == TdsEnums.SQLXMLTYPE || tdsType == TdsEnums.SQLBIGVARCHAR || tdsType == TdsEnums.SQLBIGVARBINARY || tdsType == TdsEnums.SQLNVARCHAR || tdsType == TdsEnums.SQLUDT, "Invalid streaming datatype"); col.metaType = MetaType.GetMaxMetaTypeFromMetaType(col.metaType); Debug.Assert(col.metaType.IsLong, "Max datatype not IsLong"); col.length = Int32.MaxValue; if (tdsType == TdsEnums.SQLXMLTYPE) { byte schemapresent; if (!stateObj.TryReadByte(out schemapresent)) { return false; } if ((schemapresent & 1) != 0) { if (!stateObj.TryReadByte(out byteLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionDatabase)) { return false; } } if (!stateObj.TryReadByte(out byteLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionOwningSchema)) { return false; } } short shortLen; if (!stateObj.TryReadInt16(out shortLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(shortLen, out col.xmlSchemaCollectionName)) { return false; } } } } } } if (col.type == SqlDbType.Decimal) { if (!stateObj.TryReadByte(out col.precision)) { return false; } if (!stateObj.TryReadByte(out col.scale)) { return false; } } if (col.metaType.IsVarTime) { if (!stateObj.TryReadByte(out col.scale)) { return false; } Debug.Assert(0 <= col.scale && col.scale <= 7); // calculate actual column length here switch (col.metaType.SqlDbType) { case SqlDbType.Time: col.length = MetaType.GetTimeSizeFromScale(col.scale); break; case SqlDbType.DateTime2: // Date in number of days (3 bytes) + time col.length = 3 + MetaType.GetTimeSizeFromScale(col.scale); break; case SqlDbType.DateTimeOffset: // Date in days (3 bytes) + offset in minutes (2 bytes) + time col.length = 5 + MetaType.GetTimeSizeFromScale(col.scale); break; default: Debug.Assert(false, "Unknown VariableTime type!"); break; } } // read the collation for 7.x servers if (col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE)) { if (!TryProcessCollation(stateObj, out col.collation)) { return false; } int codePage = GetCodePage(col.collation, stateObj); if (codePage == _defaultCodePage) { col.codePage = _defaultCodePage; col.encoding = _defaultEncoding; } else { col.codePage = codePage; col.encoding = System.Text.Encoding.GetEncoding(col.codePage); } } if (col.metaType.IsLong && !col.metaType.IsPlp) { int unusedLen = 0xFFFF; //We ignore this value if (!TryProcessOneTable(stateObj, ref unusedLen, out col.multiPartTableName)) { return false; } } if (!stateObj.TryReadByte(out byteLen)) { return false; } if (!stateObj.TryReadString(byteLen, out col.column)) { return false; } // We get too many DONE COUNTs from the server, causing too meany StatementCompleted event firings. // We only need to fire this event when we actually have a meta data stream with 0 or more rows. stateObj._receivedColMetaData = true; return true; }
internal bool TryReadSqlValueInternal(SqlBuffer value, byte tdsType, int length, TdsParserStateObject stateObj) { switch (tdsType) { case TdsEnums.SQLBIT: case TdsEnums.SQLBITN: Debug.Assert(length == 1, "invalid length for SqlBoolean type!"); byte byteValue; if (!stateObj.TryReadByte(out byteValue)) { return false; } value.Boolean = (byteValue != 0); break; case TdsEnums.SQLINTN: if (length == 1) { goto case TdsEnums.SQLINT1; } else if (length == 2) { goto case TdsEnums.SQLINT2; } else if (length == 4) { goto case TdsEnums.SQLINT4; } else { goto case TdsEnums.SQLINT8; } case TdsEnums.SQLINT1: Debug.Assert(length == 1, "invalid length for SqlByte type!"); if (!stateObj.TryReadByte(out byteValue)) { return false; } value.Byte = byteValue; break; case TdsEnums.SQLINT2: Debug.Assert(length == 2, "invalid length for SqlInt16 type!"); short shortValue; if (!stateObj.TryReadInt16(out shortValue)) { return false; } value.Int16 = shortValue; break; case TdsEnums.SQLINT4: Debug.Assert(length == 4, "invalid length for SqlInt32 type!"); int intValue; if (!stateObj.TryReadInt32(out intValue)) { return false; } value.Int32 = intValue; break; case TdsEnums.SQLINT8: Debug.Assert(length == 8, "invalid length for SqlInt64 type!"); long longValue; if (!stateObj.TryReadInt64(out longValue)) { return false; } value.Int64 = longValue; break; case TdsEnums.SQLFLTN: if (length == 4) { goto case TdsEnums.SQLFLT4; } else { goto case TdsEnums.SQLFLT8; } case TdsEnums.SQLFLT4: Debug.Assert(length == 4, "invalid length for SqlSingle type!"); float singleValue; if (!stateObj.TryReadSingle(out singleValue)) { return false; } value.Single = singleValue; break; case TdsEnums.SQLFLT8: Debug.Assert(length == 8, "invalid length for SqlDouble type!"); double doubleValue; if (!stateObj.TryReadDouble(out doubleValue)) { return false; } value.Double = doubleValue; break; case TdsEnums.SQLMONEYN: if (length == 4) { goto case TdsEnums.SQLMONEY4; } else { goto case TdsEnums.SQLMONEY; } case TdsEnums.SQLMONEY: { int mid; uint lo; if (!stateObj.TryReadInt32(out mid)) { return false; } if (!stateObj.TryReadUInt32(out lo)) { return false; } long l = (((long)mid) << 0x20) + ((long)lo); value.SetToMoney(l); break; } case TdsEnums.SQLMONEY4: if (!stateObj.TryReadInt32(out intValue)) { return false; } value.SetToMoney(intValue); break; case TdsEnums.SQLDATETIMN: if (length == 4) { goto case TdsEnums.SQLDATETIM4; } else { goto case TdsEnums.SQLDATETIME; } case TdsEnums.SQLDATETIM4: ushort daypartShort, timepartShort; if (!stateObj.TryReadUInt16(out daypartShort)) { return false; } if (!stateObj.TryReadUInt16(out timepartShort)) { return false; } value.SetToDateTime(daypartShort, timepartShort * SqlDateTime.SQLTicksPerMinute); break; case TdsEnums.SQLDATETIME: int daypart; uint timepart; if (!stateObj.TryReadInt32(out daypart)) { return false; } if (!stateObj.TryReadUInt32(out timepart)) { return false; } value.SetToDateTime(daypart, (int)timepart); break; case TdsEnums.SQLUNIQUEID: { Debug.Assert(length == 16, "invalid length for SqlGuid type!"); byte[] b = new byte[length]; if (!stateObj.TryReadByteArray(b, 0, length)) { return false; } value.SqlGuid = new SqlGuid(b, true); // doesn't copy the byte array break; } case TdsEnums.SQLBINARY: case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLVARBINARY: case TdsEnums.SQLIMAGE: { // Note: Better not come here with plp data!! Debug.Assert(length <= TdsEnums.MAXSIZE); byte[] b = new byte[length]; if (!stateObj.TryReadByteArray(b, 0, length)) { return false; } value.SqlBinary = new SqlBinary(b, true); // doesn't copy the byte array break; } case TdsEnums.SQLVARIANT: if (!TryReadSqlVariant(value, length, stateObj)) { return false; } break; default: Debug.Assert(false, "Unknown SqlType!" + tdsType.ToString(CultureInfo.InvariantCulture)); break; } // switch return true; }
internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, out SqlReturnValue returnValue) { returnValue = null; SqlReturnValue rec = new SqlReturnValue(); rec.length = length; // In Yukon this length is -1 ushort parameterIndex; if (!stateObj.TryReadUInt16(out parameterIndex)) { return false; } byte len; if (!stateObj.TryReadByte(out len)) { // Length of parameter name return false; } if (len > 0) { if (!stateObj.TryReadString(len, out rec.parameter)) { return false; } } // read status and ignore byte ignored; if (!stateObj.TryReadByte(out ignored)) { return false; } UInt32 userType; // read user type - 4 bytes Yukon, 2 backwards if (!stateObj.TryReadUInt32(out userType)) { return false; } // read off the flags ushort ignoredFlags; if (!stateObj.TryReadUInt16(out ignoredFlags)) { return false; } // read the type byte tdsType; if (!stateObj.TryReadByte(out tdsType)) { return false; } // read the MaxLen // For xml datatpyes, there is no tokenLength int tdsLen; if (tdsType == TdsEnums.SQLXMLTYPE) { tdsLen = TdsEnums.SQL_USHORTVARMAXLEN; } else if (IsVarTimeTds(tdsType)) tdsLen = 0; // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN else if (tdsType == TdsEnums.SQLDATE) { tdsLen = 3; } else { if (!TryGetTokenLength(tdsType, stateObj, out tdsLen)) { return false; } } rec.metaType = MetaType.GetSqlDataType(tdsType, userType, tdsLen); rec.type = rec.metaType.SqlDbType; // always use the nullable type for parameters if Shiloh or later // Sphinx sometimes sends fixed length return values rec.tdsType = rec.metaType.NullableType; rec.isNullable = true; if (tdsLen == TdsEnums.SQL_USHORTVARMAXLEN) { rec.metaType = MetaType.GetMaxMetaTypeFromMetaType(rec.metaType); } if (rec.type == SqlDbType.Decimal) { if (!stateObj.TryReadByte(out rec.precision)) { return false; } if (!stateObj.TryReadByte(out rec.scale)) { return false; } } if (rec.metaType.IsVarTime) { if (!stateObj.TryReadByte(out rec.scale)) { return false; } } if (tdsType == TdsEnums.SQLUDT) { throw SQL.UnsupportedFeatureAndToken(_connHandler, SqlDbType.Udt.ToString()); } if (rec.type == SqlDbType.Xml) { // Read schema info byte schemapresent; if (!stateObj.TryReadByte(out schemapresent)) { return false; } if ((schemapresent & 1) != 0) { if (!stateObj.TryReadByte(out len)) { return false; } if (len != 0) { if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionDatabase)) { return false; } } if (!stateObj.TryReadByte(out len)) { return false; } if (len != 0) { if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionOwningSchema)) { return false; } } short slen; if (!stateObj.TryReadInt16(out slen)) { return false; } if (slen != 0) { if (!stateObj.TryReadString(slen, out rec.xmlSchemaCollectionName)) { return false; } } } } else if (rec.metaType.IsCharType) { // read the collation for 8.x servers if (!TryProcessCollation(stateObj, out rec.collation)) { return false; } int codePage = GetCodePage(rec.collation, stateObj); // if the column lcid is the same as the default, use the default encoder if (codePage == _defaultCodePage) { rec.codePage = _defaultCodePage; rec.encoding = _defaultEncoding; } else { rec.codePage = codePage; rec.encoding = System.Text.Encoding.GetEncoding(rec.codePage); } } // for now we coerce return values into a SQLVariant, not good... bool isNull = false; ulong valLen; if (!TryProcessColumnHeaderNoNBC(rec, stateObj, out isNull, out valLen)) { return false; } // always read as sql types Debug.Assert(valLen < (ulong)(Int32.MaxValue), "ProcessReturnValue received data size > 2Gb"); int intlen = valLen > (ulong)(Int32.MaxValue) ? Int32.MaxValue : (int)valLen; if (rec.metaType.IsPlp) { intlen = Int32.MaxValue; // If plp data, read it all } if (isNull) { GetNullSqlValue(rec.value, rec); } else { if (!TryReadSqlValue(rec.value, rec, intlen, stateObj)) { return false; } } returnValue = rec; return true; }
private bool TryProcessTypeInfo (TdsParserStateObject stateObj, SqlMetaDataPriv col, UInt32 userType) { byte byteLen; byte tdsType; if (!stateObj.TryReadByte(out tdsType)) { return false; } if (tdsType == TdsEnums.SQLXMLTYPE) col.length = TdsEnums.SQL_USHORTVARMAXLEN; //Use the same length as other plp datatypes else if (IsVarTimeTds(tdsType)) col.length = 0; // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN else if (tdsType == TdsEnums.SQLDATE) { col.length = 3; } else { if (!TryGetTokenLength(tdsType, stateObj, out col.length)) { return false; } } col.metaType = MetaType.GetSqlDataType(tdsType, userType, col.length); col.type = col.metaType.SqlDbType; // If sphinx, do not change to nullable type if (_isShiloh) col.tdsType = (col.isNullable ? col.metaType.NullableType : col.metaType.TDSType); else col.tdsType = tdsType; if (_isYukon) { if (TdsEnums.SQLUDT == tdsType) { if (!TryProcessUDTMetaData((SqlMetaDataPriv) col, stateObj)) { return false; } } if (col.length == TdsEnums.SQL_USHORTVARMAXLEN) { Debug.Assert(tdsType == TdsEnums.SQLXMLTYPE || tdsType == TdsEnums.SQLBIGVARCHAR || tdsType == TdsEnums.SQLBIGVARBINARY || tdsType == TdsEnums.SQLNVARCHAR || tdsType == TdsEnums.SQLUDT, "Invalid streaming datatype"); col.metaType = MetaType.GetMaxMetaTypeFromMetaType(col.metaType); Debug.Assert(col.metaType.IsLong, "Max datatype not IsLong"); col.length = Int32.MaxValue; if (tdsType == TdsEnums.SQLXMLTYPE) { byte schemapresent; if (!stateObj.TryReadByte(out schemapresent)) { return false; } if ((schemapresent & 1) != 0) { if (!stateObj.TryReadByte(out byteLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionDatabase)) { return false; } } if (!stateObj.TryReadByte(out byteLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionOwningSchema)) { return false; } } short shortLen; if (!stateObj.TryReadInt16(out shortLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(shortLen, out col.xmlSchemaCollectionName)) { return false; } } } } } } if (col.type == SqlDbType.Decimal) { if (!stateObj.TryReadByte(out col.precision)) { return false; } if (!stateObj.TryReadByte(out col.scale)) { return false; } } if (col.metaType.IsVarTime) { if (!stateObj.TryReadByte(out col.scale)) { return false; } Debug.Assert(0 <= col.scale && col.scale <= 7); // calculate actual column length here // switch (col.metaType.SqlDbType) { case SqlDbType.Time: col.length = MetaType.GetTimeSizeFromScale(col.scale); break; case SqlDbType.DateTime2: // Date in number of days (3 bytes) + time col.length = 3 + MetaType.GetTimeSizeFromScale(col.scale); break; case SqlDbType.DateTimeOffset: // Date in days (3 bytes) + offset in minutes (2 bytes) + time col.length = 5 + MetaType.GetTimeSizeFromScale(col.scale); break; default: Debug.Assert(false, "Unknown VariableTime type!"); break; } } // read the collation for 7.x servers if (_isShiloh && col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE)) { if (!TryProcessCollation(stateObj, out col.collation)) { return false; } int codePage = GetCodePage(col.collation, stateObj); if (codePage == _defaultCodePage) { col.codePage = _defaultCodePage; col.encoding = _defaultEncoding; } else { col.codePage = codePage; col.encoding = System.Text.Encoding.GetEncoding(col.codePage); } } return true; }
/// <summary> /// <para> Parses the TDS message to read a single CIPHER_INFO table.</para> /// </summary> internal bool TryProcessCipherInfoTable (TdsParserStateObject stateObj, out SqlTceCipherInfoTable? cipherTable) { // Read count short tableSize = 0; cipherTable = null; if (!stateObj.TryReadInt16(out tableSize)) { return false; } if (0 != tableSize) { SqlTceCipherInfoTable tempTable = new SqlTceCipherInfoTable(tableSize); // Read individual entries for (int i = 0; i < tableSize; i++) { SqlTceCipherInfoEntry entry; if (!TryReadCipherInfoEntry (stateObj, out entry)) { return false; } tempTable[i] = entry; } cipherTable = tempTable; } return true; }
internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, out SqlReturnValue returnValue, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { returnValue = null; SqlReturnValue rec = new SqlReturnValue(); rec.length = length; // In Yukon this length is -1 if (_isYukon) { if (!stateObj.TryReadUInt16(out rec.parmIndex)) { return false; } } byte len; if (!stateObj.TryReadByte(out len)) { // Length of parameter name return false; } rec.parameter = null; if (len > 0) { if (!stateObj.TryReadString(len, out rec.parameter)) { return false; } } // read status and ignore byte ignored; if (!stateObj.TryReadByte(out ignored)) { return false; } UInt32 userType; // read user type - 4 bytes Yukon, 2 backwards if (IsYukonOrNewer) { if (!stateObj.TryReadUInt32(out userType)) { return false; } } else { ushort userTypeShort; if (!stateObj.TryReadUInt16(out userTypeShort)) { return false; } userType = userTypeShort; } // Read off the flags. // The first byte is ignored since it doesn't contain any interesting information. byte flags; if (!stateObj.TryReadByte(out flags)) { return false; } if (!stateObj.TryReadByte(out flags)) { return false; } // Check if the column is encrypted. if (_serverSupportsColumnEncryption) { rec.isEncrypted = (TdsEnums.IsEncrypted == (flags & TdsEnums.IsEncrypted)); } // read the type byte tdsType; if (!stateObj.TryReadByte(out tdsType)) { return false; } // read the MaxLen // For xml datatpyes, there is no tokenLength int tdsLen; if (tdsType == TdsEnums.SQLXMLTYPE) { tdsLen = TdsEnums.SQL_USHORTVARMAXLEN; } else if (IsVarTimeTds(tdsType)) tdsLen = 0; // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN else if (tdsType == TdsEnums.SQLDATE) { tdsLen = 3; } else { if (!TryGetTokenLength(tdsType, stateObj, out tdsLen)) { return false; } } rec.metaType = MetaType.GetSqlDataType(tdsType, userType, tdsLen); rec.type = rec.metaType.SqlDbType; // always use the nullable type for parameters if Shiloh or later // Sphinx sometimes sends fixed length return values if (_isShiloh) { rec.tdsType = rec.metaType.NullableType; rec.isNullable = true; if (tdsLen == TdsEnums.SQL_USHORTVARMAXLEN) { Debug.Assert(_isYukon, "plp data from pre-Yukon server"); rec.metaType = MetaType.GetMaxMetaTypeFromMetaType(rec.metaType); } } else { // For sphinx, keep the fixed type if that is what is returned if (rec.metaType.NullableType == tdsType) rec.isNullable = true; rec.tdsType = (byte)tdsType; } if (rec.type == SqlDbType.Decimal) { if (!stateObj.TryReadByte(out rec.precision)) { return false; } if (!stateObj.TryReadByte(out rec.scale)) { return false; } } if (rec.metaType.IsVarTime) { if (!stateObj.TryReadByte(out rec.scale)) { return false; } } if (tdsType == TdsEnums.SQLUDT) { if (!TryProcessUDTMetaData((SqlMetaDataPriv) rec, stateObj)) { return false; } } if (rec.type == SqlDbType.Xml) { // Read schema info byte schemapresent; if (!stateObj.TryReadByte(out schemapresent)) { return false; } if ((schemapresent & 1) != 0) { if (!stateObj.TryReadByte(out len)) { return false; } if (len != 0) { if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionDatabase)) { return false; } } if (!stateObj.TryReadByte(out len)) { return false; } if (len != 0) { if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionOwningSchema)) { return false; } } short slen; if (!stateObj.TryReadInt16(out slen)) { return false; } if (slen != 0) { if (!stateObj.TryReadString(slen, out rec.xmlSchemaCollectionName)) { return false; } } } } else if (_isShiloh && rec.metaType.IsCharType) { // read the collation for 8.x servers if (!TryProcessCollation(stateObj, out rec.collation)) { return false; } int codePage = GetCodePage(rec.collation, stateObj); // if the column lcid is the same as the default, use the default encoder if (codePage == _defaultCodePage) { rec.codePage = _defaultCodePage; rec.encoding = _defaultEncoding; } else { rec.codePage = codePage; rec.encoding = System.Text.Encoding.GetEncoding(rec.codePage); } } // For encrypted parameters, read the unencrypted type and encryption information. if (_serverSupportsColumnEncryption && rec.isEncrypted) { if (!TryProcessTceCryptoMetadata(stateObj, rec, cipherTable: null, columnEncryptionSetting: columnEncryptionSetting, isReturnValue: true)) { return false; } } // for now we coerce return values into a SQLVariant, not good... bool isNull = false; ulong valLen; if (!TryProcessColumnHeaderNoNBC(rec, stateObj, out isNull, out valLen)) { return false; } // always read as sql types Debug.Assert(valLen < (ulong)(Int32.MaxValue), "ProcessReturnValue received data size > 2Gb"); int intlen = valLen > (ulong)(Int32.MaxValue) ? Int32.MaxValue : (int)valLen; if (rec.metaType.IsPlp) { intlen = Int32.MaxValue; // If plp data, read it all } if (isNull) { GetNullSqlValue(rec.value, rec, SqlCommandColumnEncryptionSetting.Disabled, _connHandler); } else { // We should never do any decryption here, so pass disabled as the command encryption override. // We only read the binary value and decryption will be performed by OnReturnValue(). if (!TryReadSqlValue(rec.value, rec, intlen, stateObj, SqlCommandColumnEncryptionSetting.Disabled, columnName:null /*Not used*/)) { return false; } } returnValue = rec; return true; }
private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col) { byte byteLen; UInt32 userType; // read user type - 4 bytes Yukon, 2 backwards if (IsYukonOrNewer) { if (!stateObj.TryReadUInt32(out userType)) { return false; } } else { ushort userTypeShort; if (!stateObj.TryReadUInt16(out userTypeShort)) { return false; } userType = userTypeShort; } // read flags and set appropriate flags in structure byte flags; if (!stateObj.TryReadByte(out flags)) { return false; } col.updatability = (byte)((flags & TdsEnums.Updatability) >> 2); col.isNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable)); col.isIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity)); // read second byte of column metadata flags if (!stateObj.TryReadByte(out flags)) { return false; } col.isColumnSet = (TdsEnums.IsColumnSet == (flags & TdsEnums.IsColumnSet)); byte tdsType; if (!stateObj.TryReadByte(out tdsType)) { return false; } if (tdsType == TdsEnums.SQLXMLTYPE) col.length = TdsEnums.SQL_USHORTVARMAXLEN; //Use the same length as other plp datatypes else if (IsVarTimeTds(tdsType)) col.length = 0; // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN else if (tdsType == TdsEnums.SQLDATE) { col.length = 3; } else { if (!TryGetTokenLength(tdsType, stateObj, out col.length)) { return false; } } col.metaType = MetaType.GetSqlDataType(tdsType, userType, col.length); col.type = col.metaType.SqlDbType; // If sphinx, do not change to nullable type if (_isShiloh) col.tdsType = (col.isNullable ? col.metaType.NullableType : col.metaType.TDSType); else col.tdsType = tdsType; if (_isYukon) { if (TdsEnums.SQLUDT == tdsType) { if (!TryProcessUDTMetaData((SqlMetaDataPriv) col, stateObj)) { return false; } } if (col.length == TdsEnums.SQL_USHORTVARMAXLEN) { Debug.Assert(tdsType == TdsEnums.SQLXMLTYPE || tdsType == TdsEnums.SQLBIGVARCHAR || tdsType == TdsEnums.SQLBIGVARBINARY || tdsType == TdsEnums.SQLNVARCHAR || tdsType == TdsEnums.SQLUDT, "Invalid streaming datatype"); col.metaType = MetaType.GetMaxMetaTypeFromMetaType(col.metaType); Debug.Assert(col.metaType.IsLong, "Max datatype not IsLong"); col.length = Int32.MaxValue; if (tdsType == TdsEnums.SQLXMLTYPE) { byte schemapresent; if (!stateObj.TryReadByte(out schemapresent)) { return false; } if ((schemapresent & 1) != 0) { if (!stateObj.TryReadByte(out byteLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionDatabase)) { return false; } } if (!stateObj.TryReadByte(out byteLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionOwningSchema)) { return false; } } short shortLen; if (!stateObj.TryReadInt16(out shortLen)) { return false; } if (byteLen != 0) { if (!stateObj.TryReadString(shortLen, out col.xmlSchemaCollectionName)) { return false; } } } } } } if (col.type == SqlDbType.Decimal) { if (!stateObj.TryReadByte(out col.precision)) { return false; } if (!stateObj.TryReadByte(out col.scale)) { return false; } } if (col.metaType.IsVarTime) { if (!stateObj.TryReadByte(out col.scale)) { return false; } Debug.Assert(0 <= col.scale && col.scale <= 7); // calculate actual column length here // switch (col.metaType.SqlDbType) { case SqlDbType.Time: col.length = MetaType.GetTimeSizeFromScale(col.scale); break; case SqlDbType.DateTime2: // Date in number of days (3 bytes) + time col.length = 3 + MetaType.GetTimeSizeFromScale(col.scale); break; case SqlDbType.DateTimeOffset: // Date in days (3 bytes) + offset in minutes (2 bytes) + time col.length = 5 + MetaType.GetTimeSizeFromScale(col.scale); break; default: Debug.Assert(false, "Unknown VariableTime type!"); break; } } // read the collation for 7.x servers if (_isShiloh && col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE)) { if (!TryProcessCollation(stateObj, out col.collation)) { return false; } int codePage = GetCodePage(col.collation, stateObj); if (codePage == _defaultCodePage) { col.codePage = _defaultCodePage; col.encoding = _defaultEncoding; } else { col.codePage = codePage; col.encoding = System.Text.Encoding.GetEncoding(col.codePage); } } if (col.metaType.IsLong && !col.metaType.IsPlp) { if (_isYukon) { int unusedLen = 0xFFFF; //We ignore this value if (!TryProcessOneTable(stateObj, ref unusedLen, out col.multiPartTableName)) { return false; } } else { ushort shortLen; if (!stateObj.TryReadUInt16(out shortLen)) { return false; } string tableName; if (!stateObj.TryReadString(shortLen, out tableName)) { return false; } // with Sql2000 this is returned as an unquoted mix of catalog.owner.table // all of which may contain "." and unable to parse correctly from the string alone // example "select * from pubs..[A.B.C.D.E]" AND only when * will contain a image/text/ntext column // by delay parsing from execute to SqlDataReader.GetSchemaTable to enable more scenarios col.multiPartTableName = new MultiPartTableName(tableName); } } if (!stateObj.TryReadByte(out byteLen)) { return false; } if (!stateObj.TryReadString(byteLen, out col.column)) { return false; } // We get too many DONE COUNTs from the server, causing too meany StatementCompleted event firings. // We only need to fire this event when we actually have a meta data stream with 0 or more rows. stateObj._receivedColMetaData = true; return true; }