Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>2005-12-09 16:13:36 +0300
committerFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>2005-12-09 16:13:36 +0300
commit41ff85f532b26ae623e629e3c0068cd45656db93 (patch)
tree47b77f0ccffc962380baba6f8147416897850632 /mcs/class/Npgsql
parent3a0beb268ee7984f492320e4f386f7922f40a452 (diff)
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 svn path=/trunk/mcs/; revision=54161
Diffstat (limited to 'mcs/class/Npgsql')
-rw-r--r--mcs/class/Npgsql/ChangeLog29
-rwxr-xr-xmcs/class/Npgsql/Makefile1
-rw-r--r--mcs/class/Npgsql/Npgsql.dll.resources1
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs182
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs6
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs32
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs112
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs43
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnectionString.cs42
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs5
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs70
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs183
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlError.cs37
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs13
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlException.cs12
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs33
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs25
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs5
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs6
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs60
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs3
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlState.cs16
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs60
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs2
24 files changed, 673 insertions, 305 deletions
diff --git a/mcs/class/Npgsql/ChangeLog b/mcs/class/Npgsql/ChangeLog
index b3251478d63..5259d5bfc99 100644
--- a/mcs/class/Npgsql/ChangeLog
+++ b/mcs/class/Npgsql/ChangeLog
@@ -1,4 +1,33 @@
+
+
+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!
diff --git a/mcs/class/Npgsql/Makefile b/mcs/class/Npgsql/Makefile
index 34a9158755b..9a4d68dd120 100755
--- a/mcs/class/Npgsql/Makefile
+++ b/mcs/class/Npgsql/Makefile
@@ -52,6 +52,7 @@ RESX_RES = \
Npgsql/NpgsqlEventLog.resources \
Npgsql/NpgsqlException.resources \
Npgsql/PGUtil.resources \
+ Npgsql/NpgsqlConnectionString.resources \
NpgsqlTypes/NpgsqlTypesHelper.resources
include ../../build/library.make
diff --git a/mcs/class/Npgsql/Npgsql.dll.resources b/mcs/class/Npgsql/Npgsql.dll.resources
index 0b1671a6681..95a224c5da7 100644
--- a/mcs/class/Npgsql/Npgsql.dll.resources
+++ b/mcs/class/Npgsql/Npgsql.dll.resources
@@ -10,6 +10,7 @@
-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
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs b/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs
index 5ede3256fc0..d5ccfc8bb4c 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs
@@ -44,11 +44,15 @@ namespace Npgsql
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)
@@ -70,7 +74,6 @@ namespace Npgsql
{
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);
@@ -79,9 +82,6 @@ namespace Npgsql
// 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 );
@@ -98,44 +98,15 @@ namespace Npgsql
// 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));
}
}
@@ -144,79 +115,36 @@ namespace Npgsql
{
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));
+ }
}
}
@@ -233,5 +161,43 @@ namespace Npgsql
// 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);
+ }
+ }
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs
index 57d0519b2c3..2376422fec0 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs
@@ -35,7 +35,7 @@ namespace Npgsql
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()
@@ -45,10 +45,6 @@ namespace Npgsql
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Instance");
- if (_instance == null)
- {
- _instance = new NpgsqlClosedState();
- }
return _instance;
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs b/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
index 285891d55a1..77a86d9abe8 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
@@ -251,7 +251,7 @@ namespace Npgsql
internal NpgsqlConnector Connector {
get
{
- if (connector == null && this.connection != null)
+ if (this.connection != null)
connector = this.connection.Connector;
return connector;
@@ -813,6 +813,8 @@ namespace Npgsql
result = AddSingleRowBehaviorSupport(result);
+
+ result = AddSchemaOnlyBehaviorSupport(result);
return result;
}
@@ -912,7 +914,11 @@ namespace Npgsql
return ProcessRefcursorFunctionReturn(result);
- return AddSingleRowBehaviorSupport(result);
+ result = AddSingleRowBehaviorSupport(result);
+
+ result = AddSchemaOnlyBehaviorSupport(result);
+
+ return result;
}
@@ -1226,7 +1232,7 @@ namespace Npgsql
ResultCommandText = ResultCommandText.Trim();
- if ((commandBehavior & CommandBehavior.SingleRow) > 0)
+ if ((commandBehavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow)
{
if (ResultCommandText.EndsWith(";"))
ResultCommandText = ResultCommandText.Substring(0, ResultCommandText.Length - 1);
@@ -1239,6 +1245,24 @@ namespace Npgsql
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;
+
+ }
private void ExecuteCommand()
@@ -1247,7 +1271,7 @@ namespace Npgsql
CheckConnectionState();
// reset any responses just before getting new ones
- connector.Mediator.ResetResponses();
+ Connector.Mediator.ResetResponses();
if (parse == null)
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs b/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs
index cab07a1b4f0..1d1d67441cd 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs
@@ -1,9 +1,9 @@
// 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
@@ -29,6 +29,7 @@ using System;
using System.Data;
using System.Data.Common;
using System.ComponentModel;
+using NpgsqlTypes;
namespace Npgsql
{
@@ -49,6 +50,9 @@ namespace Npgsql
private string table_name = String.Empty;
+ private string quotePrefix = "\"";
+ private string quoteSuffix = "\"";
+
public NpgsqlCommandBuilder ()
{}
@@ -88,18 +92,19 @@ namespace Npgsql
}
}
- 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;
@@ -126,26 +131,77 @@ namespace Npgsql
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)
{
@@ -161,17 +217,17 @@ namespace Npgsql
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);
@@ -195,17 +251,17 @@ namespace Npgsql
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;
@@ -213,7 +269,7 @@ namespace Npgsql
}
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;
@@ -237,16 +293,16 @@ namespace Npgsql
{
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;
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
index df737229a84..15d74f54240 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
@@ -140,18 +140,19 @@ namespace Npgsql
/// <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
@@ -229,6 +230,24 @@ namespace Npgsql
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.
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnectionString.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnectionString.cs
index 820726ac4fa..c054add865f 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnectionString.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnectionString.cs
@@ -376,21 +376,22 @@ namespace Npgsql
/// </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
@@ -431,12 +432,13 @@ namespace Npgsql
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
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
index f4b730f7ffa..732da5507fe 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
@@ -252,7 +252,8 @@ namespace Npgsql
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();
@@ -279,7 +280,7 @@ namespace Npgsql
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;
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
index 91567f215bf..dac1c40aed1 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
@@ -26,6 +26,7 @@
using System;
using System.Collections;
using System.Threading;
+using System.Timers;
namespace Npgsql
{
@@ -44,6 +45,10 @@ 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
@@ -53,9 +58,63 @@ namespace Npgsql
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.
@@ -69,6 +128,12 @@ namespace Npgsql
// 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.
@@ -240,6 +305,8 @@ namespace Npgsql
if (Queue == null)
{
Queue = new ConnectorQueue();
+ Queue.ConnectionLifeTime = Connection.ConnectionLifeTime;
+ Queue.MinPoolSize = Connection.MinPoolSize;
PooledConnectors[Connection.ConnectionString.ToString()] = Queue;
}
@@ -258,7 +325,8 @@ namespace Npgsql
break;
}
- Queue.UseCount--;
+ // Don't need - we dequeue connector = decrease Queue.Count.
+ //Queue.UseCount--;
if (Queue.Count <= 0)
return GetPooledConnector(Connection);
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs b/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs
index 70fc86dc07c..a9fdd6eda10 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs
@@ -248,6 +248,7 @@ namespace Npgsql
/// </summary>
public DataTable GetSchemaTable()
{
+
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetSchemaTable");
if(_currentResultsetSchema == null)
@@ -291,6 +292,7 @@ namespace Npgsql
/// <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");
@@ -698,7 +700,13 @@ namespace Npgsql
{
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++)
@@ -750,31 +758,39 @@ namespace Npgsql
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"))
@@ -793,8 +809,8 @@ namespace Npgsql
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];
@@ -807,14 +823,14 @@ namespace Npgsql
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;
@@ -868,7 +884,104 @@ namespace Npgsql
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)
{
@@ -896,6 +1009,19 @@ namespace Npgsql
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
@@ -973,6 +1099,7 @@ namespace Npgsql
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()
@@ -981,8 +1108,8 @@ namespace Npgsql
// 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)
{
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlError.cs b/mcs/class/Npgsql/Npgsql/NpgsqlError.cs
index ac9eefef768..c428b2b52cd 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlError.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlError.cs
@@ -55,16 +55,17 @@ namespace Npgsql
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.
@@ -175,7 +176,21 @@ namespace Npgsql
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>
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs b/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs
index b1a28bbe670..e50d070cae6 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs
@@ -151,13 +151,16 @@ namespace Npgsql
{
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();
+ }
}
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlException.cs b/mcs/class/Npgsql/Npgsql/NpgsqlException.cs
index 8f5d4950b98..7b28fe4e898 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlException.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlException.cs
@@ -204,6 +204,18 @@ namespace Npgsql
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.
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs b/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs
index ea7ff00ad15..0e08e15358e 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs
@@ -49,15 +49,17 @@ namespace Npgsql
//
// 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()
{
@@ -70,6 +72,7 @@ namespace Npgsql
_notifications = new ArrayList();
_parameters = new ListDictionary(CaseInsensitiveComparer.Default);
_backend_key_data = null;
+ _sqlSent = String.Empty;
}
public void ResetExpectations()
@@ -86,6 +89,7 @@ namespace Npgsql
_notifications.Clear();
_parameters.Clear();
_backend_key_data = null;
+ _sqlSent = String.Empty;
}
@@ -168,6 +172,19 @@ namespace Npgsql
return _backend_key_data;
}
}
+
+ public String SqlSent
+ {
+ set
+ {
+ _sqlSent = value;
+ }
+
+ get
+ {
+ return _sqlSent;
+ }
+ }
public void AddNotification(NpgsqlNotificationEventArgs data)
{
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs b/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs
index cb0db918804..819a3fb9eb6 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs
@@ -65,7 +65,8 @@ namespace Npgsql
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.
@@ -74,7 +75,7 @@ namespace Npgsql
{
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>
@@ -114,10 +115,26 @@ namespace Npgsql
{
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.
@@ -354,6 +371,8 @@ namespace Npgsql
{
get
{
+ if (type_info == null)
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
return type_info;
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs b/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs
index e73110f33df..a8818ea89b0 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs
@@ -49,6 +49,11 @@ namespace Npgsql
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');
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs
index 319eb1e07b7..faf89c545c9 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs
@@ -34,7 +34,7 @@ namespace Npgsql
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.
@@ -51,10 +51,6 @@ namespace Npgsql
{
get
{
- if ( _instance == null )
- {
- _instance = new NpgsqlReadyState();
- }
return _instance;
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs b/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs
index fecf3371f52..fab11b32f4b 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs
@@ -64,8 +64,8 @@ namespace Npgsql
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;
@@ -103,6 +103,8 @@ namespace Npgsql
// 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++)
{
@@ -120,9 +122,9 @@ namespace Npgsql
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;
}
}
@@ -140,6 +142,8 @@ namespace Npgsql
// 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();
@@ -153,8 +157,8 @@ namespace Npgsql
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;
}
}
@@ -162,7 +166,7 @@ namespace Npgsql
{
get
{
- return (NpgsqlRowDescriptionFieldData)fields_data[index];
+ return fields_data[index];
}
}
@@ -170,36 +174,28 @@ namespace Npgsql
{
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");
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs b/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs
index d3fd36a8bcf..ff45da474dc 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs
@@ -111,7 +111,10 @@ namespace Npgsql
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]));
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlState.cs
index 2f6abc49ce7..c579fa9b85b 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlState.cs
@@ -45,6 +45,10 @@ namespace Npgsql
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);
@@ -158,6 +162,9 @@ namespace Npgsql
Boolean readyForQuery = false;
+ byte[] asciiRowBytes = new byte[300];
+ char[] asciiRowChars = new char[300];
+
while (!readyForQuery)
{
// Check the first Byte of response.
@@ -168,6 +175,7 @@ namespace Npgsql
{
NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
error.ReadFromStream(stream, context.Encoding);
+ error.ErrorSql = mediator.SqlSent;
mediator.Errors.Add(error);
@@ -300,7 +308,7 @@ namespace Npgsql
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.
@@ -425,6 +433,9 @@ namespace Npgsql
Boolean readyForQuery = false;
+ byte[] asciiRowBytes = new byte[300];
+ char[] asciiRowChars = new char[300];
+
while (!readyForQuery)
{
// Check the first Byte of response.
@@ -436,6 +447,7 @@ namespace Npgsql
{
NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
error.ReadFromStream(stream, context.Encoding);
+ error.ErrorSql = mediator.SqlSent;
mediator.Errors.Add(error);
@@ -566,7 +578,7 @@ namespace Npgsql
// 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.
diff --git a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs
index 50d53d7d8be..c50e260e7fd 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs
@@ -47,39 +47,39 @@ namespace NpgsqlTypes
};
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>
diff --git a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
index fe58fbeb526..6f3e1777c80 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
@@ -169,7 +169,7 @@ namespace NpgsqlTypes
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);