2 // System.Data.SqlClient.SqlCommand.cs
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Daniel Morgan (danmorg@sc.rr.com)
8 // (C) Ximian, Inc 2002
11 // use #define DEBUG_SqlCommand if you want to spew debug messages
12 // #define DEBUG_SqlCommand
15 using System.ComponentModel;
17 using System.Data.Common;
18 using System.Runtime.InteropServices;
21 namespace System.Data.SqlClient
24 /// Represents a SQL statement that is executed
25 /// while connected to a SQL database.
27 // public sealed class SqlCommand : Component, IDbCommand, ICloneable
28 public sealed class SqlCommand : IDbCommand
30 // FIXME: Console.WriteLine() is used for debugging throughout
36 // default is 30 seconds
37 // for command execution
39 SqlConnection conn = null;
40 SqlTransaction trans = null;
41 CommandType cmdType = CommandType.Text;
42 bool designTime = false;
43 SqlParameterCollection parmCollection = new
44 SqlParameterCollection();
55 public SqlCommand (string cmdText)
60 public SqlCommand (string cmdText, SqlConnection connection)
66 public SqlCommand (string cmdText, SqlConnection connection,
67 SqlTransaction transaction)
74 #endregion // Constructors
81 // FIXME: use non-blocking Exec for this
82 throw new NotImplementedException ();
85 // FIXME: is this the correct way to return a stronger type?
87 IDbDataParameter IDbCommand.CreateParameter ()
89 return CreateParameter ();
93 public SqlParameter CreateParameter ()
95 return new SqlParameter ();
98 public int ExecuteNonQuery ()
100 IntPtr pgResult; // PGresult
101 int rowsAffected = -1;
102 ExecStatusType execStatus;
103 String rowsAffectedString;
105 if(conn.State != ConnectionState.Open)
106 throw new InvalidOperationException(
107 "ConnnectionState is not Open");
109 // FIXME: PQexec blocks
110 // while PQsendQuery is non-blocking
111 // which is better to use?
112 // int PQsendQuery(PGconn *conn,
113 // const char *query);
115 // execute SQL command
116 // uses internal property to get the PGConn IntPtr
117 pgResult = PostgresLibrary.
118 PQexec (conn.PostgresConnection, sql);
120 execStatus = PostgresLibrary.
121 PQresultStatus (pgResult);
123 if(execStatus == ExecStatusType.PGRES_COMMAND_OK)
125 rowsAffectedString = PostgresLibrary.
126 PQcmdTuples (pgResult);
128 if(rowsAffectedString != null)
129 if(rowsAffectedString.Equals("") == false)
130 rowsAffected = int.Parse(rowsAffectedString);
132 PostgresLibrary.PQclear (pgResult);
138 errorMessage = PostgresLibrary.
139 PQresStatus(execStatus);
141 errorMessage += " " + PostgresLibrary.
\r
142 PQresultErrorMessage(pgResult);
\r
144 throw new SqlException(0, 0,
146 conn.DataSource, "SqlCommand", 0);
\r
153 IDataReader IDbCommand.ExecuteReader ()
155 return ExecuteReader ();
159 SqlDataReader ExecuteReader ()
161 return ExecuteReader(CommandBehavior.Default);
165 IDataReader IDbCommand.ExecuteReader (
166 CommandBehavior behavior)
168 return ExecuteReader (behavior);
172 public SqlDataReader ExecuteReader (CommandBehavior behavior)
174 // FIXME: currently only works for a
176 // ExecuteReader can be used
177 // for multiple result sets
178 SqlDataReader dataReader = null;
180 IntPtr pgResult; // PGresult
181 ExecStatusType execStatus;
183 if(conn.State != ConnectionState.Open)
184 throw new InvalidOperationException(
185 "ConnnectionState is not Open");
187 // FIXME: PQexec blocks
188 // while PQsendQuery is non-blocking
189 // which is better to use?
190 // int PQsendQuery(PGconn *conn,
191 // const char *query);
193 // execute SQL command
194 // uses internal property to get the PGConn IntPtr
195 pgResult = PostgresLibrary.
196 PQexec (conn.PostgresConnection, sql);
198 execStatus = PostgresLibrary.
199 PQresultStatus (pgResult);
201 if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
206 // FIXME: maybe i should move the
207 // BuildTableSchema code
208 // to the SqlDataReader?
209 dt = BuildTableSchema(pgResult,
210 out rows, out cols, out oids);
211 dataReader = new SqlDataReader(this, dt, pgResult,
217 errorMessage = PostgresLibrary.
218 PQresStatus(execStatus);
220 errorMessage += " " + PostgresLibrary.
\r
221 PQresultErrorMessage(pgResult);
\r
223 throw new SqlException(0, 0,
225 conn.DataSource, "SqlCommand", 0);
\r
231 internal DataTable BuildTableSchema (IntPtr pgResult,
238 DataTable dt = new DataTable();
240 nRows = PostgresLibrary.
243 nFields = PostgresLibrary.
246 oids = new int[nFields];
248 for(nCol = 0; nCol < nFields; nCol++) {
251 fieldName = PostgresLibrary.
252 PQfname(pgResult, nCol);
254 // get PostgreSQL data type (OID)
255 oids[nCol] = PostgresLibrary.
256 PQftype(pgResult, nCol);
259 // get defined size of column
260 definedSize = PostgresLibrary.
261 PQfsize(pgResult, nCol);
263 // build the data column and add it the table
264 DataColumn dc = new DataColumn(fieldName);
265 dc.DataType = PostgresHelper.OidToType(oids[nCol]);
266 dc.MaxLength = definedSize;
275 public object ExecuteScalar ()
277 IntPtr pgResult; // PGresult
278 ExecStatusType execStatus;
279 object obj = null; // return
280 int nRow = 0; // first row
281 int nCol = 0; // first column
286 if(conn.State != ConnectionState.Open)
287 throw new InvalidOperationException(
288 "ConnnectionState is not Open");
290 // FIXME: PQexec blocks
291 // while PQsendQuery is non-blocking
292 // which is better to use?
293 // int PQsendQuery(PGconn *conn,
294 // const char *query);
296 // execute SQL command
297 // uses internal property to get the PGConn IntPtr
298 pgResult = PostgresLibrary.
299 PQexec (conn.PostgresConnection, sql);
301 execStatus = PostgresLibrary.
302 PQresultStatus (pgResult);
304 if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
305 nRows = PostgresLibrary.
308 nFields = PostgresLibrary.
311 if(nRows > 0 && nFields > 0) {
315 //fieldName = PostgresLibrary.
316 // PQfname(pgResult, nCol);
319 // get PostgreSQL data type (OID)
320 oid = PostgresLibrary.
321 PQftype(pgResult, nCol);
324 // get defined size of column
325 definedSize = PostgresLibrary.
326 PQfsize(pgResult, nCol);
329 value = PostgresLibrary.
336 columnIsNull = PostgresLibrary.
337 PQgetisnull(pgResult,
342 actualLength = PostgresLibrary.
343 PQgetlength(pgResult,
346 obj = PostgresHelper.
347 ConvertPgTypeToSystem (oid, value);
351 PostgresLibrary.PQclear (pgResult);
357 errorMessage = PostgresLibrary.
358 PQresStatus(execStatus);
360 errorMessage += " " + PostgresLibrary.
\r
361 PQresultErrorMessage(pgResult);
\r
363 throw new SqlException(0, 0,
365 conn.DataSource, "SqlCommand", 0);
\r
372 public XmlReader ExecuteXmlReader ()
374 throw new NotImplementedException ();
378 public void Prepare ()
380 // FIXME: parameters have to be implemented for this
381 throw new NotImplementedException ();
385 public SqlCommand Clone ()
387 throw new NotImplementedException ();
390 #endregion // Methods
394 public string CommandText {
404 public int CommandTimeout {
410 // FIXME: if value < 0, throw
413 // throw ArgumentException;
418 public CommandType CommandType {
428 // FIXME: for property Connection, is this the correct
429 // way to handle a return of a stronger type?
430 IDbConnection IDbCommand.Connection {
436 // FIXME: throw an InvalidOperationException
437 // if the change was during a
438 // transaction in progress
441 Connection = (SqlConnection) value;
443 // Connection = value;
445 // FIXME: set Transaction property to null
449 public SqlConnection Connection {
451 // conn defaults to null
456 // FIXME: throw an InvalidOperationException
457 // if the change was during
458 // a transaction in progress
460 // FIXME: set Transaction property to null
464 public bool DesignTimeVisible {
474 // FIXME; for property Parameters, is this the correct
475 // way to handle a stronger return type?
476 IDataParameterCollection IDbCommand.Parameters {
482 SqlParameterCollection Parameters {
484 return parmCollection;
488 // FIXME: for property Transaction, is this the correct
489 // way to handle a return of a stronger type?
490 IDbTransaction IDbCommand.Transaction {
496 // FIXME: error handling - do not allow
497 // setting of transaction if transaction
501 Transaction = (SqlTransaction) value;
503 // Transaction = value;
507 public SqlTransaction Transaction {
513 // FIXME: error handling
519 public UpdateRowSource UpdatedRowSource {
520 // FIXME: do this once DbDataAdaptor
521 // and DataRow are done
523 throw new NotImplementedException ();
526 throw new NotImplementedException ();
530 #endregion // Properties
535 public void Dispose() {
536 // FIXME: need proper way to release resources
543 // FIXME: need proper way to release resources
547 #endregion //Destructors