SqlStream.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / SqlClient / SqlStream.cs / 1305376 / SqlStream.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
namespace System.Data.SqlClient { 

    using System; 
    using System.Collections;
    using System.ComponentModel;
    using System.Data;
    using System.Data.Common; 
    using System.Diagnostics;
    using System.Globalization; 
    using System.IO; 
    using System.Runtime.InteropServices;
    using System.Text; 
    using System.Xml;
    using System.Reflection;

    sealed internal class SqlStream : Stream { 
        private SqlDataReader _reader; // reader we will stream off
        private int           _columnOrdinal; 
        private long          _bytesCol; 
        int                   _bom;
        private byte[]        _bufferedData; 
        private bool          _processAllRows;
        private bool          _advanceReader;
        private bool          _readFirstRow = false;
        private bool          _endOfColumn = false; 

        internal SqlStream(SqlDataReader reader, bool addByteOrderMark, bool processAllRows) : 
            this(0, reader, addByteOrderMark, processAllRows, true) { 
        }
 
        internal SqlStream(int columnOrdinal, SqlDataReader reader, bool addByteOrderMark , bool processAllRows, bool advanceReader) {
            _columnOrdinal = columnOrdinal;
            _reader = reader;
            _bom = addByteOrderMark ? 0xfeff : 0; 
            _processAllRows = processAllRows;
            _advanceReader = advanceReader; 
        } 

        override public bool CanRead { 
            get {
                return true;
            }
        } 

        override public bool CanSeek { 
            get { 
                return false;
            } 
        }

        override public bool CanWrite {
            get { 
                return false;
            } 
        } 

        override public long Length { 
            get {
              throw ADP.NotSupported();
            }
        } 

        override public long Position { 
            get { 
                throw ADP.NotSupported();
            } 
            set {
                throw ADP.NotSupported();
            }
        } 

        override protected void Dispose(bool disposing) { 
            try { 
                if (disposing && _advanceReader && _reader != null && !_reader.IsClosed) {
                    _reader.Close(); 
                }
                _reader = null;
            }
            finally { 
                base.Dispose(disposing);
            } 
        } 

        override public void Flush() { 
            throw ADP.NotSupported();
        }

        override public int Read(byte[] buffer, int offset, int count) { 
            int intCount = 0;
            int cBufferedData = 0; 
 
            if ((null == _reader)) {
                throw ADP.StreamClosed(ADP.Read); 
            }
            if (null == buffer) {
                throw ADP.ArgumentNull(ADP.ParameterBuffer);
            } 
            if ((offset < 0) || (count < 0)) {
                throw ADP.ArgumentOutOfRange(String.Empty, (offset < 0 ? ADP.ParameterOffset : ADP.ParameterCount)); 
            } 
            if (buffer.Length - offset < count) {
                throw ADP.ArgumentOutOfRange(ADP.ParameterCount); 
            }

            // 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 (_bom > 0 ) { 
                // Read and buffer the first two bytes
                _bufferedData = new byte[2]; 
                cBufferedData = ReadBytes(_bufferedData, 0, 2);
                // Check to se if we should add the byte order mark
                if ((cBufferedData < 2) || ((_bufferedData[0] == 0xDF) && (_bufferedData[1] == 0xFF))){
                    _bom = 0; 
                }
                while (count > 0) { 
                    if (_bom > 0) { 
                        buffer[offset] = (byte)_bom;
                        _bom >>= 8; 
                        offset++;
                        count--;
                        intCount++;
                    } 
                    else {
                        break; 
                    } 
                }
            } 

            if (cBufferedData > 0) {
                while (count > 0) {
                    buffer[offset++] = _bufferedData[0]; 
                    intCount++;
                    count--; 
                    if ((cBufferedData > 1) && (count > 0)) { 
                        buffer[offset++] = _bufferedData[1];
                        intCount++; 
                        count--;
                        break;
                    }
                } 
                _bufferedData = null;
            } 
 
            intCount += ReadBytes(buffer, offset, count);
 
            return intCount;
        }

        private static bool AdvanceToNextRow(SqlDataReader reader) { 
            Debug.Assert(reader != null && !reader.IsClosed);
 
            // this method skips empty result sets 
            do {
                if (reader.Read()) { 
                    return true;
                }
            } while (reader.NextResult());
 
            // no more rows
            return false; 
        } 

        private int ReadBytes(byte[] buffer, int offset, int count) { 
            bool gotData = true;
            int intCount = 0;
            int cb = 0;
 
            if (_reader.IsClosed || _endOfColumn) {
                return 0; 
            } 
            try {
                while (count > 0) { 
                    // if I haven't read any bytes, get the next row
                    if (_advanceReader && (0 == _bytesCol)) {
                        gotData = false;
 
                        if (_readFirstRow && !_processAllRows) {
                            // for XML column, stop processing after the first row 
                            // no op here - reader is closed after the end of this loop 
                        }
                        else if (AdvanceToNextRow(_reader)) { 
                            _readFirstRow = true;

                            if (_reader.IsDBNull(_columnOrdinal)) {
                                // VSTFDEVDIV 479659: handle row with DBNULL as empty data 
                                // for XML column, processing is stopped on the next loop since _readFirstRow is true
                                continue; 
                            } 

                            // the value is not null, read it 
                            gotData = true;
                        }
                        // else AdvanceToNextRow has returned false - no more rows or result sets remained, stop processing
                    } 

                    if (gotData) { 
                        cb = (int) _reader.GetBytesInternal(_columnOrdinal, _bytesCol, buffer, offset, count); 

                        if (cb < count) { 
                            _bytesCol = 0;
                            gotData = false;
                            if (!_advanceReader) {
                                _endOfColumn = true; 
                            }
                        } 
                        else { 
                            Debug.Assert(cb == count);
                            _bytesCol += cb; 
                        }

                        // we are guaranteed that cb is < Int32.Max since we always pass in count which is of type Int32 to
                        // our getbytes interface 
                        count -= (int)cb;
                        offset += (int)cb; 
                        intCount += (int)cb; 
                    }
                    else { 
                        break; // no more data available, we are done
                    }
                }
                if (!gotData && _advanceReader) { 
                    _reader.Close();    // Need to close the reader if we are done reading
                } 
            } 
            catch (Exception e) {
                if (_advanceReader && ADP.IsCatchableExceptionType(e)) { 
                    _reader.Close();
                }
                throw;
            } 

            return intCount; 
        } 

        internal XmlReader ToXmlReader() { 
            XmlReaderSettings readerSettings = new XmlReaderSettings();
            readerSettings.ConformanceLevel = ConformanceLevel.Fragment;
            readerSettings.CloseInput = true;
 
            // 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] { (Stream)this, 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; 
        }

        override public long Seek(long offset, SeekOrigin origin) {
            throw ADP.NotSupported(); 
        }
 
        override public void SetLength(long value) { 
            throw ADP.NotSupported();
        } 

        override public void Write(byte[] buffer, int offset, int count) {
            throw ADP.NotSupported();
        } 
    }
 
 
    // XmlTextReader does not read all the bytes off the network buffers, so we have to cache it here in the random access
    // case. This causes double buffering and is a perf hit, but this is not the high perf way for accessing this type of data. 
    // In the case of sequential access, we do not have to do any buffering since the XmlTextReader we return can become
    // invalid as soon as we move off the current column.
    sealed internal class SqlCachedStream : Stream {
        int       _currentPosition;   // Position within the current array byte 
        int       _currentArrayIndex; // Index into the _cachedBytes ArrayList
        ArrayList _cachedBytes; 
        long      _totalLength; 

        // Reads off from the network buffer and caches bytes. Only reads one column value in the current row. 
        internal SqlCachedStream(SqlCachedBuffer sqlBuf ) {
            _cachedBytes = sqlBuf.CachedBytes;
        }
 
        override public bool CanRead {
            get { 
                return true; 
            }
        } 

        override public bool CanSeek {
            get {
                return true; 
            }
        } 
 
        override public bool CanWrite {
            get { 
                return false;
            }
        }
 
        override public long Length {
            get { 
                return TotalLength; 
            }
        } 

        override public long Position {
            get {
                long  pos = 0; 
                byte[]  bytArr = null;
                if (_currentArrayIndex > 0) { 
                    for (int ii = 0 ; ii < _currentArrayIndex ; ii++) { 
                        bytArr = (byte[])(_cachedBytes[ii]);
                        pos += bytArr.Length; 
                    }
                }
                pos+= _currentPosition;
                return pos; 
            }
            set { 
                if (null == _cachedBytes) { 
                    throw ADP.StreamClosed(ADP.ParameterSetPosition);
                } 
                SetInternalPosition(value, ADP.ParameterSetPosition);
            }
        }
 
        override protected void Dispose(bool disposing) {
            try { 
                if (disposing && _cachedBytes != null) 
                    _cachedBytes.Clear();
                _cachedBytes = null; 
                _currentPosition = 0;
                _currentArrayIndex = 0;
                _totalLength = 0;
            } 
            finally {
                base.Dispose(disposing); 
            } 
        }
 
        override public void Flush() {
            throw ADP.NotSupported();
        }
 
        override public int Read(byte[] buffer, int offset, int count) {
            int cb; 
            int intCount = 0; 
            byte[] curBytes = null;
 
            if (null == _cachedBytes) {
                throw ADP.StreamClosed(ADP.Read);
            }
 
            if (null == buffer) {
                throw ADP.ArgumentNull(ADP.ParameterBuffer); 
            } 

            if ((offset < 0) || (count < 0)) { 
                throw ADP.ArgumentOutOfRange(String.Empty, (offset < 0 ? ADP.ParameterOffset : ADP.ParameterCount));
            }

            if (buffer.Length - offset < count) { 
                throw ADP.ArgumentOutOfRange(ADP.ParameterCount);
            } 
 
            if (_cachedBytes.Count > _currentArrayIndex) {
                curBytes = (byte [])(_cachedBytes[_currentArrayIndex]); 
            }
            else {
                return 0;       // Everything is read!
            } 

            while (count > 0) { 
                if (curBytes.Length <= _currentPosition) { 
                    _currentArrayIndex++;       // We are done reading this chunk, go to next
                    if (_cachedBytes.Count > _currentArrayIndex) { 
                        curBytes = (byte [])(_cachedBytes[_currentArrayIndex]);
                        _currentPosition = 0;
                    }
                    else { 
                        break;
                    } 
                } 
                cb = curBytes.Length - _currentPosition;
                if (cb > count) 
                    cb = count;
                Array.Copy(curBytes, _currentPosition, buffer, offset, cb);

                _currentPosition += cb; 
                count -= (int)cb;
                offset += (int)cb; 
                intCount += (int)cb; 
            }
 
            return intCount;
        }

        override public long Seek(long offset, SeekOrigin origin) { 
            long pos = 0;
 
            if (null == _cachedBytes) { 
                throw ADP.StreamClosed(ADP.Read);
            } 

            switch(origin)  {
                case SeekOrigin.Begin:
                    SetInternalPosition(offset, ADP.ParameterOffset); 
                    break;
 					 
                case SeekOrigin.Current: 
                    pos  =  offset + Position;
                    SetInternalPosition(pos, ADP.ParameterOffset); 
                    break;
					
                case SeekOrigin.End:
                    pos  = TotalLength + offset; 
                    SetInternalPosition(pos, ADP.ParameterOffset);
                    break; 
					 
                default:
                    throw ADP.InvalidSeekOrigin(ADP.ParameterOffset); 
            }
            return pos;
        }
 
        override public void SetLength(long value) {
            throw ADP.NotSupported(); 
        } 

        override public void Write(byte[] buffer, int offset, int count) { 
            throw ADP.NotSupported();
        }

        private void SetInternalPosition(long lPos, string argumentName) { 
            long  pos = lPos;
            byte[]  bytArr = null; 
 
            if  (pos < 0) {
                throw new ArgumentOutOfRangeException(argumentName); 
            }
            for (int ii = 0 ; ii < _cachedBytes.Count ; ii++) {
                bytArr = (byte[])(_cachedBytes[ii]);
                if (pos > bytArr.Length) { 
                    pos -= bytArr.Length;
                } 
                else { 
                    _currentArrayIndex = ii;
                    _currentPosition = (int)pos; 
                    return;
                }
            }
            if (pos > 0) 
                throw new ArgumentOutOfRangeException(argumentName);
        } 
 
        private long TotalLength {
            get { 
                if ((_totalLength == 0) && (_cachedBytes != null)) {
                    long pos = 0;
                    byte[]  bytArr = null;
                    for (int ii = 0 ; ii < _cachedBytes.Count ; ii++) { 
                        bytArr = (byte[])( _cachedBytes[ii]);
                        pos += bytArr.Length; 
                    } 
                    _totalLength = pos;
                } 
                return _totalLength;
            }
        }
    } 

    sealed internal class SqlStreamingXml { 
 
        int           _columnOrdinal;
        SqlDataReader _reader; 
        XmlReader     _xmlReader;
        XmlWriter     _xmlWriter;
        StringWriter  _strWriter;
        long          _charsRemoved; 

        public SqlStreamingXml(int i, SqlDataReader reader) { 
            _columnOrdinal = i; 
            _reader = reader;
        } 

        public void Close() {
            ((IDisposable)_xmlWriter).Dispose();
            ((IDisposable)_xmlReader).Dispose(); 
            _reader = null;
            _xmlReader = null; 
            _xmlWriter = null; 
            _strWriter = null;
        } 

        public int ColumnOrdinal {
            get {
                return _columnOrdinal; 
            }
        } 
 
        public long GetChars(long dataIndex, char[] buffer, int bufferIndex, int length) {
            if (_xmlReader == null) { 
                SqlStream sqlStream = new SqlStream( _columnOrdinal, _reader, true /* addByteOrderMark */, false /* processAllRows*/, false /*advanceReader*/);
                _xmlReader = sqlStream.ToXmlReader();
                _strWriter = new StringWriter((System.IFormatProvider)null);
                XmlWriterSettings writerSettings = new XmlWriterSettings(); 
    		    writerSettings.CloseOutput = true;		// close the memory stream when done
		        writerSettings.ConformanceLevel = ConformanceLevel.Fragment; 
 		        _xmlWriter = XmlWriter.Create(_strWriter, writerSettings);				 
            }
 
            int charsToSkip = 0;
            int cnt = 0;
            if (dataIndex < _charsRemoved) {
                throw ADP.NonSeqByteAccess(dataIndex, _charsRemoved, ADP.GetChars); 
            }
            else if (dataIndex > _charsRemoved) { 
                charsToSkip = (int)(dataIndex - _charsRemoved); 
            }
 
            // If buffer parameter is null, we have to return -1 since there is no way for us to know the
            // total size up front without reading and converting the XML.
            if (buffer == null) {
                return (long)(-1); 
            }
 
            StringBuilder strBldr = _strWriter.GetStringBuilder(); 
            while (!_xmlReader.EOF) {
                if (strBldr.Length >= (length+ charsToSkip)) { 
                    break;
                }
                // Can't call _xmlWriter.WriteNode here, since it reads all of the data in before returning the first char.
                // Do own implementation of WriteNode instead that reads just enough data to return the required number of chars 
                //_xmlWriter.WriteNode(_xmlReader, true);
                //  _xmlWriter.Flush(); 
                WriteXmlElement(); 
                if (charsToSkip > 0) {
                    // Aggressively remove the characters we want to skip to avoid growing StringBuilder size too much 
                    cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip;
                    strBldr.Remove(0, cnt);
                    charsToSkip -= cnt;
                    _charsRemoved +=(long)cnt; 
                }
            } 
 
            if (charsToSkip > 0) {
                cnt = strBldr.Length < charsToSkip ? strBldr.Length : charsToSkip; 
                strBldr.Remove(0, cnt);
                charsToSkip -= cnt;
                _charsRemoved +=(long)cnt;
            } 

            if (strBldr.Length == 0) { 
                return 0; 
            }
            // At this point charsToSkip must be 0 
            Debug.Assert(charsToSkip == 0);

            cnt = strBldr.Length < length ? strBldr.Length : length;
            for (int i = 0 ; i < cnt ; i++) { 
                buffer[bufferIndex + i] = strBldr[i];
            } 
            // Remove the characters we have already returned 
            strBldr.Remove(0, cnt);
            _charsRemoved += (long)cnt; 
            return (long)cnt;
        }

        // This method duplicates the work of XmlWriter.WriteNode except that it reads one element at a time 
        // instead of reading the entire node like XmlWriter.
        private void WriteXmlElement() { 
 
            if (_xmlReader.EOF)
                return; 

            bool canReadChunk = _xmlReader.CanReadValueChunk;
            char[] writeNodeBuffer = null;
 
            // Constants
            const int WriteNodeBufferSize = 1024; 
 
            _xmlReader.Read();
            switch (_xmlReader.NodeType) { 
                case XmlNodeType.Element:
                    _xmlWriter.WriteStartElement(_xmlReader.Prefix, _xmlReader.LocalName, _xmlReader.NamespaceURI);
                    _xmlWriter.WriteAttributes(_xmlReader, true);
                    if (_xmlReader.IsEmptyElement) { 
                        _xmlWriter.WriteEndElement();
                        break; 
                    } 
                    break;
                case XmlNodeType.Text: 
                    if (canReadChunk) {
                        if (writeNodeBuffer == null) {
                            writeNodeBuffer = new char[WriteNodeBufferSize];
                        } 
                        int read;
                        while ((read = _xmlReader.ReadValueChunk(writeNodeBuffer, 0, WriteNodeBufferSize)) > 0) { 
                            _xmlWriter.WriteChars(writeNodeBuffer, 0, read); 
                        }
                    } 
                    else {
                        _xmlWriter.WriteString(_xmlReader.Value);
                    }
                    break; 
                case XmlNodeType.Whitespace:
                case XmlNodeType.SignificantWhitespace: 
                    _xmlWriter.WriteWhitespace(_xmlReader.Value); 
                    break;
                case XmlNodeType.CDATA: 
                    _xmlWriter.WriteCData(_xmlReader.Value);
                    break;
                case XmlNodeType.EntityReference:
                    _xmlWriter.WriteEntityRef(_xmlReader.Name); 
                    break;
                case XmlNodeType.XmlDeclaration: 
                case XmlNodeType.ProcessingInstruction: 
                    _xmlWriter.WriteProcessingInstruction(_xmlReader.Name, _xmlReader.Value);
                    break; 
                case XmlNodeType.DocumentType:
                    _xmlWriter.WriteDocType(_xmlReader.Name, _xmlReader.GetAttribute("PUBLIC"), _xmlReader.GetAttribute("SYSTEM"), _xmlReader.Value);
                    break;
                 case XmlNodeType.Comment: 
                    _xmlWriter.WriteComment(_xmlReader.Value);
                    break; 
                case XmlNodeType.EndElement: 
                    _xmlWriter.WriteFullEndElement();
                    break; 
            }
            _xmlWriter.Flush();
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK