2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / Mono.Data.PostgreSqlClient / Mono.Data.PostgreSqlClient / PgSqlCommand.cs
index 68ab0b05c6f8542d44866cfb445c9fc6b3387522..13a20d85e5d5afed2c4ac349ca9a92797ea3163e 100644 (file)
@@ -1,5 +1,5 @@
 //
-// System.Data.SqlClient.SqlCommand.cs
+// Mono.Data.PostgreSqlClient.PgSqlCommand.cs
 //
 // Author:
 //   Rodrigo Moya (rodrigo@ximian.com)
 //        Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
 //
 
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 // use #define DEBUG_SqlCommand if you want to spew debug messages
 // #define DEBUG_SqlCommand
 
@@ -33,13 +54,13 @@ using System.Runtime.InteropServices;
 using System.Text;
 using System.Xml;
 
-namespace System.Data.SqlClient {
+namespace Mono.Data.PostgreSqlClient {
        /// <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 {
+       // public sealed class PgSqlCommand : Component, IDbCommand, ICloneable
+       public sealed class PgSqlCommand : IDbCommand {
 
                #region Fields
 
@@ -48,15 +69,15 @@ namespace System.Data.SqlClient {
                // default is 30 seconds 
                // for command execution
 
-               private SqlConnection conn = null;
-               private SqlTransaction trans = null;
+               private PgSqlConnection conn = null;
+               private PgSqlTransaction trans = null;
                private CommandType cmdType = CommandType.Text;
                private bool designTime = false;
-               private SqlParameterCollection parmCollection = new 
-                       SqlParameterCollection();
+               private PgSqlParameterCollection parmCollection = new 
+                       PgSqlParameterCollection();
 
-               // SqlDataReader state data for ExecuteReader()
-               private SqlDataReader dataReader = null;
+               // PgSqlDataReader state data for ExecuteReader()
+               private PgSqlDataReader dataReader = null;
                private string[] queries = null;
                private int currentQuery = -1;
                private CommandBehavior cmdBehavior = CommandBehavior.Default;
@@ -67,21 +88,21 @@ namespace System.Data.SqlClient {
 
                #region Constructors
 
-               public SqlCommand() {
+               public PgSqlCommand() {
                        sql = "";
                }
 
-               public SqlCommand (string cmdText) {
+               public PgSqlCommand (string cmdText) {
                        sql = cmdText;
                }
 
-               public SqlCommand (string cmdText, SqlConnection connection) {
+               public PgSqlCommand (string cmdText, PgSqlConnection connection) {
                        sql = cmdText;
                        conn = connection;
                }
 
-               public SqlCommand (string cmdText, SqlConnection connection, 
-                       SqlTransaction transaction) {
+               public PgSqlCommand (string cmdText, PgSqlConnection connection, 
+                       PgSqlTransaction transaction) {
                        sql = cmdText;
                        conn = connection;
                        trans = transaction;
@@ -104,8 +125,23 @@ namespace System.Data.SqlClient {
                }
 
                [MonoTODO]
-               public SqlParameter CreateParameter () {
-                       return new SqlParameter ();
+               public PgSqlParameter CreateParameter () {
+                       return new PgSqlParameter ();
+               }
+
+               public uint EscapeString (string to, string from, uint length) {
+                       uint result = PostgresLibrary.PQescapeString (out to, from, length);
+                       return result;
+               }
+
+               public byte[] EscapeByteArray (byte[] bintext, uint binlen, 
+                       uint bytealen) {
+
+                       byte[] result;
+                       result = PostgresLibrary.PQescapeBytea (bintext,
+                                       binlen, bytealen);
+
+                       return result;
                }
 
                public int ExecuteNonQuery () { 
@@ -160,7 +196,7 @@ namespace System.Data.SqlClient {
                                PostgresLibrary.PQclear (pgResult);
                                pgResult = IntPtr.Zero;
 \r
-                               throw new SqlException(0, 0,
+                               throw new PgSqlException(0, 0,
                                        errorMessage, 0, "",
                                        conn.DataSource, "SqlCommand", 0);\r
                        }
@@ -174,7 +210,7 @@ namespace System.Data.SqlClient {
                }
 
                [MonoTODO]
-               public SqlDataReader ExecuteReader () {
+               public PgSqlDataReader ExecuteReader () {
                        return ExecuteReader(CommandBehavior.Default);
                }
 
@@ -185,7 +221,7 @@ namespace System.Data.SqlClient {
                }
 
                [MonoTODO]
-               public SqlDataReader ExecuteReader (CommandBehavior behavior) 
+               public PgSqlDataReader ExecuteReader (CommandBehavior behavior) 
                {
                        if(conn.State != ConnectionState.Open)
                                throw new InvalidOperationException(
@@ -195,7 +231,7 @@ namespace System.Data.SqlClient {
 
                        queries = null;
                        currentQuery = -1;
-                       dataReader = new SqlDataReader(this);
+                       dataReader = new PgSqlDataReader(this);
 
                        queries = sql.Split(new Char[] {';'});                  
 
@@ -204,9 +240,9 @@ namespace System.Data.SqlClient {
                        return dataReader;
                }
 
-               internal SqlResult NextResult() 
+               internal PgSqlResult NextResult() 
                {
-                       SqlResult res = new SqlResult();
+                       PgSqlResult res = new PgSqlResult();
                        res.Connection = this.Connection;
                        res.Behavior = cmdBehavior;
                        string statement;
@@ -230,70 +266,48 @@ namespace System.Data.SqlClient {
 
                private string TweakQuery(string query, CommandType commandType) {
                        string statement = "";
-                       StringBuilder td;
-
-#if DEBUG_SqlCommand
-                       Console.WriteLine("---------[][] TweakQuery() [][]--------");
-                       Console.WriteLine("CommandType: " + commandType + " CommandBehavior: " + cmdBehavior);
-                       Console.WriteLine("SQL before command type: " + query);
-#endif                                         
+                       
                        // finish building SQL based on CommandType
                        switch(commandType) {
                        case CommandType.Text:
-                               statement = query;
+                               // TODO: this parameters utility
+                               //       currently only support input variables
+                               //       need todo output, input/output, and return.
+                               parmUtil = new ParmUtil(query, parmCollection);
+                               statement = parmUtil.ReplaceWithParms();
                                break;
                        case CommandType.StoredProcedure:
-                               statement = 
-                                       "SELECT " + query + "()";
+                               string sParmList = GetStoredProcParmList ();
+                               statement = "SELECT " + query + "(" + sParmList + ")";
                                break;
-                       case CommandType.TableDirect:
-                               // NOTE: this is for the PostgreSQL provider
-                               //       and for OleDb, according to the docs,
-                               //       an exception is thrown if you try to use
-                               //       this with SqlCommand
-                               string[] directTables = query.Split(
-                                       new Char[] {','});      
-                                                                                
-                               td = new StringBuilder("SELECT * FROM ");
-                               
-                               for(int tab = 0; tab < directTables.Length; tab++) {
-                                       if(tab > 0)
-                                               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;
+                       case CommandType.TableDirect:                                                                            
+                               statement = "SELECT * FROM " + query;
                                break;
                        }
-#if DEBUG_SqlCommand                   
-                       Console.WriteLine("SQL after command type: " + statement);
-#endif
-                       // TODO: this parameters utility
-                       //       currently only support input variables
-                       //       need todo output, input/output, and return.
-#if DEBUG_SqlCommand
-                       Console.WriteLine("using ParmUtil in TweakQuery()...");
-#endif
-                       parmUtil = new ParmUtil(statement, parmCollection);
-#if DEBUG_SqlCommand
-                       Console.WriteLine("ReplaceWithParms...");
-#endif
-
-                       statement = parmUtil.ReplaceWithParms();
 
-#if DEBUG_SqlCommand
-                       Console.WriteLine("SQL after ParmUtil: " + statement);
-#endif 
                        return statement;
                }
 
-               private void ExecuteQuery (string query, SqlResult res)
+               string GetStoredProcParmList () {
+                       StringBuilder s = new StringBuilder();
+
+                       int addedCount = 0;
+                       for(int p = 0; p < parmCollection.Count; p++) {
+                               PgSqlParameter prm = parmCollection[p];
+                               if(prm.Direction == ParameterDirection.Input) {\r
+                                       string strObj = PostgresHelper.\r
+                                               ObjectToString(prm.DbType, \r
+                                               prm.Value);\r
+                                       if(addedCount > 0)\r
+                                               s.Append(",");\r
+                                       s.Append(strObj);\r
+                                       addedCount++;\r
+                               }
+                       }
+                       return s.ToString();
+               }
+
+               private void ExecuteQuery (string query, PgSqlResult res)
                {                       
                        IntPtr pgResult;
                
@@ -336,7 +350,7 @@ namespace System.Data.SqlClient {
                                PostgresLibrary.PQclear (pgResult);
                                pgResult = IntPtr.Zero;
 \r
-                               throw new SqlException(0, 0,
+                               throw new PgSqlException(0, 0,
                                        errorMessage, 0, "",
                                        conn.DataSource, "SqlCommand", 0);\r
                        }
@@ -360,7 +374,7 @@ namespace System.Data.SqlClient {
 
                // only meant to be used between SqlConnectioin,
                // SqlCommand, and SqlDataReader
-               internal void OpenReader(SqlDataReader reader) {
+               internal void OpenReader(PgSqlDataReader reader) {
                        conn.OpenReader(reader);
                }
 
@@ -483,7 +497,7 @@ namespace System.Data.SqlClient {
                                PostgresLibrary.PQclear (pgResult);
                                pgResult = IntPtr.Zero;
 \r
-                               throw new SqlException(0, 0,
+                               throw new PgSqlException(0, 0,
                                        errorMessage, 0, "",
                                        conn.DataSource, "SqlCommand", 0);\r
                        }
@@ -503,7 +517,7 @@ namespace System.Data.SqlClient {
                }
 
                [MonoTODO]
-               public SqlCommand Clone () {
+               public PgSqlCommand Clone () {
                        throw new NotImplementedException ();
                }
 
@@ -558,7 +572,7 @@ namespace System.Data.SqlClient {
                                // transaction in progress
 
                                // csc
-                               Connection = (SqlConnection) value; 
+                               Connection = (PgSqlConnection) value; 
                                // mcs
                                // Connection = value; 
                                
@@ -566,7 +580,7 @@ namespace System.Data.SqlClient {
                        }
                }
                
-               public SqlConnection Connection {
+               public PgSqlConnection Connection {
                        get { 
                                // conn defaults to null
                                return conn;
@@ -599,7 +613,7 @@ namespace System.Data.SqlClient {
                        }
                }
 
-               public SqlParameterCollection Parameters {
+               public PgSqlParameterCollection Parameters {
                        get { 
                                return parmCollection;
                        }
@@ -618,13 +632,13 @@ namespace System.Data.SqlClient {
                                // has already begun
 
                                // csc
-                               Transaction = (SqlTransaction) value;
+                               Transaction = (PgSqlTransaction) value;
                                // mcs
                                // Transaction = value; 
                        }
                }
 
-               public SqlTransaction Transaction {
+               public PgSqlTransaction Transaction {
                        get { 
                                return trans; 
                        }
@@ -662,7 +676,7 @@ namespace System.Data.SqlClient {
                }
 
                [MonoTODO]
-               ~SqlCommand() {
+               ~PgSqlCommand() {
                        // FIXME: need proper way to release resources
                        // Dispose(false);
                }
@@ -672,7 +686,7 @@ namespace System.Data.SqlClient {
 
        // SqlResult is used for passing Result Set data 
        // from SqlCommand to SqlDataReader
-       internal class SqlResult {
+       internal class PgSqlResult {
 
                private DataTable dataTableSchema = null; // only will contain the schema
                private IntPtr pg_result = IntPtr.Zero; // native PostgreSQL PGresult
@@ -680,7 +694,7 @@ namespace System.Data.SqlClient {
                private int fieldCount = 0;
                private string[] pgtypes = null; // PostgreSQL types (typname)
                private bool resultReturned = false;
-               private SqlConnection con = null;
+               private PgSqlConnection con = null;
                private int rowsAffected = -1;
                private ExecStatusType execStatus = ExecStatusType.PGRES_FATAL_ERROR;
                private int currentQuery = -1;
@@ -725,7 +739,7 @@ namespace System.Data.SqlClient {
 
                }
 
-               internal SqlConnection Connection {
+               internal PgSqlConnection Connection {
                        get {
                                return con;
                        }
@@ -810,7 +824,7 @@ namespace System.Data.SqlClient {
                                dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
                                dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
                                dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
-                               dataTableSchema.Columns.Add ("DataType", typeof(string));
+                               dataTableSchema.Columns.Add ("DataType", typeof(Type));
                                dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
                                dataTableSchema.Columns.Add ("ProviderType", typeof (int));
                                dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
@@ -860,7 +874,8 @@ namespace System.Data.SqlClient {
                                        schemaRow["ColumnSize"] = PostgresLibrary.PQfsize (pgResult, i);
                                        schemaRow["NumericPrecision"] = 0;
                                        schemaRow["NumericScale"] = 0;
-                                       if((cmdBehavior & CommandBehavior.SingleResult) == CommandBehavior.KeyInfo) {
+                                       // TODO: need to get KeyInfo
+                                       if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
                                                bool IsUnique, IsKey;
                                                GetKeyInfo(columnName, out IsUnique, out IsKey);
                                        }
@@ -880,7 +895,7 @@ namespace System.Data.SqlClient {
                                \r
                                        typ = PostgresHelper.DbTypeToSystemType (dbType);\r
                                        string st = typ.ToString();\r
-                                       schemaRow["DataType"] = st;\r
+                                       schemaRow["DataType"] = typ;\r
 
                                        schemaRow["AllowDBNull"] = false;
                                        schemaRow["ProviderType"] = oid;
@@ -914,7 +929,7 @@ namespace System.Data.SqlClient {
                private void GetKeyInfo(string columnName, out bool isUnique, out bool isKey) {
                        isUnique = false;
                        isKey = false;
-
+/*
                        string sql;
 
                        sql =
@@ -922,6 +937,7 @@ namespace System.Data.SqlClient {
                        "FROM pg_class c, pg_class c2, pg_index i " +
                        "WHERE c.relname = ':tableName' AND c.oid = i.indrelid " +
                        "AND i.indexrelid = c2.oid ";
+*/                     
                }
        }
 }