2008-11-05 Francisco Figueiredo Jr. <francisco@npgsql.org>
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlCopyOut.cs
1 // Npgsql.NpgsqlCopyOut.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.
26
27
28 using System.IO;
29
30 namespace Npgsql
31 {
32         /// <summary>
33         /// Represents a PostgreSQL COPY TO STDOUT operation with a corresponding SQL statement
34         /// to execute against a PostgreSQL database
35         /// and an associated stream used to write results to (if provided by user)
36         /// or for reading the results (when generated by driver).
37         /// Eg. new NpgsqlCopyOut("COPY (SELECT * FROM mytable) TO STDOUT", connection, streamToWrite).Start();
38         /// </summary>
39         public class NpgsqlCopyOut
40         {
41                 private readonly NpgsqlConnector _context;
42                 private readonly NpgsqlCommand _cmd;
43                 private Stream _copyStream;
44                 private bool _disposeCopyStream; // user did not provide stream, so reset it after use
45
46                 /// <summary>
47                 /// Creates NpgsqlCommand to run given query upon Start(), after which CopyStream provides data from database as requested in the query.
48                 /// </summary>
49                 public NpgsqlCopyOut(string copyOutQuery, NpgsqlConnection conn)
50                         : this(new NpgsqlCommand(copyOutQuery, conn), conn)
51                 {
52                 }
53
54                 /// <summary>
55                 /// Given command is run upon Start(), after which CopyStream provides data from database as requested in the query.
56                 /// </summary>
57                 public NpgsqlCopyOut(NpgsqlCommand cmd, NpgsqlConnection conn)
58                         : this(cmd, conn, null)
59                 {
60                 }
61
62                 /// <summary>
63                 /// Given command is executed upon Start() and all requested copy data is written to toStream immediately.
64                 /// </summary>
65                 public NpgsqlCopyOut(NpgsqlCommand cmd, NpgsqlConnection conn, Stream toStream)
66                 {
67                         _context = conn.Connector;
68                         _cmd = cmd;
69                         _copyStream = toStream;
70                 }
71
72                 /// <summary>
73                 /// Returns true if the connection is currently reserved for this operation.
74                 /// </summary>
75                 public bool IsActive
76                 {
77                         get
78                         {
79                                 return
80                                         _context != null && _context.CurrentState is NpgsqlCopyOutState && _context.Mediator.CopyStream == _copyStream;
81                         }
82                 }
83
84                 /// <summary>
85                 /// The stream provided by user or generated upon Start()
86                 /// </summary>
87                 public Stream CopyStream
88                 {
89                         get { return _copyStream; }
90                 }
91
92                 /// <summary>
93                 /// The Command used to execute this copy operation.
94                 /// </summary>
95                 public NpgsqlCommand NpgsqlCommand
96                 {
97                         get { return _cmd; }
98                 }
99
100                 /// <summary>
101                 /// Returns true if this operation is currently active and in binary format.
102                 /// </summary>
103                 public bool IsBinary
104                 {
105                         get { return IsActive && _context.CurrentState.CopyFormat.IsBinary; }
106                 }
107
108                 /// <summary>
109                 /// Returns true if this operation is currently active and field at given location is in binary format.
110                 /// </summary>
111                 public bool FieldIsBinary(int fieldNumber)
112                 {
113                         return IsActive && _context.CurrentState.CopyFormat.FieldIsBinary(fieldNumber);
114                 }
115
116                 /// <summary>
117                 /// Returns number of fields if this operation is currently active, otherwise -1
118                 /// </summary>
119                 public int FieldCount
120                 {
121                         get { return IsActive ? _context.CurrentState.CopyFormat.FieldCount : -1; }
122                 }
123
124                 /// <summary>
125                 /// Command specified upon creation is executed as a non-query.
126                 /// If CopyStream is set upon creation, all copy data from server will be written to it, and operation will be finished immediately.
127                 /// Otherwise the CopyStream member can be used for reading copy data from server until no more data is available.
128                 /// </summary>
129                 public void Start()
130                 {
131                         if (_context.CurrentState is NpgsqlReadyState)
132                         {
133                                 _context.Mediator.CopyStream = _copyStream;
134                                 _cmd.ExecuteBlind();
135                                 _disposeCopyStream = _copyStream == null;
136                                 _copyStream = _context.Mediator.CopyStream;
137                                 if (_copyStream == null && ! (_context.CurrentState is NpgsqlReadyState))
138                                 {
139                                         throw new NpgsqlException("Not a COPY OUT query: " + _cmd.CommandText);
140                                 }
141                         }
142                         else
143                         {
144                                 throw new NpgsqlException("Copy can only start in Ready state, not in " + _context.CurrentState);
145                         }
146                 }
147
148                 /// <summary>
149                 /// Faster alternative to using the generated CopyStream.
150                 /// </summary>
151                 public byte[] Read
152                 {
153                         get { return IsActive ? ((NpgsqlCopyOutStream) _copyStream).Read() : null; }
154                 }
155
156                 /// <summary>
157                 /// Flush generated CopyStream at once. Effectively reads and discard all the rest of copy data from server.
158                 /// </summary>
159                 public void End()
160                 {
161                         if (_context != null)
162                         {
163                                 bool wasActive = IsActive;
164                                 if (wasActive)
165                                 {
166                                         if (_copyStream is NpgsqlCopyOutStream)
167                                         {
168                                                 _copyStream.Close();
169                                         }
170                                         else
171                                         {
172                                                 while (_context.CurrentState.GetCopyData(_context) != null)
173                                                 {
174                                                         ; // flush rest
175                                                 }
176                                         }
177                                 }
178                                 if (_context.Mediator.CopyStream == _copyStream)
179                                 {
180                                         _context.Mediator.CopyStream = null;
181                                         if (_disposeCopyStream)
182                                         {
183                                                 _copyStream = null;
184                                         }
185                                 }
186                         }
187                 }
188         }
189 }