1 using System;
2 using System.Data.Common;
3 using Microsoft.SqlServer.Server;
4 
5 namespace System.Data.SqlClient
6 {
7     sealed internal class SqlSequentialStreamSmi : System.IO.Stream
8     {
9         private SmiEventSink_Default _sink;
10         private ITypedGettersV3 _getters;
11         private int _columnIndex;       // The index of out column in the table
12         private long _position;         // Current position in the stream
13         private long _length;           // Total length of the stream
14 
SqlSequentialStreamSmi(SmiEventSink_Default sink, ITypedGettersV3 getters, int columnIndex, long length)15         internal SqlSequentialStreamSmi(SmiEventSink_Default sink, ITypedGettersV3 getters, int columnIndex, long length)
16         {
17             _sink = sink;
18             _getters = getters;
19             _columnIndex = columnIndex;
20             _length = length;
21             _position = 0;
22         }
23 
24         public override bool CanRead
25         {
26             get { return ((_sink != null) && (_getters != null)); }
27         }
28 
29         public override bool CanSeek
30         {
31             get { return false; }
32         }
33 
34         public override bool CanWrite
35         {
36             get { return false; }
37         }
38 
Flush()39         public override void Flush()
40         { }
41 
42         public override long Length
43         {
44             get { throw ADP.NotSupported(); }
45         }
46 
47         public override long Position
48         {
49             get { throw ADP.NotSupported(); }
50             set { throw ADP.NotSupported(); }
51         }
52 
53         internal int ColumnIndex
54         {
55             get { return _columnIndex; }
56         }
57 
Read(byte[] buffer, int offset, int count)58         public override int Read(byte[] buffer, int offset, int count)
59         {
60             SqlSequentialStream.ValidateReadParameters(buffer, offset, count);
61             if (!CanRead)
62             {
63                 throw ADP.ObjectDisposed(this);
64             }
65 
66             try
67             {
68                 // Read whichever is less: however much the user asked for, or however much we have
69                 // NOTE: It is safe to do this since count <= Int32.MaxValue, therefore the Math.Min should always result in an int
70                 int bytesNeeded = (int)Math.Min((long)count, _length - _position);
71                 int bytesRead = 0;
72                 if (bytesNeeded > 0)
73                 {
74                     bytesRead = ValueUtilsSmi.GetBytes_Unchecked(_sink, _getters, _columnIndex, _position, buffer, offset, bytesNeeded);
75                     _position += bytesRead;
76                 }
77                 return bytesRead;
78             }
79             catch (SqlException ex)
80             {
81                 // Stream.Read() can't throw a SqlException - so wrap it in an IOException
82                 throw ADP.ErrorReadingFromStream(ex);
83             }
84         }
85 
Seek(long offset, IO.SeekOrigin origin)86         public override long Seek(long offset, IO.SeekOrigin origin)
87         {
88             throw ADP.NotSupported();
89         }
90 
SetLength(long value)91         public override void SetLength(long value)
92         {
93             throw ADP.NotSupported();
94         }
95 
Write(byte[] buffer, int offset, int count)96         public override void Write(byte[] buffer, int offset, int count)
97         {
98             throw ADP.NotSupported();
99         }
100 
101         /// <summary>
102         /// Forces the stream to act as if it was closed (i.e. CanRead=false and Read() throws)
103         /// This does not actually close the stream, read off the rest of the data or dispose this
104         /// </summary>
SetClosed()105         internal void SetClosed()
106         {
107             _sink = null;
108             _getters = null;
109         }
110 
Dispose(bool disposing)111         protected override void Dispose(bool disposing)
112         {
113             if (disposing)
114             {
115                 SetClosed();
116             }
117 
118             base.Dispose(disposing);
119         }
120     }
121 }
122