internal SqlCachedBuffer(SqlMetaDataPriv metadata, TdsParser parser, TdsParserStateObject stateObj) { int len = 0; this._cachedBytes = new ArrayList(); ulong num = parser.PlpBytesLeft(stateObj); do { if (num == 0L) { return; } do { len = (num > 0x800L) ? 0x800 : ((int) num); byte[] buff = new byte[len]; len = stateObj.ReadPlpBytes(ref buff, 0, len); if (this._cachedBytes.Count == 0) { this.AddByteOrderMark(buff); } this._cachedBytes.Add(buff); num -= len; } while (num > 0L); num = parser.PlpBytesLeft(stateObj); } while (num > 0L); }
internal virtual void CopyFrom(SqlMetaDataPriv original) { this.type = original.type; this.tdsType = original.tdsType; this.precision = original.precision; this.scale = original.scale; this.length = original.length; this.collation = original.collation; this.codePage = original.codePage; this.encoding = original.encoding; this.isNullable = original.isNullable; this.isMultiValued = original.isMultiValued; this.udtDatabaseName = original.udtDatabaseName; this.udtSchemaName = original.udtSchemaName; this.udtTypeName = original.udtTypeName; this.udtAssemblyQualifiedName = original.udtAssemblyQualifiedName; this.udtType = original.udtType; this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase; this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema; this.xmlSchemaCollectionName = original.xmlSchemaCollectionName; this.metaType = original.metaType; this.structuredTypeDatabaseName = original.structuredTypeDatabaseName; this.structuredTypeSchemaName = original.structuredTypeSchemaName; this.structuredTypeName = original.structuredTypeName; this.structuredFields = original.structuredFields; }
internal SqlCachedBuffer(SqlMetaDataPriv metadata, TdsParser parser, TdsParserStateObject stateObj) { int len = 0; this._cachedBytes = new ArrayList(); ulong num = parser.PlpBytesLeft(stateObj); do { if (num == 0L) { return; } do { len = (num > 0x800L) ? 0x800 : ((int)num); byte[] buff = new byte[len]; len = stateObj.ReadPlpBytes(ref buff, 0, len); if (this._cachedBytes.Count == 0) { this.AddByteOrderMark(buff); } this._cachedBytes.Add(buff); num -= len; }while (num > 0L); num = parser.PlpBytesLeft(stateObj); }while (num > 0L); }
internal static void CheckGetExtendedUDTInfo(SqlMetaDataPriv metaData, bool fThrow) { if (metaData.udtType == null) { metaData.udtType = Type.GetType(metaData.udtAssemblyQualifiedName, fThrow); if (fThrow && (metaData.udtType == null)) { throw SQL.UDTUnexpectedResult(metaData.udtAssemblyQualifiedName); } } }
internal object GetUdtValue(object value, SqlMetaDataPriv metaData, bool returnDBNull) { if (returnDBNull && ADP.IsNull(value)) { return DBNull.Value; } if (ADP.IsNull(value)) { return metaData.udtType.InvokeMember("Null", BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static, null, null, new object[0], CultureInfo.InvariantCulture); } MemoryStream s = new MemoryStream((byte[]) value); return SerializationHelperSql9.Deserialize(s, metaData.udtType); }
// Reads off from the network buffer and caches bytes. Only reads one column value in the current row. internal static 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 virtual void CopyFrom(SqlMetaDataPriv original) { this.type = original.type; this.tdsType = original.tdsType; this.precision = original.precision; this.scale = original.scale; this.length = original.length; this.collation = original.collation; this.codePage = original.codePage; this.encoding = original.encoding; this.isNullable = original.isNullable; this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase; this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema; this.xmlSchemaCollectionName = original.xmlSchemaCollectionName; this.metaType = original.metaType; }
// 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 object GetUdtValue(object value, SqlMetaDataPriv metaData, bool returnDBNull) => throw new PlatformNotSupportedException(EXCEPTION_MESSAGE);
private bool TryProcessColumnHeaderNoNBC(SqlMetaDataPriv col, TdsParserStateObject stateObj, out bool isNull, out ulong length) { if (col.metaType.IsLong && !col.metaType.IsPlp) { // // we don't care about TextPtrs, simply go after the data after it // byte textPtrLen; if (!stateObj.TryReadByte(out textPtrLen)) { isNull = false; length = 0; return false; } if (0 != textPtrLen) { // read past text pointer if (!stateObj.TrySkipBytes(textPtrLen)) { isNull = false; length = 0; return false; } // read past timestamp if (!stateObj.TrySkipBytes(TdsEnums.TEXT_TIME_STAMP_LEN)) { isNull = false; length = 0; return false; } isNull = false; return TryGetDataLength(col, stateObj, out length); } else { isNull = true; length = 0; return true; } } else { // non-blob columns ulong longlen; if (!TryGetDataLength(col, stateObj, out longlen)) { isNull = false; length = 0; return false; } isNull = IsNull(col.metaType, longlen); length = (isNull ? 0 : longlen); return true; } }
internal void SkipValue(SqlMetaDataPriv md, TdsParserStateObject stateObj) { if (md.metaType.IsPlp) { this.SkipPlpValue(ulong.MaxValue, stateObj); } else { int tokenLength = this.GetTokenLength(md.tdsType, stateObj); if (!this.IsNull(md.metaType, (ulong) tokenLength)) { this.SkipBytes(tokenLength, stateObj); } } }
internal void CheckGetExtendedUDTInfo(SqlMetaDataPriv metaData, bool fThrow) => throw new PlatformNotSupportedException(EXCEPTION_MESSAGE);
private void ProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObject stateObj) { metaData.length = stateObj.ReadUInt16(); int length = stateObj.ReadByte(); if (length != 0) { metaData.udtDatabaseName = stateObj.ReadString(length); } length = stateObj.ReadByte(); if (length != 0) { metaData.udtSchemaName = stateObj.ReadString(length); } length = stateObj.ReadByte(); if (length != 0) { metaData.udtTypeName = stateObj.ReadString(length); } length = stateObj.ReadUInt16(); if (length != 0) { metaData.udtAssemblyQualifiedName = stateObj.ReadString(length); } }
private bool TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObject stateObj) { ushort shortLength; byte byteLength; if (!stateObj.TryReadUInt16(out shortLength)) { // max byte size return false; } metaData.length = shortLength; // database name if (!stateObj.TryReadByte(out byteLength)) { return false; } if (byteLength != 0) { if (!stateObj.TryReadString(byteLength, out metaData.udtDatabaseName)) { return false; } } // schema name if (!stateObj.TryReadByte(out byteLength)) { return false; } if (byteLength != 0) { if (!stateObj.TryReadString(byteLength, out metaData.udtSchemaName)) { return false; } } // type name if (!stateObj.TryReadByte(out byteLength)) { return false; } if (byteLength != 0) { if (!stateObj.TryReadString(byteLength, out metaData.udtTypeName)) { return false; } } if (!stateObj.TryReadUInt16(out shortLength)) { return false; } if (shortLength != 0) { if (!stateObj.TryReadString(shortLength, out metaData.udtAssemblyQualifiedName)) { return false; } } return true; }
// // Returns the data stream length of the data identified by tds type or SqlMetaData returns // Returns either the total size or the size of the first chunk for partially length prefixed types. // internal bool TryGetDataLength(SqlMetaDataPriv colmeta, TdsParserStateObject stateObj, out ulong length) { // Handle Yukon specific tokens if (colmeta.metaType.IsPlp) { Debug.Assert(colmeta.tdsType == TdsEnums.SQLXMLTYPE || colmeta.tdsType == TdsEnums.SQLBIGVARCHAR || colmeta.tdsType == TdsEnums.SQLBIGVARBINARY || colmeta.tdsType == TdsEnums.SQLNVARCHAR || // Large UDTs is WinFS-only colmeta.tdsType == TdsEnums.SQLUDT, "GetDataLength:Invalid streaming datatype"); return stateObj.TryReadPlpLength(true, out length); } else { int intLength; if (!TryGetTokenLength(colmeta.tdsType, stateObj, out intLength)) { length = 0; return false; } length = (ulong)intLength; return true; } }
internal int ReadPlpAnsiChars(ref char[] buff, int offst, int len, SqlMetaDataPriv metadata, TdsParserStateObject stateObj) { int charsRead = 0; int charsLeft = 0; int bytesRead = 0; int totalcharsRead = 0; if (stateObj._longlen == 0) { Debug.Assert(stateObj._longlenleft == 0); return 0; // No data } Debug.Assert(((ulong)stateObj._longlen != TdsEnums.SQL_PLP_NULL), "Out of sync plp read request"); Debug.Assert((buff == null && offst == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpAnsiChars()!"); charsLeft = len; if (stateObj._longlenleft == 0) { stateObj.ReadPlpLength(false); if (stateObj._longlenleft == 0) {// Data read complete stateObj._plpdecoder = null; return 0; } } if (stateObj._plpdecoder == null) { Encoding enc = metadata.encoding; if (enc == null) { if (null == _defaultEncoding) { ThrowUnsupportedCollationEncountered(stateObj); } enc = _defaultEncoding; } stateObj._plpdecoder = enc.GetDecoder(); } while (charsLeft > 0) { bytesRead = (int)Math.Min(stateObj._longlenleft, (ulong)charsLeft); if ((stateObj._bTmp == null) || (stateObj._bTmp.Length < bytesRead)) { // Grow the array stateObj._bTmp = new byte[bytesRead]; } bytesRead = stateObj.ReadPlpBytesChunk(stateObj._bTmp, 0, bytesRead); charsRead = stateObj._plpdecoder.GetChars(stateObj._bTmp, 0, bytesRead, buff, offst); charsLeft -= charsRead; offst += charsRead; totalcharsRead += charsRead; if (stateObj._longlenleft == 0) // Read the next chunk or cleanup state if hit the end stateObj.ReadPlpLength(false); if (stateObj._longlenleft == 0) { // Data read complete stateObj._plpdecoder = null; break; } } return (totalcharsRead); }
internal void ReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, int length, TdsParserStateObject stateObj) { if (md.metaType.IsPlp) { length = 0x7fffffff; } switch (md.tdsType) { case 0x22: case 0x25: case 0x2d: case 240: case 0xa5: case 0xad: { byte[] buff = null; if (md.metaType.IsPlp) { stateObj.ReadPlpBytes(ref buff, 0, length); } else { buff = new byte[length]; stateObj.ReadByteArray(buff, 0, length); } value.SqlBinary = new SqlBinary(buff, true); return; } case 0x23: case 0x27: case 0x2f: case 0x63: case 0xef: case 0xe7: case 0xa7: case 0xaf: this.ReadSqlStringValue(value, md.tdsType, length, md.encoding, md.metaType.IsPlp, stateObj); return; case 40: case 0x29: case 0x2a: case 0x2b: this.ReadSqlDateTime(value, md.tdsType, length, md.scale, stateObj); return; case 0x6a: case 0x6c: this.ReadSqlDecimal(value, length, md.precision, md.scale, stateObj); return; case 0xf1: { SqlCachedBuffer buffer2 = new SqlCachedBuffer(md, this, stateObj); value.SqlCachedBuffer = buffer2; return; } } this.ReadSqlValueInternal(value, md.tdsType, md.metaType.TypeId, length, stateObj); }
/// <summary> /// This method skips bytes of a single column value from the media. It supports NBCROW and handles all types of values, including PLP and long /// </summary> internal bool TrySkipValue(SqlMetaDataPriv md, int columnOrdinal, TdsParserStateObject stateObj) { if (stateObj.IsNullCompressionBitSet(columnOrdinal)) { return true; } if (md.metaType.IsPlp) { ulong ignored; if (!TrySkipPlpValue(UInt64.MaxValue, stateObj, out ignored)) { return false; } } else if (md.metaType.IsLong) { Debug.Assert(!md.metaType.IsPlp, "Plp types must be handled using SkipPlpValue"); byte textPtrLen; if (!stateObj.TryReadByte(out textPtrLen)) { return false; } if (0 != textPtrLen) { if (!stateObj.TrySkipBytes(textPtrLen + TdsEnums.TEXT_TIME_STAMP_LEN)) { return false; } int length; if (!TryGetTokenLength(md.tdsType, stateObj, out length)) { return false; } if (!stateObj.TrySkipBytes(length)) { return false; } } } else { int length; if (!TryGetTokenLength(md.tdsType, stateObj, out length)) { return false; } // if false, no value to skip - it's null if (!IsNull(md.metaType, (ulong)length)) { if (!stateObj.TrySkipBytes(length)) { return false; } } } return true; }
internal virtual void CopyFrom(SqlMetaDataPriv original) { this.type = original.type; this.tdsType = original.tdsType; this.precision = original.precision; this.scale = original.scale; this.length = original.length; this.collation = original.collation; this.codePage = original.codePage; this.encoding = original.encoding; this.isNullable = original.isNullable; this.isMultiValued = original.isMultiValued; this.udtDatabaseName = original.udtDatabaseName; this.udtSchemaName = original.udtSchemaName; this.udtTypeName = original.udtTypeName; this.udtAssemblyQualifiedName = original.udtAssemblyQualifiedName; this.udtType = original.udtType; this.xmlSchemaCollectionDatabase = original.xmlSchemaCollectionDatabase; this.xmlSchemaCollectionOwningSchema = original.xmlSchemaCollectionOwningSchema; this.xmlSchemaCollectionName = original.xmlSchemaCollectionName; this.metaType = original.metaType; // this.structuredTypeDatabaseName = original.structuredTypeDatabaseName; this.structuredTypeSchemaName = original.structuredTypeSchemaName; this.structuredTypeName = original.structuredTypeName; this.structuredFields = original.structuredFields; }
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 void WriteBulkCopyValue(object value, SqlMetaDataPriv metadata, TdsParserStateObject stateObj) { MetaType metaType = metadata.metaType; ulong length = 0L; ulong byteCount = 0L; if (ADP.IsNull(value)) { if (metaType.IsPlp && ((metaType.NullableType != 240) || metaType.IsLong)) { this.WriteLong(-1L, stateObj); } else if ((!metaType.IsFixed && !metaType.IsLong) && !metaType.IsVarTime) { this.WriteShort(0xffff, stateObj); } else { this.WriteByte(0, stateObj); } } else { switch (metaType.NullableType) { case 0x22: case 0xa5: case 0xad: case 240: length = (value is byte[]) ? ((ulong) ((byte[]) value).Length) : ((ulong) ((SqlBinary) value).Length); break; case 0x23: case 0xa7: case 0xaf: if (this._defaultEncoding == null) { this.ThrowUnsupportedCollationEncountered(null); } if (value is string) { length = (ulong) ((string) value).Length; byteCount = (ulong) this._defaultEncoding.GetByteCount((string) value); } else { SqlString str4 = (SqlString) value; length = (ulong) str4.Value.Length; SqlString str3 = (SqlString) value; byteCount = (ulong) this._defaultEncoding.GetByteCount(str3.Value); } break; case 0x24: length = 0x10L; break; case 0x63: case 0xe7: case 0xef: length = (ulong) (((value is string) ? ((long) ((string) value).Length) : ((long) ((SqlString) value).Value.Length)) * 2L); break; case 0xf1: if (value is XmlReader) { value = MetaType.GetStringFromXml((XmlReader) value); } length = (ulong) (((value is string) ? ((long) ((string) value).Length) : ((long) ((SqlString) value).Value.Length)) * 2L); break; default: length = (ulong) metadata.length; break; } if (metaType.IsLong) { switch (metaType.SqlDbType) { case SqlDbType.NText: case SqlDbType.Image: case SqlDbType.Text: this.WriteByteArray(s_longDataHeader, s_longDataHeader.Length, 0, stateObj); this.WriteTokenLength(metadata.tdsType, (byteCount == 0L) ? ((int) length) : ((int) byteCount), stateObj); break; case SqlDbType.NVarChar: case SqlDbType.VarBinary: case SqlDbType.VarChar: case SqlDbType.Xml: case SqlDbType.Udt: this.WriteUnsignedLong(18446744073709551614L, stateObj); break; } } else { this.WriteTokenLength(metadata.tdsType, (byteCount == 0L) ? ((int) length) : ((int) byteCount), stateObj); } if (DataStorage.IsSqlType(value.GetType())) { this.WriteSqlValue(value, metaType, (int) length, (int) byteCount, 0, stateObj); } else if ((metaType.SqlDbType != SqlDbType.Udt) || metaType.IsLong) { this.WriteValue(value, metaType, metadata.scale, (int) length, (int) byteCount, 0, stateObj); } else { this.WriteShort((int) length, stateObj); this.WriteByteArray((byte[]) value, (int) length, 0, stateObj); } } }
internal ulong GetDataLength(SqlMetaDataPriv colmeta, TdsParserStateObject stateObj) { if (this._isYukon && colmeta.metaType.IsPlp) { return stateObj.ReadPlpLength(true); } return (ulong) this.GetTokenLength(colmeta.tdsType, stateObj); }
internal object GetNullSqlValue(SqlBuffer nullVal, SqlMetaDataPriv md) { switch (md.type) { case SqlDbType.BigInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int64); return nullVal; case SqlDbType.Binary: case SqlDbType.Image: case SqlDbType.VarBinary: case SqlDbType.Udt: nullVal.SqlBinary = SqlBinary.Null; return nullVal; case SqlDbType.Bit: nullVal.SetToNullOfType(SqlBuffer.StorageType.Boolean); return nullVal; case SqlDbType.Char: case SqlDbType.NChar: case SqlDbType.NText: case SqlDbType.NVarChar: case SqlDbType.Text: case SqlDbType.VarChar: nullVal.SetToNullOfType(SqlBuffer.StorageType.String); return nullVal; case SqlDbType.DateTime: case SqlDbType.SmallDateTime: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime); return nullVal; case SqlDbType.Decimal: nullVal.SetToNullOfType(SqlBuffer.StorageType.Decimal); return nullVal; case SqlDbType.Float: nullVal.SetToNullOfType(SqlBuffer.StorageType.Double); return nullVal; case SqlDbType.Int: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int32); return nullVal; case SqlDbType.Money: case SqlDbType.SmallMoney: nullVal.SetToNullOfType(SqlBuffer.StorageType.Money); return nullVal; case SqlDbType.Real: nullVal.SetToNullOfType(SqlBuffer.StorageType.Single); return nullVal; case SqlDbType.UniqueIdentifier: nullVal.SqlGuid = SqlGuid.Null; return nullVal; case SqlDbType.SmallInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Int16); return nullVal; case SqlDbType.Timestamp: case (SqlDbType.SmallInt | SqlDbType.Int): case (SqlDbType.Text | SqlDbType.Int): case (SqlDbType.Xml | SqlDbType.Bit): case (SqlDbType.TinyInt | SqlDbType.Int): case SqlDbType.Structured: return nullVal; case SqlDbType.TinyInt: nullVal.SetToNullOfType(SqlBuffer.StorageType.Byte); return nullVal; case SqlDbType.Variant: nullVal.SetToNullOfType(SqlBuffer.StorageType.Empty); return nullVal; case SqlDbType.Xml: nullVal.SqlCachedBuffer = SqlCachedBuffer.Null; return nullVal; case SqlDbType.Date: nullVal.SetToNullOfType(SqlBuffer.StorageType.Date); return nullVal; case SqlDbType.Time: nullVal.SetToNullOfType(SqlBuffer.StorageType.Time); return nullVal; case SqlDbType.DateTime2: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTime2); return nullVal; case SqlDbType.DateTimeOffset: nullVal.SetToNullOfType(SqlBuffer.StorageType.DateTimeOffset); return nullVal; } return nullVal; }
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; }
internal int ReadPlpAnsiChars(ref char[] buff, int offst, int len, SqlMetaDataPriv metadata, TdsParserStateObject stateObj) { int num3 = 0; int num2 = 0; int num = 0; int num4 = 0; if (stateObj._longlen == 0L) { return 0; } num2 = len; if (stateObj._longlenleft == 0L) { stateObj.ReadPlpLength(false); if (stateObj._longlenleft == 0L) { return 0; } } Encoding encoding = metadata.encoding; if (encoding == null) { if (this._defaultEncoding == null) { this.ThrowUnsupportedCollationEncountered(stateObj); } encoding = this._defaultEncoding; } while (num2 > 0) { num = (int) Math.Min(stateObj._longlenleft, (ulong) num2); if ((stateObj._bTmp == null) || (stateObj._bTmp.Length < num)) { stateObj._bTmp = new byte[num]; } num = stateObj.ReadPlpBytesChunk(stateObj._bTmp, 0, num); num3 = encoding.GetChars(stateObj._bTmp, 0, num, buff, offst); num2 -= num3; offst += num3; num4 += num3; if (stateObj._longlenleft == 0L) { stateObj.ReadPlpLength(false); } if (stateObj._longlenleft == 0L) { return num4; } } return num4; }
// takes care of any per data header information: // for long columns, reads off textptrs, reads length, check nullability // for other columns, reads length, checks nullability // returns length and nullability internal bool TryProcessColumnHeader(SqlMetaDataPriv col, TdsParserStateObject stateObj, int columnOrdinal, out bool isNull, out ulong length) { // query NBC row information first if (stateObj.IsNullCompressionBitSet(columnOrdinal)) { isNull = true; // column information is not present in TDS if null compression bit is set, return now length = 0; return true; } return TryProcessColumnHeaderNoNBC(col, stateObj, out isNull, out length); }
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 object GetNullSqlValue(SqlBuffer nullVal, SqlMetaDataPriv md) { switch (md.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: break; default: Debug.Assert(false, "unknown null sqlType!" + md.type.ToString()); break; } return nullVal; }
/// <summary> /// Deserializes the unencrypted bytes into a value based on the target type info. /// </summary> internal bool DeserializeUnencryptedValue (SqlBuffer value, byte[] unencryptedBytes, SqlMetaDataPriv md, TdsParserStateObject stateObj, byte normalizationVersion) { if (normalizationVersion != 0x01) { throw SQL.UnsupportedNormalizationVersion(normalizationVersion); } byte tdsType = md.baseTI.tdsType; int length = unencryptedBytes.Length; // For normalized types, the length and scale of the actual type might be different than the value's. int denormalizedLength = md.baseTI.length; byte denormalizedScale = md.baseTI.scale; Debug.Assert (false == md.baseTI.isEncrypted, "Double encryption detected"); switch (tdsType) { // We normalize to allow conversion across data types. All data types below are serialized into a BIGINT. case TdsEnums.SQLBIT: case TdsEnums.SQLBITN: case TdsEnums.SQLINTN: case TdsEnums.SQLINT1: case TdsEnums.SQLINT2: case TdsEnums.SQLINT4: case TdsEnums.SQLINT8: Debug.Assert(length == 8, "invalid length for SqlInt64 type!"); byte byteValue; long longValue; if (unencryptedBytes.Length != 8) { return false; } longValue = BitConverter.ToInt64(unencryptedBytes, 0); if (tdsType == TdsEnums.SQLBIT || tdsType == TdsEnums.SQLBITN) { value.Boolean = (longValue != 0); break; } if (tdsType == TdsEnums.SQLINT1 || denormalizedLength == 1) value.Byte = (byte)longValue; else if (tdsType == TdsEnums.SQLINT2 || denormalizedLength == 2) value.Int16 = (Int16)longValue; else if (tdsType == TdsEnums.SQLINT4 || denormalizedLength == 4) value.Int32 = (Int32)longValue; else 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 (unencryptedBytes.Length != 4) { return false; } singleValue = BitConverter.ToSingle(unencryptedBytes, 0); value.Single = singleValue; break; case TdsEnums.SQLFLT8: double doubleValue; if (unencryptedBytes.Length != 8) { return false; } doubleValue = BitConverter.ToDouble(unencryptedBytes, 0); value.Double = doubleValue; break; // We normalize to allow conversion across data types. SMALLMONEY is serialized into a MONEY. case TdsEnums.SQLMONEYN: case TdsEnums.SQLMONEY4: case TdsEnums.SQLMONEY: { int mid; uint lo; if (unencryptedBytes.Length != 8) { return false; } mid = BitConverter.ToInt32(unencryptedBytes, 0); lo = BitConverter.ToUInt32(unencryptedBytes, 4); long l = (((long)mid) << 0x20) + ((long)lo); value.SetToMoney(l); break; } case TdsEnums.SQLDATETIMN: if (length == 4) { goto case TdsEnums.SQLDATETIM4; } else { goto case TdsEnums.SQLDATETIME; } case TdsEnums.SQLDATETIM4: ushort daypartShort, timepartShort; if (unencryptedBytes.Length != 4) { return false; } daypartShort = (UInt16)((unencryptedBytes[1] << 8) + unencryptedBytes[0]); timepartShort = (UInt16)((unencryptedBytes[3] << 8) + unencryptedBytes[2]); value.SetToDateTime(daypartShort, timepartShort * SqlDateTime.SQLTicksPerMinute); break; case TdsEnums.SQLDATETIME: int daypart; uint timepart; if (unencryptedBytes.Length != 8) { return false; } daypart = BitConverter.ToInt32(unencryptedBytes, 0); timepart = BitConverter.ToUInt32(unencryptedBytes, 4); value.SetToDateTime(daypart, (int)timepart); break; case TdsEnums.SQLUNIQUEID: { Debug.Assert(length == 16, "invalid length for SqlGuid type!"); value.SqlGuid = new SqlGuid(unencryptedBytes, 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, "Plp data decryption attempted"); // If this is a fixed length type, pad with zeros to get to the fixed length size. if (tdsType == TdsEnums.SQLBINARY || tdsType == TdsEnums.SQLBIGBINARY) { byte[] bytes = new byte[md.baseTI.length]; Buffer.BlockCopy(unencryptedBytes, 0, bytes, 0, unencryptedBytes.Length); unencryptedBytes = bytes; } value.SqlBinary = new SqlBinary(unencryptedBytes, true); // doesn't copy the byte array break; } case TdsEnums.SQLDECIMALN: case TdsEnums.SQLNUMERICN: // Check the sign from the first byte. int index = 0; byteValue = unencryptedBytes[index++]; bool fPositive = (1 == byteValue); // Now read the 4 next integers which contain the actual value. length = checked((int)length-1); int[] bits = new int[4]; int decLength = length>>2; for (int i = 0; i < decLength; i++) { // up to 16 bytes of data following the sign byte bits[i] = BitConverter.ToInt32(unencryptedBytes, index); index += 4; } value.SetToDecimal (md.baseTI.precision, md.baseTI.scale, fPositive, bits); break; case TdsEnums.SQLCHAR: case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLVARCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: { System.Text.Encoding encoding = md.baseTI.encoding; if (null == encoding) { encoding = _defaultEncoding; } if (null == encoding) { ThrowUnsupportedCollationEncountered(stateObj); } string strValue = encoding.GetString(unencryptedBytes, 0, length); // If this is a fixed length type, pad with spaces to get to the fixed length size. if (tdsType == TdsEnums.SQLCHAR || tdsType == TdsEnums.SQLBIGCHAR) { strValue = strValue.PadRight(md.baseTI.length); } value.SetToString(strValue); break; } case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: { string strValue = System.Text.Encoding.Unicode.GetString(unencryptedBytes, 0, length); // If this is a fixed length type, pad with spaces to get to the fixed length size. if (tdsType == TdsEnums.SQLNCHAR) { strValue = strValue.PadRight(md.baseTI.length / ADP.CharSize); } value.SetToString(strValue); break; } case TdsEnums.SQLDATE: Debug.Assert(length == 3, "invalid length for date type!"); value.SetToDate(unencryptedBytes); break; case TdsEnums.SQLTIME: // We normalize to maximum precision to allow conversion across different precisions. Debug.Assert(length == 5, "invalid length for time type!"); value.SetToTime(unencryptedBytes, length, TdsEnums.MAX_TIME_SCALE, denormalizedScale); break; case TdsEnums.SQLDATETIME2: // We normalize to maximum precision to allow conversion across different precisions. Debug.Assert(length == 8, "invalid length for datetime2 type!"); value.SetToDateTime2(unencryptedBytes, length, TdsEnums.MAX_TIME_SCALE, denormalizedScale); break; case TdsEnums.SQLDATETIMEOFFSET: // We normalize to maximum precision to allow conversion across different precisions. Debug.Assert(length == 10, "invalid length for datetimeoffset type!"); value.SetToDateTimeOffset(unencryptedBytes, length, TdsEnums.MAX_TIME_SCALE, denormalizedScale); break; default: MetaType metaType = md.baseTI.metaType; // If we don't have a metatype already, construct one to get the proper type name. if (metaType == null) { metaType = MetaType.GetSqlDataType(tdsType, userType:0, length:length); } throw SQL.UnsupportedDatatypeEncryption(metaType.TypeName); } 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; }
internal Task WriteBulkCopyValue(object value, SqlMetaDataPriv metadata, TdsParserStateObject stateObj, bool isSqlType, bool isDataFeed, bool isNull) { Debug.Assert(!isSqlType || value is INullable, "isSqlType is true, but value can not be type cast to an INullable"); Debug.Assert(!isDataFeed ^ value is DataFeed, "Incorrect value for isDataFeed"); Encoding saveEncoding = _defaultEncoding; SqlCollation saveCollation = _defaultCollation; int saveCodePage = _defaultCodePage; int saveLCID = _defaultLCID; Task resultTask = null; Task internalWriteTask = null; if (!(State == TdsParserState.OpenNotLoggedIn || State == TdsParserState.OpenLoggedIn)) { throw ADP.ClosedConnectionError(); } try { if (metadata.encoding != null) { _defaultEncoding = metadata.encoding; } if (metadata.collation != null) { _defaultCollation = metadata.collation; _defaultLCID = _defaultCollation.LCID; } _defaultCodePage = metadata.codePage; MetaType metatype = metadata.metaType; int ccb = 0; int ccbStringBytes = 0; if (isNull) { // For UDT, remember we treat as binary even though it is a PLP if (metatype.IsPlp && (metatype.NullableType != TdsEnums.SQLUDT || metatype.IsLong)) { WriteLong(unchecked((long)TdsEnums.SQL_PLP_NULL), stateObj); } else if (!metatype.IsFixed && !metatype.IsLong && !metatype.IsVarTime) { WriteShort(TdsEnums.VARNULL, stateObj); } else { stateObj.WriteByte(TdsEnums.FIXEDNULL); } return resultTask; } if (!isDataFeed) { switch (metatype.NullableType) { case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLIMAGE: case TdsEnums.SQLUDT: ccb = (isSqlType) ? ((SqlBinary)value).Length : ((byte[])value).Length; break; case TdsEnums.SQLUNIQUEID: ccb = GUID_SIZE; // that's a constant for guid break; case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: if (null == _defaultEncoding) { ThrowUnsupportedCollationEncountered(null); // stateObject only when reading } string stringValue = null; if (isSqlType) { stringValue = ((SqlString)value).Value; } else { stringValue = (string)value; } ccb = stringValue.Length; ccbStringBytes = _defaultEncoding.GetByteCount(stringValue); break; case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: ccb = ((isSqlType) ? ((SqlString)value).Value.Length : ((string)value).Length) * 2; break; case TdsEnums.SQLXMLTYPE: // Value here could be string or XmlReader if (value is XmlReader) { value = MetaType.GetStringFromXml((XmlReader)value); } ccb = ((isSqlType) ? ((SqlString)value).Value.Length : ((string)value).Length) * 2; break; default: ccb = metadata.length; break; } } else { Debug.Assert(metatype.IsLong && ((metatype.SqlDbType == SqlDbType.VarBinary && value is StreamDataFeed) || ((metatype.SqlDbType == SqlDbType.VarChar || metatype.SqlDbType == SqlDbType.NVarChar) && value is TextDataFeed) || (metatype.SqlDbType == SqlDbType.Xml && value is XmlDataFeed)), "Stream data feed should only be assigned to VarBinary(max), Text data feed should only be assigned to [N]VarChar(max), Xml data feed should only be assigned to XML(max)"); } // Expected the text length in data stream for bulk copy of text, ntext, or image data. // if (metatype.IsLong) { switch (metatype.SqlDbType) { case SqlDbType.Text: case SqlDbType.NText: case SqlDbType.Image: stateObj.WriteByteArray(s_longDataHeader, s_longDataHeader.Length, 0); WriteTokenLength(metadata.tdsType, ccbStringBytes == 0 ? ccb : ccbStringBytes, stateObj); break; case SqlDbType.VarChar: case SqlDbType.NVarChar: case SqlDbType.VarBinary: case SqlDbType.Xml: case SqlDbType.Udt: // plp data WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, stateObj); break; } } else { WriteTokenLength(metadata.tdsType, ccbStringBytes == 0 ? ccb : ccbStringBytes, stateObj); } if (isSqlType) { internalWriteTask = WriteSqlValue(value, metatype, ccb, ccbStringBytes, 0, stateObj); } else if (metatype.SqlDbType != SqlDbType.Udt || metatype.IsLong) { internalWriteTask = WriteValue(value, metatype, metadata.scale, ccb, ccbStringBytes, 0, stateObj, metadata.length, isDataFeed); if ((internalWriteTask == null) && (_asyncWrite)) { internalWriteTask = stateObj.WaitForAccumulatedWrites(); } Debug.Assert(_asyncWrite || stateObj.WaitForAccumulatedWrites() == null, "Should not have accumulated writes when writing sync"); } else { WriteShort(ccb, stateObj); internalWriteTask = stateObj.WriteByteArray((byte[])value, ccb, 0); } #if DEBUG //In DEBUG mode, when SetAlwaysTaskOnWrite is true, we create a task. Allows us to verify async execution paths. if (_asyncWrite && internalWriteTask == null && SqlBulkCopy.SetAlwaysTaskOnWrite == true) { internalWriteTask = Task.FromResult<object>(null); } #endif if (internalWriteTask != null) { //i.e. the write was async. resultTask = WriteBulkCopyValueSetupContinuation(internalWriteTask, saveEncoding, saveCollation, saveCodePage, saveLCID); } } finally { if (internalWriteTask == null) { _defaultEncoding = saveEncoding; _defaultCollation = saveCollation; _defaultCodePage = saveCodePage; _defaultLCID = saveLCID; } } return resultTask; }
/// <summary> /// Writes the UserType and TYPE_INFO values for CryptoMetadata (for bulk copy). /// </summary> /// <returns></returns> internal void WriteTceUserTypeAndTypeInfo(SqlMetaDataPriv mdPriv, TdsParserStateObject stateObj) { // Write the UserType (4 byte value) WriteInt(0x0, stateObj); // TODO: fix this- timestamp columns have 0x50 value here Debug.Assert(SqlDbType.Xml != mdPriv.type); Debug.Assert(SqlDbType.Udt != mdPriv.type); stateObj.WriteByte(mdPriv.tdsType); switch (mdPriv.type) { case SqlDbType.Decimal: WriteTokenLength(mdPriv.tdsType, mdPriv.length, stateObj); stateObj.WriteByte(mdPriv.precision); stateObj.WriteByte(mdPriv.scale); break; case SqlDbType.Date: // Nothing more to write! break; case SqlDbType.Time: case SqlDbType.DateTime2: case SqlDbType.DateTimeOffset: stateObj.WriteByte(mdPriv.scale); break; default: WriteTokenLength(mdPriv.tdsType, mdPriv.length, stateObj); if (mdPriv.metaType.IsCharType && _isShiloh) { WriteUnsignedInt(mdPriv.collation.info, stateObj); stateObj.WriteByte(mdPriv.collation.sortId); } break; } }
/// <summary> /// Encrypts a column value (for SqlBulkCopy) /// </summary> /// <returns></returns> internal object EncryptColumnValue (object value, SqlMetaDataPriv metadata, string column, TdsParserStateObject stateObj, bool isDataFeed, bool isSqlType) { Debug.Assert (_serverSupportsColumnEncryption, "Server doesn't support encryption, yet we received encryption metadata"); Debug.Assert (ShouldEncryptValuesForBulkCopy(), "Encryption attempted when not requested"); if (isDataFeed) { // can't encrypt a stream column SQL.StreamNotSupportOnEncryptedColumn(column); } int actualLengthInBytes; switch(metadata.baseTI.metaType.NullableType) { case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLIMAGE: // For some datatypes, engine does truncation before storing the value. (For example, when // trying to insert a varbinary(7000) into a varbinary(3000) column). Since we encrypt the // column values, engine has no way to tell the size of the plaintext datatype. Therefore, // we truncate the values based on target column sizes here before encrypting them. This // truncation is only needed if we exceed the max column length or if the target column is // not a blob type (eg. varbinary(max)). The actual work of truncating the column happens // when we normalize and serialize the data buffers. The serialization routine expects us // to report the size of data to be copied out (for serialization). If we underreport the // size, truncation will happen for us! actualLengthInBytes = (isSqlType) ? ((SqlBinary)value).Length : ((byte[])value).Length; if (metadata.baseTI.length > 0 && actualLengthInBytes > metadata.baseTI.length) { // see comments agove actualLengthInBytes = metadata.baseTI.length; } break; case TdsEnums.SQLUNIQUEID: actualLengthInBytes = GUID_SIZE; // that's a constant for guid break; case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: if (null == _defaultEncoding) { ThrowUnsupportedCollationEncountered(null); // stateObject only when reading } string stringValue = (isSqlType) ? ((SqlString)value).Value : (string)value; actualLengthInBytes = _defaultEncoding.GetByteCount(stringValue); // If the string length is > max length, then use the max length (see comments above) if (metadata.baseTI.length > 0 && actualLengthInBytes > metadata.baseTI.length) { actualLengthInBytes = metadata.baseTI.length; // this ensure truncation! } break; case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: actualLengthInBytes = ((isSqlType) ? ((SqlString)value).Value.Length : ((string)value).Length) * 2; if (metadata.baseTI.length > 0 && actualLengthInBytes > metadata.baseTI.length) { // see comments above actualLengthInBytes = metadata.baseTI.length; } break; default: actualLengthInBytes = metadata.baseTI.length; break; } byte[] serializedValue; if (isSqlType) { // SqlType serializedValue = SerializeUnencryptedSqlValue (value, metadata.baseTI.metaType, actualLengthInBytes, offset : 0, normalizationVersion: metadata.cipherMD.NormalizationRuleVersion, stateObj: stateObj); } else { serializedValue = SerializeUnencryptedValue (value, metadata.baseTI.metaType, metadata.baseTI.scale, actualLengthInBytes, offset: 0, isDataFeed: isDataFeed, normalizationVersion: metadata.cipherMD.NormalizationRuleVersion, stateObj: stateObj); } Debug.Assert(serializedValue != null, "serializedValue should not be null in TdsExecuteRPC."); return SqlSecurityUtility.EncryptWithKey( serializedValue, metadata.cipherMD, _connHandler.ConnectionOptions.DataSource); }
internal ulong ProcessColumnHeader(SqlMetaDataPriv col, TdsParserStateObject stateObj, out bool isNull) { if (col.metaType.IsLong && !col.metaType.IsPlp) { byte num = stateObj.ReadByte(); if (num != 0) { this.SkipBytes(num, stateObj); this.SkipBytes(8, stateObj); isNull = false; return this.GetDataLength(col, stateObj); } isNull = true; return 0L; } ulong dataLength = this.GetDataLength(col, stateObj); isNull = this.IsNull(col.metaType, dataLength); if (!isNull) { return dataLength; } return 0L; }