2002-04-28 Daniel Morgan <danmorg@sc.rr.com>
[mono.git] / mcs / class / Mono.Data.PostgreSqlClient / Mono.Data.PostgreSqlClient / PgSqlCommand.cs
1 //
2 // System.Data.SqlClient.SqlCommand.cs
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Daniel Morgan (danmorg@sc.rr.com)
7 //
8 // (C) Ximian, Inc 2002
9 //
10
11 // use #define DEBUG_SqlCommand if you want to spew debug messages
12 // #define DEBUG_SqlCommand
13
14 using System;
15 using System.ComponentModel;
16 using System.Data;
17 using System.Data.Common;
18 using System.Runtime.InteropServices;
19 using System.Xml;
20
21 namespace System.Data.SqlClient
22 {
23         /// <summary>
24         /// Represents a SQL statement that is executed 
25         /// while connected to a SQL database.
26         /// </summary>
27         // public sealed class SqlCommand : Component, IDbCommand, ICloneable
28         public sealed class SqlCommand : IDbCommand
29         {
30                 // FIXME: Console.WriteLine() is used for debugging throughout
31
32                 #region Fields
33
34                 string sql = "";
35                 int timeout = 30; 
36                 // default is 30 seconds 
37                 // for command execution
38
39                 SqlConnection conn = null;
40                 SqlTransaction trans = null;
41                 CommandType cmdType = CommandType.Text;
42                 bool designTime = false;
43                 SqlParameterCollection parmCollection = new 
44                         SqlParameterCollection();
45
46                 #endregion // Fields
47
48                 #region Constructors
49
50                 public SqlCommand()
51                 {
52                         sql = "";
53                 }
54
55                 public SqlCommand (string cmdText)
56                 {
57                         sql = cmdText;
58                 }
59
60                 public SqlCommand (string cmdText, SqlConnection connection)
61                 {
62                         sql = cmdText;
63                         conn = connection;
64                 }
65
66                 public SqlCommand (string cmdText, SqlConnection connection, 
67                                                 SqlTransaction transaction)
68                 {
69                         sql = cmdText;
70                         conn = connection;
71                         trans = transaction;
72                 }
73
74                 #endregion // Constructors
75
76                 #region Methods
77
78                 [MonoTODO]
79                 public void Cancel ()
80                 {
81                         // FIXME: use non-blocking Exec for this
82                         throw new NotImplementedException ();
83                 }
84
85                 // FIXME: is this the correct way to return a stronger type?
86                 [MonoTODO]
87                 IDbDataParameter IDbCommand.CreateParameter ()
88                 {
89                         return CreateParameter ();
90                 }
91
92                 [MonoTODO]
93                 public SqlParameter CreateParameter ()
94                 {
95                         return new SqlParameter ();
96                 }
97
98                 [MonoTODO]
99                 public int ExecuteNonQuery ()
100                 {       
101                         IntPtr pgResult; // PGresult
102                         int rowsAffected = -1;
103                         ExecStatusType execStatus;
104                         String rowsAffectedString;
105
106                         if(conn.State != ConnectionState.Open)
107                                 throw new InvalidOperationException(
108                                         "ConnnectionState is not Open");
109
110                         // FIXME: PQexec blocks 
111                         // while PQsendQuery is non-blocking
112                         // which is better to use?
113                         // int PQsendQuery(PGconn *conn,
114                         //        const char *query);
115
116                         // execute SQL command
117                         // uses internal property to get the PGConn IntPtr
118                         pgResult = PostgresLibrary.
119                                 PQexec (conn.PostgresConnection, sql);
120
121                         execStatus = PostgresLibrary.
122                                         PQresultStatus (pgResult);
123                         
124                         if(execStatus == ExecStatusType.PGRES_COMMAND_OK)
125                         {
126                                 rowsAffectedString = PostgresLibrary.
127                                         PQcmdTuples (pgResult);
128 #if DEBUG_SqlCommand
129                                 Console.WriteLine("rowsAffectedString: " + 
130                                                 rowsAffectedString);
131 #endif // DEBUG_SqlCommand
132                                 if(rowsAffectedString != null)
133                                         if(rowsAffectedString.Equals("") == false)
134                                                 rowsAffected = int.Parse(rowsAffectedString);
135                         }
136                         else
137                         {
138                                 String errorMessage;
139                                 
140                                 errorMessage = PostgresLibrary.
141                                         PQresStatus(execStatus);
142
143                                 errorMessage += " " + PostgresLibrary.\r
144                                         PQresultErrorMessage(pgResult);\r
145                                 \r
146                                 throw new SqlException(0, 0,
147                                                   errorMessage, 0, "",
148                                                   conn.DataSource, "SqlCommand", 0);\r
149                         }
150 #if DEBUG_SqlCommand                    
151                         String cmdStatus;
152                         cmdStatus = PostgresLibrary.
153                                 PQcmdStatus(pgResult);
154
155                         Console.WriteLine("*** Command Status: " +
156                                 cmdStatus);
157 #endif // DEBUG_SqlCommand
158                         PostgresLibrary.PQclear (pgResult);
159                         
160                         // FIXME: get number of rows
161                         // affected for INSERT, UPDATE, or DELETE
162                         // any other, return -1 (such as, CREATE TABLE)
163                         return rowsAffected;
164                 }
165                 
166                 [MonoTODO]
167                 IDataReader IDbCommand.ExecuteReader ()
168                 {
169                         return ExecuteReader ();
170                 }
171
172                 [MonoTODO]
173                 SqlDataReader ExecuteReader ()
174                 {
175                         throw new NotImplementedException ();   
176                 }
177
178                 [MonoTODO]
179                 IDataReader IDbCommand.ExecuteReader (
180                                         CommandBehavior behavior)
181                 {
182                         return ExecuteReader (behavior);
183                 }
184
185                 [MonoTODO]
186                 public SqlDataReader ExecuteReader (CommandBehavior behavior)
187                 {
188                         throw new NotImplementedException ();
189                 }
190
191                 [MonoTODO]
192                 public object ExecuteScalar ()
193                 {
194                         throw new NotImplementedException ();
195                 }
196
197                 [MonoTODO]
198                 public XmlReader ExecuteXmlReader ()
199                 {
200                         throw new NotImplementedException ();
201                 }
202
203                 [MonoTODO]
204                 public void Prepare ()
205                 {
206                         // FIXME: parameters have to be implemented for this
207                         throw new NotImplementedException ();
208                 }
209
210                 [MonoTODO]
211                 public SqlCommand Clone ()
212                 {
213                         throw new NotImplementedException ();
214                 }
215
216                 #endregion // Methods
217
218                 #region Properties
219
220                 public string CommandText {
221                         get { 
222                                 return sql; 
223                         }
224
225                         set { 
226                                 sql = value; 
227                         }
228                 }
229
230                 public int CommandTimeout {
231                         get { 
232                                 return timeout;  
233                         }
234                         
235                         set {
236                                 // FIXME: if value < 0, throw
237                                 // ArgumentException
238                                 // if (value < 0)
239                                 //      throw ArgumentException;
240                                 timeout = value;
241                         }
242                 }
243
244                 public CommandType CommandType  {
245                         get {
246                                 return cmdType;
247                         }
248
249                         set { 
250                                 cmdType = value;
251                         }
252                 }
253
254                 // FIXME: for property Connection, is this the correct
255                 //        way to handle a return of a stronger type?
256                 IDbConnection IDbCommand.Connection {
257                         get { 
258                                 return Connection;
259                         }
260
261                         set { 
262                                 // FIXME: throw an InvalidOperationException
263                                 // if the change was during a 
264                                 // transaction in progress
265
266                                 // csc
267                                 Connection = (SqlConnection) value; 
268                                 // mcs
269                                 // Connection = value; 
270                                 
271                                 // FIXME: set Transaction property to null
272                         }
273                 }
274                 
275                 public SqlConnection Connection {
276                         get { 
277                                 // conn defaults to null
278                                 return conn;
279                         }
280
281                         set { 
282                                 // FIXME: throw an InvalidOperationException
283                                 // if the change was during 
284                                 // a transaction in progress
285                                 conn = value; 
286                                 // FIXME: set Transaction property to null
287                         }
288                 }
289
290                 public bool DesignTimeVisible {
291                         get {
292                                 return designTime;
293                         } 
294                         
295                         set{
296                                 designTime = value;
297                         }
298                 }
299
300                 // FIXME; for property Parameters, is this the correct
301                 //        way to handle a stronger return type?
302                 IDataParameterCollection IDbCommand.Parameters  {
303                         get { 
304                                 return Parameters;
305                         }
306                 }
307
308                 SqlParameterCollection Parameters {
309                         get { 
310                                 return parmCollection;
311                         }
312                 }
313
314                 // FIXME: for property Transaction, is this the correct
315                 //        way to handle a return of a stronger type?
316                 IDbTransaction IDbCommand.Transaction   {
317                         get { 
318                                 return Transaction;
319                         }
320
321                         set { 
322                                 // FIXME: error handling - do not allow
323                                 // setting of transaction if transaction
324                                 // has already begun
325
326                                 // csc
327                                 Transaction = (SqlTransaction) value;
328                                 // mcs
329                                 // Transaction = value; 
330                         }
331                 }
332
333                 public SqlTransaction Transaction {
334                         get { 
335                                 return trans; 
336                         }
337
338                         set { 
339                                 // FIXME: error handling
340                                 trans = value; 
341                         }
342                 }       
343
344                 [MonoTODO]
345                 public UpdateRowSource UpdatedRowSource {
346                         // FIXME: do this once DbDataAdaptor 
347                         // and DataRow are done
348                         get {           
349                                 throw new NotImplementedException (); 
350                         }
351                         set { 
352                                 throw new NotImplementedException (); 
353                         }
354                 }
355
356                 #endregion // Properties
357
358                 #region Destructors
359
360                 [MonoTODO]
361                 public void Dispose() {
362                         // FIXME: need proper way to release resources
363                         // Dispose(true);
364                 }
365
366                 [MonoTODO]
367                 ~SqlCommand()
368                 {
369                         // FIXME: need proper way to release resources
370                         // Dispose(false);
371                 }
372
373                 #endregion //Destructors
374         }
375 }