// 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.Net;
-using System.Net.Sockets;
-using System.IO;
using System.Text;
+using System.Resources;
using System.ComponentModel;
using System.Collections;
+
using NpgsqlTypes;
+
+#if WITHDESIGN
using Npgsql.Design;
+#endif
namespace Npgsql
{
/// <summary>
- /// Represents a SQL statement or function (stored procedure) to execute against a PostgreSQL database. This class cannot be inherited.
+ /// Represents a SQL statement or function (stored procedure) to execute
+ /// against a PostgreSQL database. This class cannot be inherited.
/// </summary>
+ #if WITHDESIGN
[System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlCommand)), ToolboxItem(true)]
- public sealed class NpgsqlCommand : Component, IDbCommand
+ #endif
+ public sealed class NpgsqlCommand : Component, IDbCommand, ICloneable
{
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlCommand";
+ private static ResourceManager resman = new ResourceManager(typeof(NpgsqlCommand));
private NpgsqlConnection connection;
+ private NpgsqlConnector connector;
private NpgsqlTransaction transaction;
private String text;
private Int32 timeout;
private CommandType type;
private NpgsqlParameterCollection parameters;
private String planName;
- private static Int32 planIndex = 0;
- private static Int32 portalIndex = 0;
private NpgsqlParse parse;
private NpgsqlBind bind;
- // Logging related values
- private static readonly String CLASSNAME = "NpgsqlCommand";
- private System.Resources.ResourceManager resman;
+ private Boolean invalidTransactionDetected = false;
+
+ private CommandBehavior commandBehavior;
// Constructors
/// <param name="transaction">The <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see> in which the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> executes.</param>
public NpgsqlCommand(String cmdText, NpgsqlConnection connection, NpgsqlTransaction transaction)
{
- resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
planName = String.Empty;
text = cmdText;
this.connection = connection;
+ if (this.connection != null)
+ this.connector = connection.Connector;
+
parameters = new NpgsqlParameterCollection();
timeout = 20;
type = CommandType.Text;
this.Transaction = transaction;
+ commandBehavior = CommandBehavior.Default;
+
+
}
- /*
/// <summary>
- /// Finalizer for <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
+ /// Used to execute internal commands.
/// </summary>
- ~NpgsqlCommand ()
+ internal NpgsqlCommand(String cmdText, NpgsqlConnector connector)
{
- Dispose(false);
- }*/
+ resman = new System.Resources.ResourceManager(this.GetType());
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+
+ planName = String.Empty;
+ text = cmdText;
+ this.connector = connector;
+ type = CommandType.Text;
+ commandBehavior = CommandBehavior.Default;
+
+ parameters = new NpgsqlParameterCollection();
+ timeout = 20;
+ }
// Public properties.
/// <summary>
planName = String.Empty;
parse = null;
bind = null;
+ commandBehavior = CommandBehavior.Default;
}
}
}
}
- IDbConnection IDbCommand.Connection {
+ IDbConnection IDbCommand.Connection
+ {
get
{
return Connection;
set
{
- connection = (NpgsqlConnection) value;
+ Connection = (NpgsqlConnection) value;
NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "IDbCommand.Connection", value);
}
}
set
{
- if (this.transaction != null && this.transaction.Connection == null)
- this.transaction = null;
- if (this.connection != null && this.connection.InTransaction == true)
+ if (this.Connection == value)
+ return;
+
+ //if (this.transaction != null && this.transaction.Connection == null)
+ // this.transaction = null;
+
+ if (this.transaction != null && this.connection != null && this.Connector.Transaction != null)
throw new InvalidOperationException(resman.GetString("Exception_SetConnectionInTransaction"));
+
+
this.connection = value;
+ Transaction = null;
+ if (this.connection != null)
+ connector = this.connection.Connector;
+
NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "Connection", value);
}
}
+ internal NpgsqlConnector Connector {
+ get
+ {
+ if (connector == null && this.connection != null)
+ connector = this.connection.Connector;
+
+ return connector;
+ }
+ }
+
IDataParameterCollection IDbCommand.Parameters {
get
{
/// Gets the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see>.
/// </summary>
/// <value>The parameters of the SQL statement or function (stored procedure). The default is an empty collection.</value>
+ #if WITHDESIGN
[Category("Data"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
+ #endif
+
public NpgsqlParameterCollection Parameters {
get
{
}
}
+
+ IDbTransaction IDbCommand.Transaction
+ {
+ get
+ {
+ return Transaction;
+ }
+
+ set
+ {
+ Transaction = (NpgsqlTransaction) value;
+ NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "IDbCommand.Transaction", value);
+ }
+ }
+
/// <summary>
/// Gets or sets the <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
/// within which the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> executes.
/// </summary>
/// <value>The <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>.
/// The default value is a null reference.</value>
+ #if WITHDESIGN
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
- public IDbTransaction Transaction {
+ #endif
+
+ public NpgsqlTransaction Transaction {
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Transaction");
/// method of the <see cref="System.Data.Common.DbDataAdapter">DbDataAdapter</see>.
/// </summary>
/// <value>One of the <see cref="System.Data.UpdateRowSource">UpdateRowSource</see> values.</value>
+ #if WITHDESIGN
[Category("Behavior"), DefaultValue(UpdateRowSource.Both)]
+ #endif
+
public UpdateRowSource UpdatedRowSource {
get
{
// [TODO] Finish method implementation.
throw new NotImplementedException();
}
+
+ /// <summary>
+ /// Create a new command based on this one.
+ /// </summary>
+ /// <returns>A new NpgsqlCommand object.</returns>
+ Object ICloneable.Clone()
+ {
+ return Clone();
+ }
+
+ /// <summary>
+ /// Create a new connection based on this one.
+ /// </summary>
+ /// <returns>A new NpgsqlConnection object.</returns>
+ public NpgsqlCommand Clone()
+ {
+ // TODO: Add consistency checks.
+
+ return new NpgsqlCommand(CommandText, Connection, Transaction);
+ }
/// <summary>
/// Creates a new instance of an <see cref="System.Data.IDbDataParameter">IDbDataParameter</see> object.
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteNonQuery");
ExecuteCommand();
-
+
+ UpdateOutputParameters();
+
+
// If nothing is returned, just return -1.
- if(connection.Mediator.CompletedResponses.Count == 0) {
+ if(Connector.Mediator.CompletedResponses.Count == 0)
+ {
return -1;
}
// Check if the response is available.
- String firstCompletedResponse = (String)connection.Mediator.CompletedResponses[0];
+ String firstCompletedResponse = (String)Connector.Mediator.CompletedResponses[0];
if (firstCompletedResponse == null)
return -1;
else
return -1;
}
+
+
+
+ private void UpdateOutputParameters()
+ {
+ // Check if there was some resultset returned. If so, put the result in output parameters.
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "UpdateOutputParameters");
+
+ // Get ResultSets.
+ ArrayList resultSets = Connector.Mediator.ResultSets;
+
+ if (resultSets.Count != 0)
+ {
+ NpgsqlResultSet nrs = (NpgsqlResultSet)resultSets[0];
+
+ if ((nrs != null) && (nrs.Count > 0))
+ {
+ NpgsqlAsciiRow nar = (NpgsqlAsciiRow)nrs[0];
+
+ Int32 i = 0;
+ Boolean hasMapping = false;
+
+ // First check if there is any mapping between parameter name and resultset name.
+ // If so, just update output parameters which has mapping.
+
+ foreach (NpgsqlParameter p in Parameters)
+ {
+ try
+ {
+ if (nrs.RowDescription.FieldIndex(p.ParameterName.Substring(1)) > -1)
+ {
+ hasMapping = true;
+ break;
+ }
+ }
+ catch(ArgumentOutOfRangeException)
+ {}
+ }
+
+
+ if (hasMapping)
+ {
+ foreach (NpgsqlParameter p in Parameters)
+ {
+ if (((p.Direction == ParameterDirection.Output) ||
+ (p.Direction == ParameterDirection.InputOutput)) && (i < nrs.RowDescription.NumFields ))
+ {
+ try
+ {
+ p.Value = nar[nrs.RowDescription.FieldIndex(p.ParameterName.Substring(1))];
+ i++;
+ }
+ catch(ArgumentOutOfRangeException)
+ {}
+ }
+ }
+
+ }
+ else
+ foreach (NpgsqlParameter p in Parameters)
+ {
+ if (((p.Direction == ParameterDirection.Output) ||
+ (p.Direction == ParameterDirection.InputOutput)) && (i < nrs.RowDescription.NumFields ))
+ {
+ p.Value = nar[i];
+ i++;
+ }
+ }
+ }
+
+ }
+
+
+ }
/// <summary>
/// Sends the <see cref="Npgsql.NpgsqlCommand.CommandText">CommandText</see> to
// [FIXME] No command behavior handling.
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteReader", cb);
+ commandBehavior = cb;
ExecuteCommand();
+
+ UpdateOutputParameters();
// Get the resultsets and create a Datareader with them.
- return new NpgsqlDataReader(connection.Mediator.ResultSets, connection.Mediator.CompletedResponses, connection, cb);
+ return new NpgsqlDataReader(Connector.Mediator.ResultSets, Connector.Mediator.CompletedResponses, connection, cb);
}
///<summary>
for (Int32 i = 0; i < parameters.Count; i++)
{
// Do not quote strings, or escape existing quotes - this will be handled by the backend.
- parameterValues[i] = NpgsqlTypesHelper.ConvertNpgsqlParameterToBackendStringValue(parameters[i], false);
+ // DBNull or null values are returned as null.
+ // TODO: Would it be better to remove this null special handling out of ConvertToBackend??
+ parameterValues[i] = parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, true);
}
bind.ParameterValues = parameterValues;
}
- connection.Bind(bind);
- connection.Mediator.RequireReadyForQuery = false;
- connection.Flush();
+ Connector.Bind(bind);
+ Connector.Mediator.RequireReadyForQuery = false;
+ Connector.Flush();
- connection.CheckErrorsAndNotifications();
+ connector.CheckErrorsAndNotifications();
}
/// <summary>
// Only the first column of the first row must be returned.
// Get ResultSets.
- ArrayList resultSets = connection.Mediator.ResultSets;
+ ArrayList resultSets = Connector.Mediator.ResultSets;
// First data is the RowDescription object.
// Check all resultsets as insert commands could have been sent along
// Check the connection state.
CheckConnectionState();
- if (! connection.SupportsPrepare) {
+ if (! Connector.SupportsPrepare)
+ {
return; // Do nothing.
}
- if (connection.BackendProtocolVersion == ProtocolVersion.Version2)
+ if (connector.BackendProtocolVersion == ProtocolVersion.Version2)
{
- NpgsqlCommand command = new NpgsqlCommand(GetPrepareCommandText(), connection );
+ NpgsqlCommand command = new NpgsqlCommand(GetPrepareCommandText(), connector );
command.ExecuteNonQuery();
}
else
{
// Use the extended query parsing...
- planName = "NpgsqlPlan" + System.Threading.Interlocked.Increment(ref planIndex);
- String portalName = "NpgsqlPortal" + System.Threading.Interlocked.Increment(ref portalIndex);
+ //planName = "NpgsqlPlan" + Connector.NextPlanIndex();
+ planName = Connector.NextPlanName();
+ String portalName = Connector.NextPortalName();
parse = new NpgsqlParse(planName, GetParseCommandText(), new Int32[] {});
- connection.Parse(parse);
- connection.Mediator.RequireReadyForQuery = false;
- connection.Flush();
+ Connector.Parse(parse);
+ Connector.Mediator.RequireReadyForQuery = false;
+ Connector.Flush();
// Check for errors and/or notifications and do the Right Thing.
- connection.CheckErrorsAndNotifications();
+ connector.CheckErrorsAndNotifications();
- bind = new NpgsqlBind(portalName, planName, new Int16[] {0}, null, new Int16[] {0});
+ bind = new NpgsqlBind("", planName, new Int16[] {0}, null, new Int16[] {0});
}
}
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckConnectionState");
+
// Check the connection state.
- if (connection == null)
- throw new InvalidOperationException(resman.GetString("Exception_ConnectionNull"));
- if (connection.State != ConnectionState.Open)
+ if (Connector == null || Connector.State != ConnectionState.Open)
+ {
throw new InvalidOperationException(resman.GetString("Exception_ConnectionNotOpen"));
-
+ }
}
/// <summary>
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetClearCommandText");
-
+ Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
+
+ Boolean functionReturnsRecord = false; // Functions don't return record by default.
+
String result = text;
if (type == CommandType.StoredProcedure)
- if (connection.SupportsPrepare)
+ {
+
+ functionReturnsRecord = CheckFunctionReturnRecord();
+
+ // Check if just procedure name was passed. If so, does not replace parameter names and just pass parameter values in order they were added in parameters collection.
+ if (!result.Trim().EndsWith(")"))
+ {
+ addProcedureParenthesis = true;
+ result += "(";
+ }
+
+ if (Connector.SupportsPrepare)
result = "select * from " + result; // This syntax is only available in 7.3+ as well SupportsPrepare.
else
- result = "select " + result; // Only a single result return supported. 7.2 and earlier.
+ result = "select " + result; //Only a single result return supported. 7.2 and earlier.
+ }
else if (type == CommandType.TableDirect)
- return "select * from " + result; // There is no parameter support on table direct.
+ return "select * from " + result; // There is no parameter support on table direct.
- if (parameters.Count == 0)
+ if (parameters == null || parameters.Count == 0)
+ {
+ if (addProcedureParenthesis)
+ result += ")";
+
+ if (functionReturnsRecord)
+ result = AddFunctionReturnsRecordSupport(result);
+
+
+ result = AddSingleRowBehaviorSupport(result);
+
return result;
+ }
//CheckParameters();
- String parameterName;
-
for (Int32 i = 0; i < parameters.Count; i++)
{
- parameterName = parameters[i].ParameterName;
-
- result = ReplaceParameterValue(result, parameterName, NpgsqlTypesHelper.ConvertNpgsqlParameterToBackendStringValue(parameters[i], true));
+ NpgsqlParameter Param = parameters[i];
+
+ if ((Param.Direction == ParameterDirection.Input) ||
+ (Param.Direction == ParameterDirection.InputOutput))
+
+
+ // If parenthesis don't need to be added, they were added by user with parameter names. Replace them.
+ if (!addProcedureParenthesis)
+ // FIXME DEBUG ONLY
+ // adding the '::<datatype>' on the end of a parameter is a highly
+ // questionable practice, but it is great for debugging!
+ // Removed as this was going in infinite loop when the parameter name had the same name of parameter
+ // type name. i.e.: parameter name called :text of type text. It would conflict with the parameter type name ::text.
+ result = ReplaceParameterValue(
+ result,
+ Param.ParameterName,
+ Param.TypeInfo.ConvertToBackend(Param.Value, false)
+ );
+ else
+ result += Param.TypeInfo.ConvertToBackend(Param.Value, false) + ",";
+ }
+
+
+ if (addProcedureParenthesis)
+ {
+ // Remove a trailing comma added from parameter handling above. If any.
+ // Maybe there are only output parameters.
+ if (result.EndsWith(","))
+ result = result.Remove(result.Length - 1, 1);
+
+ result += ")";
}
+ if (functionReturnsRecord)
+ result = AddFunctionReturnsRecordSupport(result);
+
+ return AddSingleRowBehaviorSupport(result);
+ }
+
+
+
+ private Boolean CheckFunctionReturnRecord()
+ {
+
+ if (Parameters.Count == 0)
+ return false;
+
+ String returnRecordQuery = "select count(*) > 0 from pg_proc where prorettype = ( select oid from pg_type where typname = 'record' ) and proargtypes='{0}' and proname='{1}';";
+
+ StringBuilder parameterTypes = new StringBuilder("");
+
+ foreach(NpgsqlParameter p in Parameters)
+ {
+ if ((p.Direction == ParameterDirection.Input) ||
+ (p.Direction == ParameterDirection.InputOutput))
+ {
+ parameterTypes.Append(Connection.Connector.OidToNameMapping[p.TypeInfo.Name].OID + " ");
+ }
+ }
+
+
+ NpgsqlCommand c = new NpgsqlCommand(String.Format(returnRecordQuery, parameterTypes.ToString(), CommandText), Connection);
+
+ Boolean ret = (Boolean) c.ExecuteScalar();
+
+ // reset any responses just before getting new ones
+ connector.Mediator.ResetResponses();
+ return ret;
+
+
+ }
+
+
+ private String AddFunctionReturnsRecordSupport(String OriginalResult)
+ {
+
+ StringBuilder sb = new StringBuilder(OriginalResult);
+
+ sb.Append(" as (");
+
+ foreach(NpgsqlParameter p in Parameters)
+ {
+ if ((p.Direction == ParameterDirection.Output) ||
+ (p.Direction == ParameterDirection.InputOutput))
+ {
+ sb.Append(String.Format("{0} {1}, ", p.ParameterName.Substring(1), p.TypeInfo.Name));
+ }
+ }
+
+ String result = sb.ToString();
+
+ result = result.Remove(result.Length - 2, 1);
+
+ result += ")";
+
+
+
return result;
-
+
+
}
for (Int32 i = 0; i < parameters.Count; i++)
{
- result.Append(NpgsqlTypesHelper.ConvertNpgsqlParameterToBackendStringValue(parameters[i], false) + ',');
+ result.Append(parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, false) + ',');
}
result = result.Remove(result.Length - 1, 1);
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetParseCommandText");
+ Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
+
String parseCommand = text;
if (type == CommandType.StoredProcedure)
+ {
+ // Check if just procedure name was passed. If so, does not replace parameter names and just pass parameter values in order they were added in parameters collection.
+ if (!parseCommand.Trim().EndsWith(")"))
+ {
+ addProcedureParenthesis = true;
+ parseCommand += "(";
+ }
+
parseCommand = "select * from " + parseCommand; // This syntax is only available in 7.3+ as well SupportsPrepare.
+ }
else if (type == CommandType.TableDirect)
return "select * from " + parseCommand; // There is no parameter support on TableDirect.
for (i = 0; i < parameters.Count; i++)
{
- //result = result.Replace(":" + parameterName, parameters[i].Value.ToString());
- parameterName = parameters[i].ParameterName;
- //textCommand = textCommand.Replace(':' + parameterName, "$" + (i+1));
- parseCommand = ReplaceParameterValue(parseCommand, parameterName, "$" + (i+1));
+ if ((parameters[i].Direction == ParameterDirection.Input) ||
+ (parameters[i].Direction == ParameterDirection.InputOutput))
+ {
+
+ if (!addProcedureParenthesis)
+ {
+ //result = result.Replace(":" + parameterName, parameters[i].Value.ToString());
+ parameterName = parameters[i].ParameterName;
+ //textCommand = textCommand.Replace(':' + parameterName, "$" + (i+1));
+ parseCommand = ReplaceParameterValue(parseCommand, parameterName, "$" + (i+1) + "::" + parameters[i].TypeInfo.Name);
+ }
+ else
+ parseCommand += "$" + (i+1) + "::" + parameters[i].TypeInfo.Name;
+ }
}
}
- return parseCommand;
+ if (addProcedureParenthesis)
+ return parseCommand + ")";
+ else
+ return parseCommand;
}
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetPrepareCommandText");
+ Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
-
- planName = "NpgsqlPlan" + System.Threading.Interlocked.Increment(ref planIndex);
+ planName = Connector.NextPlanName();
StringBuilder command = new StringBuilder("prepare " + planName);
String textCommand = text;
if (type == CommandType.StoredProcedure)
+ {
+ // Check if just procedure name was passed. If so, does not replace parameter names and just pass parameter values in order they were added in parameters collection.
+ if (!textCommand.Trim().EndsWith(")"))
+ {
+ addProcedureParenthesis = true;
+ textCommand += "(";
+ }
+
textCommand = "select * from " + textCommand;
+ }
else if (type == CommandType.TableDirect)
return "select * from " + textCommand; // There is no parameter support on TableDirect.
for (i = 0; i < parameters.Count; i++)
{
- //result = result.Replace(":" + parameterName, parameters[i].Value.ToString());
- parameterName = parameters[i].ParameterName;
- // The space in front of '$' fixes a parsing problem in 7.3 server
- // which gives errors of operator when finding the caracters '=$' in
- // prepare text
- textCommand = ReplaceParameterValue(textCommand, parameterName, " $" + (i+1));
+ if ((parameters[i].Direction == ParameterDirection.Input) ||
+ (parameters[i].Direction == ParameterDirection.InputOutput))
+ {
+
+ if (!addProcedureParenthesis)
+ {
+ //result = result.Replace(":" + parameterName, parameters[i].Value.ToString());
+ parameterName = parameters[i].ParameterName;
+ // The space in front of '$' fixes a parsing problem in 7.3 server
+ // which gives errors of operator when finding the caracters '=$' in
+ // prepare text
+ textCommand = ReplaceParameterValue(textCommand, parameterName, " $" + (i+1));
+ }
+ else
+ textCommand += " $" + (i+1);
+ }
}
for (i = 0; i < parameters.Count; i++)
{
- command.Append(NpgsqlTypesHelper.GetBackendTypeNameFromDbType(parameters[i].DbType));
+ // command.Append(NpgsqlTypesHelper.GetDefaultTypeInfo(parameters[i].DbType));
+ command.Append(parameters[i].TypeInfo.Name);
command.Append(',');
}
command.Append(')');
}
+
+ if (addProcedureParenthesis)
+ textCommand += ")";
command.Append(" as ");
command.Append(textCommand);
Int32 paramEnd = paramStart + paramLen;
Boolean found = false;
+
while(paramStart > -1)
{
if((resLen > paramEnd) &&
(result[paramEnd] == ' ' ||
result[paramEnd] == ',' ||
result[paramEnd] == ')' ||
- result[paramEnd] == ';'))
+ result[paramEnd] == ';' ||
+ result[paramEnd] == '\n' ||
+ result[paramEnd] == '\r' ||
+ result[paramEnd] == '\t'))
{
result = result.Substring(0, paramStart) + paramVal + result.Substring(paramEnd);
found = true;
if(!found)
throw new IndexOutOfRangeException (String.Format(resman.GetString("Exception_ParamNotInQuery"), parameterName));
+
return result;
}//ReplaceParameterValue
+
+
+ private String AddSingleRowBehaviorSupport(String ResultCommandText)
+ {
+
+ ResultCommandText = ResultCommandText.Trim();
+
+ if ((commandBehavior & CommandBehavior.SingleRow) > 0)
+ {
+ if (ResultCommandText.EndsWith(";"))
+ ResultCommandText = ResultCommandText.Substring(0, ResultCommandText.Length - 1);
+ ResultCommandText += " limit 1;";
+
+ }
+
+
+
+ return ResultCommandText;
+
+ }
private void ExecuteCommand()
// Check the connection state first.
CheckConnectionState();
- if (parse == null) {
- connection.Query(this);
+ // reset any responses just before getting new ones
+ connector.Mediator.ResetResponses();
- // Check for errors and/or notifications and do the Right Thing.
- connection.CheckErrorsAndNotifications();
- } else {
- BindParameters();
- // Check for errors and/or notifications and do the Right Thing.
- connection.CheckErrorsAndNotifications();
-
- connection.Execute(new NpgsqlExecute(bind.PortalName, 0));
+ if (parse == null)
+ {
+ Connector.Query(this);
// Check for errors and/or notifications and do the Right Thing.
- connection.CheckErrorsAndNotifications();
+ connector.CheckErrorsAndNotifications();
}
- /* else
- throw new NotImplementedException(resman.GetString("Exception_CommandTypeTableDirect"));*/
- }
+ else
+ {
+ try
+ {
+ BindParameters();
- }
+ connector.Execute(new NpgsqlExecute(bind.PortalName, 0));
+
+ // Check for errors and/or notifications and do the Right Thing.
+ connector.CheckErrorsAndNotifications();
+ }
+ finally
+ {
+ // As per documentation:
+ // "[...] When an error is detected while processing any extended-query message,
+ // the backend issues ErrorResponse, then reads and discards messages until a
+ // Sync is reached, then issues ReadyForQuery and returns to normal message processing.[...]"
+ // So, send a sync command if we get any problems.
+ connector.Sync();
+ }
+ }
+ }
+ }
}