internal LocalCommand(string commandText, SqlParameterCollection parameters, int returnParameterIndex, CommandType cmdType, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { Debug.Assert(0 <= commandText.Length, "no text"); this.CommandText = commandText; this.Parameters = parameters; this.ReturnParameterIndex = returnParameterIndex; this.CmdType = cmdType; this.ColumnEncryptionSetting = columnEncryptionSetting; }
internal LocalCommand(string commandText, SqlParameterCollection parameters, int returnParameterIndex, CommandType cmdType, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { Debug.Assert(0 <= commandText.Length, "no text"); CommandText = commandText; Parameters = parameters; ReturnParameterIndex = returnParameterIndex; CmdType = cmdType; ColumnEncryptionSetting = columnEncryptionSetting; }
public void TestSqlCommandCloneColumnEncryptionSettingSpecified(SqlCommandColumnEncryptionSetting sqlCommandColumnEncryptionSetting) { using (SqlConnection sqlConnection = new SqlConnection()) { using (SqlCommand sqlCommand1 = new SqlCommand( cmdText: "Data source = localhost; Connect Timeout = 65534;", connection: sqlConnection, transaction: null, columnEncryptionSetting: sqlCommandColumnEncryptionSetting)) { Assert.Equal(sqlCommandColumnEncryptionSetting, sqlCommand1.ColumnEncryptionSetting); // Clone the above sqlCommand1 and verify the Column Encryption Setting is propogated correctly. using (SqlCommand sqlCommand2 = sqlCommand1.Clone()) { Assert.Equal(sqlCommandColumnEncryptionSetting, sqlCommand2.ColumnEncryptionSetting); } } } }
public void TestSqlCommandSetColumnEncryptionSetting( SqlConnectionColumnEncryptionSetting sqlConnectionColumnEncryptionSetting, SqlCommandColumnEncryptionSetting sqlCommandColumnEncryptionSetting_1, SqlCommandColumnEncryptionSetting sqlCommandColumnEncryptionSetting_2 ) { MethodInfo SetColumnEncryptionSettingMethod = typeof(SqlCommand).GetMethod("SetColumnEncryptionSetting", BindingFlags.Instance | BindingFlags.NonPublic); string[] connectionStrings = { string.Format(@"Data source = localhost; Column Encryption Setting = {0}", sqlConnectionColumnEncryptionSetting).ToString(), string.Format(@"Data source = localhost; Column Encryption Setting = {0}; Enclave Attestation Url=www.foo.com; ", sqlConnectionColumnEncryptionSetting).ToString() }; foreach (var connectionString in connectionStrings) { using (SqlConnection sqlConnection = new SqlConnection(connectionString)) { using (SqlCommand sqlCommand = new SqlCommand(@"select 1", sqlConnection, transaction: null, columnEncryptionSetting: sqlCommandColumnEncryptionSetting_1)) { // Set the first column encryption setting. SetColumnEncryptionSettingMethod.Invoke(sqlCommand, new object[] { sqlCommandColumnEncryptionSetting_1 }); // Simulate setting of the second column encryption setting. If its the same setting, it should succeed. // If its different than the one used before, it should throw an exception. if (sqlCommandColumnEncryptionSetting_1 == sqlCommandColumnEncryptionSetting_2) { SetColumnEncryptionSettingMethod.Invoke(sqlCommand, new object[] { sqlCommandColumnEncryptionSetting_2 }); Assert.Equal(sqlCommandColumnEncryptionSetting_1, sqlCommand.ColumnEncryptionSetting); } else { TargetInvocationException exception = Assert.Throws <TargetInvocationException>(() => SetColumnEncryptionSettingMethod.Invoke(sqlCommand, new object[] { sqlCommandColumnEncryptionSetting_2 })); string expectedMessage = "SqlCommandColumnEncryptionSetting should be identical on all commands (SelectCommand, InsertCommand, UpdateCommand, DeleteCommand) when doing batch updates."; Assert.Equal(expectedMessage, exception.InnerException.Message); } } } } }
public void SetSqlCommandColumnEncryptionSettingAppropriately(SqlConnectionColumnEncryptionSetting sqlConnectionColumnEncryptionSetting, SqlCommandColumnEncryptionSetting sqlCommandColumnEncryptionSetting) { using (SqlConnection sqlConnectionEnclaveEnabled = new SqlConnection(DefaultConnectionString(columnEncryptionSetting: sqlConnectionColumnEncryptionSetting, fEnclaveEnabled: false, enclaveAttestationUrl: ""))) using (SqlConnection sqlConnectionEnclaveDisabled = new SqlConnection(DefaultConnectionString(columnEncryptionSetting: sqlConnectionColumnEncryptionSetting, fEnclaveEnabled: true, enclaveAttestationUrl: "www.foo.coms"))) { using (SqlCommand sqlCommandEnclaveEnabled = new SqlCommand(@"select * from sys.objects", sqlConnectionEnclaveEnabled, transaction: null, columnEncryptionSetting: sqlCommandColumnEncryptionSetting)) using (SqlCommand sqlCommandEnclaveDisabled = new SqlCommand(@"select * from sys.objects", sqlConnectionEnclaveDisabled, transaction: null, columnEncryptionSetting: sqlCommandColumnEncryptionSetting)) { Assert.Equal(sqlCommandColumnEncryptionSetting, sqlCommandEnclaveEnabled.ColumnEncryptionSetting); Assert.Equal(sqlCommandColumnEncryptionSetting, sqlCommandEnclaveDisabled.ColumnEncryptionSetting); } } }
public void NullValueTests(string connString, ConnStringColumnEncryptionSetting connStringSetting, SqlCommandColumnEncryptionSetting commandSetting, ReturnValueSetting nullReturnValue) { switch (connStringSetting) { case ConnStringColumnEncryptionSetting.Enabled: connString += "; Column Encryption Setting=Enabled"; break; case ConnStringColumnEncryptionSetting.Disabled: connString += "; Column Encryption Setting=Disabled"; break; } using (SqlConnection sqlConn = new SqlConnection(connString)) { sqlConn.Open(); object value1; object value2; SqlParameter param; // Create a command similarly using (SqlCommand cmd = new SqlCommand(String.Format("SELECT c1 FROM [{0}] ORDER BY c2 ASC", tableName), sqlConn, null, commandSetting)) { using (SqlDataReader reader = cmd.ExecuteReader()) { Assert.True(reader.Read(), "No rows fetched first time"); // Depending on the various flags verify the results value1 = reader.GetProviderSpecificValue(0); // Read next row Assert.True(reader.Read(), "No rows fetched second time"); value2 = reader.GetProviderSpecificValue(0); } } using (SqlCommand cmd2 = new SqlCommand((ReturnValueSetting.Null == nullReturnValue) ? UdfName : UdfNameNotNull, sqlConn, null, commandSetting)) { cmd2.CommandType = CommandType.StoredProcedure; param = cmd2.Parameters.Add("@foo", SqlDbType.Int); param.Direction = ParameterDirection.ReturnValue; param.Value = new System.Data.SqlTypes.SqlInt32(1); cmd2.ExecuteNonQuery(); } switch (commandSetting) { case SqlCommandColumnEncryptionSetting.Disabled: // everything should be varbinary Assert.True(value1 is System.Data.SqlTypes.SqlBinary, "Unexpected type"); Assert.True(value2 is System.Data.SqlTypes.SqlBinary, "Unexpected type"); Assert.True(param.Value is System.Data.SqlTypes.SqlBinary, "Unexpected Return value"); break; case SqlCommandColumnEncryptionSetting.Enabled: // Everything should be int // intentional fall through case SqlCommandColumnEncryptionSetting.ResultSetOnly: // Again expect int Assert.True(value1 is System.Data.SqlTypes.SqlInt32, "Unexpected type"); Assert.True(value2 is System.Data.SqlTypes.SqlInt32, "Unexpected type"); Assert.True(10 == ((System.Data.SqlTypes.SqlInt32)value2).Value, "Unexpected Value"); if (SqlCommandColumnEncryptionSetting.ResultSetOnly == commandSetting) { // For ResultSetOnly we don't expect to see plaintext for return values Assert.True(param.Value is System.Data.SqlTypes.SqlBinary, "Unexpected Return value"); } else { Assert.True(param.Value is System.Data.SqlTypes.SqlInt32, "Unexpected Return value"); } break; case SqlCommandColumnEncryptionSetting.UseConnectionSetting: // Examine the connection string setting to figure out what to expect if (ConnStringColumnEncryptionSetting.Enabled == connStringSetting) { // Expect int Assert.True(value1 is System.Data.SqlTypes.SqlInt32, "Unexpected type"); Assert.True(value2 is System.Data.SqlTypes.SqlInt32, "Unexpected type"); Assert.True(10 == ((System.Data.SqlTypes.SqlInt32)value2).Value, "Unexpected Value"); Assert.True(param.Value is System.Data.SqlTypes.SqlInt32, "Unexpected Return value"); } else { // Expect varbinary Assert.True(value1 is System.Data.SqlTypes.SqlBinary, "Unexpected type"); Assert.True(value2 is System.Data.SqlTypes.SqlBinary, "Unexpected type"); Assert.True(param.Value is System.Data.SqlTypes.SqlBinary, "Unexpected Return value"); } break; } } }
static void Postfix(SqlCommand __instance, string cmdText, SqlConnection connection, SqlTransaction transaction, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { __instance.CommandText = SqlCommandSetProcessor.Process(connection, __instance, cmdText); }
internal static object GetNullSqlValue( SqlBuffer nullVal, SqlMetaDataPriv md, SqlCommandColumnEncryptionSetting columnEncryptionSetting, SqlInternalConnectionTds connection) { SqlDbType type = md.type; if (type == SqlDbType.VarBinary && // if its a varbinary md.isEncrypted &&// and encrypted ShouldHonorTceForRead(columnEncryptionSetting, connection)){ type = md.baseTI.type; // the use the actual (plaintext) type } switch (type) { case SqlDbType.Real: nullVal.SetToNullOfType(SqlBuffer.StorageType.Single); break; case SqlDbType.Float: nullVal.SetToNullOfType(SqlBuffer.StorageType.Double); break; case SqlDbType.Udt: case SqlDbType.Binary: case SqlDbType.VarBinary: case SqlDbType.Image: nullVal.SqlBinary = SqlBinary.Null; break; case SqlDbType.UniqueIdentifier: nullVal.SqlGuid = SqlGuid.Null; break; case SqlDbType.Bit: nullVal.SetToNullOfType(SqlBuffer.StorageType.Boolean); break; case SqlDbType.TinyInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Byte); break; case SqlDbType.SmallInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int16); break; case SqlDbType.Int: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int32); break; case SqlDbType.BigInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int64); break; case SqlDbType.Char: case SqlDbType.VarChar: case SqlDbType.NChar: case SqlDbType.NVarChar: case SqlDbType.Text: case SqlDbType.NText: nullVal.SetToNullOfType(SqlBuffer.StorageType.String); break; case SqlDbType.Decimal: nullVal.SetToNullOfType(SqlBuffer.StorageType.Decimal); break; case SqlDbType.DateTime: case SqlDbType.SmallDateTime: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime); break; case SqlDbType.Money: case SqlDbType.SmallMoney: nullVal.SetToNullOfType(SqlBuffer.StorageType.Money); break; case SqlDbType.Variant: // DBNull.Value will have to work here nullVal.SetToNullOfType(SqlBuffer.StorageType.Empty); break; case SqlDbType.Xml: nullVal.SqlCachedBuffer = SqlCachedBuffer.Null; break; case SqlDbType.Date: nullVal.SetToNullOfType(SqlBuffer.StorageType.Date); break; case SqlDbType.Time: nullVal.SetToNullOfType(SqlBuffer.StorageType.Time); break; case SqlDbType.DateTime2: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime2); break; case SqlDbType.DateTimeOffset: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTimeOffset); break; case SqlDbType.Timestamp: // Dev10 Bug #479607 - this should have been the same as SqlDbType.Binary, but it's a rejected breaking change // Dev10 Bug #752790 - don't assert when it does happen break; default: Debug.Assert(false, "unknown null sqlType!" + md.type.ToString()); break; } return nullVal; }
internal bool TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, int length, TdsParserStateObject stateObj, SqlCommandColumnEncryptionSetting columnEncryptionOverride, string columnName) { bool isPlp = md.metaType.IsPlp; byte tdsType = md.tdsType; Debug.Assert(isPlp || !IsNull(md.metaType, (ulong)length), "null value should not get here!"); if (isPlp) { // We must read the column value completely, no matter what length is passed in length = Int32.MaxValue; } //DEVNOTE: When modifying the following routines (for deserialization) please pay attention to // deserialization code in DecryptWithKey () method and modify it accordingly. switch (tdsType) { case TdsEnums.SQLDECIMALN: case TdsEnums.SQLNUMERICN: if (!TryReadSqlDecimal(value, length, md.precision, md.scale, stateObj)) { return false; } break; case TdsEnums.SQLUDT: case TdsEnums.SQLBINARY: case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLVARBINARY: case TdsEnums.SQLIMAGE: byte[] b = null; // If varbinary(max), we only read the first chunk here, expecting the caller to read the rest if (isPlp) { // If we are given -1 for length, then we read the entire value, // otherwise only the requested amount, usually first chunk. int ignored; if (!stateObj.TryReadPlpBytes(ref b, 0, length, out ignored)) { return false; } } else { //Debug.Assert(length > 0 && length < (long)(Int32.MaxValue), "Bad length for column"); b = new byte[length]; if (!stateObj.TryReadByteArray(b, 0, length)) { return false; } } if (md.isEncrypted && ((columnEncryptionOverride == SqlCommandColumnEncryptionSetting.Enabled || columnEncryptionOverride == SqlCommandColumnEncryptionSetting.ResultSetOnly) || (columnEncryptionOverride == SqlCommandColumnEncryptionSetting.UseConnectionSetting && _connHandler != null && _connHandler.ConnectionOptions != null && _connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled))) { try { // CipherInfo is present, decrypt and read byte[] unencryptedBytes = SqlSecurityUtility.DecryptWithKey(b, md.cipherMD, _connHandler.ConnectionOptions.DataSource); if (unencryptedBytes != null) { DeserializeUnencryptedValue(value, unencryptedBytes, md, stateObj, md.NormalizationRuleVersion); } } catch (Exception e) { throw SQL.ColumnDecryptionFailed(columnName, null, e); } } else { value.SqlBinary = new SqlBinary(b, true); // doesn't copy the byte array } break; case TdsEnums.SQLCHAR: case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLVARCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: if (!TryReadSqlStringValue(value, tdsType, length, md.encoding, isPlp, stateObj)) { return false; } break; case TdsEnums.SQLXMLTYPE: // We store SqlCachedBuffer here, so that we can return either SqlBinary, SqlString or SqlXmlReader. SqlCachedBuffer sqlBuf; if (!SqlCachedBuffer.TryCreate(md, this, stateObj, out sqlBuf)) { return false; } value.SqlCachedBuffer = sqlBuf; break; case TdsEnums.SQLDATE: case TdsEnums.SQLTIME: case TdsEnums.SQLDATETIME2: case TdsEnums.SQLDATETIMEOFFSET: if (!TryReadSqlDateTime(value, tdsType, length, md.scale, stateObj)) { return false; } break; default: Debug.Assert(!isPlp, "ReadSqlValue calling ReadSqlValueInternal with plp data"); if (!TryReadSqlValueInternal(value, tdsType, length, stateObj)) { return false; } break; } Debug.Assert((stateObj._longlen == 0) && (stateObj._longlenleft == 0), "ReadSqlValue did not read plp field completely, longlen =" + stateObj._longlen.ToString((IFormatProvider)null) + ",longlenleft=" + stateObj._longlenleft.ToString((IFormatProvider)null)); return true; }
/// <summary> /// Determines if a column value should be transparently decrypted (based on SqlCommand and Connection String settings). /// </summary> /// <returns>true if the value should be transparently decrypted, false otherwise</returns> internal static bool ShouldHonorTceForRead (SqlCommandColumnEncryptionSetting columnEncryptionSetting, SqlInternalConnectionTds connection) { // Command leve setting trumps all switch (columnEncryptionSetting) { case SqlCommandColumnEncryptionSetting.Disabled: return false; case SqlCommandColumnEncryptionSetting.Enabled: return true; case SqlCommandColumnEncryptionSetting.ResultSetOnly: return true; default: // Check connection level setting! Debug.Assert(SqlCommandColumnEncryptionSetting.UseConnectionSetting == columnEncryptionSetting, "Unexpected value for command level override"); return (connection != null && connection.ConnectionOptions != null && connection.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled); } }
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; }
internal bool TryProcessMetaData(int cColumns, TdsParserStateObject stateObj, out _SqlMetaDataSet metaData, SqlCommandColumnEncryptionSetting columnEncryptionSetting) { Debug.Assert(cColumns > 0, "should have at least 1 column in metadata!"); // Read the cipher info table first SqlTceCipherInfoTable? cipherTable = null; if (_serverSupportsColumnEncryption) { if (!TryProcessCipherInfoTable (stateObj, out cipherTable)) { metaData = null; return false; } } // Read the ColumnData fields _SqlMetaDataSet newMetaData = new _SqlMetaDataSet(cColumns, cipherTable); for (int i = 0; i < cColumns; i++) { if (!TryCommonProcessMetaData(stateObj, newMetaData[i], cipherTable, fColMD: true, columnEncryptionSetting: columnEncryptionSetting)) { metaData = null; return false; } } // DEVNOTE: cipherTable is discarded at this point since its no longer needed. metaData = newMetaData; 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; }