importing messaging-2008 branch to trunk [continued]
[mono.git] / mcs / class / Npgsql / Npgsql / NpgsqlCopyIn.cs
1 // Npgsql.NpgsqlCopyIn.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 //  Copyright (c) 2002-2007, The Npgsql Development Team
11 //  
12 // Permission to use, copy, modify, and distribute this software and its
13 // documentation for any purpose, without fee, and without a written
14 // agreement is hereby granted, provided that the above copyright notice
15 // and this paragraph and the following two paragraphs appear in all copies.
16 // 
17 // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
18 // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
19 // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
20 // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
21 // THE POSSIBILITY OF SUCH DAMAGE.
22 // 
23 // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
24 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25 // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
26 // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
27 // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
28
29
30 using System.IO;
31
32 namespace Npgsql
33 {
34         /// <summary>
35         /// Represents a PostgreSQL COPY FROM STDIN operation with a corresponding SQL statement
36         /// to execute against a PostgreSQL database
37         /// and an associated stream used to read data from (if provided by user)
38         /// or for writing it (when generated by driver).
39         /// Eg. new NpgsqlCopyIn("COPY mytable FROM STDIN", connection, streamToRead).Start();
40         /// </summary>
41         public class NpgsqlCopyIn
42         {
43                 private readonly NpgsqlConnector _context;
44                 private readonly NpgsqlCommand _cmd;
45                 private Stream _copyStream;
46                 private bool _disposeCopyStream; // user did not provide stream, so reset it after use
47
48                 /// <summary>
49                 /// Creates NpgsqlCommand to run given query upon Start(). Data for the requested COPY IN operation can then be written to CopyData stream followed by a call to End() or Cancel().
50                 /// </summary>
51                 public NpgsqlCopyIn(string copyInQuery, NpgsqlConnection conn)
52                         : this(new NpgsqlCommand(copyInQuery, conn), conn)
53                 {
54                 }
55
56                 /// <summary>
57                 /// Given command is run upon Start(). Data for the requested COPY IN operation can then be written to CopyData stream followed by a call to End() or Cancel().
58                 /// </summary>
59                 public NpgsqlCopyIn(NpgsqlCommand cmd, NpgsqlConnection conn)
60                         : this(cmd, conn, null)
61                 {
62                 }
63
64                 /// <summary>
65                 /// Given command is executed upon Start() and all data from fromStream is passed to it as copy data.
66                 /// </summary>
67                 public NpgsqlCopyIn(NpgsqlCommand cmd, NpgsqlConnection conn, Stream fromStream)
68                 {
69                         _context = conn.Connector;
70                         _cmd = cmd;
71                         _copyStream = fromStream;
72                 }
73
74                 /// <summary>
75                 /// Returns true if the connection is currently reserved for this operation.
76                 /// </summary>
77                 public bool IsActive
78                 {
79                         get { return _context != null && _context.CurrentState is NpgsqlCopyInState && _context.Mediator.CopyStream == _copyStream; }
80                 }
81
82                 /// <summary>
83                 /// The stream provided by user or generated upon Start().
84                 /// User may provide a stream to constructor; it is used to pass to server all data read from it.
85                 /// Otherwise, call to Start() sets this to a writable NpgsqlCopyInStream that passes all data written to it to server.
86                 /// In latter case this is only available while the copy operation is active and null otherwise.
87                 /// </summary>
88                 public Stream CopyStream
89                 {
90                         get { return _copyStream; }
91                 }
92
93                 /// <summary>
94                 /// Returns true if this operation is currently active and in binary format.
95                 /// </summary>
96                 public bool IsBinary
97                 {
98                         get { return IsActive && _context.CurrentState.CopyFormat.IsBinary; }
99                 }
100
101                 /// <summary>
102                 /// Returns true if this operation is currently active and field at given location is in binary format.
103                 /// </summary>
104                 public bool FieldIsBinary(int fieldNumber)
105                 {
106                         return IsActive && _context.CurrentState.CopyFormat.FieldIsBinary(fieldNumber);
107                 }
108
109                 /// <summary>
110                 /// Returns number of fields expected on each input row if this operation is currently active, otherwise -1
111                 /// </summary>
112                 public int FieldCount
113                 {
114                         get { return IsActive ? _context.CurrentState.CopyFormat.FieldCount : -1; }
115                 }
116
117                 /// <summary>
118                 /// The Command used to execute this copy operation.
119                 /// </summary>
120                 public NpgsqlCommand NpgsqlCommand
121                 {
122                         get { return _cmd; }
123                 }
124
125                 /// <summary>
126                 /// Set before a COPY IN query to define size of internal buffer for reading from given CopyStream.
127                 /// </summary>
128                 public int CopyBufferSize
129                 {
130                         get { return _context.Mediator.CopyBufferSize; }
131                         set { _context.Mediator.CopyBufferSize = value; }
132                 }
133
134                 /// <summary>
135                 /// Command specified upon creation is executed as a non-query.
136                 /// If CopyStream is set upon creation, it will be flushed to server as copy data, and operation will be finished immediately.
137                 /// Otherwise the CopyStream member can be used for writing copy data to server and operation finished with a call to End() or Cancel().
138                 /// </summary>
139                 public void Start()
140                 {
141                         if (_context.CurrentState is NpgsqlReadyState)
142                         {
143                                 _context.Mediator.CopyStream = _copyStream;
144                                 _cmd.ExecuteBlind();
145                                 _disposeCopyStream = _copyStream == null;
146                                 _copyStream = _context.Mediator.CopyStream;
147                                 if (_copyStream == null && ! (_context.CurrentState is NpgsqlReadyState))
148                                 {
149                                         throw new NpgsqlException("Not a COPY IN query: " + _cmd.CommandText);
150                                 }
151                         }
152                         else
153                         {
154                                 throw new NpgsqlException("Copy can only start in Ready state, not in " + _context.CurrentState);
155                         }
156                 }
157
158                 /// <summary>
159                 /// Called after writing all data to CopyStream to successfully complete this copy operation.
160                 /// </summary>
161                 public void End()
162                 {
163                         if (_context != null)
164                         {
165                                 try
166                                 {
167                                         if (IsActive)
168                                         {
169                                                 _context.CurrentState.SendCopyDone(_context);
170                                         }
171                                 }
172                                 finally
173                                 {
174                                         if (_context.Mediator.CopyStream == _copyStream)
175                                         {
176                                                 _context.Mediator.CopyStream = null;
177                                         }
178                                         if (_disposeCopyStream)
179                                         {
180                                                 _copyStream = null;
181                                         }
182                                 }
183                         }
184                 }
185
186                 /// <summary>
187                 /// Withdraws an already started copy operation. The operation will fail with given error message.
188                 /// Will do nothing if current operation is not active.
189                 /// </summary>
190                 public void Cancel(string message)
191                 {
192                         if (_context != null)
193                         {
194                                 try
195                                 {
196                                         if (IsActive)
197                                         {
198                                                 _context.CurrentState.SendCopyFail(_context, message);
199                                         }
200                                 }
201                                 finally
202                                 {
203                                         if (_context.Mediator.CopyStream == _copyStream)
204                                         {
205                                                 _context.Mediator.CopyStream = null;
206                                         }
207                                         if (_disposeCopyStream)
208                                         {
209                                                 _copyStream = null;
210                                         }
211                                 }
212                         }
213                 }
214         }
215 }