// Reads off from the network buffer and caches bytes. Only reads one column value in the current row. static internal bool TryCreate(SqlMetaDataPriv metadata, TdsParser parser, TdsParserStateObject stateObj, out SqlCachedBuffer buffer) { int cb = 0; ulong plplength; byte[] byteArr; List<byte[]> cachedBytes = new List<byte[]>(); buffer = null; // the very first length is already read. if (!parser.TryPlpBytesLeft(stateObj, out plplength)) { return false; } // For now we only handle Plp data from the parser directly. Debug.Assert(metadata.metaType.IsPlp, "SqlCachedBuffer call on a non-plp data"); do { if (plplength == 0) break; do { cb = (plplength > (ulong)_maxChunkSize) ? _maxChunkSize : (int)plplength; byteArr = new byte[cb]; if (!stateObj.TryReadPlpBytes(ref byteArr, 0, cb, out cb)) { return false; } Debug.Assert(cb == byteArr.Length); if (cachedBytes.Count == 0) { // Add the Byte order mark if needed if we read the first array AddByteOrderMark(byteArr, cachedBytes); } cachedBytes.Add(byteArr); plplength -= (ulong)cb; } while (plplength > 0); if (!parser.TryPlpBytesLeft(stateObj, out plplength)) { return false; } } while (plplength > 0); Debug.Assert(stateObj._longlen == 0 && stateObj._longlenleft == 0); buffer = new SqlCachedBuffer(cachedBytes); return true; }
internal bool TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, int length, TdsParserStateObject stateObj) { 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; } switch (tdsType) { case TdsEnums.SQLDECIMALN: case TdsEnums.SQLNUMERICN: if (!TryReadSqlDecimal(value, length, md.precision, md.scale, stateObj)) { return false; } break; case TdsEnums.SQLUDT: throw SQL.UnsupportedFeatureAndToken(_connHandler, SqlDbType.Udt.ToString()); 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; } } 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; }
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; }