+
+
+2005-12-09 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
+
+ Npgsql/NpgsqlError.cs,
+ Npgsql/NpgsqlParameter.cs,
+ Npgsql/NpgsqlConnectionString.cs,
+ Npgsql/NpgsqlConnection.cs,
+ Npgsql/NpgsqlSchema.cs,
+ Npgsql/NpgsqlClosedState.cs,
+ Npgsql/NpgsqlCommand.cs,
+ Npgsql/NpgsqlState.cs,
+ Npgsql/NpgsqlAsciiRow.cs,
+ Npgsql/NpgsqlConnectorPool.cs,
+ Npgsql/NpgsqlConnector.cs,
+ Npgsql/NpgsqlQuery.cs,
+ Npgsql/NpgsqlRowDescription.cs,
+ Npgsql/NpgsqlCommandBuilder.cs,
+ Npgsql/NpgsqlDataReader.cs,
+ Npgsql/NpgsqlException.cs,
+ Npgsql/NpgsqlMediator.cs,
+ Npgsql/NpgsqlReadyState.cs,
+ Npgsql/NpgsqlEventLog.cs,
+ Npgsql.dll.resources,
+ NpgsqlTypes/NpgsqlTypeConverters.cs,
+ NpgsqlTypes/NpgsqlTypesHelper.cs,
+ Makefile: Updated to 1.0beta1
+
+
2005-08-27 Francisco Figueiredo Jr. <fxjrlists@yahoo.com.br>
* NpgsqlParameter.cs: Applied patch to fix a NullReferenceException when using Design Time support. Thanks Josh Cooley ( jbnpgsql at tuxinthebox dot net ) for patch.
* NpgsqlDataReader.cs: Updated ProviderType metadata from NpgsqlDataReader.GetResultsetSchema to be the string for the type rather than the oid. Fixed ColumnSize, NumericPrecision, NumericScale, BaseColumnName, AllowDBNull, and IsAliased. Also integrated patch from (rlp at bamafolks dot com), gborg 751. Thanks Josh Cooley (jbnpgsql at tuxinthebox dot net) for patches!
Npgsql/NpgsqlEventLog.resources \
Npgsql/NpgsqlException.resources \
Npgsql/PGUtil.resources \
+ Npgsql/NpgsqlConnectionString.resources \
NpgsqlTypes/NpgsqlTypesHelper.resources
include ../../build/library.make
-resource:Npgsql/NpgsqlEventLog.resources,Npgsql.NpgsqlEventLog.resources
-resource:Npgsql/NpgsqlException.resources,Npgsql.NpgsqlException.resources
-resource:Npgsql/PGUtil.resources,Npgsql.PGUtil.resources
+-resource:Npgsql/NpgsqlConnectionString.resources,Npgsql.NpgsqlConnectionString.resources
-resource:NpgsqlTypes/NpgsqlTypesHelper.resources,NpgsqlTypes.NpgsqlTypesHelper.resources
private static readonly String CLASSNAME = "NpgsqlAsciiRow";
private readonly Int16 READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
+ private byte[] _inputBuffer;
+ private char[] _chars;
- public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion)
+ public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion, byte[] inputBuffer, char[] chars)
: base(rowDesc, protocolVersion)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+ _inputBuffer = inputBuffer;
+ _chars = chars;
}
public override void ReadFromStream(Stream inputStream, Encoding encoding)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
- Byte[] input_buffer = new Byte[READ_BUFFER_SIZE];
Byte[] null_map_array = new Byte[(row_desc.NumFields + 7)/8];
Array.Clear(null_map_array, 0, null_map_array.Length);
// Decoders used to get decoded chars when using unicode like encodings which may have chars crossing the byte buffer bounds.
Decoder decoder = encoding.GetDecoder();
- Char[] chars = null;
- Int32 charCount;
-
// Read the null fields bitmap.
PGUtil.CheckedStreamRead(inputStream, null_map_array, 0, null_map_array.Length );
// Read the first data of the first row.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, 4);
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, 4);
NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
- Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
+ Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(_inputBuffer, 0));
field_value_size -= 4;
- Int32 bytes_left = field_value_size;
-
- StringBuilder result = new StringBuilder();
-
- while (bytes_left > READ_BUFFER_SIZE)
- {
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, READ_BUFFER_SIZE);
-
- charCount = decoder.GetCharCount(input_buffer, 0, READ_BUFFER_SIZE);
-
- chars = new Char[charCount];
-
- decoder.GetChars(input_buffer, 0, READ_BUFFER_SIZE, chars, 0);
-
- result.Append(new String(chars));
-
- bytes_left -= READ_BUFFER_SIZE;
- }
-
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, bytes_left);
-
-
- charCount = decoder.GetCharCount(input_buffer, 0, bytes_left);
- chars = new Char[charCount];
- decoder.GetChars(input_buffer, 0, bytes_left, chars, 0);
-
- result.Append(new String(chars));
-
+ string result = ReadStringFromStream(inputStream, field_value_size, decoder);
// Add them to the AsciiRow data.
- data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result.ToString(), field_descr.type_size, field_descr.type_modifier));
+ data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
}
}
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
- Byte[] input_buffer = new Byte[READ_BUFFER_SIZE];
-
- PGUtil.ReadInt32(inputStream, input_buffer);
- Int16 numCols = PGUtil.ReadInt16(inputStream, input_buffer);
+ PGUtil.ReadInt32(inputStream, _inputBuffer);
+ Int16 numCols = PGUtil.ReadInt16(inputStream, _inputBuffer);
Decoder decoder = encoding.GetDecoder();
- Char[] chars = null;
- Int32 charCount;
-
- for (Int16 field_count = 0; field_count < numCols; field_count++)
- {
- Int32 field_value_size = PGUtil.ReadInt32(inputStream, input_buffer);
-
- // Check if this field is null
- if (field_value_size == -1) // Null value
- {
- data.Add(DBNull.Value);
- continue;
- }
- NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
- Int32 bytes_left = field_value_size;
- StringBuilder result = new StringBuilder();
-
- while (bytes_left > READ_BUFFER_SIZE)
- {
-
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, READ_BUFFER_SIZE);
-
- // Read the bytes as string.
- //result.Append(new String(encoding.GetChars(input_buffer, 0, READ_BUFFER_SIZE)));
- charCount = decoder.GetCharCount(input_buffer, 0, READ_BUFFER_SIZE);
-
- chars = new Char[charCount];
-
- decoder.GetChars(input_buffer, 0, READ_BUFFER_SIZE, chars, 0);
-
- result.Append(new String(chars));
-
- bytes_left -= READ_BUFFER_SIZE;
-
- // Now, read just the field value.
- /*PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, READ_BUFFER_SIZE);
-
- // Read the bytes as string.
- result.Append(new String(encoding.GetChars(input_buffer, 0, READ_BUFFER_SIZE)));
-
- bytes_left -= READ_BUFFER_SIZE;*/
- }
-
- // Now, read just the field value.
- PGUtil.CheckedStreamRead(inputStream, input_buffer, 0, bytes_left);
-
- if (row_desc[field_count].format_code == FormatCode.Text)
- {
- // Read the bytes as string.
- //result.Append(new String(encoding.GetChars(input_buffer, 0, bytes_left)));
-
-
- charCount = decoder.GetCharCount(input_buffer, 0, bytes_left);
- chars = new Char[charCount];
- decoder.GetChars(input_buffer, 0, bytes_left, chars, 0);
-
- result.Append(new String(chars));
-
- // Add them to the AsciiRow data.
- data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result.ToString(), field_descr.type_size, field_descr.type_modifier));
-
- }
- else
- // FIXME: input_buffer isn't holding all the field value. This code isn't handling binary data correctly.
- data.Add(NpgsqlTypesHelper.ConvertBackendBytesToSystemType(field_descr.type_info, input_buffer, encoding, field_value_size, field_descr.type_modifier));
+ for (Int16 field_count = 0; field_count < numCols; field_count++)
+ {
+ Int32 field_value_size = PGUtil.ReadInt32(inputStream, _inputBuffer);
+
+ // Check if this field is null
+ if (field_value_size == -1) // Null value
+ {
+ data.Add(DBNull.Value);
+ continue;
+ }
+
+ NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
+
+ if (row_desc[field_count].format_code == FormatCode.Text)
+ {
+ string result = ReadStringFromStream(inputStream, field_value_size, decoder);
+ // Add them to the AsciiRow data.
+ data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
+ }
+ else
+ {
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, Math.Min(field_value_size, _inputBuffer.Length));
+ // FIXME: _inputBuffer isn't holding all the field value. This code isn't handling binary data correctly.
+ data.Add(NpgsqlTypesHelper.ConvertBackendBytesToSystemType(field_descr.type_info, _inputBuffer, encoding, field_value_size, field_descr.type_modifier));
+ }
}
}
// MSB and test it with the byte 10000000.
return (((test_byte << (index%8)) & 0x80) == 0);
}
+
+ private int GetCharsFromStream(Stream inputStream, int count, Decoder decoder, char[] chars)
+ {
+ // Now, read just the field value.
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, count);
+ int charCount = decoder.GetCharCount(_inputBuffer, 0, count);
+ decoder.GetChars(_inputBuffer, 0, count, chars, 0);
+ return charCount;
+ }
+
+ private string ReadStringFromStream(Stream inputStream, int field_value_size, Decoder decoder)
+ {
+ int bytes_left = field_value_size;
+ int charCount;
+
+ if (field_value_size > _inputBuffer.Length)
+ {
+ StringBuilder result = new StringBuilder();
+
+ while (bytes_left > READ_BUFFER_SIZE)
+ {
+ charCount = GetCharsFromStream(inputStream, READ_BUFFER_SIZE, decoder, _chars);
+ result.Append(_chars, 0,charCount);
+ bytes_left -= READ_BUFFER_SIZE;
+ }
+
+ charCount = GetCharsFromStream(inputStream, bytes_left, decoder, _chars);
+ result.Append(_chars, 0,charCount);
+
+ return result.ToString();
+ }
+ else
+ {
+ charCount = GetCharsFromStream(inputStream, bytes_left, decoder, _chars);
+
+ return new String(_chars, 0,charCount);
+ }
+ }
}
}
internal sealed class NpgsqlClosedState : NpgsqlState
{
- private static NpgsqlClosedState _instance = null;
+ private static NpgsqlClosedState _instance = new NpgsqlClosedState();
private static readonly String CLASSNAME = "NpgsqlClosedState";
private NpgsqlClosedState() : base()
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Instance");
- if (_instance == null)
- {
- _instance = new NpgsqlClosedState();
- }
return _instance;
}
}
internal NpgsqlConnector Connector {
get
{
- if (connector == null && this.connection != null)
+ if (this.connection != null)
connector = this.connection.Connector;
return connector;
result = AddSingleRowBehaviorSupport(result);
+
+ result = AddSchemaOnlyBehaviorSupport(result);
return result;
}
return ProcessRefcursorFunctionReturn(result);
- return AddSingleRowBehaviorSupport(result);
+ result = AddSingleRowBehaviorSupport(result);
+
+ result = AddSchemaOnlyBehaviorSupport(result);
+
+ return result;
}
ResultCommandText = ResultCommandText.Trim();
- if ((commandBehavior & CommandBehavior.SingleRow) > 0)
+ if ((commandBehavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow)
{
if (ResultCommandText.EndsWith(";"))
ResultCommandText = ResultCommandText.Substring(0, ResultCommandText.Length - 1);
+ return ResultCommandText;
+
+ }
+
+ private String AddSchemaOnlyBehaviorSupport(String ResultCommandText)
+ {
+
+ ResultCommandText = ResultCommandText.Trim();
+
+ if ((commandBehavior & CommandBehavior.SchemaOnly) == CommandBehavior.SchemaOnly)
+ {
+ if (ResultCommandText.EndsWith(";"))
+ ResultCommandText = ResultCommandText.Substring(0, ResultCommandText.Length - 1);
+ ResultCommandText += " limit 0;";
+
+ }
+
+
return ResultCommandText;
}
CheckConnectionState();
// reset any responses just before getting new ones
- connector.Mediator.ResetResponses();
+ Connector.Mediator.ResetResponses();
if (parse == null)
// NpgsqlCommandBuilder.cs
//
// Author:
-// Pedro MartÃnez Juliá (yoros@wanadoo.es)
+// Pedro MartÃnez Juliá (yoros@wanadoo.es)
//
-// Copyright (C) 2003 Pedro MartÃnez Juliá
+// Copyright (C) 2003 Pedro MartÃnez Juliá
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Data;
using System.Data.Common;
using System.ComponentModel;
+using NpgsqlTypes;
namespace Npgsql
{
private string table_name = String.Empty;
+ private string quotePrefix = "\"";
+ private string quoteSuffix = "\"";
+
public NpgsqlCommandBuilder ()
{}
}
}
- private void OnRowUpdating(Object sender, NpgsqlRowUpdatingEventArgs value) {
+ private void OnRowUpdating(Object sender, NpgsqlRowUpdatingEventArgs value)
+ {
switch (value.StatementType)
{
- case StatementType.Insert:
- value.Command = GetInsertCommand(value.Row);
- break;
- case StatementType.Update:
- value.Command = GetUpdateCommand(value.Row);
- break;
- case StatementType.Delete:
- value.Command = GetDeleteCommand(value.Row);
- break;
+ case StatementType.Insert:
+ value.Command = GetInsertCommand(value.Row);
+ break;
+ case StatementType.Update:
+ value.Command = GetUpdateCommand(value.Row);
+ break;
+ case StatementType.Delete:
+ value.Command = GetDeleteCommand(value.Row);
+ break;
}
DataColumnMappingCollection columnMappings = value.TableMapping.ColumnMappings;
value.Row.AcceptChanges ();
}
+
public string QuotePrefix {
get
{
- return "";
+ return quotePrefix;
}
set
- { }
+ {
+ quotePrefix = value;
+ }
}
+
public string QuoteSuffix {
get
{
- return "";
+ return quoteSuffix;
}
set
- { }
+ {
+ quoteSuffix = value;
+ }
}
+ ///<summary>
+ ///
+ /// This method is reponsible to derive the command parameter list with values obtained from function definition.
+ /// It clears the Parameters collection of command. Also, if there is any parameter type which is not supported by Npgsql, an InvalidOperationException will be thrown.
+ /// Parameters name will be parameter1, parameter2, ...
+ /// For while, only parameter name and NpgsqlDbType are obtained.
+ ///</summary>
+ /// <param name="command">NpgsqlCommand whose function parameters will be obtained.</param>
+
public static void DeriveParameters (NpgsqlCommand command)
- {}
+ {
+ String query = "select proargtypes from pg_proc where proname = :procname";
+
+ NpgsqlCommand c = new NpgsqlCommand(query, command.Connection);
+ c.Parameters.Add(new NpgsqlParameter("procname", NpgsqlDbType.Text));
+ c.Parameters[0].Value = command.CommandText;
+
+ String types = (String) c.ExecuteScalar();
+
+ command.Parameters.Clear();
+ Int32 i = 1;
+
+ foreach(String s in types.Split())
+ {
+ if (!c.Connector.OidToNameMapping.ContainsOID(Int32.Parse(s)))
+ {
+ command.Parameters.Clear();
+ throw new InvalidOperationException(String.Format("Invalid parameter type: {0}", s));
+ }
+ command.Parameters.Add(new NpgsqlParameter("parameter" + i++, c.Connector.OidToNameMapping[Int32.Parse(s)].NpgsqlDbType));
+ }
+
+ }
+
+ private string GetQuotedName(string str)
+ {
+ string result = str;
+ if ((QuotePrefix != string.Empty) && !str.StartsWith(QuotePrefix))
+ {
+ result = QuotePrefix + result;
+ }
+ if ((QuoteSuffix != string.Empty) && !str.EndsWith(QuoteSuffix))
+ {
+ result = result + QuoteSuffix;
+ }
+ return result;
+ }
public NpgsqlCommand GetInsertCommand (DataRow row)
{
fields += ", ";
values += ", ";
}
- fields += column.ColumnName;
+ fields += GetQuotedName(column.ColumnName);
values += ":param_" + column.ColumnName;
}
if (table_name == String.Empty)
{
table_name = row.Table.TableName;
}
- NpgsqlCommand cmdaux = new NpgsqlCommand("insert into " + table_name + " (" + fields + ") values (" + values + ")", data_adapter.SelectCommand.Connection);
+ NpgsqlCommand cmdaux = new NpgsqlCommand("insert into " + GetQuotedName(table_name) + " (" + fields + ") values (" + values + ")", data_adapter.SelectCommand.Connection);
foreach (DataColumn column in row.Table.Columns)
{
- NpgsqlParameter aux = new NpgsqlParameter("param_" + column.ColumnName, row[column]);
+ NpgsqlParameter aux = new NpgsqlParameter("param_" + column.ColumnName, row[column], NpgsqlTypesHelper.GetNativeTypeInfo(column.DataType));
aux.Direction = ParameterDirection.Input;
aux.SourceColumn = column.ColumnName;
cmdaux.Parameters.Add(aux);
wheres += " and ";
}
DataColumn column = row.Table.Columns[i];
- sets += String.Format("{0} = :s_param_{0}", column.ColumnName);
- wheres += String.Format("(({0} is null) or ({0} = :w_param_{0}))", column.ColumnName);
+ sets += String.Format(GetQuotedName("{0}") + " = :s_param_{0}", column.ColumnName);
+ wheres += String.Format("((" + GetQuotedName("{0}") + " is null) or (" + GetQuotedName("{0}") + " = :w_param_{0}))", column.ColumnName);
}
if (table_name == String.Empty)
{
table_name = row.Table.TableName;
}
- NpgsqlCommand cmdaux = new NpgsqlCommand("update " + table_name + " set " + sets + " where ( " + wheres + " )", data_adapter.SelectCommand.Connection);
+ NpgsqlCommand cmdaux = new NpgsqlCommand("update " + GetQuotedName(table_name) + " set " + sets + " where ( " + wheres + " )", data_adapter.SelectCommand.Connection);
foreach (DataColumn column in row.Table.Columns)
{
- NpgsqlParameter aux = new NpgsqlParameter("s_param_" + column.ColumnName, row[column]);
+ NpgsqlParameter aux = new NpgsqlParameter("s_param_" + column.ColumnName, row[column], NpgsqlTypesHelper.GetNativeTypeInfo(column.DataType));
aux.Direction = ParameterDirection.Input;
aux.SourceColumn = column.ColumnName;
aux.SourceVersion = DataRowVersion.Current;
}
foreach (DataColumn column in row.Table.Columns)
{
- NpgsqlParameter aux = new NpgsqlParameter("w_param_" + column.ColumnName, row[column]);
+ NpgsqlParameter aux = new NpgsqlParameter("w_param_" + column.ColumnName, row[column], NpgsqlTypesHelper.GetNativeTypeInfo(column.DataType));
aux.Direction = ParameterDirection.Input;
aux.SourceColumn = column.ColumnName;
aux.SourceVersion = DataRowVersion.Original;
{
wheres += " and ";
}
- wheres += String.Format("(({0} is null) or ({0} = :param_{0}))", column.ColumnName);
+ wheres += String.Format("((" + GetQuotedName("{0}") + " is null) or (" + GetQuotedName("{0}") + " = :param_{0}))", column.ColumnName);
}
if (table_name == String.Empty)
{
table_name = row.Table.TableName;
}
- NpgsqlCommand cmdaux = new NpgsqlCommand("delete from " + table_name + " where ( " + wheres + " )", data_adapter.SelectCommand.Connection);
+ NpgsqlCommand cmdaux = new NpgsqlCommand("delete from " + GetQuotedName(table_name) + " where ( " + wheres + " )", data_adapter.SelectCommand.Connection);
foreach (DataColumn column in row.Table.Columns)
{
- NpgsqlParameter aux = new NpgsqlParameter("param_" + column.ColumnName, row[column,DataRowVersion.Original]);
+ NpgsqlParameter aux = new NpgsqlParameter("param_" + column.ColumnName, row[column,DataRowVersion.Original], NpgsqlTypesHelper.GetNativeTypeInfo(column.DataType));
aux.Direction = ParameterDirection.Input;
aux.SourceColumn = column.ColumnName;
aux.SourceVersion = DataRowVersion.Original;
/// <summary>
/// Gets or sets the string used to connect to a PostgreSQL database.
/// Valid values are:
- /// Server: Address/Name of Postgresql Server;
- /// Port: Port to connect to;
- /// Protocol: Protocol version to use, instead of automatic; Integer 2 or 3;
- /// Database: Database name. Defaults to user name if not specified;
- /// User Id: User name;
- /// Password: Password for clear text authentication;
- /// SSL: True or False. Controls whether to attempt a secure connection. Default = False;
- /// Pooling: True or False. Controls whether connection pooling is used. Default = True;
- /// MinPoolSize: Min size of connection pool;
- /// MaxPoolSize: Max size of connection pool;
- /// Encoding: Encoding to be used;
- /// Timeout: Time to wait for connection open in seconds.
+ /// Server: Address/Name of Postgresql Server;
+ /// Port: Port to connect to;
+ /// Protocol: Protocol version to use, instead of automatic; Integer 2 or 3;
+ /// Database: Database name. Defaults to user name if not specified;
+ /// User Id: User name;
+ /// Password: Password for clear text authentication;
+ /// SSL: True or False. Controls whether to attempt a secure connection. Default = False;
+ /// Pooling: True or False. Controls whether connection pooling is used. Default = True;
+ /// MinPoolSize: Min size of connection pool;
+ /// MaxPoolSize: Max size of connection pool;
+ /// Encoding: Encoding to be used;
+ /// Timeout: Time to wait for connection open in seconds.
+ /// ConnectionLifeTime: Time to wait before closing unused connections in the pool.
/// </summary>
/// <value>The connection string that includes the server name,
/// the database name, and other parameters needed to establish
return connection_string.ToInt32(ConnectionStringKeys.Timeout, ConnectionStringDefaults.Timeout);
}
}
+
+ /// <summary>
+ /// Gets the time to wait before closing unused connections in the pool if the count
+ /// of all connections exeeds MinPoolSize.
+ /// </summary>
+ /// <remarks>
+ /// If connection pool contains unused connections for ConnectionLifeTime seconds,
+ /// the half of them will be closed. If there will be unused connections in a second
+ /// later then again the half of them will be closed and so on.
+ /// This strategy provide smooth change of connection count in the pool.
+ /// </remarks>
+ /// <value>The time (in seconds) to wait. The default value is 15 seconds.</value>
+ public Int32 ConnectionLifeTime {
+ get
+ {
+ return connection_string.ToInt32(ConnectionStringKeys.ConnectionLifeTime, ConnectionStringDefaults.ConnectionLifeTime);
+ }
+ }
///<summary>
/// Gets the name of the current database or the database to be used after a connection is opened.
/// </summary>
internal abstract class ConnectionStringKeys
{
- public static readonly String Host = "SERVER";
- public static readonly String Port = "PORT";
- public static readonly String Protocol = "PROTOCOL";
- public static readonly String Database = "DATABASE";
- public static readonly String UserName = "USER ID";
- public static readonly String Password = "PASSWORD";
- public static readonly String SSL = "SSL";
- public static readonly String SslMode = "SSLMODE";
- public static readonly String Encoding = "ENCODING";
- public static readonly String Timeout = "TIMEOUT";
-
+ public static readonly String Host = "SERVER";
+ public static readonly String Port = "PORT";
+ public static readonly String Protocol = "PROTOCOL";
+ public static readonly String Database = "DATABASE";
+ public static readonly String UserName = "USER ID";
+ public static readonly String Password = "PASSWORD";
+ public static readonly String SSL = "SSL";
+ public static readonly String SslMode = "SSLMODE";
+ public static readonly String Encoding = "ENCODING";
+ public static readonly String Timeout = "TIMEOUT";
+
// These are for the connection pool
- public static readonly String Pooling = "POOLING";
- public static readonly String MinPoolSize = "MINPOOLSIZE";
- public static readonly String MaxPoolSize = "MAXPOOLSIZE";
+ public static readonly String Pooling = "POOLING";
+ public static readonly String ConnectionLifeTime = "CONNECTIONLIFETIME";
+ public static readonly String MinPoolSize = "MINPOOLSIZE";
+ public static readonly String MaxPoolSize = "MAXPOOLSIZE";
// A list of aliases for some of the above values. If one of these aliases is
// encountered when parsing a connection string, it's real key name will
internal abstract class ConnectionStringDefaults
{
// Connection string defaults
- public static readonly Int32 Port = 5432;
- public static readonly String Encoding = "SQL_ASCII";
- public static readonly Boolean Pooling = true;
- public static readonly Int32 MinPoolSize = 1;
- public static readonly Int32 MaxPoolSize = 20;
- public static readonly Int32 Timeout = 15; // Seconds
+ public static readonly Int32 Port = 5432;
+ public static readonly String Encoding = "SQL_ASCII";
+ public static readonly Boolean Pooling = true;
+ public static readonly Int32 MinPoolSize = 1;
+ public static readonly Int32 MaxPoolSize = 20;
+ public static readonly Int32 Timeout = 15; // Seconds
+ public static readonly Int32 ConnectionLifeTime = 15; // Seconds
}
internal enum SslMode
try
{
// Here we use a fake NpgsqlCommand, just to send the test query string.
- Query(new NpgsqlCommand("select 1 as ConnectionTest"));
+
+ Query(new NpgsqlCommand("select 1 as ConnectionTest", this));
// Clear mediator.
Mediator.ResetResponses();
if (_planIndex > 0)
{
for(i = 1; i <= _planIndex; i++)
- Query(new NpgsqlCommand(String.Format("deallocate \"{0}\";", _planNamePrefix + i)));
+ Query(new NpgsqlCommand(String.Format("deallocate \"{0}\";", _planNamePrefix + i), this));
}
_portalIndex = 0;
using System;
using System.Collections;
using System.Threading;
+using System.Timers;
namespace Npgsql
{
/// are currently in use.
/// </summary>
public Int32 UseCount = 0;
+ public Int32 ConnectionLifeTime;
+ public Int32 InactiveTime = 0;
+ public Int32 MinPoolSize;
+
}
/// <value>Unique static instance of the connector pool
public NpgsqlConnectorPool()
{
PooledConnectors = new Hashtable();
+ Timer = new System.Timers.Timer(1000);
+ Timer.AutoReset = true;
+ Timer.Elapsed += new ElapsedEventHandler(TimerElapsedHandler);
+ Timer.Start();
+
+ }
+
+
+ ~NpgsqlConnectorPool()
+ {
+ Timer.Stop();
+ }
+
+ private void TimerElapsedHandler(object sender, ElapsedEventArgs e)
+ {
+ NpgsqlConnector Connector;
+ lock (this)
+ {
+ foreach (ConnectorQueue Queue in PooledConnectors.Values)
+ {
+ if (Queue.Count > 0)
+ {
+ if (Queue.Count + Queue.UseCount > Queue.MinPoolSize)
+ {
+ if (Queue.InactiveTime >= Queue.ConnectionLifeTime)
+ {
+ Int32 diff = Queue.Count + Queue.UseCount - Queue.MinPoolSize;
+ Int32 toBeClosed = (diff + 1) / 2;
+ if (diff < 2)
+ diff = 2;
+ Queue.InactiveTime -= Queue.ConnectionLifeTime / (int)(Math.Log(diff) / Math.Log(2));
+ for (Int32 i = 0; i < toBeClosed; ++i)
+ {
+ Connector = (NpgsqlConnector)Queue.Dequeue();
+ Connector.Close();
+ }
+ }
+ else
+ {
+ Queue.InactiveTime++;
+ }
+ }
+ else
+ {
+ Queue.InactiveTime = 0;
+ }
+ }
+ else
+ {
+ Queue.InactiveTime = 0;
+ }
+ }
+ }
}
+
/// <value>Map of index to unused pooled connectors, avaliable to the
/// next RequestConnector() call.</value>
/// <remarks>This hashmap will be indexed by connection string.
// To be implemented
//private Hashtable SharedConnectors;
+
+ /// <value>Timer for tracking unused connections in pools.</value>
+ // I used System.Timers.Timer because of bad experience with System.Threading.Timer
+ // on Windows - it's going mad sometimes and don't respect interval was set.
+ private System.Timers.Timer Timer;
+
/// <summary>
/// Searches the shared and pooled connector lists for a
/// matching connector object or creates a new one.
if (Queue == null)
{
Queue = new ConnectorQueue();
+ Queue.ConnectionLifeTime = Connection.ConnectionLifeTime;
+ Queue.MinPoolSize = Connection.MinPoolSize;
PooledConnectors[Connection.ConnectionString.ToString()] = Queue;
}
break;
}
- Queue.UseCount--;
+ // Don't need - we dequeue connector = decrease Queue.Count.
+ //Queue.UseCount--;
if (Queue.Count <= 0)
return GetPooledConnector(Connection);
/// </summary>
public DataTable GetSchemaTable()
{
+
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetSchemaTable");
if(_currentResultsetSchema == null)
/// <summary>
/// Return the data type OID of the column at index <param name="Index"></param>.
/// </summary>
+ /// FIXME: Why this method returns String?
public String GetDataTypeOID(Int32 Index)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDataTypeName");
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "FillSchemaTable_v2");
NpgsqlRowDescription rd = _currentResultset.RowDescription;
- ArrayList keyList = GetPrimaryKeys(GetTableNameFromQuery());
+ ArrayList keyList = null;
+
+ if ((_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo)
+ {
+ keyList = GetPrimaryKeys(GetTableNameFromQuery());
+ }
+
DataRow row;
for (Int16 i = 0; i < rd.NumFields; i++)
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "FillSchemaTable_v3");
NpgsqlRowDescription rd = _currentResultset.RowDescription;
- ArrayList tableOids = new ArrayList();
- for(short i=0; i<rd.NumFields; ++i)
- {
- if (rd[i].table_oid != 0 && !tableOids.Contains(rd[i].table_oid))
- tableOids.Add(rd[i].table_oid);
- }
- Hashtable oidTableLookup = GetTablesFromOids(tableOids);
-
- ArrayList keyList = null;
- if (oidTableLookup != null && oidTableLookup.Count == 1)
- {
- // only 1, but we can't index into the Hashtable
- foreach(DictionaryEntry entry in oidTableLookup)
- {
- GetPrimaryKeys(((object[])entry.Value)[Tables.table_name].ToString());
- }
- }
-
- Hashtable columnLookup = GetColumns();
+ Hashtable oidTableLookup = null;
+ KeyLookup keyLookup = new KeyLookup();
+ Hashtable columnLookup = null;
+
+ if ((_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo)
+ {
+ ArrayList tableOids = new ArrayList();
+ for(short i=0; i<rd.NumFields; ++i)
+ {
+ if (rd[i].table_oid != 0 && !tableOids.Contains(rd[i].table_oid))
+ tableOids.Add(rd[i].table_oid);
+ }
+ oidTableLookup = GetTablesFromOids(tableOids);
+
+ if (oidTableLookup != null && oidTableLookup.Count == 1)
+ {
+ // only 1, but we can't index into the Hashtable
+ foreach(DictionaryEntry entry in oidTableLookup)
+ {
+ keyLookup = GetKeys((Int32)entry.Key);
+ }
+ }
+
+ columnLookup = GetColumns();
+ }
DataRow row;
for (Int16 i = 0; i < rd.NumFields; i++)
{
row = schema.NewRow();
+ string baseColumnName = GetBaseColumnName(columnLookup, i);
+
row["ColumnName"] = GetName(i);
row["ColumnOrdinal"] = i + 1;
if (rd[i].type_modifier != -1 && (rd[i].type_info.Name == "varchar" || rd[i].type_info.Name == "bpchar"))
row["NumericPrecision"] = 0;
row["NumericScale"] = 0;
}
- row["IsUnique"] = false;
- row["IsKey"] = IsKey(GetName(i), keyList);
+ row["IsUnique"] = IsUnique(keyLookup, baseColumnName);
+ row["IsKey"] = IsKey(keyLookup, baseColumnName);
if (rd[i].table_oid != 0 && oidTableLookup != null)
{
row["BaseCatalogName"] = ((object[])oidTableLookup[rd[i].table_oid])[Tables.table_catalog];
row["BaseSchemaName"] = "";
row["BaseTableName"] = "";
}
- row["BaseColumnName"] = GetBaseColumnName(columnLookup, i);
+ row["BaseColumnName"] = baseColumnName;
row["DataType"] = GetFieldType(i);
row["AllowDBNull"] = IsNullable(columnLookup, i);
row["ProviderType"] = rd[i].type_info.Name;
- row["IsAliased"] = string.CompareOrdinal((string)row["ColumnName"], (string)row["BaseColumnName"]) != 0;
+ row["IsAliased"] = string.CompareOrdinal((string)row["ColumnName"], baseColumnName) != 0;
row["IsExpression"] = false;
row["IsIdentity"] = false;
- row["IsAutoIncrement"] = false;
+ row["IsAutoIncrement"] = IsAutoIncrement(columnLookup, i);
row["IsRowVersion"] = false;
row["IsHidden"] = false;
row["IsLong"] = false;
return result;
}
-
+ private bool IsKey(KeyLookup keyLookup, string fieldName)
+ {
+ if (keyLookup.primaryKey == null || keyLookup.primaryKey.Count == 0)
+ return false;
+
+ for (int i=0; i<keyLookup.primaryKey.Count; ++i)
+ {
+ if (fieldName == (String)keyLookup.primaryKey[i])
+ return true;
+ }
+
+ return false;
+ }
+
+ private bool IsUnique(KeyLookup keyLookup, string fieldName)
+ {
+ if (keyLookup.uniqueColumns == null || keyLookup.uniqueColumns.Count == 0)
+ return false;
+
+ for (int i=0; i<keyLookup.uniqueColumns.Count; ++i)
+ {
+ if (fieldName == (String)keyLookup.uniqueColumns[i])
+ return true;
+ }
+
+ return false;
+ }
+
+ private struct KeyLookup
+ {
+ /// <summary>
+ /// Contains the column names as the keys
+ /// </summary>
+ public ArrayList primaryKey;
+ /// <summary>
+ /// Contains all unique columns
+ /// </summary>
+ public ArrayList uniqueColumns;
+ }
+
+ private KeyLookup GetKeys(Int32 tableOid)
+ {
+
+ string getKeys = "select a.attname, ci.relname, i.indisprimary from pg_catalog.pg_class ct, pg_catalog.pg_class ci, pg_catalog.pg_attribute a, pg_catalog.pg_index i WHERE ct.oid=i.indrelid AND ci.oid=i.indexrelid AND a.attrelid=ci.oid AND i.indisunique AND ct.oid = :tableOid order by ci.relname";
+
+ KeyLookup lookup = new KeyLookup();
+ lookup.primaryKey = new ArrayList();
+ lookup.uniqueColumns = new ArrayList();
+
+ using (NpgsqlConnection metadataConn = _connection.Clone())
+ {
+ NpgsqlCommand c = new NpgsqlCommand(getKeys, metadataConn);
+ c.Parameters.Add(new NpgsqlParameter("tableOid", NpgsqlDbType.Integer)).Value = tableOid;
+
+ using (NpgsqlDataReader dr = c.ExecuteReader())
+ {
+ string previousKeyName = null;
+ string possiblyUniqueColumn = null;
+ string columnName;
+ string currentKeyName;
+ // loop through adding any column that is primary to the primary key list
+ // add any column that is the only column for that key to the unique list
+ // unique here doesn't mean general unique constraint (with possibly multiple columns)
+ // it means all values in this single column must be unique
+ while (dr.Read())
+ {
+
+ columnName = dr.GetString(0);
+ currentKeyName = dr.GetString(1);
+ // if i.indisprimary
+ if (dr.GetBoolean(2))
+ {
+ // add column name as part of the primary key
+ lookup.primaryKey.Add(columnName);
+ }
+ if (currentKeyName != previousKeyName)
+ {
+ if (possiblyUniqueColumn != null)
+ {
+ lookup.uniqueColumns.Add(possiblyUniqueColumn);
+ }
+ possiblyUniqueColumn = columnName;
+ }
+ else
+ {
+ possiblyUniqueColumn = null;
+ }
+ previousKeyName = currentKeyName;
+ }
+ // if finished reading and have a possiblyUniqueColumn name that is
+ // not null, then it is the name of a unique column
+ if (possiblyUniqueColumn != null)
+ lookup.uniqueColumns.Add(possiblyUniqueColumn);
+ }
+ }
+
+ return lookup;
+ }
private Boolean IsNullable(Hashtable columnLookup, Int32 FieldIndex)
{
return GetName(FieldIndex);
}
+ private bool IsAutoIncrement(Hashtable columnLookup, Int32 FieldIndex)
+ {
+ if (columnLookup == null || _currentResultset.RowDescription[FieldIndex].table_oid == 0)
+ return false;
+
+ string lookupKey = _currentResultset.RowDescription[FieldIndex].table_oid.ToString() + "," + _currentResultset.RowDescription[FieldIndex].column_attribute_number;
+ object[] row = (object[])columnLookup[lookupKey];
+ if (row != null)
+ return row[Columns.column_default].ToString().StartsWith("nextval(");
+ else
+ return true;
+ }
+
///<summary>
/// This methods parses the command text and tries to get the tablename
public const int column_notnull = 1;
public const int table_id = 2;
public const int column_num = 3;
+ public const int column_default = 4;
}
private Hashtable GetColumns()
// the column index is used to find data.
// any changes to the order of the columns needs to be reflected in struct Columns
- sb.Append("SELECT a.attname AS column_name, a.attnotnull AS column_notnull, a.attrelid AS table_id, a.attnum AS column_num");
- sb.Append(" from pg_attribute a WHERE a.attnum > 0 AND (");
+ sb.Append("SELECT a.attname AS column_name, a.attnotnull AS column_notnull, a.attrelid AS table_id, a.attnum AS column_num, d.adsrc as column_default");
+ sb.Append(" FROM pg_attribute a LEFT OUTER JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attnum > 0 AND (");
bool first = true;
for(int i=0; i<_currentResultset.RowDescription.NumFields; ++i)
{
private static readonly String CLASSNAME = "NpgsqlError";
private ProtocolVersion protocol_version;
- private String _severity = "";
- private String _code = "";
- private String _message = "";
- private String _detail = "";
- private String _hint = "";
- private String _position = "";
- private String _where = "";
- private String _file = "";
- private String _line = "";
- private String _routine = "";
+ private String _severity = String.Empty;
+ private String _code = String.Empty;
+ private String _message = String.Empty;
+ private String _detail = String.Empty;
+ private String _hint = String.Empty;
+ private String _position = String.Empty;
+ private String _where = String.Empty;
+ private String _file = String.Empty;
+ private String _line = String.Empty;
+ private String _routine = String.Empty;
+ private String _errorSql = String.Empty;
/// <summary>
/// Severity code. All versions.
return _routine;
}
}
-
+
+ /// <summary>
+ /// String containing the sql sent which produced this error.
+ /// </summary>
+ public String ErrorSql
+ {
+ set
+ {
+ _errorSql = value;
+ }
+ get
+ {
+ return _errorSql;
+ }
+ }
/// <summary>
/// Return a string representation of this error object.
/// </summary>
{
if (logfile != "")
{
+ lock(logfile)
+ {
- StreamWriter writer = new StreamWriter(logfile, true);
+ StreamWriter writer = new StreamWriter(logfile, true);
- // The format of the logfile is
- // [Date] [Time] [PID] [Level] [Message]
- writer.WriteLine(System.DateTime.Now + "\t" + proc.Id + "\t" + msglevel + "\t" + message);
- writer.Close();
+ // The format of the logfile is
+ // [Date] [Time] [PID] [Level] [Message]
+ writer.WriteLine(System.DateTime.Now + "\t" + proc.Id + "\t" + msglevel + "\t" + message);
+ writer.Close();
+ }
}
}
}
return this[0].Routine;
}
}
+
+ /// <summary>
+ /// String containing the sql sent which produced this error.
+ /// </summary>
+ public String ErrorSql
+ {
+ get
+ {
+ return this[0].ErrorSql;
+ }
+ }
+
/// <summary>
/// Returns the entire list of errors provided by the PostgreSQL backend.
//
// Responses collected from the backend.
//
- private ArrayList _errors;
- private ArrayList _notices;
- private ArrayList _resultSets;
- private ArrayList _responses;
- private ArrayList _notifications;
- private ListDictionary _parameters;
- private NpgsqlBackEndKeyData _backend_key_data;
+ private ArrayList _errors;
+ private ArrayList _notices;
+ private ArrayList _resultSets;
+ private ArrayList _responses;
+ private ArrayList _notifications;
+ private ListDictionary _parameters;
+ private NpgsqlBackEndKeyData _backend_key_data;
private NpgsqlRowDescription _rd;
- private ArrayList _rows;
+ private ArrayList _rows;
+ private String _sqlSent;
+
public NpgsqlMediator()
{
_notifications = new ArrayList();
_parameters = new ListDictionary(CaseInsensitiveComparer.Default);
_backend_key_data = null;
+ _sqlSent = String.Empty;
}
public void ResetExpectations()
_notifications.Clear();
_parameters.Clear();
_backend_key_data = null;
+ _sqlSent = String.Empty;
}
return _backend_key_data;
}
}
+
+ public String SqlSent
+ {
+ set
+ {
+ _sqlSent = value;
+ }
+
+ get
+ {
+ return _sqlSent;
+ }
+ }
public void AddNotification(NpgsqlNotificationEventArgs data)
{
private DataRowVersion source_version = DataRowVersion.Current;
private Object value = DBNull.Value;
private System.Resources.ResourceManager resman;
-
+
+
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> class.
{
resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
- type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
+ //type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
}
/// <summary>
{
throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), value.GetType()));
}
+
+
}
}
-
+
+ /// <summary>
+ /// Internal constructor to handle parameter creation from CommandBuilder passing a NpgsqlNativeTypeInfo directly.
+ /// </summary>
+ internal NpgsqlParameter(String parameterName, object value, NpgsqlNativeTypeInfo type_info)
+ {
+ resman = new System.Resources.ResourceManager(this.GetType());
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, parameterName, value, type_info);
+
+ this.ParameterName = parameterName;
+ this.value = (value == null) ? DBNull.Value : value;
+
+ this.type_info = (type_info == null) ? NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String)) : type_info;
+ }
+
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>
/// class with the parameter name and the data type.
{
get
{
+ if (type_info == null)
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
return type_info;
}
}
String commandText = _command.GetCommandText();
+
+ // Tell to mediator what command is being sent.
+
+ _command.Connector.Mediator.SqlSent = commandText;
+
// Send the query to server.
// Write the byte 'Q' to identify a query message.
outputStream.WriteByte((Byte)'Q');
internal sealed class NpgsqlReadyState : NpgsqlState
{
- private static NpgsqlReadyState _instance = null;
+ private static NpgsqlReadyState _instance = new NpgsqlReadyState();
// Flush and Sync messages. It doesn't need to be created every time it is called.
{
get
{
- if ( _instance == null )
- {
- _instance = new NpgsqlReadyState();
- }
return _instance;
}
}
private static readonly String CLASSNAME = "NpgsqlRowDescription";
- private ArrayList fields_data = new ArrayList();
- private ArrayList fields_index = new ArrayList();
+ private NpgsqlRowDescriptionFieldData[] fields_data;
+ private string[] fields_index;
private ProtocolVersion protocol_version;
// Temporary FieldData object to get data from stream and put in array.
NpgsqlRowDescriptionFieldData fd;
+ fields_data = new NpgsqlRowDescriptionFieldData[num_fields];
+ fields_index = new string[num_fields];
// Now, iterate through each field getting its data.
for (Int16 i = 0; i < num_fields; i++)
{
fd.type_modifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 6));
// Add field data to array.
- fields_data.Add(fd);
+ fields_data[i] = fd;
- fields_index.Add(fd.name);
+ fields_index[i] = fd.name;
}
}
// Temporary FieldData object to get data from stream and put in array.
NpgsqlRowDescriptionFieldData fd;
+ fields_data = new NpgsqlRowDescriptionFieldData[num_fields];
+ fields_index = new string[num_fields];
for (Int16 i = 0; i < num_fields; i++)
{
fd = new NpgsqlRowDescriptionFieldData();
fd.type_modifier = PGUtil.ReadInt32(input_stream, input_buffer);
fd.format_code = (FormatCode)PGUtil.ReadInt16(input_stream, input_buffer);
- fields_data.Add(fd);
- fields_index.Add(fd.name);
+ fields_data[i] = fd;
+ fields_index[i] = fd.name;
}
}
{
get
{
- return (NpgsqlRowDescriptionFieldData)fields_data[index];
+ return fields_data[index];
}
}
{
get
{
- return (Int16)fields_data.Count;
+ return (Int16)fields_data.Length;
}
}
public Int16 FieldIndex(String fieldName)
{
- Int16 result = -1;
-
- // First try to find the index with IndexOf (case-sensitive)
- result = (Int16)fields_index.IndexOf(fieldName);
-
- if (result > -1)
- {
- return result;
- }
- else
- {
-
- result = 0;
- foreach (String name in fields_index)
- {
-
- if (name.ToLower().Equals(fieldName.ToLower()))
- {
- return result;
- }
- result++;
- }
-
- }
+ // First try to find the index with IndexOf (case-sensitive)
+ Int16 result = (Int16)Array.IndexOf(fields_index, fieldName, 0, fields_index.Length);
+
+ if (result != -1)
+ {
+ return result;
+ }
+ else
+ {
+ foreach(string name in fields_index)
+ {
+ ++result;
+ if (string.Compare(name, fieldName, true) == 0)
+ return result;
+ }
+ }
throw new ArgumentOutOfRangeException("fieldName", fieldName, "Field name not found");
if (restrictions[i] != null && restrictions[i].Length != 0)
{
if (addWhere)
+ {
query.Append(" WHERE ");
+ addWhere = false;
+ }
query.AppendFormat("{0} = :{0}", names[i]);
command.Parameters.Add(new NpgsqlParameter(names[i], restrictions[i]));
private readonly String CLASSNAME = "NpgsqlState";
protected static ResourceManager resman = new ResourceManager(typeof(NpgsqlState));
+ internal NpgsqlState()
+ {
+ }
+
public virtual void Open(NpgsqlConnector context)
{
throw new InvalidOperationException("Internal Error! " + this);
Boolean readyForQuery = false;
+ byte[] asciiRowBytes = new byte[300];
+ char[] asciiRowChars = new char[300];
+
while (!readyForQuery)
{
// Check the first Byte of response.
{
NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
error.ReadFromStream(stream, context.Encoding);
+ error.ErrorSql = mediator.SqlSent;
mediator.Errors.Add(error);
NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");
{
- NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion);
+ NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
asciiRow.ReadFromStream(stream, context.Encoding);
// Add this row to the rows array.
Boolean readyForQuery = false;
+ byte[] asciiRowBytes = new byte[300];
+ char[] asciiRowChars = new char[300];
+
while (!readyForQuery)
{
// Check the first Byte of response.
{
NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
error.ReadFromStream(stream, context.Encoding);
+ error.ErrorSql = mediator.SqlSent;
mediator.Errors.Add(error);
// This is the AsciiRow message.
NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "DataRow");
{
- NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion);
+ NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
asciiRow.ReadFromStream(stream, context.Encoding);
// Add this row to the rows array.
};
private static readonly String[] TimeFormats = new String[]
- {
- "HH:mm:ss.ffffff",
- "HH:mm:ss.fffff",
- "HH:mm:ss.ffff",
- "HH:mm:ss.fff",
- "HH:mm:ss.ff",
- "HH:mm:ss.f",
- "HH:mm:ss",
- "HH:mm:ss.ffffffzz",
- "HH:mm:ss.fffffzz",
- "HH:mm:ss.ffffzz",
- "HH:mm:ss.fffzz",
- "HH:mm:ss.ffzz",
- "HH:mm:ss.fzz",
- "HH:mm:sszz"
+ {
+ "HH:mm:ss.ffffff",
+ "HH:mm:ss",
+ "HH:mm:ss.ffffffzz",
+ "HH:mm:sszz",
+ "HH:mm:ss.fffff",
+ "HH:mm:ss.ffff",
+ "HH:mm:ss.fff",
+ "HH:mm:ss.ff",
+ "HH:mm:ss.f",
+ "HH:mm:ss.fffffzz",
+ "HH:mm:ss.ffffzz",
+ "HH:mm:ss.fffzz",
+ "HH:mm:ss.ffzz",
+ "HH:mm:ss.fzz",
};
private static readonly String[] DateTimeFormats = new String[]
- {
- "yyyy-MM-dd HH:mm:ss.ffffff",
- "yyyy-MM-dd HH:mm:ss.fffff",
- "yyyy-MM-dd HH:mm:ss.ffff",
- "yyyy-MM-dd HH:mm:ss.fff",
- "yyyy-MM-dd HH:mm:ss.ff",
- "yyyy-MM-dd HH:mm:ss.f",
- "yyyy-MM-dd HH:mm:ss",
- "yyyy-MM-dd HH:mm:ss.ffffffzz",
- "yyyy-MM-dd HH:mm:ss.fffffzz",
- "yyyy-MM-dd HH:mm:ss.ffffzz",
- "yyyy-MM-dd HH:mm:ss.fffzz",
- "yyyy-MM-dd HH:mm:ss.ffzz",
- "yyyy-MM-dd HH:mm:ss.fzz",
- "yyyy-MM-dd HH:mm:sszz"
+ {
+ "yyyy-MM-dd HH:mm:ss.ffffff",
+ "yyyy-MM-dd HH:mm:ss",
+ "yyyy-MM-dd HH:mm:ss.ffffffzz",
+ "yyyy-MM-dd HH:mm:sszz",
+ "yyyy-MM-dd HH:mm:ss.fffff",
+ "yyyy-MM-dd HH:mm:ss.ffff",
+ "yyyy-MM-dd HH:mm:ss.fff",
+ "yyyy-MM-dd HH:mm:ss.ff",
+ "yyyy-MM-dd HH:mm:ss.f",
+ "yyyy-MM-dd HH:mm:ss.fffffzz",
+ "yyyy-MM-dd HH:mm:ss.ffffzz",
+ "yyyy-MM-dd HH:mm:ss.fffzz",
+ "yyyy-MM-dd HH:mm:ss.ffzz",
+ "yyyy-MM-dd HH:mm:ss.fzz",
};
/// <summary>
NativeTypeMapping.AddType("refcursor", NpgsqlDbType.Refcursor, DbType.String, true, null);
- NativeTypeMapping.AddType("char", NpgsqlDbType.Char, DbType.String, true, null);
+ NativeTypeMapping.AddType("char", NpgsqlDbType.Char, DbType.String, true, null);
NativeTypeMapping.AddType("varchar", NpgsqlDbType.Varchar, DbType.String, true, null);