| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715 |
- //
- // System.Data.SqlClient.SqlCommand.cs
- //
- // Author:
- // Rodrigo Moya ([email protected])
- // Daniel Morgan ([email protected])
- //
- // (C) Ximian, Inc 2002 http://www.ximian.com/
- // (C) Daniel Morgan, 2002
- //
- // Credits:
- // SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
- // http://www.gnome-db.org/
- // with permission from the authors of the
- // PostgreSQL provider in libgda:
- // Michael Lausch <[email protected]>
- // Rodrigo Moya <[email protected]>
- // Vivien Malerba <[email protected]>
- // Gonzalo Paniagua Javier <[email protected]>
- //
- // use #define DEBUG_SqlCommand if you want to spew debug messages
- // #define DEBUG_SqlCommand
- using System;
- using System.Collections;
- using System.ComponentModel;
- using System.Data;
- using System.Data.Common;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Xml;
- namespace System.Data.SqlClient {
- /// <summary>
- /// Represents a SQL statement that is executed
- /// while connected to a SQL database.
- /// </summary>
- // public sealed class SqlCommand : Component, IDbCommand, ICloneable
- public sealed class SqlCommand : IDbCommand {
- // FIXME: Console.WriteLine() is used for debugging throughout
- #region Fields
- private string sql = "";
- private int timeout = 30;
- // default is 30 seconds
- // for command execution
- private SqlConnection conn = null;
- private SqlTransaction trans = null;
- private CommandType cmdType = CommandType.Text;
- private bool designTime = false;
- private SqlParameterCollection parmCollection = new
- SqlParameterCollection();
- // SqlDataReader state data for ExecuteReader()
- private SqlDataReader dataReader;
- private string[] queries;
- private int currentQuery;
- CommandBehavior cmdBehavior;
-
- #endregion // Fields
- #region Constructors
- public SqlCommand() {
- sql = "";
- }
- public SqlCommand (string cmdText) {
- sql = cmdText;
- }
- public SqlCommand (string cmdText, SqlConnection connection) {
- sql = cmdText;
- conn = connection;
- }
- public SqlCommand (string cmdText, SqlConnection connection,
- SqlTransaction transaction) {
- sql = cmdText;
- conn = connection;
- trans = transaction;
- }
- #endregion // Constructors
- #region Methods
- [MonoTODO]
- public void Cancel () {
- // FIXME: use non-blocking Exec for this
- throw new NotImplementedException ();
- }
- // FIXME: is this the correct way to return a stronger type?
- [MonoTODO]
- IDbDataParameter IDbCommand.CreateParameter () {
- return CreateParameter ();
- }
- [MonoTODO]
- public SqlParameter CreateParameter () {
- return new SqlParameter ();
- }
- public int ExecuteNonQuery () {
- IntPtr pgResult; // PGresult
- int rowsAffected = -1;
- ExecStatusType execStatus;
- String rowsAffectedString;
- string query;
- if(conn.State != ConnectionState.Open)
- throw new InvalidOperationException(
- "ConnnectionState is not Open");
- query = TweakQuery(sql, cmdType);
- // FIXME: PQexec blocks
- // while PQsendQuery is non-blocking
- // which is better to use?
- // int PQsendQuery(PGconn *conn,
- // const char *query);
- // execute SQL command
- // uses internal property to get the PGConn IntPtr
- pgResult = PostgresLibrary.
- PQexec (conn.PostgresConnection, query);
- execStatus = PostgresLibrary.
- PQresultStatus (pgResult);
-
- if(execStatus == ExecStatusType.PGRES_COMMAND_OK) {
- rowsAffectedString = PostgresLibrary.
- PQcmdTuples (pgResult);
- if(rowsAffectedString != null)
- if(rowsAffectedString.Equals("") == false)
- rowsAffected = int.Parse(rowsAffectedString);
- PostgresLibrary.PQclear (pgResult);
- }
- else {
- String errorMessage;
-
- errorMessage = PostgresLibrary.
- PQresStatus(execStatus);
- errorMessage += " " + PostgresLibrary.
- PQresultErrorMessage(pgResult);
-
- throw new SqlException(0, 0,
- errorMessage, 0, "",
- conn.DataSource, "SqlCommand", 0);
- }
-
- return rowsAffected;
- }
-
- [MonoTODO]
- IDataReader IDbCommand.ExecuteReader () {
- return ExecuteReader ();
- }
- [MonoTODO]
- public SqlDataReader ExecuteReader () {
- return ExecuteReader(CommandBehavior.Default);
- }
- [MonoTODO]
- IDataReader IDbCommand.ExecuteReader (
- CommandBehavior behavior) {
- return ExecuteReader (behavior);
- }
- [MonoTODO]
- public SqlDataReader ExecuteReader (CommandBehavior behavior)
- {
- if(conn.State != ConnectionState.Open)
- throw new InvalidOperationException(
- "ConnectionState is not Open");
- cmdBehavior = behavior;
- queries = null;
- currentQuery = -1;
- dataReader = new SqlDataReader(this);
- if((behavior & CommandBehavior.SingleResult) == CommandBehavior.SingleResult) {
- queries = new String[1];
- queries[0] = sql;
- }
- else {
- queries = sql.Split(new Char[] {';'});
- }
- dataReader.NextResult();
-
- return dataReader;
- }
- internal SqlResult NextResult()
- {
- SqlResult res = new SqlResult();
- res.Connection = this.Connection;
- string statement;
-
- currentQuery++;
- if(currentQuery < queries.Length && queries[currentQuery].Equals("") == false) {
- statement = TweakQuery(queries[currentQuery], cmdType);
- ExecuteQuery(statement, res);
- res.ResultReturned = true;
- }
- else {
- res.ResultReturned = false;
- }
- return res;
- }
- private string TweakQuery(string query, CommandType commandType) {
- string statement = "";
- StringBuilder td;
- // TODO: need to handle parameters
-
- // finish building SQL based on CommandType
- switch(commandType) {
- case CommandType.Text:
- statement = query;
- break;
- case CommandType.StoredProcedure:
- statement =
- "SELECT " + query + "()";
- break;
- case CommandType.TableDirect:
- string[] directTables = query.Split(
- new Char[] {','});
-
- td = new StringBuilder("SELECT * FROM ");
-
- for(int tab = 0; tab < directTables.Length; tab++) {
- if(tab > 0 && tab < directTables.Length - 1)
- td.Append(',');
- td.Append(directTables[tab]);
- // FIXME: if multipe tables, how do we
- // join? based on Primary/Foreign Keys?
- // Otherwise, a Cartesian Product happens
- }
- statement = td.ToString();
- break;
- default:
- // FIXME: throw an exception?
- statement = query;
- break;
- }
- return statement;
- }
- private void ExecuteQuery (string query, SqlResult res)
- {
- IntPtr pgResult;
-
- ExecStatusType execStatus;
- if(conn.State != ConnectionState.Open)
- throw new InvalidOperationException(
- "ConnectionState is not Open");
- // FIXME: PQexec blocks
- // while PQsendQuery is non-blocking
- // which is better to use?
- // int PQsendQuery(PGconn *conn,
- // const char *query);
- // execute SQL command
- // uses internal property to get the PGConn IntPtr
- pgResult = PostgresLibrary.
- PQexec (conn.PostgresConnection, query);
- execStatus = PostgresLibrary.
- PQresultStatus (pgResult);
-
- if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
- res.BuildTableSchema(pgResult);
- }
- else {
- String errorMessage;
-
- errorMessage = PostgresLibrary.
- PQresStatus(execStatus);
- errorMessage += " " + PostgresLibrary.
- PQresultErrorMessage(pgResult);
-
- throw new SqlException(0, 0,
- errorMessage, 0, "",
- conn.DataSource, "SqlCommand", 0);
- }
- }
- // since SqlCommand has resources so SqlDataReader
- // can do Read() and NextResult(), need to free
- // those resources. Also, need to allow this SqlCommand
- // and this SqlConnection to things again.
- internal void CloseReader() {
- conn.OpenReader = false;
- dataReader = null;
- queries = null;
- }
- /// <summary>
- /// ExecuteScalar is used to retrieve one object
- /// from one result set
- /// that has one row and one column.
- /// It is lightweight compared to ExecuteReader.
- /// </summary>
- [MonoTODO]
- public object ExecuteScalar () {
- IntPtr pgResult; // PGresult
- ExecStatusType execStatus;
- object obj = null; // return
- int nRow = 0; // first row
- int nCol = 0; // first column
- String value;
- int nRows;
- int nFields;
- string query;
- if(conn.State != ConnectionState.Open)
- throw new InvalidOperationException(
- "ConnnectionState is not Open");
- query = TweakQuery(sql, cmdType);
- // FIXME: PQexec blocks
- // while PQsendQuery is non-blocking
- // which is better to use?
- // int PQsendQuery(PGconn *conn,
- // const char *query);
- // execute SQL command
- // uses internal property to get the PGConn IntPtr
- pgResult = PostgresLibrary.
- PQexec (conn.PostgresConnection, query);
- execStatus = PostgresLibrary.
- PQresultStatus (pgResult);
-
- if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
- nRows = PostgresLibrary.
- PQntuples(pgResult);
- nFields = PostgresLibrary.
- PQnfields(pgResult);
- if(nRows > 0 && nFields > 0) {
- // get column name
- //String fieldName;
- //fieldName = PostgresLibrary.
- // PQfname(pgResult, nCol);
- int oid;
- string sType;
- DbType dbType;
- // get PostgreSQL data type (OID)
- oid = PostgresLibrary.
- PQftype(pgResult, nCol);
- sType = PostgresHelper.
- OidToTypname (oid, conn.Types);
- dbType = PostgresHelper.
- TypnameToSqlDbType(sType);
- int definedSize;
- // get defined size of column
- definedSize = PostgresLibrary.
- PQfsize(pgResult, nCol);
- // get data value
- value = PostgresLibrary.
- PQgetvalue(
- pgResult,
- nRow, nCol);
- int columnIsNull;
- // is column NULL?
- columnIsNull = PostgresLibrary.
- PQgetisnull(pgResult,
- nRow, nCol);
- int actualLength;
- // get Actual Length
- actualLength = PostgresLibrary.
- PQgetlength(pgResult,
- nRow, nCol);
-
- obj = PostgresHelper.
- ConvertDbTypeToSystem (
- dbType,
- value);
- }
- // close result set
- PostgresLibrary.PQclear (pgResult);
- pgResult = IntPtr.Zero;
- }
- else {
- String errorMessage;
-
- errorMessage = PostgresLibrary.
- PQresStatus(execStatus);
- errorMessage += " " + PostgresLibrary.
- PQresultErrorMessage(pgResult);
-
- throw new SqlException(0, 0,
- errorMessage, 0, "",
- conn.DataSource, "SqlCommand", 0);
- }
-
- return obj;
- }
- [MonoTODO]
- public XmlReader ExecuteXmlReader () {
- throw new NotImplementedException ();
- }
- [MonoTODO]
- public void Prepare () {
- // FIXME: parameters have to be implemented for this
- throw new NotImplementedException ();
- }
- [MonoTODO]
- public SqlCommand Clone () {
- throw new NotImplementedException ();
- }
- #endregion // Methods
- #region Properties
- public string CommandText {
- get {
- return sql;
- }
- set {
- sql = value;
- }
- }
- public int CommandTimeout {
- get {
- return timeout;
- }
-
- set {
- // FIXME: if value < 0, throw
- // ArgumentException
- // if (value < 0)
- // throw ArgumentException;
- timeout = value;
- }
- }
- public CommandType CommandType {
- get {
- return cmdType;
- }
- set {
- cmdType = value;
- }
- }
- // FIXME: for property Connection, is this the correct
- // way to handle a return of a stronger type?
- IDbConnection IDbCommand.Connection {
- get {
- return Connection;
- }
- set {
- // FIXME: throw an InvalidOperationException
- // if the change was during a
- // transaction in progress
- // csc
- Connection = (SqlConnection) value;
- // mcs
- // Connection = value;
-
- // FIXME: set Transaction property to null
- }
- }
-
- public SqlConnection Connection {
- get {
- // conn defaults to null
- return conn;
- }
- set {
- // FIXME: throw an InvalidOperationException
- // if the change was during
- // a transaction in progress
- conn = value;
- // FIXME: set Transaction property to null
- }
- }
- public bool DesignTimeVisible {
- get {
- return designTime;
- }
-
- set{
- designTime = value;
- }
- }
- // FIXME; for property Parameters, is this the correct
- // way to handle a stronger return type?
- IDataParameterCollection IDbCommand.Parameters {
- get {
- return Parameters;
- }
- }
- SqlParameterCollection Parameters {
- get {
- return parmCollection;
- }
- }
- // FIXME: for property Transaction, is this the correct
- // way to handle a return of a stronger type?
- IDbTransaction IDbCommand.Transaction {
- get {
- return Transaction;
- }
- set {
- // FIXME: error handling - do not allow
- // setting of transaction if transaction
- // has already begun
- // csc
- Transaction = (SqlTransaction) value;
- // mcs
- // Transaction = value;
- }
- }
- public SqlTransaction Transaction {
- get {
- return trans;
- }
- set {
- // FIXME: error handling
- trans = value;
- }
- }
- [MonoTODO]
- public UpdateRowSource UpdatedRowSource {
- // FIXME: do this once DbDataAdaptor
- // and DataRow are done
- get {
- throw new NotImplementedException ();
- }
- set {
- throw new NotImplementedException ();
- }
- }
- #endregion // Properties
- #region Inner Classes
- #endregion // Inner Classes
- #region Destructors
- [MonoTODO]
- public void Dispose() {
- // FIXME: need proper way to release resources
- // Dispose(true);
- }
- [MonoTODO]
- ~SqlCommand() {
- // FIXME: need proper way to release resources
- // Dispose(false);
- }
- #endregion //Destructors
- }
- // SqlResult is used for passing Result Set data
- // from SqlCommand to SqlDataReader
- internal class SqlResult {
- private DataTable dataTableSchema; // only will contain the schema
- private IntPtr pg_result; // native PostgreSQL PGresult
- private int rowCount;
- private int fieldCount;
- private string[] pgtypes; // PostgreSQL types (typname)
- private bool resultReturned = false;
- private SqlConnection con;
- internal SqlConnection Connection {
- set {
- con = value;
- }
- }
- internal bool ResultReturned {
- get {
- return resultReturned;
- }
- set {
- resultReturned = value;
- }
- }
- internal DataTable Table {
- get {
- return dataTableSchema;
- }
- }
- internal IntPtr PgResult {
- get {
- return pg_result;
- }
- }
- internal int RowCount {
- get {
- return rowCount;
- }
- }
- internal int FieldCount {
- get {
- return fieldCount;
- }
- }
- internal string[] PgTypes {
- get {
- return pgtypes;
- }
- }
- internal void BuildTableSchema (IntPtr pgResult) {
- pg_result = pgResult;
- int nCol;
-
- dataTableSchema = new DataTable();
- rowCount = PostgresLibrary.
- PQntuples(pgResult);
- fieldCount = PostgresLibrary.
- PQnfields(pgResult);
-
- int oid;
- pgtypes = new string[fieldCount];
-
- for(nCol = 0; nCol < fieldCount; nCol++) {
-
- DbType dbType;
- // get column name
- String fieldName;
- fieldName = PostgresLibrary.
- PQfname(pgResult, nCol);
- // get PostgreSQL data type (OID)
- oid = PostgresLibrary.
- PQftype(pgResult, nCol);
- pgtypes[nCol] = PostgresHelper.
- OidToTypname (oid, con.Types);
-
- int definedSize;
- // get defined size of column
- definedSize = PostgresLibrary.
- PQfsize(pgResult, nCol);
-
- // build the data column and add it the table
- DataColumn dc = new DataColumn(fieldName);
- dbType = PostgresHelper.
- TypnameToSqlDbType(pgtypes[nCol]);
- dc.DataType = PostgresHelper.
- DbTypeToSystemType(dbType);
- dc.MaxLength = definedSize;
- dc.SetTable(dataTableSchema);
-
- dataTableSchema.Columns.Add(dc);
- }
- }
- }
- }
|