File: SqlCachedBuffer.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (156 lines) | stat: -rw-r--r-- 6,370 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//------------------------------------------------------------------------------
// <copyright file="SqlCachedBuffer.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</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 ;
            }
        }

    }
    
}