| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- //------------------------------------------------------------------------------
- // <copyright file="SqlCachedBuffer.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- // <owner current="true" primary="false">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data.SqlClient {
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Data.Common;
- using System.Diagnostics;
- using System.Globalization;
- using System.Text;
- using System.Xml;
- using System.Data.SqlTypes;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Reflection;
- using System.Runtime.CompilerServices;
- // Caches the bytes returned from partial length prefixed datatypes, like XML
- sealed internal class SqlCachedBuffer : System.Data.SqlTypes.INullable{
- public static readonly SqlCachedBuffer Null = new SqlCachedBuffer();
- private const int _maxChunkSize = 2048; // Arbitrary value for chunk size. Revisit this later for better perf
-
- private List<byte[]> _cachedBytes;
- private SqlCachedBuffer() {
- // For constructing Null
- }
-
- private SqlCachedBuffer(List<byte[]> cachedBytes) {
- _cachedBytes = cachedBytes;
- }
- internal List<byte[]> CachedBytes {
- get { return _cachedBytes; }
- }
- // 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 static void AddByteOrderMark(byte[] byteArr, List<byte[]> cachedBytes) {
- // Need to find out if we should add byte order mark or not.
- // We need to add this if we are getting ntext xml, not if we are getting binary xml
- // Binary Xml always begins with the bytes 0xDF and 0xFF
- // If we aren't getting these, then we are getting unicode xml
- if ((byteArr.Length < 2 ) || (byteArr[0] != 0xDF) || (byteArr[1] != 0xFF)){
- Debug.Assert(cachedBytes.Count == 0);
- cachedBytes.Add(TdsEnums.XMLUNICODEBOMBYTES);
- }
- }
-
- internal Stream ToStream() {
- return new SqlCachedStream(this);
- }
-
- override public string ToString() {
- if (IsNull)
- throw new SqlNullValueException();
- if (_cachedBytes.Count == 0) {
- return String.Empty;
- }
- SqlXml sxml = new SqlXml(ToStream());
- return sxml.Value;
- }
- internal SqlString ToSqlString() {
- if (IsNull)
- return SqlString.Null;
- string str = ToString();
- return new SqlString(str);
- }
- internal SqlXml ToSqlXml() {
- SqlXml sx = new SqlXml(ToStream());
- return sx;
- }
- // Prevent inlining so that reflection calls are not moved to caller that may be in a different assembly that may have a different grant set.
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal XmlReader ToXmlReader() {
- //XmlTextReader xr = new XmlTextReader(fragment, XmlNodeType.Element, null);
- XmlReaderSettings readerSettings = new XmlReaderSettings();
- readerSettings.ConformanceLevel = ConformanceLevel.Fragment;
- // Call internal XmlReader.CreateSqlReader from System.Xml.
- // Signature: internal static XmlReader CreateSqlReader(Stream input, XmlReaderSettings settings, XmlParserContext inputContext);
- MethodInfo createSqlReaderMethodInfo = typeof(System.Xml.XmlReader).GetMethod("CreateSqlReader", BindingFlags.Static | BindingFlags.NonPublic);
- object[] args = new object[3] { ToStream(), readerSettings, null };
- XmlReader xr;
- new System.Security.Permissions.ReflectionPermission(System.Security.Permissions.ReflectionPermissionFlag.MemberAccess).Assert();
- try {
- xr = (XmlReader)createSqlReaderMethodInfo.Invoke(null, args);
- }
- finally {
- System.Security.Permissions.ReflectionPermission.RevertAssert();
- }
- return xr;
- }
- public bool IsNull {
- get {
- return (_cachedBytes == null) ? true : false ;
- }
- }
- }
-
- }
|