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 TryProcessCollation(TdsParserStateObject stateObj, out SqlCollation collation) { SqlCollation newCollation = new SqlCollation(); if (!stateObj.TryReadUInt32(out newCollation.info)) { collation = null; return false; } if (!stateObj.TryReadByte(out newCollation.sortId)) { collation = null; return false; } collation = newCollation; return true; }
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; }
private bool TryProcessSessionState(TdsParserStateObject stateObj, int length, SessionData sdata) { if (length < 5) { throw SQL.ParsingError(); } UInt32 seqNum; if (!stateObj.TryReadUInt32(out seqNum)) { return false; } if (seqNum == UInt32.MaxValue) { _connHandler.DoNotPoolThisConnection(); } byte status; if (!stateObj.TryReadByte(out status)) { return false; } if (status > 1) { throw SQL.ParsingError(); } bool recoverable = status != 0; length -= 5; while (length > 0) { byte stateId; if (!stateObj.TryReadByte(out stateId)) { return false; } int stateLen; byte stateLenByte; if (!stateObj.TryReadByte(out stateLenByte)) { return false; } if (stateLenByte < 0xFF) { stateLen = stateLenByte; } else { if (!stateObj.TryReadInt32(out stateLen)) { return false; } } byte[] buffer = null; lock (sdata._delta) { if (sdata._delta[stateId] == null) { buffer = new byte[stateLen]; sdata._delta[stateId] = new SessionStateRecord { _version = seqNum, _dataLength = stateLen, _data = buffer, _recoverable = recoverable }; sdata._deltaDirty = true; if (!recoverable) { checked { sdata._unrecoverableStatesCount++; } } } else { if (sdata._delta[stateId]._version <= seqNum) { SessionStateRecord sv = sdata._delta[stateId]; sv._version = seqNum; sv._dataLength = stateLen; if (sv._recoverable != recoverable) { if (recoverable) { Debug.Assert(sdata._unrecoverableStatesCount > 0, "Unrecoverable states count >0"); sdata._unrecoverableStatesCount--; } else { checked { sdata._unrecoverableStatesCount++; } } sv._recoverable = recoverable; } buffer = sv._data; if (buffer.Length < stateLen) { buffer = new byte[stateLen]; sv._data = buffer; } } } } if (buffer != null) { if (!stateObj.TryReadByteArray(buffer, 0, stateLen)) { return false; } } else { if (!stateObj.TrySkipBytes(stateLen)) return false; } if (stateLenByte < 0xFF) { length -= 2 + stateLen; } else { length -= 6 + stateLen; } } sdata.AssertUnrecoverableStateCountIsCorrect(); 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 TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col, SqlTceCipherInfoTable? cipherTable, bool fColMD, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { 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)); if (fColMD && _serverSupportsColumnEncryption) { col.isEncrypted = (TdsEnums.IsEncrypted == (flags & TdsEnums.IsEncrypted)); } // Read TypeInfo if (!TryProcessTypeInfo (stateObj, col, userType)) { return false; } // Read tablename if present 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); } } // Read the TCE column cryptoinfo if (fColMD && _serverSupportsColumnEncryption && col.isEncrypted) { // If the column is encrypted, we should have a valid cipherTable if (cipherTable.HasValue && !TryProcessTceCryptoMetadata (stateObj, col, cipherTable.Value, columnEncryptionSetting, isReturnValue: false)) { return false; } } // Read the column name 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; }
private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) { // read feature ID byte featureId; do { if (!stateObj.TryReadByte(out featureId)) { return false; } if (featureId != TdsEnums.FEATUREEXT_TERMINATOR) { UInt32 dataLen; if (!stateObj.TryReadUInt32(out dataLen)) { return false; } byte[] data = new byte[dataLen]; if (dataLen > 0) { if (!stateObj.TryReadByteArray(data, 0, checked((int)dataLen))) { return false; } } _connHandler.OnFeatureExtAck(featureId, data); } } while (featureId != TdsEnums.FEATUREEXT_TERMINATOR); return true; }
internal bool TryProcessTceCryptoMetadata (TdsParserStateObject stateObj, SqlMetaDataPriv col, SqlTceCipherInfoTable? cipherTable, SqlCommandColumnEncryptionSetting columnEncryptionSetting, bool isReturnValue) { Debug.Assert(isReturnValue == (cipherTable == null), "Ciphertable is not set iff this is a return value"); // Read the ordinal into cipher table ushort index = 0; UInt32 userType; // For return values there is not cipher table and no ordinal. if (cipherTable.HasValue) { if (!stateObj.TryReadUInt16(out index)) { return false; } // validate the index (ordinal passed) if (index >= cipherTable.Value.Size) { Bid.Trace("<sc.TdsParser.TryProcessTceCryptoMetadata|TCE> Incorrect ordinal received %d, max tab size: %d\n", index, cipherTable.Value.Size); throw SQL.ParsingErrorValue(ParsingErrorState.TceInvalidOrdinalIntoCipherInfoTable, index); } } // Read the user type if (!stateObj.TryReadUInt32(out userType)) { return false; } // Read the base TypeInfo col.baseTI = new SqlMetaDataPriv(); if (!TryProcessTypeInfo(stateObj, col.baseTI, userType)) { return false; } // Read the cipher algorithm Id byte cipherAlgorithmId; if (!stateObj.TryReadByte(out cipherAlgorithmId)) { return false; } string cipherAlgorithmName = null; if (TdsEnums.CustomCipherAlgorithmId == cipherAlgorithmId) { // Custom encryption algorithm, read the name byte nameSize; if (!stateObj.TryReadByte(out nameSize)) { return false; } if (!stateObj.TryReadString(nameSize, out cipherAlgorithmName)) { return false; } } // Read Encryption Type. byte encryptionType; if (!stateObj.TryReadByte(out encryptionType)) { return false; } // Read Normalization Rule Version. byte normalizationRuleVersion; if (!stateObj.TryReadByte(out normalizationRuleVersion)) { return false; } Debug.Assert(col.cipherMD == null, "col.cipherMD should be null in TryProcessTceCryptoMetadata."); // Check if TCE is enable and if it is set the crypto MD for the column. // TCE is enabled if the command is set to enabled or to resultset only and this is not a return value // or if it is set to use connection setting and the connection has TCE enabled. if ((columnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled || (columnEncryptionSetting == SqlCommandColumnEncryptionSetting.ResultSetOnly && !isReturnValue)) || (columnEncryptionSetting == SqlCommandColumnEncryptionSetting.UseConnectionSetting && _connHandler != null && _connHandler.ConnectionOptions != null && _connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled)) { col.cipherMD = new SqlCipherMetadata(cipherTable.HasValue ? (SqlTceCipherInfoEntry?)cipherTable.Value[index] : null, index, cipherAlgorithmId: cipherAlgorithmId, cipherAlgorithmName: cipherAlgorithmName, encryptionType: encryptionType, normalizationRuleVersion: normalizationRuleVersion); } else { // If TCE is disabled mark the MD as not encrypted. col.isEncrypted = false; } 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 TryProcessFedAuthInfo(TdsParserStateObject stateObj, int tokenLen, out SqlFedAuthInfo sqlFedAuthInfo) { sqlFedAuthInfo = null; SqlFedAuthInfo tempFedAuthInfo = new SqlFedAuthInfo(); // Skip reading token length, since it has already been read in caller if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FEDAUTHINFO token stream length = {0}\n", tokenLen); } if (tokenLen < sizeof(uint)) { // the token must at least contain a DWORD indicating the number of info IDs Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream length too short for CountOfInfoIDs.\n"); throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForCountOfInfoIds, tokenLen); } // read how many FedAuthInfo options there are uint optionsCount; if (!stateObj.TryReadUInt32(out optionsCount)) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read CountOfInfoIDs in FEDAUTHINFO token stream.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadCountOfInfoIds); } tokenLen -= sizeof(uint); // remaining length is shortened since we read optCount if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> CountOfInfoIDs = {0}\n", optionsCount.ToString(CultureInfo.InvariantCulture)); } if (tokenLen > 0) { // read the rest of the token byte[] tokenData = new byte[tokenLen]; int totalRead = 0; bool successfulRead = stateObj.TryReadByteArray(tokenData, 0, tokenLen, out totalRead); if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Read rest of FEDAUTHINFO token stream: {0}\n", BitConverter.ToString(tokenData, 0, totalRead)); } if (!successfulRead || totalRead != tokenLen) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read FEDAUTHINFO token stream. Attempted to read {0} bytes, actually read {1}\n", tokenLen, totalRead); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadTokenStream); } // each FedAuthInfoOpt is 9 bytes: // 1 byte for FedAuthInfoID // 4 bytes for FedAuthInfoDataLen // 4 bytes for FedAuthInfoDataOffset // So this is the index in tokenData for the i-th option const uint optionSize = 9; // the total number of bytes for all FedAuthInfoOpts together uint totalOptionsSize = checked(optionsCount * optionSize); for (uint i = 0; i < optionsCount; i++) { uint currentOptionOffset = checked(i * optionSize); byte id = tokenData[currentOptionOffset]; uint dataLen = BitConverter.ToUInt32(tokenData, checked((int)(currentOptionOffset + 1))); uint dataOffset = BitConverter.ToUInt32(tokenData, checked((int)(currentOptionOffset + 5))); if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FedAuthInfoOpt: ID={0}, DataLen={1}, Offset={2}\n", id, dataLen.ToString(CultureInfo.InvariantCulture), dataOffset.ToString(CultureInfo.InvariantCulture)); } // offset is measured from optCount, so subtract to make offset measured // from the beginning of tokenData checked { dataOffset -= sizeof(uint); } // if dataOffset points to a region within FedAuthInfoOpt or after the end of the token, throw if (dataOffset < totalOptionsSize || dataOffset >= tokenLen) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FedAuthInfoDataOffset points to an invalid location.\n"); throw SQL.ParsingErrorOffset(ParsingErrorState.FedAuthInfoInvalidOffset, unchecked((int)dataOffset)); } // try to read data and throw if the arguments are bad, meaning the server sent us a bad token string data; try { data = System.Text.Encoding.Unicode.GetString(tokenData, checked((int)dataOffset), checked((int)dataLen)); } catch (ArgumentOutOfRangeException e) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read FedAuthInfoData.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadData, e); } catch (ArgumentException e) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FedAuthInfoData is not in unicode format.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoDataNotUnicode, e); } if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FedAuthInfoData: {0}\n", data); } // store data in tempFedAuthInfo switch ((TdsEnums.FedAuthInfoId)id) { case TdsEnums.FedAuthInfoId.Spn: tempFedAuthInfo.spn = data; break; case TdsEnums.FedAuthInfoId.Stsurl: tempFedAuthInfo.stsurl = data; break; default: if (Bid.AdvancedOn) { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Ignoring unknown federated authentication info option: {0}\n", id); } break; } } } else { Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream is not long enough to contain the data it claims to.\n"); throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForData, tokenLen); } Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Processed FEDAUTHINFO token stream: {0}\n", tempFedAuthInfo.ToString()); if (String.IsNullOrWhiteSpace(tempFedAuthInfo.stsurl) || String.IsNullOrWhiteSpace(tempFedAuthInfo.spn)) { // We should be receiving both stsurl and spn Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream does not contain both STSURL and SPN.\n"); throw SQL.ParsingError(ParsingErrorState.FedAuthInfoDoesNotContainStsurlAndSpn); } sqlFedAuthInfo = tempFedAuthInfo; return true; }
private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) { // read feature ID byte featureId; do { if (!stateObj.TryReadByte(out featureId)) { return false; } if (featureId != TdsEnums.FEATUREEXT_TERMINATOR) { UInt32 dataLen; if (!stateObj.TryReadUInt32(out dataLen)) { return false; } byte[] data = new byte[dataLen]; if (dataLen > 0) { if (!stateObj.TryReadByteArray(data, 0, checked ((int)dataLen))) { return false; } } _connHandler.OnFeatureExtAck(featureId, data); } } while (featureId != TdsEnums.FEATUREEXT_TERMINATOR); // Check if column encryption was on and feature wasn't acknowledged. if (_connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled && !IsColumnEncryptionSupported) { throw SQL.TceNotSupported (); } 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; }