* Npgsql/NpgsqlDataAdapter.cs: Changed RowUpdated and RowUpdating prefix to Npgsql.
* Npgsql/NpgsqlClosedState.cs: Removed dependency in TlsException. Carlos Guzman will change this excpetion to internal.
* Npgsql/NpgsqlCommand.cs * Npgsql/NpgsqlCommand.resx * Npgsql/NpgsqlConnection.cs * Npgsql/NpgsqlConnection.resx * Npgsql/NpgsqlDataAdapter.cs * Npgsql/NpgsqlError.cs * Npgsql/NpgsqlException.cs * Npgsql/NpgsqlException.resx * Npgsql/NpgsqlMediator.cs * Npgsql/NpgsqlState.cs * Npgsql/NpgsqlState.resx * Npgsql/PGUtil.cs : Added initial error handling code improvements. Thanks Glen Parker (glenebob@nwlink.com) for the patch. NpgsqlException now gives aceess to error collection through the Errors property. This property return a collection of NpgsqlErrors objects. Also it gives access to error message, hint, severity and code. This fixes the feature request 689 in gborg.
svn path=/trunk/mcs/; revision=25786
+2004-04-21 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
+ * Npgsql/NpgsqlDataAdapter.cs: Changed RowUpdated and RowUpdating prefix to Npgsql.
+ * Npgsql/NpgsqlClosedState.cs: Removed dependency in TlsException. Carlos Guzman will change this excpetion to internal.
+
+ * Npgsql/NpgsqlCommand.cs
+ * Npgsql/NpgsqlCommand.resx
+ * Npgsql/NpgsqlConnection.cs
+ * Npgsql/NpgsqlConnection.resx
+ * Npgsql/NpgsqlDataAdapter.cs
+ * Npgsql/NpgsqlError.cs
+ * Npgsql/NpgsqlException.cs
+ * Npgsql/NpgsqlException.resx
+ * Npgsql/NpgsqlMediator.cs
+ * Npgsql/NpgsqlState.cs
+ * Npgsql/NpgsqlState.resx
+ * Npgsql/PGUtil.cs : Added initial error handling code improvements. Thanks Glen Parker (glenebob@nwlink.com) for the patch. NpgsqlException now gives aceess to error collection through the Errors property. This property return a collection of NpgsqlErrors objects. Also it gives access to error message, hint, severity and code. This fixes the feature request 689 in gborg.
+
+
+
2004-04-09 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
* Npgsql/NpgsqlDataAdapter.cs: Fixed DataAdapter to raise the RowUpdating and RowUpdated events. This also fixes some issues in gborg 710 bug. This modification may have broken CommandBuilder support. Working on that.
// We only need to do this for version 2 protocol.
private static Boolean IsBackendNull(Byte[] null_map_array, Int32 index)
{
-
+
// Get the byte that holds the bit index position.
Byte test_byte = null_map_array[index/8];
if ((index < 0) || (index >= row_desc.NumFields))
throw new ArgumentOutOfRangeException("this[] index value");
-
+
return data[index];
if (IsBackendNull(null_map_array, field_count))
{
// Field is null just keep next field.
-
+
data.Add(DBNull.Value);
continue;
}
return _instance;
}
}
-
-
+
+
public override void Open(NpgsqlConnection context)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
- try
+ TcpClient tcpc = new TcpClient(context.ServerName, Int32.Parse(context.ServerPort));
+ Stream stream = tcpc.GetStream();
+ // If the PostgreSQL server has SSL connections enabled Open SslClientStream if (response == 'S') {
+ if (context.SSL == "yes")
{
-
- TcpClient tcpc = new TcpClient(context.ServerName, Int32.Parse(context.ServerPort));
- Stream stream = tcpc.GetStream();
- // If the PostgreSQL server has SSL connections enabled Open SslClientStream if (response == 'S') {
- if (context.SSL == "yes")
+ PGUtil.WriteInt32(stream, 8);
+ PGUtil.WriteInt32(stream,80877103);
+ // Receive response
+ Char response = (Char)stream.ReadByte();
+ if (response == 'S')
{
- PGUtil.WriteInt32(stream, 8);
- PGUtil.WriteInt32(stream,80877103);
- // Receive response
- Char response = (Char)stream.ReadByte();
- if (response == 'S')
- {
- stream = new SslClientStream(tcpc.GetStream(), context.ServerName, true, Mono.Security.Protocol.Tls.SecurityProtocolType.Default);
- /*stream = new SslClientStream(
- tcpc.GetStream(),
- context.ServerName,
- true,
- Tls.SecurityProtocolType.Tls|
- Tls.SecurityProtocolType.Ssl3);*/
-
-
- ((SslClientStream)stream).ServerCertValidationDelegate = context.CertificateValidationCallback;
- ((SslClientStream)stream).ClientCertSelectionDelegate = context.CertificateSelectionCallback;
- ((SslClientStream)stream).PrivateKeyCertSelectionDelegate = context.PrivateKeySelectionCallback;
-
- }
+ stream = new SslClientStream(tcpc.GetStream(),
+ context.ServerName,
+ true,
+ Mono.Security.Protocol.Tls.SecurityProtocolType.Default);
+ /*stream = new SslClientStream(
+ tcpc.GetStream(),
+ context.ServerName,
+ true,
+ Tls.SecurityProtocolType.Tls|
+ Tls.SecurityProtocolType.Ssl3);*/
+
+
+ ((SslClientStream)stream).ServerCertValidationDelegate = context.CertificateValidationCallback;
+ ((SslClientStream)stream).ClientCertSelectionDelegate = context.CertificateSelectionCallback;
+ ((SslClientStream)stream).PrivateKeyCertSelectionDelegate = context.PrivateKeySelectionCallback;
+
}
-
-
+ }
- context.Connector.Stream = stream;
- }
- catch (TlsException e)
- {
- throw new NpgsqlException(e.ToString());
- }
+ context.Connector.Stream = stream;
+
NpgsqlEventLog.LogMsg(resman, "Log_ConnectedTo", LogLevel.Normal, context.ServerName, context.ServerPort);
ChangeState(context, NpgsqlConnectedState.Instance);
// Check if there were any errors.
if (connection.Mediator.Errors.Count > 0)
- {
- StringWriter sw = new StringWriter();
- sw.WriteLine(String.Format(resman.GetString("Exception_MediatorErrors"), "ExecuteNonQuery"));
- uint i = 1;
- foreach(string error in connection.Mediator.Errors)
- {
- sw.WriteLine("{0}. {1}", i++, error);
- }
- throw new NpgsqlException(sw.ToString());
- }
+ throw new NpgsqlException(resman.GetString("Exception_BackendErrors"), connection.Mediator.Errors);
+
CheckNotification();
if(connection.Mediator.GetCompletedResponses().Count == 0)
return -1;
-
+
// Check if the response is available.
String firstCompletedResponse = (String)connection.Mediator.GetCompletedResponses()[0];
-
+
if (firstCompletedResponse == null)
return -1;
-
+
String[] ret_string_tokens = firstCompletedResponse.Split(null); // whitespace separator.
// Only theses commands return rows affected.
// [FIXME] Is there a better way to check this??
if ((String.Compare(ret_string_tokens[0], "INSERT", true) == 0) ||
- (String.Compare(ret_string_tokens[0], "UPDATE", true) == 0) ||
- (String.Compare(ret_string_tokens[0], "DELETE", true) == 0))
+ (String.Compare(ret_string_tokens[0], "UPDATE", true) == 0) ||
+ (String.Compare(ret_string_tokens[0], "DELETE", true) == 0))
// The number of rows affected is in the third token for insert queries
// and in the second token for update and delete queries.
// Check if there were any errors.
if (connection.Mediator.Errors.Count > 0)
- {
- StringWriter sw = new StringWriter();
- sw.WriteLine(String.Format(resman.GetString("Exception_MediatorErrors_1P"), "ExecuteReader", cb));
- uint i = 1;
- foreach(string error in connection.Mediator.Errors)
- {
- sw.WriteLine("{0}. {1}", i++, error);
- }
- throw new NpgsqlException(sw.ToString());
- }
+ throw new NpgsqlException(resman.GetString("Exception_BackendErrors"), connection.Mediator.Errors);
+
CheckNotification();
-
+
// Get the resultsets and create a Datareader with them.
return new NpgsqlDataReader(connection.Mediator.GetResultSets(), connection.Mediator.GetCompletedResponses(), connection, cb);
}
// Check if there were any errors.
// [FIXME] Just check the first error.
if (connection.Mediator.Errors.Count > 0)
- {
- StringWriter sw = new StringWriter();
- sw.WriteLine(String.Format(resman.GetString("Exception_MediatorErrors"), "ExecuteScalar"));
- uint i = 1;
- foreach(string error in connection.Mediator.Errors)
- {
- sw.WriteLine("{0}. {1}", i++, error);
- }
- throw new NpgsqlException(sw.ToString());
- }
+ throw new NpgsqlException(resman.GetString("Exception_BackendErrors"), connection.Mediator.Errors);
+
+
CheckNotification();
// First data is the RowDescription object.
// Check all resultsets as insert commands could have been sent along
// with resultset queries. The insert commands return null and and some queries
- // may return empty resultsets, so, if we find one of these, skip to next resultset.
+ // may return empty resultsets, so, if we find one of these, skip to next resultset.
// If no resultset is found, return null as per specification.
-
+
NpgsqlAsciiRow ascii_row = null;
foreach( NpgsqlResultSet nrs in resultSets )
{
return ascii_row[0];
}
}
-
-
+
+
return null;
<data name="Exception_CommandTypeTableDirect">
<value>Only Text and StoredProcedure types supported!</value>
</data>
+ <data name="Exception_BackendErrors">
+ <value>There have been errors reported by the backend.</value>
+ </data>
<data name="Exception_MediatorErrors">
<value>There have been errors on {0}():</value>
</data>
/// </summary>
public event NotificationEventHandler Notification;
-
+
// Public properties for ssl callbacks
public CertificateValidationCallback CertificateValidationCallback;
public CertificateSelectionCallback CertificateSelectionCallback;
public PrivateKeySelectionCallback PrivateKeySelectionCallback;
-
-
-
+
+
+
private NpgsqlState state;
private ConnectionState connection_state;
// These are for ODBC connection string compatibility
internal readonly String ODBC_USERID = "UID";
internal readonly String ODBC_PASSWORD = "PWD";
-
+
// These are for the connection pool
internal readonly String MIN_POOL_SIZE = "MINPOOLSIZE";
internal readonly String MAX_POOL_SIZE = "MAXPOOLSIZE";
-
+
internal readonly String CONN_ENCODING = "ENCODING";
-
+
internal readonly String CONN_TIMEOUT = "TIMEOUT";
-
+
// Values for possible CancelRequest messages.
private NpgsqlBackEndKeyData backend_keydata;
private readonly String CLASSNAME = "NpgsqlConnection";
private Stream stream;
-
+
private Connector _connector;
-
+
private Encoding connection_encoding;
private Boolean _supportsPrepare = false;
private System.Resources.ResourceManager resman;
private Int32 _backendProtocolVersion;
-
+
private Int32 _connectionTimeout;
_mediator = new NpgsqlMediator();
_oidToNameMapping = new Hashtable();
-
+
_connectionTimeout = 15;
-
+
CertificateValidationCallback = new CertificateValidationCallback(DefaultCertificateValidationCallback);
-
+
if (connection_string != String.Empty)
ParseConnectionString();
}
-
+
/// <summary>
/// Gets or sets the string used to open a SQL Server database.
/// </summary>
if (connection_string_values[CONN_ENCODING] == null)
connection_string_values[CONN_ENCODING] = "SQL_ASCII";
if (connection_string_values[CONN_TIMEOUT] == null)
- connection_string_values[CONN_TIMEOUT] = "15";
-
+ connection_string_values[CONN_TIMEOUT] = "15";
+
try
{
-
+
// Check if the connection is already open.
if (connection_state == ConnectionState.Open)
throw new NpgsqlException(resman.GetString("Exception_ConnOpen"));
lock(ConnectorPool.ConnectorPoolMgr)
{
- Connector = ConnectorPool.ConnectorPoolMgr.RequestConnector(ConnectionString,
- Int32.Parse((String)connection_string_values[MAX_POOL_SIZE]),
- Int32.Parse((String)connection_string_values[CONN_TIMEOUT]),
- false);
+ Connector = ConnectorPool.ConnectorPoolMgr.RequestConnector(ConnectionString,
+ Int32.Parse((String)connection_string_values[MAX_POOL_SIZE]),
+ Int32.Parse((String)connection_string_values[CONN_TIMEOUT]),
+ false);
Connector.InUse = true;
}
-
+
if (!Connector.IsInitialized)
{
-
+
// Reset state to initialize new connector in pool.
CurrentState = NpgsqlClosedState.Instance;
// Try first connect using the 3.0 protocol...
CurrentState.Open(this);
-
+
// Change the state of connection to open.
connection_state = ConnectionState.Open;
-
+
// Check if there were any errors.
if (_mediator.Errors.Count > 0)
{
// As the message can be localized, just check the initial unlocalized part of the
// message. If it is an error other than protocol error, when connecting using
// version 2.0 we shall catch the error again.
- if (((String)_mediator.Errors[0]).StartsWith("FATAL"))
+ if (((NpgsqlError)_mediator.Errors[0]).Message.StartsWith("FATAL"))
{
// Try using the 2.0 protocol.
_mediator.Reset();
BackendProtocolVersion = ProtocolVersion.Version2;
CurrentState.Open(this);
}
-
+
// Keep checking for errors...
if(_mediator.Errors.Count > 0)
- {
- StringWriter sw = new StringWriter();
- sw.WriteLine(resman.GetString("Exception_OpenError"));
- uint i = 1;
- foreach(string error in _mediator.Errors)
- {
- sw.WriteLine("{0}. {1}", i++, error);
- }
- CurrentState = NpgsqlClosedState.Instance;
- _mediator.Reset();
- throw new NpgsqlException(sw.ToString());
- }
+ throw new NpgsqlException(resman.GetString("Exception_BackendErrors"), _mediator.Errors);
+
}
-
+
backend_keydata = _mediator.GetBackEndKeyData();
// Get version information to enable/disable server version features.
NpgsqlCommand command = new NpgsqlCommand("select version();set DATESTYLE TO ISO;", this);
_serverVersion = (String) command.ExecuteScalar();
}
-
- // Adjust client encoding.
-
+
+ // Adjust client encoding.
+
//NpgsqlCommand commandEncoding = new NpgsqlCommand("show client_encoding", this);
//String clientEncoding = (String)commandEncoding.ExecuteScalar();
-
+
if (connection_string_values[CONN_ENCODING].Equals("UNICODE"))
connection_encoding = Encoding.UTF8;
-
-
+
+
Connector.ServerVersion = ServerVersion;
Connector.BackendProtocolVersion = BackendProtocolVersion;
Connector.Encoding = connection_encoding;
-
+
}
-
- // Connector was obtained from pool.
+
+ // Connector was obtained from pool.
// Do a mini initialization in the state machine.
-
+
connection_state = ConnectionState.Open;
ServerVersion = Connector.ServerVersion;
BackendProtocolVersion = Connector.BackendProtocolVersion;
Encoding = Connector.Encoding;
-
+
CurrentState = NpgsqlReadyState.Instance;
-
+
ProcessServerVersion();
_oidToNameMapping = NpgsqlTypesHelper.LoadTypesMapping(this);
-
-
-
+
+
+
}
public void Close()
{
Dispose(true);
-
+
}
/// <summary>
{
if (disposing)
{
- // Only if explicitly calling Close or dispose we still have access to
+ // Only if explicitly calling Close or dispose we still have access to
// managed resources.
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose", disposing);
{
CurrentState.Close(this);
}
-
+
}
catch (IOException e)
{
stream.Close();*/
connection_state = ConnectionState.Closed;
}
-
+
}
base.Dispose (disposing);
}
-
-
+
+
public Object Clone()
{
return new NpgsqlConnection(ConnectionString);
// 3.0+ version is set by ParameterStatus message.
// On protocol 3.0, 7.4 and above support it.
SupportsPrepare = (_serverVersion.IndexOf("7.4") != -1)
- || (_serverVersion.IndexOf("7.5") != -1);
+ || (_serverVersion.IndexOf("7.5") != -1);
}
}
stream = value;
}
}
-
+
internal Connector Connector
{
get
{
CurrentState.Execute(this, execute);
}
-
-
+
+
// Default SSL Callbacks implementation.
private Boolean DefaultCertificateValidationCallback(
- X509Certificate certificate,
- int[] certificateErrors)
+ X509Certificate certificate,
+ int[] certificateErrors)
{
return true;
}
-
-
+
+
internal NpgsqlState CurrentState {
get
{
return connection_encoding;
}
-
+
set
{
connection_encoding = value;
_backendProtocolVersion = value;
}
}
-
+
internal Int32 MinPoolSize {
get
{
return Int32.Parse((String)connection_string_values[MIN_POOL_SIZE]);
}
}
-
+
internal Int32 MaxPoolSize {
get
{
<data name="Exception_ChangeDatabaseOnOpenConn">
<value>The connection is not open. Use 'Database=X;' in the connection string to set the database for a closed connection.</value>
</data>
-</root>
\ No newline at end of file
+ <data name="Exception_BackendErrors">
+ <value>There have been errors reported by the backend.</value>
+ </data>
+</root>
/// <summary>
/// !!! Helper class, for compilation only.
/// </summary>
-
+
/// <summary>
/// Connector implements the logic for the Connection Objects to
/// access the physical connection to the database, and isolate
private Stream _stream;
-
+
// This is information about the connection
// this connector is holding. For while only the server version is used.
// Change later for a more generic way to keep it. (Hashtable)
private String _serverVersion;
-
+
private Int32 _backendProtocolVersion;
-
+
private Encoding _encoding;
-
-
+
+
private Boolean _isInitialized;
-
+
private Boolean mPooled;
private Boolean mOpen;
this.mPooled = value;
}
}
-
+
internal String ServerVersion
{
get
{
return _serverVersion;
}
-
+
set
{
_serverVersion = value;
}
}
-
+
internal Encoding Encoding
{
get
{
return _encoding;
}
-
+
set
{
_encoding = value;
}
}
-
+
internal Int32 BackendProtocolVersion
{
get
{
return _backendProtocolVersion;
}
-
+
set
{
_backendProtocolVersion = value;
}
}
-
+
internal Stream Stream {
get
{
_isInitialized = true;
}
}
-
+
internal Boolean IsInitialized
{
get
{
return _isInitialized;
}
-
+
}
-
+
/// <value>Buffer for the public Shared property</value>
private bool mShared;
// !!! to be fixed
//private Npgsql.Socket Socket;
-
+
/// <summary>
/// Default constructor. Creates a pooled Connector by default.
/// </summary>
//this.Socket.Open(); // !!! to be fixed
//this.mOpen = true;
}
-
-
+
+
internal Boolean InUse {
get
{
{
_inUse = value;
}
-
+
}
/// <summary>
/// <value>Unique static instance of the connector pool
/// mamager.</value>
internal static ConnectorPool ConnectorPoolMgr = new Npgsql.ConnectorPool();
-
+
public ConnectorPool()
{
PooledConnectors = new Hashtable();
}
-
+
/// <value>Map of index to unused pooled connectors, avaliable to the
/// next RequestConnector() call.</value>
// point the list to the new head
this.PooledConnectors = Connector;
}*/
-
-
+
+
internal Int32 GetPoolSize(String connectionString)
{
ArrayList pool = (ArrayList)PooledConnectors[connectionString];
return 0;
else
return pool.Count;
-
-
+
+
}
/// <summary>
/// on a single connector. </param>
/// <returns>A pooled connector object.</returns>
internal Npgsql.Connector RequestConnector (String connectionString,
- Int32 maxPoolSize,
- Int32 timeout,
- Boolean shared )
+ Int32 maxPoolSize,
+ Int32 timeout,
+ Boolean shared )
{
Connector connector;
ArrayList connectorPool = null;
return Connector;
}
}*/
-
+
return null;
}
else
// if a shared connector could not be found or a
// nonshared connector is requested, then the pooled
// (unused) connectors are beeing searched.
-
-
+
+
connectorPool = (ArrayList)PooledConnectors[connectionString];
-
+
if (connectorPool == null)
{
connectorPool = new ArrayList();
PooledConnectors[connectionString] = connectorPool;
}
-
-
+
+
// Now look for an available connector.
-
+
Connector freeConnector = FindFreeConnector(connectorPool);
if (freeConnector != null)
return freeConnector;
-
+
// No suitable connector could be found, so create new one
// if there is room available.
-
+
if (connectorPool.Count < maxPoolSize)
{
connector = new Npgsql.Connector(connectionString, shared);
connectorPool.Add(connector);
-
+
// and then returned to the caller
- return connector;
+ return connector;
}
else
{
// keep checking in the pool until some connector is available or
// a timeout occurs.
Int32 timeoutMilliseconds = timeout * 1000;
-
+
while (timeoutMilliseconds > 0)
{
Connector freeConnector2 = FindFreeConnector(connectorPool);
Thread.Sleep((timeoutMilliseconds > 900) ? 900 : timeoutMilliseconds);
timeoutMilliseconds -= 900;
}
-
+
throw new NpgsqlException("Timeout while getting a connection from pool.");
-
+
}
-
+
}
}
-
+
private Connector FindFreeConnector(ArrayList connectorPool)
{
foreach (Connector c in connectorPool)
if (!c.InUse)
return c;
}
-
+
return null;
}
}
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">A <see cref="Npgsql.NpgsqlRowUpdatedEventArgs">NpgsqlRowUpdatedEventArgs</see> that contains the event data.</param>
- public delegate void RowUpdatedEventHandler(Object sender, NpgsqlRowUpdatedEventArgs e);
-
+ public delegate void NpgsqlRowUpdatedEventHandler(Object sender, NpgsqlRowUpdatedEventArgs e);
+
/// <summary>
/// Represents the method that handles the <see cref="Npgsql.NpgsqlDataAdapter.RowUpdating">RowUpdating</see> events.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">A <see cref="Npgsql.NpgsqlRowUpdatingEventArgs">NpgsqlRowUpdatingEventArgs</see> that contains the event data.</param>
- public delegate void RowUpdatingEventHandler(Object sender, NpgsqlRowUpdatingEventArgs e);
-
-
+ public delegate void NpgsqlRowUpdatingEventHandler(Object sender, NpgsqlRowUpdatingEventArgs e);
+
+
public sealed class NpgsqlDataAdapter : DbDataAdapter, IDbDataAdapter
{
// Log support
private static readonly String CLASSNAME = "NpgsqlDataAdapter";
-
-
- public event RowUpdatedEventHandler RowUpdated;
- public event RowUpdatingEventHandler RowUpdating;
+
+
+ public event NpgsqlRowUpdatedEventHandler RowUpdated;
+ public event NpgsqlRowUpdatingEventHandler RowUpdating;
public NpgsqlDataAdapter()
{}
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "OnRowUpdating");
if ((RowUpdating != null) && (value is NpgsqlRowUpdatingEventArgs))
RowUpdating(this, (NpgsqlRowUpdatingEventArgs) value);
-
+
/*switch (value.StatementType)
{
case StatementType.Insert:
parameter.Value = value.Row [dsColumnName, rowVersion];
}
value.Row.AcceptChanges ();*/
-
+
}
ITableMappingCollection IDataAdapter.TableMappings
DataTableMapping tableMapping
) : base(dataRow, command, statementType, tableMapping)
- {
- }
+ {}
}
DataTableMapping tableMapping
) : base(dataRow, command, statementType, tableMapping)
- {
- }
+ {}
}
private DataTable _currentResultsetSchema;
private CommandBehavior _behavior;
private Boolean _isClosed;
-
+
// Logging related values
_connection = connection;
_rowIndex = -1;
_resultsetIndex = 0;
-
+
if (_resultsets.Count > 0)
_currentResultset = (NpgsqlResultSet)_resultsets[_resultsetIndex];
-
+
_behavior = behavior;
_isClosed = false;
//NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CanRead");
/*if (_currentResultset == null)
return false;*/
- return ((_currentResultset != null) &&
- (_currentResultset.Count > 0) &&
+ return ((_currentResultset != null) &&
+ (_currentResultset.Count > 0) &&
(_rowIndex < _currentResultset.Count));
}
{
Dispose(true);
}
-
+
/// <summary>
/// Releases the resources used by the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
/// </summary>
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "RecordsAffected");
-
+
if (CanRead())
return -1;
public void Close()
{
- if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
+ if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
{
_connection.Close();
_isClosed = true;
public Boolean NextResult()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "NextResult");
-
+
if((_resultsetIndex + 1) < _resultsets.Count)
{
_resultsetIndex++;
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Read");
_rowIndex++;
-
+
if (!CanRead())
return false;
else
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "FieldCount");
-
+
if (_currentResultset == null) //Executed a non return rows query.
return -1;
else
public Single GetFloat(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFloat");
-
+
return (Single) GetValue(i);
}
public Double GetDouble(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDouble");
-
+
return (Double) GetValue(i);
}
{
/// <summary>
- /// This class represents the ErrorResponse message sent from PostgreSQL
- /// server.
+ /// This class represents the ErrorResponse and NoticeResponse
+ /// message sent from PostgreSQL server.
/// </summary>
///
- internal sealed class NpgsqlError
+ public sealed class NpgsqlError
{
// Logging related values
private static readonly String CLASSNAME = "NpgsqlError";
- private Int32 _protocolVersion;
- private String _severity;
- private String _code;
- private String _message;
+ private Int32 protocol_version;
+ private String _severity = "";
+ private String _code = "";
+ private String _message = "";
private String _detail;
- private String _hint;
+ private String _hint = "";
private String _position;
private String _where;
private String _file;
private String _line;
private String _routine;
+ public String Severity
+ {
+ get
+ {
+ return _severity;
+ }
+ }
+ public String Code
+ {
+ get
+ {
+ return _code;
+ }
+ }
public String Message
{
}
}
+ public String Hint
+ {
+ get
+ {
+ return _hint;
+ }
+ }
+
+ private NpgsqlError()
+ {}
- public NpgsqlError(Int32 protocolVersion)
+ internal NpgsqlError(Int32 protocolVersion)
{
- _protocolVersion = protocolVersion;
+ protocol_version = protocolVersion;
}
- public void ReadFromStream(Stream inputStream, Encoding encoding)
+ internal void ReadFromStream(Stream inputStream, Encoding encoding)
{
-
- if (_protocolVersion == ProtocolVersion.Version2)
+ if (protocol_version == ProtocolVersion.Version2)
{
- _message = PGUtil.ReadString(inputStream, encoding);
+ ReadFromStream_Ver_2(inputStream, encoding);
+ }
+ else
+ {
+ ReadFromStream_Ver_3(inputStream, encoding);
+ }
+ }
+
+ private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
+ {
+ String Raw;
+ String[] Parts;
+
+ Raw = PGUtil.ReadString(inputStream, encoding);
+
+ Parts = Raw.Split(new char[] {':'}, 2);
+ if (Parts.Length == 2)
+ {
+ _severity = Parts[0];
+ _message = Parts[1].Trim();
}
else
{
- Int32 messageLength = PGUtil.ReadInt32(inputStream, new Byte[4]);
+ _message = Parts[0];
+ }
+ }
- //[TODO] Would this be the right way to do?
- // Check the messageLength value. If it is 1178686529, this would be the
- // "FATA" string, which would mean a protocol 2.0 error string.
+ private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
+ {
+ Int32 messageLength = PGUtil.ReadInt32(inputStream, new Byte[4]);
- if (messageLength == 1178686529)
- {
- _message = "FATA" + PGUtil.ReadString(inputStream, encoding);
- return;
- }
+ //[TODO] Would this be the right way to do?
+ // Check the messageLength value. If it is 1178686529, this would be the
+ // "FATA" string, which would mean a protocol 2.0 error string.
+ if (messageLength == 1178686529)
+ {
+ _severity = "FATAL";
+ _message = "FATA" + PGUtil.ReadString(inputStream, encoding);
+ return;
+ }
- Char field;
- String fieldValue;
+ Char field;
+ String fieldValue;
- field = (Char) inputStream.ReadByte();
+ field = (Char) inputStream.ReadByte();
- // Now start to read fields.
- while (field != 0)
- {
+ // Now start to read fields.
+ while (field != 0)
+ {
+ fieldValue = PGUtil.ReadString(inputStream, encoding);
- fieldValue = PGUtil.ReadString(inputStream, encoding);
-
- switch (field)
- {
- case 'S':
- _severity = fieldValue;
- break;
- case 'C':
- _code = fieldValue;
- break;
- case 'M':
- _message = fieldValue;
- break;
- case 'D':
- _detail = fieldValue;
- break;
- case 'H':
- _hint = fieldValue;
- break;
- case 'P':
- _position = fieldValue;
- break;
- case 'W':
- _where = fieldValue;
- break;
- case 'F':
- _file = fieldValue;
- break;
- case 'L':
- _line = fieldValue;
- break;
- case 'R':
- _routine = fieldValue;
- break;
-
- }
-
- field = (Char) inputStream.ReadByte();
+ switch (field)
+ {
+ case 'S':
+ _severity = fieldValue;
+ break;
+ case 'C':
+ _code = fieldValue;
+ break;
+ case 'M':
+ _message = fieldValue;
+ break;
+ case 'D':
+ _detail = fieldValue;
+ break;
+ case 'H':
+ _hint = fieldValue;
+ break;
+ case 'P':
+ _position = fieldValue;
+ break;
+ case 'W':
+ _where = fieldValue;
+ break;
+ case 'F':
+ _file = fieldValue;
+ break;
+ case 'L':
+ _line = fieldValue;
+ break;
+ case 'R':
+ _routine = fieldValue;
+ break;
}
- // Read 0 byte terminator.
- //inputStream.ReadByte();
- }
+ field = (Char) inputStream.ReadByte();
+ }
}
}
}
{
Console.WriteLine(message);
}
-
+
if (logfile != null)
{
if (logfile != "")
using System;
using System.Resources;
+using System.IO;
+using System.Text;
+using System.Collections;
namespace Npgsql
{
[Serializable]
public class NpgsqlException : Exception
{
+ private IList errors;
+
// Logging related values
private static readonly String CLASSNAME = "NpgsqlException";
{
NpgsqlEventLog.LogMsg(resman, "Log_ExceptionOccured", LogLevel.Normal, message + " (" + inner.Message + ")");
}
+
+ public NpgsqlException(String message, IList errors) : base(message)
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_ExceptionOccured", LogLevel.Normal, message);
+ this.errors = errors;
+ }
+
+ public String Severity
+ {
+ get
+ {
+ return (errors != null) ? ((NpgsqlError)errors[0]).Severity : String.Empty;
+ }
+ }
+
+ public String Code
+ {
+ get
+ {
+ return (errors != null) ? ((NpgsqlError)errors[0]).Code : String.Empty;
+ }
+ }
+
+ public override String Message
+ {
+ get
+ {
+ return (errors != null) ? ((NpgsqlError)errors[0]).Message : String.Empty;
+ }
+ }
+
+ public String Hint
+ {
+ get
+ {
+ return (errors != null) ? ((NpgsqlError)errors[0]).Hint : String.Empty;
+ }
+ }
+
+ public IList Errors
+ {
+ get
+ {
+ return errors;
+ }
+
+ }
+
+ public override String ToString()
+ {
+ return String.Format(base.Message + "Severity: {0} \nCode: {1} \nMessage: {2} \nHint: {3}", Severity, Code, Message, Hint);
+ }
+
}
+
+
+
}
<data name="Log_ExceptionOccured">
<value>An NpgsqlException occured: {0}.</value>
</data>
+ <data name="Log_BackendExceptionOccured">
+ <value>An NpgsqlBackendException occured: {0}.</value>
+ </data>
</root>
internal sealed class NpgsqlMediator
{
- private ArrayList _errorMessages;
+ private ArrayList _errors;
+ private ArrayList _notices;
private ArrayList _resultSets;
private ArrayList _responses;
private ArrayList _notifications;
public NpgsqlMediator()
{
- _errorMessages = new ArrayList();
+ _errors = new ArrayList();
+ _notices = new ArrayList();
_resultSets = new ArrayList();
_responses = new ArrayList();
_notifications = new ArrayList();
public void Reset()
{
- _errorMessages.Clear();
+ _errors.Clear();
+ _notices.Clear();
_resultSets.Clear();
_responses.Clear();
_notifications.Clear();
{
get
{
- return _errorMessages;
+ return _errors;
+ }
+ }
+
+ public ArrayList Notices
+ {
+ get
+ {
+ return _notices;
}
}
{
resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, parameterName, value);
-
-
+
+
this.value = value;
this.ParameterName = parameterName;
-
-
+
+
// Set db_type according to:
// http://msdn.microsoft.com/library/en-us/cpguide/html/cpconusingparameterswithdataadapters.asp
// Should this be in this.Value.set{}?
throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), type.ToString()));
}
-
+
}
public Int16 FieldIndex(String fieldName)
{
Int16 result = 0;
-
+
foreach (String name in fields_index)
{
-
+
if (name.Equals(fieldName))
{
return result;
}
result++;
}
-
- return -1;
-
+
+ return -1;
+
}
}
// Database name.
PGUtil.WriteString(database_name, output_stream, encoding);
-
+
// DateStyle.
PGUtil.WriteString("DateStyle", output_stream, encoding);
stream.Flush();
}
}*/
-
+
context.Connector.InUse = false;
context.Connector = null;
//ChangeState( context, NpgsqlClosedState.Instance );
///
protected virtual void ProcessBackendResponses( NpgsqlConnection context )
+ {
+ switch (context.BackendProtocolVersion)
+ {
+ case ProtocolVersion.Version2 :
+ ProcessBackendResponses_Ver_2(context);
+ break;
+
+ case ProtocolVersion.Version3 :
+ ProcessBackendResponses_Ver_3(context);
+ break;
+
+ }
+ }
+
+ protected virtual void ProcessBackendResponses_Ver_2( NpgsqlConnection context )
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");
{
case NpgsqlMessageTypes.ErrorResponse :
- NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
- error.ReadFromStream(stream, context.Encoding);
+ {
+ NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
+ error.ReadFromStream(stream, context.Encoding);
- //mediator.Errors.Add(errorMessage);
- mediator.Errors.Add(error.Message);
+ mediator.Errors.Add(error);
- NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
+ NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
+ }
// Return imediately if it is in the startup state or connected state as
// there is no more messages to consume.
stream.Read(inputBuffer, 0, 4);
- if (context.BackendProtocolVersion >= ProtocolVersion.Version3)
- stream.Read(inputBuffer, 0, 4);
-
authType = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 0));
if ( authType == NpgsqlMessageTypes.AuthenticationOk )
case NpgsqlMessageTypes.NoticeResponse :
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NoticeResponse");
- String noticeResponse = PGUtil.ReadString( stream, context.Encoding );
+ {
+ NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
+ notice.ReadFromStream(stream, context.Encoding);
+
+ mediator.Notices.Add(notice);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
+ }
// Wait for ReadForQuery message
break;
// Get the string returned.
- if (context.BackendProtocolVersion >= ProtocolVersion.Version3)
- PGUtil.ReadInt32(stream, new Byte[4]);
-
String result = PGUtil.ReadString(stream, context.Encoding);
NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, result);
}
}
- }
+
+ protected virtual void ProcessBackendResponses_Ver_3( NpgsqlConnection context )
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");
+
+ BufferedStream stream = new BufferedStream(context.Stream);
+ Int32 authType;
+ Boolean readyForQuery = false;
+
+ NpgsqlMediator mediator = context.Mediator;
+
+ // Reset the mediator.
+ mediator.Reset();
+
+ Int16 rowDescNumFields = 0;
+ NpgsqlRowDescription rd = null;
+ String Str; // for various strings
+ Byte[] Buff = new Byte[4]; // for various reads
+
+ Byte[] inputBuffer = new Byte[ 500 ];
+
+
+ while (!readyForQuery)
+ {
+ // Check the first Byte of response.
+ switch ( stream.ReadByte() )
+ {
+ case NpgsqlMessageTypes.ErrorResponse :
+
+ {
+ NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
+ error.ReadFromStream(stream, context.Encoding);
+
+ mediator.Errors.Add(error);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
+ }
+
+ // Return imediately if it is in the startup state or connected state as
+ // there is no more messages to consume.
+ // Possible error in the NpgsqlStartupState:
+ // Invalid password.
+ // Possible error in the NpgsqlConnectedState:
+ // No pg_hba.conf configured.
+
+ if ((context.CurrentState == NpgsqlStartupState.Instance) ||
+ (context.CurrentState == NpgsqlConnectedState.Instance))
+ return;
+
+ break;
+
+
+ case NpgsqlMessageTypes.AuthenticationRequest :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
+
+ stream.Read(inputBuffer, 0, 4);
+ stream.Read(inputBuffer, 0, 4);
+
+ authType = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 0));
+
+ if ( authType == NpgsqlMessageTypes.AuthenticationOk )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
+
+ break;
+ }
+
+ if ( authType == NpgsqlMessageTypes.AuthenticationClearTextPassword )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
+
+ // Send the PasswordPacket.
+
+ ChangeState( context, NpgsqlStartupState.Instance );
+ context.Authenticate(context.ServerPassword);
+
+ break;
+ }
+
+
+ if ( authType == NpgsqlMessageTypes.AuthenticationMD5Password )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
+ // Now do the "MD5-Thing"
+ // for this the Password has to be:
+ // 1. md5-hashed with the username as salt
+ // 2. md5-hashed again with the salt we get from the backend
+
+
+ MD5 md5 = MD5.Create();
+
+
+ // 1.
+ byte[] passwd = context.Encoding.GetBytes(context.ServerPassword);
+ byte[] saltUserName = context.Encoding.GetBytes(context.UserName);
+
+ byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];
+
+ passwd.CopyTo(crypt_buf, 0);
+ saltUserName.CopyTo(crypt_buf, passwd.Length);
+
+ StringBuilder sb = new StringBuilder ();
+ byte[] hashResult = md5.ComputeHash(crypt_buf);
+ foreach (byte b in hashResult)
+ sb.Append (b.ToString ("x2"));
+
+
+ String prehash = sb.ToString();
+
+ byte[] prehashbytes = context.Encoding.GetBytes(prehash);
+
+
+ byte[] saltServer = Buff;
+ stream.Read(saltServer, 0, 4);
+ // Send the PasswordPacket.
+ ChangeState( context, NpgsqlStartupState.Instance );
+
+
+ // 2.
+
+ crypt_buf = new byte[prehashbytes.Length + saltServer.Length];
+ prehashbytes.CopyTo(crypt_buf, 0);
+ saltServer.CopyTo(crypt_buf, prehashbytes.Length);
+
+ sb = new StringBuilder ("md5"); // This is needed as the backend expects md5 result starts with "md5"
+ hashResult = md5.ComputeHash(crypt_buf);
+ foreach (byte b in hashResult)
+ sb.Append (b.ToString ("x2"));
+
+ context.Authenticate(sb.ToString ());
+
+ break;
+ }
+
+ // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
+ mediator.Errors.Add(String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType));
+ return;
+
+ case NpgsqlMessageTypes.RowDescription:
+ // This is the RowDescription message.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
+ rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
+ rd.ReadFromStream(stream, context.Encoding);
+
+ // Initialize the array list which will contain the data from this rowdescription.
+ //rows = new ArrayList();
+
+ rowDescNumFields = rd.NumFields;
+ mediator.AddRowDescription(rd);
+
+
+ // Now wait for the AsciiRow messages.
+ break;
+
+ case NpgsqlMessageTypes.AsciiRow:
+
+ // This is the AsciiRow message.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");
+ NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(rd, context.OidToNameMapping, context.BackendProtocolVersion);
+ asciiRow.ReadFromStream(stream, context.Encoding);
+
+
+ // Add this row to the rows array.
+ //rows.Add(ascii_row);
+ mediator.AddAsciiRow(asciiRow);
+
+ // Now wait for CompletedResponse message.
+ break;
+
+ case NpgsqlMessageTypes.ReadyForQuery :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
+
+ // Possible status bytes returned:
+ // I = Idle (no transaction active).
+ // T = In transaction, ready for more.
+ // E = Error in transaction, queries will fail until transaction aborted.
+ // Just eat the status byte, we have no use for it at this time.
+ PGUtil.ReadInt32(stream, Buff);
+ PGUtil.ReadString(stream, context.Encoding, 1);
+
+ readyForQuery = true;
+ ChangeState( context, NpgsqlReadyState.Instance );
+
+ break;
+
+ case NpgsqlMessageTypes.BackendKeyData :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
+ // BackendKeyData message.
+ NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion);
+ backend_keydata.ReadFromStream(stream);
+ mediator.AddBackendKeydata(backend_keydata);
+
+
+ // Wait for ReadForQuery message
+ break;
+
+ case NpgsqlMessageTypes.NoticeResponse :
+
+ // Notices and errors are identical except that we
+ // just throw notices away completely ignored.
+ {
+ NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
+ notice.ReadFromStream(stream, context.Encoding);
+
+ mediator.Notices.Add(notice);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
+ }
+
+ // Wait for ReadForQuery message
+ break;
+
+ case NpgsqlMessageTypes.CompletedResponse :
+ // This is the CompletedResponse message.
+ // Get the string returned.
+
+ PGUtil.ReadInt32(stream, Buff);
+ Str = PGUtil.ReadString(stream, context.Encoding);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, Str);
+
+ // Add result from the processing.
+ mediator.AddCompletedResponse(Str);
+
+ break;
+
+ case NpgsqlMessageTypes.CursorResponse :
+ // This is the cursor response message.
+ // It is followed by a C NULL terminated string with the name of
+ // the cursor in a FETCH case or 'blank' otherwise.
+ // In this case it should be always 'blank'.
+ // [FIXME] Get another name for this function.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CursorResponse");
+
+ PGUtil.ReadString(stream, context.Encoding);
+ // Continue waiting for ReadyForQuery message.
+ break;
+
+ case NpgsqlMessageTypes.ParseComplete :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParseComplete");
+ // Just read up the message length.
+ PGUtil.ReadInt32(stream, Buff);
+ readyForQuery = true;
+ break;
+
+ case NpgsqlMessageTypes.BindComplete :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
+ // Just read up the message length.
+ PGUtil.ReadInt32(stream, Buff);
+ readyForQuery = true;
+ break;
+
+ case NpgsqlMessageTypes.EmptyQueryResponse :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
+ // This is the EmptyQueryResponse.
+ // [FIXME] Just ignore it this way?
+ // networkStream.Read(inputBuffer, 0, 1);
+ //GetStringFromNetStream(networkStream);
+ PGUtil.ReadInt32(stream, Buff);
+ break;
+
+ case NpgsqlMessageTypes.NotificationResponse :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");
+
+ // Eat the length
+ PGUtil.ReadInt32(stream, Buff);
+ {
+ Int32 PID = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(Buff, 0));
+ // Notification string
+ String notificationResponse = PGUtil.ReadString( stream, context.Encoding );
+ // Additional info, currently not implemented by PG (empty string always), eat it
+ PGUtil.ReadString( stream, context.Encoding );
+ mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));
+ }
+
+ // Wait for ReadForQuery message
+ break;
+
+ case NpgsqlMessageTypes.ParameterStatus :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
+ NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus();
+ parameterStatus.ReadFromStream(stream, context.Encoding);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter, parameterStatus.ParameterValue);
+ if (parameterStatus.Parameter == "server_version")
+ context.ServerVersion = parameterStatus.ParameterValue;
+ break;
+ }
+ }
+ }
+ }
}
<data name="Log_ErrorResponse">
<value>ErrorResponse message from Server: {0}.</value>
</data>
+ <data name="Log_NoticeResponse">
+ <value>NoticeResponse message from Server: {0}.</value>
+ </data>
<data name="Log_AuthenticationOk">
<value>AAuthenticationOK received.</value>
</data>
internal NpgsqlTransaction(NpgsqlConnection conn) : this(conn, IsolationLevel.ReadCommitted)
- {
- }
+ {}
internal NpgsqlTransaction(NpgsqlConnection conn, IsolationLevel isolation)
{
return string_read;
}
+ ///<summary>
+ /// This method gets a length terminated string from a network stream.
+ /// It returns the resultant string of bytes read.
+ /// This string is sent from backend.
+ /// </summary>
+
+ public static String ReadString(Stream network_stream, Encoding encoding, Int32 length)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadString");
+
+ // [FIXME] Is 512 enough?
+ Byte[] buffer = new Byte[512];
+ Byte b;
+ Int16 counter = 0;
+
+ while(counter < length)
+ {
+ // [FIXME] Is this cast always safe?
+ b = (Byte)network_stream.ReadByte();
+ buffer[counter] = b;
+ counter++;
+ }
+ String string_read = encoding.GetString(buffer, 0, counter);
+ NpgsqlEventLog.LogMsg(resman, "Log_StringRead", LogLevel.Debug, string_read);
+ return string_read;
+ }
+
///<summary>
/// This method writes a C NULL terminated string to the network stream.
/// It appends a NULL terminator to the end of the String.
}
-
+ [Test]
+ public void MultipleQueriesFirstResultsetEmpty()
+ {
+ _conn.Open();
+
+ NpgsqlCommand command = new NpgsqlCommand("insert into tablea(field_text) values ('a'); select count(*) from tablea;", _conn);
+
+ Object result = command.ExecuteScalar();
+
+
+ command.CommandText = "delete from tablea where field_serial > 5";
+ command.ExecuteNonQuery();
+
+ command.CommandText = "select * from tablea where field_serial = 0";
+ command.ExecuteScalar();
+
+
+ Assertion.AssertEquals(6, result);
+
+
+ }
+
+ [Test]
+ [ExpectedException(typeof(NpgsqlException))]
+ public void ConnectionStringWithInvalidParameters()
+ {
+ NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;User Id=npgsql_tests;Password=j");
+
+ NpgsqlCommand command = new NpgsqlCommand("select * from tablea", conn);
+
+ command.Connection.Open();
+ command.ExecuteReader();
+ command.Connection.Close();
+
+
+ }
+
+ [Test]
+ [ExpectedException(typeof(NpgsqlException))]
+ public void InvalidConnectionString()
+ {
+ NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;User Id=npgsql_tests");
+
+ NpgsqlCommand command = new NpgsqlCommand("select * from tablea", conn);
+
+ command.Connection.Open();
+ command.ExecuteReader();
+ command.Connection.Close();
+
+
+ }
+
+ [Test]
+ public void AmbiguousFunctionParameterType()
+ {
+ NpgsqlConnection conn = new NpgsqlConnection("Server=127.0.0.1;User Id=npgsql_tests;Password=npgsql_tests");
+
+
+ NpgsqlCommand command = new NpgsqlCommand("ambiguousParameterType(:a, :b, :c, :d, :e, :f)", conn);
+ command.CommandType = CommandType.StoredProcedure;
+ NpgsqlParameter p = new NpgsqlParameter("a", DbType.Int16);
+ p.Value = 2;
+ command.Parameters.Add(p);
+ p = new NpgsqlParameter("b", DbType.Int32);
+ p.Value = 2;
+ command.Parameters.Add(p);
+ p = new NpgsqlParameter("c", DbType.Int64);
+ p.Value = 2;
+ command.Parameters.Add(p);
+ p = new NpgsqlParameter("d", DbType.String);
+ p.Value = "a";
+ command.Parameters.Add(p);
+ p = new NpgsqlParameter("e", DbType.String);
+ p.Value = "a";
+ command.Parameters.Add(p);
+ p = new NpgsqlParameter("f", DbType.String);
+ p.Value = "a";
+ command.Parameters.Add(p);
+
+
+ command.Connection.Open();
+ command.Prepare();
+ command.ExecuteScalar();
+ command.Connection.Close();
+
+
+ }
+
}
}
}
+
+ [Test]
+ [ExpectedException(typeof(InvalidOperationException))]
+ public void ReadPastDataReaderEnd()
+ {
+ _conn.Open();
+ NpgsqlCommand command = new NpgsqlCommand("select * from tablea;", _conn);
+
+ NpgsqlDataReader dr = command.ExecuteReader();
+
+ while (dr.Read());
+
+ Object o = dr[0];
+
+ }
+
+ [Test]
+ public void IsDBNull()
+ {
+ _conn.Open();
+ NpgsqlCommand command = new NpgsqlCommand("select field_text from tablea;", _conn);
+
+ NpgsqlDataReader dr = command.ExecuteReader();
+
+ dr.Read();
+ Assertion.AssertEquals(false, dr.IsDBNull(0));
+ dr.Read();
+ Assertion.AssertEquals(true, dr.IsDBNull(0));
+
+
+ }
+
+ [Test]
+ public void IsDBNullFromScalar()
+ {
+ _conn.Open();
+ NpgsqlCommand command = new NpgsqlCommand("select max(field_serial) from tablea;", _conn);
+
+ NpgsqlDataReader dr = command.ExecuteReader();
+
+ dr.Read();
+ Assertion.AssertEquals(false, dr.IsDBNull(0));
+
+ }