1 //------------------------------------------------------------------------------
2 // <copyright file="SqlCachedBuffer.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
9 namespace System.Data.SqlClient {
12 using System.Collections.Generic;
13 using System.ComponentModel;
15 using System.Data.Common;
16 using System.Diagnostics;
17 using System.Globalization;
20 using System.Data.SqlTypes;
22 using System.Runtime.InteropServices;
23 using System.Reflection;
24 using System.Runtime.CompilerServices;
26 // Caches the bytes returned from partial length prefixed datatypes, like XML
27 sealed internal class SqlCachedBuffer : System.Data.SqlTypes.INullable{
28 public static readonly SqlCachedBuffer Null = new SqlCachedBuffer();
29 private const int _maxChunkSize = 2048; // Arbitrary value for chunk size. Revisit this later for better perf
31 private List<byte[]> _cachedBytes;
33 private SqlCachedBuffer() {
34 // For constructing Null
37 private SqlCachedBuffer(List<byte[]> cachedBytes) {
38 _cachedBytes = cachedBytes;
41 internal List<byte[]> CachedBytes {
42 get { return _cachedBytes; }
45 // Reads off from the network buffer and caches bytes. Only reads one column value in the current row.
46 static internal bool TryCreate(SqlMetaDataPriv metadata, TdsParser parser, TdsParserStateObject stateObj, out SqlCachedBuffer buffer) {
51 List<byte[]> cachedBytes = new List<byte[]>();
54 // the very first length is already read.
55 if (!parser.TryPlpBytesLeft(stateObj, out plplength)) {
58 // For now we only handle Plp data from the parser directly.
59 Debug.Assert(metadata.metaType.IsPlp, "SqlCachedBuffer call on a non-plp data");
64 cb = (plplength > (ulong) _maxChunkSize) ? _maxChunkSize : (int)plplength ;
65 byteArr = new byte[cb];
66 if (!stateObj.TryReadPlpBytes(ref byteArr, 0, cb, out cb)) {
69 Debug.Assert(cb == byteArr.Length);
70 if (cachedBytes.Count == 0) {
71 // Add the Byte order mark if needed if we read the first array
72 AddByteOrderMark(byteArr, cachedBytes);
74 cachedBytes.Add(byteArr);
75 plplength -= (ulong)cb;
76 } while (plplength > 0);
77 if (!parser.TryPlpBytesLeft(stateObj, out plplength)) {
80 } while (plplength > 0);
81 Debug.Assert(stateObj._longlen == 0 && stateObj._longlenleft == 0);
83 buffer = new SqlCachedBuffer(cachedBytes);
87 private static void AddByteOrderMark(byte[] byteArr, List<byte[]> cachedBytes) {
88 // Need to find out if we should add byte order mark or not.
89 // We need to add this if we are getting ntext xml, not if we are getting binary xml
90 // Binary Xml always begins with the bytes 0xDF and 0xFF
91 // If we aren't getting these, then we are getting unicode xml
92 if ((byteArr.Length < 2 ) || (byteArr[0] != 0xDF) || (byteArr[1] != 0xFF)){
93 Debug.Assert(cachedBytes.Count == 0);
94 cachedBytes.Add(TdsEnums.XMLUNICODEBOMBYTES);
98 internal Stream ToStream() {
99 return new SqlCachedStream(this);
102 override public string ToString() {
104 throw new SqlNullValueException();
106 if (_cachedBytes.Count == 0) {
109 SqlXml sxml = new SqlXml(ToStream());
113 internal SqlString ToSqlString() {
115 return SqlString.Null;
116 string str = ToString();
117 return new SqlString(str);
120 internal SqlXml ToSqlXml() {
121 SqlXml sx = new SqlXml(ToStream());
125 // 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.
126 [MethodImpl(MethodImplOptions.NoInlining)]
127 internal XmlReader ToXmlReader() {
128 //XmlTextReader xr = new XmlTextReader(fragment, XmlNodeType.Element, null);
129 XmlReaderSettings readerSettings = new XmlReaderSettings();
130 readerSettings.ConformanceLevel = ConformanceLevel.Fragment;
132 // Call internal XmlReader.CreateSqlReader from System.Xml.
133 // Signature: internal static XmlReader CreateSqlReader(Stream input, XmlReaderSettings settings, XmlParserContext inputContext);
134 MethodInfo createSqlReaderMethodInfo = typeof(System.Xml.XmlReader).GetMethod("CreateSqlReader", BindingFlags.Static | BindingFlags.NonPublic);
135 object[] args = new object[3] { ToStream(), readerSettings, null };
138 new System.Security.Permissions.ReflectionPermission(System.Security.Permissions.ReflectionPermissionFlag.MemberAccess).Assert();
140 xr = (XmlReader)createSqlReaderMethodInfo.Invoke(null, args);
143 System.Security.Permissions.ReflectionPermission.RevertAssert();
150 return (_cachedBytes == null) ? true : false ;