2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Npgsql / Npgsql / NpgsqlCopyOutStream.cs
blob453169238e4303513b84a03c6c7761729a1b5ef3
1 // Npgsql.NpgsqlCopyOutStream.cs
2 //
3 // Author:
4 // Kalle Hallivuori <kato@iki.fi>
5 //
6 // Copyright (C) 2007 The Npgsql Development Team
7 // npgsql-general@gborg.postgresql.org
8 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
9 //
10 // Permission to use, copy, modify, and distribute this software and its
11 // documentation for any purpose, without fee, and without a written
12 // agreement is hereby granted, provided that the above copyright notice
13 // and this paragraph and the following two paragraphs appear in all copies.
14 //
15 // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
16 // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
17 // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
18 // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
19 // THE POSSIBILITY OF SUCH DAMAGE.
20 //
21 // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
22 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23 // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
24 // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
25 // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
28 using System;
29 using System.IO;
31 namespace Npgsql
33 /// <summary>
34 /// Stream for reading data from a table or select on a PostgreSQL version 7.4 or newer database during an active COPY TO STDOUT operation.
35 /// <b>Passes data exactly as provided by the server.</b>
36 /// </summary>
37 internal class NpgsqlCopyOutStream : Stream
39 private NpgsqlConnector _context;
40 private long _bytesPassed = 0;
41 private byte[] _buf = null;
42 private int _bufOffset = 0;
44 /// <summary>
45 /// True while this stream can be used to read copy data from server
46 /// </summary>
47 private bool IsActive
49 get { return _context != null && _context.CurrentState is NpgsqlCopyOutState && _context.Mediator.CopyStream == this; }
52 /// <summary>
53 /// Created only by NpgsqlCopyOutState.StartCopy()
54 /// </summary>
55 internal NpgsqlCopyOutStream(NpgsqlConnector context)
57 _context = context;
60 /// <summary>
61 /// True
62 /// </summary>
63 public override bool CanRead
65 get { return true; }
68 /// <summary>
69 /// False
70 /// </summary>
71 public override bool CanWrite
73 get { return false; }
76 /// <summary>
77 /// False
78 /// </summary>
79 public override bool CanSeek
81 get { return false; }
84 /// <summary>
85 /// Number of bytes read so far
86 /// </summary>
87 public override long Length
89 get { return _bytesPassed; }
92 /// <summary>
93 /// Number of bytes read so far; can not be set.
94 /// </summary>
95 public override long Position
97 get { return _bytesPassed; }
98 set { throw new NotSupportedException("Tried to set Position of network stream " + this); }
101 /// <summary>
102 /// Discards copy data as long as server pushes it. Returns after operation is finished.
103 /// Does nothing if this stream is not the active copy operation reader.
104 /// </summary>
105 public override void Close()
107 if (_context != null)
109 if (IsActive)
111 while (_context.CurrentState.GetCopyData(_context) != null)
113 ; // flush rest
116 if (_context.Mediator.CopyStream == this)
118 _context.Mediator.CopyStream = null;
120 _context = null;
124 /// <summary>
125 /// Not writable.
126 /// </summary>
127 public override void Write(byte[] buf, int off, int len)
129 throw new NotSupportedException("Tried to write non-writable " + this);
132 /// <summary>
133 /// Not flushable.
134 /// </summary>
135 public override void Flush()
137 throw new NotSupportedException("Tried to flush read-only " + this);
140 /// <summary>
141 /// Copies data read from server to given byte buffer.
142 /// Since server returns data row by row, length will differ each time, but it is only zero once the operation ends.
143 /// Can be mixed with calls to the more efficient NpgsqlCopyOutStream.Read() : byte[] though that would not make much sense.
144 /// </summary>
145 public override int Read(byte[] buf, int off, int len)
147 if (! IsActive)
149 throw new ObjectDisposedException("Reading from closed " + this);
152 if (_buf == null) // otherwise _buf still contains data that did not fit into request buffer in an earlier call
154 _buf = Read();
155 _bufOffset = 0;
157 if (off + len > buf.Length)
159 len = buf.Length - off;
162 int i = 0;
163 if (_buf != null)
165 for (; _bufOffset < _buf.Length && i < len; i++)
167 buf[off + i] = _buf[_bufOffset++];
169 if (_bufOffset >= _buf.Length)
171 _buf = null; // whole of our contents fit into request buffer
173 _bytesPassed += i;
175 return i;
178 /// <summary>
179 /// Not seekable
180 /// </summary>
181 public override long Seek(long pos, SeekOrigin so)
183 throw new NotSupportedException("Tried to seek non-seekable " + this);
186 /// <summary>
187 /// Not supported
188 /// </summary>
189 public override void SetLength(long len)
191 throw new NotSupportedException("Tried to set length of network stream " + this);
194 /// <summary>
195 /// Returns a whole row of data from server without extra work.
196 /// If standard Stream.Read(...) has been called before, it's internal buffers remains are returned.
197 /// </summary>
198 public byte[] Read()
200 byte[] result;
201 if (_buf == null)
203 result = _context.CurrentState.GetCopyData(_context);
205 else if (_bufOffset < 1)
207 result = _buf;
209 else
211 result = new byte[_buf.Length - _bufOffset];
212 for (int i = 0; i < result.Length; i++)
214 result[i] = _buf[_bufOffset + i];
216 _buf = null;
218 return result;