X Tutup
// created on 21/5/2002 at 20:03 // Npgsql.NpgsqlCommand.cs // // Author: // Francisco Jr. (fxjrlists@yahoo.com.br) // // Copyright (C) 2002 The Npgsql Development Team // npgsql-general@gborg.postgresql.org // http://gborg.postgresql.org/project/npgsql/projdisplay.php // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose, without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph and the following two paragraphs appear in all copies. // // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. // // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.IO; using System.Reflection; using System.Resources; using System.Text; using System.Text.RegularExpressions; using NpgsqlTypes; #if WITHDESIGN #endif namespace Npgsql { /// /// Represents a SQL statement or function (stored procedure) to execute /// against a PostgreSQL database. This class cannot be inherited. /// #if WITHDESIGN [System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlCommand)), ToolboxItem(true)] #endif public sealed partial class NpgsqlCommand : DbCommand, ICloneable { private enum PrepareStatus { NotPrepared, NeedsPrepare, V2Prepared, V3Prepared } // Logging related values private static readonly String CLASSNAME = MethodBase.GetCurrentMethod().DeclaringType.Name; private static readonly ResourceManager resman = new ResourceManager(MethodBase.GetCurrentMethod().DeclaringType); private NpgsqlConnection connection; private NpgsqlConnector m_Connector; //renamed to account for hiding it in a local function //if all locals were named with this prefix, it would solve LOTS of issues. private NpgsqlTransaction transaction; private String commandText; private Int32 timeout; private CommandType commandType; private readonly NpgsqlParameterCollection parameters = new NpgsqlParameterCollection(); private String planName; private Boolean designTimeVisible; private PrepareStatus prepared = PrepareStatus.NotPrepared; private NpgsqlBind bind = null; private NpgsqlExecute execute = null; private NpgsqlRowDescription currentRowDescription = null; private Int64 lastInsertedOID = 0; // locals about function support so we don`t need to check it everytime a function is called. private Boolean functionChecksDone = false; private Boolean functionNeedsColumnListDefinition = false; // Functions don't return record by default. private Boolean commandTimeoutSet = false; private UpdateRowSource updateRowSource = UpdateRowSource.Both; private static readonly Array ParamNameCharTable; // Constructors static NpgsqlCommand() { ParamNameCharTable = BuildParameterNameCharacterTable(); } private static Array BuildParameterNameCharacterTable() { Array paramNameCharTable; // Table has lower bound of (int)'.'; paramNameCharTable = Array.CreateInstance(typeof(byte), new int[] {'z' - '.' + 1}, new int[] {'.'}); paramNameCharTable.SetValue((byte)'.', (int)'.'); for (int i = '0' ; i <= '9' ; i++) { paramNameCharTable.SetValue((byte)i, i); } for (int i = 'A' ; i <= 'Z' ; i++) { paramNameCharTable.SetValue((byte)i, i); } paramNameCharTable.SetValue((byte)'_', (int)'_'); for (int i = 'a' ; i <= 'z' ; i++) { paramNameCharTable.SetValue((byte)i, i); } return paramNameCharTable; } /// /// Initializes a new instance of the NpgsqlCommand class. /// public NpgsqlCommand() : this(String.Empty, null, null) { } /// /// Initializes a new instance of the NpgsqlCommand class with the text of the query. /// /// The text of the query. public NpgsqlCommand(String cmdText) : this(cmdText, null, null) { } /// /// Initializes a new instance of the NpgsqlCommand class with the text of the query and a NpgsqlConnection. /// /// The text of the query. /// A NpgsqlConnection that represents the connection to a PostgreSQL server. public NpgsqlCommand(String cmdText, NpgsqlConnection connection) : this(cmdText, connection, null) { } /// /// Initializes a new instance of the NpgsqlCommand class with the text of the query, a NpgsqlConnection, and the NpgsqlTransaction. /// /// The text of the query. /// A NpgsqlConnection that represents the connection to a PostgreSQL server. /// The NpgsqlTransaction in which the NpgsqlCommand executes. public NpgsqlCommand(String cmdText, NpgsqlConnection connection, NpgsqlTransaction transaction) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME); planName = String.Empty; commandText = cmdText; this.connection = connection; if (this.connection != null) { this.m_Connector = connection.Connector; if (m_Connector != null && m_Connector.AlwaysPrepare) { prepared = PrepareStatus.NeedsPrepare; } } commandType = CommandType.Text; this.Transaction = transaction; SetCommandTimeout(); } /// /// Used to execute internal commands. /// internal NpgsqlCommand(String cmdText, NpgsqlConnector connector) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME); planName = String.Empty; commandText = cmdText; this.m_Connector = connector; commandType = CommandType.Text; // Removed this setting. It was causing too much problem. // Do internal commands really need different timeout setting? // Internal commands aren't affected by command timeout value provided by user. // timeout = 20; } // Public properties. /// /// Gets or sets the SQL statement or function (stored procedure) to execute at the data source. /// /// The Transact-SQL statement or stored procedure to execute. The default is an empty string. [Category("Data"), DefaultValue("")] public override String CommandText { get { return commandText; } set { // [TODO] Validate commandtext. NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "CommandText", value); commandText = value; UnPrepare(); functionChecksDone = false; } } /// /// Gets or sets the wait time before terminating the attempt /// to execute a command and generating an error. /// /// The time (in seconds) to wait for the command to execute. /// The default is 20 seconds. [DefaultValue(20)] public override Int32 CommandTimeout { get { return timeout; } set { if (value < 0) { throw new ArgumentOutOfRangeException(resman.GetString("Exception_CommandTimeoutLessZero")); } timeout = value; NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "CommandTimeout", value); commandTimeoutSet = true; } } /// /// Gets or sets a value indicating how the /// CommandText property is to be interpreted. /// /// One of the CommandType values. The default is CommandType.Text. [Category("Data"), DefaultValue(CommandType.Text)] public override CommandType CommandType { get { return commandType; } set { commandType = value; NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "CommandType", value); } } protected override DbConnection DbConnection { get { return Connection; } set { Connection = (NpgsqlConnection)value; NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "DbConnection", value); } } /// /// Gets or sets the NpgsqlConnection /// used by this instance of the NpgsqlCommand. /// /// The connection to a data source. The default value is a null reference. [Category("Behavior"), DefaultValue(null)] public new NpgsqlConnection Connection { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Connection"); return connection; } set { if (this.Connection == value) { return; } //if (this.transaction != null && this.transaction.Connection == null) // this.transaction = null; // All this checking needs revising. It should be simpler. // This this.Connector != null check was added to remove the nullreferenceexception in case // of the previous connection has been closed which makes Connector null and so the last check would fail. // See bug 1000581 for more details. if (this.transaction != null && this.connection != null && this.Connector != null && this.Connector.Transaction != null) { throw new InvalidOperationException(resman.GetString("Exception_SetConnectionInTransaction")); } this.connection = value; Transaction = null; if (this.connection != null) { m_Connector = this.connection.Connector; } SetCommandTimeout(); NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "Connection", value); } } internal NpgsqlConnector Connector { get { if (this.connection != null) { m_Connector = this.connection.Connector; } return m_Connector; } } internal Type[] ExpectedTypes { get; set; } protected override DbParameterCollection DbParameterCollection { get { return Parameters; } } /// /// Gets the NpgsqlParameterCollection. /// /// The parameters of the SQL statement or function (stored procedure). The default is an empty collection. #if WITHDESIGN [Category("Data"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] #endif public new NpgsqlParameterCollection Parameters { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Parameters"); return parameters; } } protected override DbTransaction DbTransaction { get { return Transaction; } set { Transaction = (NpgsqlTransaction)value; NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "IDbCommand.Transaction", value); } } /// /// Gets or sets the NpgsqlTransaction /// within which the NpgsqlCommand executes. /// /// The NpgsqlTransaction. /// The default value is a null reference. #if WITHDESIGN [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] #endif public new NpgsqlTransaction Transaction { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Transaction"); if (this.transaction != null && this.transaction.Connection == null) { this.transaction = null; } return this.transaction; } set { NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "Transaction", value); this.transaction = value; } } /// /// Gets or sets how command results are applied to the DataRow /// when used by the Update /// method of the DbDataAdapter. /// /// One of the UpdateRowSource values. #if WITHDESIGN [Category("Behavior"), DefaultValue(UpdateRowSource.Both)] #endif public override UpdateRowSource UpdatedRowSource { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "UpdatedRowSource"); return updateRowSource; } set { switch (value) { // validate value (required based on base type contract) case UpdateRowSource.None: case UpdateRowSource.OutputParameters: case UpdateRowSource.FirstReturnedRecord: case UpdateRowSource.Both: updateRowSource = value; break; default: throw new ArgumentOutOfRangeException(); } } } /// /// Returns oid of inserted row. This is only updated when using executenonQuery and when command inserts just a single row. If table is created without oids, this will always be 0. /// public Int64 LastInsertedOID { get { return lastInsertedOID; } } /// /// Attempts to cancel the execution of a NpgsqlCommand. /// /// This Method isn't implemented yet. public override void Cancel() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Cancel"); try { // get copy for thread safety of null test NpgsqlConnector connector = Connector; if (connector != null) { connector.CancelRequest(); } } catch (IOException) { Connection.ClearPool(); } catch (NpgsqlException) { // Cancel documentation says the Cancel doesn't throw on failure } } /// /// Create a new command based on this one. /// /// A new NpgsqlCommand object. Object ICloneable.Clone() { return Clone(); } /// /// Create a new command based on this one. /// /// A new NpgsqlCommand object. public NpgsqlCommand Clone() { // TODO: Add consistency checks. NpgsqlCommand clone = new NpgsqlCommand(CommandText, Connection, Transaction); clone.CommandTimeout = CommandTimeout; clone.CommandType = CommandType; clone.DesignTimeVisible = DesignTimeVisible; if (ExpectedTypes != null) { clone.ExpectedTypes = (Type[])ExpectedTypes.Clone(); } foreach (NpgsqlParameter parameter in Parameters) { clone.Parameters.Add(parameter.Clone()); } return clone; } /// /// Creates a new instance of an DbParameter object. /// /// An DbParameter object. protected override DbParameter CreateDbParameter() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateDbParameter"); return CreateParameter(); } /// /// Creates a new instance of a NpgsqlParameter object. /// /// A NpgsqlParameter object. public new NpgsqlParameter CreateParameter() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateParameter"); return new NpgsqlParameter(); } /* /// /// Releases the resources used by the NpgsqlCommand. /// protected override void Dispose (bool disposing) { if (disposing) { // Only if explicitly calling Close or dispose we still have access to // managed resources. NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose"); if (connection != null) { connection.Dispose(); } base.Dispose(disposing); } }*/ private void SetCommandTimeout() { if (commandTimeoutSet) return; if (Connection != null) { timeout = Connection.CommandTimeout; } else { timeout = (int)NpgsqlConnectionStringBuilder.GetDefaultValue(Keywords.CommandTimeout); } } internal NpgsqlException ClearPoolAndCreateException(Exception e) { Connection.ClearPool(); return new NpgsqlException(resman.GetString("Exception_ConnectionBroken"), e); } public override bool DesignTimeVisible { get { return designTimeVisible; } set { designTimeVisible = value; } } } }
X Tutup