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 void Bind(TdsParserStateObject stateObj) { stateObj.Owner = this; this._stateObj = stateObj; this._parser = stateObj.Parser; this._defaultLCID = this._parser.DefaultLCID; }
internal TdsValueSetter(TdsParserStateObject stateObj, SmiMetaData md) { this._stateObj = stateObj; this._metaData = md; this._isPlp = MetaDataUtilsSmi.IsPlpFormat(md); this._plpUnknownSent = false; this._encoder = null; }
private int _currentOffset; // for chunking, verify that caller is using correct offsets #endif #endregion #region Exposed Construct/factory methods internal TdsValueSetter(TdsParserStateObject stateObj, SmiMetaData md) { _stateObj = stateObj; _metaData = md; _isPlp = MetaDataUtilsSmi.IsPlpFormat(md); _plpUnknownSent = false; _encoder = null; #if DEBUG _currentOffset = 0; #endif }
internal TdsRecordBufferSetter(TdsParserStateObject stateObj, SmiMetaData md) { this._fieldSetters = new TdsValueSetter[md.FieldMetaData.Count]; for (int i = 0; i < md.FieldMetaData.Count; i++) { this._fieldSetters[i] = new TdsValueSetter(stateObj, md.FieldMetaData[i]); } this._stateObj = stateObj; this._metaData = md; }
private int _currentField; // validate that caller sets columns in correct order. #endif #endregion #region Exposed Construct and control methods/properties internal TdsRecordBufferSetter(TdsParserStateObject stateObj, SmiMetaData md) { Debug.Assert(SqlDbType.Structured == md.SqlDbType, "Unsupported SqlDbType: " + md.SqlDbType); _fieldSetters = new TdsValueSetter[md.FieldMetaData.Count]; for(int i=0; i<md.FieldMetaData.Count; i++) { _fieldSetters[i] = new TdsValueSetter(stateObj, md.FieldMetaData[i]); } _stateObj = stateObj; _metaData = md; #if DEBUG _currentField = ReadyForToken; #endif }
// 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; }
private const ulong _indeterminateSize = 0xffffffffffffffff; // Represents unknown size internal ulong PlpBytesTotalLength(TdsParserStateObject stateObj) { if (stateObj._longlen == TdsEnums.SQL_PLP_UNKNOWNLEN) return _indeterminateSize; else if (stateObj._longlen == TdsEnums.SQL_PLP_NULL) return 0; return stateObj._longlen; }
internal ulong PlpBytesLeft(TdsParserStateObject stateObj) { if ((stateObj._longlen != 0) && (stateObj._longlenleft == 0)) stateObj.ReadPlpLength(false); return stateObj._longlenleft; }
// ensure value is not null and does not have an NBC bit set for it before using this method internal ulong SkipPlpValue(ulong cb, TdsParserStateObject stateObj) { ulong skipped; Debug.Assert(stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); bool result = TrySkipPlpValue(cb, stateObj, out skipped); if (!result) { throw SQL.SynchronousCallMayNotPend(); } return skipped; }
// Reads the requested number of chars from a plp data stream, or the entire data if // requested length is -1 or larger than the actual length of data. First call to this method // should be preceeded by a call to ReadPlpLength or ReadDataLength. // Returns the actual chars read. internal bool TryReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj, out int totalCharsRead) { int charsRead = 0; int charsLeft = 0; char[] newbuf; if (stateObj._longlen == 0) { Debug.Assert(stateObj._longlenleft == 0); totalCharsRead = 0; return true; // 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 ReadPlpUnicodeChars()!"); charsLeft = len; // If total length is known up front, allocate the whole buffer in one shot instead of realloc'ing and copying over each time if (buff == null && stateObj._longlen != TdsEnums.SQL_PLP_UNKNOWNLEN) { buff = new char[(int)Math.Min((int)stateObj._longlen, len)]; } if (stateObj._longlenleft == 0) { ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { totalCharsRead = 0; return false; } if (stateObj._longlenleft == 0) { // Data read complete totalCharsRead = 0; return true; } } totalCharsRead = 0; while (charsLeft > 0) { charsRead = (int)Math.Min((stateObj._longlenleft + 1) >> 1, (ulong)charsLeft); if ((buff == null) || (buff.Length < (offst + charsRead))) { // Grow the array newbuf = new char[offst + charsRead]; if (buff != null) { Buffer.BlockCopy(buff, 0, newbuf, 0, offst * 2); } buff = newbuf; } if (charsRead > 0) { if (!TryReadPlpUnicodeCharsChunk(buff, offst, charsRead, stateObj, out charsRead)) { return false; } charsLeft -= charsRead; offst += charsRead; totalCharsRead += charsRead; } // Special case single byte left if (stateObj._longlenleft == 1 && (charsLeft > 0)) { byte b1; if (!stateObj.TryReadByte(out b1)) { return false; } stateObj._longlenleft--; ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } Debug.Assert((stateObj._longlenleft != 0), "ReadPlpUnicodeChars: Odd byte left at the end!"); byte b2; if (!stateObj.TryReadByte(out b2)) { return false; } stateObj._longlenleft--; // Put it at the end of the array. At this point we know we have an extra byte. buff[offst] = (char)(((b2 & 0xff) << 8) + (b1 & 0xff)); offst = checked((int)offst + 1); charsRead++; charsLeft--; totalCharsRead++; } if (stateObj._longlenleft == 0) { // Read the next chunk or cleanup state if hit the end ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } } if (stateObj._longlenleft == 0) // Data read complete break; } return true; }
// Reads the next chunk in a nvarchar(max) data stream. // This call must be preceeded by a call to ReadPlpLength or ReadDataLength. // Will not start reading into the next chunk if bytes requested is larger than // the current chunk length. Do another ReadPlpLength, ReadPlpUnicodeChars in that case. // Returns the actual chars read private bool TryReadPlpUnicodeCharsChunk(char[] buff, int offst, int len, TdsParserStateObject stateObj, out int charsRead) { Debug.Assert((buff == null && len == 0) || (buff.Length >= offst + len), "Invalid length sent to ReadPlpUnicodeChars()!"); Debug.Assert((stateObj._longlen != 0) && (stateObj._longlen != TdsEnums.SQL_PLP_NULL), "Out of sync plp read request"); if (stateObj._longlenleft == 0) { Debug.Assert(false, "Out of sync read request"); charsRead = 0; return true; } charsRead = len; // stateObj._longlenleft is in bytes if ((stateObj._longlenleft >> 1) < (ulong)len) charsRead = (int)(stateObj._longlenleft >> 1); for (int ii = 0; ii < charsRead; ii++) { if (!stateObj.TryReadChar(out buff[offst + ii])) { return false; } } stateObj._longlenleft -= ((ulong)charsRead << 1); return true; }
// For MAX types, this method can only write everything in one big chunk. If multiple // chunk writes needed, please use WritePlpBytes/WritePlpChars private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int actualLength, int encodingByteSize, int offset, TdsParserStateObject stateObj, int paramSize, bool isDataFeed) { Debug.Assert((null != value) && (DBNull.Value != value), "unexpected missing or empty object"); // parameters are always sent over as BIG or N types switch (type.NullableType) { case TdsEnums.SQLFLTN: if (type.FixedLength == 4) WriteFloat((Single)value, stateObj); else { Debug.Assert(type.FixedLength == 8, "Invalid length for SqlDouble type!"); WriteDouble((Double)value, stateObj); } break; case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLIMAGE: case TdsEnums.SQLUDT: { // An array should be in the object Debug.Assert(isDataFeed || value is byte[], "Value should be an array of bytes"); Debug.Assert(!isDataFeed || value is StreamDataFeed, "Value should be a stream"); if (isDataFeed) { Debug.Assert(type.IsPlp, "Stream assigned to non-PLP was not converted!"); return NullIfCompletedWriteTask(WriteStreamFeed((StreamDataFeed)value, stateObj, paramSize)); } else { if (type.IsPlp) { WriteInt(actualLength, stateObj); // chunk length } return stateObj.WriteByteArray((byte[])value, actualLength, offset, canAccumulate: false); } } case TdsEnums.SQLUNIQUEID: { System.Guid guid = (System.Guid)value; byte[] b = guid.ToByteArray(); Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); stateObj.WriteByteArray(b, actualLength, 0); break; } case TdsEnums.SQLBITN: { Debug.Assert(type.FixedLength == 1, "Invalid length for SqlBoolean type"); if ((bool)value == true) stateObj.WriteByte(1); else stateObj.WriteByte(0); break; } case TdsEnums.SQLINTN: if (type.FixedLength == 1) stateObj.WriteByte((byte)value); else if (type.FixedLength == 2) WriteShort((Int16)value, stateObj); else if (type.FixedLength == 4) WriteInt((Int32)value, stateObj); else { Debug.Assert(type.FixedLength == 8, "invalid length for SqlIntN type: " + type.FixedLength.ToString(CultureInfo.InvariantCulture)); WriteLong((Int64)value, stateObj); } break; case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: { Debug.Assert(!isDataFeed || (value is TextDataFeed || value is XmlDataFeed), "Value must be a TextReader or XmlReader"); Debug.Assert(isDataFeed || (value is string || value is byte[]), "Value is a byte array or string"); if (isDataFeed) { Debug.Assert(type.IsPlp, "Stream assigned to non-PLP was not converted!"); TextDataFeed tdf = value as TextDataFeed; if (tdf == null) { return NullIfCompletedWriteTask(WriteXmlFeed((XmlDataFeed)value, stateObj, needBom: true, encoding: _defaultEncoding, size: paramSize)); } else { return NullIfCompletedWriteTask(WriteTextFeed(tdf, _defaultEncoding, false, stateObj, paramSize)); } } else { if (type.IsPlp) { WriteInt(encodingByteSize, stateObj); // chunk length } if (value is byte[]) { // If LazyMat non-filled blob, send cookie rather than value return stateObj.WriteByteArray((byte[])value, actualLength, 0, canAccumulate: false); } else { return WriteEncodingChar((string)value, actualLength, offset, _defaultEncoding, stateObj, canAccumulate: false); } } } case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: case TdsEnums.SQLXMLTYPE: { Debug.Assert(!isDataFeed || (value is TextDataFeed || value is XmlDataFeed), "Value must be a TextReader or XmlReader"); Debug.Assert(isDataFeed || (value is string || value is byte[]), "Value is a byte array or string"); if (isDataFeed) { Debug.Assert(type.IsPlp, "Stream assigned to non-PLP was not converted!"); TextDataFeed tdf = value as TextDataFeed; if (tdf == null) { return NullIfCompletedWriteTask(WriteXmlFeed((XmlDataFeed)value, stateObj, IsBOMNeeded(type, value), Encoding.Unicode, paramSize)); } else { return NullIfCompletedWriteTask(WriteTextFeed(tdf, null, IsBOMNeeded(type, value), stateObj, paramSize)); } } else { if (type.IsPlp) { if (IsBOMNeeded(type, value)) { WriteInt(actualLength + 2, stateObj); // chunk length WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); } else { WriteInt(actualLength, stateObj); // chunk length } } if (value is byte[]) { // If LazyMat non-filled blob, send cookie rather than value return stateObj.WriteByteArray((byte[])value, actualLength, 0, canAccumulate: false); } else { // convert to cchars instead of cbytes actualLength >>= 1; return WriteString((string)value, actualLength, offset, stateObj, canAccumulate: false); } } } case TdsEnums.SQLNUMERICN: Debug.Assert(type.FixedLength <= 17, "Decimal length cannot be greater than 17 bytes"); WriteDecimal((Decimal)value, stateObj); break; case TdsEnums.SQLDATETIMN: Debug.Assert(type.FixedLength <= 0xff, "Invalid Fixed Length"); TdsDateTime dt = MetaType.FromDateTime((DateTime)value, (byte)type.FixedLength); if (type.FixedLength == 4) { if (0 > dt.days || dt.days > UInt16.MaxValue) throw SQL.SmallDateTimeOverflow(MetaType.ToDateTime(dt.days, dt.time, 4).ToString(CultureInfo.InvariantCulture)); WriteShort(dt.days, stateObj); WriteShort(dt.time, stateObj); } else { WriteInt(dt.days, stateObj); WriteInt(dt.time, stateObj); } break; case TdsEnums.SQLMONEYN: { WriteCurrency((Decimal)value, type.FixedLength, stateObj); break; } case TdsEnums.SQLDATE: { WriteDate((DateTime)value, stateObj); break; } case TdsEnums.SQLTIME: if (scale > TdsEnums.DEFAULT_VARTIME_SCALE) { throw SQL.TimeScaleValueOutOfRange(scale); } WriteTime((TimeSpan)value, scale, actualLength, stateObj); break; case TdsEnums.SQLDATETIME2: if (scale > TdsEnums.DEFAULT_VARTIME_SCALE) { throw SQL.TimeScaleValueOutOfRange(scale); } WriteDateTime2((DateTime)value, scale, actualLength, stateObj); break; case TdsEnums.SQLDATETIMEOFFSET: WriteDateTimeOffset((DateTimeOffset)value, scale, actualLength, stateObj); break; default: Debug.Assert(false, "Unknown TdsType!" + type.NullableType.ToString("x2", (IFormatProvider)null)); break; } // switch // return point for accumualated writes, note: non-accumulated writes returned from their case statements return null; // Debug.WriteLine("value: " + value.ToString(CultureInfo.InvariantCulture)); }
private void WriteRPCBatchHeaders(TdsParserStateObject stateObj) { /* Header: TotalLength - DWORD - including all headers and lengths, including itself Each Data Session: { HeaderLength - DWORD - including all header length fields, including itself HeaderType - USHORT HeaderData } */ const int marsHeaderSize = 18; // 4 + 2 + 8 + 4 int totalHeaderLength = 4 + marsHeaderSize; Debug.Assert(stateObj._outBytesUsed == stateObj._outputHeaderLen, "Output bytes written before total header length"); // Write total header length WriteInt(totalHeaderLength, stateObj); // Write Mars header length WriteInt(marsHeaderSize, stateObj); // Write Mars header data WriteMarsHeaderData(stateObj, CurrentTransaction); }
// Write mars header data, not including the mars header length private void WriteMarsHeaderData(TdsParserStateObject stateObj, SqlInternalTransaction transaction) { // Function to send over additional payload header data for Yukon and beyond only. // These are not necessary - can have local started in distributed. // Debug.Assert(!(null != sqlTransaction && null != distributedTransaction), "Error to have local (api started) and distributed transaction at the same time!"); // Debug.Assert(!(null != _userStartedLocalTransaction && null != distributedTransaction), "Error to have local (started outside of the api) and distributed transaction at the same time!"); // We may need to update the mars header length if mars header is changed in the future WriteShort(TdsEnums.HEADERTYPE_MARS, stateObj); if (null != transaction && SqlInternalTransaction.NullTransactionId != transaction.TransactionId) { WriteLong(transaction.TransactionId, stateObj); WriteInt(stateObj.IncrementAndObtainOpenResultCount(transaction), stateObj); } else { WriteLong(SqlInternalTransaction.NullTransactionId, stateObj); WriteInt(stateObj.IncrementAndObtainOpenResultCount(null), stateObj); } }
private async Task WriteStreamFeed(StreamDataFeed feed, TdsParserStateObject stateObj, int len) { TdsOutputStream output = new TdsOutputStream(this, stateObj, null); byte[] buff = new byte[constBinBufferSize]; int nWritten = 0; do { int nRead = 0; int readSize = constBinBufferSize; if (len > 0 && nWritten + readSize > len) { readSize = len - nWritten; } Debug.Assert(readSize >= 0); if (_asyncWrite) { nRead = await feed._source.ReadAsync(buff, 0, readSize).ConfigureAwait(false); } else { nRead = feed._source.Read(buff, 0, readSize); } if (nRead == 0) { return; } if (_asyncWrite) { await output.WriteAsync(buff, 0, nRead).ConfigureAwait(false); } else { output.Write(buff, 0, nRead); } nWritten += nRead; } while (len <= 0 || nWritten < len); }
private Task WriteValue(object value, MetaType type, byte scale, int actualLength, int encodingByteSize, int offset, TdsParserStateObject stateObj, int paramSize, bool isDataFeed) { return GetTerminationTask(WriteUnterminatedValue(value, type, scale, actualLength, encodingByteSize, offset, stateObj, paramSize, isDataFeed), value, type, actualLength, stateObj, isDataFeed); }
// // Reverse function of GetTokenLength // private void WriteTokenLength(byte token, int length, TdsParserStateObject stateObj) { int tokenLength = 0; Debug.Assert(token != 0, "0 length token!"); // For Plp fields, this should only be used when writing to metadata header. // For actual data length, WriteDataLength should be used. // For Xml fields, there is no token length field. For MAX fields it is 0xffff. { if (TdsEnums.SQLUDT == token) { tokenLength = 8; } else if (token == TdsEnums.SQLXMLTYPE) { tokenLength = 8; } } if (tokenLength == 0) { switch (token & TdsEnums.SQLLenMask) { case TdsEnums.SQLFixedLen: Debug.Assert(length == 0x01 << ((token & 0x0c) >> 2), "length does not match encoded length in token"); tokenLength = 0; break; case TdsEnums.SQLZeroLen: tokenLength = 0; break; case TdsEnums.SQLVarLen: case TdsEnums.SQLVarCnt: if (0 != (token & 0x80)) tokenLength = 2; else if (0 == (token & 0x0c)) tokenLength = 4; else tokenLength = 1; break; default: Debug.Assert(false, "Unknown token length!"); break; } switch (tokenLength) { case 1: stateObj.WriteByte((byte)length); break; case 2: WriteShort(length, stateObj); break; case 4: WriteInt(length, stateObj); break; case 8: // In the metadata case we write 0xffff for partial length prefixed types. // For actual data length preceding data, WriteDataLength should be used. WriteShort(TdsEnums.SQL_USHORTVARMAXLEN, stateObj); break; } // end switch } }
// // we always send over nullable types for parameters so we always write the varlen fields // internal void WriteParameterVarLen(MetaType type, int size, bool isNull, TdsParserStateObject stateObj, bool unknownLength = false) { if (type.IsLong) { // text/image/SQLVariant have a 4 byte length, plp datatypes have 8 byte lengths if (isNull) { if (type.IsPlp) { WriteLong(unchecked((long)TdsEnums.SQL_PLP_NULL), stateObj); } else { WriteInt(unchecked((int)TdsEnums.VARLONGNULL), stateObj); } } else if (type.NullableType == TdsEnums.SQLXMLTYPE || unknownLength) { WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, stateObj); } else if (type.IsPlp) { // Non-xml plp types WriteLong((long)size, stateObj); } else { WriteInt(size, stateObj); } } else if (type.IsVarTime) { if (isNull) { stateObj.WriteByte(TdsEnums.FIXEDNULL); } else { stateObj.WriteByte((byte)size); } } else if (false == type.IsFixed) { // non-long but variable length column, must be a BIG* type: 2 byte length if (isNull) { WriteShort(TdsEnums.VARNULL, stateObj); } else { WriteShort(size, stateObj); } } else { if (isNull) { stateObj.WriteByte(TdsEnums.FIXEDNULL); } else { Debug.Assert(type.FixedLength <= 0xff, "WriteParameterVarLen: invalid one byte length!"); stateObj.WriteByte((byte)(type.FixedLength & 0xff)); // 1 byte for everything else } } }
private Task GetTerminationTask(Task unterminatedWriteTask, object value, MetaType type, int actualLength, TdsParserStateObject stateObj, bool isDataFeed) { if (type.IsPlp && ((actualLength > 0) || isDataFeed)) { if (unterminatedWriteTask == null) { WriteInt(0, stateObj); return null; } else { return AsyncHelper.CreateContinuationTask<int, TdsParserStateObject>(unterminatedWriteTask, WriteInt, 0, stateObj, connectionToDoom: _connHandler); } } else { return unterminatedWriteTask; } }
internal int ReadPlpUnicodeChars(ref char[] buff, int offst, int len, TdsParserStateObject stateObj) { int charsRead; Debug.Assert(stateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); bool result = TryReadPlpUnicodeChars(ref buff, offst, len, stateObj, out charsRead); if (!result) { throw SQL.SynchronousCallMayNotPend(); } return charsRead; }
private Task WriteSqlValue(object value, MetaType type, int actualLength, int codePageByteSize, int offset, TdsParserStateObject stateObj) { return GetTerminationTask( WriteUnterminatedSqlValue(value, type, actualLength, codePageByteSize, offset, stateObj), value, type, actualLength, stateObj, false); }
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); }
// For MAX types, this method can only write everything in one big chunk. If multiple // chunk writes needed, please use WritePlpBytes/WritePlpChars private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLength, int codePageByteSize, int offset, TdsParserStateObject stateObj) { Debug.Assert(((type.NullableType == TdsEnums.SQLXMLTYPE) || (value is INullable && !((INullable)value).IsNull)), "unexpected null SqlType!"); // parameters are always sent over as BIG or N types switch (type.NullableType) { case TdsEnums.SQLFLTN: if (type.FixedLength == 4) WriteFloat(((SqlSingle)value).Value, stateObj); else { Debug.Assert(type.FixedLength == 8, "Invalid length for SqlDouble type!"); WriteDouble(((SqlDouble)value).Value, stateObj); } break; case TdsEnums.SQLBIGBINARY: case TdsEnums.SQLBIGVARBINARY: case TdsEnums.SQLIMAGE: { if (type.IsPlp) { WriteInt(actualLength, stateObj); // chunk length } if (value is SqlBinary) { return stateObj.WriteByteArray(((SqlBinary)value).Value, actualLength, offset, canAccumulate: false); } else { Debug.Assert(value is SqlBytes); return stateObj.WriteByteArray(((SqlBytes)value).Value, actualLength, offset, canAccumulate: false); } } case TdsEnums.SQLUNIQUEID: { byte[] b = ((SqlGuid)value).ToByteArray(); Debug.Assert((actualLength == b.Length) && (actualLength == 16), "Invalid length for guid type in com+ object"); stateObj.WriteByteArray(b, actualLength, 0); break; } case TdsEnums.SQLBITN: { Debug.Assert(type.FixedLength == 1, "Invalid length for SqlBoolean type"); if (((SqlBoolean)value).Value == true) stateObj.WriteByte(1); else stateObj.WriteByte(0); break; } case TdsEnums.SQLINTN: if (type.FixedLength == 1) stateObj.WriteByte(((SqlByte)value).Value); else if (type.FixedLength == 2) WriteShort(((SqlInt16)value).Value, stateObj); else if (type.FixedLength == 4) WriteInt(((SqlInt32)value).Value, stateObj); else { Debug.Assert(type.FixedLength == 8, "invalid length for SqlIntN type: " + type.FixedLength.ToString(CultureInfo.InvariantCulture)); WriteLong(((SqlInt64)value).Value, stateObj); } break; case TdsEnums.SQLBIGCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: if (type.IsPlp) { WriteInt(codePageByteSize, stateObj); // chunk length } if (value is SqlChars) { String sch = new String(((SqlChars)value).Value); return WriteEncodingChar(sch, actualLength, offset, _defaultEncoding, stateObj, canAccumulate: false); } else { Debug.Assert(value is SqlString); return WriteEncodingChar(((SqlString)value).Value, actualLength, offset, _defaultEncoding, stateObj, canAccumulate: false); } case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: case TdsEnums.SQLXMLTYPE: if (type.IsPlp) { if (IsBOMNeeded(type, value)) { WriteInt(actualLength + 2, stateObj); // chunk length WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); } else { WriteInt(actualLength, stateObj); // chunk length } } // convert to cchars instead of cbytes // Xml type is already converted to string through GetCoercedValue if (actualLength != 0) actualLength >>= 1; if (value is SqlChars) { return WriteCharArray(((SqlChars)value).Value, actualLength, offset, stateObj, canAccumulate: false); } else { Debug.Assert(value is SqlString); return WriteString(((SqlString)value).Value, actualLength, offset, stateObj, canAccumulate: false); } case TdsEnums.SQLNUMERICN: Debug.Assert(type.FixedLength <= 17, "Decimal length cannot be greater than 17 bytes"); WriteSqlDecimal((SqlDecimal)value, stateObj); break; case TdsEnums.SQLDATETIMN: SqlDateTime dt = (SqlDateTime)value; if (type.FixedLength == 4) { if (0 > dt.DayTicks || dt.DayTicks > UInt16.MaxValue) throw SQL.SmallDateTimeOverflow(dt.ToString()); WriteShort(dt.DayTicks, stateObj); WriteShort(dt.TimeTicks / SqlDateTime.SQLTicksPerMinute, stateObj); } else { WriteInt(dt.DayTicks, stateObj); WriteInt(dt.TimeTicks, stateObj); } break; case TdsEnums.SQLMONEYN: { WriteSqlMoney((SqlMoney)value, type.FixedLength, stateObj); break; } case TdsEnums.SQLUDT: throw ADP.DbTypeNotSupported(SqlDbType.Udt.ToString()); default: Debug.Assert(false, "Unknown TdsType!" + type.NullableType.ToString("x2", (IFormatProvider)null)); break; } // switch // return point for accumualated writes, note: non-accumulated writes returned from their case statements return null; }
internal bool TrySkipPlpValue(ulong cb, TdsParserStateObject stateObj, out ulong totalBytesSkipped) { // Read and skip cb bytes or until ReadPlpLength returns 0. int bytesSkipped; totalBytesSkipped = 0; if (stateObj._longlenleft == 0) { ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } } while ((totalBytesSkipped < cb) && (stateObj._longlenleft > 0)) { if (stateObj._longlenleft > Int32.MaxValue) bytesSkipped = Int32.MaxValue; else bytesSkipped = (int)stateObj._longlenleft; bytesSkipped = ((cb - totalBytesSkipped) < (ulong)bytesSkipped) ? (int)(cb - totalBytesSkipped) : bytesSkipped; if (!stateObj.TrySkipBytes(bytesSkipped)) { return false; } stateObj._longlenleft -= (ulong)bytesSkipped; totalBytesSkipped += (ulong)bytesSkipped; if (stateObj._longlenleft == 0) { ulong ignored; if (!stateObj.TryReadPlpLength(false, out ignored)) { return false; } } } return true; }
public TdsOutputStream(TdsParser parser, TdsParserStateObject stateObj, byte[] preambleToStrip) { _parser = parser; _stateObj = stateObj; _preambleToStrip = preambleToStrip; }
internal bool TryPlpBytesLeft(TdsParserStateObject stateObj, out ulong left) { if ((stateObj._longlen != 0) && (stateObj._longlenleft == 0)) { if (!stateObj.TryReadPlpLength(false, out left)) { return false; } } left = stateObj._longlenleft; return true; }
private async Task WriteXmlFeed(XmlDataFeed feed, TdsParserStateObject stateObj, bool needBom, Encoding encoding, int size) { byte[] preambleToSkip = null; if (!needBom) { preambleToSkip = encoding.GetPreamble(); } ConstrainedTextWriter writer = new ConstrainedTextWriter(new StreamWriter(new TdsOutputStream(this, stateObj, preambleToSkip), encoding), size); XmlWriterSettings writerSettings = new XmlWriterSettings(); writerSettings.CloseOutput = false; // don't close the memory stream writerSettings.ConformanceLevel = ConformanceLevel.Fragment; if (_asyncWrite) { writerSettings.Async = true; } XmlWriter ww = XmlWriter.Create(writer, writerSettings); if (feed._source.ReadState == ReadState.Initial) { feed._source.Read(); } while (!feed._source.EOF && !writer.IsComplete) { // We are copying nodes from a reader to a writer. This will cause the // XmlDeclaration to be emitted despite ConformanceLevel.Fragment above. // Therefore, we filter out the XmlDeclaration while copying. if (feed._source.NodeType == XmlNodeType.XmlDeclaration) { feed._source.Read(); continue; } if (_asyncWrite) { await ww.WriteNodeAsync(feed._source, true).ConfigureAwait(false); } else { ww.WriteNode(feed._source, true); } } if (_asyncWrite) { await ww.FlushAsync().ConfigureAwait(false); } else { ww.Flush(); } }
// Used to close the connection and then free the memory allocated for the netlib connection. internal void Disconnect() { if (null != _sessionPool) { // MARSOn may be true, but _sessionPool not yet created _sessionPool.Dispose(); } // Can close the connection if its open or broken if (_state != TdsParserState.Closed) { //benign assert - the user could close the connection before consuming all the data //Debug.Assert(_physicalStateObj._inBytesUsed == _physicalStateObj._inBytesRead && _physicalStateObj._outBytesUsed == _physicalStateObj._inputHeaderLen, "TDSParser closed with data not fully sent or consumed."); _state = TdsParserState.Closed; try { // If the _physicalStateObj has an owner, we will delay the disposal until the owner is finished with it if (!_physicalStateObj.HasOwner) { _physicalStateObj.SniContext = SniContext.Snix_Close; #if DEBUG _physicalStateObj.InvalidateDebugOnlyCopyOfSniContext(); #endif _physicalStateObj.Dispose(); } else { // Remove the "initial" callback (this will allow the stateObj to be GC collected if need be) _physicalStateObj.DecrementPendingCallbacks(false); } // Not allocated until MARS is actually enabled in SNI. if (null != _pMarsPhysicalConObj) { _pMarsPhysicalConObj.Dispose(); } } finally { _pMarsPhysicalConObj = null; } } }
private async Task WriteTextFeed(TextDataFeed feed, Encoding encoding, bool needBom, TdsParserStateObject stateObj, int size) { Debug.Assert(encoding == null || !needBom); char[] inBuff = new char[constTextBufferSize]; encoding = encoding ?? Encoding.Unicode; ConstrainedTextWriter writer = new ConstrainedTextWriter(new StreamWriter(new TdsOutputStream(this, stateObj, null), encoding), size); if (needBom) { if (_asyncWrite) { await writer.WriteAsync((char)TdsEnums.XMLUNICODEBOM).ConfigureAwait(false); } else { writer.Write((char)TdsEnums.XMLUNICODEBOM); } } int nWritten = 0; do { int nRead = 0; if (_asyncWrite) { nRead = await feed._source.ReadBlockAsync(inBuff, 0, constTextBufferSize).ConfigureAwait(false); } else { nRead = feed._source.ReadBlock(inBuff, 0, constTextBufferSize); } if (nRead == 0) { break; } if (_asyncWrite) { await writer.WriteAsync(inBuff, 0, nRead).ConfigureAwait(false); } else { writer.Write(inBuff, 0, nRead); } nWritten += nRead; } while (!writer.IsComplete); if (_asyncWrite) { await writer.FlushAsync().ConfigureAwait(false); } else { writer.Flush(); } }