[pgsqlclient-checkins] pgsqlclient_10/source/PostgreSql/Data/PostgreSqlClient PgCommand.cs,NONE,1.1
Status: Inactive
Brought to you by:
carlosga_fb
Update of /cvsroot/pgsqlclient/pgsqlclient_10/source/PostgreSql/Data/PostgreSqlClient In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7345/Data/PostgreSqlClient Added Files: PgCommand.cs PgCommandBuilder.cs PgConnection.cs PgConnectionInternal.cs PgConnectionPool.cs PgDataAdapter.cs PgDataReader.cs PgDbType.cs PgError.cs PgErrorCollection.cs PgException.cs PgInfoMessageEventArgs.cs PgNotificationEventArgs.cs PgNotificationEventHandler.cs PgParameter.cs PgParameterCollection.cs PgRowUpdatedEventArgs.cs PgRowUpdatingEventArgs.cs PgTransaction.cs Log Message: Started the reorganization of the CVS module --- NEW FILE: PgTransaction.cs --- /* PgSqlClient - ADO.NET Data Provider for PostgreSQL 7.4+ * Copyright (c) 2003-2005 Carlos Guzman Alvarez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Data; using System.Collections; using PostgreSql.Data.Protocol; namespace PostgreSql.Data.PostgreSqlClient { public sealed class PgTransaction : MarshalByRefObject, IDbTransaction, IDisposable { #region · Fields · private PgConnection connection; private IsolationLevel isolationLevel; private bool disposed; private bool isUpdated; #endregion #region · Properties · IDbConnection IDbTransaction.Connection { get { return this.Connection; } } public PgConnection Connection { get { if (!this.isUpdated) { return this.connection; } else { return null; } } } public IsolationLevel IsolationLevel { get { return this.isolationLevel; } } internal bool IsUpdated { get { return this.isUpdated; } set { if (this.connection != null && value) { this.connection.InternalConnection.ActiveTransaction = null; this.connection = null; } this.isUpdated = value; } } #endregion #region · Constructors · private PgTransaction() : this(null) { } internal PgTransaction(PgConnection connection) : this(connection, IsolationLevel.ReadCommitted) { } internal PgTransaction(PgConnection connection, IsolationLevel isolation) { this.connection = connection; this.isolationLevel = isolation; } #endregion #region · Finalizer · ~PgTransaction() { this.Dispose(false); } #endregion #region · IDisposable Methods · public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { try { if (this.connection != null && !this.isUpdated) { // Implicitly roll back if the transaction still valid. this.Rollback(); } } finally { if (this.connection != null) { this.connection.InternalConnection.ActiveTransaction = null; this.connection = null; } this.disposed = true; this.isUpdated = true; } } } } #endregion #region · Methods · public void Commit() { if (this.isUpdated) { throw new InvalidOperationException("This Transaction has completed; it is no longer usable."); } try { this.connection.InternalConnection.Database.CommitTransaction(); this.IsUpdated = true; } catch (PgClientException ex) { throw new PgException(ex.Message, ex); } } public void Rollback() { if (this.isUpdated) { throw new InvalidOperationException("This Transaction has completed; it is no longer usable."); } try { this.connection.InternalConnection.Database.RollbackTransction(); this.IsUpdated = true; } catch (PgClientException ex) { throw new PgException(ex.Message, ex); } } #endregion #region · Internal Methods · internal void InternalBeginTransaction() { try { this.connection.InternalConnection.Database.BeginTransaction(isolationLevel); this.IsUpdated = false; } catch (PgClientException ex) { throw new PgException(ex.Message, ex); } } #endregion } } --- NEW FILE: PgInfoMessageEventArgs.cs --- /* PgSqlClient - ADO.NET Data Provider for PostgreSQL 7.4+ * Copyright (c) 2003-2005 Carlos Guzman Alvarez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using PostgreSql.Data.Protocol; using PostgreSql.Data.DbSchema; namespace PostgreSql.Data.PostgreSqlClient { #region Delegates public delegate void PgInfoMessageEventHandler(object sender, PgInfoMessageEventArgs e); #endregion public sealed class PgInfoMessageEventArgs : EventArgs { #region · Fields · private PgErrorCollection errors = new PgErrorCollection(); private string message = String.Empty; #endregion #region · Properties · public PgErrorCollection Errors { get { return this.errors; } } public string Message { get { return this.message; } } #endregion #region · Constructors · internal PgInfoMessageEventArgs(PgClientException ex) { this.message = ex.Message; foreach (PgClientError error in ex.Errors) { PgError newError = new PgError(); newError.Severity = error.Severity; newError.Code = error.Code; newError.Message = error.Message; newError.Detail = error.Detail; newError.Hint = error.Hint; newError.Line = error.Line; newError.Where = error.Where; newError.Position = error.Position; newError.Routine = error.Routine; this.errors.Add(newError); } } #endregion } } --- NEW FILE: PgNotificationEventHandler.cs --- /* PgSqlClient - ADO.NET Data Provider for PostgreSQL 7.4+ * Copyright (c) 2003-2005 Carlos Guzman Alvarez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; namespace PostgreSql.Data.PostgreSqlClient { public delegate void PgNotificationEventHandler(object sender, PgNotificationEventArgs e); } --- NEW FILE: PgConnectionPool.cs --- // // Firebird .NET Data Provider - Firebird managed data provider for .NET and Mono // Copyright (C) 2002-2004 Carlos Guzman Alvarez // // Distributable under LGPL license. // You may obtain a copy of the License at http://www.gnu.org/copyleft/lesser.html // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // using System; using System.Data; using System.Collections; using System.Threading; namespace PostgreSql.Data.PostgreSqlClient { internal class PgConnectionPool : MarshalByRefObject { #region · Fields · private static ConnectionPool pool = null; #endregion #region · Methods · public static void Init() { if (pool == null) { pool = new ConnectionPool(); } } public static PgConnectionInternal GetConnection(string connectionString, PgConnection owningConnection) { Init(); return ((PgConnectionInternal)pool.CheckOut(connectionString, owningConnection)); } public static void FreeConnection(PgConnectionInternal c) { pool.CheckIn(c); } #endregion } internal class ConnectionPool { #region · Fields · private ArrayList locked; private ArrayList unlocked; private Thread cleanUpThread; #endregion #region · Constructors · public ConnectionPool() { this.locked = ArrayList.Synchronized(new ArrayList()); this.unlocked = ArrayList.Synchronized(new ArrayList()); this.cleanUpThread = new Thread(new ThreadStart(RunCleanUp)); this.cleanUpThread.Name = "CleanUp Thread"; this.cleanUpThread.Start(); this.cleanUpThread.IsBackground = true; } #endregion #region · Methods · public PgConnectionInternal CheckOut(string connectionString, PgConnection owningConnection) { PgConnectionInternal newConnection = null; lock (typeof(PgConnectionPool)) { if (this.unlocked.Count > 0) { long now = System.DateTime.Now.Ticks; PgConnectionInternal[] list = new PgConnectionInternal[this.unlocked.Count]; this.unlocked.CopyTo(0, list, 0, list.Length); foreach (PgConnectionInternal connection in list) { if (this.Validate(connection, connectionString)) { if (connection.Lifetime != 0) { if ((now - connection.Created) > connection.Lifetime) { this.unlocked.Remove(connection); this.Expire(connection); } else { this.unlocked.Remove(connection); this.locked.Add(connection); connection.OwningConnection = owningConnection; return connection; } } else { this.unlocked.Remove(connection); this.locked.Add(connection); connection.OwningConnection = owningConnection; return connection; } } else { this.unlocked.Remove(connection); this.Expire(connection); } } } newConnection = this.Create(connectionString); newConnection.OwningConnection = owningConnection; newConnection.Pooled = true; newConnection.Created = System.DateTime.Now.Ticks; newConnection.Connect(); this.locked.Add(newConnection); } return newConnection; } public void CheckIn(PgConnectionInternal connection) { lock (typeof(PgConnectionPool)) { connection.Created = System.DateTime.Now.Ticks; connection.OwningConnection = null; this.locked.Remove(connection); this.unlocked.Add(connection); } } #endregion #region · Private Methods · private void RunCleanUp() { TimeSpan interval = new TimeSpan(0, 0, 10); while (true) { this.CleanUp(null); Thread.Sleep(interval); } } private PgConnectionInternal Create(string connectionString) { try { PgConnectionInternal connection = new PgConnectionInternal(connectionString); return connection; } catch (Exception) { throw; } } private bool Validate(PgConnectionInternal connection, string connectionString) { try { return (connection.ConnectionString == connectionString && connection.Verify()); } catch (Exception) { throw; } } private void Expire(PgConnectionInternal connection) { try { if (connection.Verify()) { connection.Disconnect(); } } catch (Exception) { throw new PgException("Error closing database connection."); } } private void CleanUp(object State) { long now = System.DateTime.Now.Ticks; lock (this.unlocked.SyncRoot) { if (this.unlocked.Count > 0) { PgConnectionInternal[] list = new PgConnectionInternal[this.unlocked.Count]; this.unlocked.CopyTo(0, list, 0, list.Length); foreach (PgConnectionInternal connection in list) { if (connection.Lifetime != 0) { if ((now - connection.Created) >= connection.Lifetime) { this.unlocked.Remove(connection); this.Expire(connection); } } } } } } #endregion } } --- NEW FILE: PgConnectionInternal.cs --- /* PgSqlClient - ADO.NET Data Provider for PostgreSQL 7.4+ * Copyright (c) 2003-2005 Carlos Guzman Alvarez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections; using System.Data; using System.Text; using System.Text.RegularExpressions; using Mono.Security.Protocol.Tls; using PostgreSql.Data.Protocol; using PostgreSql.Data.DbSchema; namespace PostgreSql.Data.PostgreSqlClient { internal sealed class PgConnectionInternal : MarshalByRefObject { #region · Fields · private string connectionString; private PgConnection owningConnection; private PgDbClient database; private PgConnectionParams options; private PgTransaction activeTransaction; private ArrayList preparedCommands; private int lifetime; private long created; private bool pooled; #endregion #region · Properties · public PgDbClient Database { get { return this.database; } } public PgTransaction ActiveTransaction { get { return this.activeTransaction; } set { this.activeTransaction = value; } } public string ConnectionString { get { return this.connectionString; } } public int Lifetime { get { return this.lifetime; } set { this.lifetime = value; } } public long Created { get { return this.created; } set { this.created = value; } } public bool Pooled { get { return this.pooled; } set { this.pooled = value; } } public PgConnectionParams Options { get { return this.options; } } public ArrayList PreparedCommands { get { if (this.preparedCommands == null) { this.preparedCommands = new ArrayList(); } return this.preparedCommands; } } public bool HasActiveTransaction { get { return (this.activeTransaction != null && !this.activeTransaction.IsUpdated); } } public PgConnection OwningConnection { set { this.owningConnection = value; } } #endregion #region · Constructors · public PgConnectionInternal(string connectionString) { this.options = new PgConnectionParams(); this.connectionString = connectionString; this.lifetime = 0; this.created = 0; this.pooled = true; this.database = new PgDbClient(); this.owningConnection = owningConnection; if (connectionString != null) { this.ParseConnectionString(connectionString); } } #endregion #region · Methods · public void Connect() { try { this.database.SslConnection = new SslConnectionCallback(OnSslConnection); this.database.Settings = this.Options; this.database.Connect(); } catch (PgClientException ex) { throw new PgException(ex.Message, ex); } } public void Disconnect() { try { this.database.Disconnect(); } catch (PgClientException ex) { throw new PgException(ex.Message, ex); } } public PgTransaction BeginTransaction(IsolationLevel level) { if (this.activeTransaction != null && !this.activeTransaction.IsUpdated) { throw new InvalidOperationException("A transaction is currently active. Parallel transactions are not supported."); } try { this.activeTransaction = new PgTransaction(this.owningConnection, level); this.activeTransaction.InternalBeginTransaction(); } catch (PgClientException ex) { throw new PgException(ex.Message, ex); } return this.activeTransaction; } public DataTable GetSchema(string collectionName, string[] restrictions) { PgDbSchema dbSchema = PgDbSchemaFactory.GetSchema(collectionName); if (dbSchema == null) { throw new NotSupportedException("Specified schema type is not supported."); } if (restrictions != null) { if (restrictions.Length > dbSchema.RestrictionColumns.Count) { throw new InvalidOperationException("The number of specified restrictions is not valid."); } } return dbSchema.GetSchema(this.owningConnection, restrictions); } public void DisposeActiveTransaction() { // Rollback active transation if (this.HasActiveTransaction) { this.activeTransaction.Dispose(); this.activeTransaction = null; } } public void ClosePreparedCommands() { if (this.PreparedCommands.Count > 0) { PgCommand[] commands = new PgCommand[this.PreparedCommands.Count]; this.PreparedCommands.CopyTo(0, commands, 0, commands.Length); foreach (PgCommand command in commands) { command.InternalClose(); } this.preparedCommands.Clear(); this.preparedCommands = null; } } public void AddPreparedCommand(PgCommand command) { if (!this.PreparedCommands.Contains(command)) { this.PreparedCommands.Add(command); } } public void RemovePreparedCommand(PgCommand command) { if (this.PreparedCommands.Contains(command)) { this.PreparedCommands.Remove(command); } } #endregion #region · Internal Methods · internal bool Verify() { bool isValid = true; try { // Try to send a Sync message to the PostgreSQL Server this.database.Sync(); } catch (Exception) { isValid = false; } return isValid; } #endregion #region · Private Methods · private void ParseConnectionString(string connectionStirng) { Regex search = new Regex(@"([\w\s\d]*)\s*=\s*([^;]*)"); MatchCollection elements = search.Matches(connectionString); foreach (Match element in elements) { if (element.Groups[2].Value.Trim().Length > 0) { switch (element.Groups[1].Value.Trim().ToLower()) { case "datasource": case "server": case "host": this.options.ServerName = element.Groups[2].Value.Trim(); break; case "database": this.options.Database = element.Groups[2].Value.Trim(); break; case "user name": case "user": this.options.UserName = element.Groups[2].Value.Trim(); break; case "user password": case "password": this.options.UserPassword = element.Groups[2].Value.Trim(); break; case "port": this.options.ServerPort = Int32.Parse(element.Groups[2].Value.Trim()); break; case "connection lifetime": this.lifetime = Int32.Parse(element.Groups[2].Value.Trim()); break; case "timeout": case "connection timeout": this.options.Timeout = Int32.Parse(element.Groups[2].Value.Trim()); break; case "packet size": this.options.PacketSize = Int32.Parse(element.Groups[2].Value.Trim()); break; case "pooling": this.options.Pooling = Boolean.Parse(element.Groups[2].Value.Trim()); break; case "ssl": this.options.SSL = Boolean.Parse(element.Groups[2].Value.Trim()); break; } } } if (options.UserName == String.Empty || options.ServerName == String.Empty || options.ServerPort == 0) { throw new ArgumentException("An invalid connection string argument has been supplied or a required connection string argument has not been supplied."); } else { if (options.PacketSize < 512 || options.PacketSize > 32767) { StringBuilder msg = new StringBuilder(); msg.AppendFormat("'Packet Size' value of {0} is not valid.\r\nThe value should be an integer >= 512 and <= 32767.", options.PacketSize); throw new ArgumentException(msg.ToString()); } } } #endregion #region SSL Callbacks private void OnSslConnection() { // Server certificate validation this.database.SslClientStream.ServerCertValidationDelegate = new CertificateValidationCallback(owningConnection.OnServerCertificateValidation); // Client certificate selection this.database.SslClientStream.ClientCertSelectionDelegate = new CertificateSelectionCallback(owningConnection.OnClientCertificateSelection); } #endregion } } --- NEW FILE: PgDbType.cs --- /* PgSqlClient - ADO.NET Data Provider for PostgreSQL 7.4+ * Copyright (c) 2003-2005 Carlos Guzman Alvarez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; namespace PostgreSql.Data.PostgreSqlClient { [Serializable] public enum PgDbType { Array , Binary , Boolean , Box , Byte , Char , Circle , Currency , Date , Decimal , Double , Float , Int2 , Int4 , Int8 , Interval , Line , LSeg , Numeric , Path , Point , Polygon , Text , Time , TimeWithTZ , Timestamp , TimestampWithTZ , VarChar , Vector } } --- NEW FILE: PgDataReader.cs --- /* PgSqlClient - ADO.NET Data Provider for PostgreSQL 7.4+ * Copyright (c) 2003-2005 Carlos Guzman Alvarez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Collections; using System.Data; using System.Data.Common; using System.Globalization; using System.Reflection; using System.ComponentModel; using PostgreSql.Data.Protocol; using PostgreSql.Data.DbSchema; using PostgreSql.Data.PgTypes; namespace PostgreSql.Data.PostgreSqlClient { public sealed class PgDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord { #region · Fields · private const int STARTPOS = -1; private bool disposed; private bool open; private int position; private int recordsAffected; private int fieldCount; private DataTable schemaTable; private CommandBehavior behavior; private PgCommand command; private PgConnection connection; private object[] row; #endregion #region · Constructors · private PgDataReader() { this.open = true; this.position = STARTPOS; this.recordsAffected = -1; this.fieldCount = -1; } internal PgDataReader(PgCommand command, PgConnection connection) : this() { this.command = command; this.behavior = this.command.CommandBehavior; this.connection = connection; this.fieldCount = this.command.Statement.RowDescriptor.Fields.Length; } #endregion #region · Finalizer · ~PgDataReader() { this.Dispose(false); } #endregion #region · IDisposable Methods · void IDisposable.Dispose() { this.Dispose(true); System.GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!this.disposed) { try { if (disposing) { // release any managed resources this.Close(); this.command = null; this.connection = null; this.row = null; this.schemaTable= null; } // release any unmanaged resources } finally { } this.disposed = true; } } #endregion #region IDataReader Properties & Methods public int Depth { get { return 0; } } public bool IsClosed { get { return !this.open; } } public int RecordsAffected { get { return this.IsClosed ? this.recordsAffected : -1; } } public bool HasRows { get { return this.command.Statement.HasRows; } } public void Close() { if (!this.open) { return; } // This will update RecordsAffected property this.UpdateRecordsAffected(); if (this.command != null && !this.command.IsDisposed) { if (this.command.Statement != null) { // Set values of output parameters this.command.InternalSetOutputParameters(); } this.command.ActiveDataReader = null; } if (this.connection != null) { if ((this.behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection) { this.connection.Close(); } } this.open = false; this.position = STARTPOS; } public bool NextResult() { return false; } public bool Read() { bool read = false; if ((this.behavior == CommandBehavior.SingleRow && this.position != STARTPOS) || !this.command.Statement.HasRows) { } else { try { this.fieldCount = this.command.Statement.RowDescriptor.Fields.Length; this.position++; row = this.command.Statement.FetchRow(); read = (this.row == null) ? false : true; } catch (PgClientException ex) { throw new PgException(ex.Message, ex); } } return read; } #endregion #region GetSchemaTable Method public DataTable GetSchemaTable() { if (schemaTable == null) { schemaTable = this.GetSchemaTableStructure(); schemaTable.BeginLoadData(); PgCommand cInfoCmd = this.GetColumnInfoCmd(); PgCommand pKeyCmd = this.GetPrimaryKeyInfoCmd(); for (int i = 0; i < command.Statement.RowDescriptor.Fields.Length; i++) { object[] columnInfo = null; System.Array pKeyInfo = null; // Execute commands cInfoCmd.Parameters[0].Value = command.Statement.RowDescriptor.Fields[i].OidNumber; cInfoCmd.Parameters[1].Value = command.Statement.RowDescriptor.Fields[i].OidTable; pKeyCmd.Parameters[0].Value = command.Statement.RowDescriptor.Fields[i].OidTable; cInfoCmd.InternalPrepare(); pKeyCmd.InternalPrepare(); cInfoCmd.InternalExecute(); pKeyCmd.InternalExecute(); // Get Column Information if (cInfoCmd.Statement.Rows != null && cInfoCmd.Statement.Rows.Length > 0) { columnInfo = (object[])cInfoCmd.Statement.Rows[0]; } // Get Primary Key Info if (pKeyCmd.Statement.Rows != null && pKeyCmd.Statement.Rows.Length > 0) { object[] temp = (object[])pKeyCmd.Statement.Rows[0]; pKeyInfo = (System.Array)temp[3]; } // Add row information DataRow schemaRow = schemaTable.NewRow(); schemaRow["ColumnName"] = this.GetName(i); schemaRow["ColumnOrdinal"] = i; schemaRow["ColumnSize"] = this.GetSize(i); if (this.IsNumeric(i)) { schemaRow["NumericPrecision"] = this.GetNumericPrecision(i); schemaRow["NumericScale"] = this.GetNumericScale(i); } else { schemaRow["NumericPrecision"] = DBNull.Value; schemaRow["NumericScale"] = DBNull.Value; } schemaRow["DataType"] = this.GetFieldType(i); schemaRow["ProviderType"] = this.GetProviderType(i); schemaRow["IsLong"] = this.IsLong(i); schemaRow["IsRowVersion"] = false; schemaRow["IsUnique"] = false; schemaRow["IsAliased"] = this.IsAliased(i); schemaRow["IsExpression"] = this.IsExpression(i); schemaRow["BaseCatalogName"] = System.DBNull.Value; if (columnInfo != null) { schemaRow["IsReadOnly"] = (bool)columnInfo[10]; schemaRow["IsAutoIncrement"] = (bool)columnInfo[10]; schemaRow["IsKey"] = this.IsPrimaryKey(pKeyInfo, (short)columnInfo[6]); schemaRow["AllowDBNull"] = ((bool)columnInfo[9]) ? false : true; schemaRow["BaseSchemaName"] = columnInfo[0].ToString(); schemaRow["BaseTableName"] = columnInfo[1].ToString(); schemaRow["BaseColumnName"] = columnInfo[2].ToString(); } else { schemaRow["IsReadOnly"] = false; schemaRow["IsAutoIncrement"] = false; schemaRow["IsKey"] = false; schemaRow["AllowDBNull"] = System.DBNull.Value; schemaRow["BaseSchemaName"] = System.DBNull.Value; schemaRow["BaseTableName"] = System.DBNull.Value; schemaRow["BaseColumnName"] = System.DBNull.Value; } schemaTable.Rows.Add(schemaRow); } schemaTable.EndLoadData(); cInfoCmd.Dispose(); pKeyCmd.Dispose(); } return schemaTable; } private PgCommand GetColumnInfoCmd() { PgDbSchema dbSchema = PgDbSchemaFactory.GetSchema("Columns"); dbSchema.AddWhereFilter("pg_attribute.attnum = @OidNumber"); dbSchema.AddWhereFilter("pg_attribute.attrelid = @OidTable"); PgCommand cmd = new PgCommand(dbSchema.GetCommandText(null), command.Connection); cmd.Parameters.Add("@OidNumber", PgDbType.Int4); cmd.Parameters.Add("@OidTable", PgDbType.Int4); return cmd; } private PgCommand GetPrimaryKeyInfoCmd() { PgDbSchema dbSchema = PgDbSchemaFactory.GetSchema("PrimaryKeys"); dbSchema.AddWhereFilter("pg_class.oid = @OidTable"); PgCommand cmd = new PgCommand(dbSchema.GetCommandText(null), command.Connection); cmd.Parameters.Add("@OidTable", PgDbType.Int4); return cmd; } private bool IsPrimaryKey(System.Array pKeyInfo, short ordinal) { if (pKeyInfo != null) { for (int i = pKeyInfo.GetLowerBound(0); i <= pKeyInfo.GetUpperBound(0); i++) { if ((short)pKeyInfo.GetValue(i) == ordinal) { return true; } } } return false; } #endregion #region Indexers public object this[int i] { get { return this.GetValue(i); } } public object this[string name] { get { return this.GetValue(this.GetOrdinal(name)); } } #endregion #region IDataRecord Properties & Methods public int FieldCount { get { return this.command.Statement.RowDescriptor.Fields.Length; } } public String GetName(int i) { this.CheckIndex(i); return this.command.Statement.RowDescriptor.Fields[i].FieldName; } [EditorBrowsable(EditorBrowsableState.Never)] public String GetDataTypeName(int i) { this.CheckIndex(i); return this.command.Statement.RowDescriptor.Fields[i].DataType.Name; } public Type GetFieldType(int i) { this.CheckIndex(i); return this.command.Statement.RowDescriptor.Fields[i].DataType.SystemType; } public object GetValue(int i) { this.CheckPosition(); this.CheckIndex(i); return this.row[i]; } public int GetValues(object[] values) { this.CheckPosition(); for (int i = 0; i < FieldCount; i++) { values[i] = GetValue(i); } return values.Length; } public int GetOrdinal(string name) { if (this.IsClosed) { throw new InvalidOperationException("Reader closed"); } for (int i = 0; i < this.command.Statement.RowDescriptor.Fields.Length; i++) { if (this.CultureAwareCompare(command.Statement.RowDescriptor.Fields[i].FieldName, name)) { return i; } } return -1; } public bool GetBoolean(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToBoolean(this.GetValue(i)); } public byte GetByte(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToByte(this.GetValue(i)); } public long GetBytes( int i, long dataIndex, byte[] buffer, int bufferIndex, int length) { int bytesRead = 0; int realLength = length; if (buffer == null) { if (this.IsDBNull(i)) { return 0; } else { byte[] data = (byte[])this.GetValue(i); return data.Length; } } byte[] byteArray = (byte[])this.GetValue(i); if (length > (byteArray.Length - dataIndex)) { realLength = byteArray.Length - (int)dataIndex; } Array.Copy(byteArray, (int)dataIndex, buffer, bufferIndex, realLength); if ((byteArray.Length - dataIndex) < length) { bytesRead = byteArray.Length - (int)dataIndex; } else { bytesRead = length; } return bytesRead; } [EditorBrowsable(EditorBrowsableState.Never)] public char GetChar(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToChar(this.GetValue(i)); } public long GetChars( int i, long dataIndex, char[] buffer, int bufferIndex, int length) { this.CheckPosition(); this.CheckIndex(i); if (buffer == null) { if (this.IsDBNull(i)) { return 0; } else { char[] data = ((string)this.GetValue(i)).ToCharArray(); return data.Length; } } int charsRead = 0; int realLength = length; char[] charArray = ((string)this.GetValue(i)).ToCharArray(); if (length > (charArray.Length - dataIndex)) { realLength = charArray.Length - (int)dataIndex; } System.Array.Copy(charArray, (int)dataIndex, buffer, bufferIndex, realLength); if ( (charArray.Length - dataIndex) < length) { charsRead = charArray.Length - (int)dataIndex; } else { charsRead = length; } return charsRead; } public Guid GetGuid(int i) { throw new NotSupportedException("Guid datatype is not supported"); } public Int16 GetInt16(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToInt16(this.GetValue(i)); } public Int32 GetInt32(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToInt32(this.GetValue(i)); } public Int64 GetInt64(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToInt64(this.GetValue(i)); } public float GetFloat(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToSingle(this.GetValue(i)); } public double GetDouble(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToDouble(this.GetValue(i)); } public String GetString(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToString(this.GetValue(i)); } public Decimal GetDecimal(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToDecimal(this.GetValue(i)); } public DateTime GetDateTime(int i) { this.CheckPosition(); this.CheckIndex(i); return Convert.ToDateTime(this.GetValue(i)); } public TimeSpan GetTimeSpan(int i) { this.CheckPosition(); this.CheckIndex(i); return (TimeSpan)GetValue(i); } public PgPoint GetPgPoint(int i) { this.CheckPosition(); this.CheckIndex(i); return (PgPoint)this.GetPgValue(i); } public PgBox GetPgBox(int i) { this.CheckPosition(); this.CheckIndex(i); return (PgBox)this.GetPgValue(i); } public PgLSeg GetPgLSeg(int i) { this.CheckPosition(); this.CheckIndex(i); return (PgLSeg)this.GetPgValue(i); } public PgCircle GetPgCircle(int i) { this.CheckPosition(); this.CheckIndex(i); return (PgCircle)this.GetPgValue(i); } public PgPath GetPgPath(int i) { this.CheckPosition(); this.CheckIndex(i); return (PgPath)this.GetPgValue(i); } public PgPolygon GetPgPolygon(int i) { this.CheckPosition(); this.CheckIndex(i); return (PgPolygon)this.GetPgValue(i); } public PgTimeSpan GetPgTimeSpan(int i) { this.CheckPosition(); this.CheckIndex(i); return new PgTimeSpan(this.GetTimeSpan(i)); } public object GetPgValue(int i) { this.CheckPosition(); this.CheckIndex(i); switch (this.GetProviderType(i)) { case PgDbType.Interval: return this.GetPgTimeSpan(i); default: return this.GetValue(i); } } public int GetPgValues(object[] values) { return this.GetValues(values); } public IDataReader GetData(int i) { throw new NotSupportedException(); } public bool IsDBNull(int i) { this.CheckPosition(); this.CheckIndex(i); bool returnValue = false; if (this.row[i] == System.DBNull.Value) { returnValue = true; } return returnValue; } #endregion #region IEnumerable Methods IEnumerator IEnumerable.GetEnumerator() { return new DbEnumerator(this); } #endregion #region · Private Methods · private void CheckIndex(int i) { if (i < 0 || i >= this.fieldCount) { throw new IndexOutOfRangeException("Could not find specified column in results."); } } private void CheckPosition() { if (this.position == STARTPOS) { throw new InvalidOperationException("There are no data to read."); } } private int GetSize(int i) { return this.command.Statement.RowDescriptor.Fields[i].DataType.Size; } private int GetNumericPrecision(int i) { #warning "Add implementation" return 0; } private int GetNumericScale(int i) { #warning "Add implementation" return 0; } private PgDbType GetProviderType(int i) { return (PgDbType)this.command.Statement.RowDescriptor.Fields[i].DataType.DataType; } private bool IsNumeric(int i) { if (i < 0 || i >= this.FieldCount) { throw new IndexOutOfRangeException("Could not find specified column in results."); } return this.command.Statement.RowDescriptor.Fields[i].DataType.IsNumeric(); } private bool IsLong(int i) { if (i < 0 || i >= this.FieldCount) { throw new IndexOutOfRangeException("Could not find specified column in results."); } return this.command.Statement.RowDescriptor.Fields[i].DataType.IsLong(); } private bool IsAliased(int i) { /* TODO: Add implementation */ return false; } private bool IsExpression(int i) { bool returnValue = false; if (this.command.Statement.RowDescriptor.Fields[i].OidNumber == 0 && this.command.Statement.RowDescriptor.Fields[i].OidTable == 0) { returnValue = true; } return returnValue; } private DataTable GetSchemaTableStructure() { DataTable schema = new DataTable("Schema"); schema.Columns.Add("ColumnName" , System.Type.GetType("System.String")); schema.Columns.Add("ColumnOrdinal" , System.Type.GetType("System.Int32")); schema.Columns.Add("ColumnSize" , System.Type.GetType("System.Int32")); schema.Columns.Add("NumericPrecision", System.Type.GetType("System.Int32")); schema.Columns.Add("NumericScale" , System.Type.GetType("System.Int32")); schema.Columns.Add("DataType" , System.Type.GetType("System.Type")); schema.Columns.Add("ProviderType" , System.Type.GetType("System.Int32")); schema.Columns.Add("IsLong" , System.Type.GetType("System.Boolean")); schema.Columns.Add("AllowDBNull" , System.Type.GetType("System.Boolean")); schema.Columns.Add("IsReadOnly" , System.Type.GetType("System.Boolean")); schema.Columns.Add("IsRowVersion" , System.Type.GetType("System.Boolean")); schema.Columns.Add("IsUnique" , System.Type.GetType("System.Boolean")); schema.Columns.Add("IsKey" , System.Type.GetType("System.Boolean")); schema.Columns.Add("IsAutoIncrement", System.Type.GetType("System.Boolean")); schema.Columns.Add("IsAliased" , System.Type.GetType("System.Boolean")); schema.Columns.Add("IsExpression" , System.Type.GetType("System.Boolean")); schema.Columns.Add("BaseSchemaName" , System.Type.GetType("System.String")); schema.Columns.Add("BaseCatalogName", System.Type.GetType("System.String")); schema.Columns.Add("BaseTableName" , System.Type.GetType("System.String")); schema.Columns.Add("BaseColumnName" , System.Type.GetType("System.String")); return schema; } private void UpdateRecordsAffected() { if (this.command != null && !this.command.IsDisposed) { if (this.command.RecordsAffected != -1) { this.recordsAffected = this.recordsAffected == -1 ? 0 : this.recordsAffected; this.recordsAffected += this.command.RecordsAffected; } } } private bool CultureAwareCompare(string strA, string strB) { return CultureInfo.CurrentCulture.CompareInfo.Compare( strA, strB, CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase) == 0 ? true : false; } #endregion } } --- NEW FILE: PgCommandBuilder.cs --- /* PgSqlClient - ADO.NET Data Provider for PostgreSQL 7.4+ * Copyright (c) 2003-2005 Carlos Guzman Alvarez * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using System; using System.Data; using System.Data.Common; using System.Text; using System.ComponentModel; using PostgreSql.Data.Protocol; namespace PostgreSql.Data.PostgreSqlClient { public sealed class PgCommandBuilder : Component { #region · Fields · private PgDataAdapter dataAdapter; private PgCommand insertCommand; private PgCommand updateCommand; private PgCommand deleteCommand; private DataTable schemaTable; private string sqlInsert; private string sqlUpdate; private string sqlDelete; private string separator; private string whereClausule1; private string whereClausule2; private string setClausule; private string tableName; private bool hasPrimaryKey; private bool hasUniqueKey; private string quotePrefix; private string quoteSuffix; private bool disposed; private PgRowUpdatingEventHandler adapterHandler; #endregion #region · Properties · [DefaultValue(null)] public PgDataAdapter DataAdapter { get { return this.dataAdapter; } set { this.dataAdapter = value; // Registers the CommandBuilder as a listener for RowUpdating events that are // generated by the PgDataAdapter specified in this property. if (this.dataAdapter != null) { this.adapterHandler = new PgRowUpdatingEventHandler(this.RowUpdatingHandler); this.dataAdapter.RowUpdating += this.adapterHandler; } } } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string QuotePrefix { get { return this.quotePrefix; } set { if (this.insertCommand != null || this.updateCommand != null || this.deleteCommand != null) { throw new InvalidOperationException("This property cannot be changed after an insert, update, or delete command has been generated."); } this.quotePrefix = value; } } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string QuoteSuffix { get { return this.quoteSuffix; } set { if (this.insertCommand != null || this.updateCommand != null || this.deleteCommand != null) { throw new InvalidOperationException("This property cannot be changed after an insert, update, or delete command has been generated."); } this.quoteSuffix = value; } } #endregion #region · Internal Properties · internal PgCommand SelectCommand { get { if (this.dataAdapter.SelectCommand != null) { return this.dataAdapter.SelectCommand; } return null; } } #endregion #region · Constructors · public PgCommandBuilder() : base() { this.sqlInsert = "INSERT INTO {0} ({1}) VALUES ({2})"; this.sqlUpdate = "UPDATE {0} SET {1} WHERE ( {2} )"; this.sqlDelete = "DELETE FROM {0} WHERE ( {1} )"; this.whereClausule1 = "(({0} IS NULL AND ${1} = NULL) OR ({0} = ${2}))"; // this.whereClausule2 = "({0} = ${1})"; // this.setClausule = "{0} = ${1}"; this.whereClausule2 = "({0} = {1})"; this.setClausule = "{0} = {1}"; this.separator = ", "; this.quotePrefix = String.Empty; this.quoteSuffix = String.Empty; GC.SuppressFinalize(this); } public PgCommandBuilder(PgDataAdapter adapter) : this() { this.DataAdapter = adapter; } #endregion #region · IDisposable Methods · protected override void Dispose(bool disposing) { if (!this.disposed) { try { if (disposing) { this.RefreshSchema(); if (this.adapterHandler != null) { this.dataAdapter.RowUpdating -= this.adapterHandler; } this.sqlInsert = null; this.sqlUpdate = null; this.sqlDelete = null; this.whereClausule1 = null; this.whereClausule2 = null; this.setClausule = null; this.separator = null; this.quotePrefix = null; this.quoteSuffix = null; } // release any unmanaged resources this.disposed = true; } finally { base.Dispose(disposing); } } } #endregion #region · Static Methods · public static void DeriveParameters(PgCommand command) { if (command.CommandType != CommandType.StoredProcedure) { throw new InvalidOperationException("The command text is not a valid stored procedure name."); } command.Parameters.Clear(); DataTable spSchema = command.Connection.GetSchema("Functions", new string[] { null, command.CommandText.ToLower() }); if (spSchema.Rows.Count != 0) { int[] parameterTypes = (int[])spSchema.Rows[0]["ARGUMENTS"]; int parameterCount = (short)spSchema.Rows[0]["ARGUMENT_NUMBER"]; for (int i = 0; i < parameterCount; i++) { PgParameter parameter = command.Parameters.Add( "@ip" + i.ToString(), (PgDbType)PgDbClient.Types[parameterTypes[i]].DataType); parameter.Direction = ParameterDirection.Input; } int returnType = (int)spSchema.Rows[0]["RETURN_TYPE"]; if (returnType != 0) { PgParameter parameter = command.Parameters.Add( "@op0", PgDbClient.Types[returnType]); parameter.Direction = ParameterDirection.Output; } } } #endregion #region · Methods · public PgCommand GetInsertCommand() { if (this.insertCommand == null) { this.BuildInsertCommand(null, null); } return this.insertCommand; } public PgCommand GetUpdateCommand() { if (this.updateCommand == null) { this.BuildUpdateCommand(null, null); } return this.updateCommand; } public PgCommand GetDeleteCommand() { if (this.deleteCommand == null) { this.BuildDeleteCommand(null, null); } return this.deleteCommand; } public void RefreshSchema() { if (this.dataAdapter != null) { if (this.dataAdapter.InsertCommand == this.insertCommand) { this.dataAdapter.InsertCommand = null; } if (this.dataAdapter.DeleteCommand == this.deleteCommand) { this.dataAdapter.DeleteCommand = null; } if (this.dataAdapter.UpdateCommand == this.updateCommand) { this.dataAdapter.UpdateCommand = null; } } if (this.insertCommand != null) { this.insertCommand.Dispose(); } if (this.updateCommand != null) { this.updateCommand.Dispose(); } if (this.deleteCommand != null) { this.deleteCommand.Dispose(); } if (this.schemaTable != null) { this.schemaTable.Dispose(); } this.schemaTable = null; this.insertCommand = null; this.updateCommand = null; this.deleteCommand = null; } #endregion #region Build Command Methods private PgCommand BuildInsertCommand(DataRow row, DataTableMapping tableMapping) { StringBuilder sql = new StringBuilder(); StringBuilder fields = new StringBuilder(); StringBuilder values = new StringBuilder(); this.BuildSchemaTable(); // Create a new command this.CreateCommand(ref this.insertCommand); int i = 1; foreach (DataRow schemaRow in schemaTable.Rows) { if (this.IsUpdatable(schemaRow, row, tableMapping)) { if (fields.Length > 0) { fields.Append(this.separator); } if (values.Length > 0) { values.Append(this.separator); } PgParameter parameter = this.CreateParameter( schemaRow, i, false); if (row != null && tableMapping != null) { DataColumn column = this.GetDataColumn( schemaRow["BaseColumnName"].ToString(), tableMapping, row); if (column != null) { parameter.Value = row[column]; } } i++; // Build Field name and append it to the string fields.Append(this.GetQuotedIdentifier(schemaRow["BaseColumnName"])); // Build value name and append it to the string values.Append(parameter.ParameterName); this.insertCommand.Parameters.Add(parameter); } } sql.AppendFormat( this.sqlInsert, this.GetQuotedIdentifier(tableName), fields.ToString(), values.ToString()); this.insertCommand.CommandText = sql.ToString(); return this.insertCommand; } private PgCommand BuildUpdateCommand(DataRow row, DataTableMapping tableMapping) { StringBuilder sql = new StringBuilder(); StringBuilder sets = new StringBuilder(); StringBuilder where = new StringBuilder(); this.BuildSchemaTable(); if (!this.hasPrimaryKey && !this.hasUniqueKey) { throw new InvalidOperationException("Dynamic SQL generation for the UpdateCommand is not supported against a SelectCommand that does not return any key column information."); } // Create a new command this.CreateCommand(ref this.updateCommand); int i = 1; foreach (DataRow schemaRow in schemaTable.Rows) { if (this.IsUpdatable(schemaRow, row, tableMapping)) { if (sets.Length > 0) { sets.Append(separator); } PgParameter parameter = this.CreateParameter(schemaRow, i, false); // Build Field name and append it to the string sets.AppendFormat( this.setClausule, this.GetQuotedIdentifier(schemaRow["BaseColumnName"]), parameter.ParameterName); if (row != null && tableMapping != null) { DataColumn column = this.GetDataColumn( schemaRow["BaseColumnName"].ToString(), tableMapping, row); if (column != null) { parameter.Value = row[column]; } } this.updateCommand.Parameters.Add(parameter); i++; } } // Build where clausule foreach (DataRow schemaRow in schemaTable.Rows) { if (this.IncludedInWhereClause(schemaRow)) { if (where.Length > 0) { where.Append(" AND "); } string quotedId = this.GetQuotedIdentifier(schemaRow["BaseColumnName"]); PgParameter parameter = this.CreateParameter(schemaRow, i, true); where.AppendFormat( this.whereClausule2, quotedId, parameter.ParameterName); if (row != null && tableMapping != null) { DataColumn column = this.GetDataColumn( schemaRow["BaseColumnName"].ToString(), tableMapping, row); if (column != null) { parameter.Value = row[column, DataRowVersion.Original]; } } this.updateCommand.Parameters.Add(parameter); i++; } } sql.AppendFormat( this.sqlUpdate, this.GetQuotedIdentifier(tableName), sets.ToString(), where.ToString()); this.updateCommand.CommandText = sql.ToString(); return this.updateCommand; } private PgCommand BuildDeleteCommand(DataRow row, DataTableMapping tableMapping) { StringBuilder sql = new StringBuilder(); StringBuilder where = new StringBuilder(); string dsColumnName = String.Empty; this.BuildSchemaTable(); if (!this.hasPrimaryKey && !this.hasUniqueKey) { throw new InvalidOperationException("Dynamic SQL generation for the DeleteCommand is not supported against a SelectCommand that does not return any key column information."); } // Create a new command this.CreateCommand(ref this.deleteCommand); // Build where clausule int i = 1; foreach (DataRow schemaRow in schemaTable.Rows) { if (this.IncludedInWhereClause(schemaRow)) { if (where.Length > 0) { where.Append(" AND "); } string quotedId = this.GetQuotedIdentifier(schemaRow["BaseColumnName"]); PgParameter parameter = this.CreateParameter(schemaRow, i, true); where.AppendFormat( this.whereClausule2, quotedId, parameter.ParameterName); if (row != null && tableMapping != null) { DataColumn column = this.GetDataColumn( schemaRow["BaseColumnName"].ToString(), tableMapping, row); if (column != null) { parameter.Value = row[column, DataRowVersion.Original]; } } this.deleteCommand.Parameters.Add(parameter); i++; } } sql.AppendFormat( this.sqlDelete, this.GetQuotedIdentifier(tableName), where.ToString()); this.deleteCommand.CommandText = sql.ToString(); return this.deleteCommand; } private PgParameter CreateParameter( DataRow schemaRow, int index, bool isWhereParameter) { PgParameter parameter = new PgParameter(String.Format("@p{0}", index), (PgDbType)schemaRow["ProviderType"]); parameter.Size = Convert.ToInt32(schemaRow["ColumnSize"]); if (schemaRow["NumericPrecision"] != DBNull.Value) { parameter.Precision = Convert.ToByte(schemaRow["NumericPrecision"]); } if (schemaRow["NumericScale"] != DBNull.Value) { parameter.Precision = Convert.ToByte(schemaRow["NumericScale"]); } parameter.SourceColumn = Convert.ToString(schemaRow["BaseColumnName"]); if (isWhereParameter) { parameter.SourceVersion = DataRowVersion.Original; } else { parameter.SourceVersion = DataRowVersion.Current; } return parameter; } private bool IsUpdatable( DataRow schemaRow, DataRow row, DataTableMapping tableMapping) { if (row != null && tableMapping != null) { DataColumn column = this.GetDataColumn( schemaRow["BaseColumnName"].ToString(), tableMapping, row); if (column != null) { if (column.Expression != null && column.Expression.Length != 0) { return false; } if (column.AutoIncrement) { return false; } if (column.ReadOnly) { return false; } } } if ((bool) schemaRow["IsExpression"]) { return false; } if ((bool) schemaRow["IsAutoIncrement"]) { return false; } if ((bool) schemaRow["IsRowVersion"]) { return false; } if ((bool) schemaRow["IsReadOnly"]) { return false; } return true; } private bool IncludedInWhereClause(DataRow schemaRow) { PgDbType pgDbType = (PgDbType)schemaRow["ProviderType"]; if (!(bool)schemaRow["IsKey"]) { return false; } if (pgDbType == PgDbType.Binary) { return false; } if (pgDbType == PgDbType.Array) { return false; } return true; } private void BuildSchemaTable() { bool mustClose = false; if (this.SelectCommand == null) { throw new InvalidOperationException("The DataAdapter.SelectCommand property needs to be initialized."); } if (this.SelectCommand.Connection == null) { throw new InvalidOperationException("The DataAdapter.SelectCommand.Connection property needs to be initialized."); } if (this.schemaTable == null) { if (this.SelectCommand.Connection.State == ConnectionState.Closed) { mustClose = true; this.SelectCommand.Connection.Open(); } try { PgDataReader reader = SelectCommand.ExecuteReader(CommandBehavior.SchemaOnly); schemaTable = reader.GetSchemaTable(); reader.Close(); this.CheckSchemaTable(); } catch { throw; } finally { if (mustClose) { this.SelectCommand.Connection.Close(); } } } } private void CheckSchemaTable() { tableName = String.Empty; hasPrimaryKey = false; hasUniqueKey = false; foreach (DataRow schemaRow in schemaTable.Rows) { if (tableName.Length == 0) { tableName = (string)schemaRow["BaseSchemaName"] + "." + (string)schemaRow["BaseTableName"]; } if (!(bool)schemaRow["IsExpression"] && tableName != (string)schemaRow["BaseSchemaName"] + "." + (string)schemaRow["BaseTableName"]) { throw new InvalidOperationException("Dynamic SQL generation is not supported against multiple base tables."); } if ((bool)schemaRow["IsKey"]) { hasPrimaryKey = true; } if ((bool)schemaRow["IsUnique"]) { hasUniqueKey = true; } } } private string GetQuotedIdentifier(object identifier) { return quotePrefix + identifier.ToString() + quoteSuffix; } private void CreateCommand(ref PgCommand command) { if (command == null) { command = this.SelectCommand.Connection.CreateCommand(); } command.Transaction = this.SelectCommand.Transaction; command.CommandType = CommandType.Text; // ... [truncated message content] |