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>2008-11-06 06:08:03 +0300
committerFrancisco Figueiredo Jr. <fxjr@mono-cvs.ximian.com>2008-11-06 06:08:03 +0300
commita3bc867dd9c3237bfac9f359a35f04d03256d109 (patch)
tree5347626555ca06711601d00ff3d86dcde7ed997f /mcs/class/Npgsql
parent7b867dfd1859e28eef7b42f5c7f3dcb559c67aa3 (diff)
2008-11-06 Francisco Figueiredo Jr. <francisco@npgsql.org>
Reverted last update because it broke the svn trunk. svn path=/trunk/mcs/; revision=118072
Diffstat (limited to 'mcs/class/Npgsql')
-rw-r--r--mcs/class/Npgsql/ChangeLog4
-rwxr-xr-xmcs/class/Npgsql/Makefile1
-rwxr-xr-xmcs/class/Npgsql/Npgsql.dll.sources22
-rw-r--r--mcs/class/Npgsql/Npgsql/HashAlgorithm.cs396
-rw-r--r--mcs/class/Npgsql/Npgsql/MD5.cs84
-rw-r--r--mcs/class/Npgsql/Npgsql/MD5CryptoServiceProvider.cs933
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs376
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlBackEndKeyData.cs114
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlBind.cs366
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlCancelRequest.cs98
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs286
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs1327
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs706
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnectedState.cs110
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs1776
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs876
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs1133
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlDataAdapter.cs439
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs2404
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlDescribe.cs95
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlError.cs634
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs647
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlException.cs480
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlExecute.cs96
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlFlush.cs71
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs335
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlMessageTypes.cs162
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlNotificationEventArgs.cs76
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs409
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlParameter.resx5
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlParameterCollection.cs988
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlParameterStatus.cs103
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlParse.cs135
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlPasswordPacket.cs131
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs99
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs282
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlRow.cs519
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs417
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs554
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlStartupPacket.cs211
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlStartupState.cs85
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlState.cs1358
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlState.resx16
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlSync.cs71
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlTransaction.cs212
-rw-r--r--mcs/class/Npgsql/Npgsql/NpgsqlTransaction.resx8
-rw-r--r--mcs/class/Npgsql/Npgsql/PGUtil.cs1089
-rw-r--r--mcs/class/Npgsql/Npgsql/PGUtil.resx134
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/FastPath.cs709
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs163
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs317
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs270
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/NpgsqlDbType.cs105
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs1141
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypes.cs707
-rw-r--r--mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs2046
56 files changed, 12141 insertions, 14190 deletions
diff --git a/mcs/class/Npgsql/ChangeLog b/mcs/class/Npgsql/ChangeLog
index f5099b6d136..6d3ec4026af 100644
--- a/mcs/class/Npgsql/ChangeLog
+++ b/mcs/class/Npgsql/ChangeLog
@@ -1,4 +1,8 @@
2008-11-05 Francisco Figueiredo Jr. <francisco@npgsql.org>
+
+ Undone update as it breaks the svn tree.
+
+2008-11-05 Francisco Figueiredo Jr. <francisco@npgsql.org>
Updated Npgsql to Npgsql2 2.0.1. Now Npgsql requires .Net 2.0 or above
diff --git a/mcs/class/Npgsql/Makefile b/mcs/class/Npgsql/Makefile
index f05c133588d..1dafe2da7d1 100755
--- a/mcs/class/Npgsql/Makefile
+++ b/mcs/class/Npgsql/Makefile
@@ -9,7 +9,6 @@ LIBRARY_SNK = Npgsql/Npgsql.snk
LIB_MCS_FLAGS = /r:$(corlib) /r:System.dll /r:System.Xml.dll \
/r:System.Data.dll \
/r:Mono.Security.dll \
- /r:System.Transactions.dll \
@Npgsql.dll.resources
TEST_MCS_FLAGS = /r:$(corlib) /r:System.dll /r:System.Xml.dll \
diff --git a/mcs/class/Npgsql/Npgsql.dll.sources b/mcs/class/Npgsql/Npgsql.dll.sources
index a866a3dba22..29c1d0c19e8 100755
--- a/mcs/class/Npgsql/Npgsql.dll.sources
+++ b/mcs/class/Npgsql/Npgsql.dll.sources
@@ -1,30 +1,22 @@
Npgsql/AssemblyInfo.cs
../../build/common/Consts.cs
-Npgsql/Cache.cs
Npgsql/HashAlgorithm.cs
Npgsql/MD5.cs
Npgsql/MD5CryptoServiceProvider.cs
Npgsql/NpgsqlAsciiRow.cs
Npgsql/NpgsqlBackEndKeyData.cs
Npgsql/NpgsqlBind.cs
+Npgsql/NpgsqlBinaryRow.cs
Npgsql/NpgsqlCancelRequest.cs
Npgsql/NpgsqlClosedState.cs
Npgsql/NpgsqlCommand.cs
Npgsql/NpgsqlCommandBuilder.cs
Npgsql/NpgsqlConnectedState.cs
Npgsql/NpgsqlConnection.cs
-Npgsql/NpgsqlConnectionStringBuilder.cs
+Npgsql/NpgsqlConnectionString.cs
Npgsql/NpgsqlConnector.cs
Npgsql/NpgsqlConnectorPool.cs
-Npgsql/NpgsqlCopyFormat.cs
-Npgsql/NpgsqlCopyIn.cs
-Npgsql/NpgsqlCopyInState.cs
-Npgsql/NpgsqlCopyInStream.cs
-Npgsql/NpgsqlCopyOut.cs
-Npgsql/NpgsqlCopyOutState.cs
-Npgsql/NpgsqlCopyOutStream.cs
-Npgsql/NpgsqlCopySerializer.cs
Npgsql/NpgsqlDataAdapter.cs
Npgsql/NpgsqlDataReader.cs
Npgsql/NpgsqlDescribe.cs
@@ -32,7 +24,6 @@ Npgsql/NpgsqlError.cs
Npgsql/NpgsqlEventLog.cs
Npgsql/NpgsqlException.cs
Npgsql/NpgsqlExecute.cs
-Npgsql/NpgsqlFactory.cs
Npgsql/NpgsqlFlush.cs
Npgsql/NpgsqlMediator.cs
Npgsql/NpgsqlMessageTypes.cs
@@ -42,27 +33,20 @@ Npgsql/NpgsqlParameterCollection.cs
Npgsql/NpgsqlParameterStatus.cs
Npgsql/NpgsqlParse.cs
Npgsql/NpgsqlPasswordPacket.cs
-Npgsql/NpgsqlPromotableSinglePhaseNotification.cs
-Npgsql/NpgsqlProviderManifest.cs
Npgsql/NpgsqlQuery.cs
Npgsql/NpgsqlReadyState.cs
-Npgsql/NpgsqlResourceManager.cs
+Npgsql/NpgsqlResultSet.cs
Npgsql/NpgsqlRow.cs
Npgsql/NpgsqlRowDescription.cs
Npgsql/NpgsqlSchema.cs
-Npgsql/NpgsqlServices.cs
Npgsql/NpgsqlStartupPacket.cs
Npgsql/NpgsqlStartupState.cs
Npgsql/NpgsqlState.cs
Npgsql/NpgsqlSync.cs
Npgsql/NpgsqlTransaction.cs
-Npgsql/NpgsqlTransactionCallbacks.cs
Npgsql/PGUtil.cs
-Npgsql/SSPIHandler.cs
-NpgsqlTypes/ArrayHandling.cs
NpgsqlTypes/LargeObjectManager.cs
-NpgsqlTypes/DateDatatypes.cs
NpgsqlTypes/NpgsqlDbType.cs
NpgsqlTypes/FastPath.cs
NpgsqlTypes/NpgsqlTypeConverters.cs
diff --git a/mcs/class/Npgsql/Npgsql/HashAlgorithm.cs b/mcs/class/Npgsql/Npgsql/HashAlgorithm.cs
index f624ee68c9b..ad05a0ef0db 100644
--- a/mcs/class/Npgsql/Npgsql/HashAlgorithm.cs
+++ b/mcs/class/Npgsql/Npgsql/HashAlgorithm.cs
@@ -16,95 +16,98 @@
using System;
using System.IO;
+
namespace Npgsql
{
- // Comment: Removed the ICryptoTransform implementation as this interface may be not supported by
- // all platforms.
-
- internal abstract class HashAlgorithm : IDisposable
- {
- protected byte[] HashValue; // Caches the hash after it is calculated. Accessed through the Hash property.
- protected int HashSizeValue; // The size of the hash in bits.
- protected int State; // nonzero when in use; zero when not in use
- private bool disposed;
-
- /// <summary>
- /// Called from constructor of derived class.
- /// </summary>
- protected HashAlgorithm()
- {
- disposed = false;
- }
-
- /// <summary>
- /// Finalizer for HashAlgorithm
- /// </summary>
- ~HashAlgorithm()
- {
- Dispose(false);
- }
-
- /// <summary>
- /// Get whether or not the hash can transform multiple blocks at a time.
- /// Note: MUST be overriden if descendant can transform multiple block
- /// on a single call!
- /// </summary>
- public virtual bool CanTransformMultipleBlocks
- {
- get { return true; }
- }
-
- public virtual bool CanReuseTransform
- {
- get { return true; }
- }
-
- public void Clear()
- {
- // same as System.IDisposable.Dispose() which is documented
- Dispose(true);
- }
-
- /// <summary>
- /// Computes the entire hash of all the bytes in the byte array.
- /// </summary>
- public byte[] ComputeHash(byte[] input)
- {
- return ComputeHash(input, 0, input.Length);
- }
-
- public byte[] ComputeHash(byte[] buffer, int offset, int count)
- {
- if (disposed)
- {
- throw new ObjectDisposedException("HashAlgorithm");
- }
-
- HashCore(buffer, offset, count);
- HashValue = HashFinal();
- Initialize();
-
- return HashValue;
- }
-
- public byte[] ComputeHash(Stream inputStream)
- {
- // don't read stream unless object is ready to use
- if (disposed)
- {
- throw new ObjectDisposedException("HashAlgorithm");
- }
-
- int l = (int) (inputStream.Length - inputStream.Position);
- byte[] buffer = new byte[l];
- inputStream.Read(buffer, 0, l);
-
- return ComputeHash(buffer, 0, l);
- }
-
- // Commented out because it uses the CryptoConfig which can't be available in all platforms
-
- /*
+
+
+ // Comment: Removed the ICryptoTransform implementation as this interface may be not supported by
+ // all platforms.
+
+ internal abstract class HashAlgorithm : IDisposable
+ {
+ protected byte[] HashValue; // Caches the hash after it is calculated. Accessed through the Hash property.
+ protected int HashSizeValue; // The size of the hash in bits.
+ protected int State; // nonzero when in use; zero when not in use
+ private bool disposed;
+
+ /// <summary>
+ /// Called from constructor of derived class.
+ /// </summary>
+ protected HashAlgorithm ()
+ {
+ disposed = false;
+ }
+
+ /// <summary>
+ /// Finalizer for HashAlgorithm
+ /// </summary>
+ ~HashAlgorithm ()
+ {
+ Dispose(false);
+ }
+
+ /// <summary>
+ /// Get whether or not the hash can transform multiple blocks at a time.
+ /// Note: MUST be overriden if descendant can transform multiple block
+ /// on a single call!
+ /// </summary>
+ public virtual bool CanTransformMultipleBlocks {
+ get
+ {
+ return true;
+ }
+ }
+
+ public virtual bool CanReuseTransform {
+ get
+ {
+ return true;
+ }
+ }
+
+ public void Clear()
+ {
+ // same as System.IDisposable.Dispose() which is documented
+ Dispose (true);
+ }
+
+ /// <summary>
+ /// Computes the entire hash of all the bytes in the byte array.
+ /// </summary>
+ public byte[] ComputeHash (byte[] input)
+ {
+ return ComputeHash (input, 0, input.Length);
+ }
+
+ public byte[] ComputeHash (byte[] buffer, int offset, int count)
+ {
+ if (disposed)
+ throw new ObjectDisposedException ("HashAlgorithm");
+
+ HashCore (buffer, offset, count);
+ HashValue = HashFinal ();
+ Initialize ();
+
+ return HashValue;
+ }
+
+ public byte[] ComputeHash (Stream inputStream)
+ {
+ // don't read stream unless object is ready to use
+ if (disposed)
+ throw new ObjectDisposedException ("HashAlgorithm");
+
+ int l = (int) (inputStream.Length - inputStream.Position);
+ byte[] buffer = new byte [l];
+ inputStream.Read (buffer, 0, l);
+
+ return ComputeHash (buffer, 0, l);
+ }
+
+ // Commented out because it uses the CryptoConfig which can't be available in all platforms
+
+ /*
/// <summary>
/// Creates the default implementation of the default hash algorithm (SHA1).
/// </summary>
@@ -113,7 +116,7 @@ namespace Npgsql
return Create ("System.Security.Cryptography.HashAlgorithm");
}*/
- /*
+ /*
/// <summary>
/// Creates a specific implementation of the general hash idea.
/// </summary>
@@ -124,109 +127,114 @@ namespace Npgsql
}*/
- // Changed Exception type because it uses the CryptographicUnexpectedOperationException
- // which can't be available in all platforms.
- /// <summary>
- /// Gets the previously computed hash.
- /// </summary>
- public virtual byte[] Hash
- {
- get
- {
- if (HashValue == null)
- {
- throw new NullReferenceException("HashValue is null");
- }
- return HashValue;
- }
- }
-
- /// <summary>
- /// When overridden in a derived class, drives the hashing function.
- /// </summary>
- /// <param name="rgb"></param>
- /// <param name="start"></param>
- /// <param name="size"></param>
- protected abstract void HashCore(byte[] rgb, int start, int size);
-
- /// <summary>
- /// When overridden in a derived class, this pads and hashes whatever data might be left in the buffers and then returns the hash created.
- /// </summary>
- protected abstract byte[] HashFinal();
-
- /// <summary>
- /// Returns the size in bits of the hash.
- /// </summary>
- public virtual int HashSize
- {
- get { return HashSizeValue; }
- }
-
- /// <summary>
- /// When overridden in a derived class, initializes the object to prepare for hashing.
- /// </summary>
- public abstract void Initialize();
-
- protected virtual void Dispose(bool disposing)
- {
- disposed = true;
- }
-
- /// <summary>
- /// Must be overriden if not 1
- /// </summary>
- public virtual int InputBlockSize
- {
- get { return 1; }
- }
-
- /// <summary>
- /// Must be overriden if not 1
- /// </summary>
- public virtual int OutputBlockSize
- {
- get { return 1; }
- }
-
- void IDisposable.Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this); // Finalization is now unnecessary
- }
-
- /// <summary>
- /// Used for stream chaining. Computes hash as data passes through it.
- /// </summary>
- /// <param name="inputBuffer">The buffer from which to grab the data to be copied.</param>
- /// <param name="inputOffset">The offset into the input buffer to start reading at.</param>
- /// <param name="inputCount">The number of bytes to be copied.</param>
- /// <param name="outputBuffer">The buffer to write the copied data to.</param>
- /// <param name="outputOffset">At what point in the outputBuffer to write the data at.</param>
- public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
- {
- Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
- HashCore(inputBuffer, inputOffset, inputCount);
-
- return inputCount;
- }
-
- /// <summary>
- /// Used for stream chaining. Computes hash as data passes through it. Finishes off the hash.
- /// </summary>
- /// <param name="inputBuffer">The buffer from which to grab the data to be copied.</param>
- /// <param name="inputOffset">The offset into the input buffer to start reading at.</param>
- /// <param name="inputCount">The number of bytes to be copied.</param>
- public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
- {
- byte[] outputBuffer = new byte[inputCount];
-
- Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, 0, inputCount);
-
- HashCore(inputBuffer, inputOffset, inputCount);
- HashValue = HashFinal();
- Initialize();
-
- return outputBuffer;
- }
- }
-} \ No newline at end of file
+
+ // Changed Exception type because it uses the CryptographicUnexpectedOperationException
+ // which can't be available in all platforms.
+ /// <summary>
+ /// Gets the previously computed hash.
+ /// </summary>
+ public virtual byte[] Hash {
+ get
+ {
+ if (HashValue == null)
+ throw new NullReferenceException("HashValue is null");
+ return HashValue;
+ }
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, drives the hashing function.
+ /// </summary>
+ /// <param name="rgb"></param>
+ /// <param name="start"></param>
+ /// <param name="size"></param>
+ protected abstract void HashCore (byte[] rgb, int start, int size);
+
+ /// <summary>
+ /// When overridden in a derived class, this pads and hashes whatever data might be left in the buffers and then returns the hash created.
+ /// </summary>
+ protected abstract byte[] HashFinal ();
+
+ /// <summary>
+ /// Returns the size in bits of the hash.
+ /// </summary>
+ public virtual int HashSize {
+ get
+ {
+ return HashSizeValue;
+ }
+ }
+
+ /// <summary>
+ /// When overridden in a derived class, initializes the object to prepare for hashing.
+ /// </summary>
+ public abstract void Initialize ();
+
+ protected virtual void Dispose (bool disposing)
+ {
+ disposed = true;
+ }
+
+ /// <summary>
+ /// Must be overriden if not 1
+ /// </summary>
+ public virtual int InputBlockSize {
+ get
+ {
+ return 1;
+ }
+ }
+
+ /// <summary>
+ /// Must be overriden if not 1
+ /// </summary>
+ public virtual int OutputBlockSize {
+ get
+ {
+ return 1;
+ }
+ }
+
+ void IDisposable.Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this); // Finalization is now unnecessary
+ }
+
+ /// <summary>
+ /// Used for stream chaining. Computes hash as data passes through it.
+ /// </summary>
+ /// <param name="inputBuffer">The buffer from which to grab the data to be copied.</param>
+ /// <param name="inputOffset">The offset into the input buffer to start reading at.</param>
+ /// <param name="inputCount">The number of bytes to be copied.</param>
+ /// <param name="outputBuffer">The buffer to write the copied data to.</param>
+ /// <param name="outputOffset">At what point in the outputBuffer to write the data at.</param>
+ public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+ {
+ Buffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
+ HashCore (inputBuffer, inputOffset, inputCount);
+
+ return inputCount;
+ }
+
+ /// <summary>
+ /// Used for stream chaining. Computes hash as data passes through it. Finishes off the hash.
+ /// </summary>
+ /// <param name="inputBuffer">The buffer from which to grab the data to be copied.</param>
+ /// <param name="inputOffset">The offset into the input buffer to start reading at.</param>
+ /// <param name="inputCount">The number of bytes to be copied.</param>
+ public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ byte[] outputBuffer = new byte[inputCount];
+
+ Buffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, 0, inputCount);
+
+ HashCore (inputBuffer, inputOffset, inputCount);
+ HashValue = HashFinal ();
+ Initialize ();
+
+ return outputBuffer;
+ }
+ }
+
+}
diff --git a/mcs/class/Npgsql/Npgsql/MD5.cs b/mcs/class/Npgsql/Npgsql/MD5.cs
index 628a2030311..7391466adc3 100644
--- a/mcs/class/Npgsql/Npgsql/MD5.cs
+++ b/mcs/class/Npgsql/Npgsql/MD5.cs
@@ -4,25 +4,23 @@
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
+
//
// System.Security.Cryptography MD5 Class implementation
//
@@ -40,32 +38,37 @@
//
+
+
+
namespace Npgsql
{
- /// <summary>
- /// Common base class for all derived MD5 implementations.
- /// </summary>
- internal abstract class MD5 : HashAlgorithm
- {
- /// <summary>
- /// Called from constructor of derived class.
- /// </summary>
- // Why is it protected when others abstract hash classes are public ?
- protected MD5()
- {
- HashSizeValue = 128;
- }
- /// <summary>
- /// Creates the default derived class.
- /// </summary>
- public static MD5 Create()
- {
- //return Create ("System.Security.Cryptography.MD5");
- return new MD5CryptoServiceProvider();
- }
- /*
+ /// <summary>
+ /// Common base class for all derived MD5 implementations.
+ /// </summary>
+ internal abstract class MD5 : HashAlgorithm
+ {
+ /// <summary>
+ /// Called from constructor of derived class.
+ /// </summary>
+ // Why is it protected when others abstract hash classes are public ?
+ protected MD5 ()
+ {
+ HashSizeValue = 128;
+ }
+
+ /// <summary>
+ /// Creates the default derived class.
+ /// </summary>
+ public static MD5 Create ()
+ {
+ //return Create ("System.Security.Cryptography.MD5");
+ return new MD5CryptoServiceProvider();
+ }
+
+ /*
// Commented out because it uses the CryptoConfig which can't be available in all
// platforms.
/// <summary>
@@ -76,5 +79,6 @@ namespace Npgsql
{
return (MD5) CryptoConfig.CreateFromName (hashName);
}*/
- }
-} \ No newline at end of file
+
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/MD5CryptoServiceProvider.cs b/mcs/class/Npgsql/Npgsql/MD5CryptoServiceProvider.cs
index ced30403391..06ebc4d1f0c 100644
--- a/mcs/class/Npgsql/Npgsql/MD5CryptoServiceProvider.cs
+++ b/mcs/class/Npgsql/Npgsql/MD5CryptoServiceProvider.cs
@@ -14,549 +14,508 @@
using System;
+
namespace Npgsql
{
- /// <summary>
- /// C# implementation of the MD5 cryptographic hash function.
- /// </summary>
+ /// <summary>
+ /// C# implementation of the MD5 cryptographic hash function.
+ /// </summary>
#if USE_VERSION_1_0
internal class MD5CryptoServiceProvider : MD5
{
#else
- internal sealed class MD5CryptoServiceProvider : MD5
- {
+ internal sealed class MD5CryptoServiceProvider : MD5
+ {
#endif
- private const int BLOCK_SIZE_BYTES = 64;
- private const int HASH_SIZE_BYTES = 16;
- private const int HASH_SIZE_BITS = 128;
- private readonly uint[] _H;
- private uint count;
- private readonly byte[] _ProcessingBuffer; // Used to start data when passed less than a block worth.
- private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
-
- /// <summary>
- /// Creates a new MD5CryptoServiceProvider.
- /// </summary>
- public MD5CryptoServiceProvider()
- {
- _H = new uint[4];
- HashSizeValue = HASH_SIZE_BITS;
- _ProcessingBuffer = new byte[BLOCK_SIZE_BYTES];
-
- Initialize();
- }
-
- ~MD5CryptoServiceProvider()
- {
- Dispose(false);
- }
-
- protected override void Dispose(bool disposing)
- {
- // nothing to do (managed implementation)
- }
-
- /// <summary>
- /// Drives the hashing function.
- /// </summary>
- /// <param name="rgb">Byte array containing the data to hash.</param>
- /// <param name="start">Where in the input buffer to start.</param>
- /// <param name="size">Size in bytes of the data in the buffer to hash.</param>
- protected override void HashCore(byte[] rgb, int start, int size)
- {
- int i;
- State = 1;
-
- if (_ProcessingBufferCount != 0)
- {
- if (size < (BLOCK_SIZE_BYTES - _ProcessingBufferCount))
- {
- Buffer.BlockCopy(rgb, start, _ProcessingBuffer, _ProcessingBufferCount, size);
- _ProcessingBufferCount += size;
- return;
- }
- else
- {
- i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
- Buffer.BlockCopy(rgb, start, _ProcessingBuffer, _ProcessingBufferCount, i);
- ProcessBlock(_ProcessingBuffer, 0);
- _ProcessingBufferCount = 0;
- start += i;
- size -= i;
- }
- }
-
- for (i = 0; i < size - size%BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES)
- {
- ProcessBlock(rgb, start + i);
- }
-
- if (size%BLOCK_SIZE_BYTES != 0)
- {
- Buffer.BlockCopy(rgb, size - size%BLOCK_SIZE_BYTES + start, _ProcessingBuffer, 0, size%BLOCK_SIZE_BYTES);
- _ProcessingBufferCount = size%BLOCK_SIZE_BYTES;
- }
- }
-
- /// <summary>
- /// This finalizes the hash. Takes the data from the chaining variables and returns it.
- /// </summary>
- protected override byte[] HashFinal()
- {
- byte[] hash = new byte[16];
- int i, j;
-
- ProcessFinalBlock(_ProcessingBuffer, 0, _ProcessingBufferCount);
-
- for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
- {
- hash[i*4 + j] = (byte) (_H[i] >> j*8);
- }
- }
-
- return hash;
- }
-
- /// <summary>
- /// Resets the class after use. Called automatically after hashing is done.
- /// </summary>
- public override void Initialize()
- {
- count = 0;
- _ProcessingBufferCount = 0;
-
- _H[0] = 0x67452301;
- _H[1] = 0xefcdab89;
- _H[2] = 0x98badcfe;
- _H[3] = 0x10325476;
- }
-
- /// <summary>
- /// This is the meat of the hash function. It is what processes each block one at a time.
- /// </summary>
- /// <param name="inputBuffer">Byte array to process data from.</param>
- /// <param name="inputOffset">Where in the byte array to start processing.</param>
- private void ProcessBlock(byte[] inputBuffer, int inputOffset)
- {
- uint[] buff = new uint[16];
- uint a, b, c, d;
- int i;
-
- count += BLOCK_SIZE_BYTES;
-
- for (i = 0; i < 16; i++)
- {
- buff[i] = (inputBuffer[inputOffset + 4*i]) | (((uint) (inputBuffer[inputOffset + 4*i + 1])) << 8) |
- (((uint) (inputBuffer[inputOffset + 4*i + 2])) << 16) |
- (((uint) (inputBuffer[inputOffset + 4*i + 3])) << 24);
- }
-
- a = _H[0];
- b = _H[1];
- c = _H[2];
- d = _H[3];
-
- // This function was unrolled because it seems to be doubling our performance with current compiler/VM.
- // Possibly roll up if this changes.
-
-
- // ---- Round 1 --------
-
- a += (((c ^ d) & b) ^ d) + (uint) Constants.C0 + buff[0];
- a = (a << 7) | (a >> 25);
- a += b;
-
- d += (((b ^ c) & a) ^ c) + (uint) Constants.C1 + buff[1];
- d = (d << 12) | (d >> 20);
- d += a;
-
- c += (((a ^ b) & d) ^ b) + (uint) Constants.C2 + buff[2];
- c = (c << 17) | (c >> 15);
- c += d;
-
- b += (((d ^ a) & c) ^ a) + (uint) Constants.C3 + buff[3];
- b = (b << 22) | (b >> 10);
- b += c;
-
- a += (((c ^ d) & b) ^ d) + (uint) Constants.C4 + buff[4];
- a = (a << 7) | (a >> 25);
- a += b;
-
- d += (((b ^ c) & a) ^ c) + (uint) Constants.C5 + buff[5];
- d = (d << 12) | (d >> 20);
- d += a;
-
- c += (((a ^ b) & d) ^ b) + (uint) Constants.C6 + buff[6];
- c = (c << 17) | (c >> 15);
- c += d;
-
- b += (((d ^ a) & c) ^ a) + (uint) Constants.C7 + buff[7];
- b = (b << 22) | (b >> 10);
- b += c;
-
- a += (((c ^ d) & b) ^ d) + (uint) Constants.C8 + buff[8];
- a = (a << 7) | (a >> 25);
- a += b;
-
- d += (((b ^ c) & a) ^ c) + (uint) Constants.C9 + buff[9];
- d = (d << 12) | (d >> 20);
- d += a;
+ private const int BLOCK_SIZE_BYTES = 64;
+ private const int HASH_SIZE_BYTES = 16;
+ private const int HASH_SIZE_BITS = 128;
+ [CLSCompliant(false)] private uint[] _H;
+ [CLSCompliant(false)] private uint count;
+ private byte[] _ProcessingBuffer; // Used to start data when passed less than a block worth.
+ private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
+
+ /// <summary>
+ /// Creates a new MD5CryptoServiceProvider.
+ /// </summary>
+ public MD5CryptoServiceProvider ()
+ {
+ _H = new uint[4];
+ HashSizeValue = HASH_SIZE_BITS;
+ _ProcessingBuffer = new byte[BLOCK_SIZE_BYTES];
+
+ Initialize();
+ }
+
+ ~MD5CryptoServiceProvider ()
+ {
+ Dispose (false);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ // nothing to do (managed implementation)
+ }
+
+ /// <summary>
+ /// Drives the hashing function.
+ /// </summary>
+ /// <param name="rgb">Byte array containing the data to hash.</param>
+ /// <param name="start">Where in the input buffer to start.</param>
+ /// <param name="size">Size in bytes of the data in the buffer to hash.</param>
+ protected override void HashCore (byte[] rgb, int start, int size)
+ {
+ int i;
+ State = 1;
+
+ if (_ProcessingBufferCount != 0)
+ {
+ if (size < (BLOCK_SIZE_BYTES - _ProcessingBufferCount))
+ {
+ System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, size);
+ _ProcessingBufferCount += size;
+ return;
+ }
+ else
+ {
+ i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
+ System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, i);
+ ProcessBlock (_ProcessingBuffer, 0);
+ _ProcessingBufferCount = 0;
+ start += i;
+ size -= i;
+ }
+ }
+
+ for (i=0; i<size-size%BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES)
+ {
+ ProcessBlock (rgb, start+i);
+ }
+
+ if (size%BLOCK_SIZE_BYTES != 0)
+ {
+ System.Buffer.BlockCopy (rgb, size-size%BLOCK_SIZE_BYTES+start, _ProcessingBuffer, 0, size%BLOCK_SIZE_BYTES);
+ _ProcessingBufferCount = size%BLOCK_SIZE_BYTES;
+ }
+ }
+
+ /// <summary>
+ /// This finalizes the hash. Takes the data from the chaining variables and returns it.
+ /// </summary>
+ protected override byte[] HashFinal ()
+ {
+ byte[] hash = new byte[16];
+ int i, j;
+
+ ProcessFinalBlock(_ProcessingBuffer, 0, _ProcessingBufferCount);
+
+ for (i=0; i<4; i++)
+ {
+ for (j=0; j<4; j++)
+ {
+ hash[i*4+j] = (byte)(_H[i] >> j*8);
+ }
+ }
+
+ return hash;
+ }
+
+ /// <summary>
+ /// Resets the class after use. Called automatically after hashing is done.
+ /// </summary>
+ public override void Initialize ()
+ {
+ count = 0;
+ _ProcessingBufferCount = 0;
+
+ _H[0] = 0x67452301;
+ _H[1] = 0xefcdab89;
+ _H[2] = 0x98badcfe;
+ _H[3] = 0x10325476;
+ }
+
+ /// <summary>
+ /// This is the meat of the hash function. It is what processes each block one at a time.
+ /// </summary>
+ /// <param name="inputBuffer">Byte array to process data from.</param>
+ /// <param name="inputOffset">Where in the byte array to start processing.</param>
+ private void ProcessBlock (byte[] inputBuffer, int inputOffset)
+ {
+ uint[] buff = new uint[16];
+ uint a, b, c, d;
+ int i;
+
+ count += BLOCK_SIZE_BYTES;
+
+ for (i=0; i<16; i++)
+ {
+ buff[i] = (uint)(inputBuffer[inputOffset+4*i])
+ | (((uint)(inputBuffer[inputOffset+4*i+1])) << 8)
+ | (((uint)(inputBuffer[inputOffset+4*i+2])) << 16)
+ | (((uint)(inputBuffer[inputOffset+4*i+3])) << 24);
+ }
+
+ a = _H[0];
+ b = _H[1];
+ c = _H[2];
+ d = _H[3];
+
+ // This function was unrolled because it seems to be doubling our performance with current compiler/VM.
+ // Possibly roll up if this changes.
+
+
+ // ---- Round 1 --------
+
+ a += (((c ^ d) & b) ^ d) + (uint) Constants.C0 + buff [0];
+ a = (a << 7) | (a >> 25);
+ a += b;
+
+ d += (((b ^ c) & a) ^ c) + (uint) Constants.C1 + buff [1];
+ d = (d << 12) | (d >> 20);
+ d += a;
+
+ c += (((a ^ b) & d) ^ b) + (uint) Constants.C2 + buff [2];
+ c = (c << 17) | (c >> 15);
+ c += d;
+
+ b += (((d ^ a) & c) ^ a) + (uint) Constants.C3 + buff [3];
+ b = (b << 22) | (b >> 10);
+ b += c;
+
+ a += (((c ^ d) & b) ^ d) + (uint) Constants.C4 + buff [4];
+ a = (a << 7) | (a >> 25);
+ a += b;
+
+ d += (((b ^ c) & a) ^ c) + (uint) Constants.C5 + buff [5];
+ d = (d << 12) | (d >> 20);
+ d += a;
+
+ c += (((a ^ b) & d) ^ b) + (uint) Constants.C6 + buff [6];
+ c = (c << 17) | (c >> 15);
+ c += d;
+
+ b += (((d ^ a) & c) ^ a) + (uint) Constants.C7 + buff [7];
+ b = (b << 22) | (b >> 10);
+ b += c;
+
+ a += (((c ^ d) & b) ^ d) + (uint) Constants.C8 + buff [8];
+ a = (a << 7) | (a >> 25);
+ a += b;
+
+ d += (((b ^ c) & a) ^ c) + (uint) Constants.C9 + buff [9];
+ d = (d << 12) | (d >> 20);
+ d += a;
- c += (((a ^ b) & d) ^ b) + (uint) Constants.C10 + buff[10];
- c = (c << 17) | (c >> 15);
- c += d;
+ c += (((a ^ b) & d) ^ b) + (uint) Constants.C10 + buff [10];
+ c = (c << 17) | (c >> 15);
+ c += d;
+
+ b += (((d ^ a) & c) ^ a) + (uint) Constants.C11 + buff [11];
+ b = (b << 22) | (b >> 10);
+ b += c;
- b += (((d ^ a) & c) ^ a) + (uint) Constants.C11 + buff[11];
- b = (b << 22) | (b >> 10);
- b += c;
+ a += (((c ^ d) & b) ^ d) + (uint) Constants.C12 + buff [12];
+ a = (a << 7) | (a >> 25);
+ a += b;
- a += (((c ^ d) & b) ^ d) + (uint) Constants.C12 + buff[12];
- a = (a << 7) | (a >> 25);
- a += b;
+ d += (((b ^ c) & a) ^ c) + (uint) Constants.C13 + buff [13];
+ d = (d << 12) | (d >> 20);
+ d += a;
- d += (((b ^ c) & a) ^ c) + (uint) Constants.C13 + buff[13];
- d = (d << 12) | (d >> 20);
- d += a;
+ c += (((a ^ b) & d) ^ b) + (uint) Constants.C14 + buff [14];
+ c = (c << 17) | (c >> 15);
+ c += d;
- c += (((a ^ b) & d) ^ b) + (uint) Constants.C14 + buff[14];
- c = (c << 17) | (c >> 15);
- c += d;
+ b += (((d ^ a) & c) ^ a) + (uint) Constants.C15 + buff [15];
+ b = (b << 22) | (b >> 10);
+ b += c;
- b += (((d ^ a) & c) ^ a) + (uint) Constants.C15 + buff[15];
- b = (b << 22) | (b >> 10);
- b += c;
+ // ---- Round 2 --------
- // ---- Round 2 --------
+ a += (((b ^ c) & d) ^ c) + (uint) Constants.C16 + buff [1];
+ a = (a << 5) | (a >> 27);
+ a += b;
- a += (((b ^ c) & d) ^ c) + (uint) Constants.C16 + buff[1];
- a = (a << 5) | (a >> 27);
- a += b;
+ d += (((a ^ b) & c) ^ b) + (uint) Constants.C17 + buff [6];
+ d = (d << 9) | (d >> 23);
+ d += a;
- d += (((a ^ b) & c) ^ b) + (uint) Constants.C17 + buff[6];
- d = (d << 9) | (d >> 23);
- d += a;
+ c += (((d ^ a) & b) ^ a) + (uint) Constants.C18 + buff [11];
+ c = (c << 14) | (c >> 18);
+ c += d;
- c += (((d ^ a) & b) ^ a) + (uint) Constants.C18 + buff[11];
- c = (c << 14) | (c >> 18);
- c += d;
+ b += (((c ^ d) & a) ^ d) + (uint) Constants.C19 + buff [0];
+ b = (b << 20) | (b >> 12);
+ b += c;
- b += (((c ^ d) & a) ^ d) + (uint) Constants.C19 + buff[0];
- b = (b << 20) | (b >> 12);
- b += c;
+ a += (((b ^ c) & d) ^ c) + (uint) Constants.C20 + buff [5];
+ a = (a << 5) | (a >> 27);
+ a += b;
- a += (((b ^ c) & d) ^ c) + (uint) Constants.C20 + buff[5];
- a = (a << 5) | (a >> 27);
- a += b;
+ d += (((a ^ b) & c) ^ b) + (uint) Constants.C21 + buff [10];
+ d = (d << 9) | (d >> 23);
+ d += a;
- d += (((a ^ b) & c) ^ b) + (uint) Constants.C21 + buff[10];
- d = (d << 9) | (d >> 23);
- d += a;
+ c += (((d ^ a) & b) ^ a) + (uint) Constants.C22 + buff [15];
+ c = (c << 14) | (c >> 18);
+ c += d;
- c += (((d ^ a) & b) ^ a) + (uint) Constants.C22 + buff[15];
- c = (c << 14) | (c >> 18);
- c += d;
+ b += (((c ^ d) & a) ^ d) + (uint) Constants.C23 + buff [4];
+ b = (b << 20) | (b >> 12);
+ b += c;
- b += (((c ^ d) & a) ^ d) + (uint) Constants.C23 + buff[4];
- b = (b << 20) | (b >> 12);
- b += c;
+ a += (((b ^ c) & d) ^ c) + (uint) Constants.C24 + buff [9];
+ a = (a << 5) | (a >> 27);
+ a += b;
- a += (((b ^ c) & d) ^ c) + (uint) Constants.C24 + buff[9];
- a = (a << 5) | (a >> 27);
- a += b;
+ d += (((a ^ b) & c) ^ b) + (uint) Constants.C25 + buff [14];
+ d = (d << 9) | (d >> 23);
+ d += a;
- d += (((a ^ b) & c) ^ b) + (uint) Constants.C25 + buff[14];
- d = (d << 9) | (d >> 23);
- d += a;
+ c += (((d ^ a) & b) ^ a) + (uint) Constants.C26 + buff [3];
+ c = (c << 14) | (c >> 18);
+ c += d;
- c += (((d ^ a) & b) ^ a) + (uint) Constants.C26 + buff[3];
- c = (c << 14) | (c >> 18);
- c += d;
+ b += (((c ^ d) & a) ^ d) + (uint) Constants.C27 + buff [8];
+ b = (b << 20) | (b >> 12);
+ b += c;
- b += (((c ^ d) & a) ^ d) + (uint) Constants.C27 + buff[8];
- b = (b << 20) | (b >> 12);
- b += c;
+ a += (((b ^ c) & d) ^ c) + (uint) Constants.C28 + buff [13];
+ a = (a << 5) | (a >> 27);
+ a += b;
- a += (((b ^ c) & d) ^ c) + (uint) Constants.C28 + buff[13];
- a = (a << 5) | (a >> 27);
- a += b;
+ d += (((a ^ b) & c) ^ b) + (uint) Constants.C29 + buff [2];
+ d = (d << 9) | (d >> 23);
+ d += a;
- d += (((a ^ b) & c) ^ b) + (uint) Constants.C29 + buff[2];
- d = (d << 9) | (d >> 23);
- d += a;
+ c += (((d ^ a) & b) ^ a) + (uint) Constants.C30 + buff [7];
+ c = (c << 14) | (c >> 18);
+ c += d;
- c += (((d ^ a) & b) ^ a) + (uint) Constants.C30 + buff[7];
- c = (c << 14) | (c >> 18);
- c += d;
+ b += (((c ^ d) & a) ^ d) + (uint) Constants.C31 + buff [12];
+ b = (b << 20) | (b >> 12);
+ b += c;
- b += (((c ^ d) & a) ^ d) + (uint) Constants.C31 + buff[12];
- b = (b << 20) | (b >> 12);
- b += c;
+ // ---- Round 3 --------
- // ---- Round 3 --------
+ a += (b ^ c ^ d) + (uint) Constants.C32 + buff [5];
+ a = (a << 4) | (a >> 28);
+ a += b;
- a += (b ^ c ^ d) + (uint) Constants.C32 + buff[5];
- a = (a << 4) | (a >> 28);
- a += b;
+ d += (a ^ b ^ c) + (uint) Constants.C33 + buff [8];
+ d = (d << 11) | (d >> 21);
+ d += a;
- d += (a ^ b ^ c) + (uint) Constants.C33 + buff[8];
- d = (d << 11) | (d >> 21);
- d += a;
+ c += (d ^ a ^ b) + (uint) Constants.C34 + buff [11];
+ c = (c << 16) | (c >> 16);
+ c += d;
- c += (d ^ a ^ b) + (uint) Constants.C34 + buff[11];
- c = (c << 16) | (c >> 16);
- c += d;
+ b += (c ^ d ^ a) + (uint) Constants.C35 + buff [14];
+ b = (b << 23) | (b >> 9);
+ b += c;
- b += (c ^ d ^ a) + (uint) Constants.C35 + buff[14];
- b = (b << 23) | (b >> 9);
- b += c;
+ a += (b ^ c ^ d) + (uint) Constants.C36 + buff [1];
+ a = (a << 4) | (a >> 28);
+ a += b;
- a += (b ^ c ^ d) + (uint) Constants.C36 + buff[1];
- a = (a << 4) | (a >> 28);
- a += b;
+ d += (a ^ b ^ c) + (uint) Constants.C37 + buff [4];
+ d = (d << 11) | (d >> 21);
+ d += a;
- d += (a ^ b ^ c) + (uint) Constants.C37 + buff[4];
- d = (d << 11) | (d >> 21);
- d += a;
+ c += (d ^ a ^ b) + (uint) Constants.C38 + buff [7];
+ c = (c << 16) | (c >> 16);
+ c += d;
- c += (d ^ a ^ b) + (uint) Constants.C38 + buff[7];
- c = (c << 16) | (c >> 16);
- c += d;
+ b += (c ^ d ^ a) + (uint) Constants.C39 + buff [10];
+ b = (b << 23) | (b >> 9);
+ b += c;
- b += (c ^ d ^ a) + (uint) Constants.C39 + buff[10];
- b = (b << 23) | (b >> 9);
- b += c;
+ a += (b ^ c ^ d) + (uint) Constants.C40 + buff [13];
+ a = (a << 4) | (a >> 28);
+ a += b;
- a += (b ^ c ^ d) + (uint) Constants.C40 + buff[13];
- a = (a << 4) | (a >> 28);
- a += b;
+ d += (a ^ b ^ c) + (uint) Constants.C41 + buff [0];
+ d = (d << 11) | (d >> 21);
+ d += a;
- d += (a ^ b ^ c) + (uint) Constants.C41 + buff[0];
- d = (d << 11) | (d >> 21);
- d += a;
+ c += (d ^ a ^ b) + (uint) Constants.C42 + buff [3];
+ c = (c << 16) | (c >> 16);
+ c += d;
- c += (d ^ a ^ b) + (uint) Constants.C42 + buff[3];
- c = (c << 16) | (c >> 16);
- c += d;
+ b += (c ^ d ^ a) + (uint) Constants.C43 + buff [6];
+ b = (b << 23) | (b >> 9);
+ b += c;
- b += (c ^ d ^ a) + (uint) Constants.C43 + buff[6];
- b = (b << 23) | (b >> 9);
- b += c;
+ a += (b ^ c ^ d) + (uint) Constants.C44 + buff [9];
+ a = (a << 4) | (a >> 28);
+ a += b;
- a += (b ^ c ^ d) + (uint) Constants.C44 + buff[9];
- a = (a << 4) | (a >> 28);
- a += b;
+ d += (a ^ b ^ c) + (uint) Constants.C45 + buff [12];
+ d = (d << 11) | (d >> 21);
+ d += a;
- d += (a ^ b ^ c) + (uint) Constants.C45 + buff[12];
- d = (d << 11) | (d >> 21);
- d += a;
+ c += (d ^ a ^ b) + (uint) Constants.C46 + buff [15];
+ c = (c << 16) | (c >> 16);
+ c += d;
- c += (d ^ a ^ b) + (uint) Constants.C46 + buff[15];
- c = (c << 16) | (c >> 16);
- c += d;
+ b += (c ^ d ^ a) + (uint) Constants.C47 + buff [2];
+ b = (b << 23) | (b >> 9);
+ b += c;
- b += (c ^ d ^ a) + (uint) Constants.C47 + buff[2];
- b = (b << 23) | (b >> 9);
- b += c;
+ // ---- Round 4 --------
- // ---- Round 4 --------
+ a += (((~d) | b) ^ c) + (uint) Constants.C48 + buff [0];
+ a = (a << 6) | (a >> 26);
+ a += b;
- a += (((~d) | b) ^ c) + (uint) Constants.C48 + buff[0];
- a = (a << 6) | (a >> 26);
- a += b;
+ d += (((~c) | a) ^ b) + (uint) Constants.C49 + buff [7];
+ d = (d << 10) | (d >> 22);
+ d += a;
- d += (((~c) | a) ^ b) + (uint) Constants.C49 + buff[7];
- d = (d << 10) | (d >> 22);
- d += a;
+ c += (((~b) | d) ^ a) + (uint) Constants.C50 + buff [14];
+ c = (c << 15) | (c >> 17);
+ c += d;
- c += (((~b) | d) ^ a) + (uint) Constants.C50 + buff[14];
- c = (c << 15) | (c >> 17);
- c += d;
+ b += (((~a) | c) ^ d) + (uint) Constants.C51 + buff [5];
+ b = (b << 21) | (b >> 11);
+ b += c;
- b += (((~a) | c) ^ d) + (uint) Constants.C51 + buff[5];
- b = (b << 21) | (b >> 11);
- b += c;
+ a += (((~d) | b) ^ c) + (uint) Constants.C52 + buff [12];
+ a = (a << 6) | (a >> 26);
+ a += b;
- a += (((~d) | b) ^ c) + (uint) Constants.C52 + buff[12];
- a = (a << 6) | (a >> 26);
- a += b;
+ d += (((~c) | a) ^ b) + (uint) Constants.C53 + buff [3];
+ d = (d << 10) | (d >> 22);
+ d += a;
- d += (((~c) | a) ^ b) + (uint) Constants.C53 + buff[3];
- d = (d << 10) | (d >> 22);
- d += a;
+ c += (((~b) | d) ^ a) + (uint) Constants.C54 + buff [10];
+ c = (c << 15) | (c >> 17);
+ c += d;
- c += (((~b) | d) ^ a) + (uint) Constants.C54 + buff[10];
- c = (c << 15) | (c >> 17);
- c += d;
+ b += (((~a) | c) ^ d) + (uint) Constants.C55 + buff [1];
+ b = (b << 21) | (b >> 11);
+ b += c;
+
+ a += (((~d) | b) ^ c) + (uint) Constants.C56 + buff [8];
+ a = (a << 6) | (a >> 26);
+ a += b;
+
+ d += (((~c) | a) ^ b) + (uint) Constants.C57 + buff [15];
+ d = (d << 10) | (d >> 22);
+ d += a;
+
+ c += (((~b) | d) ^ a) + (uint) Constants.C58 + buff [6];
+ c = (c << 15) | (c >> 17);
+ c += d;
+
+ b += (((~a) | c) ^ d) + (uint) Constants.C59 + buff [13];
+ b = (b << 21) | (b >> 11);
+ b += c;
+
+ a += (((~d) | b) ^ c) + (uint) Constants.C60 + buff [4];
+ a = (a << 6) | (a >> 26);
+ a += b;
+
+ d += (((~c) | a) ^ b) + (uint) Constants.C61 + buff [11];
+ d = (d << 10) | (d >> 22);
+ d += a;
+
+ c += (((~b) | d) ^ a) + (uint) Constants.C62 + buff [2];
+ c = (c << 15) | (c >> 17);
+ c += d;
+
+ b += (((~a) | c) ^ d) + (uint) Constants.C63 + buff [9];
+ b = (b << 21) | (b >> 11);
+ b += c;
+
+
+ _H[0] += a;
+ _H[1] += b;
+ _H[2] += c;
+ _H[3] += d;
+ }
+
+ /// <summary>
+ /// Pads and then processes the final block.
+ /// </summary>
+ /// <param name="inputBuffer">Buffer to grab data from.</param>
+ /// <param name="inputOffset">Position in buffer in bytes to get data from.</param>
+ /// <param name="inputCount">How much data in bytes in the buffer to use.</param>
+ private void ProcessFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
+ {
+ byte[] fooBuffer;
+ int paddingSize;
+ int i;
+ uint size;
+
+ paddingSize = (int)(56 - (inputCount + count) % BLOCK_SIZE_BYTES);
+
+ if (paddingSize < 1)
+ paddingSize += BLOCK_SIZE_BYTES;
+
+
+ fooBuffer = new byte[inputCount+paddingSize+8];
+
+ for (i=0; i<inputCount; i++)
+ {
+ fooBuffer[i] = inputBuffer[i+inputOffset];
+ }
+
+ fooBuffer[inputCount] = 0x80;
+ for (i=inputCount+1; i<inputCount+paddingSize; i++)
+ {
+ fooBuffer[i] = 0x00;
+ }
+
+ size = (uint)(count+inputCount);
+ size *= 8;
+ fooBuffer[inputCount+paddingSize] = (byte)((size) >> 0);
+ fooBuffer[inputCount+paddingSize+1] = (byte)((size) >> 8);
+ fooBuffer[inputCount+paddingSize+2] = (byte)((size) >> 16);
+ fooBuffer[inputCount+paddingSize+3] = (byte)((size) >> 24);
+
+ fooBuffer[inputCount+paddingSize+4] = 0x00;
+ fooBuffer[inputCount+paddingSize+5] = 0x00;
+ fooBuffer[inputCount+paddingSize+6] = 0x00;
+ fooBuffer[inputCount+paddingSize+7] = 0x00;
+
+ ProcessBlock(fooBuffer, 0);
+
+ if (inputCount+paddingSize+8 == 128)
+ {
+ ProcessBlock(fooBuffer, 64);
+ }
+ }
+
+ private enum Constants :
+ uint {
+ C0 = 0xd76aa478, C1 = 0xe8c7b756, C2 = 0x242070db,
+ C3 = 0xc1bdceee, C4 = 0xf57c0faf, C5 = 0x4787c62a,
+ C6 = 0xa8304613, C7 = 0xfd469501, C8 = 0x698098d8,
+ C9 = 0x8b44f7af,C10 = 0xffff5bb1,C11 = 0x895cd7be,
+ C12 = 0x6b901122,C13 = 0xfd987193,C14 = 0xa679438e,
+ C15 = 0x49b40821,C16 = 0xf61e2562,C17 = 0xc040b340,
+ C18 = 0x265e5a51,C19 = 0xe9b6c7aa,C20 = 0xd62f105d,
+ C21 = 0x02441453,C22 = 0xd8a1e681,C23 = 0xe7d3fbc8,
+ C24 = 0x21e1cde6,C25 = 0xc33707d6,C26 = 0xf4d50d87,
+ C27 = 0x455a14ed,C28 = 0xa9e3e905,C29 = 0xfcefa3f8,
+ C30 = 0x676f02d9,C31 = 0x8d2a4c8a,C32 = 0xfffa3942,
+ C33 = 0x8771f681,C34 = 0x6d9d6122,C35 = 0xfde5380c,
+ C36 = 0xa4beea44,C37 = 0x4bdecfa9,C38 = 0xf6bb4b60,
+ C39 = 0xbebfbc70,C40 = 0x289b7ec6,C41 = 0xeaa127fa,
+ C42 = 0xd4ef3085,C43 = 0x04881d05,C44 = 0xd9d4d039,
+ C45 = 0xe6db99e5,C46 = 0x1fa27cf8,C47 = 0xc4ac5665,
+ C48 = 0xf4292244,C49 = 0x432aff97,C50 = 0xab9423a7,
+ C51 = 0xfc93a039,C52 = 0x655b59c3,C53 = 0x8f0ccc92,
+ C54 = 0xffeff47d,C55 = 0x85845dd1,C56 = 0x6fa87e4f,
+ C57 = 0xfe2ce6e0,C58 = 0xa3014314,C59 = 0x4e0811a1,
+ C60 = 0xf7537e82,C61 = 0xbd3af235,C62 = 0x2ad7d2bb,
+ C63 = 0xeb86d391
+ }
+
+ }
+}
- b += (((~a) | c) ^ d) + (uint) Constants.C55 + buff[1];
- b = (b << 21) | (b >> 11);
- b += c;
-
- a += (((~d) | b) ^ c) + (uint) Constants.C56 + buff[8];
- a = (a << 6) | (a >> 26);
- a += b;
-
- d += (((~c) | a) ^ b) + (uint) Constants.C57 + buff[15];
- d = (d << 10) | (d >> 22);
- d += a;
-
- c += (((~b) | d) ^ a) + (uint) Constants.C58 + buff[6];
- c = (c << 15) | (c >> 17);
- c += d;
-
- b += (((~a) | c) ^ d) + (uint) Constants.C59 + buff[13];
- b = (b << 21) | (b >> 11);
- b += c;
-
- a += (((~d) | b) ^ c) + (uint) Constants.C60 + buff[4];
- a = (a << 6) | (a >> 26);
- a += b;
-
- d += (((~c) | a) ^ b) + (uint) Constants.C61 + buff[11];
- d = (d << 10) | (d >> 22);
- d += a;
-
- c += (((~b) | d) ^ a) + (uint) Constants.C62 + buff[2];
- c = (c << 15) | (c >> 17);
- c += d;
-
- b += (((~a) | c) ^ d) + (uint) Constants.C63 + buff[9];
- b = (b << 21) | (b >> 11);
- b += c;
-
-
- _H[0] += a;
- _H[1] += b;
- _H[2] += c;
- _H[3] += d;
- }
-
- /// <summary>
- /// Pads and then processes the final block.
- /// </summary>
- /// <param name="inputBuffer">Buffer to grab data from.</param>
- /// <param name="inputOffset">Position in buffer in bytes to get data from.</param>
- /// <param name="inputCount">How much data in bytes in the buffer to use.</param>
- private void ProcessFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
- {
- byte[] fooBuffer;
- int paddingSize;
- int i;
- uint size;
-
- paddingSize = (int) (56 - (inputCount + count)%BLOCK_SIZE_BYTES);
-
- if (paddingSize < 1)
- {
- paddingSize += BLOCK_SIZE_BYTES;
- }
-
-
- fooBuffer = new byte[inputCount + paddingSize + 8];
-
- for (i = 0; i < inputCount; i++)
- {
- fooBuffer[i] = inputBuffer[i + inputOffset];
- }
-
- fooBuffer[inputCount] = 0x80;
- for (i = inputCount + 1; i < inputCount + paddingSize; i++)
- {
- fooBuffer[i] = 0x00;
- }
-
- size = (uint) (count + inputCount);
- size *= 8;
- fooBuffer[inputCount + paddingSize] = (byte) ((size) >> 0);
- fooBuffer[inputCount + paddingSize + 1] = (byte) ((size) >> 8);
- fooBuffer[inputCount + paddingSize + 2] = (byte) ((size) >> 16);
- fooBuffer[inputCount + paddingSize + 3] = (byte) ((size) >> 24);
-
- fooBuffer[inputCount + paddingSize + 4] = 0x00;
- fooBuffer[inputCount + paddingSize + 5] = 0x00;
- fooBuffer[inputCount + paddingSize + 6] = 0x00;
- fooBuffer[inputCount + paddingSize + 7] = 0x00;
-
- ProcessBlock(fooBuffer, 0);
-
- if (inputCount + paddingSize + 8 == 128)
- {
- ProcessBlock(fooBuffer, 64);
- }
- }
-
- private enum Constants :
- uint
- {
- C0 = 0xd76aa478,
- C1 = 0xe8c7b756,
- C2 = 0x242070db,
- C3 = 0xc1bdceee,
- C4 = 0xf57c0faf,
- C5 = 0x4787c62a,
- C6 = 0xa8304613,
- C7 = 0xfd469501,
- C8 = 0x698098d8,
- C9 = 0x8b44f7af,
- C10 = 0xffff5bb1,
- C11 = 0x895cd7be,
- C12 = 0x6b901122,
- C13 = 0xfd987193,
- C14 = 0xa679438e,
- C15 = 0x49b40821,
- C16 = 0xf61e2562,
- C17 = 0xc040b340,
- C18 = 0x265e5a51,
- C19 = 0xe9b6c7aa,
- C20 = 0xd62f105d,
- C21 = 0x02441453,
- C22 = 0xd8a1e681,
- C23 = 0xe7d3fbc8,
- C24 = 0x21e1cde6,
- C25 = 0xc33707d6,
- C26 = 0xf4d50d87,
- C27 = 0x455a14ed,
- C28 = 0xa9e3e905,
- C29 = 0xfcefa3f8,
- C30 = 0x676f02d9,
- C31 = 0x8d2a4c8a,
- C32 = 0xfffa3942,
- C33 = 0x8771f681,
- C34 = 0x6d9d6122,
- C35 = 0xfde5380c,
- C36 = 0xa4beea44,
- C37 = 0x4bdecfa9,
- C38 = 0xf6bb4b60,
- C39 = 0xbebfbc70,
- C40 = 0x289b7ec6,
- C41 = 0xeaa127fa,
- C42 = 0xd4ef3085,
- C43 = 0x04881d05,
- C44 = 0xd9d4d039,
- C45 = 0xe6db99e5,
- C46 = 0x1fa27cf8,
- C47 = 0xc4ac5665,
- C48 = 0xf4292244,
- C49 = 0x432aff97,
- C50 = 0xab9423a7,
- C51 = 0xfc93a039,
- C52 = 0x655b59c3,
- C53 = 0x8f0ccc92,
- C54 = 0xffeff47d,
- C55 = 0x85845dd1,
- C56 = 0x6fa87e4f,
- C57 = 0xfe2ce6e0,
- C58 = 0xa3014314,
- C59 = 0x4e0811a1,
- C60 = 0xf7537e82,
- C61 = 0xbd3af235,
- C62 = 0x2ad7d2bb,
- C63 = 0xeb86d391
- }
- }
-} \ No newline at end of file
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs b/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs
index d8f10f8aef3..995e4881550 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlAsciiRow.cs
@@ -9,232 +9,216 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Data;
+using System.Collections;
using System.IO;
+using System.Text;
+using System.Net;
+
using NpgsqlTypes;
namespace Npgsql
{
- /// <summary>
- /// Implements <see cref="RowReader"/> for version 3 of the protocol.
- /// </summary>
- internal sealed class StringRowReaderV3 : RowReader
- {
- private readonly int _messageSize;
- private int? _nextFieldSize = null;
-
- public StringRowReaderV3(NpgsqlRowDescription rowDesc, Stream inputStream)
- : base(rowDesc, inputStream)
- {
- _messageSize = PGUtil.ReadInt32(inputStream);
- if (PGUtil.ReadInt16(inputStream) != rowDesc.NumFields)
- {
- throw new DataException();
- }
- }
- protected override object ReadNext()
- {
- int fieldSize = GetThisFieldCount();
- if (fieldSize >= _messageSize)
- {
- AbandonShip();
- }
- _nextFieldSize = null;
+ /// <summary>
+ /// This class represents the AsciiRow (version 2) and DataRow (version 3+)
+ /// message sent from the PostgreSQL server.
+ /// </summary>
+ internal sealed class NpgsqlAsciiRow : NpgsqlRow
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlAsciiRow";
- // Check if this field is null
- if (fieldSize == -1) // Null value
- {
- return DBNull.Value;
- }
+ private readonly Int16 READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??
+ private byte[] _inputBuffer;
+ private char[] _chars;
- NpgsqlRowDescription.FieldData field_descr = FieldData;
+ public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion, byte[] inputBuffer, char[] chars)
+ : base(rowDesc, protocolVersion)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+ _inputBuffer = inputBuffer;
+ _chars = chars;
+ }
- byte[] buffer = new byte[fieldSize];
- PGUtil.CheckedStreamRead(Stream, buffer, 0, fieldSize);
+ public override void ReadFromStream(Stream inputStream, Encoding encoding)
+ {
+ switch (protocol_version)
+ {
+ case ProtocolVersion.Version2 :
+ ReadFromStream_Ver_2(inputStream, encoding);
+ break;
- try
- {
- if (field_descr.FormatCode == FormatCode.Text)
- {
- char[] charBuffer = new char[UTF8Encoding.GetCharCount(buffer, 0, buffer.Length)];
- UTF8Encoding.GetChars(buffer, 0, buffer.Length, charBuffer, 0);
- return
- NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.TypeInfo, new string(charBuffer),
- field_descr.TypeSize, field_descr.TypeModifier);
- }
- else
- {
- return
- NpgsqlTypesHelper.ConvertBackendBytesToSystemType(field_descr.TypeInfo, buffer, fieldSize,
- field_descr.TypeModifier);
- }
- }
- catch (InvalidCastException ice)
- {
- return ice;
- }
- catch (Exception ex)
- {
- return new InvalidCastException(ex.Message, ex);
- }
- }
+ case ProtocolVersion.Version3 :
+ ReadFromStream_Ver_3(inputStream, encoding);
+ break;
- private void AbandonShip()
- {
- //field size will always be smaller than message size
- //but if we fall out of sync with the stream due to an error then we will probably hit
- //such a situation soon as bytes from elsewhere in the stream get interpreted as a size.
- //so if we see this happens, we know we've lost the stream - our best option is to just give up on it,
- //and have the connector recovered later.
- try
- {
- Stream.WriteByte((byte) FrontEndMessageCode.Termination);
- PGUtil.WriteInt32(Stream, 4);
- Stream.Flush();
- }
- catch
- {
- }
- try
- {
- Stream.Close();
- }
- catch
- {
- }
- throw new DataException();
- }
+ }
+ }
- protected override void SkipOne()
- {
- int fieldSize = GetThisFieldCount();
- if (fieldSize >= _messageSize)
- {
- AbandonShip();
- }
- _nextFieldSize = null;
- PGUtil.EatStreamBytes(Stream, fieldSize);
- }
+ private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
- public override bool IsNextDBNull
- {
- get { return GetThisFieldCount() == -1; }
- }
+ Byte[] null_map_array = new Byte[(row_desc.NumFields + 7)/8];
- private int GetThisFieldCount()
- {
- return (_nextFieldSize = _nextFieldSize ?? PGUtil.ReadInt32(Stream)).Value;
- }
+ Array.Clear(null_map_array, 0, null_map_array.Length);
- protected override int GetNextFieldCount()
- {
- int ret = GetThisFieldCount();
- _nextFieldSize = null;
- return ret;
- }
- }
-
- /// <summary>
- /// Implements <see cref="RowReader"/> for version 2 of the protocol.
- /// </summary>
- internal sealed class StringRowReaderV2 : RowReader
- {
- /// <summary>
- /// Encapsulates the null mapping bytes sent at the start of a version 2
- /// datarow message, and the process of identifying the nullity of the data
- /// at a particular index
- /// </summary>
- private sealed class NullMap
- {
- private readonly byte[] _map;
- public NullMap(NpgsqlRowDescription desc, Stream inputStream)
- {
- _map = new byte[(desc.NumFields + 7)/8];
- PGUtil.CheckedStreamRead(inputStream, _map, 0, _map.Length);
- }
+ // Decoders used to get decoded chars when using unicode like encodings which may have chars crossing the byte buffer bounds.
- public bool IsNull(int index)
- {
- // Get the byte that holds the bit index position.
- // Then check the bit that in MSB order corresponds
- // to the index position.
- return (_map[index/8] & (0x80 >> (index%8))) == 0;
- }
- }
+ Decoder decoder = encoding.GetDecoder();
- private readonly NullMap _nullMap;
+ // Read the null fields bitmap.
+ PGUtil.CheckedStreamRead(inputStream, null_map_array, 0, null_map_array.Length );
- public StringRowReaderV2(NpgsqlRowDescription rowDesc, Stream inputStream)
- : base(rowDesc, inputStream)
- {
- _nullMap = new NullMap(rowDesc, inputStream);
- }
+ // Get the data.
+ for (Int16 field_count = 0; field_count < row_desc.NumFields; field_count++)
+ {
+ // Check if this field is null
+ if (IsBackendNull(null_map_array, field_count))
+ {
+ data.Add(DBNull.Value);
+ continue;
+ }
- protected override object ReadNext()
- {
- if (_nullMap.IsNull(CurrentField))
- {
- return DBNull.Value;
- }
+ // Read the first data of the first row.
- NpgsqlRowDescription.FieldData field_descr = FieldData;
- Int32 field_value_size = PGUtil.ReadInt32(Stream) - 4;
- byte[] buffer = new byte[field_value_size];
- PGUtil.CheckedStreamRead(Stream, buffer, 0, field_value_size);
- char[] charBuffer = new char[UTF8Encoding.GetCharCount(buffer, 0, buffer.Length)];
- UTF8Encoding.GetChars(buffer, 0, buffer.Length, charBuffer, 0);
- try
- {
- return
- NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.TypeInfo, new string(charBuffer),
- field_descr.TypeSize, field_descr.TypeModifier);
- }
- catch (InvalidCastException ice)
- {
- return ice;
- }
- catch (Exception ex)
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, 4);
+
+ NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
+ Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(_inputBuffer, 0));
+ field_value_size -= 4;
+
+ 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));
+
+ }
+ }
+
+ private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
+
+ PGUtil.ReadInt32(inputStream, _inputBuffer);
+ Int16 numCols = PGUtil.ReadInt16(inputStream, _inputBuffer);
+
+ Decoder decoder = encoding.GetDecoder();
+
+ for (Int16 field_count = 0; field_count < numCols; field_count++)
{
- return new InvalidCastException(ex.Message, ex);
- }
- }
+ 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;
+ }
- public override bool IsNextDBNull
+ 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
+ {
+ Byte[] binary_data = ReadBytesFromStream(inputStream, field_value_size);
+
+ data.Add(NpgsqlTypesHelper.ConvertBackendBytesToSystemType(field_descr.type_info, binary_data, encoding,field_value_size, field_descr.type_modifier));
+ }
+ }
+ }
+
+ // Using the given null field map (provided by the backend),
+ // determine if the given field index is mapped null by the backend.
+ // We only need to do this for version 2 protocol.
+ private static Boolean IsBackendNull(Byte[] null_map_array, Int32 index)
+ {
+ // Get the byte that holds the bit index position.
+ Byte test_byte = null_map_array[index/8];
+
+ // Now, check if index bit is set.
+ // To do this, get its position in the byte, shift to
+ // 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)
{
- get { return _nullMap.IsNull(CurrentField + 1); }
+ // 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;
}
- protected override void SkipOne()
+ private string ReadStringFromStream(Stream inputStream, int field_value_size, Decoder decoder)
{
- if (!_nullMap.IsNull(CurrentField))
+ int bytes_left = field_value_size;
+ int charCount;
+
+ if (field_value_size > _inputBuffer.Length)
{
- PGUtil.EatStreamBytes(Stream, PGUtil.ReadInt32(Stream) - 4);
+ 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);
- protected override int GetNextFieldCount()
- {
- return _nullMap.IsNull(CurrentField) ? -1 : PGUtil.ReadInt32(Stream) - 4;
+ return new String(_chars, 0,charCount);
+ }
}
- }
-} \ No newline at end of file
+
+ private byte[] ReadBytesFromStream(Stream inputStream, int field_value_size)
+ {
+ byte[] binary_data = new byte[field_value_size];
+ int bytes_left = field_value_size;
+ if (field_value_size > _inputBuffer.Length)
+ {
+ int i=0;
+ while (bytes_left > READ_BUFFER_SIZE)
+ {
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, READ_BUFFER_SIZE);
+ _inputBuffer.CopyTo(binary_data, i*READ_BUFFER_SIZE);
+ i++;
+ bytes_left -= READ_BUFFER_SIZE;
+ }
+ }
+ PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, bytes_left);
+ Int32 offset = field_value_size - bytes_left;
+ Array.Copy(_inputBuffer, 0, binary_data, offset, bytes_left);
+ return binary_data;
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlBackEndKeyData.cs b/mcs/class/Npgsql/Npgsql/NpgsqlBackEndKeyData.cs
index a684695b170..693c5c88de0 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlBackEndKeyData.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlBackEndKeyData.cs
@@ -10,48 +10,84 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
using System.IO;
+using System.Text;
+using System.Net;
namespace Npgsql
{
- /// <summary>
- /// This class represents a BackEndKeyData message received
- /// from PostgreSQL
- /// </summary>
- internal sealed class NpgsqlBackEndKeyData
- {
- public readonly int ProcessID;
- public readonly int SecretKey;
-
- public NpgsqlBackEndKeyData(ProtocolVersion protocolVersion, Stream stream)
- {
- // Read the BackendKeyData message contents. Two Int32 integers = 8 Bytes.
- // For protocol version 3.0 they are three integers. The first one is just the size of message
- // so, just read it.
- if (protocolVersion >= ProtocolVersion.Version3)
- {
- PGUtil.EatStreamBytes(stream, 4);
- }
- ProcessID = PGUtil.ReadInt32(stream);
- SecretKey = PGUtil.ReadInt32(stream);
- }
- }
-} \ No newline at end of file
+ /// <summary>
+ /// This class represents a BackEndKeyData message received
+ /// from PostgreSQL
+ /// </summary>
+ internal sealed class NpgsqlBackEndKeyData
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlBackEndKeyData";
+
+ private Int32 _processId;
+ private Int32 _secretKey;
+
+ private ProtocolVersion _protocolVersion;
+
+ public NpgsqlBackEndKeyData(ProtocolVersion protocolVersion)
+ {
+ _protocolVersion = protocolVersion;
+ _processId = -1;
+ _secretKey = -1;
+ }
+
+
+ public void ReadFromStream(Stream inputStream)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+
+ Byte[] inputBuffer = new Byte[8];
+
+ // Read the BackendKeyData message contents. Two Int32 integers = 8 Bytes.
+ // For protocol version 3.0 they are three integers. The first one is just the size of message
+ // so, just read it.
+ if (_protocolVersion >= ProtocolVersion.Version3)
+ inputStream.Read(inputBuffer, 0, 4);
+
+ inputStream.Read(inputBuffer, 0, 8);
+ _processId = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 0));
+ _secretKey = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 4));
+
+ }
+
+ public Int32 ProcessID
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "ProcessID");
+ return _processId;
+ }
+ }
+
+ public Int32 SecretKey
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "SecretKey");
+ return _secretKey;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlBind.cs b/mcs/class/Npgsql/Npgsql/NpgsqlBind.cs
index 35de60c056b..91056afc587 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlBind.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlBind.cs
@@ -9,174 +9,210 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Text;
+using System.Data;
+
namespace Npgsql
{
- /// <summary>
- /// This class represents the Bind message sent to PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlBind : ClientMessage
- {
- private readonly String _portalName;
- private readonly String _preparedStatementName;
- private Int16[] _parameterFormatCodes;
- private Object[] _parameterValues;
- private Int16[] _resultFormatCodes;
-
-
- public NpgsqlBind(String portalName, String preparedStatementName, Int16[] parameterFormatCodes,
- Object[] parameterValues, Int16[] resultFormatCodes)
- {
- _portalName = portalName;
- _preparedStatementName = preparedStatementName;
- _parameterFormatCodes = parameterFormatCodes;
- _parameterValues = parameterValues;
- _resultFormatCodes = resultFormatCodes;
- }
-
- public String PortalName
- {
- get { return _portalName; }
- }
-
- public String PreparedStatementName
- {
- get { return _preparedStatementName; }
- }
-
- public Int16[] ResultFormatCodes
- {
- get { return _resultFormatCodes; }
- set { _resultFormatCodes = value; }
- }
-
- public Int16[] ParameterFormatCodes
- {
- get { return _parameterFormatCodes; }
-
- set { _parameterFormatCodes = value; }
- }
-
- public Object[] ParameterValues
- {
- get { return _parameterValues; }
-
- set { _parameterValues = value; }
- }
-
-
- public override void WriteToStream(Stream outputStream)
- {
- Int32 messageLength = 4 + UTF8Encoding.GetByteCount(_portalName) + 1 +
- UTF8Encoding.GetByteCount(_preparedStatementName) + 1 + 2 + (_parameterFormatCodes.Length*2) +
- 2;
-
-
- // Get size of parameter values.
- Int32 i;
-
- if (_parameterValues != null)
- {
- for (i = 0; i < _parameterValues.Length; i++)
- {
- messageLength += 4;
- if (_parameterValues[i] != null)
- {
- if (((_parameterFormatCodes.Length == 1) && (_parameterFormatCodes[0] == (Int16) FormatCode.Binary)) ||
- ((_parameterFormatCodes.Length != 1) && (_parameterFormatCodes[i] == (Int16) FormatCode.Binary)))
- {
- messageLength += ((Byte[]) _parameterValues[i]).Length;
- }
- else
- {
- messageLength += UTF8Encoding.GetByteCount((String) _parameterValues[i]);
- }
- }
- }
- }
-
- messageLength += 2 + (_resultFormatCodes.Length*2);
-
-
- outputStream.WriteByte((byte) FrontEndMessageCode.Bind);
-
- PGUtil.WriteInt32(outputStream, messageLength);
- PGUtil.WriteString(_portalName, outputStream);
- PGUtil.WriteString(_preparedStatementName, outputStream);
-
- PGUtil.WriteInt16(outputStream, (Int16) _parameterFormatCodes.Length);
-
- for (i = 0; i < _parameterFormatCodes.Length; i++)
- {
- PGUtil.WriteInt16(outputStream, _parameterFormatCodes[i]);
- }
-
- if (_parameterValues != null)
- {
- PGUtil.WriteInt16(outputStream, (Int16) _parameterValues.Length);
-
- for (i = 0; i < _parameterValues.Length; i++)
- {
- if (((_parameterFormatCodes.Length == 1) && (_parameterFormatCodes[0] == (Int16) FormatCode.Binary)) ||
- ((_parameterFormatCodes.Length != 1) && (_parameterFormatCodes[i] == (Int16) FormatCode.Binary)))
- {
- Byte[] parameterValue = (Byte[]) _parameterValues[i];
- if (parameterValue == null)
- {
- PGUtil.WriteInt32(outputStream, -1);
- }
- else
- {
- PGUtil.WriteInt32(outputStream, parameterValue.Length);
- outputStream.Write(parameterValue, 0, parameterValue.Length);
- }
- }
- else
- {
- if ((_parameterValues[i] == null))
- {
- PGUtil.WriteInt32(outputStream, -1);
- }
- else
- {
- Byte[] parameterValueBytes = UTF8Encoding.GetBytes((String) _parameterValues[i]);
- PGUtil.WriteInt32(outputStream, parameterValueBytes.Length);
- outputStream.Write(parameterValueBytes, 0, parameterValueBytes.Length);
- }
- }
- }
- }
- else
- {
- PGUtil.WriteInt16(outputStream, 0);
- }
-
- PGUtil.WriteInt16(outputStream, (Int16) _resultFormatCodes.Length);
- for (i = 0; i < _resultFormatCodes.Length; i++)
- {
- PGUtil.WriteInt16(outputStream, _resultFormatCodes[i]);
- }
- }
- }
-} \ No newline at end of file
+
+ /// <summary>
+ /// This class represents the Bind message sent to PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlBind
+ {
+
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlBind";
+
+ private String _portalName;
+ private String _preparedStatementName;
+ private Int16[] _parameterFormatCodes;
+ private Object[] _parameterValues;
+ private Int16[] _resultFormatCodes;
+
+
+
+ public NpgsqlBind(String portalName,
+ String preparedStatementName,
+ Int16[] parameterFormatCodes,
+ Object[] parameterValues,
+ Int16[] resultFormatCodes)
+ {
+
+ _portalName = portalName;
+ _preparedStatementName = preparedStatementName;
+ _parameterFormatCodes = parameterFormatCodes;
+ _parameterValues = parameterValues;
+ _resultFormatCodes = resultFormatCodes;
+
+
+
+
+ }
+
+ public String PortalName
+ {
+ get
+ {
+ return _portalName;
+ }
+ }
+
+ public String PreparedStatementName
+ {
+ get
+ {
+ return _preparedStatementName;
+ }
+ }
+
+ public Int16[] ResultFormatCodes
+ {
+ get
+ {
+ return _resultFormatCodes;
+ }
+ set
+ {
+ _resultFormatCodes = value;
+
+ }
+ }
+
+ public Int16[] ParameterFormatCodes
+ {
+ get
+ {
+ return _parameterFormatCodes;
+ }
+
+ set
+ {
+ _parameterFormatCodes = value;
+
+ }
+ }
+
+ public Object[] ParameterValues
+ {
+ get
+ {
+ return _parameterValues;
+ }
+
+ set
+ {
+ _parameterValues = value;
+ }
+ }
+
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+
+
+
+ Int32 messageLength = 4 +
+ encoding.GetByteCount(_portalName) + 1 +
+ encoding.GetByteCount(_preparedStatementName) + 1 +
+ 2 +
+ (_parameterFormatCodes.Length * 2) +
+ 2;
+
+
+ // Get size of parameter values.
+ Int32 i;
+
+ if (_parameterValues != null)
+ for (i = 0; i < _parameterValues.Length; i++)
+ {
+ messageLength += 4;
+ if ( _parameterValues[i] != null)
+ if ( ((_parameterFormatCodes.Length == 1) && (_parameterFormatCodes[0] == (Int16) FormatCode.Binary)) ||
+ ((_parameterFormatCodes.Length != 1) && (_parameterFormatCodes[i] == (Int16) FormatCode.Binary)) )
+ messageLength += ((Byte[])_parameterValues[i]).Length;
+ else
+ messageLength += encoding.GetByteCount((String)_parameterValues[i]);
+
+ }
+
+ messageLength += 2 + (_resultFormatCodes.Length * 2);
+
+
+ outputStream.WriteByte((Byte)'B');
+
+ PGUtil.WriteInt32(outputStream, messageLength);
+ PGUtil.WriteString(_portalName, outputStream, encoding);
+ PGUtil.WriteString(_preparedStatementName, outputStream, encoding);
+
+ PGUtil.WriteInt16(outputStream, (Int16)_parameterFormatCodes.Length);
+
+ for (i = 0; i < _parameterFormatCodes.Length; i++)
+ PGUtil.WriteInt16(outputStream, _parameterFormatCodes[i]);
+
+ if (_parameterValues != null)
+ {
+ PGUtil.WriteInt16(outputStream, (Int16)_parameterValues.Length);
+
+ for (i = 0; i < _parameterValues.Length; i++)
+ {
+ if ( ((_parameterFormatCodes.Length == 1) && (_parameterFormatCodes[0] == (Int16) FormatCode.Binary)) ||
+ ((_parameterFormatCodes.Length != 1) && (_parameterFormatCodes[i] == (Int16) FormatCode.Binary)) )
+ {
+
+ Byte[] parameterValue = (Byte[])_parameterValues[i];
+ if (parameterValue == null)
+ PGUtil.WriteInt32(outputStream, -1);
+ else
+ {
+ PGUtil.WriteInt32(outputStream, parameterValue.Length);
+ outputStream.Write(parameterValue, 0, parameterValue.Length);
+ }
+ }
+ else
+ {
+ if ((_parameterValues[i] == null))
+ PGUtil.WriteInt32(outputStream, -1);
+ else
+ {
+ Byte[] parameterValueBytes = encoding.GetBytes((String)_parameterValues[i]);
+ PGUtil.WriteInt32(outputStream, parameterValueBytes.Length);
+ outputStream.Write(parameterValueBytes, 0, parameterValueBytes.Length);
+ }
+ }
+
+ }
+ }
+ else
+ PGUtil.WriteInt16(outputStream, 0);
+
+ PGUtil.WriteInt16(outputStream, (Int16)_resultFormatCodes.Length);
+ for (i = 0; i < _resultFormatCodes.Length; i++)
+ PGUtil.WriteInt16(outputStream, _resultFormatCodes[i]);
+
+
+
+ }
+
+ }
+}
+
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlCancelRequest.cs b/mcs/class/Npgsql/Npgsql/NpgsqlCancelRequest.cs
index 776fc58bfdc..9b0c02a5a01 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlCancelRequest.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlCancelRequest.cs
@@ -6,58 +6,60 @@
// Copyright (C) 2002-2006 The Npgsql Development Team
// http://pgfoundry.org/projects/npgsql
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Text;
namespace Npgsql
{
- /// <summary>
- /// This class represents the CancelRequest message sent to PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlCancelRequest : ClientMessage
- {
- // Logging related values
- //private static readonly String CLASSNAME = "NpgsqlCancelRequest";
-
-
- private static readonly Int32 CancelRequestMessageSize = 16;
- private static readonly Int32 CancelRequestCode = 1234 << 16 | 5678;
-
- private readonly NpgsqlBackEndKeyData BackendKeydata;
-
-
- public NpgsqlCancelRequest(NpgsqlBackEndKeyData BackendKeydata)
- {
- this.BackendKeydata = BackendKeydata;
- }
-
- public override void WriteToStream(Stream outputStream)
- {
- PGUtil.WriteInt32(outputStream, CancelRequestMessageSize);
- PGUtil.WriteInt32(outputStream, CancelRequestCode);
- PGUtil.WriteInt32(outputStream, BackendKeydata.ProcessID);
- PGUtil.WriteInt32(outputStream, BackendKeydata.SecretKey);
-
- outputStream.Flush();
- }
- }
+
+ /// <summary>
+ /// This class represents the CancelRequest message sent to PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlCancelRequest
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlCancelRequest";
+
+
+ private static Int32 CancelRequestMessageSize = 16;
+ private static Int32 CancelRequestCode = 1234 << 16 | 5678;
+
+ private NpgsqlBackEndKeyData BackendKeydata;
+
+
+ public NpgsqlCancelRequest(NpgsqlBackEndKeyData BackendKeydata)
+ {
+ this.BackendKeydata = BackendKeydata;
+
+ }
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+ PGUtil.WriteInt32(outputStream, CancelRequestMessageSize);
+ PGUtil.WriteInt32(outputStream, CancelRequestCode);
+ PGUtil.WriteInt32(outputStream, BackendKeydata.ProcessID);
+ PGUtil.WriteInt32(outputStream, BackendKeydata.SecretKey);
+
+ outputStream.Flush();
+
+ }
+
+ }
} \ No newline at end of file
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs
index 795046c31d4..e6cd113e836 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlClosedState.cs
@@ -1,88 +1,96 @@
// Npgsql.NpgsqlClosedState.cs
//
-// Authors:
-// Dave Joyner <d4ljoyn@yahoo.com>
-// Daniel Nauck <dna(at)mono-project.de>
+// Author:
+// Dave Joyner <d4ljoyn@yahoo.com>
//
// Copyright (C) 2002 The Npgsql Development Team
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
+using System.Collections;
using System.Threading;
+
using Mono.Security.Protocol.Tls;
-using SecurityProtocolType=Mono.Security.Protocol.Tls.SecurityProtocolType;
namespace Npgsql
{
- internal sealed class NpgsqlClosedState : NpgsqlState
- {
- private static readonly NpgsqlClosedState _instance = new NpgsqlClosedState();
- private static readonly String CLASSNAME = "NpgsqlClosedState";
-
-
- private NpgsqlClosedState()
- : base()
- {
- }
-
- public static NpgsqlClosedState Instance
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Instance");
- return _instance;
- }
- }
-
-
- /// <summary>
- /// Resolve a host name or IP address.
- /// This is needed because if you call Dns.Resolve() with an IP address, it will attempt
- /// to resolve it as a host name, when it should just convert it to an IP address.
- /// </summary>
- /// <param name="HostName"></param>
- private static IPAddress[] ResolveIPHost(String HostName)
- {
- return Dns.GetHostAddresses(HostName);
- }
-
- public override void Open(NpgsqlConnector context)
- {
- try
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
-
- /*TcpClient tcpc = new TcpClient();
+
+ internal sealed class NpgsqlClosedState : NpgsqlState
+ {
+
+ private static NpgsqlClosedState _instance = new NpgsqlClosedState();
+ private static readonly String CLASSNAME = "NpgsqlClosedState";
+
+
+ private NpgsqlClosedState() : base()
+ { }
+
+ public static NpgsqlClosedState Instance {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Instance");
+ return _instance;
+ }
+ }
+
+
+
+ /// <summary>
+ /// Resolve a host name or IP address.
+ /// This is needed because if you call Dns.Resolve() with an IP address, it will attempt
+ /// to resolve it as a host name, when it should just convert it to an IP address.
+ /// </summary>
+ /// <param name="HostName"></param>
+ private static IPAddress ResolveIPHost(String HostName)
+ {
+
+ try
+ {
+ // Is it a raw IP address?
+ return IPAddress.Parse(HostName);
+ }
+ catch (FormatException)
+ {
+ // Not an IP, must be a host name...
+ return Dns.Resolve(HostName).AddressList[0];
+ }
+ }
+
+ public override void Open(NpgsqlConnector context)
+ {
+
+ try
+ {
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
+
+ /*TcpClient tcpc = new TcpClient();
tcpc.Connect(new IPEndPoint(ResolveIPHost(context.Host), context.Port));
Stream stream = tcpc.GetStream();*/
+
+ Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
+
+ /*socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout, context.ConnectionTimeout*1000);*/
- /*socket.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.SendTimeout, context.ConnectionTimeout*1000);*/
-
- //socket.Connect(new IPEndPoint(ResolveIPHost(context.Host), context.Port));
-
-
- /*Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
+ //socket.Connect(new IPEndPoint(ResolveIPHost(context.Host), context.Port));
IAsyncResult result = socket.BeginConnect(new IPEndPoint(ResolveIPHost(context.Host), context.Port), null, null);
@@ -96,105 +104,57 @@ namespace Npgsql
{
socket.EndConnect(result);
}
- catch (Exception)
+ catch (Exception ex)
{
socket.Close();
throw;
}
- */
-
- IPAddress[] ips = ResolveIPHost(context.Host);
- Socket socket = null;
-
- // try every ip address of the given hostname, use the first reachable one
- foreach (IPAddress ip in ips)
- {
- NpgsqlEventLog.LogMsg(resman, "Log_ConnectingTo", LogLevel.Debug, ip);
-
- IPEndPoint ep = new IPEndPoint(ip, context.Port);
- socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
-
- try
- {
- IAsyncResult result = socket.BeginConnect(ep, null, null);
-
- if (!result.AsyncWaitHandle.WaitOne(context.ConnectionTimeout*1000, true))
- {
- socket.Close();
- throw new Exception(resman.GetString("Exception_ConnectionTimeout"));
- }
-
- socket.EndConnect(result);
-
- // connect was successful, leave the loop
- break;
- }
- catch (Exception)
- {
- NpgsqlEventLog.LogMsg(resman, "Log_FailedConnection", LogLevel.Normal, ip);
- socket.Close();
- }
- }
-
- if (socket == null || !socket.Connected)
- {
- throw new Exception(string.Format(resman.GetString("Exception_FailedConnection"), context.Host));
- }
-
- Stream stream = new NetworkStream(socket, true);
-
-
- // If the PostgreSQL server has SSL connectors enabled Open SslClientStream if (response == 'S') {
- if (context.SSL || (context.SslMode == SslMode.Require) || (context.SslMode == SslMode.Prefer))
- {
- PGUtil.WriteInt32(stream, 8);
- PGUtil.WriteInt32(stream, 80877103);
- // Receive response
-
- Char response = (Char) stream.ReadByte();
- if (response == 'S')
- {
- stream = new SslClientStream(stream, context.Host, true, SecurityProtocolType.Default);
-
- ((SslClientStream) stream).ClientCertSelectionDelegate =
- new CertificateSelectionCallback(context.DefaultCertificateSelectionCallback);
- ((SslClientStream) stream).ServerCertValidationDelegate =
- new CertificateValidationCallback(context.DefaultCertificateValidationCallback);
- ((SslClientStream) stream).PrivateKeyCertSelectionDelegate =
- new PrivateKeySelectionCallback(context.DefaultPrivateKeySelectionCallback);
- }
- else if (context.SslMode == SslMode.Require)
- {
- throw new InvalidOperationException(resman.GetString("Exception_Ssl_RequestError"));
- }
- }
-
- context.Stream = new BufferedStream(stream);
- context.Socket = socket;
-
-
- NpgsqlEventLog.LogMsg(resman, "Log_ConnectedTo", LogLevel.Normal, context.Host, context.Port);
- ChangeState(context, NpgsqlConnectedState.Instance);
- }
- //FIXME: Exceptions that come from what we are handling should be wrapped - e.g. an error connecting to
- //the server should definitely be presented to the uesr as an NpgsqlError. Exceptions from userland should
- //be passed untouched - e.g. ThreadAbortException because the user started this in a thread they created and
- //then aborted should be passed through.
- //Are there any others that should be pass through? Alternatively, are there a finite number that should
- //be wrapped?
- catch (ThreadAbortException)
- {
- throw;
- }
- catch (Exception e)
- {
- throw new NpgsqlException(e.Message, e);
- }
- }
-
- public override void Close(NpgsqlConnector context)
- {
- //DO NOTHING.
- }
- }
-} \ No newline at end of file
+
+ Stream stream = new NetworkStream(socket, true);
+
+
+
+ // If the PostgreSQL server has SSL connectors enabled Open SslClientStream if (response == 'S') {
+ if (context.SSL || (context.SslMode == SslMode.Require) || (context.SslMode == SslMode.Prefer))
+ {
+ PGUtil.WriteInt32(stream, 8);
+ PGUtil.WriteInt32(stream,80877103);
+ // Receive response
+
+ Char response = (Char)stream.ReadByte();
+ if (response == 'S')
+ {
+ stream = new SslClientStream(
+ stream,
+ context.Host,
+ true,
+ Mono.Security.Protocol.Tls.SecurityProtocolType.Default
+ );
+
+ ((SslClientStream)stream).ClientCertSelectionDelegate = new CertificateSelectionCallback(context.DefaultCertificateSelectionCallback);
+ ((SslClientStream)stream).ServerCertValidationDelegate = new CertificateValidationCallback(context.DefaultCertificateValidationCallback);
+ ((SslClientStream)stream).PrivateKeyCertSelectionDelegate = new PrivateKeySelectionCallback(context.DefaultPrivateKeySelectionCallback);
+ }
+ else if (context.SslMode == SslMode.Require)
+ throw new InvalidOperationException(resman.GetString("Exception_Ssl_RequestError"));
+
+ }
+
+ context.Stream = new BufferedStream(stream);
+ context.Socket = socket;
+
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ConnectedTo", LogLevel.Normal, context.Host, context.Port);
+ ChangeState(context, NpgsqlConnectedState.Instance);
+
+
+ }
+ catch (Exception e)
+ {
+ throw new NpgsqlException(e.Message, e);
+ }
+ }
+
+ }
+
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs b/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
index a0cf749c417..4a536daec4e 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlCommand.cs
@@ -3,42 +3,40 @@
// Npgsql.NpgsqlCommand.cs
//
// Author:
-// Francisco Jr. (fxjrlists@yahoo.com.br)
+// Francisco Jr. (fxjrlists@yahoo.com.br)
//
-// Copyright (C) 2002 The Npgsql Development Team
-// npgsql-general@gborg.postgresql.org
-// http://gborg.postgresql.org/project/npgsql/projdisplay.php
+// Copyright (C) 2002 The Npgsql Development Team
+// npgsql-general@gborg.postgresql.org
+// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.ComponentModel;
using System.Data;
-using System.Data.Common;
-using System.IO;
-using System.Reflection;
-using System.Resources;
using System.Text;
-using System.Text.RegularExpressions;
+using System.Resources;
+using System.ComponentModel;
+using System.Collections;
+using System.IO;
+
using NpgsqlTypes;
-#if WITHDESIGN
+using System.Text.RegularExpressions;
+#if WITHDESIGN
+using Npgsql.Design;
#endif
namespace Npgsql
@@ -47,62 +45,54 @@ namespace Npgsql
/// Represents a SQL statement or function (stored procedure) to execute
/// against a PostgreSQL database. This class cannot be inherited.
/// </summary>
-#if WITHDESIGN
+ #if WITHDESIGN
[System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlCommand)), ToolboxItem(true)]
-#endif
-
- public sealed class NpgsqlCommand : DbCommand, ICloneable
+ #endif
+ public sealed class NpgsqlCommand : Component, IDbCommand, ICloneable
{
// Logging related values
private static readonly String CLASSNAME = "NpgsqlCommand";
- private static ResourceManager resman = new ResourceManager(MethodBase.GetCurrentMethod().DeclaringType);
- private readonly Regex parameterReplace = new Regex(@"([:@][\w\.]*)", RegexOptions.Singleline);
+ private static ResourceManager resman = new ResourceManager(typeof(NpgsqlCommand));
+ private static readonly Regex parameterReplace = new Regex(@"([:@][\w\.]*)", RegexOptions.Singleline);
+
+ private NpgsqlConnection connection;
+ private NpgsqlConnector connector;
+ private NpgsqlTransaction transaction;
+ private String text;
+ private Int32 timeout;
+ private CommandType type;
+ private NpgsqlParameterCollection parameters;
+ private String planName;
- private NpgsqlConnection connection;
- private NpgsqlConnector m_Connector; //renamed to account for hiding it in a local function
- //if all locals were named with this prefix, it would solve LOTS of issues.
- private NpgsqlTransaction transaction;
- private String text;
- private Int32 timeout;
- private CommandType type;
- private readonly NpgsqlParameterCollection parameters;
- private String planName;
- private Boolean designTimeVisible;
+ private NpgsqlParse parse;
+ private NpgsqlBind bind;
- private NpgsqlParse parse;
- private NpgsqlBind bind;
+ private Boolean invalidTransactionDetected = false;
+
+ private CommandBehavior commandBehavior;
- private Int64 lastInsertedOID = 0;
+ private Int64 lastInsertedOID = 0;
// Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> class.
/// </summary>
- public NpgsqlCommand()
- : this(String.Empty, null, null)
- {
- }
-
+ public NpgsqlCommand() : this(String.Empty, null, null)
+ {}
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> class with the text of the query.
/// </summary>
/// <param name="cmdText">The text of the query.</param>
- public NpgsqlCommand(String cmdText)
- : this(cmdText, null, null)
- {
- }
-
+ public NpgsqlCommand(String cmdText) : this(cmdText, null, null)
+ {}
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> class with the text of the query and a <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
/// </summary>
/// <param name="cmdText">The text of the query.</param>
/// <param name="connection">A <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> that represents the connection to a PostgreSQL server.</param>
- public NpgsqlCommand(String cmdText, NpgsqlConnection connection)
- : this(cmdText, connection, null)
- {
- }
-
+ public NpgsqlCommand(String cmdText, NpgsqlConnection connection) : this(cmdText, connection, null)
+ {}
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> class with the text of the query, a <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>, and the <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>.
/// </summary>
@@ -116,17 +106,18 @@ namespace Npgsql
planName = String.Empty;
text = cmdText;
this.connection = connection;
-
+
if (this.connection != null)
- {
- this.m_Connector = connection.Connector;
- }
+ this.connector = connection.Connector;
parameters = new NpgsqlParameterCollection();
type = CommandType.Text;
this.Transaction = transaction;
+ commandBehavior = CommandBehavior.Default;
SetCommandTimeout();
+
+
}
/// <summary>
@@ -134,15 +125,16 @@ namespace Npgsql
/// </summary>
internal NpgsqlCommand(String cmdText, NpgsqlConnector connector)
{
- resman = new ResourceManager(this.GetType());
+ resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
-
+
planName = String.Empty;
text = cmdText;
- this.m_Connector = connector;
+ this.connector = connector;
type = CommandType.Text;
-
+ commandBehavior = CommandBehavior.Default;
+
parameters = new NpgsqlParameterCollection();
// Internal commands aren't affected by command timeout value provided by user.
@@ -155,9 +147,11 @@ namespace Npgsql
/// </summary>
/// <value>The Transact-SQL statement or stored procedure to execute. The default is an empty string.</value>
[Category("Data"), DefaultValue("")]
- public override String CommandText
- {
- get { return text; }
+ public String CommandText {
+ get
+ {
+ return text;
+ }
set
{
@@ -167,6 +161,7 @@ namespace Npgsql
planName = String.Empty;
parse = null;
bind = null;
+ commandBehavior = CommandBehavior.Default;
}
}
@@ -177,16 +172,17 @@ namespace Npgsql
/// <value>The time (in seconds) to wait for the command to execute.
/// The default is 20 seconds.</value>
[DefaultValue(20)]
- public override Int32 CommandTimeout
+ public Int32 CommandTimeout
{
- get { return timeout; }
+ get
+ {
+ return timeout;
+ }
set
{
if (value < 0)
- {
throw new ArgumentOutOfRangeException(resman.GetString("Exception_CommandTimeoutLessZero"));
- }
timeout = value;
NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "CommandTimeout", value);
@@ -199,9 +195,12 @@ namespace Npgsql
/// </summary>
/// <value>One of the <see cref="System.Data.CommandType">CommandType</see> values. The default is <see cref="System.Data.CommandType">CommandType.Text</see>.</value>
[Category("Data"), DefaultValue(CommandType.Text)]
- public override CommandType CommandType
+ public CommandType CommandType
{
- get { return type; }
+ get
+ {
+ return type;
+ }
set
{
@@ -210,14 +209,17 @@ namespace Npgsql
}
}
- protected override DbConnection DbConnection
+ IDbConnection IDbCommand.Connection
{
- get { return Connection; }
+ get
+ {
+ return Connection;
+ }
set
{
- Connection = (NpgsqlConnection)value;
- NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "DbConnection", value);
+ Connection = (NpgsqlConnection) value;
+ NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "IDbCommand.Connection", value);
}
}
@@ -227,7 +229,7 @@ namespace Npgsql
/// </summary>
/// <value>The connection to a data source. The default value is a null reference.</value>
[Category("Behavior"), DefaultValue(null)]
- public new NpgsqlConnection Connection
+ public NpgsqlConnection Connection
{
get
{
@@ -238,31 +240,22 @@ namespace Npgsql
set
{
if (this.Connection == value)
- {
return;
- }
//if (this.transaction != null && this.transaction.Connection == null)
- // this.transaction = null;
-
- // All this checking needs revising. It should be simpler.
- // This this.Connector != null check was added to remove the nullreferenceexception in case
- // of the previous connection has been closed which makes Connector null and so the last check would fail.
- // See bug 1000581 for more details.
- if (this.transaction != null && this.connection != null && this.Connector != null && this.Connector.Transaction != null)
- {
+ // this.transaction = null;
+
+ if (this.transaction != null && this.connection != null && this.Connector.Transaction != null)
throw new InvalidOperationException(resman.GetString("Exception_SetConnectionInTransaction"));
- }
+
this.connection = value;
Transaction = null;
if (this.connection != null)
- {
- m_Connector = this.connection.Connector;
- }
+ connector = this.connection.Connector;
SetCommandTimeout();
-
+
NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "Connection", value);
}
}
@@ -272,28 +265,28 @@ namespace Npgsql
get
{
if (this.connection != null)
- {
- m_Connector = this.connection.Connector;
- }
+ connector = this.connection.Connector;
- return m_Connector;
+ return connector;
}
}
- protected override DbParameterCollection DbParameterCollection
- {
- get { return Parameters; }
+ IDataParameterCollection IDbCommand.Parameters {
+ get
+ {
+ return Parameters;
+ }
}
/// <summary>
/// Gets the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see>.
/// </summary>
/// <value>The parameters of the SQL statement or function (stored procedure). The default is an empty collection.</value>
-#if WITHDESIGN
+ #if WITHDESIGN
[Category("Data"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
-#endif
-
- public new NpgsqlParameterCollection Parameters
+ #endif
+
+ public NpgsqlParameterCollection Parameters
{
get
{
@@ -302,29 +295,32 @@ namespace Npgsql
}
}
-
- protected override DbTransaction DbTransaction
+
+ IDbTransaction IDbCommand.Transaction
{
- get { return Transaction; }
+ get
+ {
+ return Transaction;
+ }
+
set
{
- Transaction = (NpgsqlTransaction)value;
+ Transaction = (NpgsqlTransaction) value;
NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "IDbCommand.Transaction", value);
}
}
-
+
/// <summary>
/// Gets or sets the <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
/// within which the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> executes.
/// </summary>
/// <value>The <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>.
/// The default value is a null reference.</value>
-#if WITHDESIGN
+ #if WITHDESIGN
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-#endif
-
- public new NpgsqlTransaction Transaction
- {
+ #endif
+
+ public NpgsqlTransaction Transaction {
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Transaction");
@@ -338,40 +334,46 @@ namespace Npgsql
set
{
- NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "Transaction", value);
+ NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "Transaction" ,value);
- this.transaction = value;
+ this.transaction = (NpgsqlTransaction) value;
}
}
/// <summary>
/// Gets or sets how command results are applied to the <see cref="System.Data.DataRow">DataRow</see>
- /// when used by the <see cref="System.Data.Common.DbDataAdapter.Update(DataSet)">Update</see>
+ /// when used by the <see cref="System.Data.Common.DbDataAdapter.Update">Update</see>
/// method of the <see cref="System.Data.Common.DbDataAdapter">DbDataAdapter</see>.
/// </summary>
/// <value>One of the <see cref="System.Data.UpdateRowSource">UpdateRowSource</see> values.</value>
-#if WITHDESIGN
+ #if WITHDESIGN
[Category("Behavior"), DefaultValue(UpdateRowSource.Both)]
-#endif
-
- public override UpdateRowSource UpdatedRowSource
- {
+ #endif
+
+ public UpdateRowSource UpdatedRowSource {
get
{
+
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "UpdatedRowSource");
return UpdateRowSource.Both;
}
- set { }
+ set
+ {
+ }
}
/// <summary>
/// Returns oid of inserted row. This is only updated when using executenonQuery and when command inserts just a single row. If table is created without oids, this will always be 0.
/// </summary>
- public Int64 LastInsertedOID
+
+ public Int64 LastInsertedOID
{
- get { return lastInsertedOID; }
+ get
+ {
+ return lastInsertedOID;
+ }
}
@@ -379,7 +381,7 @@ namespace Npgsql
/// Attempts to cancel the execution of a <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
/// </summary>
/// <remarks>This Method isn't implemented yet.</remarks>
- public override void Cancel()
+ public void Cancel()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Cancel");
@@ -395,13 +397,13 @@ namespace Npgsql
catch (IOException)
{
Connection.ClearPool();
- }
+ }
catch (NpgsqlException)
{
// Cancel documentation says the Cancel doesn't throw on failure
}
}
-
+
/// <summary>
/// Create a new command based on this one.
/// </summary>
@@ -419,33 +421,25 @@ namespace Npgsql
{
// TODO: Add consistency checks.
- NpgsqlCommand clone = new NpgsqlCommand(CommandText, Connection, Transaction);
- clone.CommandTimeout = CommandTimeout;
- clone.CommandType = CommandType;
- clone.DesignTimeVisible = DesignTimeVisible;
- foreach (NpgsqlParameter parameter in Parameters)
- {
- clone.Parameters.Add(((ICloneable)parameter).Clone());
- }
- return clone;
+ return new NpgsqlCommand(CommandText, Connection, Transaction);
}
/// <summary>
- /// Creates a new instance of an <see cref="System.Data.Common.DbParameter">DbParameter</see> object.
+ /// Creates a new instance of an <see cref="System.Data.IDbDataParameter">IDbDataParameter</see> object.
/// </summary>
- /// <returns>An <see cref="System.Data.Common.DbParameter">DbParameter</see> object.</returns>
- protected override DbParameter CreateDbParameter()
+ /// <returns>An <see cref="System.Data.IDbDataParameter">IDbDataParameter</see> object.</returns>
+ IDbDataParameter IDbCommand.CreateParameter()
{
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateDbParameter");
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbCommand.CreateParameter");
- return CreateParameter();
+ return (NpgsqlParameter) CreateParameter();
}
/// <summary>
/// Creates a new instance of a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.
/// </summary>
/// <returns>A <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
- public new NpgsqlParameter CreateParameter()
+ public NpgsqlParameter CreateParameter()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateParameter");
@@ -453,38 +447,143 @@ namespace Npgsql
}
/// <summary>
- /// Slightly optimised version of ExecuteNonQuery() for internal ues in cases where the number
- /// of affected rows is of no interest.
- /// </summary>
- internal void ExecuteBlind()
- {
- GetReader(CommandBehavior.SequentialAccess).Dispose();
- }
-
- /// <summary>
/// Executes a SQL statement against the connection and returns the number of rows affected.
/// </summary>
- /// <returns>The number of rows affected if known; -1 otherwise.</returns>
- public override Int32 ExecuteNonQuery()
+ /// <returns>The number of rows affected.</returns>
+ public Int32 ExecuteNonQuery()
{
- //We treat this as a simple wrapper for calling ExecuteReader() and then
- //update the records affected count at every call to NextResult();
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteNonQuery");
- int? ret = null;
- using (NpgsqlDataReader rdr = GetReader(CommandBehavior.SequentialAccess))
+
+ // Initialize lastInsertOID
+ lastInsertedOID = 0;
+
+ ExecuteCommand();
+
+ UpdateOutputParameters();
+
+
+ // If nothing is returned, just return -1.
+ if(Connector.Mediator.CompletedResponses.Count == 0)
{
- do
+ return -1;
+ }
+
+ // Check if the response is available.
+ String firstCompletedResponse = (String)Connector.Mediator.CompletedResponses[0];
+
+ if (firstCompletedResponse == null)
+ return -1;
+
+ String[] ret_string_tokens = firstCompletedResponse.Split(null); // whitespace separator.
+
+
+ // Check if the command was insert, delete, update, fetch or move.
+ // Only theses commands return rows affected.
+ // [FIXME] Is there a better way to check this??
+ if ((String.Compare(ret_string_tokens[0], "INSERT", true) == 0) ||
+ (String.Compare(ret_string_tokens[0], "UPDATE", true) == 0) ||
+ (String.Compare(ret_string_tokens[0], "DELETE", true) == 0) ||
+ (String.Compare(ret_string_tokens[0], "FETCH", true) == 0) ||
+ (String.Compare(ret_string_tokens[0], "MOVE", true) == 0))
+
+
+ {
+ if (String.Compare(ret_string_tokens[0], "INSERT", true) == 0)
+ // Get oid of inserted row.
+ lastInsertedOID = Int32.Parse(ret_string_tokens[1]);
+
+ // The number of rows affected is in the third token for insert queries
+ // and in the second token for update and delete queries.
+ // In other words, it is the last token in the 0-based array.
+
+ return Int32.Parse(ret_string_tokens[ret_string_tokens.Length - 1]);
+ }
+ else
+ return -1;
+ }
+
+
+
+ private void UpdateOutputParameters()
+ {
+ // Check if there was some resultset returned. If so, put the result in output parameters.
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "UpdateOutputParameters");
+
+ // Get ResultSets.
+ ArrayList resultSets = Connector.Mediator.ResultSets;
+
+ if (resultSets.Count != 0)
+ {
+ NpgsqlResultSet nrs = (NpgsqlResultSet)resultSets[0];
+
+ if ((nrs != null) && (nrs.Count > 0))
{
- int thisRecord = rdr.RecordsAffected;
- if (thisRecord != -1)
+ NpgsqlAsciiRow nar = (NpgsqlAsciiRow)nrs[0];
+
+ Int32 i = 0;
+ Boolean hasMapping = false;
+
+ // First check if there is any mapping between parameter name and resultset name.
+ // If so, just update output parameters which has mapping.
+
+ foreach (NpgsqlParameter p in Parameters)
+ {
+ if (nrs.RowDescription.FieldIndex(p.ParameterName.Substring(1)) > -1)
+ {
+ hasMapping = true;
+ break;
+ }
+
+ }
+
+
+ if (hasMapping)
{
- ret = (ret ?? 0) + thisRecord;
+ foreach (NpgsqlParameter p in Parameters)
+ {
+ if (((p.Direction == ParameterDirection.Output) ||
+ (p.Direction == ParameterDirection.InputOutput)) && (i < nrs.RowDescription.NumFields ))
+ {
+ Int32 fieldIndex = nrs.RowDescription.FieldIndex(p.ParameterName.Substring(1));
+
+ if (fieldIndex > -1)
+ {
+ p.Value = nar[fieldIndex];
+ i++;
+ }
+
+ }
+ }
+
}
- lastInsertedOID = rdr.LastInsertedOID ?? lastInsertedOID;
+ else
+ foreach (NpgsqlParameter p in Parameters)
+ {
+ if (((p.Direction == ParameterDirection.Output) ||
+ (p.Direction == ParameterDirection.InputOutput)) && (i < nrs.RowDescription.NumFields ))
+ {
+ p.Value = nar[i];
+ i++;
+ }
+ }
}
- while (rdr.NextResult());
- }
- return ret ?? -1;
+
+ }
+
+
+ }
+
+ /// <summary>
+ /// Sends the <see cref="Npgsql.NpgsqlCommand.CommandText">CommandText</see> to
+ /// the <see cref="Npgsql.NpgsqlConnection">Connection</see> and builds a
+ /// <see cref="Npgsql.NpgsqlDataReader">NpgsqlDataReader</see>.
+ /// </summary>
+ /// <returns>A <see cref="Npgsql.NpgsqlDataReader">NpgsqlDataReader</see> object.</returns>
+ IDataReader IDbCommand.ExecuteReader()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbCommand.ExecuteReader");
+
+ return (NpgsqlDataReader) ExecuteReader();
}
/// <summary>
@@ -493,11 +592,13 @@ namespace Npgsql
/// <see cref="Npgsql.NpgsqlDataReader">NpgsqlDataReader</see>
/// using one of the <see cref="System.Data.CommandBehavior">CommandBehavior</see> values.
/// </summary>
- /// <param name="behavior">One of the <see cref="System.Data.CommandBehavior">CommandBehavior</see> values.</param>
+ /// <param name="cb">One of the <see cref="System.Data.CommandBehavior">CommandBehavior</see> values.</param>
/// <returns>A <see cref="Npgsql.NpgsqlDataReader">NpgsqlDataReader</see> object.</returns>
- protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
+ IDataReader IDbCommand.ExecuteReader(CommandBehavior cb)
{
- return ExecuteReader(behavior);
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbCommand.ExecuteReader", cb);
+
+ return (NpgsqlDataReader) ExecuteReader(cb);
}
/// <summary>
@@ -506,7 +607,7 @@ namespace Npgsql
/// <see cref="Npgsql.NpgsqlDataReader">NpgsqlDataReader</see>.
/// </summary>
/// <returns>A <see cref="Npgsql.NpgsqlDataReader">NpgsqlDataReader</see> object.</returns>
- public new NpgsqlDataReader ExecuteReader()
+ public NpgsqlDataReader ExecuteReader()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteReader");
@@ -522,70 +623,19 @@ namespace Npgsql
/// <param name="cb">One of the <see cref="System.Data.CommandBehavior">CommandBehavior</see> values.</param>
/// <returns>A <see cref="Npgsql.NpgsqlDataReader">NpgsqlDataReader</see> object.</returns>
/// <remarks>Currently the CommandBehavior parameter is ignored.</remarks>
- public new NpgsqlDataReader ExecuteReader(CommandBehavior cb)
+ public NpgsqlDataReader ExecuteReader(CommandBehavior cb)
{
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteReader", cb);
-
- // Close connection if requested even when there is an error.
-
- try
- {
- if (connection != null)
- {
- if (connection.PreloadReader)
- {
- //Adjust behaviour so source reader is sequential access - for speed - and doesn't close the connection - or it'll do so at the wrong time.
- CommandBehavior adjusted = (cb | CommandBehavior.SequentialAccess) & ~CommandBehavior.CloseConnection;
- return new CachingDataReader(GetReader(adjusted), cb);
- }
- }
- return GetReader(cb);
- }
- catch (Exception)
- {
- if ((cb & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
- {
- connection.Close();
- }
- throw;
- }
-
- }
-
- internal ForwardsOnlyDataReader GetReader(CommandBehavior cb)
- {
- try
- {
- CheckConnectionState();
-
- // reset any responses just before getting new ones
- Connector.Mediator.ResetResponses();
-
- // Set command timeout.
- m_Connector.Mediator.CommandTimeout = CommandTimeout;
+ // [FIXME] No command behavior handling.
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteReader", cb);
+ commandBehavior = cb;
- using (m_Connector.BlockNotificationThread())
- {
- if (parse == null)
- {
- return new ForwardsOnlyDataReader(m_Connector.QueryEnum(this), cb, this, m_Connector.BlockNotificationThread(), false);
- }
- //return new ForwardsOnlyDataReader(m_Connector.QueryEnum(this), cb, this, m_Connector.BlockNotificationThread(), false);
- else
- {
- BindParameters();
- return
- new ForwardsOnlyDataReader(m_Connector.ExecuteEnum(new NpgsqlExecute(bind.PortalName, 0)), cb, this,
- m_Connector.BlockNotificationThread(), true);
- //return new ForwardsOnlyDataReader(m_Connector.ExecuteEnum(new NpgsqlExecute(bind.PortalName, 0)), cb, this, m_Connector.BlockNotificationThread(), true);
- }
- }
- }
- catch (IOException ex)
- {
- throw ClearPoolAndCreateException(ex);
- }
+ ExecuteCommand();
+
+ UpdateOutputParameters();
+
+ // Get the resultsets and create a Datareader with them.
+ return new NpgsqlDataReader(Connector.Mediator.ResultSets, Connector.Mediator.CompletedResponses, cb, this);
}
///<summary>
@@ -594,34 +644,29 @@ namespace Npgsql
/// </summary>
private void BindParameters()
{
+
if (parameters.Count != 0)
{
Object[] parameterValues = new Object[parameters.Count];
Int16[] parameterFormatCodes = bind.ParameterFormatCodes;
-
+
for (Int32 i = 0; i < parameters.Count; i++)
{
// Do not quote strings, or escape existing quotes - this will be handled by the backend.
// DBNull or null values are returned as null.
// TODO: Would it be better to remove this null special handling out of ConvertToBackend??
-
+
// Do special handling of bytea values. They will be send in binary form.
// TODO: Add binary format support for all supported types. Not only bytea.
if (parameters[i].TypeInfo.NpgsqlDbType != NpgsqlDbType.Bytea)
{
+
parameterValues[i] = parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, true);
}
else
{
- if (parameters[i].Value != DBNull.Value)
- {
- parameterFormatCodes[i] = (Int16)FormatCode.Binary;
- parameterValues[i] = (byte[])parameters[i].Value;
- }
- else
- {
- parameterValues[i] = parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, true);
- }
+ parameterFormatCodes[i] = (Int16) FormatCode.Binary;
+ parameterValues[i]=(byte[])parameters[i].Value;
}
}
bind.ParameterValues = parameterValues;
@@ -629,8 +674,13 @@ namespace Npgsql
}
Connector.Bind(bind);
-
+
+ // See Prepare() method for a discussion of this.
+ Connector.Mediator.RequireReadyForQuery = false;
Connector.Flush();
+
+
+ connector.CheckErrorsAndNotifications();
}
/// <summary>
@@ -639,120 +689,150 @@ namespace Npgsql
/// </summary>
/// <returns>The first column of the first row in the result set,
/// or a null reference if the result set is empty.</returns>
- public override Object ExecuteScalar()
+ public Object ExecuteScalar()
{
- using (
- NpgsqlDataReader reader =
- GetReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ExecuteScalar");
+
+ ExecuteCommand();
+
+
+ // Now get the results.
+ // Only the first column of the first row must be returned.
+
+ // Get ResultSets.
+ ArrayList resultSets = Connector.Mediator.ResultSets;
+
+ // First data is the RowDescription object.
+ // Check all resultsets as insert commands could have been sent along
+ // with resultset queries. The insert commands return null and and some queries
+ // may return empty resultsets, so, if we find one of these, skip to next resultset.
+ // If no resultset is found, return null as per specification.
+
+ NpgsqlAsciiRow ascii_row = null;
+ foreach( NpgsqlResultSet nrs in resultSets )
{
- return reader.Read() && reader.FieldCount != 0 ? reader.GetValue(0) : null;
+ if( (nrs != null) && (nrs.Count > 0) )
+ {
+ ascii_row = (NpgsqlAsciiRow) nrs[0];
+ return ascii_row[0];
+ }
}
+
+ return null;
}
/// <summary>
/// Creates a prepared version of the command on a PostgreSQL server.
/// </summary>
- public override void Prepare()
+ public void Prepare()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Prepare");
// Check the connection state.
CheckConnectionState();
-
+
// reset any responses just before getting new ones
Connector.Mediator.ResetResponses();
-
+
// Set command timeout.
- m_Connector.Mediator.CommandTimeout = CommandTimeout;
+ connector.Mediator.CommandTimeout = CommandTimeout;
- if (!m_Connector.SupportsPrepare)
+ if (! connector.SupportsPrepare)
{
- return; // Do nothing.
+ return; // Do nothing.
}
- if (m_Connector.BackendProtocolVersion == ProtocolVersion.Version2)
+ if (connector.BackendProtocolVersion == ProtocolVersion.Version2)
{
- using (NpgsqlCommand command = new NpgsqlCommand(GetPrepareCommandText(), m_Connector))
- {
- command.ExecuteBlind();
- }
+ NpgsqlCommand command = new NpgsqlCommand(GetPrepareCommandText(), connector );
+ command.ExecuteNonQuery();
}
else
{
- using (m_Connector.BlockNotificationThread())
+ try
{
- try
+
+ connector.StopNotificationThread();
+
+ // Use the extended query parsing...
+ planName = connector.NextPlanName();
+ String portalName = connector.NextPortalName();
+
+ parse = new NpgsqlParse(planName, GetParseCommandText(), new Int32[] {});
+
+ connector.Parse(parse);
+
+ // We need that because Flush() doesn't cause backend to send
+ // ReadyForQuery on error. Without ReadyForQuery, we don't return
+ // from query extended processing.
+
+ // We could have used Connector.Flush() which sends us back a
+ // ReadyForQuery, but on postgresql server below 8.1 there is an error
+ // with extended query processing which hinders us from using it.
+ connector.Mediator.RequireReadyForQuery = false;
+ connector.Flush();
+
+ // Check for errors and/or notifications and do the Right Thing.
+ connector.CheckErrorsAndNotifications();
+
+
+ // Description...
+ NpgsqlDescribe describe = new NpgsqlDescribe('S', planName);
+
+
+ connector.Describe(describe);
+
+ connector.Sync();
+
+ Npgsql.NpgsqlRowDescription returnRowDesc = connector.Mediator.LastRowDescription;
+
+ Int16[] resultFormatCodes;
+
+
+ if (returnRowDesc != null)
{
- // Use the extended query parsing...
- planName = m_Connector.NextPlanName();
- String portalName = m_Connector.NextPortalName();
-
- parse = new NpgsqlParse(planName, GetParseCommandText(), new Int32[] { });
-
- m_Connector.Parse(parse);
-
- // We need that because Flush() doesn't cause backend to send
- // ReadyForQuery on error. Without ReadyForQuery, we don't return
- // from query extended processing.
-
- // We could have used Connector.Flush() which sends us back a
- // ReadyForQuery, but on postgresql server below 8.1 there is an error
- // with extended query processing which hinders us from using it.
- m_Connector.RequireReadyForQuery = false;
- m_Connector.Flush();
-
-
- // Description...
- NpgsqlDescribe describe = new NpgsqlDescribe('S', planName);
-
-
- m_Connector.Describe(describe);
-
- NpgsqlRowDescription returnRowDesc = m_Connector.Sync();
-
- Int16[] resultFormatCodes;
-
-
- if (returnRowDesc != null)
+ resultFormatCodes = new Int16[returnRowDesc.NumFields];
+
+ for (int i=0; i < returnRowDesc.NumFields; i++)
{
- resultFormatCodes = new Int16[returnRowDesc.NumFields];
-
- for (int i = 0; i < returnRowDesc.NumFields; i++)
+ Npgsql.NpgsqlRowDescriptionFieldData returnRowDescData = returnRowDesc[i];
+
+
+ if (returnRowDescData.type_info != null && returnRowDescData.type_info.NpgsqlDbType == NpgsqlTypes.NpgsqlDbType.Bytea)
{
- NpgsqlRowDescription.FieldData returnRowDescData = returnRowDesc[i];
-
-
- if (returnRowDescData.TypeInfo != null && returnRowDescData.TypeInfo.NpgsqlDbType == NpgsqlDbType.Bytea)
- {
- // Binary format
- resultFormatCodes[i] = (Int16)FormatCode.Binary;
- }
- else
- {
- // Text Format
- resultFormatCodes[i] = (Int16)FormatCode.Text;
- }
+ // Binary format
+ resultFormatCodes[i] = (Int16)FormatCode.Binary;
}
+ else
+ // Text Format
+ resultFormatCodes[i] = (Int16)FormatCode.Text;
}
- else
- {
- resultFormatCodes = new Int16[] { 0 };
- }
-
- bind = new NpgsqlBind("", planName, new Int16[Parameters.Count], null, resultFormatCodes);
- }
- catch (IOException e)
- {
- throw ClearPoolAndCreateException(e);
- }
- catch
- {
- // See ExecuteCommand method for a discussion of this.
- m_Connector.Sync();
-
- throw;
+
+
}
+ else
+ resultFormatCodes = new Int16[]{0};
+
+ bind = new NpgsqlBind("", planName, new Int16[Parameters.Count], null, resultFormatCodes);
+ }
+ catch (IOException e)
+ {
+ ClearPoolAndThrowException(e);
+ }
+ catch
+ {
+ // See ExecuteCommand method for a discussion of this.
+ connector.Sync();
+
+ throw;
}
+ finally
+ {
+ connector.ResumeNotificationThread();
+ }
+
+
+
}
}
@@ -788,15 +868,10 @@ namespace Npgsql
// Check the connection state.
- if (Connector == null || Connector.State == ConnectionState.Closed)
+ if (Connector == null || Connector.State != ConnectionState.Open)
{
throw new InvalidOperationException(resman.GetString("Exception_ConnectionNotOpen"));
}
- if (Connector.State != ConnectionState.Open)
- {
- throw new InvalidOperationException(
- "There is already an open DataReader associated with this Command which must be closed first.");
- }
}
/// <summary>
@@ -809,37 +884,31 @@ namespace Npgsql
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetCommandText");
- if (string.IsNullOrEmpty(planName))//== String.Empty)
- {
+ if (planName == String.Empty)
return GetClearCommandText();
- }
- return GetPreparedCommandText();
-
+ else
+ return GetPreparedCommandText();
}
private String GetClearCommandText()
{
if (NpgsqlEventLog.Level == LogLevel.Debug)
- {
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetClearCommandText");
- }
- Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
+ Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
- Boolean functionReturnsRecord = false; // Functions don't return record by default.
+ Boolean functionReturnsRecord = false; // Functions don't return record by default.
- Boolean functionReturnsRefcursor = false; // Functions don't return refcursor by default.
+ Boolean functionReturnsRefcursor = false; // Functions don't return refcursor by default.
String result = text;
-
if (type == CommandType.StoredProcedure)
{
+
if (Parameters.Count > 0)
- {
- functionReturnsRecord = !CheckFunctionHasOutParameters() && CheckFunctionReturn("record");
- }
+ functionReturnsRecord = CheckFunctionReturn("record");
functionReturnsRefcursor = CheckFunctionReturn("refcursor");
@@ -851,40 +920,33 @@ namespace Npgsql
}
if (Connector.SupportsPrepare)
- {
result = "select * from " + result; // This syntax is only available in 7.3+ as well SupportsPrepare.
- }
else
- {
- result = "select " + result; //Only a single result return supported. 7.2 and earlier.
- }
+ result = "select " + result; //Only a single result return supported. 7.2 and earlier.
}
else if (type == CommandType.TableDirect)
- {
- return "select * from " + result; // There is no parameter support on table direct.
- }
+ return "select * from " + result; // There is no parameter support on table direct.
if (parameters == null || parameters.Count == 0)
{
if (addProcedureParenthesis)
- {
result += ")";
- }
// If function returns ref cursor just process refcursor-result function call
// and return command which will be used to return data from refcursor.
if (functionReturnsRefcursor)
- {
return ProcessRefcursorFunctionReturn(result);
- }
if (functionReturnsRecord)
- {
result = AddFunctionReturnsRecordSupport(result);
- }
+
+
+ result = AddSingleRowBehaviorSupport(result);
+
+ result = AddSchemaOnlyBehaviorSupport(result);
return result;
}
@@ -908,36 +970,35 @@ namespace Npgsql
foreach (String s in queryparts)
{
if (s == string.Empty)
- {
continue;
- }
- if ((s[0] == ':' || s[0] == '@') && Parameters.TryGetValue(s, out p))
+ if ((s[0] == ':' || s[0] == '@') &&
+ Parameters.TryGetValue(s, out p))
{
-
// It's a parameter. Lets handle it.
- if ((p.Direction == ParameterDirection.Input) || (p.Direction == ParameterDirection.InputOutput))
+ if ((p.Direction == ParameterDirection.Input) ||
+ (p.Direction == ParameterDirection.InputOutput))
{
-
+ // FIXME DEBUG ONLY
+ // adding the '::<datatype>' on the end of a parameter is a highly
+ // questionable practice, but it is great for debugging!
sb.Append(p.TypeInfo.ConvertToBackend(p.Value, false));
-
- if (p.UseCast)
+
+ // Only add data type info if we are calling an stored procedure.
+
+ if (type == CommandType.StoredProcedure)
{
sb.Append("::");
- sb.Append(p.TypeInfo.CastName);
-
+ sb.Append(p.TypeInfo.Name);
- if (p.TypeInfo.UseSize && (p.Size > 0))
- {
- sb.Append("(").Append(p.Size).Append(")");
- }
- }
+ if (p.TypeInfo.UseSize && (p.Size > 0))
+ sb.Append("(").Append(p.Size).Append(")");
+ }
}
+
}
else
- {
sb.Append(s);
- }
}
result = sb.ToString();
@@ -945,70 +1006,49 @@ namespace Npgsql
else
{
+
for (Int32 i = 0; i < parameters.Count; i++)
{
NpgsqlParameter Param = parameters[i];
- if ((Param.Direction == ParameterDirection.Input) || (Param.Direction == ParameterDirection.InputOutput))
- {
- if (Param.UseCast)
- result += Param.TypeInfo.ConvertToBackend(Param.Value, false) + "::" + Param.TypeInfo.CastName + ",";
- else
- result += Param.TypeInfo.ConvertToBackend(Param.Value, false) + ",";
- }
+ if ((Param.Direction == ParameterDirection.Input) ||
+ (Param.Direction == ParameterDirection.InputOutput))
+
+
+ result += Param.TypeInfo.ConvertToBackend(Param.Value, false) + "::" + Param.TypeInfo.Name + ",";
}
// Remove a trailing comma added from parameter handling above. If any.
// Maybe there are only output parameters. If so, there will be no comma.
if (result.EndsWith(","))
- {
result = result.Remove(result.Length - 1, 1);
- }
result += ")";
}
if (functionReturnsRecord)
- {
result = AddFunctionReturnsRecordSupport(result);
- }
// If function returns ref cursor just process refcursor-result function call
// and return command which will be used to return data from refcursor.
if (functionReturnsRefcursor)
- {
return ProcessRefcursorFunctionReturn(result);
- }
+
+ result = AddSingleRowBehaviorSupport(result);
+
+ result = AddSchemaOnlyBehaviorSupport(result);
+
return result;
}
-
-
- private Boolean CheckFunctionHasOutParameters()
+
+
+
+ private Boolean CheckFunctionReturn(String ReturnType)
{
- // Check if this function has output parameters.
- // This is used to enable or not the colum definition list
- // when calling functions which return record.
- // Functions which has out or inout parameters have return record
- // but doesn't allow column definition list.
- // See http://pgfoundry.org/forum/forum.php?thread_id=1075&forum_id=519
- // for discussion about that.
-
-
- // inout parameters are only supported from 8.1+ versions.
- if (Connection.PostgreSqlVersion < new Version(8, 1, 0))
- {
- return false;
- }
-
-
- //String outParameterExistanceQuery =
- // "select count(*) > 0 from pg_proc where proname=:proname and ('o' = any (proargmodes) OR 'b' = any(proargmodes))";
-
-
// Updated after 0.99.3 to support the optional existence of a name qualifying schema and allow for case insensitivity
// when the schema or procedure name do not contain a quote.
// The hard-coded schema name 'public' was replaced with code that uses schema as a qualifier, only if it is provided.
@@ -1017,30 +1057,30 @@ namespace Npgsql
StringBuilder parameterTypes = new StringBuilder("");
-
+
// Process parameters
-
- foreach (NpgsqlParameter p in Parameters)
+
+ foreach(NpgsqlParameter p in Parameters)
{
- if ((p.Direction == ParameterDirection.Input) || (p.Direction == ParameterDirection.InputOutput))
+ if ((p.Direction == ParameterDirection.Input) ||
+ (p.Direction == ParameterDirection.InputOutput))
{
parameterTypes.Append(Connection.Connector.OidToNameMapping[p.TypeInfo.Name].OID + " ");
}
}
-
+
// Process schema name.
-
+
String schemaName = String.Empty;
String procedureName = String.Empty;
-
-
+
+
String[] fullName = CommandText.Split('.');
-
+
if (fullName.Length == 2)
{
- returnRecordQuery =
- "select count(*) > 0 from pg_proc p left join pg_namespace n on p.pronamespace = n.oid where prorettype = ( select oid from pg_type where typname = 'record' ) and proargtypes=:proargtypes and proname=:proname and n.nspname=:nspname and ('o' = any (proargmodes) OR 'b' = any(proargmodes))";
+ returnRecordQuery = "select count(*) > 0 from pg_proc p left join pg_namespace n on p.pronamespace = n.oid where prorettype = ( select oid from pg_type where typname = :typename ) and proargtypes=:proargtypes and proname=:proname and n.nspname=:nspname";
schemaName = (fullName[0].IndexOf("\"") != -1) ? fullName[0] : fullName[0].ToLower();
procedureName = (fullName[1].IndexOf("\"") != -1) ? fullName[1] : fullName[1].ToLower();
@@ -1049,144 +1089,74 @@ namespace Npgsql
{
// Instead of defaulting don't use the nspname, as an alternative, query pg_proc and pg_namespace to try and determine the nspname.
//schemaName = "public"; // This was removed after build 0.99.3 because the assumption that a function is in public is often incorrect.
- returnRecordQuery =
- "select count(*) > 0 from pg_proc p where prorettype = ( select oid from pg_type where typname = 'record' ) and proargtypes=:proargtypes and proname=:proname and ('o' = any (proargmodes) OR 'b' = any(proargmodes))";
-
+ returnRecordQuery = "select count(*) > 0 from pg_proc p where prorettype = ( select oid from pg_type where typname = :typename ) and proargtypes=:proargtypes and proname=:proname";
+
procedureName = (CommandText.IndexOf("\"") != -1) ? CommandText : CommandText.ToLower();
}
-
+
+
+
NpgsqlCommand c = new NpgsqlCommand(returnRecordQuery, Connection);
-
- c.Parameters.Add(new NpgsqlParameter("proargtypes", NpgsqlDbType.Oidvector));
+
+ c.Parameters.Add(new NpgsqlParameter("typename", NpgsqlDbType.Text));
+ c.Parameters.Add(new NpgsqlParameter("proargtypes", NpgsqlDbType.Text));
c.Parameters.Add(new NpgsqlParameter("proname", NpgsqlDbType.Text));
-
- c.Parameters[0].Value = parameterTypes.ToString();
- c.Parameters[1].Value = procedureName;
+
+ c.Parameters[0].Value = ReturnType;
+ c.Parameters[1].Value = parameterTypes.ToString();
+ c.Parameters[2].Value = procedureName;
if (schemaName != null && schemaName.Length > 0)
{
c.Parameters.Add(new NpgsqlParameter("nspname", NpgsqlDbType.Text));
- c.Parameters[2].Value = schemaName;
+ c.Parameters[3].Value = schemaName;
}
+
-
- Boolean ret = (Boolean)c.ExecuteScalar();
+ Boolean ret = (Boolean) c.ExecuteScalar();
// reset any responses just before getting new ones
- m_Connector.Mediator.ResetResponses();
-
+ connector.Mediator.ResetResponses();
+
// Set command timeout.
- m_Connector.Mediator.CommandTimeout = CommandTimeout;
-
+ connector.Mediator.CommandTimeout = CommandTimeout;
+
return ret;
- }
- private Boolean CheckFunctionReturn(String ReturnType)
- {
- // Updated after 0.99.3 to support the optional existence of a name qualifying schema and allow for case insensitivity
- // when the schema or procedure name do not contain a quote.
- // The hard-coded schema name 'public' was replaced with code that uses schema as a qualifier, only if it is provided.
-
- String returnRecordQuery;
-
- StringBuilder parameterTypes = new StringBuilder("");
-
-
- // Process parameters
-
- foreach (NpgsqlParameter p in Parameters)
- {
- if ((p.Direction == ParameterDirection.Input) || (p.Direction == ParameterDirection.InputOutput))
- {
- parameterTypes.Append(Connection.Connector.OidToNameMapping[p.TypeInfo.Name].OID + " ");
- }
- }
-
-
- // Process schema name.
-
- String schemaName = String.Empty;
- String procedureName = String.Empty;
-
-
- String[] fullName = CommandText.Split('.');
- if (fullName.Length == 2)
- {
- returnRecordQuery =
- "select count(*) > 0 from pg_proc p left join pg_namespace n on p.pronamespace = n.oid where prorettype = ( select oid from pg_type where typname = :typename ) and proargtypes=:proargtypes and proname=:proname and n.nspname=:nspname";
-
- schemaName = (fullName[0].IndexOf("\"") != -1) ? fullName[0] : fullName[0].ToLower();
- procedureName = (fullName[1].IndexOf("\"") != -1) ? fullName[1] : fullName[1].ToLower();
- }
- else
- {
- // Instead of defaulting don't use the nspname, as an alternative, query pg_proc and pg_namespace to try and determine the nspname.
- //schemaName = "public"; // This was removed after build 0.99.3 because the assumption that a function is in public is often incorrect.
- returnRecordQuery =
- "select count(*) > 0 from pg_proc p where prorettype = ( select oid from pg_type where typname = :typename ) and proargtypes=:proargtypes and proname=:proname";
-
- procedureName = (CommandText.IndexOf("\"") != -1) ? CommandText : CommandText.ToLower();
- }
-
-
- bool ret;
-
- using (NpgsqlCommand c = new NpgsqlCommand(returnRecordQuery, Connection))
- {
- c.Parameters.Add(new NpgsqlParameter("typename", NpgsqlDbType.Text));
- c.Parameters.Add(new NpgsqlParameter("proargtypes", NpgsqlDbType.Oidvector));
- c.Parameters.Add(new NpgsqlParameter("proname", NpgsqlDbType.Text));
-
- c.Parameters[0].Value = ReturnType;
- c.Parameters[1].Value = parameterTypes.ToString();
- c.Parameters[2].Value = procedureName;
-
- if (schemaName != null && schemaName.Length > 0)
- {
- c.Parameters.Add(new NpgsqlParameter("nspname", NpgsqlDbType.Text));
- c.Parameters[3].Value = schemaName;
- }
-
-
- ret = (Boolean)c.ExecuteScalar();
- }
-
- // reset any responses just before getting new ones
- m_Connector.Mediator.ResetResponses();
-
- // Set command timeout.
- m_Connector.Mediator.CommandTimeout = CommandTimeout;
-
- return ret;
}
-
-
+
+
private String AddFunctionReturnsRecordSupport(String OriginalResult)
{
+
StringBuilder sb = new StringBuilder(OriginalResult);
-
+
sb.Append(" as (");
-
- foreach (NpgsqlParameter p in Parameters)
+
+ foreach(NpgsqlParameter p in Parameters)
{
- if ((p.Direction == ParameterDirection.Output) || (p.Direction == ParameterDirection.InputOutput))
+ if ((p.Direction == ParameterDirection.Output) ||
+ (p.Direction == ParameterDirection.InputOutput))
{
- sb.Append(String.Format("{0} {1}, ", p.CleanName, p.TypeInfo.Name));
+ sb.Append(String.Format("{0} {1}, ", p.ParameterName.Substring(1), p.TypeInfo.Name));
}
}
-
+
String result = sb.ToString();
-
+
result = result.Remove(result.Length - 2, 1);
-
+
result += ")";
-
-
+
+
+
return result;
+
+
}
-
+
///<summary>
/// This methods takes a string with a function call witch returns a refcursor or a set of
/// refcursor. It will return the names of the open cursors/portals which will hold
@@ -1194,40 +1164,42 @@ namespace Npgsql
/// in form of one resultset for each cursor open. This way, clients don't need to do anything
/// else besides calling function normally to get results in this way.
///</summary>
+
private String ProcessRefcursorFunctionReturn(String FunctionCall)
{
+ NpgsqlCommand c = new NpgsqlCommand(FunctionCall, Connection);
+
+ NpgsqlDataReader dr = c.ExecuteReader();
+
StringBuilder sb = new StringBuilder();
- using (NpgsqlCommand c = new NpgsqlCommand(FunctionCall, Connection))
+
+ while (dr.Read())
{
- using (NpgsqlDataReader dr = c.GetReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
- {
- while (dr.Read())
- {
- sb.Append("fetch all from \"").Append(dr.GetString(0)).Append("\";");
- }
- }
+ sb.Append("fetch all from \"").Append(dr.GetString(0)).Append("\";");
+
}
-
+
sb.Append(";"); // Just in case there is no response from refcursor function return.
-
+
// reset any responses just before getting new ones
- m_Connector.Mediator.ResetResponses();
-
+ connector.Mediator.ResetResponses();
+
// Set command timeout.
- m_Connector.Mediator.CommandTimeout = CommandTimeout;
-
+ connector.Mediator.CommandTimeout = CommandTimeout;
+
return sb.ToString();
+
+
}
+
private String GetPreparedCommandText()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetPreparedCommandText");
if (parameters.Count == 0)
- {
- return string.Format("execute {0}", planName);
- }
+ return "execute " + planName;
StringBuilder result = new StringBuilder("execute " + planName + '(');
@@ -1235,46 +1207,40 @@ namespace Npgsql
for (Int32 i = 0; i < parameters.Count; i++)
{
- if (parameters[i].UseCast)
- result.Append(string.Format("{0}::{1},", parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, false), parameters[i].TypeInfo.CastName));
- else
- result.Append(parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, false) + ',');
-
+ result.Append(parameters[i].TypeInfo.ConvertToBackend(parameters[i].Value, false) + ',');
}
result = result.Remove(result.Length - 1, 1);
result.Append(')');
return result.ToString();
+
}
+
private String GetParseCommandText()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetParseCommandText");
- Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
-
+ Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
+
String parseCommand = text;
if (type == CommandType.StoredProcedure)
{
// Check if just procedure name was passed. If so, does not replace parameter names and just pass parameter values in order they were added in parameters collection.
- if (!parseCommand.Trim().EndsWith(")"))
+ if (!parseCommand.Trim().EndsWith(")"))
{
addProcedureParenthesis = true;
parseCommand += "(";
}
-
- parseCommand = string.Format("select * from {0}", parseCommand); // This syntax is only available in 7.3+ as well SupportsPrepare.
- }
- else
- {
- if (type == CommandType.TableDirect)
- {
- return string.Format("select * from {0}", parseCommand); // There is no parameter support on TableDirect.
- }
+
+ parseCommand = "select * from " + parseCommand; // This syntax is only available in 7.3+ as well SupportsPrepare.
}
+ else if (type == CommandType.TableDirect)
+ return "select * from " + parseCommand; // There is no parameter support on TableDirect.
+
if (parameters.Count > 0)
{
// The ReplaceParameterValue below, also checks if the parameter is present.
@@ -1285,43 +1251,28 @@ namespace Npgsql
for (i = 0; i < parameters.Count; i++)
{
if ((parameters[i].Direction == ParameterDirection.Input) ||
- (parameters[i].Direction == ParameterDirection.InputOutput))
+ (parameters[i].Direction == ParameterDirection.InputOutput))
{
+
if (!addProcedureParenthesis)
{
//result = result.Replace(":" + parameterName, parameters[i].Value.ToString());
- parameterName = parameters[i].CleanName;
+ parameterName = parameters[i].ParameterName;
//textCommand = textCommand.Replace(':' + parameterName, "$" + (i+1));
-
- // Just add typecast if needed.
- if (parameters[i].UseCast)
- parseCommand = ReplaceParameterValue(parseCommand, parameterName, string.Format("${0}::{1}", (i + 1), parameters[i].TypeInfo.CastName));
- else
- parseCommand = ReplaceParameterValue(parseCommand, parameterName, string.Format("${0}", (i + 1)));
+ parseCommand = ReplaceParameterValue(parseCommand, parameterName, "$" + (i+1) + "::" + parameters[i].TypeInfo.Name);
}
else
- {
- if (parameters[i].UseCast)
- parseCommand += string.Format("${0}::{1}", (i + 1), parameters[i].TypeInfo.CastName);
- else
- parseCommand += string.Format("${0}", (i + 1));
- }
+ parseCommand += "$" + (i+1) + "::" + parameters[i].TypeInfo.Name;
}
+
}
}
+ if (addProcedureParenthesis)
+ return parseCommand + ")";
+ else
+ return parseCommand;
- return string.Format("{0}{1}", parseCommand, addProcedureParenthesis ? ")" : string.Empty);
-
-
- //if (addProcedureParenthesis)
- //{
- // return parseCommand + ")";
- //}
- //else
- //{
- // return parseCommand;
- //}
}
@@ -1329,7 +1280,7 @@ namespace Npgsql
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetPrepareCommandText");
- Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
+ Boolean addProcedureParenthesis = false; // Do not add procedure parenthesis by default.
planName = Connector.NextPlanName();
@@ -1340,18 +1291,16 @@ namespace Npgsql
if (type == CommandType.StoredProcedure)
{
// Check if just procedure name was passed. If so, does not replace parameter names and just pass parameter values in order they were added in parameters collection.
- if (!textCommand.Trim().EndsWith(")"))
+ if (!textCommand.Trim().EndsWith(")"))
{
addProcedureParenthesis = true;
textCommand += "(";
}
-
+
textCommand = "select * from " + textCommand;
}
else if (type == CommandType.TableDirect)
- {
return "select * from " + textCommand; // There is no parameter support on TableDirect.
- }
if (parameters.Count > 0)
@@ -1364,22 +1313,22 @@ namespace Npgsql
for (i = 0; i < parameters.Count; i++)
{
if ((parameters[i].Direction == ParameterDirection.Input) ||
- (parameters[i].Direction == ParameterDirection.InputOutput))
+ (parameters[i].Direction == ParameterDirection.InputOutput))
{
+
if (!addProcedureParenthesis)
{
//result = result.Replace(":" + parameterName, parameters[i].Value.ToString());
- parameterName = parameters[i].CleanName;
+ parameterName = parameters[i].ParameterName;
// The space in front of '$' fixes a parsing problem in 7.3 server
// which gives errors of operator when finding the caracters '=$' in
// prepare text
- textCommand = ReplaceParameterValue(textCommand, parameterName, " $" + (i + 1));
+ textCommand = ReplaceParameterValue(textCommand, parameterName, " $" + (i+1));
}
else
- {
- textCommand += " $" + (i + 1);
- }
+ textCommand += " $" + (i+1);
}
+
}
//[TODO] Check if there are any missing parameters in the query.
@@ -1390,106 +1339,204 @@ namespace Npgsql
for (i = 0; i < parameters.Count; i++)
{
// command.Append(NpgsqlTypesHelper.GetDefaultTypeInfo(parameters[i].DbType));
- if (parameters[i].UseCast)
- command.Append(parameters[i].TypeInfo.Name);
- else
- command.Append("unknown");
+ command.Append(parameters[i].TypeInfo.Name);
command.Append(',');
}
command = command.Remove(command.Length - 1, 1);
command.Append(')');
- }
+ }
+
if (addProcedureParenthesis)
- {
textCommand += ")";
- }
command.Append(" as ");
command.Append(textCommand);
return command.ToString();
+
}
private static String ReplaceParameterValue(String result, String parameterName, String paramVal)
{
+
String quote_pattern = @"['][^']*[']";
- string parameterMarker = string.Empty;
- // search parameter marker since it is not part of the name
- String pattern = "[- |\n\r\t,)(;=+/<>][:|@]" + parameterMarker + parameterName + "([- |\n\r\t,)(;=+/<>]|$)";
+ String pattern = "[- |\n\r\t,)(;=+/]" + parameterName + "([- |\n\r\t,)(;=+/]|$)";
Int32 start, end;
String withoutquote = result;
Boolean found = false;
// First of all
// Suppress quoted string from query (because we ave to ignore them)
- MatchCollection results = Regex.Matches(result, quote_pattern);
+ MatchCollection results = Regex.Matches(result,quote_pattern);
foreach (Match match in results)
{
start = match.Index;
end = match.Index + match.Length;
- String spaces = new String(' ', match.Length - 2);
- withoutquote = withoutquote.Substring(0, start + 1) + spaces + withoutquote.Substring(end - 1);
+ String spaces = new String(' ', match.Length-2);
+ withoutquote = withoutquote.Substring(0,start + 1) + spaces + withoutquote.Substring(end - 1);
}
do
{
// Now we look for the searched parameters on the "withoutquote" string
- results = Regex.Matches(withoutquote, pattern);
+ results = Regex.Matches(withoutquote,pattern);
if (results.Count == 0)
- {
- // If no parameter is found, go out!
+ // If no parameter is found, go out!
break;
- }
// We take the first parameter found
found = true;
Match match = results[0];
start = match.Index;
- if ((match.Length - parameterName.Length) == 3)
- {
+ if ((match.Length - parameterName.Length) == 2)
// If the found string is not the end of the string
end = match.Index + match.Length - 1;
- }
else
- {
// If the found string is the end of the string
end = match.Index + match.Length;
- }
result = result.Substring(0, start + 1) + paramVal + result.Substring(end);
- withoutquote = withoutquote.Substring(0, start + 1) + paramVal + withoutquote.Substring(end);
+ withoutquote = withoutquote.Substring(0,start + 1) + paramVal + withoutquote.Substring(end);
}
while (true);
if (!found)
+ throw new IndexOutOfRangeException (String.Format(resman.GetString("Exception_ParamNotInQuery"),
+ parameterName));
+ return result;
+ }
+
+
+ private String AddSingleRowBehaviorSupport(String ResultCommandText)
+ {
+
+ ResultCommandText = ResultCommandText.Trim();
+
+ // Do not add SingleRowBehavior if SchemaOnly behavior is set.
+
+ if ((commandBehavior & CommandBehavior.SchemaOnly) == CommandBehavior.SchemaOnly)
+ return ResultCommandText;
+
+ if ((commandBehavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow)
{
- throw new IndexOutOfRangeException(String.Format(resman.GetString("Exception_ParamNotInQuery"), parameterName));
+ if (ResultCommandText.EndsWith(";"))
+ ResultCommandText = ResultCommandText.Substring(0, ResultCommandText.Length - 1);
+ ResultCommandText += " limit 1;";
+
}
- return result;
+
+
+
+ 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 SetCommandTimeout()
+
+ private void ExecuteCommand()
{
- if (Connection != null)
+ try
{
- timeout = Connection.CommandTimeout;
+
+ // Check the connection state first.
+ CheckConnectionState();
+
+ // reset any responses just before getting new ones
+ Connector.Mediator.ResetResponses();
+
+ // Set command timeout.
+ connector.Mediator.CommandTimeout = CommandTimeout;
+
+
+ connector.StopNotificationThread();
+
+
+ if (parse == null)
+ {
+ connector.Query(this);
+
+
+ connector.ResumeNotificationThread();
+
+ // Check for errors and/or notifications and do the Right Thing.
+ connector.CheckErrorsAndNotifications();
+
+
+
}
else
{
- timeout = (int)NpgsqlConnectionStringBuilder.GetDefaultValue(Keywords.CommandTimeout);
+ try
+ {
+
+ BindParameters();
+
+ connector.Execute(new NpgsqlExecute(bind.PortalName, 0));
+
+ // Check for errors and/or notifications and do the Right Thing.
+ connector.CheckErrorsAndNotifications();
+ }
+ catch
+ {
+ // As per documentation:
+ // "[...] When an error is detected while processing any extended-query message,
+ // the backend issues ErrorResponse, then reads and discards messages until a
+ // Sync is reached, then issues ReadyForQuery and returns to normal message processing.[...]"
+ // So, send a sync command if we get any problems.
+
+ connector.Sync();
+
+ throw;
+ }
+ finally
+ {
+ connector.ResumeNotificationThread();
+ }
+ }
+
+ }
+
+ catch(IOException e)
+ {
+ ClearPoolAndThrowException(e);
}
+
}
- internal NpgsqlException ClearPoolAndCreateException(Exception e)
+ private void SetCommandTimeout()
{
- Connection.ClearPool();
- return new NpgsqlException(resman.GetString("Exception_ConnectionBroken"), e);
+ if (Connector != null)
+ timeout = Connector.CommandTimeout;
+ else
+ timeout = ConnectionStringDefaults.CommandTimeout;
}
- public override bool DesignTimeVisible
+ private void ClearPoolAndThrowException(Exception e)
{
- get { return designTimeVisible; }
- set { designTimeVisible = value; }
+ Connection.ClearPool();
+ throw new NpgsqlException(resman.GetString("Exception_ConnectionBroken"), e);
+
}
+
+
+
+
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs b/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs
index 9935d2e8ab6..4628d91ce0a 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlCommandBuilder.cs
@@ -5,286 +5,488 @@
//
// 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
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
+using System.Resources;
using System.Data;
using System.Data.Common;
-using System.Globalization;
-using System.Resources;
+using System.ComponentModel;
using NpgsqlTypes;
namespace Npgsql
{
- ///<summary>
- /// This class is responsible to create database commands for automatic insert, update and delete operations.
- ///</summary>
- public sealed class NpgsqlCommandBuilder : DbCommandBuilder
- {
- // Logging related values
- //private static readonly String CLASSNAME = "NpgsqlCommandBuilder";
- private readonly static ResourceManager resman = new ResourceManager(typeof (NpgsqlCommandBuilder));
- private NpgsqlRowUpdatingEventHandler rowUpdatingHandler;
-
-
- public NpgsqlCommandBuilder()
- : this(null)
- {
- }
- public NpgsqlCommandBuilder(NpgsqlDataAdapter adapter)
- : base()
- {
- DataAdapter = adapter;
- this.QuotePrefix = "\"";
- this.QuoteSuffix = "\"";
- }
+ ///<summary>
+ /// This class is responsible to create database commands for automatic insert, update and delete operations.
+ ///</summary>
+ public sealed class NpgsqlCommandBuilder : Component
+ {
+
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlCommandBuilder";
+ private static ResourceManager resman = new ResourceManager(typeof(NpgsqlCommandBuilder));
+
+ bool disposed = false;
+
+
+ private NpgsqlDataAdapter data_adapter;
+ private NpgsqlCommand insert_command;
+ private NpgsqlCommand update_command;
+ private NpgsqlCommand delete_command;
+
+ private string quotePrefix = "\"";
+ private string quoteSuffix = "\"";
+ private DataTable select_schema;
+
+ public NpgsqlCommandBuilder ()
+ {}
+
+ public NpgsqlCommandBuilder (NpgsqlDataAdapter adapter)
+ {
+ DataAdapter = adapter;
+ }
+
+ public NpgsqlDataAdapter DataAdapter {
+ get
+ {
+ return data_adapter;
+ }
+ set
+ {
+ if (data_adapter != null)
+ {
+ throw new InvalidOperationException ("DataAdapter is already set");
+ }
+ data_adapter = value;
+ data_adapter.RowUpdating += new NpgsqlRowUpdatingEventHandler(OnRowUpdating);
+ }
+ }
+
+ private void OnRowUpdating(Object sender, NpgsqlRowUpdatingEventArgs value) {
+ switch (value.StatementType)
+ {
+ case StatementType.Insert:
+ value.Command = GetInsertCommand(value.Row, false);
+ break;
+ case StatementType.Update:
+ value.Command = GetUpdateCommand(value.Row, false);
+ break;
+ case StatementType.Delete:
+ value.Command = GetDeleteCommand(value.Row, false);
+ break;
+ }
+
+ DataColumnMappingCollection columnMappings = value.TableMapping.ColumnMappings;
+ foreach (IDataParameter parameter in value.Command.Parameters)
+ {
+
+ string dsColumnName = parameter.SourceColumn;
+ if (columnMappings.Contains(parameter.SourceColumn))
+ {
+ DataColumnMapping mapping = columnMappings[parameter.SourceColumn];
+ if (mapping != null)
+ {
+ dsColumnName = mapping.DataSetColumn;
+ }
+ }
+
+ DataRowVersion rowVersion = DataRowVersion.Default;
+ if (value.StatementType == StatementType.Update)
+ rowVersion = parameter.SourceVersion;
+ if (value.StatementType == StatementType.Delete)
+ rowVersion = DataRowVersion.Original;
+ parameter.Value = value.Row [dsColumnName, rowVersion];
+ }
+ }
+
+ public string QuotePrefix {
+ get
+ {
+ return quotePrefix;
+ }
+ set
+ {
+ quotePrefix = value;
+ }
+ }
+
+ public string QuoteSuffix {
+ get
+ {
+ return quoteSuffix;
+ }
+ set
+ {
+ quoteSuffix = value;
+ }
+ }
- public override string QuotePrefix
- {
- get { return base.QuotePrefix; }
- set
- {
- if (String.IsNullOrEmpty(value))
- {
- base.QuotePrefix = value;
- }
- else
+ ///<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)
+ {
+
+ // Updated after 0.99.3 to support the optional existence of a name qualifying schema and case insensitivity when the schema ror procedure name do not contain a quote.
+ // This fixed an incompatibility with NpgsqlCommand.CheckFunctionReturn(String ReturnType)
+ String query = null;
+ string procedureName = null;
+ string schemaName = null;
+ string[] fullName = command.CommandText.Split('.');
+ if (fullName.Length > 1 && fullName[0].Length > 0)
+ {
+ query = "select proargtypes from pg_proc p left join pg_namespace n on p.pronamespace = n.oid where proname=:proname and n.nspname=:nspname";
+ schemaName = (fullName[0].IndexOf("\"") != -1) ? fullName[0] : fullName[0].ToLower();
+ procedureName = (fullName[1].IndexOf("\"") != -1) ? fullName[1] : fullName[1].ToLower();
+ }
+ else
+ {
+ query = "select proargtypes from pg_proc where proname = :proname";
+ procedureName = (fullName[0].IndexOf("\"") != -1) ? fullName[0] : fullName[0].ToLower();
+ }
+
+ NpgsqlCommand c = new NpgsqlCommand(query, command.Connection);
+ c.Parameters.Add(new NpgsqlParameter("proname", NpgsqlDbType.Text));
+
+
+ c.Parameters[0].Value = procedureName.Replace("\"", "").Trim();
+
+ if (fullName.Length > 1 && schemaName.Length > 0)
+ {
+ NpgsqlParameter prm = c.Parameters.Add(new NpgsqlParameter("nspname", NpgsqlDbType.Text));
+ prm.Value = schemaName.Replace("\"", "").Trim();
+ }
+
+ String types = (String) c.ExecuteScalar();
+
+ if (types == null)
+ throw new InvalidOperationException (String.Format(resman.GetString("Exception_InvalidFunctionName"), command.CommandText));
+
+ 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)
+ {
+ return GetInsertCommand(row, true);
+ }
+
+ private NpgsqlCommand GetInsertCommand(DataRow row, bool setParameterValues)
+ {
+ if (insert_command == null)
+ {
+ string fields = "";
+ string values = "";
+ bool first = true;
+ if (select_schema == null)
{
- base.QuotePrefix = "\"";
+ BuildSchema();
}
- }
- }
-
- public override string QuoteSuffix
- {
- get { return base.QuoteSuffix; }
- set
- {
- if (String.IsNullOrEmpty(value))
+ string schema_name = string.Empty;
+ string table_name = string.Empty;
+ string quotedName;
+ NpgsqlCommand cmdaux = new NpgsqlCommand();
+ foreach(DataRow schemaRow in select_schema.Rows)
{
- base.QuoteSuffix = value;
+ if (!(bool)schemaRow["IsAutoIncrement"])
+ {
+ if (!first)
+ {
+ fields += ", ";
+ values += ", ";
+ }
+ else
+ {
+ schema_name = (string)schemaRow["BaseSchemaName"];
+ table_name = (string)schemaRow["BaseTableName"];
+ if (table_name == null || table_name.Length == 0)
+ {
+ table_name = row.Table.TableName;
+ }
+ }
+ quotedName = GetQuotedName((string)schemaRow["BaseColumnName"]);
+ DataColumn column = row.Table.Columns[(string)schemaRow["ColumnName"]];
+
+ fields += quotedName;
+ values += ":param_" + column.ColumnName;
+ first = false;
+
+ NpgsqlParameter aux = new NpgsqlParameter("param_" + column.ColumnName, NpgsqlTypesHelper.GetNativeTypeInfo(column.DataType));
+ aux.Direction = ParameterDirection.Input;
+ aux.SourceColumn = column.ColumnName;
+ cmdaux.Parameters.Add(aux);
+ }
}
- else
+ cmdaux.CommandText = "insert into " + QualifiedTableName(schema_name, table_name) + " (" + fields + ") values (" + values + ")";
+ cmdaux.Connection = data_adapter.SelectCommand.Connection;
+ insert_command = cmdaux;
+ }
+ if (setParameterValues)
+ {
+ SetParameterValuesFromRow(insert_command, row);
+ }
+ return insert_command;
+ }
+
+ public NpgsqlCommand GetUpdateCommand (DataRow row)
+ {
+ return GetUpdateCommand(row, true);
+ }
+
+ private NpgsqlCommand GetUpdateCommand(DataRow row, bool setParameterValues)
+ {
+ if (update_command == null)
+ {
+ string sets = "";
+ string wheres = "";
+ bool first = true;
+ if (select_schema == null)
{
- base.QuoteSuffix = "\"";
+ BuildSchema();
}
- }
- }
-
- ///<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)
- {
- // Updated after 0.99.3 to support the optional existence of a name qualifying schema and case insensitivity when the schema ror procedure name do not contain a quote.
- // This fixed an incompatibility with NpgsqlCommand.CheckFunctionReturn(String ReturnType)
- String query = null;
- string procedureName = null;
- string schemaName = null;
- string[] fullName = command.CommandText.Split('.');
- if (fullName.Length > 1 && fullName[0].Length > 0)
- {
- query =
- "select proargtypes from pg_proc p left join pg_namespace n on p.pronamespace = n.oid where proname=:proname and n.nspname=:nspname";
- schemaName = (fullName[0].IndexOf("\"") != -1) ? fullName[0] : fullName[0].ToLower();
- procedureName = (fullName[1].IndexOf("\"") != -1) ? fullName[1] : fullName[1].ToLower();
- }
- else
- {
- query = "select proargtypes from pg_proc where proname = :proname";
- procedureName = (fullName[0].IndexOf("\"") != -1) ? fullName[0] : fullName[0].ToLower();
- }
-
- using (NpgsqlCommand c = new NpgsqlCommand(query, command.Connection))
- {
- c.Parameters.Add(new NpgsqlParameter("proname", NpgsqlDbType.Text));
- c.Parameters[0].Value = procedureName.Replace("\"", "").Trim();
- if (fullName.Length > 1 && !String.IsNullOrEmpty(schemaName))
+ string schema_name = string.Empty;
+ string table_name = string.Empty;
+ string quotedName;
+ NpgsqlCommand cmdaux = new NpgsqlCommand();
+ foreach(DataRow schemaRow in select_schema.Rows)
{
- NpgsqlParameter prm = c.Parameters.Add(new NpgsqlParameter("nspname", NpgsqlDbType.Text));
- prm.Value = schemaName.Replace("\"", "").Trim();
+ if (!first)
+ {
+ sets += ", ";
+ wheres += " and ";
+ }
+ else
+ {
+ schema_name = (string)schemaRow["BaseSchemaName"];
+ table_name = (string)schemaRow["BaseTableName"];
+ if (table_name == null || table_name.Length == 0)
+ {
+ table_name = row.Table.TableName;
+ }
+ }
+ quotedName = GetQuotedName((string)schemaRow["BaseColumnName"]);
+ DataColumn column = row.Table.Columns[(string)schemaRow["ColumnName"]];
+ sets += String.Format("{0} = :s_param_{1}", quotedName, column.ColumnName);
+ wheres += String.Format("(({0} is null) or ({0} = :w_param_{1}))", quotedName, column.ColumnName);
+ first = false;
+
+ NpgsqlNativeTypeInfo typeInfo = NpgsqlTypesHelper.GetNativeTypeInfo(column.DataType);
+ NpgsqlParameter aux_set = new NpgsqlParameter("s_param_" + column.ColumnName, typeInfo);
+ aux_set.Direction = ParameterDirection.Input;
+ aux_set.SourceColumn = column.ColumnName;
+ aux_set.SourceVersion = DataRowVersion.Current;
+ cmdaux.Parameters.Add(aux_set);
+
+ NpgsqlParameter aux_where = new NpgsqlParameter("w_param_" + column.ColumnName, typeInfo);
+ aux_where.Direction = ParameterDirection.Input;
+ aux_where.SourceColumn = column.ColumnName;
+ aux_where.SourceVersion = DataRowVersion.Original;
+ cmdaux.Parameters.Add(aux_where);
}
- String types = (String) c.ExecuteScalar();
- if (types == null)
+ cmdaux.CommandText = "update " + QualifiedTableName(schema_name, table_name) + " set " + sets + " where ( " + wheres + " )";
+ cmdaux.Connection = data_adapter.SelectCommand.Connection;
+ update_command = cmdaux;
+
+ }
+ if (setParameterValues)
+ {
+ SetParameterValuesFromRow(update_command, row);
+ }
+ return update_command;
+ }
+
+ public NpgsqlCommand GetDeleteCommand (DataRow row)
+ {
+ return GetDeleteCommand(row, true);
+ }
+
+ private NpgsqlCommand GetDeleteCommand(DataRow row, bool setParameterValues)
+ {
+ if (delete_command == null)
+ {
+ string wheres = "";
+ bool first = true;
+ if (select_schema == null)
{
- throw new InvalidOperationException(
- String.Format(resman.GetString("Exception_InvalidFunctionName"), command.CommandText));
+ BuildSchema();
}
-
- command.Parameters.Clear();
- Int32 i = 1;
- foreach (String s in types.Split())
+ string schema_name = string.Empty;
+ string table_name = string.Empty;
+ string quotedName;
+ NpgsqlCommand cmdaux = new NpgsqlCommand();
+ foreach(DataRow schemaRow in select_schema.Rows)
{
- NpgsqlBackendTypeInfo typeInfo = null;
- if (!c.Connector.OidToNameMapping.TryGetValue(int.Parse(s), out typeInfo))
+ if (!first)
{
- command.Parameters.Clear();
- throw new InvalidOperationException(String.Format("Invalid parameter type: {0}", s));
+ wheres += " and ";
}
- command.Parameters.Add(new NpgsqlParameter("parameter" + i++, typeInfo.NpgsqlDbType));
+ else
+ {
+ schema_name = (string)schemaRow["BaseSchemaName"];
+ table_name = (string)schemaRow["BaseTableName"];
+ if (table_name == null || table_name.Length == 0)
+ {
+ table_name = row.Table.TableName;
+ }
+ }
+
+ quotedName = GetQuotedName((string)schemaRow["BaseColumnName"]);
+ DataColumn column = row.Table.Columns[(string)schemaRow["ColumnName"]];
+
+ wheres += String.Format("(({0} is null) or ({0} = :param_{1}))", quotedName , column.ColumnName);
+ first = false;
+
+ NpgsqlParameter aux = new NpgsqlParameter("param_" + column.ColumnName, NpgsqlTypesHelper.GetNativeTypeInfo(column.DataType));
+ aux.Direction = ParameterDirection.Input;
+ aux.SourceColumn = column.ColumnName;
+ aux.SourceVersion = DataRowVersion.Original;
+ cmdaux.Parameters.Add(aux);
}
- }
- }
-
- public new NpgsqlCommand GetInsertCommand()
- {
- return (NpgsqlCommand) base.GetInsertCommand();
- }
-
- public new NpgsqlCommand GetInsertCommand(bool useColumnsForParameterNames)
- {
- return (NpgsqlCommand) base.GetInsertCommand(useColumnsForParameterNames);
- }
-
- public new NpgsqlCommand GetUpdateCommand()
- {
- return (NpgsqlCommand) base.GetUpdateCommand();
- }
-
- public new NpgsqlCommand GetUpdateCommand(bool useColumnsForParameterNames)
- {
- return (NpgsqlCommand) base.GetUpdateCommand(useColumnsForParameterNames);
- }
-
- public new NpgsqlCommand GetDeleteCommand()
- {
- return (NpgsqlCommand) base.GetDeleteCommand();
- }
-
- public new NpgsqlCommand GetDeleteCommand(bool useColumnsForParameterNames)
- {
- return (NpgsqlCommand) base.GetDeleteCommand(useColumnsForParameterNames);
- }
-
- //never used
- //private string QualifiedTableName(string schema, string tableName)
- //{
- // if (schema == null || schema.Length == 0)
- // {
- // return tableName;
- // }
- // else
- // {
- // return schema + "." + tableName;
- // }
- //}
-
-/*
- private static void SetParameterValuesFromRow(NpgsqlCommand command, DataRow row)
- {
- foreach (NpgsqlParameter parameter in command.Parameters)
- {
- parameter.Value = row[parameter.SourceColumn, parameter.SourceVersion];
- }
- }
-*/
-
- protected override void ApplyParameterInfo(DbParameter p, DataRow row, StatementType statementType, bool whereClause)
- {
- NpgsqlParameter parameter = (NpgsqlParameter) p;
- parameter.DbType = NpgsqlTypesHelper.GetNativeTypeInfo((Type) row[SchemaTableColumn.DataType]).DbType;
- }
-
- protected override string GetParameterName(int parameterOrdinal)
- {
- return String.Format(CultureInfo.InvariantCulture, "@p{0}", parameterOrdinal);
- }
-
- protected override string GetParameterName(string parameterName)
- {
- return String.Format(CultureInfo.InvariantCulture, "@{0}", parameterName);
- }
-
- protected override string GetParameterPlaceholder(int parameterOrdinal)
- {
- return GetParameterName(parameterOrdinal);
- }
-
- protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
+ cmdaux.CommandText = "delete from " + QualifiedTableName(schema_name, table_name) + " where ( " + wheres + " )";
+ cmdaux.Connection = data_adapter.SelectCommand.Connection;
+ delete_command = cmdaux;
+ }
+ if (setParameterValues)
+ {
+ SetParameterValuesFromRow(delete_command, row);
+ }
+ return delete_command;
+ }
+
+ public void RefreshSchema ()
+ {
+ insert_command = null;
+ update_command = null;
+ delete_command = null;
+ select_schema = null;
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ if (insert_command != null)
+ {
+ insert_command.Dispose();
+ }
+ if (update_command != null)
+ {
+ update_command.Dispose();
+ }
+ if (delete_command != null)
+ {
+ delete_command.Dispose();
+ }
+
+ data_adapter.RowUpdating -= new NpgsqlRowUpdatingEventHandler(OnRowUpdating);
+ }
+ }
+ base.Dispose(disposing);
+ }
+
+ private void BuildSchema()
{
- if (!(adapter is NpgsqlDataAdapter))
- {
- throw new InvalidOperationException("adapter needs to be a NpgsqlDataAdapter");
- }
-
-
- this.rowUpdatingHandler = new NpgsqlRowUpdatingEventHandler(this.RowUpdatingHandler);
-
- ((NpgsqlDataAdapter) adapter).RowUpdating += this.rowUpdatingHandler;
- }
-
-
- private void RowUpdatingHandler(object sender, NpgsqlRowUpdatingEventArgs e)
-
- {
- base.RowUpdatingHandler(e);
- }
-
-
- public override string QuoteIdentifier(string unquotedIdentifier)
-
- {
- if (unquotedIdentifier == null)
-
+ if (select_schema == null)
{
- throw new ArgumentNullException("Unquoted identifier parameter cannot be null");
+ bool openedConnection = false;
+ try
+ {
+ if ((data_adapter.SelectCommand.Connection.State & ConnectionState.Open) != ConnectionState.Open)
+ {
+ data_adapter.SelectCommand.Connection.Open();
+ openedConnection = true;
+ }
+ using (NpgsqlDataReader reader = data_adapter.SelectCommand.ExecuteReader(CommandBehavior.SchemaOnly|CommandBehavior.KeyInfo))
+ {
+ select_schema = reader.GetSchemaTable();
+ }
+ }
+ finally
+ {
+ if (openedConnection)
+ {
+ data_adapter.SelectCommand.Connection.Close();
+ }
+ }
}
-
-
- return String.Format("{0}{1}{2}", this.QuotePrefix, unquotedIdentifier, this.QuoteSuffix);
}
-
- public override string UnquoteIdentifier(string quotedIdentifier)
-
- {
- if (quotedIdentifier == null)
-
- {
- throw new ArgumentNullException("Quoted identifier parameter cannot be null");
- }
-
-
- string unquotedIdentifier = quotedIdentifier.Trim();
-
-
- if (unquotedIdentifier.StartsWith(this.QuotePrefix))
-
- {
- unquotedIdentifier = unquotedIdentifier.Remove(0, 1);
- }
-
- if (unquotedIdentifier.EndsWith(this.QuoteSuffix))
-
- {
- unquotedIdentifier = unquotedIdentifier.Remove(unquotedIdentifier.Length - 1, 1);
- }
-
-
- return unquotedIdentifier;
- }
- }
-} \ No newline at end of file
+ /*~NpgsqlCommandBuilder ()
+ {
+ Dispose(false);
+ }*/
+
+ private string QualifiedTableName(string schema, string tableName)
+ {
+ if (schema == null || schema.Length == 0)
+ {
+ return GetQuotedName(tableName);
+ }
+ else
+ {
+ return GetQuotedName(schema) + "." + GetQuotedName(tableName);
+ }
+ }
+
+ private static void SetParameterValuesFromRow(NpgsqlCommand command, DataRow row)
+ {
+ foreach (NpgsqlParameter parameter in command.Parameters)
+ {
+ parameter.Value = row[parameter.SourceColumn, parameter.SourceVersion];
+ }
+ }
+ }
+
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnectedState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnectedState.cs
index 67b3e197d93..a32d89430fb 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnectedState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnectedState.cs
@@ -8,54 +8,72 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
using System.IO;
+
namespace Npgsql
{
- internal sealed class NpgsqlConnectedState : NpgsqlState
- {
- public static readonly NpgsqlConnectedState Instance = new NpgsqlConnectedState();
-
- private NpgsqlConnectedState()
- {
- }
-
- public override void Startup(NpgsqlConnector context)
- {
- NpgsqlStartupPacket startupPacket = new NpgsqlStartupPacket(296, //Not used.
- context.BackendProtocolVersion, context.Database,
- context.UserName, "", "", "");
-
- startupPacket.WriteToStream(new BufferedStream(context.Stream));
- context.RequireReadyForQuery = false;
- context.Mediator.CommandTimeout = 20;
- context.Stream.Flush();
- ProcessBackendResponses(context);
- }
-
- public override void CancelRequest(NpgsqlConnector context)
- {
- NpgsqlCancelRequest CancelRequestMessage = new NpgsqlCancelRequest(context.BackEndKeyData);
-
-
- CancelRequestMessage.WriteToStream(context.Stream);
- }
- }
-} \ No newline at end of file
+ internal sealed class NpgsqlConnectedState : NpgsqlState
+ {
+
+ private static NpgsqlConnectedState _instance = null;
+
+ private NpgsqlConnectedState()
+ {}
+
+ public static NpgsqlConnectedState Instance
+ {
+ get
+ {
+ if ( _instance == null )
+ {
+ _instance = new NpgsqlConnectedState();
+ }
+ return _instance;
+ }
+ }
+
+ public override void Startup(NpgsqlConnector context)
+ {
+ NpgsqlStartupPacket startupPacket = new NpgsqlStartupPacket(296, //Not used.
+ context.BackendProtocolVersion,
+ context.Database,
+ context.UserName,
+ "",
+ "",
+ "");
+
+ startupPacket.WriteToStream( new BufferedStream(context.Stream), context.Encoding );
+ context.Mediator.RequireReadyForQuery = false;
+ context.Mediator.CommandTimeout = 20;
+ context.Stream.Flush();
+ ProcessBackendResponses( context );
+ }
+
+ public override void CancelRequest(NpgsqlConnector context)
+ {
+ NpgsqlCancelRequest CancelRequestMessage = new NpgsqlCancelRequest(context.BackEndKeyData);
+
+
+ CancelRequestMessage.WriteToStream(context.Stream, context.Encoding);
+
+
+ }
+
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
index 56b5949e959..cbc595c351f 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnection.cs
@@ -9,969 +9,881 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.ComponentModel;
using System.Data;
-using System.Data.Common;
+using System.Text;
+using System.Collections;
using System.Resources;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
-using System.Transactions;
+
using Mono.Security.Protocol.Tls;
-using IsolationLevel = System.Data.IsolationLevel;
-#if WITHDESIGN
+using NpgsqlTypes;
+#if WITHDESIGN
+using Npgsql.Design;
#endif
namespace Npgsql
{
- /// <summary>
- /// Represents the method that handles the <see cref="Npgsql.NpgsqlConnection.Notification">Notice</see> events.
- /// </summary>
- /// <param name="e">A <see cref="Npgsql.NpgsqlNoticeEventArgs">NpgsqlNoticeEventArgs</see> that contains the event data.</param>
- public delegate void NoticeEventHandler(Object sender, NpgsqlNoticeEventArgs e);
-
- /// <summary>
- /// Represents the method that handles the <see cref="Npgsql.NpgsqlConnection.Notification">Notification</see> events.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">A <see cref="Npgsql.NpgsqlNotificationEventArgs">NpgsqlNotificationEventArgs</see> that contains the event data.</param>
- public delegate void NotificationEventHandler(Object sender, NpgsqlNotificationEventArgs e);
-
- /// <summary>
- /// This class represents a connection to a
- /// PostgreSQL server.
- /// </summary>
-#if WITHDESIGN
+ /// <summary>
+ /// Represents the method that handles the <see cref="Npgsql.NpgsqlConnection.Notification">Notice</see> events.
+ /// </summary>
+ /// <param name="e">A <see cref="Npgsql.NpgsqlNoticeEventArgs">NpgsqlNoticeEventArgs</see> that contains the event data.</param>
+ public delegate void NoticeEventHandler(Object sender, NpgsqlNoticeEventArgs e);
+
+ /// <summary>
+ /// Represents the method that handles the <see cref="Npgsql.NpgsqlConnection.Notification">Notification</see> events.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">A <see cref="Npgsql.NpgsqlNotificationEventArgs">NpgsqlNotificationEventArgs</see> that contains the event data.</param>
+ public delegate void NotificationEventHandler(Object sender, NpgsqlNotificationEventArgs e);
+
+ /// <summary>
+ /// This class represents a connection to a
+ /// PostgreSQL server.
+ /// </summary>
+ #if WITHDESIGN
[System.Drawing.ToolboxBitmapAttribute(typeof(NpgsqlConnection))]
-#endif
+ #endif
+
+ public sealed class NpgsqlConnection : Component, IDbConnection, ICloneable
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlConnection";
+ private static ResourceManager resman = new System.Resources.ResourceManager(typeof(NpgsqlConnection));
- public sealed class NpgsqlConnection : DbConnection, ICloneable
- {
- // Logging related values
- private static readonly String CLASSNAME = "NpgsqlConnection";
- private static readonly ResourceManager resman = new ResourceManager(typeof(NpgsqlConnection));
-
- // Parsed connection string cache
- private static readonly Cache<NpgsqlConnectionStringBuilder> cache = new Cache<NpgsqlConnectionStringBuilder>();
-
- /// <summary>
- /// Occurs on NoticeResponses from the PostgreSQL backend.
- /// </summary>
- public event NoticeEventHandler Notice;
-
- internal NoticeEventHandler NoticeDelegate;
-
- /// <summary>
- /// Occurs on NotificationResponses from the PostgreSQL backend.
- /// </summary>
- public event NotificationEventHandler Notification;
-
- internal NotificationEventHandler NotificationDelegate;
-
- /// <summary>
- /// Mono.Security.Protocol.Tls.CertificateSelectionCallback delegate.
- /// </summary>
- public event CertificateSelectionCallback CertificateSelectionCallback;
-
- internal CertificateSelectionCallback CertificateSelectionCallbackDelegate;
-
- /// <summary>
- /// Mono.Security.Protocol.Tls.CertificateValidationCallback delegate.
- /// </summary>
- public event CertificateValidationCallback CertificateValidationCallback;
-
- internal CertificateValidationCallback CertificateValidationCallbackDelegate;
-
- /// <summary>
- /// Mono.Security.Protocol.Tls.PrivateKeySelectionCallback delegate.
- /// </summary>
- public event PrivateKeySelectionCallback PrivateKeySelectionCallback;
-
- internal PrivateKeySelectionCallback PrivateKeySelectionCallbackDelegate;
-
- // Set this when disposed is called.
- private bool disposed = false;
-
- // Used when we closed the connector due to an error, but are pretending it's open.
- private bool _fakingOpen;
-
- // Strong-typed ConnectionString values
- private NpgsqlConnectionStringBuilder settings;
-
- // Connector being used for the active connection.
- private NpgsqlConnector connector = null;
-
- private readonly NpgsqlPromotableSinglePhaseNotification promotable = null;
-
- /// <summary>
- /// Initializes a new instance of the
- /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class.
- /// </summary>
- public NpgsqlConnection()
- : this(String.Empty)
- {
- }
-
- /// <summary>
- /// Initializes a new instance of the
- /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class
- /// and sets the <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
- /// </summary>
- /// <param name="ConnectionString">The connection used to open the PostgreSQL database.</param>
- public NpgsqlConnection(String ConnectionString)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, "NpgsqlConnection()");
-
- NpgsqlConnectionStringBuilder builder = cache[ConnectionString];
- if (builder == null)
- {
- settings = new NpgsqlConnectionStringBuilder(ConnectionString);
- }
- else
- {
- settings = builder.Clone();
- }
-
- LogConnectionString();
-
- NoticeDelegate = new NoticeEventHandler(OnNotice);
- NotificationDelegate = new NotificationEventHandler(OnNotification);
-
- CertificateValidationCallbackDelegate = new CertificateValidationCallback(DefaultCertificateValidationCallback);
- CertificateSelectionCallbackDelegate = new CertificateSelectionCallback(DefaultCertificateSelectionCallback);
- PrivateKeySelectionCallbackDelegate = new PrivateKeySelectionCallback(DefaultPrivateKeySelectionCallback);
-
- // Fix authentication problems. See https://bugzilla.novell.com/show_bug.cgi?id=MONO77559 and
- // http://pgfoundry.org/forum/message.php?msg_id=1002377 for more info.
- RSACryptoServiceProvider.UseMachineKeyStore = true;
-
- promotable = new NpgsqlPromotableSinglePhaseNotification(this);
- }
-
- /// <summary>
- /// Gets or sets the string used to connect to a PostgreSQL database.
- /// Valid values are:
- /// <ul>
- /// <li>
- /// Server: Address/Name of Postgresql Server;
- /// </li>
- /// <li>
- /// Port: Port to connect to;
- /// </li>
- /// <li>
- /// Protocol: Protocol version to use, instead of automatic; Integer 2 or 3;
- /// </li>
- /// <li>
- /// Database: Database name. Defaults to user name if not specified;
- /// </li>
- /// <li>
- /// User Id: User name;
- /// </li>
- /// <li>
- /// Password: Password for clear text authentication;
- /// </li>
- /// <li>
- /// SSL: True or False. Controls whether to attempt a secure connection. Default = False;
- /// </li>
- /// <li>
- /// Pooling: True or False. Controls whether connection pooling is used. Default = True;
- /// </li>
- /// <li>
- /// MinPoolSize: Min size of connection pool;
- /// </li>
- /// <li>
- /// MaxPoolSize: Max size of connection pool;
- /// </li>
- /// <li>
- /// Timeout: Time to wait for connection open in seconds. Default is 15.
- /// </li>
- /// <li>
- /// CommandTimeout: Time to wait for command to finish execution before throw an exception. In seconds. Default is 20.
- /// </li>
- /// <li>
- /// Sslmode: Mode for ssl connection control. Can be Prefer, Require, Allow or Disable. Default is Disable. Check user manual for explanation of values.
- /// </li>
- /// <li>
- /// ConnectionLifeTime: Time to wait before closing unused connections in the pool in seconds. Default is 15.
- /// </li>
- /// <li>
- /// SyncNotification: Specifies if Npgsql should use synchronous notifications.
- /// </li>
- /// <li>
- /// SearchPath: Changes search path to specified and public schemas.
- /// </li>
- /// </ul>
- /// </summary>
- /// <value>The connection string that includes the server name,
- /// the database name, and other parameters needed to establish
- /// the initial connection. The default value is an empty string.
- /// </value>
+ /// <summary>
+ /// Occurs on NoticeResponses from the PostgreSQL backend.
+ /// </summary>
+ public event NoticeEventHandler Notice;
+ internal NoticeEventHandler NoticeDelegate;
-#if WITHDESIGN
+ /// <summary>
+ /// Occurs on NotificationResponses from the PostgreSQL backend.
+ /// </summary>
+ public event NotificationEventHandler Notification;
+ internal NotificationEventHandler NotificationDelegate;
+
+ /// <summary>
+ /// Mono.Security.Protocol.Tls.CertificateSelectionCallback delegate.
+ /// </summary>
+ public event CertificateSelectionCallback CertificateSelectionCallback;
+ internal CertificateSelectionCallback CertificateSelectionCallbackDelegate;
+
+ /// <summary>
+ /// Mono.Security.Protocol.Tls.CertificateValidationCallback delegate.
+ /// </summary>
+ public event CertificateValidationCallback CertificateValidationCallback;
+ internal CertificateValidationCallback CertificateValidationCallbackDelegate;
+
+ /// <summary>
+ /// Mono.Security.Protocol.Tls.PrivateKeySelectionCallback delegate.
+ /// </summary>
+ public event PrivateKeySelectionCallback PrivateKeySelectionCallback;
+ internal PrivateKeySelectionCallback PrivateKeySelectionCallbackDelegate;
+
+ // Set this when disposed is called.
+ private bool disposed = false;
+
+ // Connection string values.
+ private NpgsqlConnectionString connection_string;
+
+ // Connector being used for the active connection.
+ private NpgsqlConnector connector = null;
+
+
+ /// <summary>
+ /// Initializes a new instance of the
+ /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class.
+ /// </summary>
+ public NpgsqlConnection() : this(String.Empty)
+ {}
+
+ /// <summary>
+ /// Initializes a new instance of the
+ /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see> class
+ /// and sets the <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
+ /// </summary>
+ /// <param name="ConnectionString">The connection used to open the PostgreSQL database.</param>
+ public NpgsqlConnection(String ConnectionString)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, "NpgsqlConnection()");
+
+ connection_string = NpgsqlConnectionString.ParseConnectionString(ConnectionString);
+ LogConnectionString();
+
+ NoticeDelegate = new NoticeEventHandler(OnNotice);
+ NotificationDelegate = new NotificationEventHandler(OnNotification);
+
+ CertificateValidationCallbackDelegate = new CertificateValidationCallback(DefaultCertificateValidationCallback);
+ CertificateSelectionCallbackDelegate = new CertificateSelectionCallback(DefaultCertificateSelectionCallback);
+ PrivateKeySelectionCallbackDelegate = new PrivateKeySelectionCallback(DefaultPrivateKeySelectionCallback);
+ }
+
+ /// <summary>
+ /// Gets or sets the string used to connect to a PostgreSQL database.
+ /// Valid values are:
+ /// <ul>
+ /// <li>
+ /// Server: Address/Name of Postgresql Server;
+ /// </li>
+ /// <li>
+ /// Port: Port to connect to;
+ /// </li>
+ /// <li>
+ /// Protocol: Protocol version to use, instead of automatic; Integer 2 or 3;
+ /// </li>
+ /// <li>
+ /// Database: Database name. Defaults to user name if not specified;
+ /// </li>
+ /// <li>
+
+ /// User Id: User name;
+ /// </li>
+ /// <li>
+
+ /// Password: Password for clear text authentication;
+ /// </li>
+ /// <li>
+
+ /// SSL: True or False. Controls whether to attempt a secure connection. Default = False;
+ /// </li>
+ /// <li>
+
+ /// Pooling: True or False. Controls whether connection pooling is used. Default = True;
+ /// </li>
+ /// <li>
+
+ /// MinPoolSize: Min size of connection pool;
+ /// </li>
+ /// <li>
+
+ /// MaxPoolSize: Max size of connection pool;
+ /// </li>
+ /// <li>
+
+ /// Encoding: Encoding to be used; Can be ASCII or UNICODE. Default is ASCII. Use UNICODE if you are having problems with accents.
+ /// </li>
+ /// <li>
+
+ /// Timeout: Time to wait for connection open in seconds. Default is 15.
+ /// </li>
+ /// <li>
+
+ /// CommandTimeout: Time to wait for command to finish execution before throw an exception. In seconds. Default is 20.
+ /// </li>
+ /// <li>
+
+ /// Sslmode: Mode for ssl connection control. Can be Prefer, Require, Allow or Disable. Default is Disable. Check user manual for explanation of values.
+ /// </li>
+
+ /// <li>
+
+ /// ConnectionLifeTime: Time to wait before closing unused connections in the pool in seconds. Default is 15.
+ /// </li>
+ /// <li>
+
+ /// SyncNotification: Specifies if Npgsql should use synchronous notifications.
+ /// </li>
+ /// </ul>
+
+
+ /// </summary>
+ /// <value>The connection string that includes the server name,
+ /// the database name, and other parameters needed to establish
+ /// the initial connection. The default value is an empty string.
+ /// </value>
+
+ #if WITHDESIGN
[RefreshProperties(RefreshProperties.All), DefaultValue(""), RecommendedAsConfigurable(true)]
[NpgsqlSysDescription("Description_ConnectionString", typeof(NpgsqlConnection)), Category("Data")]
[Editor(typeof(ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
-#endif
+ #endif
+
+ public String ConnectionString {
+ get
+ {
+ return connection_string.ToString();
+ }
+ set
+ {
+ // Connection string is used as the key to the connector. Because of this,
+ // we cannot change it while we own a connector.
+ CheckConnectionClosed();
+ NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "ConnectionString", value);
+ connection_string = NpgsqlConnectionString.ParseConnectionString(value);
+ LogConnectionString();
+ }
+ }
- public override String ConnectionString
- {
- get { return settings.ConnectionString; }
- set
- {
- // Connection string is used as the key to the connector. Because of this,
- // we cannot change it while we own a connector.
- CheckConnectionClosed();
- NpgsqlEventLog.LogPropertySet(LogLevel.Debug, CLASSNAME, "ConnectionString", value);
- NpgsqlConnectionStringBuilder builder = cache[value];
- if (builder == null)
- {
- settings = new NpgsqlConnectionStringBuilder(value);
- }
- else
- {
- settings = builder.Clone();
- }
- LogConnectionString();
- }
- }
-
- /// <summary>
- /// Backend server host name.
- /// </summary>
- [Browsable(true)]
- public String Host
- {
- get { return settings.Host; }
- }
-
- /// <summary>
- /// Backend server port.
- /// </summary>
- [Browsable(true)]
- public Int32 Port
- {
- get { return settings.Port; }
- }
-
- /// <summary>
- /// If true, the connection will attempt to use SSL.
- /// </summary>
- [Browsable(true)]
- public Boolean SSL
- {
- get { return settings.SSL; }
- }
-
- /// <summary>
- /// Gets the time to wait while trying to establish a connection
- /// before terminating the attempt and generating an error.
- /// </summary>
- /// <value>The time (in seconds) to wait for a connection to open. The default value is 15 seconds.</value>
+ /// <summary>
+ /// Backend server host name.
+ /// </summary>
+ [Browsable(true)]
+ public String Host {
+ get
+ {
+ return connection_string.ToString(ConnectionStringKeys.Host);
+ }
+ }
-#if WITHDESIGN
+ /// <summary>
+ /// Backend server port.
+ /// </summary>
+ [Browsable(true)]
+ public Int32 Port {
+ get
+ {
+ return connection_string.ToInt32(ConnectionStringKeys.Port, ConnectionStringDefaults.Port);
+ }
+ }
+
+ /// <summary>
+ /// If true, the connection will attempt to use SSL.
+ /// </summary>
+ [Browsable(true)]
+ public Boolean SSL {
+ get
+ {
+ return connection_string.ToBool(ConnectionStringKeys.SSL);
+ }
+ }
+
+ /// <summary>
+ /// Gets the time to wait while trying to establish a connection
+ /// before terminating the attempt and generating an error.
+ /// </summary>
+ /// <value>The time (in seconds) to wait for a connection to open. The default value is 15 seconds.</value>
+
+ #if WITHDESIGN
[NpgsqlSysDescription("Description_ConnectionTimeout", typeof(NpgsqlConnection))]
-#endif
+ #endif
+
+ public Int32 ConnectionTimeout {
+ get
+ {
+ 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);
+ }
+ }
- public override Int32 ConnectionTimeout
- {
- get { return settings.Timeout; }
- }
-
- /// <summary>
- /// Gets the time to wait while trying to execute a command
- /// before terminating the attempt and generating an error.
- /// </summary>
- /// <value>The time (in seconds) to wait for a command to complete. The default value is 20 seconds.</value>
- public Int32 CommandTimeout
- {
- get { return settings.CommandTimeout; }
- }
-
- /// <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 settings.ConnectionLifeTime; }
- }
-
- ///<summary>
- /// Gets the name of the current database or the database to be used after a connection is opened.
- /// </summary>
- /// <value>The name of the current database or the name of the database to be
- /// used after a connection is opened. The default value is the empty string.</value>
-#if WITHDESIGN
+ ///<summary>
+ /// Gets the name of the current database or the database to be used after a connection is opened.
+ /// </summary>
+ /// <value>The name of the current database or the name of the database to be
+ /// used after a connection is opened. The default value is the empty string.</value>
+ #if WITHDESIGN
[NpgsqlSysDescription("Description_Database", typeof(NpgsqlConnection))]
-#endif
-
- public override String Database
- {
- get { return settings.Database; }
- }
-
- /// <summary>
- /// Whether datareaders are loaded in their entirety (for compatibility with earlier code).
- /// </summary>
- public bool PreloadReader
- {
- get { return settings.PreloadReader; }
- }
-
- /// <summary>
- /// Gets the database server name.
- /// </summary>
- public override string DataSource
- {
- get { return settings.Host; }
- }
-
- /// <summary>
- /// Gets flag indicating if we are using Synchronous notification or not.
- /// The default value is false.
- /// </summary>
- public Boolean SyncNotification
- {
- get { return settings.SyncNotification; }
- }
-
- /// <summary>
- /// Gets the current state of the connection.
- /// </summary>
- /// <value>A bitwise combination of the <see cref="System.Data.ConnectionState">ConnectionState</see> values. The default is <b>Closed</b>.</value>
- [Browsable(false)]
- public ConnectionState FullState
- {
- get
- {
- CheckNotDisposed();
-
- if (connector != null)
- {
- return connector.State;
- }
- else
- {
- return ConnectionState.Closed;
- }
- }
- }
-
- /// <summary>
- /// Gets whether the current state of the connection is Open or Closed
- /// </summary>
- /// <value>ConnectionState.Open or ConnectionState.Closed</value>
- [Browsable(false)]
- public override ConnectionState State
+ #endif
+
+ public String Database {
+ get
+ {
+ return connection_string.ToString(ConnectionStringKeys.Database);
+ }
+ }
+
+ /// <summary>
+ /// Gets flag indicating if we are using Synchronous notification or not.
+ /// The default value is false.
+ /// </summary>
+ public Boolean SyncNotification
{
get
{
- return (FullState & ConnectionState.Open) == ConnectionState.Open ? ConnectionState.Open : ConnectionState.Closed;
- }
- }
-
- /// <summary>
- /// Version of the PostgreSQL backend.
- /// This can only be called when there is an active connection.
- /// </summary>
- [Browsable(false)]
- public Version PostgreSqlVersion
- {
- get
- {
- CheckConnectionOpen();
- return connector.ServerVersion;
- }
- }
-
- public override string ServerVersion
- {
- get { return PostgreSqlVersion.ToString(); }
- }
-
- /// <summary>
- /// Protocol version in use.
- /// This can only be called when there is an active connection.
- /// </summary>
- [Browsable(false)]
- public ProtocolVersion BackendProtocolVersion
- {
- get
- {
- CheckConnectionOpen();
- return connector.BackendProtocolVersion;
- }
- }
-
- /// <summary>
- /// Process id of backend server.
- /// This can only be called when there is an active connection.
- /// </summary>
- [Browsable(false)]
- public Int32 ProcessID
- {
- get
- {
- CheckConnectionOpen();
- return connector.BackEndKeyData.ProcessID;
- }
- }
-
- /// <summary>
- /// Begins a database transaction with the specified isolation level.
- /// </summary>
- /// <param name="isolationLevel">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
- /// <returns>An <see cref="System.Data.Common.DbTransaction">DbTransaction</see>
- /// object representing the new transaction.</returns>
- /// <remarks>
- /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
- /// There's no support for nested transactions.
- /// </remarks>
- protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginDbTransaction", isolationLevel);
-
- return BeginTransaction(isolationLevel);
- }
-
- /// <summary>
- /// Begins a database transaction.
- /// </summary>
- /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
- /// object representing the new transaction.</returns>
- /// <remarks>
- /// Currently there's no support for nested transactions.
- /// </remarks>
- public new NpgsqlTransaction BeginTransaction()
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction");
- return this.BeginTransaction(IsolationLevel.ReadCommitted);
- }
-
- /// <summary>
- /// Begins a database transaction with the specified isolation level.
- /// </summary>
- /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
- /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
- /// object representing the new transaction.</returns>
- /// <remarks>
- /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
- /// There's no support for nested transactions.
- /// </remarks>
- public new NpgsqlTransaction BeginTransaction(IsolationLevel level)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction", level);
-
- CheckConnectionOpen();
-
- if (connector.Transaction != null)
- {
- throw new InvalidOperationException(resman.GetString("Exception_NoNestedTransactions"));
- }
-
- return new NpgsqlTransaction(this, level);
- }
-
- /// <summary>
- /// Opens a database connection with the property settings specified by the
- /// <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
- /// </summary>
- public override void Open()
- {
- CheckConnectionClosed();
-
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
-
- // Check if there is any missing argument.
- if (!settings.ContainsKey(Keywords.Host))
- {
- throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"),
- NpgsqlConnectionStringBuilder.GetKeyName(Keywords.Host));
- }
- if (!settings.ContainsKey(Keywords.UserName) && !settings.ContainsKey(Keywords.IntegratedSecurity))
- {
- throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"),
- NpgsqlConnectionStringBuilder.GetKeyName(Keywords.UserName));
- }
-
- // Get a Connector. The connector returned is guaranteed to be connected and ready to go.
- connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector(this);
-
- connector.Notice += NoticeDelegate;
- connector.Notification += NotificationDelegate;
-
- if (SyncNotification)
- {
- connector.AddNotificationThread();
- }
-
- if (Enlist)
- {
- promotable.Enlist(Transaction.Current);
- }
- }
-
- /// <summary>
- /// This method changes the current database by disconnecting from the actual
- /// database and connecting to the specified.
- /// </summary>
- /// <param name="dbName">The name of the database to use in place of the current database.</param>
- public override void ChangeDatabase(String dbName)
- {
- CheckNotDisposed();
-
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ChangeDatabase", dbName);
-
- if (dbName == null)
- {
- throw new ArgumentNullException("dbName");
- }
-
- if (string.IsNullOrEmpty(dbName))
- {
- throw new ArgumentOutOfRangeException(String.Format(resman.GetString("Exception_InvalidDbName"), dbName), "dbName");
- }
-
- String oldDatabaseName = Database;
-
- Close();
-
- settings[Keywords.Database] = dbName;
-
- Open();
- }
-
- internal void EmergencyClose()
- {
- _fakingOpen = true;
- }
-
- /// <summary>
- /// Releases the connection to the database. If the connection is pooled, it will be
- /// made available for re-use. If it is non-pooled, the actual connection will be shutdown.
- /// </summary>
- public override void Close()
- {
- if (!disposed)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
-
- promotable.Prepare();
-
- if (connector != null)
- {
- connector.Notification -= NotificationDelegate;
- connector.Notice -= NoticeDelegate;
-
- if (SyncNotification)
- {
- connector.RemoveNotificationThread();
- }
-
- NpgsqlConnectorPool.ConnectorPoolMgr.ReleaseConnector(this, connector);
-
-
- connector = null;
- }
- }
- }
-
- /// <summary>
- /// Creates and returns a <see cref="System.Data.Common.DbCommand">DbCommand</see>
- /// object associated with the <see cref="System.Data.Common.DbConnection">IDbConnection</see>.
- /// </summary>
- /// <returns>A <see cref="System.Data.Common.DbCommand">DbCommand</see> object.</returns>
- protected override DbCommand CreateDbCommand()
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateDbCommand");
- return CreateCommand();
- }
-
- /// <summary>
- /// Creates and returns a <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>
- /// object associated with the <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
- /// </summary>
- /// <returns>A <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> object.</returns>
- public new NpgsqlCommand CreateCommand()
- {
- CheckNotDisposed();
-
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateCommand");
- return new NpgsqlCommand("", this);
- }
-
- /// <summary>
- /// Releases all resources used by the
- /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
- /// </summary>
- /// <param name="disposing"><b>true</b> when called from Dispose();
- /// <b>false</b> when being called from the finalizer.</param>
- protected override void Dispose(bool disposing)
- {
- if (!disposed)
- {
- if (disposing)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
- Close();
- }
- else
- {
- if (FullState != ConnectionState.Closed)
- {
- NpgsqlEventLog.LogMsg(resman, "Log_ConnectionLeaking", LogLevel.Debug);
- NpgsqlConnectorPool.ConnectorPoolMgr.FixPoolCountBecauseOfConnectionDisposeFalse(this);
- }
- }
-
- base.Dispose(disposing);
- disposed = true;
- }
- }
-
- /// <summary>
- /// Create a new connection based on this one.
- /// </summary>
- /// <returns>A new NpgsqlConnection object.</returns>
- Object ICloneable.Clone()
- {
- return Clone();
- }
-
- /// <summary>
- /// Create a new connection based on this one.
- /// </summary>
- /// <returns>A new NpgsqlConnection object.</returns>
- public NpgsqlConnection Clone()
- {
- CheckNotDisposed();
-
- NpgsqlConnection C = new NpgsqlConnection(ConnectionString);
-
- C.Notice += this.Notice;
-
- if (connector != null)
- {
- C.Open();
- }
-
- return C;
- }
-
- //
- // Internal methods and properties
- //
- internal void OnNotice(object O, NpgsqlNoticeEventArgs E)
- {
- if (Notice != null)
- {
- Notice(this, E);
- }
- }
-
- internal void OnNotification(object O, NpgsqlNotificationEventArgs E)
- {
- if (Notification != null)
- {
- Notification(this, E);
- }
- }
-
- /// <summary>
- /// The connector object connected to the backend.
- /// </summary>
- internal NpgsqlConnector Connector
- {
- get { return connector; }
- }
-
-
- /// <summary>
- /// Gets the NpgsqlConnectionStringBuilder containing the parsed connection string values.
- /// </summary>
- internal NpgsqlConnectionStringBuilder ConnectionStringValues
- {
- get { return settings; }
- }
-
- /// <summary>
- /// User name.
- /// </summary>
- internal String UserName
- {
- get { return settings.UserName; }
- }
-
- public bool UseExtendedTypes
- {
- get
- {
- bool ext = settings.UseExtendedTypes;
- return ext;
- }
- }
-
- /// <summary>
- /// Password.
- /// </summary>
- internal String Password
- {
- get { return settings.Password; }
- }
-
- /// <summary>
- /// Determine if connection pooling will be used for this connection.
- /// </summary>
- internal Boolean Pooling
- {
- get { return (settings.Pooling && (settings.MaxPoolSize > 0)); }
- }
-
- internal Int32 MinPoolSize
- {
- get { return settings.MinPoolSize; }
- }
-
- internal Int32 MaxPoolSize
- {
- get { return settings.MaxPoolSize; }
- }
-
- internal Int32 Timeout
- {
- get { return settings.Timeout; }
- }
-
- internal Boolean Enlist
- {
- get { return settings.Enlist; }
- }
-
-
- //
- // Event handlers
- //
-
- /// <summary>
- /// Default SSL CertificateSelectionCallback implementation.
- /// </summary>
- internal X509Certificate DefaultCertificateSelectionCallback(X509CertificateCollection clientCertificates,
- X509Certificate serverCertificate, string targetHost,
- X509CertificateCollection serverRequestedCertificates)
- {
- if (CertificateSelectionCallback != null)
- {
- return CertificateSelectionCallback(clientCertificates, serverCertificate, targetHost, serverRequestedCertificates);
- }
- else
- {
- return null;
- }
- }
-
- /// <summary>
- /// Default SSL CertificateValidationCallback implementation.
- /// </summary>
- internal bool DefaultCertificateValidationCallback(X509Certificate certificate, int[] certificateErrors)
- {
- if (CertificateValidationCallback != null)
- {
- return CertificateValidationCallback(certificate, certificateErrors);
- }
- else
- {
- return true;
- }
- }
-
- /// <summary>
- /// Default SSL PrivateKeySelectionCallback implementation.
- /// </summary>
- internal AsymmetricAlgorithm DefaultPrivateKeySelectionCallback(X509Certificate certificate, string targetHost)
- {
- if (PrivateKeySelectionCallback != null)
- {
- return PrivateKeySelectionCallback(certificate, targetHost);
- }
- else
- {
- return null;
- }
- }
-
-
- //
- // Private methods and properties
- //
-
-
- /// <summary>
- /// Write each key/value pair in the connection string to the log.
- /// </summary>
- private void LogConnectionString()
- {
- foreach (string key in settings.Keys)
- {
- NpgsqlEventLog.LogMsg(resman, "Log_ConnectionStringValues", LogLevel.Debug, key, settings[key]);
- }
- }
-
- private void CheckConnectionOpen()
- {
- if (disposed)
- {
- throw new ObjectDisposedException(CLASSNAME);
- }
-
- if (_fakingOpen)
- {
- if (connector != null)
- {
- try
- {
- Close();
- }
- catch
- {
- }
- }
- Open();
- _fakingOpen = false;
- }
-
- if (connector == null)
- {
- throw new InvalidOperationException(resman.GetString("Exception_ConnNotOpen"));
- }
- }
-
- private void CheckConnectionClosed()
- {
- if (disposed)
- {
- throw new ObjectDisposedException(CLASSNAME);
- }
-
- if (connector != null)
- {
- throw new InvalidOperationException(resman.GetString("Exception_ConnOpen"));
- }
- }
-
- private void CheckNotDisposed()
- {
- if (disposed)
- {
- throw new ObjectDisposedException(CLASSNAME);
- }
- }
-
-
- /// <summary>
- /// Returns the supported collections
- /// </summary>
- public override DataTable GetSchema()
- {
- return NpgsqlSchema.GetMetaDataCollections();
- }
-
- /// <summary>
- /// Returns the schema collection specified by the collection name.
- /// </summary>
- /// <param name="collectionName">The collection name.</param>
- /// <returns>The collection specified.</returns>
- public override DataTable GetSchema(string collectionName)
- {
- return GetSchema(collectionName, null);
- }
-
- /// <summary>
- /// Returns the schema collection specified by the collection name filtered by the restrictions.
- /// </summary>
- /// <param name="collectionName">The collection name.</param>
- /// <param name="restrictions">
- /// The restriction values to filter the results. A description of the restrictions is contained
- /// in the Restrictions collection.
- /// </param>
- /// <returns>The collection specified.</returns>
- public override DataTable GetSchema(string collectionName, string[] restrictions)
- {
- switch (collectionName)
- {
- case "MetaDataCollections":
- return NpgsqlSchema.GetMetaDataCollections();
- case "Restrictions":
- return NpgsqlSchema.GetRestrictions();
- case "DataSourceInformation":
- return NpgsqlSchema.GetDataSourceInformation();
- case "DataTypes":
- case "ReservedWords":
- throw new NotSupportedException();
- // custom collections for npgsql
- case "Databases":
- return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetDatabases(restrictions);
- case "Tables":
- return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetTables(restrictions);
- case "Columns":
- return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetColumns(restrictions);
- case "Views":
- return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetViews(restrictions);
- case "Users":
- return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetUsers(restrictions);
- default:
- throw new NotSupportedException();
- }
- }
-
- public void ClearPool()
- {
- NpgsqlConnectorPool.ConnectorPoolMgr.ClearPool(this);
- }
-
- public static void ClearAllPools()
- {
- NpgsqlConnectorPool.ConnectorPoolMgr.ClearAllPools();
- }
-
- public override void EnlistTransaction(Transaction transaction)
- {
- promotable.Enlist(transaction);
- }
-
-#if NET35
- protected override DbProviderFactory DbProviderFactory
+ return connection_string.ToBool(ConnectionStringKeys.SyncNotification, ConnectionStringDefaults.SyncNotification);
+ }
+ }
+
+ /// <summary>
+ /// Gets the current state of the connection.
+ /// </summary>
+ /// <value>A bitwise combination of the <see cref="System.Data.ConnectionState">ConnectionState</see> values. The default is <b>Closed</b>.</value>
+ [Browsable(false)]
+ public ConnectionState State {
+ get
+ {
+ CheckNotDisposed();
+
+ if (connector != null)
+ {
+ return connector.State;
+ }
+ else
+ {
+ return ConnectionState.Closed;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Version of the PostgreSQL backend.
+ /// This can only be called when there is an active connection.
+ /// </summary>
+ [Browsable(false)]
+ public ServerVersion ServerVersion {
+ get
+ {
+ CheckConnectionOpen();
+ return connector.ServerVersion;
+ }
+ }
+
+ /// <summary>
+ /// Protocol version in use.
+ /// This can only be called when there is an active connection.
+ /// </summary>
+ [Browsable(false)]
+ public ProtocolVersion BackendProtocolVersion {
+ get
+ {
+ CheckConnectionOpen();
+ return connector.BackendProtocolVersion;
+ }
+ }
+
+ /// <summary>
+ /// Begins a database transaction.
+ /// </summary>
+ /// <returns>An <see cref="System.Data.IDbTransaction">IDbTransaction</see>
+ /// object representing the new transaction.</returns>
+ /// <remarks>
+ /// Currently there's no support for nested transactions.
+ /// </remarks>
+ IDbTransaction IDbConnection.BeginTransaction()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.BeginTransaction");
+
+ return BeginTransaction();
+ }
+
+ /// <summary>
+ /// Begins a database transaction with the specified isolation level.
+ /// </summary>
+ /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
+ /// <returns>An <see cref="System.Data.IDbTransaction">IDbTransaction</see>
+ /// object representing the new transaction.</returns>
+ /// <remarks>
+ /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
+ /// There's no support for nested transactions.
+ /// </remarks>
+ IDbTransaction IDbConnection.BeginTransaction(IsolationLevel level)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.BeginTransaction", level);
+
+ return BeginTransaction(level);
+ }
+
+ /// <summary>
+ /// Begins a database transaction.
+ /// </summary>
+ /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
+ /// object representing the new transaction.</returns>
+ /// <remarks>
+ /// Currently there's no support for nested transactions.
+ /// </remarks>
+ public NpgsqlTransaction BeginTransaction()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction");
+ return this.BeginTransaction(IsolationLevel.ReadCommitted);
+ }
+
+ /// <summary>
+ /// Begins a database transaction with the specified isolation level.
+ /// </summary>
+ /// <param name="level">The <see cref="System.Data.IsolationLevel">isolation level</see> under which the transaction should run.</param>
+ /// <returns>A <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
+ /// object representing the new transaction.</returns>
+ /// <remarks>
+ /// Currently the IsolationLevel ReadCommitted and Serializable are supported by the PostgreSQL backend.
+ /// There's no support for nested transactions.
+ /// </remarks>
+ public NpgsqlTransaction BeginTransaction(IsolationLevel level)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "BeginTransaction", level);
+
+ CheckConnectionOpen();
+
+ if (connector.Transaction != null)
+ {
+ throw new InvalidOperationException(resman.GetString("Exception_NoNestedTransactions"));
+ }
+
+ return new NpgsqlTransaction(this, level);
+ }
+
+ /// <summary>
+ /// Opens a database connection with the property settings specified by the
+ /// <see cref="Npgsql.NpgsqlConnection.ConnectionString">ConnectionString</see>.
+ /// </summary>
+ public void Open()
+ {
+ CheckConnectionClosed();
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");
+
+ // Check if there is any missing argument.
+ if (! connection_string.Contains(ConnectionStringKeys.Host))
+ throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), ConnectionStringKeys.Host);
+ if (! connection_string.Contains(ConnectionStringKeys.UserName))
+ throw new ArgumentException(resman.GetString("Exception_MissingConnStrArg"), ConnectionStringKeys.UserName);
+
+ // Get a Connector. The connector returned is guaranteed to be connected and ready to go.
+ connector = NpgsqlConnectorPool.ConnectorPoolMgr.RequestConnector (this);
+
+ connector.Notice += NoticeDelegate;
+ connector.Notification += NotificationDelegate;
+
+ if (SyncNotification)
+ connector.AddNotificationThread();
+
+ }
+
+ /// <summary>
+ /// This method changes the current database by disconnecting from the actual
+ /// database and connecting to the specified.
+ /// </summary>
+ /// <param name="dbName">The name of the database to use in place of the current database.</param>
+ public void ChangeDatabase(String dbName)
+ {
+ CheckNotDisposed();
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ChangeDatabase", dbName);
+
+ if (dbName == null)
+ throw new ArgumentNullException("dbName");
+
+ if (dbName == String.Empty)
+ throw new ArgumentOutOfRangeException(String.Format(resman.GetString("Exception_InvalidDbName"), dbName), "dbName");
+
+ String oldDatabaseName = Database;
+
+ Close();
+
+ connection_string[ConnectionStringKeys.Database] = dbName;
+
+ Open();
+ }
+
+ /// <summary>
+ /// Releases the connection to the database. If the connection is pooled, it will be
+ /// made available for re-use. If it is non-pooled, the actual connection will be shutdown.
+ /// </summary>
+ public void Close()
+ {
+ if (!disposed)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
+
+ if (connector != null)
+ {
+
+ connector.Notification -= NotificationDelegate;
+ connector.Notice -= NoticeDelegate;
+
+ if (SyncNotification)
+ connector.RemoveNotificationThread();
+
+ NpgsqlConnectorPool.ConnectorPoolMgr.ReleaseConnector(this, connector);
+
+
+
+ connector = null;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Creates and returns a <see cref="System.Data.IDbCommand">IDbCommand</see>
+ /// object associated with the <see cref="System.Data.IDbConnection">IDbConnection</see>.
+ /// </summary>
+ /// <returns>A <see cref="System.Data.IDbCommand">IDbCommand</see> object.</returns>
+ IDbCommand IDbConnection.CreateCommand()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IDbConnection.CreateCommand");
+ return (NpgsqlCommand) CreateCommand();
+ }
+
+ /// <summary>
+ /// Creates and returns a <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>
+ /// object associated with the <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
+ /// </summary>
+ /// <returns>A <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see> object.</returns>
+ public NpgsqlCommand CreateCommand()
+ {
+ CheckNotDisposed();
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateCommand");
+ return new NpgsqlCommand("", this);
+ }
+
+ /// <summary>
+ /// Releases all resources used by the
+ /// <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>.
+ /// </summary>
+ /// <param name="disposing"><b>true</b> when called from Dispose();
+ /// <b>false</b> when being called from the finalizer.</param>
+ protected override void Dispose(bool disposing)
+ {
+
+ if (!disposed)
+ {
+ if (disposing)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
+ Close();
+ }
+ else
+ {
+ if (State != ConnectionState.Closed)
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_ConnectionLeaking", LogLevel.Debug);
+ NpgsqlConnectorPool.ConnectorPoolMgr.FixPoolCountBecauseOfConnectionDisposeFalse(this);
+ }
+ }
+
+ base.Dispose (disposing);
+ disposed = true;
+
+ }
+ }
+
+ /// <summary>
+ /// Create a new connection based on this one.
+ /// </summary>
+ /// <returns>A new NpgsqlConnection object.</returns>
+ Object ICloneable.Clone()
+ {
+ return Clone();
+ }
+
+ /// <summary>
+ /// Create a new connection based on this one.
+ /// </summary>
+ /// <returns>A new NpgsqlConnection object.</returns>
+ public NpgsqlConnection Clone()
+ {
+ CheckNotDisposed();
+
+ NpgsqlConnection C = new NpgsqlConnection(ConnectionString);
+
+ C.Notice += this.Notice;
+
+ if (connector != null)
+ {
+ C.Open();
+ }
+
+ return C;
+ }
+
+ //
+ // Internal methods and properties
+ //
+ internal void OnNotice(object O, NpgsqlNoticeEventArgs E)
+ {
+ if (Notice != null)
+ {
+ Notice(this, E);
+ }
+ }
+
+ internal void OnNotification(object O, NpgsqlNotificationEventArgs E)
+ {
+ if (Notification != null)
+ {
+ Notification(this, E);
+ }
+ }
+
+ /// <summary>
+ /// The connector object connected to the backend.
+ /// </summary>
+ internal NpgsqlConnector Connector
{
get
{
- return NpgsqlFactory.Instance;
+ return connector;
}
}
-#endif
- }
+
+ /// <summary>
+ /// Gets the NpgsqlConnectionString containing the parsed connection string values.
+ /// </summary>
+ internal NpgsqlConnectionString ConnectionStringValues {
+ get
+ {
+ return connection_string;
+ }
+ }
+
+ /// <summary>
+ /// User name.
+ /// </summary>
+ internal String UserName {
+ get
+ {
+ return connection_string.ToString(ConnectionStringKeys.UserName);
+ }
+ }
+
+ /// <summary>
+ /// Password.
+ /// </summary>
+ internal String Password {
+ get
+ {
+ return connection_string.ToString(ConnectionStringKeys.Password);
+ }
+ }
+
+ /// <summary>
+ /// Determine if connection pooling will be used for this connection.
+ /// </summary>
+ internal Boolean Pooling {
+ get
+ {
+ return (
+ connection_string.ToBool(ConnectionStringKeys.Pooling, ConnectionStringDefaults.Pooling) &&
+ connection_string.ToInt32(ConnectionStringKeys.MaxPoolSize, ConnectionStringDefaults.MaxPoolSize) > 0
+ );
+ }
+ }
+
+ internal Int32 MinPoolSize {
+ get
+ {
+ return connection_string.ToInt32(ConnectionStringKeys.MinPoolSize, 0, MaxPoolSize, ConnectionStringDefaults.MinPoolSize);
+ }
+ }
+
+ internal Int32 MaxPoolSize {
+ get
+ {
+ return connection_string.ToInt32(ConnectionStringKeys.MaxPoolSize, 0, 1024, ConnectionStringDefaults.MaxPoolSize);
+ }
+ }
+
+ internal Int32 Timeout {
+ get
+ {
+ return connection_string.ToInt32(ConnectionStringKeys.Timeout, 0, 1024, ConnectionStringDefaults.Timeout);
+ }
+ }
+
+
+
+ //
+ // Event handlers
+ //
+
+ /// <summary>
+ /// Default SSL CertificateSelectionCallback implementation.
+ /// </summary>
+ internal X509Certificate DefaultCertificateSelectionCallback(
+ X509CertificateCollection clientCertificates,
+ X509Certificate serverCertificate,
+ string targetHost,
+ X509CertificateCollection serverRequestedCertificates)
+ {
+ if (CertificateSelectionCallback != null)
+ {
+ return CertificateSelectionCallback(clientCertificates, serverCertificate, targetHost, serverRequestedCertificates);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Default SSL CertificateValidationCallback implementation.
+ /// </summary>
+ internal bool DefaultCertificateValidationCallback(
+ X509Certificate certificate,
+ int[] certificateErrors)
+ {
+ if (CertificateValidationCallback != null)
+ {
+ return CertificateValidationCallback(certificate, certificateErrors);
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Default SSL PrivateKeySelectionCallback implementation.
+ /// </summary>
+ internal AsymmetricAlgorithm DefaultPrivateKeySelectionCallback(
+ X509Certificate certificate,
+ string targetHost)
+ {
+ if (PrivateKeySelectionCallback != null)
+ {
+ return PrivateKeySelectionCallback(certificate, targetHost);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+
+ //
+ // Private methods and properties
+ //
+
+
+ /// <summary>
+ /// Write each key/value pair in the connection string to the log.
+ /// </summary>
+ private void LogConnectionString()
+ {
+ foreach (DictionaryEntry DE in connection_string)
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_ConnectionStringValues", LogLevel.Debug, DE.Key, DE.Value);
+ }
+ }
+
+ private void CheckConnectionOpen()
+ {
+ if (disposed)
+ {
+ throw new ObjectDisposedException(CLASSNAME);
+ }
+
+ if (connector == null)
+ {
+ throw new InvalidOperationException(resman.GetString("Exception_ConnNotOpen"));
+ }
+ }
+
+ private void CheckConnectionClosed()
+ {
+ if (disposed)
+ {
+ throw new ObjectDisposedException(CLASSNAME);
+ }
+
+ if (connector != null)
+ {
+ throw new InvalidOperationException(resman.GetString("Exception_ConnOpen"));
+ }
+ }
+
+ private void CheckNotDisposed()
+ {
+ if (disposed)
+ {
+ throw new ObjectDisposedException(CLASSNAME);
+ }
+ }
+
+
+ /// <summary>
+ /// Returns the supported collections
+ /// <summary>
+ public DataTable GetSchema()
+ {
+ return NpgsqlSchema.GetMetaDataCollections();
+ }
+
+ /// <summary>
+ /// Returns the schema collection specified by the collection name.
+ /// </summary>
+ /// <param name="collectionName">The collection name.</param>
+ /// <returns>The collection specified.</returns>
+ public DataTable GetSchema(string collectionName)
+ {
+ return GetSchema(collectionName, null);
+ }
+
+ /// <summary>
+ /// Returns the schema collection specified by the collection name filtered by the restrictions.
+ /// </summary>
+ /// <param name="collectionName">The collection name.</param>
+ /// <param name="restrictions">
+ /// The restriction values to filter the results. A description of the restrictions is contained
+ /// in the Restrictions collection.
+ /// </param>
+ /// <returns>The collection specified.</returns>
+ public DataTable GetSchema(string collectionName, string[] restrictions)
+ {
+ switch(collectionName)
+ {
+ case "MetaDataCollections":
+ return NpgsqlSchema.GetMetaDataCollections();
+ case "Restrictions":
+ return NpgsqlSchema.GetRestrictions();
+ case "DataSourceInformation":
+ case "DataTypes":
+ case "ReservedWords":
+ throw new NotSupportedException();
+ // custom collections for npgsql
+ case "Databases":
+ return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetDatabases(restrictions);
+ case "Tables":
+ return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetTables(restrictions);
+ case "Columns":
+ return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetColumns(restrictions);
+ case "Views":
+ return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetViews(restrictions);
+ case "Users":
+ return new NpgsqlSchema(new NpgsqlConnection(ConnectionString)).GetUsers(restrictions);
+ default:
+ throw new NotSupportedException();
+ }
+ }
+
+ public void ClearPool()
+ {
+ NpgsqlConnectorPool.ConnectorPoolMgr.ClearPool(this);
+ }
+
+ public void ClearAllPools()
+ {
+ NpgsqlConnectorPool.ConnectorPoolMgr.ClearAllPools();
+ }
+
+ }
+
+
+
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
index 81003118b83..fd6c391b0aa 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnector.cs
@@ -1,41 +1,42 @@
-// Copyright (C) 2002 The Npgsql Development Team
-// npgsql-general@gborg.postgresql.org
-// http://gborg.postgresql.org/project/npgsql/projdisplay.php
+// Copyright (C) 2002 The Npgsql Development Team
+// npgsql-general@gborg.postgresql.org
+// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
//
-// Connector.cs
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Connector.cs
// ------------------------------------------------------------------
-// Project
-// Npgsql
-// Status
-// 0.00.0000 - 06/17/2002 - ulrich sprick - created
-// - 06/??/2004 - Glen Parker<glenebob@nwlink.com> rewritten
+// Project
+// Npgsql
+// Status
+// 0.00.0000 - 06/17/2002 - ulrich sprick - created
+// - 06/??/2004 - Glen Parker<glenebob@nwlink.com> rewritten
using System;
-using System.Collections.Generic;
-using System.Data;
+using System.Collections;
using System.IO;
-using System.Net.Sockets;
+using System.Text;
+using System.Data;
+using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
+using System.Net.Sockets;
+
using Mono.Security.Protocol.Tls;
+
using NpgsqlTypes;
namespace Npgsql
@@ -49,113 +50,91 @@ namespace Npgsql
internal class NpgsqlConnector
{
// Immutable.
- private readonly NpgsqlConnectionStringBuilder settings;
+ internal NpgsqlConnectionString ConnectionString;
/// <summary>
/// Occurs on NoticeResponses from the PostgreSQL backend.
/// </summary>
- internal event NoticeEventHandler Notice;
+ internal event NoticeEventHandler Notice;
/// <summary>
/// Occurs on NotificationResponses from the PostgreSQL backend.
/// </summary>
- internal event NotificationEventHandler Notification;
+ internal event NotificationEventHandler Notification;
/// <summary>
/// Mono.Security.Protocol.Tls.CertificateSelectionCallback delegate.
/// </summary>
- internal event CertificateSelectionCallback CertificateSelectionCallback;
+ internal event CertificateSelectionCallback CertificateSelectionCallback;
/// <summary>
/// Mono.Security.Protocol.Tls.CertificateValidationCallback delegate.
/// </summary>
- internal event CertificateValidationCallback CertificateValidationCallback;
+ internal event CertificateValidationCallback CertificateValidationCallback;
/// <summary>
/// Mono.Security.Protocol.Tls.PrivateKeySelectionCallback delegate.
/// </summary>
- internal event PrivateKeySelectionCallback PrivateKeySelectionCallback;
+ internal event PrivateKeySelectionCallback PrivateKeySelectionCallback;
- private ConnectionState _connection_state;
+ private ConnectionState _connection_state;
// The physical network connection to the backend.
- private Stream _stream;
-
- private Socket _socket;
+ private Stream _stream;
+ private Socket _socket;
+
// Mediator which will hold data generated from backend.
- private readonly NpgsqlMediator _mediator;
+ private NpgsqlMediator _mediator;
- private ProtocolVersion _backendProtocolVersion;
- private Version _serverVersion;
+ private ProtocolVersion _backendProtocolVersion;
+ private ServerVersion _serverVersion;
// Values for possible CancelRequest messages.
- private NpgsqlBackEndKeyData _backend_keydata;
+ private NpgsqlBackEndKeyData _backend_keydata;
// Flag for transaction status.
// private Boolean _inTransaction = false;
- private NpgsqlTransaction _transaction = null;
-
- private Boolean _supportsPrepare = false;
-
- private Boolean _supportsSavepoint = false;
+ private NpgsqlTransaction _transaction = null;
- private NpgsqlBackendTypeMapping _oidToNameMapping = null;
+ private Boolean _supportsPrepare = false;
- private Boolean _isInitialized;
+ private NpgsqlBackendTypeMapping _oidToNameMapping = null;
- private readonly Boolean _pooled;
- private readonly Boolean _shared;
+ private Encoding _encoding;
- private NpgsqlState _state;
+ private Boolean _isInitialized;
+ private Boolean _pooled;
+ private Boolean _shared;
- private Int32 _planIndex;
- private Int32 _portalIndex;
+ private NpgsqlState _state;
- private const String _planNamePrefix = "npgsqlplan";
- private const String _portalNamePrefix = "npgsqlportal";
+ private Int32 _planIndex;
+ private Int32 _portalIndex;
- private Thread _notificationThread;
+ private const String _planNamePrefix = "npgsqlplan";
+ private const String _portalNamePrefix = "npgsqlportal";
+
+ private Thread _notificationThread;
+
// The AutoResetEvent to synchronize processing threads.
- internal AutoResetEvent _notificationAutoResetEvent;
-
+ internal AutoResetEvent _notificationAutoResetEvent;
+
// Counter of notification thread start/stop requests in order to
- internal Int16 _notificationThreadStopCount;
-
- private Exception _notificationException;
+ internal Int16 _notificationThreadStopCount;
- internal ForwardsOnlyDataReader CurrentReader;
-
- // Some kinds of messages only get one response, and do not
- // expect a ready_for_query response.
- private bool _requireReadyForQuery = true;
-
- private readonly Dictionary<string, NpgsqlParameterStatus> _serverParameters =
- new Dictionary<string, NpgsqlParameterStatus>(StringComparer.InvariantCultureIgnoreCase);
-
-#if WINDOWS && UNMANAGED
-
- private SSPIHandler _sspi;
-
- internal SSPIHandler SSPI
- {
- get { return _sspi; }
- set { _sspi = value; }
- }
-
-#endif
/// <summary>
/// Constructor.
/// </summary>
/// <param name="Shared">Controls whether the connector can be shared.</param>
- public NpgsqlConnector(NpgsqlConnectionStringBuilder ConnectionString, bool Pooled, bool Shared)
+ public NpgsqlConnector(NpgsqlConnectionString ConnectionString, bool Pooled, bool Shared)
{
- this.settings = ConnectionString;
+ this.ConnectionString = ConnectionString;
_connection_state = ConnectionState.Closed;
_pooled = Pooled;
_shared = Shared;
@@ -167,169 +146,142 @@ namespace Npgsql
_portalIndex = 0;
_notificationThreadStopCount = 1;
_notificationAutoResetEvent = new AutoResetEvent(true);
- }
- //Finalizer should never be used, but if some incident has left to a connector being abandoned (most likely
- //case being a user not cleaning up a connection properly) then this way we can at least reduce the damage.
- ~NpgsqlConnector()
- {
- Close();
}
internal String Host
{
- get { return settings.Host; }
+ get
+ {
+ return ConnectionString.ToString(ConnectionStringKeys.Host);
+ }
}
internal Int32 Port
{
- get { return settings.Port; }
+ get
+ {
+ return ConnectionString.ToInt32(ConnectionStringKeys.Port, ConnectionStringDefaults.Port);
+ }
}
internal String Database
{
- get { return settings.ContainsKey(Keywords.Database) ? settings.Database : settings.UserName; }
+ get
+ {
+ return ConnectionString.ToString(ConnectionStringKeys.Database, UserName);
+ }
}
internal String UserName
{
- get { return settings.UserName; }
+ get
+ {
+ return ConnectionString.ToString(ConnectionStringKeys.UserName);
+ }
}
internal String Password
{
- get { return settings.Password; }
+ get
+ {
+ return ConnectionString.ToString(ConnectionStringKeys.Password);
+ }
}
internal Boolean SSL
{
- get { return settings.SSL; }
+ get
+ {
+ return ConnectionString.ToBool(ConnectionStringKeys.SSL);
+ }
}
-
+
internal SslMode SslMode
{
- get { return settings.SslMode; }
+ get
+ {
+ return ConnectionString.ToSslMode(ConnectionStringKeys.SslMode);
+ }
}
-
+
internal Int32 ConnectionTimeout
{
- get { return settings.Timeout; }
+ get
+ {
+ return ConnectionString.ToInt32(ConnectionStringKeys.Timeout, ConnectionStringDefaults.Timeout);
+ }
}
internal Int32 CommandTimeout
{
- get { return settings.CommandTimeout; }
- }
-
- internal Boolean Enlist
- {
- get { return settings.Enlist; }
- }
-
- public bool UseExtendedTypes
- {
- get { return settings.UseExtendedTypes; }
- }
-
- internal Boolean IntegratedSecurity
- {
- get { return settings.IntegratedSecurity; }
+ get
+ {
+ return ConnectionString.ToInt32(ConnectionStringKeys.CommandTimeout, ConnectionStringDefaults.CommandTimeout);
+ }
}
+
/// <summary>
/// Gets the current state of the connection.
/// </summary>
- internal ConnectionState State
- {
+ internal ConnectionState State {
get
{
- if (_connection_state != ConnectionState.Closed && CurrentReader != null && !CurrentReader._cleanedUp)
- {
- return ConnectionState.Open | ConnectionState.Fetching;
- }
return _connection_state;
}
}
- /// <summary>
- /// Return Connection String.
- /// </summary>
- internal string ConnectionString
- {
- get { return settings.ConnectionString; }
- }
// State
- internal void Query(NpgsqlCommand queryCommand)
- {
- CurrentState.Query(this, queryCommand);
- }
-
- internal IEnumerable<IServerResponseObject> QueryEnum(NpgsqlCommand queryCommand)
+ internal void Query (NpgsqlCommand queryCommand)
{
- if (CurrentReader != null)
- {
- if (!CurrentReader._cleanedUp)
- {
- throw new InvalidOperationException(
- "There is already an open DataReader associated with this Command which must be closed first.");
- }
- CurrentReader.Close();
- }
- return CurrentState.QueryEnum(this, queryCommand);
+ CurrentState.Query(this, queryCommand );
}
- internal void Authenticate(string password)
+ internal void Authenticate (string password)
{
- CurrentState.Authenticate(this, password);
+ CurrentState.Authenticate(this, password );
}
- internal void Parse(NpgsqlParse parse)
+ internal void Parse (NpgsqlParse parse)
{
CurrentState.Parse(this, parse);
}
- internal void Flush()
+ internal void Flush ()
{
CurrentState.Flush(this);
}
- internal void TestConnector()
+ internal void Sync ()
{
- CurrentState.TestConnector(this);
+ CurrentState.Sync(this);
}
- internal NpgsqlRowDescription Sync()
- {
- return CurrentState.Sync(this);
- }
-
- internal void Bind(NpgsqlBind bind)
+ internal void Bind (NpgsqlBind bind)
{
CurrentState.Bind(this, bind);
}
-
- internal void Describe(NpgsqlDescribe describe)
+
+ internal void Describe (NpgsqlDescribe describe)
{
CurrentState.Describe(this, describe);
}
- internal void Execute(NpgsqlExecute execute)
+ internal void Execute (NpgsqlExecute execute)
{
CurrentState.Execute(this, execute);
}
- internal IEnumerable<IServerResponseObject> ExecuteEnum(NpgsqlExecute execute)
- {
- return CurrentState.ExecuteEnum(this, execute);
- }
/// <summary>
/// This method checks if the connector is still ok.
/// We try to send a simple query text, select 1 as ConnectionTest;
/// </summary>
+
internal Boolean IsValid()
{
try
@@ -340,7 +292,7 @@ namespace Npgsql
// Clear mediator.
Mediator.ResetResponses();
- this.RequireReadyForQuery = true;
+ Mediator.ResetExpectations();
}
@@ -351,21 +303,25 @@ namespace Npgsql
return true;
}
+
+
+
/// <summary>
/// This method is responsible for releasing all resources associated with this Connector.
/// </summary>
+
internal void ReleaseResources()
{
- if (_connection_state != ConnectionState.Closed)
- {
- ReleasePlansPortals();
- ReleaseRegisteredListen();
- }
+ ReleasePlansPortals();
+ ReleaseRegisteredListen();
+
+
}
internal void ReleaseRegisteredListen()
{
Query(new NpgsqlCommand("unlisten *", this));
+
}
/// <summary>
@@ -377,56 +333,91 @@ namespace Npgsql
if (_planIndex > 0)
{
- for (i = 1; i <= _planIndex; i++)
- {
- try
- {
- Query(new NpgsqlCommand(String.Format("deallocate \"{0}\";", _planNamePrefix + i), this));
- }
-
- // Ignore any error which may occur when releasing portals as this portal name may not be valid anymore. i.e.: the portal name was used on a prepared query which had errors.
- catch(Exception) {}
- }
+ for(i = 1; i <= _planIndex; i++)
+ Query(new NpgsqlCommand(String.Format("deallocate \"{0}\";", _planNamePrefix + i), this));
}
_portalIndex = 0;
_planIndex = 0;
+
+
+ }
+
+
+
+
+
+ /// <summary>
+ /// Check for mediator errors (sent by backend) and throw the appropriate
+ /// exception if errors found. This needs to be called after every interaction
+ /// with the backend.
+ /// </summary>
+ internal void CheckErrors()
+ {
+ if (_mediator.Errors.Count > 0)
+ {
+ throw new NpgsqlException(_mediator.Errors);
+ }
}
- internal void FireNotice(NpgsqlError e)
+ /// <summary>
+ /// Check for notices and fire the appropiate events.
+ /// This needs to be called after every interaction
+ /// with the backend.
+ /// </summary>
+ internal void CheckNotices()
{
if (Notice != null)
{
- try
+ foreach (NpgsqlError E in _mediator.Notices)
{
- Notice(this, new NpgsqlNoticeEventArgs(e));
+ Notice(this, new NpgsqlNoticeEventArgs(E));
}
- catch
- {
- } //Eat exceptions from user code.
}
}
- internal void FireNotification(NpgsqlNotificationEventArgs e)
+ /// <summary>
+ /// Check for notifications and fire the appropiate events.
+ /// This needs to be called after every interaction
+ /// with the backend.
+ /// </summary>
+ internal void CheckNotifications()
{
if (Notification != null)
{
- try
- {
- Notification(this, e);
+
+ foreach (NpgsqlNotificationEventArgs E in _mediator.Notifications)
+ {
+ // Wrap our notification thread call while running on user land code.
+ // This prevents our thread of possibly dying there if there is no exception handling.
+ try
+ {
+ Notification(this, E);
+ }
+ catch(Exception){}
+ }
}
- catch
- {
- } //Eat exceptions from user code.
- }
+
+ }
+
+ /// <summary>
+ /// Check for errors AND notifications in one call.
+ /// </summary>
+ internal void CheckErrorsAndNotifications()
+ {
+ CheckNotices();
+ CheckNotifications();
+ CheckErrors();
}
/// <summary>
/// Default SSL CertificateSelectionCallback implementation.
/// </summary>
- internal X509Certificate DefaultCertificateSelectionCallback(X509CertificateCollection clientCertificates,
- X509Certificate serverCertificate, string targetHost,
- X509CertificateCollection serverRequestedCertificates)
+ internal X509Certificate DefaultCertificateSelectionCallback(
+ X509CertificateCollection clientCertificates,
+ X509Certificate serverCertificate,
+ string targetHost,
+ X509CertificateCollection serverRequestedCertificates)
{
if (CertificateSelectionCallback != null)
{
@@ -441,7 +432,9 @@ namespace Npgsql
/// <summary>
/// Default SSL CertificateValidationCallback implementation.
/// </summary>
- internal bool DefaultCertificateValidationCallback(X509Certificate certificate, int[] certificateErrors)
+ internal bool DefaultCertificateValidationCallback(
+ X509Certificate certificate,
+ int[] certificateErrors)
{
if (CertificateValidationCallback != null)
{
@@ -456,7 +449,9 @@ namespace Npgsql
/// <summary>
/// Default SSL PrivateKeySelectionCallback implementation.
/// </summary>
- internal AsymmetricAlgorithm DefaultPrivateKeySelectionCallback(X509Certificate certificate, string targetHost)
+ internal AsymmetricAlgorithm DefaultPrivateKeySelectionCallback(
+ X509Certificate certificate,
+ string targetHost)
{
if (PrivateKeySelectionCallback != null)
{
@@ -471,10 +466,28 @@ namespace Npgsql
/// <summary>
/// Version of backend server this connector is connected to.
/// </summary>
- internal Version ServerVersion
+ internal ServerVersion ServerVersion
+ {
+ get
+ {
+ return _serverVersion;
+ }
+ set
+ {
+ _serverVersion = value;
+ }
+ }
+
+ internal Encoding Encoding
{
- get { return _serverVersion; }
- set { _serverVersion = value; }
+ get
+ {
+ return _encoding;
+ }
+ set
+ {
+ _encoding = value;
+ }
}
/// <summary>
@@ -482,26 +495,43 @@ namespace Npgsql
/// </summary>
internal ProtocolVersion BackendProtocolVersion
{
- get { return _backendProtocolVersion; }
- set { _backendProtocolVersion = value; }
+ get
+ {
+ return _backendProtocolVersion;
+ }
+ set
+ {
+ _backendProtocolVersion = value;
+ }
}
/// <summary>
/// The physical connection stream to the backend.
/// </summary>
- internal Stream Stream
- {
- get { return _stream; }
- set { _stream = value; }
+ internal Stream Stream {
+ get
+ {
+ return _stream;
+ }
+ set
+ {
+ _stream = value;
+ }
}
-
+
/// <summary>
/// The physical connection socket to the backend.
/// </summary>
- internal Socket Socket
- {
- get { return _socket; }
- set { _socket = value; }
+
+ internal Socket Socket {
+ get
+ {
+ return _socket;
+ }
+ set
+ {
+ _socket = value;
+ }
}
/// <summary>
@@ -509,69 +539,94 @@ namespace Npgsql
/// </summary>
internal Boolean IsInitialized
{
- get { return _isInitialized; }
- set { _isInitialized = value; }
+ get
+ {
+ return _isInitialized;
+ }
+ set
+ {
+ _isInitialized = value;
+ }
}
- internal NpgsqlState CurrentState
- {
- get { return _state; }
- set { _state = value; }
+ internal NpgsqlState CurrentState {
+ get
+ {
+ return _state;
+ }
+ set
+ {
+ _state = value;
+ }
}
internal bool Pooled
{
- get { return _pooled; }
+ get
+ {
+ return _pooled;
+ }
}
internal bool Shared
{
- get { return _shared; }
+ get
+ {
+ return _shared;
+ }
}
- internal NpgsqlBackEndKeyData BackEndKeyData
- {
- get { return _backend_keydata; }
- set { _backend_keydata = value; }
+ internal NpgsqlBackEndKeyData BackEndKeyData {
+ get
+ {
+ return _backend_keydata;
+ }
}
- internal NpgsqlBackendTypeMapping OidToNameMapping
- {
- get { return _oidToNameMapping; }
+ internal NpgsqlBackendTypeMapping OidToNameMapping {
+ get
+ {
+ return _oidToNameMapping;
+ }
}
/// <summary>
/// The connection mediator.
/// </summary>
- internal NpgsqlMediator Mediator
- {
- get { return _mediator; }
+ internal NpgsqlMediator Mediator {
+ get
+ {
+ return _mediator;
+ }
}
/// <summary>
/// Report if the connection is in a transaction.
/// </summary>
- internal NpgsqlTransaction Transaction
- {
- get { return _transaction; }
- set { _transaction = value; }
+ internal NpgsqlTransaction Transaction {
+ get
+ {
+ return _transaction;
+ }
+ set
+ {
+ _transaction = value;
+ }
}
/// <summary>
/// Report whether the current connection can support prepare functionality.
/// </summary>
- internal Boolean SupportsPrepare
- {
- get { return _supportsPrepare; }
- set { _supportsPrepare = value; }
- }
-
- internal Boolean SupportsSavepoint
- {
- get { return _supportsSavepoint; }
- set { _supportsSavepoint = value; }
-
+ internal Boolean SupportsPrepare {
+ get
+ {
+ return _supportsPrepare;
+ }
+ set
+ {
+ _supportsPrepare = value;
+ }
}
/// <summary>
@@ -579,16 +634,15 @@ namespace Npgsql
/// SupportsPrepare means the server can use prepared query plans (7.3+)
/// </summary>
// FIXME - should be private
- internal void ProcessServerVersion()
+ internal void ProcessServerVersion ()
{
- this._supportsPrepare = (ServerVersion >= new Version(7, 3, 0));
- this._supportsSavepoint = (ServerVersion >= new Version(8, 0, 0));
+ this._supportsPrepare = (ServerVersion >= new ServerVersion(7, 3, 0));
}
- /*/// <value>Counts the numbers of Connections that share
+ /// <value>Counts the numbers of Connections that share
/// this Connector. Used in Release() to decide wether this
/// connector is to be moved to the PooledConnectors list.</value>
- // internal int mShareCount;*/
+ // internal int mShareCount;
/// <summary>
/// Opens the physical connection to the server.
@@ -597,104 +651,96 @@ namespace Npgsql
/// Method of the connection pool manager.</remarks>
internal void Open()
{
- ServerVersion = null;
+ ProtocolVersion PV;
+
// If Connection.ConnectionString specifies a protocol version, we will
// not try to fall back to version 2 on failure.
+ if (ConnectionString.Contains(ConnectionStringKeys.Protocol))
+ {
+ PV = ConnectionString.ToProtocolVersion(ConnectionStringKeys.Protocol);
+ }
+ else
+ {
+ PV = ProtocolVersion.Unknown;
+ }
- _backendProtocolVersion = (settings.Protocol == ProtocolVersion.Unknown)
- ? ProtocolVersion.Version3
- : settings.Protocol;
+ _backendProtocolVersion = (PV == ProtocolVersion.Unknown) ? ProtocolVersion.Version3 : PV;
// Reset state to initialize new connector in pool.
+ Encoding = Encoding.Default;
CurrentState = NpgsqlClosedState.Instance;
// Get a raw connection, possibly SSL...
CurrentState.Open(this);
- try
- {
- // Establish protocol communication and handle authentication...
- CurrentState.Startup(this);
- }
- catch (NpgsqlException ne)
+ // Establish protocol communication and handle authentication...
+ CurrentState.Startup(this);
+
+ // Check for protocol not supported. If we have been told what protocol to use,
+ // we will not try this step.
+ if (_mediator.Errors.Count > 0 && PV == ProtocolVersion.Unknown)
{
- // Check for protocol not supported. If we have been told what protocol to use,
- // we will not try this step.
- if (settings.Protocol != ProtocolVersion.Unknown)
- {
- throw;
- }
// If we attempted protocol version 3, it may be possible to drop back to version 2.
- if (BackendProtocolVersion != ProtocolVersion.Version3)
+ if (BackendProtocolVersion == ProtocolVersion.Version3)
{
- throw;
- }
- NpgsqlError Error0 = (NpgsqlError) ne.Errors[0];
+ NpgsqlError Error0 = (NpgsqlError)_mediator.Errors[0];
- // If NpgsqlError..ctor() encounters a version 2 error,
- // it will set its own protocol version to version 2. That way, we can tell
- // easily if the error was a FATAL: protocol error.
- if (Error0.BackendProtocolVersion != ProtocolVersion.Version2)
- {
- throw;
+ // If NpgsqlError.ReadFromStream_Ver_3() encounters a version 2 error,
+ // it will set its own protocol version to version 2. That way, we can tell
+ // easily if the error was a FATAL: protocol error.
+ if (Error0.BackendProtocolVersion == ProtocolVersion.Version2)
+ {
+ // Try using the 2.0 protocol.
+ _mediator.ResetResponses();
+ BackendProtocolVersion = ProtocolVersion.Version2;
+ CurrentState = NpgsqlClosedState.Instance;
+
+ // Get a raw connection, possibly SSL...
+ CurrentState.Open(this);
+ // Establish protocol communication and handle authentication...
+ CurrentState.Startup(this);
+ }
}
- // Try using the 2.0 protocol.
- _mediator.ResetResponses();
- BackendProtocolVersion = ProtocolVersion.Version2;
- CurrentState = NpgsqlClosedState.Instance;
-
- // Get a raw connection, possibly SSL...
- CurrentState.Open(this);
- // Establish protocol communication and handle authentication...
- CurrentState.Startup(this);
}
+ // Check for errors and do the Right Thing.
+ // FIXME - CheckErrors needs to be moved to Connector
+ CheckErrors();
+
+ _backend_keydata = _mediator.BackendKeyData;
+
// Change the state of connection to open and ready.
_connection_state = ConnectionState.Open;
CurrentState = NpgsqlReadyState.Instance;
+ String ServerVersionString = String.Empty;
+
+ // First try to determine backend server version using the newest method.
+ if (((NpgsqlParameterStatus)_mediator.Parameters["__npgsql_server_version"]) != null)
+ ServerVersionString = ((NpgsqlParameterStatus)_mediator.Parameters["__npgsql_server_version"]).ParameterValue;
+
+
// Fall back to the old way, SELECT VERSION().
// This should not happen for protocol version 3+.
- if (ServerVersion == null)
+ if (ServerVersionString.Length == 0)
{
- NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this);
- ServerVersion = new Version(PGUtil.ExtractServerVersion((string) command.ExecuteScalar()));
+ NpgsqlCommand command = new NpgsqlCommand("select version();set DATESTYLE TO ISO;", this);
+ ServerVersionString = PGUtil.ExtractServerVersion( (String)command.ExecuteScalar() );
}
+ // Cook version string so we can use it for enabling/disabling things based on
+ // backend version.
+ ServerVersion = PGUtil.ParseServerVersion(ServerVersionString);
+
// Adjust client encoding.
- NpgsqlParameterStatus clientEncodingParam = null;
- if(
- !ServerParameters.TryGetValue("client_encoding", out clientEncodingParam) ||
- (!string.Equals(clientEncodingParam.ParameterValue, "UTF8", StringComparison.OrdinalIgnoreCase) && !string.Equals(clientEncodingParam.ParameterValue, "UNICODE", StringComparison.OrdinalIgnoreCase))
- )
- new NpgsqlCommand("SET CLIENT_ENCODING TO UTF8", this).ExecuteBlind();
+ //NpgsqlCommand commandEncoding1 = new NpgsqlCommand("show client_encoding", _connector);
+ //String clientEncoding1 = (String)commandEncoding1.ExecuteScalar();
- if (!string.IsNullOrEmpty(settings.SearchPath))
+ if (ConnectionString.ToString(ConnectionStringKeys.Encoding, ConnectionStringDefaults.Encoding).ToUpper() == "UNICODE")
{
- /*NpgsqlParameter p = new NpgsqlParameter("p", DbType.String);
- p.Value = settings.SearchPath;
- NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH TO :p,public", this);
- commandSearchPath.Parameters.Add(p);
- commandSearchPath.ExecuteNonQuery();*/
-
- /*NpgsqlParameter p = new NpgsqlParameter("p", DbType.String);
- p.Value = settings.SearchPath;
- NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH TO :p,public", this);
- commandSearchPath.Parameters.Add(p);
- commandSearchPath.ExecuteNonQuery();*/
-
- // TODO: Add proper message when finding a semicolon in search_path.
- // This semicolon could lead to a sql injection security hole as someone could write in connection string:
- // searchpath=public;delete from table; and it would be executed.
-
- if (settings.SearchPath.Contains(";"))
- {
- throw new InvalidOperationException();
- }
-
- // This is using string concatenation because set search_path doesn't allow type casting. ::text
- NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH=" + settings.SearchPath, this);
- commandSearchPath.ExecuteBlind();
+ Encoding = Encoding.UTF8;
+ NpgsqlCommand commandEncoding = new NpgsqlCommand("SET CLIENT_ENCODING TO UNICODE", this);
+ commandEncoding.ExecuteNonQuery();
}
// Make a shallow copy of the type mapping that the connector will own.
@@ -718,40 +764,36 @@ namespace Npgsql
{
try
{
- if (_connection_state != ConnectionState.Closed)
- {
- _connection_state = ConnectionState.Closed;
- this.CurrentState.Close(this);
- _serverParameters.Clear();
- ServerVersion = null;
- }
- }
- catch
- {
+ this.CurrentState.Close(this);
}
+ catch {}
}
-
+
internal void CancelRequest()
{
- NpgsqlConnector CancelConnector = new NpgsqlConnector(settings, false, false);
-
+
+ NpgsqlConnector CancelConnector = new NpgsqlConnector(ConnectionString, false, false);
+
CancelConnector._backend_keydata = BackEndKeyData;
-
-
+
+
// Get a raw connection, possibly SSL...
CancelConnector.CurrentState.Open(CancelConnector);
-
+
// Cancel current request.
CancelConnector.CurrentState.CancelRequest(CancelConnector);
+
+
}
///<summary>
/// Returns next portal index.
///</summary>
- internal String NextPortalName()
+ internal String NextPortalName()
{
- return _portalNamePrefix + Interlocked.Increment(ref _portalIndex);
+
+ return _portalNamePrefix + System.Threading.Interlocked.Increment(ref _portalIndex);
}
@@ -760,166 +802,114 @@ namespace Npgsql
///</summary>
internal String NextPlanName()
{
- return _planNamePrefix + Interlocked.Increment(ref _planIndex);
+ return _planNamePrefix + System.Threading.Interlocked.Increment(ref _planIndex);
}
-
-
+
+
internal void RemoveNotificationThread()
{
// Wait notification thread finish its work.
_notificationAutoResetEvent.WaitOne();
-
+
// Kill notification thread.
_notificationThread.Abort();
_notificationThread = null;
-
+
// Special case in order to not get problems with thread synchronization.
// It will be turned to 0 when synch thread is created.
- _notificationThreadStopCount = 1;
+ _notificationThreadStopCount = 1;
+
}
-
+
internal void AddNotificationThread()
{
+
_notificationThreadStopCount = 0;
_notificationAutoResetEvent.Set();
-
+
NpgsqlContextHolder contextHolder = new NpgsqlContextHolder(this, CurrentState);
-
+
_notificationThread = new Thread(new ThreadStart(contextHolder.ProcessServerMessages));
-
+
_notificationThread.Start();
+
+
+
}
-
- //Use with using(){} to perform the sentry pattern
- //on stopping and starting notification thread
- //(The sentry pattern is a generalisation of RAII where we
- //have a pair of actions - one "undoing" the previous
- //and we want to execute the first and second around other code,
- //then we treat it much like resource mangement in RAII.
- //try{}finally{} also does execute-around, but sentry classes
- //have some extra flexibility (e.g. they can be "owned" by
- //another object and then cleaned up when that object is
- //cleaned up), and can act as the sole gate-way
- //to the code in question, guaranteeing that using code can't be written
- //so that the "undoing" is forgotten.
- internal class NotificationThreadBlock : IDisposable
- {
- private NpgsqlConnector _connector;
-
- public NotificationThreadBlock(NpgsqlConnector connector)
- {
- (_connector = connector).StopNotificationThread();
- }
-
- public void Dispose()
- {
- if (_connector != null)
- {
- _connector.ResumeNotificationThread();
- }
- _connector = null;
- }
- }
-
- internal NotificationThreadBlock BlockNotificationThread()
- {
- return new NotificationThreadBlock(this);
- }
-
- private void StopNotificationThread()
+
+ internal void StopNotificationThread()
{
- // first check to see if an exception has
- // been thrown by the notification thread.
- if (_notificationException != null)
- throw _notificationException;
-
+
_notificationThreadStopCount++;
-
+
if (_notificationThreadStopCount == 1) // If this call was the first to increment.
{
+
_notificationAutoResetEvent.WaitOne();
+
}
}
-
- private void ResumeNotificationThread()
+
+ internal void ResumeNotificationThread()
{
_notificationThreadStopCount--;
if (_notificationThreadStopCount == 0)
{
// Release the synchronization handle.
-
+
_notificationAutoResetEvent.Set();
}
+
}
-
+
internal Boolean IsNotificationThreadRunning
{
- get { return _notificationThreadStopCount <= 0; }
+ get
+ {
+ return _notificationThreadStopCount <= 0;
+
+ }
}
-
-
+
+
internal class NpgsqlContextHolder
{
- private readonly NpgsqlConnector connector;
- private readonly NpgsqlState state;
-
+
+ private NpgsqlConnector connector;
+ private NpgsqlState state;
+
internal NpgsqlContextHolder(NpgsqlConnector connector, NpgsqlState state)
{
this.connector = connector;
this.state = state;
+
}
-
+
internal void ProcessServerMessages()
{
- try
+
+ while(true)
{
- while (true)
+ this.connector._notificationAutoResetEvent.WaitOne();
+
+ if (this.connector.Socket.Poll(1000, SelectMode.SelectRead))
{
- Thread.Sleep(0);
- //To give runtime chance to release correctly the lock. See http://pgfoundry.org/forum/message.php?msg_id=1002650 for more information.
- this.connector._notificationAutoResetEvent.WaitOne();
-
- if (this.connector.Socket.Poll(100, SelectMode.SelectRead))
- {
- // reset any responses just before getting new ones
- this.connector.Mediator.ResetResponses();
- this.state.ProcessBackendResponses(this.connector);
- }
-
- this.connector._notificationAutoResetEvent.Set();
+ // reset any responses just before getting new ones
+ this.connector.Mediator.ResetResponses();
+ this.state.ProcessBackendResponses(this.connector);
+ this.connector.CheckErrorsAndNotifications();
}
- }
- catch (IOException ex)
- {
- this.connector._notificationException = ex;
+
this.connector._notificationAutoResetEvent.Set();
}
-
+
+
+
}
-
+
}
- public bool RequireReadyForQuery
- {
- get { return _requireReadyForQuery; }
- set { _requireReadyForQuery = value; }
- }
- public void AddParameterStatus(NpgsqlParameterStatus ps)
- {
- if (_serverParameters.ContainsKey(ps.Parameter))
- {
- _serverParameters[ps.Parameter] = ps;
- }
- else
- {
- _serverParameters.Add(ps.Parameter, ps);
- }
- }
- public IDictionary<string, NpgsqlParameterStatus> ServerParameters
- {
- get { return new ReadOnlyDictionary<string, NpgsqlParameterStatus>(_serverParameters); }
- }
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs b/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
index 2bc87f24316..4690c8e654f 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlConnectorPool.cs
@@ -2,22 +2,19 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// ConnectorPool.cs
// ------------------------------------------------------------------
@@ -27,602 +24,534 @@
// System.Queue.
using System;
-using System.Collections.Generic;
-using System.Data;
+using System.Collections;
using System.Threading;
using System.Timers;
-using Timer = System.Timers.Timer;
namespace Npgsql
{
- /// <summary>
- /// This class manages all connector objects, pooled AND non-pooled.
- /// </summary>
- internal class NpgsqlConnectorPool
- {
- /// <summary>
- /// A queue with an extra Int32 for keeping track of busy connections.
- /// </summary>
- private class ConnectorQueue : Queue<NpgsqlConnector>
- {
- /// <summary>
- /// The number of pooled Connectors that belong to this queue but
- /// 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
- /// mamager.</value>
- internal static NpgsqlConnectorPool ConnectorPoolMgr = new NpgsqlConnectorPool();
-
- public NpgsqlConnectorPool()
- {
- PooledConnectors = new Dictionary<string, ConnectorQueue>();
- Timer = new 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;
- toBeClosed = Math.Min(toBeClosed, Queue.Count);
-
- if (diff < 2)
- {
- diff = 2;
- }
- Queue.InactiveTime -= Queue.ConnectionLifeTime / (int)(Math.Log(diff) / Math.Log(2));
- for (Int32 i = 0; i < toBeClosed; ++i)
- {
- Connector = 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.
- /// This key will hold a list of queues of pooled connectors available to be used.</remarks>
- private readonly Dictionary<string, ConnectorQueue> PooledConnectors;
-
- /*/// <value>Map of shared connectors, avaliable to the
+ /// <summary>
+ /// This class manages all connector objects, pooled AND non-pooled.
+ /// </summary>
+ internal class NpgsqlConnectorPool
+ {
+ /// <summary>
+ /// A queue with an extra Int32 for keeping track of busy connections.
+ /// </summary>
+ private class ConnectorQueue : System.Collections.Queue
+ {
+ /// <summary>
+ /// The number of pooled Connectors that belong to this queue but
+ /// 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
+ /// mamager.</value>
+ internal static NpgsqlConnectorPool ConnectorPoolMgr = new NpgsqlConnectorPool();
+
+ 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.
+ /// This key will hold a list of queues of pooled connectors available to be used.</remarks>
+ private Hashtable PooledConnectors;
+
+ /// <value>Map of shared connectors, avaliable to the
/// next RequestConnector() call.</value>
/// <remarks>This hashmap will be indexed by connection string.
/// This key will hold a list of shared connectors available to be used.</remarks>
// To be implemented
- //private Dictionary<?, ?> 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 readonly Timer Timer;
-
- /// <summary>
- /// Searches the shared and pooled connector lists for a
- /// matching connector object or creates a new one.
- /// </summary>
- /// <param name="Connection">The NpgsqlConnection that is requesting
- /// the connector. Its ConnectionString will be used to search the
- /// pool for available connectors.</param>
- /// <returns>A connector object.</returns>
- public NpgsqlConnector RequestConnector(NpgsqlConnection Connection)
- {
- NpgsqlConnector Connector;
-
- if (Connection.Pooling)
- {
- Connector = RequestPooledConnector(Connection);
- }
- else
- {
- Connector = GetNonPooledConnector(Connection);
- }
-
- return Connector;
- }
-
- /// <summary>
- /// Find a pooled connector. Handle locking and timeout here.
- /// </summary>
- private NpgsqlConnector RequestPooledConnector(NpgsqlConnection Connection)
- {
- NpgsqlConnector Connector;
- Int32 timeoutMilliseconds = Connection.Timeout * 1000;
-
- lock (this)
- {
- Connector = RequestPooledConnectorInternal(Connection);
- }
-
- while (Connector == null && timeoutMilliseconds > 0)
- {
- Int32 ST = timeoutMilliseconds > 1000 ? 1000 : timeoutMilliseconds;
-
- Thread.Sleep(ST);
- timeoutMilliseconds -= ST;
-
- lock (this)
- {
- Connector = RequestPooledConnectorInternal(Connection);
- }
- }
-
- if (Connector == null)
- {
- if (Connection.Timeout > 0)
- {
- throw new Exception("Timeout while getting a connection from pool.");
- }
- else
- {
- throw new Exception("Connection pool exceeds maximum size.");
- }
- }
-
- return Connector;
- }
-
- /// <summary>
- /// Find a pooled connector. Handle shared/non-shared here.
- /// </summary>
- private NpgsqlConnector RequestPooledConnectorInternal(NpgsqlConnection Connection)
- {
- NpgsqlConnector Connector = null;
- Boolean Shared = false;
-
- // If sharing were implemented, I suppose Shared would be set based
- // on some property on the Connection.
-
- if (Shared)
- {
- // Connection sharing? What's that?
- throw new NotImplementedException("Internal: Shared pooling not implemented");
-
- }
- Connector = GetPooledConnector(Connection);
-
-
- return Connector;
- }
-
- private delegate void CleanUpConnectorDel(NpgsqlConnection Connection, NpgsqlConnector Connector);
-
- private void CleanUpConnectorMethod(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- try
- {
- Connector.CurrentReader.Close();
- Connector.CurrentReader = null;
- ReleaseConnector(Connection, Connector);
- }
- catch
- {
- }
- }
-
- private void CleanUpConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- new CleanUpConnectorDel(CleanUpConnectorMethod).BeginInvoke(Connection, Connector, null, null);
- }
-
- /// <summary>
- /// Releases a connector, possibly back to the pool for future use.
- /// </summary>
- /// <remarks>
- /// Pooled connectors will be put back into the pool if there is room.
- /// Shared connectors should just have their use count decremented
- /// since they always stay in the shared pool.
- /// </remarks>
- /// <param name="Connector">The connector to release.</param>
- public void ReleaseConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- if (Connector.CurrentReader != null)
- {
- CleanUpConnector(Connection, Connector);
- }
- else if (Connector.Pooled)
- {
- ReleasePooledConnector(Connection, Connector);
- }
- else
- {
- UngetNonPooledConnector(Connection, Connector);
- }
- }
-
- /// <summary>
- /// Release a pooled connector. Handle locking here.
- /// </summary>
- private void ReleasePooledConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- lock (this)
- {
- ReleasePooledConnectorInternal(Connection, Connector);
- }
- }
-
- /// <summary>
- /// Release a pooled connector. Handle shared/non-shared here.
- /// </summary>
- private void ReleasePooledConnectorInternal(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- if (!Connector.Shared)
- {
- UngetPooledConnector(Connection, Connector);
- }
- else
- {
- // Connection sharing? What's that?
- throw new NotImplementedException("Internal: Shared pooling not implemented");
- }
- }
-
- /// <summary>
- /// Create a connector without any pooling functionality.
- /// </summary>
- private static NpgsqlConnector GetNonPooledConnector(NpgsqlConnection Connection)
- {
- NpgsqlConnector Connector;
-
- Connector = CreateConnector(Connection);
-
- Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate;
- Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate;
- Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate;
-
- Connector.Open();
-
- return Connector;
- }
-
- /// <summary>
- /// Find an available pooled connector in the non-shared pool, or create
- /// a new one if none found.
- /// </summary>
- private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection)
- {
- ConnectorQueue Queue;
- NpgsqlConnector Connector = null;
-
- // Try to find a queue.
- if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue))
- {
- Queue = new ConnectorQueue();
- Queue.ConnectionLifeTime = Connection.ConnectionLifeTime;
- Queue.MinPoolSize = Connection.MinPoolSize;
- PooledConnectors[Connection.ConnectionString] = Queue;
- }
-
- // Fix queue use count. Use count may be dropped below zero if Queue was cleared and there were connections open.
- if (Queue.UseCount < 0)
- {
- Queue.UseCount = 0;
- }
-
-
- if (Queue.Count > 0)
- {
- // Found a queue with connectors. Grab the top one.
-
- // Check if the connector is still valid.
-
- Connector = Queue.Dequeue();
- /*try
- {
- Connector.TestConnector();
- Connector.RequireReadyForQuery = true;
- }
- catch //This connector is broken!
- {
- try
- {
- Connector.Close();
- }
- catch
- {
- try
- {
- Connector.Stream.Close();
- }
- catch
- {
- }
- }
- return GetPooledConnector(Connection); //Try again
- }*/
-
- if (!Connector.IsValid())
- {
- try
- {
- Connector.Close();
- }
- catch
- {
- try
- {
- Connector.Stream.Close();
- }
- catch
- {
- }
- }
- return GetPooledConnector(Connection); //Try again
-
- }
- Queue.UseCount++;
- }
- else if (Queue.Count + Queue.UseCount < Connection.MaxPoolSize)
- {
- Connector = CreateConnector(Connection);
-
- Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate;
- Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate;
- Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate;
-
- try
- {
- Connector.Open();
- }
- catch
- {
- try
- {
- Connector.Close();
- }
- catch
- {
- }
-
- throw;
- }
-
-
- Queue.UseCount++;
- }
-
- // Meet the MinPoolSize requirement if needed.
- if (Connection.MinPoolSize > 0)
- {
- while (Queue.Count + Queue.UseCount < Connection.MinPoolSize)
- {
- NpgsqlConnector Spare = CreateConnector(Connection);
-
- Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate;
- Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate;
- Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate;
-
- Spare.Open();
-
- Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate;
- Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate;
- Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate;
-
- Queue.Enqueue(Spare);
- }
- }
-
- return Connector;
- }
-
- /*
- /// <summary>
- /// Find an available shared connector in the shared pool, or create
- /// a new one if none found.
- /// </summary>
- private NpgsqlConnector GetSharedConnector(NpgsqlConnection Connection)
- {
- // To be implemented
-
- return null;
- }
- */
-
- private static NpgsqlConnector CreateConnector(NpgsqlConnection Connection)
- {
- return new NpgsqlConnector(Connection.ConnectionStringValues.Clone(), Connection.Pooling, false);
- }
-
-
- /// <summary>
- /// This method is only called when NpgsqlConnection.Dispose(false) is called which means a
- /// finalization. This also means, an NpgsqlConnection was leak. We clear pool count so that
- /// client doesn't end running out of connections from pool. When the connection is finalized, its underlying
- /// socket is closed.
- /// </summary>
- public void FixPoolCountBecauseOfConnectionDisposeFalse(NpgsqlConnection Connection)
- {
- ConnectorQueue Queue;
-
- // Prevent multithread access to connection pool count.
- lock (this)
- {
- // Try to find a queue.
- if (PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue) && Queue != null)
- {
- Queue.UseCount--;
- }
- }
- }
-
- /// <summary>
- /// Close the connector.
- /// </summary>
- /// <param name="Connection"></param>
- /// <param name="Connector">Connector to release</param>
- private static void UngetNonPooledConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- Connector.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate;
- Connector.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate;
- Connector.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate;
-
- if (Connector.Transaction != null)
- {
- Connector.Transaction.Cancel();
- }
-
- Connector.Close();
- }
-
- /// <summary>
- /// Put a pooled connector into the pool queue.
- /// </summary>
- /// <param name="Connector">Connector to pool</param>
- private void UngetPooledConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- ConnectorQueue Queue;
-
- // Find the queue.
- if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue) || Queue == null)
- {
- return; // Queue may be emptied by connection problems. See ClearPool below.
- }
-
- Connector.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate;
- Connector.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate;
- Connector.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate;
-
- Queue.UseCount--;
-
- if (!Connector.IsInitialized)
- {
- if (Connector.Transaction != null)
- {
- Connector.Transaction.Cancel();
- }
-
- Connector.Close();
- }
- else
- {
- if (Connector.Transaction != null)
- {
- try
- {
- Connector.Transaction.Rollback();
- }
- catch
- {
- Connector.Close();
- }
- }
- }
-
- if (Connector.State == ConnectionState.Open &&
- (Thread.CurrentThread.ThreadState & (ThreadState.Aborted | ThreadState.AbortRequested)) == 0)
- {
- // Release all resources associated with this connector.
- Connector.ReleaseResources();
-
- Queue.Enqueue(Connector);
- }
- }
-
- /*
- /// <summary>
- /// Stop sharing a shared connector.
- /// </summary>
- /// <param name="Connector">Connector to unshare</param>
- private void UngetSharedConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
- {
- // To be implemented
- }
- */
-
- private static void ClearQueue(ConnectorQueue Queue)
- {
- if (Queue == null)
- {
- return;
- }
-
- while (Queue.Count > 0)
- {
- NpgsqlConnector connector = Queue.Dequeue();
-
- try
- {
- connector.Close();
- }
- catch
- {
- // Maybe we should log something here to say we got an exception while closing connector?
- }
- }
- }
-
-
- internal void ClearPool(NpgsqlConnection Connection)
- {
- // Prevent multithread access to connection pool count.
- lock (this)
- {
- ConnectorQueue queue;
- // Try to find a queue.
- if (PooledConnectors.TryGetValue(Connection.ConnectionString, out queue))
+ //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.
+ /// </summary>
+ /// <param name="Connection">The NpgsqlConnection that is requesting
+ /// the connector. Its ConnectionString will be used to search the
+ /// pool for available connectors.</param>
+ /// <returns>A connector object.</returns>
+ public NpgsqlConnector RequestConnector (NpgsqlConnection Connection)
+ {
+ NpgsqlConnector Connector;
+
+ if (Connection.Pooling)
+ {
+ Connector = RequestPooledConnector(Connection);
+ }
+ else
+ {
+ Connector = GetNonPooledConnector(Connection);
+ }
+
+ return Connector;
+ }
+
+ /// <summary>
+ /// Find a pooled connector. Handle locking and timeout here.
+ /// </summary>
+ private NpgsqlConnector RequestPooledConnector (NpgsqlConnection Connection)
+ {
+ NpgsqlConnector Connector;
+ Int32 timeoutMilliseconds = Connection.Timeout * 1000;
+
+ lock(this)
+ {
+ Connector = RequestPooledConnectorInternal(Connection);
+ }
+
+ while (Connector == null && timeoutMilliseconds > 0)
+ {
+ Int32 ST = timeoutMilliseconds > 1000 ? 1000 : timeoutMilliseconds;
+
+ Thread.Sleep(ST);
+ timeoutMilliseconds -= ST;
+
+ lock(this)
{
- ClearQueue(queue);
+ Connector = RequestPooledConnectorInternal(Connection);
+ }
+ }
- PooledConnectors.Remove(Connection.ConnectionString);
+ if (Connector == null)
+ {
+ if (Connection.Timeout > 0)
+ {
+ throw new Exception("Timeout while getting a connection from pool.");
}
- }
- }
-
-
- internal void ClearAllPools()
- {
- lock (this)
- {
- foreach (ConnectorQueue Queue in PooledConnectors.Values)
- {
- ClearQueue(Queue);
- }
- PooledConnectors.Clear();
- }
- }
- }
+ else
+ {
+ throw new Exception("Connection pool exceeds maximum size.");
+ }
+ }
+
+ return Connector;
+ }
+
+ /// <summary>
+ /// Find a pooled connector. Handle shared/non-shared here.
+ /// </summary>
+ private NpgsqlConnector RequestPooledConnectorInternal (NpgsqlConnection Connection)
+ {
+ NpgsqlConnector Connector = null;
+ Boolean Shared = false;
+
+ // If sharing were implemented, I suppose Shared would be set based
+ // on some property on the Connection.
+
+ if (! Shared)
+ {
+ Connector = GetPooledConnector(Connection);
+ }
+ else
+ {
+ // Connection sharing? What's that?
+ throw new NotImplementedException("Internal: Shared pooling not implemented");
+ }
+
+ return Connector;
+ }
+
+ /// <summary>
+ /// Releases a connector, possibly back to the pool for future use.
+ /// </summary>
+ /// <remarks>
+ /// Pooled connectors will be put back into the pool if there is room.
+ /// Shared connectors should just have their use count decremented
+ /// since they always stay in the shared pool.
+ /// </remarks>
+ /// <param name="Connector">The connector to release.</param>
+ /// <param name="ForceClose">Force the connector to close, even if it is pooled.</param>
+ public void ReleaseConnector (NpgsqlConnection Connection, NpgsqlConnector Connector)
+ {
+ if (Connector.Pooled)
+ {
+ ReleasePooledConnector(Connection, Connector);
+ }
+ else
+ {
+ UngetNonPooledConnector(Connection, Connector);
+ }
+ }
+
+ /// <summary>
+ /// Release a pooled connector. Handle locking here.
+ /// </summary>
+ private void ReleasePooledConnector (NpgsqlConnection Connection, NpgsqlConnector Connector)
+ {
+ lock(this)
+ {
+ ReleasePooledConnectorInternal(Connection, Connector);
+ }
+ }
+
+ /// <summary>
+ /// Release a pooled connector. Handle shared/non-shared here.
+ /// </summary>
+ private void ReleasePooledConnectorInternal (NpgsqlConnection Connection, NpgsqlConnector Connector)
+ {
+ if (! Connector.Shared)
+ {
+ UngetPooledConnector(Connection, Connector);
+ }
+ else
+ {
+ // Connection sharing? What's that?
+ throw new NotImplementedException("Internal: Shared pooling not implemented");
+ }
+ }
+
+ /// <summary>
+ /// Create a connector without any pooling functionality.
+ /// </summary>
+ private NpgsqlConnector GetNonPooledConnector(NpgsqlConnection Connection)
+ {
+ NpgsqlConnector Connector;
+
+ Connector = CreateConnector(Connection);
+
+ Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate;
+ Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate;
+ Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate;
+
+ Connector.Open();
+
+ return Connector;
+ }
+
+ /// <summary>
+ /// Find an available pooled connector in the non-shared pool, or create
+ /// a new one if none found.
+ /// </summary>
+ private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection)
+ {
+ ConnectorQueue Queue;
+ NpgsqlConnector Connector = null;
+
+ // Try to find a queue.
+ Queue = (ConnectorQueue)PooledConnectors[Connection.ConnectionString.ToString()];
+
+ if (Queue == null)
+ {
+ Queue = new ConnectorQueue();
+ Queue.ConnectionLifeTime = Connection.ConnectionLifeTime;
+ Queue.MinPoolSize = Connection.MinPoolSize;
+ PooledConnectors[Connection.ConnectionString.ToString()] = Queue;
+ }
+
+ // Fix queue use count. Use count may be dropped below zero if Queue was cleared and there were connections open.
+ if (Queue.UseCount < 0)
+ Queue.UseCount = 0;
+
+
+ if (Queue.Count > 0)
+ {
+ // Found a queue with connectors. Grab the top one.
+
+ // Check if the connector is still valid.
+
+ Connector = (NpgsqlConnector)Queue.Dequeue();
+ Queue.UseCount++;
+
+
+
+ }
+ else if (Queue.Count + Queue.UseCount < Connection.MaxPoolSize)
+ {
+ Connector = CreateConnector(Connection);
+
+ Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate;
+ Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate;
+ Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate;
+
+ try
+ {
+ Connector.Open();
+ }
+ catch {
+ try
+ {
+ Connector.Close();
+ }
+ catch {}
+
+ throw;
+ }
+
+
+ Queue.UseCount++;
+ }
+
+ // Meet the MinPoolSize requirement if needed.
+ if (Connection.MinPoolSize > 0)
+ {
+ while (Queue.Count + Queue.UseCount < Connection.MinPoolSize)
+ {
+ NpgsqlConnector Spare = CreateConnector(Connection);
+
+ Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate;
+ Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate;
+ Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate;
+
+ Spare.Open();
+
+ Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate;
+ Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate;
+ Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate;
+
+ Queue.Enqueue(Spare);
+ }
+ }
+
+ return Connector;
+ }
+
+ /// <summary>
+ /// Find an available shared connector in the shared pool, or create
+ /// a new one if none found.
+ /// </summary>
+ private NpgsqlConnector GetSharedConnector(NpgsqlConnection Connection)
+ {
+ // To be implemented
+
+ return null;
+ }
+
+ private NpgsqlConnector CreateConnector(NpgsqlConnection Connection)
+ {
+ return new NpgsqlConnector(
+ Connection.ConnectionStringValues.Clone(),
+ Connection.Pooling,
+ false
+ );
+ }
+
+
+ /// <summary>
+ /// This method is only called when NpgsqlConnection.Dispose(false) is called which means a
+ /// finalization. This also means, an NpgsqlConnection was leak. We clear pool count so that
+ /// client doesn't end running out of connections from pool. When the connection is finalized, its underlying
+ /// socket is closed.
+ /// </summary
+ public void FixPoolCountBecauseOfConnectionDisposeFalse(NpgsqlConnection Connection)
+ {
+ ConnectorQueue Queue;
+
+ // Prevent multithread access to connection pool count.
+ lock(this)
+ {
+ // Try to find a queue.
+ Queue = (ConnectorQueue)PooledConnectors[Connection.ConnectionString.ToString()];
+
+ if (Queue != null)
+ Queue.UseCount--;
+
+ }
+ }
+
+ /// <summary>
+ /// Close the connector.
+ /// </summary>
+ /// <param name="Connector">Connector to release</param>
+ private void UngetNonPooledConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
+ {
+ Connector.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate;
+ Connector.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate;
+ Connector.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate;
+
+ if (Connector.Transaction != null)
+ {
+ Connector.Transaction.Cancel();
+ }
+
+ Connector.Close();
+ }
+
+ /// <summary>
+ /// Put a pooled connector into the pool queue.
+ /// </summary>
+ /// <param name="Connector">Connector to pool</param>
+ private void UngetPooledConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
+ {
+ ConnectorQueue Queue;
+
+ // Find the queue.
+ Queue = (ConnectorQueue)PooledConnectors[Connector.ConnectionString.ToString()];
+
+ if (Queue == null)
+ return; // Queue may be emptied by connection problems. See ClearPool below.
+
+ Connector.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate;
+ Connector.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate;
+ Connector.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate;
+
+ Queue.UseCount--;
+
+ if (! Connector.IsInitialized)
+ {
+ if (Connector.Transaction != null)
+ {
+ Connector.Transaction.Cancel();
+ }
+
+ Connector.Close();
+ }
+ else
+ {
+ if (Connector.Transaction != null)
+ {
+ try
+ {
+ Connector.Transaction.Rollback();
+ }
+ catch {
+ Connector.Close()
+ ;
+ }
+ }
+ }
+
+ if (Connector.State == System.Data.ConnectionState.Open)
+ {
+ // Release all resources associated with this connector.
+ Connector.ReleaseResources();
+
+ Queue.Enqueue(Connector);
+ }
+ }
+
+ /// <summary>
+ /// Stop sharing a shared connector.
+ /// </summary>
+ /// <param name="Connector">Connector to unshare</param>
+ private void UngetSharedConnector(NpgsqlConnection Connection, NpgsqlConnector Connector)
+ {
+ // To be implemented
+ }
+
+ private void ClearQueue(ConnectorQueue Queue)
+ {
+ if (Queue == null)
+ return;
+
+ while (Queue.Count > 0)
+ {
+ NpgsqlConnector connector = (NpgsqlConnector)Queue.Dequeue();
+
+ try
+ {
+ connector.Close();
+ }
+ catch {
+ // Maybe we should log something here to say we got an exception while closing connector?
+
+ }
+
+ }
+
+ }
+
+
+ internal void ClearPool(NpgsqlConnection Connection)
+ {
+ // Prevent multithread access to connection pool count.
+ lock(this)
+ {
+ // Try to find a queue.
+ ConnectorQueue queue = (ConnectorQueue)PooledConnectors[Connection.ConnectionString.ToString()];
+
+ ClearQueue(queue);
+
+ PooledConnectors[Connection.ConnectionString.ToString()] = null;
+
+ }
+
+
+ }
+
+ internal void ClearAllPools()
+ {
+
+ lock (this)
+ {
+ foreach (ConnectorQueue Queue in PooledConnectors.Values)
+ ClearQueue(Queue);
+
+ }
+
+
+ }
+
+ }
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlDataAdapter.cs b/mcs/class/Npgsql/Npgsql/NpgsqlDataAdapter.cs
index 167642c66b1..d41193edd0c 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlDataAdapter.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlDataAdapter.cs
@@ -10,212 +10,267 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Data;
using System.Data.Common;
+using System.Resources;
namespace Npgsql
{
- /// <summary>
- /// Represents the method that handles the <see cref="Npgsql.NpgsqlDataAdapter.RowUpdated">RowUpdated</see> events.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">A <see cref="NpgsqlRowUpdatedEventArgs">NpgsqlRowUpdatedEventArgs</see> that contains the event data.</param>
- public delegate void NpgsqlRowUpdatedEventHandler(Object sender, NpgsqlRowUpdatedEventArgs e);
-
- /// <summary>
- /// Represents the method that handles the <see cref="Npgsql.NpgsqlDataAdapter.RowUpdating">RowUpdating</see> events.
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">A <see cref="NpgsqlRowUpdatingEventArgs">NpgsqlRowUpdatingEventArgs</see> that contains the event data.</param>
- public delegate void NpgsqlRowUpdatingEventHandler(Object sender, NpgsqlRowUpdatingEventArgs e);
-
-
- /// <summary>
- /// This class represents an adapter from many commands: select, update, insert and delete to fill <see cref="System.Data.DataSet">Datasets.</see>
- /// </summary>
- public sealed class NpgsqlDataAdapter : DbDataAdapter, IDbDataAdapter
- {
- private NpgsqlCommand _selectCommand;
- private NpgsqlCommand _updateCommand;
- private NpgsqlCommand _deleteCommand;
- private NpgsqlCommand _insertCommand;
-
- // Log support
- private static readonly String CLASSNAME = "NpgsqlDataAdapter";
-
-
- public event NpgsqlRowUpdatedEventHandler RowUpdated;
- public event NpgsqlRowUpdatingEventHandler RowUpdating;
-
- public NpgsqlDataAdapter()
- {
- }
-
- public NpgsqlDataAdapter(NpgsqlCommand selectCommand)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
- _selectCommand = selectCommand;
- }
-
- public NpgsqlDataAdapter(String selectCommandText, NpgsqlConnection selectConnection)
- : this(new NpgsqlCommand(selectCommandText, selectConnection))
- {
- }
-
- public NpgsqlDataAdapter(String selectCommandText, String selectConnectionString)
- : this(selectCommandText, new NpgsqlConnection(selectConnectionString))
- {
- }
-
-
- protected override RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand command,
- StatementType statementType,
- DataTableMapping tableMapping)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateRowUpdatedEvent");
- return new NpgsqlRowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
- }
-
- protected override RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand command,
- StatementType statementType,
- DataTableMapping tableMapping)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateRowUpdatingEvent");
- return new NpgsqlRowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
- }
-
- protected override void OnRowUpdated(RowUpdatedEventArgs value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "OnRowUpdated");
- //base.OnRowUpdated(value);
- if ((RowUpdated != null) && (value is NpgsqlRowUpdatedEventArgs))
- {
- RowUpdated(this, (NpgsqlRowUpdatedEventArgs) value);
- }
- }
-
- protected override void OnRowUpdating(RowUpdatingEventArgs value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "OnRowUpdating");
- if ((RowUpdating != null) && (value is NpgsqlRowUpdatingEventArgs))
- {
- RowUpdating(this, (NpgsqlRowUpdatingEventArgs) value);
- }
- }
-
- ITableMappingCollection IDataAdapter.TableMappings
- {
- get { return TableMappings; }
- }
-
- IDbCommand IDbDataAdapter.DeleteCommand
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IDbDataAdapter.DeleteCommand");
- return DeleteCommand;
- }
-
- set { DeleteCommand = (NpgsqlCommand) value; }
- }
-
-
- public new NpgsqlCommand DeleteCommand
- {
- get { return _deleteCommand; }
-
- set { _deleteCommand = value; }
- }
-
- IDbCommand IDbDataAdapter.SelectCommand
- {
- get { return SelectCommand; }
-
- set { SelectCommand = (NpgsqlCommand) value; }
- }
-
-
- public new NpgsqlCommand SelectCommand
- {
- get { return _selectCommand; }
-
- set { _selectCommand = value; }
- }
-
- IDbCommand IDbDataAdapter.UpdateCommand
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IDbDataAdapter.UpdateCommand");
- return UpdateCommand;
- }
-
- set { UpdateCommand = (NpgsqlCommand) value; }
- }
-
-
- public new NpgsqlCommand UpdateCommand
- {
- get { return _updateCommand; }
-
- set { _updateCommand = value; }
- }
-
- IDbCommand IDbDataAdapter.InsertCommand
- {
- get { return InsertCommand; }
-
- set { InsertCommand = (NpgsqlCommand) value; }
- }
-
-
- public new NpgsqlCommand InsertCommand
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "InsertCommand");
- return _insertCommand;
- }
-
- set { _insertCommand = value; }
- }
- }
+ /// <summary>
+ /// Represents the method that handles the <see cref="Npgsql.NpgsqlDataAdapter.RowUpdated">RowUpdated</see> events.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">A <see cref="Npgsql.NpgsqlRowUpdatedEventArgs">NpgsqlRowUpdatedEventArgs</see> that contains the event data.</param>
+ public delegate void NpgsqlRowUpdatedEventHandler(Object sender, NpgsqlRowUpdatedEventArgs e);
+
+ /// <summary>
+ /// Represents the method that handles the <see cref="Npgsql.NpgsqlDataAdapter.RowUpdating">RowUpdating</see> events.
+ /// </summary>
+ /// <param name="sender">The source of the event.</param>
+ /// <param name="e">A <see cref="Npgsql.NpgsqlRowUpdatingEventArgs">NpgsqlRowUpdatingEventArgs</see> that contains the event data.</param>
+ public delegate void NpgsqlRowUpdatingEventHandler(Object sender, NpgsqlRowUpdatingEventArgs e);
+
+
+ /// <summary>
+ /// This class represents an adapter from many commands: select, update, insert and delete to fill <see cref="System.Data.DataSet">Datasets.</see>
+ /// </summary>
+ public sealed class NpgsqlDataAdapter : DbDataAdapter, IDbDataAdapter
+ {
+
+ private NpgsqlCommand _selectCommand;
+ private NpgsqlCommand _updateCommand;
+ private NpgsqlCommand _deleteCommand;
+ private NpgsqlCommand _insertCommand;
+
+ // Log support
+ private static readonly String CLASSNAME = "NpgsqlDataAdapter";
+
+
+ public event NpgsqlRowUpdatedEventHandler RowUpdated;
+ public event NpgsqlRowUpdatingEventHandler RowUpdating;
+
+ public NpgsqlDataAdapter()
+ {}
+
+ public NpgsqlDataAdapter(NpgsqlCommand selectCommand)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+ _selectCommand = selectCommand;
+ }
+
+ public NpgsqlDataAdapter(String selectCommandText, NpgsqlConnection selectConnection) : this(new NpgsqlCommand(selectCommandText, selectConnection))
+ {}
+
+ public NpgsqlDataAdapter(String selectCommandText, String selectConnectionString) : this(selectCommandText, new NpgsqlConnection(selectConnectionString))
+ {}
+
+
+ protected override RowUpdatedEventArgs CreateRowUpdatedEvent(
+ DataRow dataRow,
+ IDbCommand command,
+ StatementType statementType,
+ DataTableMapping tableMapping
+ )
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateRowUpdatedEvent");
+ return new NpgsqlRowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
+
+
+
+ }
+
+ protected override RowUpdatingEventArgs CreateRowUpdatingEvent(
+ DataRow dataRow,
+ IDbCommand command,
+ StatementType statementType,
+ DataTableMapping tableMapping
+ )
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CreateRowUpdatingEvent");
+ return new NpgsqlRowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
+ }
+
+ protected override void OnRowUpdated(
+ RowUpdatedEventArgs value
+ )
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "OnRowUpdated");
+ //base.OnRowUpdated(value);
+ if ((RowUpdated != null) && (value is NpgsqlRowUpdatedEventArgs))
+ RowUpdated(this, (NpgsqlRowUpdatedEventArgs) value);
+
+ }
+
+ protected override void OnRowUpdating(
+ RowUpdatingEventArgs value
+ )
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "OnRowUpdating");
+ if ((RowUpdating != null) && (value is NpgsqlRowUpdatingEventArgs))
+ RowUpdating(this, (NpgsqlRowUpdatingEventArgs) value);
+ }
+
+ ITableMappingCollection IDataAdapter.TableMappings
+ {
+ get
+ {
+ return TableMappings;
+ }
+ }
+
+ IDbCommand IDbDataAdapter.DeleteCommand
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IDbDataAdapter.DeleteCommand");
+ return (NpgsqlCommand) DeleteCommand;
+ }
+
+ set
+ {
+ DeleteCommand = (NpgsqlCommand) value;
+ }
+ }
+
+
+ public NpgsqlCommand DeleteCommand
+ {
+ get
+ {
+ return _deleteCommand;
+ }
+
+ set
+ {
+ _deleteCommand = value;
+ }
+ }
+
+ IDbCommand IDbDataAdapter.SelectCommand
+ {
+ get
+ {
+ return (NpgsqlCommand) SelectCommand;
+ }
+
+ set
+ {
+ SelectCommand = (NpgsqlCommand) value;
+ }
+ }
+
+
+ public NpgsqlCommand SelectCommand
+ {
+ get
+ {
+ return _selectCommand;
+ }
+
+ set
+ {
+ _selectCommand = value;
+ }
+ }
+
+ IDbCommand IDbDataAdapter.UpdateCommand
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IDbDataAdapter.UpdateCommand");
+ return (NpgsqlCommand) UpdateCommand;
+ }
+
+ set
+ {
+ UpdateCommand = (NpgsqlCommand) value;
+ }
+ }
+
+
+ public NpgsqlCommand UpdateCommand
+ {
+ get
+ {
+ return _updateCommand;
+ }
+
+ set
+ {
+ _updateCommand = value;
+ }
+ }
+
+ IDbCommand IDbDataAdapter.InsertCommand
+ {
+ get
+ {
+ return (NpgsqlCommand) InsertCommand;
+ }
+
+ set
+ {
+ InsertCommand = (NpgsqlCommand) value;
+ }
+ }
+
+
+ public NpgsqlCommand InsertCommand
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "InsertCommand");
+ return _insertCommand;
+ }
+
+ set
+ {
+ _insertCommand = value;
+ }
+ }
+
+
+ }
}
+
public class NpgsqlRowUpdatingEventArgs : RowUpdatingEventArgs
{
- public NpgsqlRowUpdatingEventArgs(DataRow dataRow, IDbCommand command, StatementType statementType,
- DataTableMapping tableMapping)
- : base(dataRow, command, statementType, tableMapping)
+ public NpgsqlRowUpdatingEventArgs (
+ DataRow dataRow,
+ IDbCommand command,
+ StatementType statementType,
+ DataTableMapping tableMapping
+ ) : base(dataRow, command, statementType, tableMapping)
+
+ {}
- {
- }
}
public class NpgsqlRowUpdatedEventArgs : RowUpdatedEventArgs
{
- public NpgsqlRowUpdatedEventArgs(DataRow dataRow, IDbCommand command, StatementType statementType,
- DataTableMapping tableMapping)
- : base(dataRow, command, statementType, tableMapping)
+ public NpgsqlRowUpdatedEventArgs (
+ DataRow dataRow,
+ IDbCommand command,
+ StatementType statementType,
+ DataTableMapping tableMapping
+ ) : base(dataRow, command, statementType, tableMapping)
+
+ {}
- {
- }
-} \ No newline at end of file
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs b/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs
index b15c8b62253..6244c36e493 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlDataReader.cs
@@ -1,3 +1,4 @@
+
// Npgsql.NpgsqlDataReader.cs
//
// Author:
@@ -8,686 +9,965 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Collections;
-using System.Collections.Generic;
using System.Data;
-using System.Data.Common;
+using System.Collections;
using System.Text;
-using System.Threading;
+
using NpgsqlTypes;
namespace Npgsql
{
- /// <summary>
- /// Provides a means of reading a forward-only stream of rows from a PostgreSQL backend. This class cannot be inherited.
- /// </summary>
- public abstract class NpgsqlDataReader : DbDataReader
- {
- //NpgsqlDataReader is abstract because the desired implementation depends upon whether the user
- //is using the backwards-compatibility option of preloading the entire reader (configurable from the
- //connection string).
- //Everything that can be done here is, but where the implementation must be different between the
- //two modi operandi, that code will differ between the two implementations, ForwardsOnlyDataReader
- //and CachingDataReader.
- //Since the concrete classes are internal and returned to the user through an NpgsqlDataReader reference,
- //the differences between the two is hidden from the user. Because CachingDataReader is a less efficient
- //class supplied only to resolve some backwards-compatibility issues that are possible with some code, all
- //internal use uses ForwardsOnlyDataReader directly.
- internal NpgsqlConnector _connector;
- internal NpgsqlConnection _connection;
- internal DataTable _currentResultsetSchema;
- internal CommandBehavior _behavior;
- internal NpgsqlCommand _command;
-
- internal NpgsqlDataReader(NpgsqlCommand command, CommandBehavior behavior)
- {
- _behavior = behavior;
- _connection = (_command = command).Connection;
- _connector = command.Connector;
- }
+ /// <summary>
+ /// Provides a means of reading a forward-only stream of rows from a PostgreSQL backend. This class cannot be inherited.
+ /// </summary>
+ public sealed class NpgsqlDataReader : IDataReader, IEnumerable
+ {
+ private NpgsqlConnection _connection;
+ private ArrayList _resultsets;
+ private ArrayList _responses;
+ private Int32 _rowIndex;
+ private Int32 _resultsetIndex;
+ private Int32 _recordsAffected;
+ private NpgsqlResultSet _currentResultset;
+ private DataTable _currentResultsetSchema;
+ private CommandBehavior _behavior;
+ private Boolean _isClosed;
+ private NpgsqlCommand _command;
+
+
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlDataReader";
+
+ internal NpgsqlDataReader( ArrayList resultsets, ArrayList responses, CommandBehavior behavior, NpgsqlCommand command)
+ {
+ _resultsets = resultsets;
+ _responses = responses;
+ _connection = command.Connection;
+ _rowIndex = -1;
+ _resultsetIndex = -1;
+ _recordsAffected = -1;
+
+ // positioned before the first results.
+ // move to the first results
+ NextResult();
+
+ _behavior = behavior;
+ _isClosed = false;
+ _command = command;
+ }
+
+ private Boolean HaveResultSet()
+ {
+ return (_currentResultset != null);
+ }
+
+ private Boolean HaveRow()
+ {
+ return (HaveResultSet() && _rowIndex >= 0 && _rowIndex < _currentResultset.Count);
+ }
+
+ private void CheckHaveResultSet()
+ {
+ if (! HaveResultSet())
+ {
+ throw new InvalidOperationException("Cannot read data. No result set.");
+ }
+ }
- internal bool _isClosed = false;
+ private void CheckHaveRow()
+ {
+ CheckHaveResultSet();
- /// <summary>
- /// Is raised whenever Close() is called.
- /// </summary>
- public event EventHandler ReaderClosed;
+ if (_rowIndex < 0)
+ {
+ throw new InvalidOperationException("DataReader positioned before beginning of result set. Did you call Read()?");
+ }
+ else if (_rowIndex >= _currentResultset.Count)
+ {
+ throw new InvalidOperationException("DataReader positioned beyond end of result set.");
+ }
+ }
+
+
+ /// <summary>
+ /// Releases the resources used by the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ /// <summary>
+ /// Releases the resources used by the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
+ /// </summary>
+ protected void Dispose (bool disposing)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
+ if (disposing)
+ {
+ this.Close();
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating the depth of nesting for the current row. Always returns zero.
+ /// </summary>
+ public Int32 Depth
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Depth");
+ return 0;
+ }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the data reader is closed.
+ /// </summary>
+ public Boolean IsClosed
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsClosed");
+ return _isClosed;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement.
+ /// </summary>
+ public Int32 RecordsAffected
+ {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "RecordsAffected");
+ return _recordsAffected;
+ }
+ }
- internal abstract long? LastInsertedOID { get; }
+ /// <summary>
+ /// Indicates if NpgsqlDatareader has rows to be read.
+ /// </summary>
- private bool TryGetTypeInfo(int fieldIndex, out NpgsqlBackendTypeInfo backendTypeInfo)
- {
- if (CurrentDescription == null)
- {
- throw new IndexOutOfRangeException(); //Essentially, all indices are out of range.
- }
- return (backendTypeInfo = CurrentDescription[fieldIndex].TypeInfo) != null;
- }
+ public Boolean HasRows
+ {
+ get
+ {
+ return (HaveResultSet() ? _currentResultset.Count > 0 : false);
+ }
- internal abstract void CheckHaveRow();
- internal abstract NpgsqlRowDescription CurrentDescription { get; }
+ }
- /// <summary>
- /// Return the data type name of the column at index <param name="Index"></param>.
- /// </summary>
- public override String GetDataTypeName(Int32 Index)
- {
- NpgsqlBackendTypeInfo TI;
- return TryGetTypeInfo(Index, out TI) ? TI.Name : GetDataTypeOID(Index);
- }
+ /// <summary>
+ /// Closes the data reader object.
+ /// </summary>
+ public void Close()
+ {
+ if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
+ {
+ _connection.Close();
+ }
- /// <summary>
- /// Return the data type of the column at index <param name="Index"></param>.
- /// </summary>
- public override Type GetFieldType(Int32 Index)
- {
- NpgsqlBackendTypeInfo TI;
- return TryGetTypeInfo(Index, out TI) ? TI.Type : typeof (string); //Default type is string.
- }
+ _isClosed = true;
+ if (this.ReaderClosed != null)
+ this.ReaderClosed(this, EventArgs.Empty);
+ }
+
+ /// <summary>
+ /// Is raised whenever Close() is called.
+ /// </summary>
+ public event EventHandler ReaderClosed;
+
+ /// <summary>
+ /// Advances the data reader to the next result, when multiple result sets were returned by the PostgreSQL backend.
+ /// </summary>
+ /// <returns>True if the reader was advanced, otherwise false.</returns>
+ public Boolean NextResult()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "NextResult");
+
+ _currentResultset = null;
+ while((_resultsetIndex + 1) < _resultsets.Count && !HaveResultSet())
+ {
+ _resultsetIndex++;
+ _rowIndex = -1;
+ _currentResultset = (NpgsqlResultSet)_resultsets[_resultsetIndex];
+
+ if (!HaveResultSet())
+ {
+ String[] _returnStringTokens = ((String)_responses[_resultsetIndex]).Split(null); // whitespace separator.
+ int responseAffectedRows = 0;
+
+ try
+ {
+ responseAffectedRows = Int32.Parse(_returnStringTokens[_returnStringTokens.Length - 1]);
+ }
+ catch (FormatException)
+ {
+ responseAffectedRows = -1;
+ }
+
+ if (responseAffectedRows != -1)
+ {
+ if (_recordsAffected == -1)
+ {
+ _recordsAffected = responseAffectedRows;
+ }
+ else
+ {
+ _recordsAffected += responseAffectedRows;
+ }
+ }
+ }
+ }
+ return HaveResultSet();
+
+ }
+
+ /// <summary>
+ /// Advances the data reader to the next row.
+ /// </summary>
+ /// <returns>True if the reader was advanced, otherwise false.</returns>
+ public Boolean Read()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Read");
+
+ if (!HaveResultSet())
+ return false;
+
+ if (_rowIndex < _currentResultset.Count)
+ {
+ _rowIndex++;
+ return (_rowIndex < _currentResultset.Count);
+ }
+ else
+ {
+ return false;
+ }
- /// <summary>
- /// Gets the number of columns in the current row.
- /// </summary>
- public override Int32 FieldCount
- {
- get { return CurrentDescription == null ? -1 : CurrentDescription.NumFields; }
- }
- /// <summary>
- /// Return the column name of the column at index <param name="Index"></param>.
- /// </summary>
- public override String GetName(Int32 Index)
- {
- if (CurrentDescription == null)
- {
- throw new IndexOutOfRangeException(); //Essentially, all indices are out of range.
- }
+ }
- return CurrentDescription[Index].Name;
- }
+ /// <summary>
+ /// Returns a System.Data.DataTable that describes the column metadata of the DataReader.
+ /// </summary>
+ public DataTable GetSchemaTable()
+ {
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetSchemaTable");
- /// <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)
- {
- if (CurrentDescription == null)
- {
- throw new IndexOutOfRangeException(); //Essentially, all indices are out of range.
- }
+ if(_currentResultsetSchema == null)
+ _currentResultsetSchema = GetResultsetSchema();
- return CurrentDescription[Index].TypeOID.ToString();
- }
+ return _currentResultsetSchema;
+ }
+ /// <summary>
+ /// Gets the number of columns in the current row.
+ /// </summary>
+ public Int32 FieldCount
+ {
+ get
+ {
- /// <summary>
- /// Gets the value of a column in its native format.
- /// </summary>
- public override Object this[Int32 i]
- {
- get { return GetValue(i); }
- }
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "FieldCount");
- /// <summary>
- /// Return the column name of the column named <param name="Name"></param>.
- /// </summary>
- public override Int32 GetOrdinal(String Name)
- {
- if (CurrentDescription == null)
- {
- throw new IndexOutOfRangeException(); //Essentially, all indices are out of range.
- }
- return CurrentDescription.FieldIndex(Name);
- }
+ if (! HaveResultSet()) //Executed a non return rows query.
+ return -1;
+ else
+ return _currentResultset.RowDescription.NumFields;
- /// <summary>
- /// Gets the value of a column in its native format.
- /// </summary>
- public override Object this[String name]
- {
- get
- {
- Int32 fieldIndex = CurrentDescription.FieldIndex(name);
- if (fieldIndex == -1)
- {
- throw new IndexOutOfRangeException("Field not found");
- }
- return GetValue(fieldIndex);
- }
- }
+ }
- /// <summary>
- /// Return the data DbType of the column at index <param name="Index"></param>.
- /// </summary>
- public DbType GetFieldDbType(Int32 Index)
- {
- NpgsqlBackendTypeInfo TI;
- return TryGetTypeInfo(Index, out TI) ? TI.DbType : DbType.String;
- }
+ }
- /// <summary>
- /// Return the data NpgsqlDbType of the column at index <param name="Index"></param>.
- /// </summary>
- public NpgsqlDbType GetFieldNpgsqlDbType(Int32 Index)
- {
- NpgsqlBackendTypeInfo TI;
- return TryGetTypeInfo(Index, out TI) ? TI.NpgsqlDbType : NpgsqlDbType.Text;
- }
+ /// <summary>
+ /// Return the column name of the column at index <param name="Index"></param>.
+ /// </summary>
+ public String GetName(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetName");
- /// <summary>
- /// Get the value of a column as a <see cref="NpgsqlInterval"/>.
- /// <remarks>If the differences between <see cref="NpgsqlInterval"/> and <see cref="System.Timespan"/>
- /// in handling of days and months is not important to your application, use <see cref="GetTimeSpan()"/>
- /// instead.</remarks>
- /// </summary>
- /// <param name="i">Index of the field to find.</param>
- /// <returns><see cref="NpgsqlInterval"/> value of the field.</returns>
- public NpgsqlInterval GetInterval(Int32 i)
- {
- return (NpgsqlInterval) GetValue(i);
- }
+ CheckHaveResultSet();
- public NpgsqlTime GetTime(int i)
- {
- return (NpgsqlTime) GetValue(i);
- }
+ return _currentResultset.RowDescription[Index].name;
+ }
- public NpgsqlTimeTZ GetTimeTZ(int i)
- {
- return (NpgsqlTimeTZ) GetValue(i);
- }
+ /// <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");
- public NpgsqlTimeStamp GetTimeStamp(int i)
- {
- return (NpgsqlTimeStamp) GetValue(i);
- }
+ CheckHaveResultSet();
- public NpgsqlTimeStampTZ GetTimeStampTZ(int i)
- {
- return (NpgsqlTimeStampTZ) GetValue(i);
- }
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
- public NpgsqlDate GetDate(int i)
- {
- return (NpgsqlDate) GetValue(i);
- }
+ return _currentResultset.RowDescription[Index].type_oid.ToString();
+ }
- protected void SendClosedEvent()
- {
- if (this.ReaderClosed != null)
- {
- this.ReaderClosed(this, EventArgs.Empty);
- }
- }
+ /// <summary>
+ /// Return the data type name of the column at index <param name="Index"></param>.
+ /// </summary>
+ public String GetDataTypeName(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDataTypeName");
- /// <summary>
- /// Gets the value of a column converted to a Guid.
- /// </summary>
- public override Guid GetGuid(Int32 i)
- {
- return (Guid) GetValue(i);
- }
+ CheckHaveResultSet();
- /// <summary>
- /// Gets the value of a column as Int16.
- /// </summary>
- public override Int16 GetInt16(Int32 i)
- {
- return (Int16) GetValue(i);
- }
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
- /// <summary>
- /// Gets the value of a column as Int32.
- /// </summary>
- public override Int32 GetInt32(Int32 i)
- {
- return (Int32) GetValue(i);
- }
+ if (TI == null)
+ {
+ return _currentResultset.RowDescription[Index].type_oid.ToString();
+ }
+ else
+ {
+ return TI.Name;
+ }
+ }
- /// <summary>
- /// Gets the value of a column as Int64.
- /// </summary>
- public override Int64 GetInt64(Int32 i)
- {
- return (Int64) GetValue(i);
- }
+ /// <summary>
+ /// Return the data type of the column at index <param name="Index"></param>.
+ /// </summary>
+ public Type GetFieldType(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFieldType");
- /// <summary>
- /// Gets the value of a column as Single.
- /// </summary>
- public override Single GetFloat(Int32 i)
- {
- return (Single) GetValue(i);
- }
+ CheckHaveResultSet();
- /// <summary>
- /// Gets the value of a column as Double.
- /// </summary>
- public override Double GetDouble(Int32 i)
- {
- return (Double) GetValue(i);
- }
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
- /// <summary>
- /// Gets the value of a column as String.
- /// </summary>
- public override String GetString(Int32 i)
- {
- return (String) GetValue(i);
- }
+ if (TI == null)
+ {
+ return typeof(String); //Default type is string.
+ }
+ else
+ {
+ return TI.Type;
+ }
+ }
- /// <summary>
- /// Gets the value of a column as Decimal.
- /// </summary>
- public override Decimal GetDecimal(Int32 i)
- {
- return (Decimal) GetValue(i);
- }
+ /// <summary>
+ /// Return the data DbType of the column at index <param name="Index"></param>.
+ /// </summary>
+ public DbType GetFieldDbType(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFieldType");
- /// <summary>
- /// Gets a value indicating the depth of nesting for the current row. Always returns zero.
- /// </summary>
- public override Int32 Depth
- {
- get { return 0; }
- }
+ CheckHaveResultSet();
- /// <summary>
- /// Gets a value indicating whether the data reader is closed.
- /// </summary>
- public override Boolean IsClosed
- {
- get { return _isClosed; }
- }
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
- /// <summary>
- /// Copy values from each column in the current row into <param name="Values"></param>.
- /// </summary>
- /// <returns>The number of column values copied.</returns>
- public override Int32 GetValues(Object[] Values)
- {
- CheckHaveRow();
+ if (TI == null)
+ {
+ return DbType.String;
+ }
+ else
+ {
+ //return TI.DBType;
+ return DbType.String;
+ }
+ }
- // Only the number of elements in the array are filled.
- // It's also possible to pass an array with more that FieldCount elements.
- Int32 maxColumnIndex = (Values.Length < FieldCount) ? Values.Length : FieldCount;
+ /// <summary>
+ /// Return the data NpgsqlDbType of the column at index <param name="Index"></param>.
+ /// </summary>
+ public NpgsqlDbType GetFieldNpgsqlDbType(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFieldType");
- for (Int32 i = 0; i < maxColumnIndex; i++)
- {
- Values[i] = GetValue(i);
- }
+ CheckHaveResultSet();
- return maxColumnIndex;
- }
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
- /// <summary>
- /// Gets the value of a column as Boolean.
- /// </summary>
- public override Boolean GetBoolean(Int32 i)
- {
- // Should this be done using the GetValue directly and not by converting to String
- // and parsing from there?
- return (Boolean) GetValue(i);
- }
+ if (TI == null)
+ {
+ return NpgsqlDbType.Text;
+ }
+ else
+ {
+ return TI.NpgsqlDbType;
- /// <summary>
- /// Gets the value of a column as Byte. Not implemented.
- /// </summary>
- public override Byte GetByte(Int32 i)
- {
- throw new NotImplementedException();
- }
+ }
+ }
- /// <summary>
- /// Gets the value of a column as Char.
- /// </summary>
- public override Char GetChar(Int32 i)
- {
- //This is an interesting one. In the world of databases we've the idea of chars which is 0 to n characters
- //where n is stated (and can perhaps be infinite) and various variations upon that (postgres is admirable
- //in being relatively consistent and in not generally encouraging limiting n purely for performance reasons,
- //but across many different platforms we'll find such things as text, ntext, char, nchar, varchar, nvarchar,
- //and so on with some platforms not having them all and many implementaiton differences).
- //
- //In the world of .NET, and many other languages, we have the idea of characters and of strings - which are
- //sequences of characters with differing degress of encapsulation from C just having char* through to .NET
- //having full-blown objects
- //
- //Database char, varchar, text, etc. are all generally mapped to strings. There's a bit of a question as to
- //what maps to a .NET char. Interestingly enough, SQLDataReader doesn't support GetChar() and neither do
- //a few other providers (Oracle for example). It would seem that IDataReader.GetChar() was defined largely
- //to have a complete set of .NET base types. Still, the closets thing in the database world to a char value
- //is a char(1) or varchar(1) - that is to say the value of a string of length one, so that's what is used here.
- string s = GetString(i);
- if (s.Length != 1)
- {
- throw new InvalidCastException();
- }
- return s[0];
- }
- /// <summary>
- /// Gets the value of a column as DateTime.
- /// </summary>
- public override DateTime GetDateTime(Int32 i)
- {
- return (DateTime) GetValue(i);
- }
+ /// <summary>
+ /// Return the value of the column at index <param name="Index"></param>.
+ /// </summary>
+ public Object GetValue(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValue");
- /// <summary>
- /// Returns a System.Data.DataTable that describes the column metadata of the DataReader.
- /// </summary>
- public override DataTable GetSchemaTable()
- {
- return _currentResultsetSchema = _currentResultsetSchema ?? GetResultsetSchema();
- }
+ if (Index < 0 || Index >= _currentResultset.RowDescription.NumFields)
+ {
+ throw new IndexOutOfRangeException("Column index out of range");
+ }
- private DataTable GetResultsetSchema()
- {
- DataTable result = null;
+ CheckHaveRow();
- if (CurrentDescription.NumFields > 0)
- {
- result = new DataTable("SchemaTable");
-
- result.Columns.Add("ColumnName", typeof (string));
- result.Columns.Add("ColumnOrdinal", typeof (int));
- result.Columns.Add("ColumnSize", typeof (int));
- result.Columns.Add("NumericPrecision", typeof (int));
- result.Columns.Add("NumericScale", typeof (int));
- result.Columns.Add("IsUnique", typeof (bool));
- result.Columns.Add("IsKey", typeof (bool));
- result.Columns.Add("BaseCatalogName", typeof (string));
- result.Columns.Add("BaseColumnName", typeof (string));
- result.Columns.Add("BaseSchemaName", typeof (string));
- result.Columns.Add("BaseTableName", typeof (string));
- result.Columns.Add("DataType", typeof (Type));
- result.Columns.Add("AllowDBNull", typeof (bool));
- result.Columns.Add("ProviderType", typeof (string));
- result.Columns.Add("IsAliased", typeof (bool));
- result.Columns.Add("IsExpression", typeof (bool));
- result.Columns.Add("IsIdentity", typeof (bool));
- result.Columns.Add("IsAutoIncrement", typeof (bool));
- result.Columns.Add("IsRowVersion", typeof (bool));
- result.Columns.Add("IsHidden", typeof (bool));
- result.Columns.Add("IsLong", typeof (bool));
- result.Columns.Add("IsReadOnly", typeof (bool));
-
- if (_connector.BackendProtocolVersion == ProtocolVersion.Version2)
- {
- FillSchemaTable_v2(result);
- }
- else if (_connector.BackendProtocolVersion == ProtocolVersion.Version3)
- {
- FillSchemaTable_v3(result);
- }
- }
+ return ((NpgsqlAsciiRow)_currentResultset[_rowIndex])[Index];
+ }
- return result;
- }
+ /// <summary>
+ /// Copy values from each column in the current row into <param name="Values"></param>.
+ /// </summary>
+ /// <returns>The number of column values copied.</returns>
+ public Int32 GetValues(Object[] Values)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValues");
- private void FillSchemaTable_v2(DataTable schema)
- {
- List<string> keyList = (_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo
- ? new List<string>(GetPrimaryKeys(GetTableNameFromQuery()))
- : new List<string>();
+ CheckHaveRow();
- for (Int16 i = 0; i < CurrentDescription.NumFields; i++)
- {
- DataRow row = schema.NewRow();
+ // Only the number of elements in the array are filled.
+ // It's also possible to pass an array with more that FieldCount elements.
+ Int32 maxColumnIndex = (Values.Length < FieldCount) ? Values.Length : FieldCount;
- row["ColumnName"] = GetName(i);
- row["ColumnOrdinal"] = i + 1;
- if (CurrentDescription[i].TypeModifier != -1 && CurrentDescription[i].TypeInfo != null &&
- (CurrentDescription[i].TypeInfo.Name == "varchar" || CurrentDescription[i].TypeInfo.Name == "bpchar"))
- {
- row["ColumnSize"] = CurrentDescription[i].TypeModifier - 4;
- }
- else if (CurrentDescription[i].TypeModifier != -1 && CurrentDescription[i].TypeInfo != null &&
- (CurrentDescription[i].TypeInfo.Name == "bit" || CurrentDescription[i].TypeInfo.Name == "varbit"))
- {
- row["ColumnSize"] = CurrentDescription[i].TypeModifier;
- }
- else
- {
- row["ColumnSize"] = (int) CurrentDescription[i].TypeSize;
- }
- if (CurrentDescription[i].TypeModifier != -1 && CurrentDescription[i].TypeInfo != null &&
- CurrentDescription[i].TypeInfo.Name == "numeric")
- {
- row["NumericPrecision"] = ((CurrentDescription[i].TypeModifier - 4) >> 16) & ushort.MaxValue;
- row["NumericScale"] = (CurrentDescription[i].TypeModifier - 4) & ushort.MaxValue;
- }
- else
- {
- row["NumericPrecision"] = 0;
- row["NumericScale"] = 0;
- }
- row["IsUnique"] = false;
- row["IsKey"] = IsKey(GetName(i), keyList);
- row["BaseCatalogName"] = "";
- row["BaseSchemaName"] = "";
- row["BaseTableName"] = "";
- row["BaseColumnName"] = GetName(i);
- row["DataType"] = GetFieldType(i);
- row["AllowDBNull"] = true;
- // without other information, must allow dbnull on the client
- if (CurrentDescription[i].TypeInfo != null)
- {
- row["ProviderType"] = CurrentDescription[i].TypeInfo.Name;
- }
- row["IsAliased"] = false;
- row["IsExpression"] = false;
- row["IsIdentity"] = false;
- row["IsAutoIncrement"] = false;
- row["IsRowVersion"] = false;
- row["IsHidden"] = false;
- row["IsLong"] = false;
- row["IsReadOnly"] = false;
-
- schema.Rows.Add(row);
+ for (Int32 i = 0; i < maxColumnIndex; i++)
+ {
+ Values[i] = GetValue(i);
+ }
+
+ return maxColumnIndex;
+
+ }
+
+ /// <summary>
+ /// Return the column name of the column named <param name="Name"></param>.
+ /// </summary>
+ public Int32 GetOrdinal(String Name)
+ {
+ CheckHaveResultSet();
+ return _currentResultset.RowDescription.FieldIndex(Name);
+ }
+
+ /// <summary>
+ /// Gets the value of a column in its native format.
+ /// </summary>
+ public Object this [ Int32 i ]
+ {
+ get
+ {
+ NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, i);
+ return GetValue(i);
+ }
+ }
+
+ /// <summary>
+ /// Gets the value of a column in its native format.
+ /// </summary>
+ public Object this [ String name ]
+ {
+ get
+ {
+ NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, name);
+ Int32 fieldIndex = _currentResultset.RowDescription.FieldIndex(name);
+ if (fieldIndex == -1)
+ throw new IndexOutOfRangeException("Field not found");
+ return GetValue(fieldIndex);
+ }
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Boolean.
+ /// </summary>
+ public Boolean GetBoolean(Int32 i)
+ {
+ // Should this be done using the GetValue directly and not by converting to String
+ // and parsing from there?
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBoolean");
+
+ return (Boolean) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Byte. Not implemented.
+ /// </summary>
+ public Byte GetByte(Int32 i)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Gets raw data from a column.
+ /// </summary>
+ public Int64 GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length)
+ {
+
+ Byte[] result;
+
+ result = (Byte[]) GetValue(i);
+
+ if (buffer == null)
+ return result.Length;
+
+
+ // We just support read all the field for while. So, any fieldOffset value other than 0 will not read
+ // anything and return 0.
+
+ if (fieldOffset != 0)
+ return 0;
+
+ // [TODO] Implement blob support.
+
+ result.CopyTo(buffer, 0);
+
+
+ return result.Length;
+
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Char. Not implemented.
+ /// </summary>
+ public Char GetChar(Int32 i)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Gets raw data from a column.
+ /// </summary>
+ public Int64 GetChars(Int32 i, Int64 fieldoffset, Char[] buffer, Int32 bufferoffset, Int32 length)
+ {
+ String str;
+
+ str = GetString(i);
+ if (buffer == null)
+ return str.Length;
+
+ str.ToCharArray(bufferoffset, length).CopyTo(buffer, 0);
+ return buffer.GetLength(0);
+ }
+
+ /// <summary>
+ /// Gets the value of a column converted to a Guid. Not implemented.
+ /// </summary>
+ public Guid GetGuid(Int32 i)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Int16.
+ /// </summary>
+ public Int16 GetInt16(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt16");
+
+ return (Int16) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Int32.
+ /// </summary>
+ public Int32 GetInt32(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt32");
+
+ return (Int32) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Int64.
+ /// </summary>
+ public Int64 GetInt64(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt64");
+
+ return (Int64) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Single.
+ /// </summary>
+ public Single GetFloat(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFloat");
+
+ return (Single) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Double.
+ /// </summary>
+ public Double GetDouble(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDouble");
+
+ return (Double) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as String.
+ /// </summary>
+ public String GetString(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetString");
+
+ return (String) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as Decimal.
+ /// </summary>
+ public Decimal GetDecimal(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDecimal");
+
+ return (Decimal) GetValue(i);
+ }
+
+ /// <summary>
+ /// Gets the value of a column as DateTime.
+ /// </summary>
+ public DateTime GetDateTime(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDateTime");
+
+ return (DateTime) GetValue(i);
+ }
+
+ /// <summary>
+ /// Not implemented.
+ /// </summary>
+ public IDataReader GetData(Int32 i)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Report whether the value in a column is DBNull.
+ /// </summary>
+ public Boolean IsDBNull(Int32 i)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IsDBNull");
+
+ return (GetValue(i) == DBNull.Value);
+ }
+
+ internal NpgsqlBackendTypeInfo GetTypeInfo(Int32 FieldIndex)
+ {
+ return _currentResultset.RowDescription[FieldIndex].type_info;
+ }
+
+ private DataTable GetResultsetSchema()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetResultsetSchema");
+ DataTable result = null;
+
+ NpgsqlRowDescription rd = _currentResultset.RowDescription;
+
+ Int16 numFields = rd.NumFields;
+ if(numFields > 0)
+ {
+ result = new DataTable("SchemaTable");
+
+ result.Columns.Add ("ColumnName", typeof (string));
+ result.Columns.Add ("ColumnOrdinal", typeof (int));
+ result.Columns.Add ("ColumnSize", typeof (int));
+ result.Columns.Add ("NumericPrecision", typeof (int));
+ result.Columns.Add ("NumericScale", typeof (int));
+ result.Columns.Add ("IsUnique", typeof (bool));
+ result.Columns.Add ("IsKey", typeof (bool));
+ result.Columns.Add ("BaseCatalogName", typeof (string));
+ result.Columns.Add ("BaseColumnName", typeof (string));
+ result.Columns.Add ("BaseSchemaName", typeof (string));
+ result.Columns.Add ("BaseTableName", typeof (string));
+ result.Columns.Add ("DataType", typeof(Type));
+ result.Columns.Add ("AllowDBNull", typeof (bool));
+ result.Columns.Add ("ProviderType", typeof (string));
+ result.Columns.Add ("IsAliased", typeof (bool));
+ result.Columns.Add ("IsExpression", typeof (bool));
+ result.Columns.Add ("IsIdentity", typeof (bool));
+ result.Columns.Add ("IsAutoIncrement", typeof (bool));
+ result.Columns.Add ("IsRowVersion", typeof (bool));
+ result.Columns.Add ("IsHidden", typeof (bool));
+ result.Columns.Add ("IsLong", typeof (bool));
+ result.Columns.Add ("IsReadOnly", typeof (bool));
+
+ if (_connection.Connector.BackendProtocolVersion == ProtocolVersion.Version2)
+ {
+ FillSchemaTable_v2(result);
+ }
+ else if (_connection.Connector.BackendProtocolVersion == ProtocolVersion.Version3)
+ {
+ FillSchemaTable_v3(result);
+ }
+ }
+
+ return result;
+
+ }
+
+ private void FillSchemaTable_v2(DataTable schema)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "FillSchemaTable_v2");
+ NpgsqlRowDescription rd = _currentResultset.RowDescription;
+ ArrayList keyList = null;
+
+ if ((_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo)
+ {
+ keyList = GetPrimaryKeys(GetTableNameFromQuery());
}
- }
- private void FillSchemaTable_v3(DataTable schema)
- {
- Dictionary<long, Table> oidTableLookup = new Dictionary<long, Table>();
+ DataRow row;
+
+ for (Int16 i = 0; i < rd.NumFields; i++)
+ {
+ row = schema.NewRow();
+
+ row["ColumnName"] = GetName(i);
+ row["ColumnOrdinal"] = i + 1;
+ if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "varchar" || rd[i].type_info.Name == "bpchar"))
+ row["ColumnSize"] = rd[i].type_modifier - 4;
+ else if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "bit" || rd[i].type_info.Name == "varbit"))
+ row["ColumnSize"] = rd[i].type_modifier;
+ else
+ row["ColumnSize"] = (int) rd[i].type_size;
+ if (rd[i].type_modifier != -1 && rd[i].type_info != null && rd[i].type_info.Name == "numeric")
+ {
+ row["NumericPrecision"] = ((rd[i].type_modifier-4)>>16)&ushort.MaxValue;
+ row["NumericScale"] = (rd[i].type_modifier-4)&ushort.MaxValue;
+ }
+ else
+ {
+ row["NumericPrecision"] = 0;
+ row["NumericScale"] = 0;
+ }
+ row["IsUnique"] = false;
+ row["IsKey"] = IsKey(GetName(i), keyList);
+ row["BaseCatalogName"] = "";
+ row["BaseSchemaName"] = "";
+ row["BaseTableName"] = "";
+ row["BaseColumnName"] = GetName(i);
+ row["DataType"] = GetFieldType(i);
+ row["AllowDBNull"] = IsNullable(null, i);
+ if (rd[i].type_info != null)
+ {
+ row["ProviderType"] = rd[i].type_info.Name;
+ }
+ row["IsAliased"] = false;
+ row["IsExpression"] = false;
+ row["IsIdentity"] = false;
+ row["IsAutoIncrement"] = false;
+ row["IsRowVersion"] = false;
+ row["IsHidden"] = false;
+ row["IsLong"] = false;
+ row["IsReadOnly"] = false;
+
+ schema.Rows.Add(row);
+ }
+ }
+
+ private void FillSchemaTable_v3(DataTable schema)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "FillSchemaTable_v3");
+ NpgsqlRowDescription rd = _currentResultset.RowDescription;
+
+ Hashtable oidTableLookup = null;
KeyLookup keyLookup = new KeyLookup();
- // needs to be null because there is a difference
- // between an empty dictionary and not setting it
- // the default values will be different
- Dictionary<string, Column> columnLookup = null;
+ Hashtable columnLookup = null;
if ((_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo)
{
- List<int> tableOids = new List<int>();
- for (int i = 0; i != CurrentDescription.NumFields; ++i)
+ ArrayList tableOids = new ArrayList();
+ for(short i=0; i<rd.NumFields; ++i)
{
- if (CurrentDescription[i].TableOID != 0 && !tableOids.Contains(CurrentDescription[i].TableOID))
- {
- tableOids.Add(CurrentDescription[i].TableOID);
- }
+ if (rd[i].table_oid != 0 && !tableOids.Contains(rd[i].table_oid))
+ tableOids.Add(rd[i].table_oid);
}
oidTableLookup = GetTablesFromOids(tableOids);
- if (oidTableLookup.Count == 1)
+ if (oidTableLookup != null && oidTableLookup.Count == 1)
{
- // only 1, but we can't index into the Dictionary
- foreach (int key in oidTableLookup.Keys)
+ // only 1, but we can't index into the Hashtable
+ foreach(DictionaryEntry entry in oidTableLookup)
{
- keyLookup = GetKeys(key);
+ keyLookup = GetKeys((Int32)entry.Key);
}
}
columnLookup = GetColumns();
}
- for (Int16 i = 0; i < CurrentDescription.NumFields; i++)
- {
- DataRow row = schema.NewRow();
+ 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 (CurrentDescription[i].TypeModifier != -1 && CurrentDescription[i].TypeInfo != null &&
- (CurrentDescription[i].TypeInfo.Name == "varchar" || CurrentDescription[i].TypeInfo.Name == "bpchar"))
- {
- row["ColumnSize"] = CurrentDescription[i].TypeModifier - 4;
- }
- else if (CurrentDescription[i].TypeModifier != -1 && CurrentDescription[i].TypeInfo != null &&
- (CurrentDescription[i].TypeInfo.Name == "bit" || CurrentDescription[i].TypeInfo.Name == "varbit"))
- {
- row["ColumnSize"] = CurrentDescription[i].TypeModifier;
- }
- else
- {
- row["ColumnSize"] = (int) CurrentDescription[i].TypeSize;
- }
- if (CurrentDescription[i].TypeModifier != -1 && CurrentDescription[i].TypeInfo != null &&
- CurrentDescription[i].TypeInfo.Name == "numeric")
- {
- row["NumericPrecision"] = ((CurrentDescription[i].TypeModifier - 4) >> 16) & ushort.MaxValue;
- row["NumericScale"] = (CurrentDescription[i].TypeModifier - 4) & ushort.MaxValue;
- }
- else
- {
- row["NumericPrecision"] = 0;
- row["NumericScale"] = 0;
- }
- row["IsUnique"] = IsUnique(keyLookup, baseColumnName);
- row["IsKey"] = IsKey(keyLookup, baseColumnName);
- if (CurrentDescription[i].TableOID != 0 && oidTableLookup.ContainsKey(CurrentDescription[i].TableOID))
- {
- row["BaseCatalogName"] = oidTableLookup[CurrentDescription[i].TableOID].Catalog;
- row["BaseSchemaName"] = oidTableLookup[CurrentDescription[i].TableOID].Schema;
- row["BaseTableName"] = oidTableLookup[CurrentDescription[i].TableOID].Name;
- }
- else
- {
- row["BaseCatalogName"] = row["BaseSchemaName"] = row["BaseTableName"] = "";
- }
- row["BaseColumnName"] = baseColumnName;
- row["DataType"] = GetFieldType(i);
- row["AllowDBNull"] = IsNullable(columnLookup, i);
- if (CurrentDescription[i].TypeInfo != null)
- {
- row["ProviderType"] = CurrentDescription[i].TypeInfo.Name;
- }
- row["IsAliased"] = string.CompareOrdinal((string) row["ColumnName"], baseColumnName) != 0;
- row["IsExpression"] = false;
- row["IsIdentity"] = false;
- row["IsAutoIncrement"] = IsAutoIncrement(columnLookup, i);
- row["IsRowVersion"] = false;
- row["IsHidden"] = false;
- row["IsLong"] = false;
- row["IsReadOnly"] = false;
-
- schema.Rows.Add(row);
- }
- }
+ row["ColumnName"] = GetName(i);
+ row["ColumnOrdinal"] = i + 1;
+ if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "varchar" || rd[i].type_info.Name == "bpchar"))
+ row["ColumnSize"] = rd[i].type_modifier - 4;
+ else if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "bit" || rd[i].type_info.Name == "varbit"))
+ row["ColumnSize"] = rd[i].type_modifier;
+ else
+ row["ColumnSize"] = (int) rd[i].type_size;
+ if (rd[i].type_modifier != -1 && rd[i].type_info != null && rd[i].type_info.Name == "numeric")
+ {
+ row["NumericPrecision"] = ((rd[i].type_modifier-4)>>16)&ushort.MaxValue;
+ row["NumericScale"] = (rd[i].type_modifier-4)&ushort.MaxValue;
+ }
+ else
+ {
+ row["NumericPrecision"] = 0;
+ row["NumericScale"] = 0;
+ }
+ 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"] = ((object[])oidTableLookup[rd[i].table_oid])[Tables.table_schema];
+ row["BaseTableName"] = ((object[])oidTableLookup[rd[i].table_oid])[Tables.table_name];
+ }
+ else
+ {
+ row["BaseCatalogName"] = "";
+ row["BaseSchemaName"] = "";
+ row["BaseTableName"] = "";
+ }
+ row["BaseColumnName"] = baseColumnName;
+ row["DataType"] = GetFieldType(i);
+ row["AllowDBNull"] = IsNullable(columnLookup, i);
+ if (rd[i].type_info != null)
+ {
+ row["ProviderType"] = rd[i].type_info.Name;
+ }
+ row["IsAliased"] = string.CompareOrdinal((string)row["ColumnName"], baseColumnName) != 0;
+ row["IsExpression"] = false;
+ row["IsIdentity"] = false;
+ row["IsAutoIncrement"] = IsAutoIncrement(columnLookup, i);
+ row["IsRowVersion"] = false;
+ row["IsHidden"] = false;
+ row["IsLong"] = false;
+ row["IsReadOnly"] = false;
+
+ schema.Rows.Add(row);
+ }
+ }
- private static Boolean IsKey(String ColumnName, IEnumerable<string> ListOfKeys)
- {
- foreach (String s in ListOfKeys)
- {
- if (s == ColumnName)
- {
- return true;
- }
- }
+ private Boolean IsKey(String ColumnName, ArrayList ListOfKeys)
+ {
+ if (ListOfKeys == null || ListOfKeys.Count == 0)
+ return false;
- return false;
- }
+ foreach(String s in ListOfKeys)
+ {
- private IEnumerable<string> GetPrimaryKeys(String tablename)
- {
- if (string.IsNullOrEmpty(tablename))
- {
- yield break;
- }
+ if (s == ColumnName)
+ return true;
+ }
- String getPKColumns =
- "select a.attname 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.indisprimary AND ct.relname = :tablename";
+ return false;
+ }
- using (NpgsqlConnection metadataConn = _connection.Clone())
- {
- using (NpgsqlCommand c = new NpgsqlCommand(getPKColumns, metadataConn))
- {
- c.Parameters.Add(new NpgsqlParameter("tablename", NpgsqlDbType.Text));
- c.Parameters["tablename"].Value = tablename;
+ private ArrayList GetPrimaryKeys(String tablename)
+ {
+ if (tablename == String.Empty)
+ return null;
- using (NpgsqlDataReader dr = c.GetReader(CommandBehavior.SingleResult | CommandBehavior.SequentialAccess))
- {
- while (dr.Read())
- {
- yield return dr.GetString(0);
- }
- }
- }
- }
- }
+ String getPKColumns = "select a.attname 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.indisprimary AND ct.relname = :tablename";
+
+ ArrayList result = new ArrayList();
+ NpgsqlConnection metadataConn = _connection.Clone();
+ NpgsqlCommand c = new NpgsqlCommand(getPKColumns, metadataConn);
+ c.Parameters.Add(new NpgsqlParameter("tablename", NpgsqlDbType.Text));
+ c.Parameters["tablename"].Value = tablename;
- private static bool IsKey(KeyLookup keyLookup, string fieldName)
+ NpgsqlDataReader dr = c.ExecuteReader();
+
+
+ while (dr.Read())
+ result.Add(dr[0]);
+
+
+ metadataConn.Close();
+
+ return result;
+ }
+
+ private bool IsKey(KeyLookup keyLookup, string fieldName)
{
- return keyLookup.primaryKey.Contains(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 static bool IsUnique(KeyLookup keyLookup, string fieldName)
+ private bool IsUnique(KeyLookup keyLookup, string fieldName)
{
- return keyLookup.uniqueColumns.Contains(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 class KeyLookup
+ private struct KeyLookup
{
/// <summary>
/// Contains the column names as the keys
/// </summary>
- public readonly List<string> primaryKey = new List<string>();
-
+ public ArrayList primaryKey;
/// <summary>
/// Contains all unique columns
/// </summary>
- public readonly List<string> uniqueColumns = new List<string>();
+ 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";
+
+ 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.GetReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
+ using (NpgsqlDataReader dr = c.ExecuteReader())
{
string previousKeyName = null;
string possiblyUniqueColumn = null;
@@ -699,6 +979,7 @@ namespace Npgsql
// 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
@@ -724,895 +1005,176 @@ namespace Npgsql
// 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(Dictionary<string, Column> columnLookup, Int32 FieldIndex)
- {
- if (columnLookup == null || CurrentDescription[FieldIndex].TableOID == 0)
- {
- return true;
- }
- string lookupKey = string.Format("{0},{1}", CurrentDescription[FieldIndex].TableOID, CurrentDescription[FieldIndex].ColumnAttributeNumber);
- Column col = null;
- return columnLookup.TryGetValue(lookupKey, out col) ? !col.NotNull : true;
+ return lookup;
}
- private string GetBaseColumnName(Dictionary<string, Column> columnLookup, Int32 FieldIndex)
- {
- if (columnLookup == null || CurrentDescription[FieldIndex].TableOID == 0)
- {
- return GetName(FieldIndex);
- }
+ private Boolean IsNullable(Hashtable columnLookup, Int32 FieldIndex)
+ {
+ if (columnLookup == null || _currentResultset.RowDescription[FieldIndex].table_oid == 0)
+ return true;
- string lookupKey = string.Format("{0},{1}", CurrentDescription[FieldIndex].TableOID, CurrentDescription[FieldIndex].ColumnAttributeNumber);
- Column col = null;
- return columnLookup.TryGetValue(lookupKey, out col) ? col.Name : GetName(FieldIndex);
- }
+ string lookupKey = _currentResultset.RowDescription[FieldIndex].table_oid.ToString() + "," + _currentResultset.RowDescription[FieldIndex].column_attribute_number;
+ object[] row = (object[])columnLookup[lookupKey];
+ if (row != null)
+ return !(bool)row[Columns.column_notnull];
+ else
+ return true;
+ }
+
+ private string GetBaseColumnName(Hashtable columnLookup, Int32 FieldIndex)
+ {
+ if (columnLookup == null || _currentResultset.RowDescription[FieldIndex].table_oid == 0)
+ return GetName(FieldIndex);
+
+ string lookupKey = _currentResultset.RowDescription[FieldIndex].table_oid.ToString() + "," + _currentResultset.RowDescription[FieldIndex].column_attribute_number;
+ object[] row = (object[])columnLookup[lookupKey];
+ if (row != null)
+ return (string)row[Columns.column_name];
+ else
+ return GetName(FieldIndex);
+ }
- private bool IsAutoIncrement(Dictionary<string, Column> columnLookup, Int32 FieldIndex)
+ private bool IsAutoIncrement(Hashtable columnLookup, Int32 FieldIndex)
{
- if (columnLookup == null || CurrentDescription[FieldIndex].TableOID == 0)
- {
+ if (columnLookup == null || _currentResultset.RowDescription[FieldIndex].table_oid == 0)
return false;
- }
- string lookupKey = string.Format("{0},{1}", CurrentDescription[FieldIndex].TableOID, CurrentDescription[FieldIndex].ColumnAttributeNumber);
- Column col = null;
- return
- columnLookup.TryGetValue(lookupKey, out col)
- ? col.ColumnDefault is string && col.ColumnDefault.ToString().StartsWith("nextval(")
- : true;
+ 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
- /// from it.
- ///</summary>
- private String GetTableNameFromQuery()
- {
- Int32 fromClauseIndex = _command.CommandText.ToLowerInvariant().IndexOf("from");
+ ///<summary>
+ /// This methods parses the command text and tries to get the tablename
+ /// from it.
+ ///</summary>
+ private String GetTableNameFromQuery()
+ {
+ Int32 fromClauseIndex = _command.CommandText.ToLower().IndexOf("from");
- String tableName = _command.CommandText.Substring(fromClauseIndex + 4).Trim();
+ String tableName = _command.CommandText.Substring(fromClauseIndex + 4).Trim();
- if (string.IsNullOrEmpty(tableName))// == String.Empty)
- {
- return String.Empty;
- }
+ if (tableName == String.Empty)
+ return String.Empty;
- /*if (tableName.EndsWith("."));
+ /*if (tableName.EndsWith("."));
return String.Empty;
*/
- foreach (Char c in tableName.Substring(0, tableName.Length - 1))
- {
- if (!Char.IsLetterOrDigit(c) && c != '_' && c != '.')
- {
- return String.Empty;
- }
- }
-
-
- return tableName;
- }
-
- private struct Table
- {
- public readonly string Catalog;
- public readonly string Schema;
- public readonly string Name;
- public readonly long Id;
-
- public Table(IDataReader rdr)
- {
- Catalog = rdr.GetString(0);
- Schema = rdr.GetString(1);
- Name = rdr.GetString(2);
- Id = rdr.GetInt64(3);
- }
- }
-
- private Dictionary<long, Table> GetTablesFromOids(List<int> oids)
- {
- if (oids.Count == 0)
- {
- return new Dictionary<long, Table>(); //Empty collection is simpler than requiring tests for null;
- }
-
- // the column index is used to find data.
- // any changes to the order of the columns needs to be reflected in struct Tables
- StringBuilder sb =
- new StringBuilder(
- "SELECT current_database(), nc.nspname, c.relname, c.oid FROM pg_namespace nc, pg_class c WHERE c.relnamespace = nc.oid AND (c.relkind = 'r' OR c.relkind = 'v') AND c.oid IN (");
- bool first = true;
- foreach (int oid in oids)
- {
- if (!first)
- {
- sb.Append(',');
- }
- sb.Append(oid);
- first = false;
- }
- sb.Append(')');
-
- using (NpgsqlConnection connection = _connection.Clone())
- {
- using (NpgsqlCommand command = new NpgsqlCommand(sb.ToString(), connection))
- {
- using (NpgsqlDataReader reader = command.GetReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)
- )
- {
- Dictionary<long, Table> oidLookup = new Dictionary<long, Table>(oids.Count);
- int columnCount = reader.FieldCount;
- while (reader.Read())
- {
- Table t = new Table(reader);
- oidLookup.Add(t.Id, t);
- }
- return oidLookup;
- }
- }
- }
- }
-
- private class Column
- {
- public readonly string Name;
- public readonly bool NotNull;
- public readonly long TableId;
- public readonly short ColumnNum;
- public readonly object ColumnDefault;
-
- public string Key
- {
- get { return string.Format("{0},{1}", TableId, ColumnNum); }
- }
-
- public Column(IDataReader rdr)
- {
- Name = rdr.GetString(0);
- NotNull = rdr.GetBoolean(1);
- TableId = rdr.GetInt64(2);
- ColumnNum = rdr.GetInt16(3);
- ColumnDefault = rdr.GetValue(4);
- }
- }
-
- private Dictionary<string, Column> GetColumns()
- {
- StringBuilder sb = new StringBuilder();
-
- // 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, 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 < CurrentDescription.NumFields; ++i)
- {
- if (CurrentDescription[i].TableOID != 0)
- {
- if (!first)
- {
- sb.Append(" OR ");
- }
- sb.AppendFormat("(a.attrelid={0} AND a.attnum={1})", CurrentDescription[i].TableOID,
- CurrentDescription[i].ColumnAttributeNumber);
- first = false;
- }
- }
- sb.Append(')');
-
- // if the loop ended without setting first to false, then there will be no results from the query
- if (first)
- {
- return null;
- }
-
- using (NpgsqlConnection connection = _connection.Clone())
- {
- using (NpgsqlCommand command = new NpgsqlCommand(sb.ToString(), connection))
- {
- using (NpgsqlDataReader reader = command.GetReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)
- )
- {
- Dictionary<string, Column> columnLookup = new Dictionary<string, Column>();
- while (reader.Read())
- {
- Column column = new Column(reader);
- columnLookup.Add(column.Key, column);
- }
- return columnLookup;
- }
- }
- }
- }
-
- public override IEnumerator GetEnumerator()
- {
- return new DbEnumerator(this);
- }
- }
-
- /// <summary>
- /// This is the primary implementation of NpgsqlDataReader. It is the one used in normal cases (where the
- /// preload-reader option is not set in the connection string to resolve some potential backwards-compatibility
- /// issues), the only implementation used internally, and in cases where CachingDataReader is used, it is still
- /// used to do the actual "leg-work" of turning a response stream from the server into a datareader-style
- /// object - with CachingDataReader then filling it's cache from here.
- /// </summary>
- internal class ForwardsOnlyDataReader : NpgsqlDataReader, IStreamOwner
- {
- private readonly IEnumerator<IServerResponseObject> _dataEnumerator;
- private NpgsqlRowDescription _currentDescription;
- private NpgsqlRow _currentRow = null;
- private int? _recordsAffected = null;
- private int? _nextRecordsAffected;
- private long? _lastInsertOID = null;
- private long? _nextInsertOID = null;
- internal bool _cleanedUp = false;
- private readonly NpgsqlConnector.NotificationThreadBlock _threadBlock;
- private readonly bool _synchOnReadError; //maybe this should always be done?
-
- //Unfortunately we sometimes don't know we're going to be dealing with
- //a description until it comes when we look for a row or a message, and
- //we may also need test if we may have rows for HasRows before the first call
- //to Read(), so we need to be able to cache one of each.
- private NpgsqlRowDescription _pendingDescription = null;
- private NpgsqlRow _pendingRow = null;
-
- // Logging related values
- private static readonly String CLASSNAME = "ForwardsOnlyDataReader";
-
- internal ForwardsOnlyDataReader(IEnumerable<IServerResponseObject> dataEnumeration, CommandBehavior behavior,
- NpgsqlCommand command, NpgsqlConnector.NotificationThreadBlock threadBlock,
- bool synchOnReadError)
- : base(command, behavior)
- {
- _dataEnumerator = dataEnumeration.GetEnumerator();
- _connector.CurrentReader = this;
- _threadBlock = threadBlock;
- _synchOnReadError = synchOnReadError;
- //DataReaders always start prepared to read from the first Resultset (if any).
- NextResult();
- UpdateOutputParameters();
- }
-
- internal override NpgsqlRowDescription CurrentDescription
- {
- get { return _currentDescription; }
- }
-
- private void UpdateOutputParameters()
- {
- if (CurrentDescription != null)
- {
- NpgsqlRow row = null;
- Queue<NpgsqlParameter> pending = new Queue<NpgsqlParameter>();
- List<int> taken = new List<int>();
- foreach (NpgsqlParameter p in _command.Parameters)
- {
- if (p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Output)
- {
- int idx = CurrentDescription.FieldIndex(p.CleanName);
- if (idx == -1)
- {
- pending.Enqueue(p);
- }
- else
- {
- if ((row = row ?? ParameterUpdateRow) == null)
- {
- return;
- }
- p.Value = row[idx];
- taken.Add(idx);
- }
- }
- }
- for (int i = 0; pending.Count != 0 && i != (row = row ?? ParameterUpdateRow).NumFields; ++i)
- {
- if (!taken.Contains(i))
- {
- pending.Dequeue().Value = row[i];
- }
- }
- }
- }
-
- // We always receive a ForwardsOnlyRow, but if we are not
- // doing SequentialAccess we want the flexibility of CachingRow,
- // so here we either return the ForwardsOnlyRow we received, or
- // build a CachingRow from it, as appropriate.
- private NpgsqlRow BuildRow(ForwardsOnlyRow fo)
- {
- if (fo == null)
- {
- return null;
- }
- else if ((_behavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess)
- {
- return fo;
- }
- else
- {
- return new CachingRow(fo);
- }
- }
-
- private NpgsqlRow ParameterUpdateRow
- {
- get
- {
- NpgsqlRow ret = CurrentRow ?? _pendingRow ?? GetNextRow(false);
- if (ret is ForwardsOnlyRow)
- {
- ret = _pendingRow = new CachingRow((ForwardsOnlyRow) ret);
- }
- return ret;
- }
- }
-
- /// <summary>
- /// Iterate through the objects returned through from the server.
- /// If it's a CompletedResponse the rowsaffected count is updated appropriately,
- /// and we iterate again, otherwise we return it (perhaps updating our cache of pending
- /// rows if appropriate).
- /// </summary>
- /// <returns>The next <see cref="IServerResponseObject"/> we will deal with.</returns>
- private IServerResponseObject GetNextResponseObject()
- {
- try
- {
- CurrentRow = null;
- if (_pendingRow != null)
- {
- _pendingRow.Dispose();
- }
- _pendingRow = null;
- while (_dataEnumerator.MoveNext())
- {
- IServerResponseObject respNext = _dataEnumerator.Current;
- if (respNext is CompletedResponse)
- {
- CompletedResponse cr = respNext as CompletedResponse;
- if (cr.RowsAffected.HasValue)
- {
- _nextRecordsAffected = (_nextRecordsAffected ?? 0) + cr.RowsAffected.Value;
- }
- _nextInsertOID = cr.LastInsertedOID ?? _nextInsertOID;
- }
- else if (respNext is ForwardsOnlyRow)
- {
- return _pendingRow = BuildRow((ForwardsOnlyRow) respNext);
- }
- else
- {
- return respNext;
- }
- }
- CleanUp(true);
- return null;
- }
- catch
- {
- CleanUp(true);
- if (_synchOnReadError) //Should we always do this?
- {
- // As per documentation:
- // "[...] When an error is detected while processing any extended-query message,
- // the backend issues ErrorResponse, then reads and discards messages until a
- // Sync is reached, then issues ReadyForQuery and returns to normal message processing.[...]"
- // So, send a sync command if we get any problems.
-
- _connector.Sync();
- }
- throw;
- }
- }
-
- /// <summary>
- /// Advances the data reader to the next result, when multiple result sets were returned by the PostgreSQL backend.
- /// </summary>
- /// <returns>True if the reader was advanced, otherwise false.</returns>
- private NpgsqlRowDescription GetNextRowDescription()
- {
- if ((_behavior & CommandBehavior.SingleResult) != 0 && CurrentDescription != null)
- {
- CleanUp(false);
- return null;
- }
- NpgsqlRowDescription rd = _pendingDescription;
- while (rd == null)
- {
- object objNext = GetNextResponseObject();
- if (objNext == null)
- {
- break;
- }
- if (objNext is NpgsqlRow)
- {
- (objNext as NpgsqlRow).Dispose();
- }
-
- rd = objNext as NpgsqlRowDescription;
- }
-
- _pendingDescription = null;
- _recordsAffected = _nextRecordsAffected;
- _nextRecordsAffected = null;
- _lastInsertOID = _nextInsertOID;
- _nextInsertOID = null;
- return rd;
- }
-
- private NpgsqlRow CurrentRow
- {
- get { return _currentRow; }
- set
- {
- if (_currentRow != null)
- {
- _currentRow.Dispose();
- }
- _currentRow = value;
- }
- }
-
- private NpgsqlRow GetNextRow(bool clearPending)
- {
- if (_pendingDescription != null)
- {
- return null;
- }
- if (((_behavior & CommandBehavior.SingleRow) != 0 && CurrentRow != null && _pendingDescription == null) ||
- ((_behavior & CommandBehavior.SchemaOnly) != 0))
- {
- if (!clearPending)
- {
- return null;
- }
- //We should only have one row, and we've already had it. Move to end
- //of recordset.
- CurrentRow = null;
- for (object skip = GetNextResponseObject();
- skip != null && (_pendingDescription = skip as NpgsqlRowDescription) == null;
- skip = GetNextResponseObject())
- {
- if (skip is NpgsqlRow)
- {
- (skip as NpgsqlRow).Dispose();
- }
- }
-
- return null;
- }
- if (_pendingRow != null)
- {
- NpgsqlRow ret = _pendingRow;
- if (clearPending)
- {
- _pendingRow = null;
- }
- return ret;
- }
- CurrentRow = null;
- object objNext = GetNextResponseObject();
- if (clearPending)
- {
- _pendingRow = null;
- }
- if (objNext is NpgsqlRowDescription)
- {
- _pendingDescription = objNext as NpgsqlRowDescription;
- return null;
- }
- return objNext as NpgsqlRow;
- }
+ foreach (Char c in tableName.Substring (0, tableName.Length - 1))
+ if (!Char.IsLetterOrDigit (c) && c != '_' && c != '.')
+ return String.Empty;
- internal override void CheckHaveRow()
- {
- if (CurrentRow == null)
- {
- throw new InvalidOperationException("Invalid attempt to read when no data is present.");
- }
- }
- /// <summary>
- /// Releases the resources used by the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
- /// </summary>
- protected override void Dispose(bool disposing)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
- base.Dispose(disposing);
- }
+ return tableName;
+ }
- /// <summary>
- /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement.
- /// </summary>
- public override Int32 RecordsAffected
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "RecordsAffected");
- return _recordsAffected ?? -1;
- }
- }
+ private struct Tables
+ {
+ public const int table_catalog = 0;
+ public const int table_schema = 1;
+ public const int table_name = 2;
+ public const int table_id = 3;
+ }
- internal override long? LastInsertedOID
- {
- get { return _lastInsertOID; }
- }
+ private Hashtable GetTablesFromOids(ArrayList oids)
+ {
+ if (oids.Count == 0)
+ return null;
- /// <summary>
- /// Indicates if NpgsqlDatareader has rows to be read.
- /// </summary>
- public override Boolean HasRows
- {
- get { return GetNextRow(false) != null; }
- }
+ StringBuilder sb = new StringBuilder();
- private void CleanUp(bool finishedMessages)
- {
- lock (this)
- {
- if (_cleanedUp)
- {
- return;
- }
- _cleanedUp = true;
- }
- if (!finishedMessages)
- {
- do
- {
- if ((Thread.CurrentThread.ThreadState & (ThreadState.Aborted | ThreadState.AbortRequested)) != 0)
- {
- _connection.EmergencyClose();
- return;
- }
- }
- while (GetNextResponseObject() != null);
- }
- _connector.CurrentReader = null;
- _threadBlock.Dispose();
- }
-
- /// <summary>
- /// Closes the data reader object.
- /// </summary>
- public override void Close()
- {
- CleanUp(false);
- if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
- {
- _connection.Close();
- }
- _isClosed = true;
- SendClosedEvent();
- }
-
- /// <summary>
- /// Advances the data reader to the next result, when multiple result sets were returned by the PostgreSQL backend.
- /// </summary>
- /// <returns>True if the reader was advanced, otherwise false.</returns>
- public override Boolean NextResult()
- {
- try
- {
- CurrentRow = null;
- _currentResultsetSchema = null;
- return (_currentDescription = GetNextRowDescription()) != null;
- }
- catch (System.IO.IOException ex)
+ // the column index is used to find data.
+ // any changes to the order of the columns needs to be reflected in struct Tables
+ sb.Append("SELECT current_database() AS table_catalog, nc.nspname AS table_schema, c.relname AS table_name, c.oid as table_id");
+ sb.Append(" FROM pg_namespace nc, pg_class c WHERE c.relnamespace = nc.oid AND (c.relkind = 'r' OR c.relkind = 'v') AND c.oid IN (");
+ bool first = true;
+ foreach(int oid in oids)
{
- throw _command.ClearPoolAndCreateException(ex);
+ if (!first)
+ sb.Append(',');
+ sb.Append(oid);
+ first = false;
}
- }
+ sb.Append(')');
- /// <summary>
- /// Advances the data reader to the next row.
- /// </summary>
- /// <returns>True if the reader was advanced, otherwise false.</returns>
- public override Boolean Read()
- {
- try
+ using (NpgsqlConnection connection = _connection.Clone())
+ using (NpgsqlCommand command = new NpgsqlCommand(sb.ToString(), connection))
+ using (NpgsqlDataReader reader = command.ExecuteReader())
{
- //CurrentRow = null;
- return (CurrentRow = GetNextRow(true)) != null;
+ Hashtable oidLookup = new Hashtable();
+ int columnCount = reader.FieldCount;
+ while (reader.Read())
+ {
+ object[] values = new object[columnCount];
+ reader.GetValues(values);
+ oidLookup[Convert.ToInt32(reader[Tables.table_id])] = values;
+ }
+ return oidLookup;
}
- catch (System.IO.IOException ex)
+ }
+
+ private struct Columns
+ {
+ public const int column_name = 0;
+ 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()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ // 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, 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)
{
- throw _command.ClearPoolAndCreateException(ex);
+ if (_currentResultset.RowDescription[i].table_oid != 0)
+ {
+ if (!first)
+ sb.Append(" OR ");
+ sb.AppendFormat("(a.attrelid={0} AND a.attnum={1})", _currentResultset.RowDescription[i].table_oid, _currentResultset.RowDescription[i].column_attribute_number);
+ first = false;
+ }
}
- }
-
- /// <summary>
- /// Return the value of the column at index <param name="Index"></param>.
- /// </summary>
- public override Object GetValue(Int32 Index)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValue");
-
- if (Index < 0 || Index >= CurrentDescription.NumFields)
- {
- throw new IndexOutOfRangeException("Column index out of range");
- }
-
- CheckHaveRow();
-
- object ret = CurrentRow[Index];
- if (ret is Exception)
- {
- throw (Exception) ret;
- }
- return ret;
- }
-
- /// <summary>
- /// Gets raw data from a column.
- /// </summary>
- public override Int64 GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length)
- {
- return CurrentRow.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
- }
-
-
- /// <summary>
- /// Gets raw data from a column.
- /// </summary>
- public override Int64 GetChars(Int32 i, Int64 fieldoffset, Char[] buffer, Int32 bufferoffset, Int32 length)
- {
- return CurrentRow.GetChars(i, fieldoffset, buffer, bufferoffset, length);
- }
-
-
- /// <summary>
- /// Report whether the value in a column is DBNull.
- /// </summary>
- public override Boolean IsDBNull(Int32 i)
- {
- CheckHaveRow();
-
- return CurrentRow.IsDBNull(i);
- }
- }
-
- /// <summary>
- /// <para>Provides an implementation of NpgsqlDataReader in which all data is pre-loaded into memory.
- /// This operates by first creating a ForwardsOnlyDataReader as usual, and then loading all of it's
- /// Rows into memory. There is a general principle that when there is a trade-off between a class design that
- /// is more efficient and/or scalable on the one hand and one that is less efficient but has more functionality
- /// (in this case the internal-only functionality of caching results) that one can build the less efficent class
- /// from the most efficient without significant extra loss in efficiency, but not the other way around. The relationship
- /// between ForwardsOnlyDataReader and CachingDataReader is an example of this).</para>
- /// <para>Since the interface presented to the user is still forwards-only, queues are used to
- /// store this information, so that dequeueing as we go we give the garbage collector the best opportunity
- /// possible to reclaim any memory that is no longer in use.</para>
- /// <para>ForwardsOnlyDataReader being used to actually
- /// obtain the information from the server means that the "leg-work" is still only done (and need only be
- /// maintained) in one place.</para>
- /// <para>This class exists to allow for certain potential backwards-compatibility issues to be resolved
- /// with little effort on the part of affected users. It is considerably less efficient than ForwardsOnlyDataReader
- /// and hence never used internally.</para>
- /// </summary>
- internal class CachingDataReader : NpgsqlDataReader
- {
- private class DataRow : List<object>
- {
- }
-
- private class ResultSet : Queue<DataRow>
- {
- private readonly int _recordsAffected;
- private readonly long? _lastInsertedOID;
- private readonly NpgsqlRowDescription _description;
-
- public ResultSet(NpgsqlRowDescription description, int recordsAffected, long? lastInsertedOID)
- {
- _description = description;
- _recordsAffected = recordsAffected;
- _lastInsertedOID = lastInsertedOID;
- }
-
- public NpgsqlRowDescription Description
- {
- get { return _description; }
- }
-
- public int RecordsAffected
- {
- get { return _recordsAffected; }
- }
-
- public long? LastInsertedOID
- {
- get { return _lastInsertedOID; }
- }
- }
-
- private readonly Queue<ResultSet> _results = new Queue<ResultSet>();
- private ResultSet _currentResult;
- private DataRow _currentRow;
- private int _lastRecordsAffected;
-
- public CachingDataReader(ForwardsOnlyDataReader reader, CommandBehavior behavior)
- : base(reader._command, behavior)
- {
- do
- {
- ResultSet rs = new ResultSet(reader.CurrentDescription, reader.RecordsAffected, reader.LastInsertedOID);
- while (reader.Read())
- {
- DataRow dr = new DataRow();
- for (int i = 0; i != reader.FieldCount; ++i)
- {
- dr.Add(reader.GetValue(i));
- }
- rs.Enqueue(dr);
- }
- _results.Enqueue(rs);
- }
- while (reader.NextResult());
- reader.Dispose();
- NextResult();
- UpdateOutputParameters();
- }
-
- private void UpdateOutputParameters()
- {
- if (CurrentDescription != null && _currentResult != null && _currentResult.Count != 0)
- {
- DataRow row = _currentResult.Peek();
- Queue<NpgsqlParameter> pending = new Queue<NpgsqlParameter>();
- List<int> taken = new List<int>();
- foreach (NpgsqlParameter p in _command.Parameters)
- {
- if (p.Direction == ParameterDirection.InputOutput || p.Direction == ParameterDirection.Output)
- {
- int idx = CurrentDescription.FieldIndex(p.CleanName);
- if (idx == -1)
- {
- pending.Enqueue(p);
- }
- else
- {
- p.Value = row[idx];
- taken.Add(idx);
- }
- }
- }
- for (int i = 0; pending.Count != 0 && i != CurrentDescription.NumFields; ++i)
- {
- if (!taken.Contains(i))
- {
- pending.Dequeue().Value = row[i];
- }
- }
- }
- }
-
- internal override long? LastInsertedOID
- {
- get { return _currentResult.LastInsertedOID; }
- }
-
- internal override NpgsqlRowDescription CurrentDescription
- {
- get { return _currentResult.Description; }
- }
-
- public override bool HasRows
- {
- get
- {
- if (_currentRow != null || _currentResult.Count != 0)
- {
- return true;
- }
- foreach (ResultSet rs in _results)
- {
- if (rs.Count != 0)
- {
- return true;
- }
- }
- return false;
- }
- }
-
- public override int RecordsAffected
- {
- get { return _lastRecordsAffected; }
- }
-
- internal override void CheckHaveRow()
- {
- if (_currentRow == null)
- {
- throw new InvalidOperationException("Invalid attempt to read when no data is present.");
- }
- }
-
- public override void Close()
- {
- if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
- {
- _connection.Close();
- }
- _isClosed = true;
- SendClosedEvent();
- }
-
- public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
- {
- byte[] source = (byte[]) this[i];
- if (buffer == null)
- {
- return source.Length - fieldOffset;
- }
- long finalLength = Math.Max(0, Math.Min(length, source.Length - fieldOffset));
- Array.Copy(source, fieldOffset, buffer, bufferoffset, finalLength);
- return finalLength;
- }
-
- public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
- {
- string source = (string) this[i];
- if (buffer == null)
- {
- return source.Length - fieldoffset;
- }
- long finalLength = Math.Max(0, Math.Min(length, source.Length - fieldoffset));
- Array.Copy(source.ToCharArray(), fieldoffset, buffer, bufferoffset, finalLength);
- return finalLength;
- }
-
- public override Object GetValue(Int32 ordinal)
- {
- CheckHaveRow();
- if (ordinal < 0 || ordinal >= CurrentDescription.NumFields)
- {
- throw new IndexOutOfRangeException();
- }
- return _currentRow[ordinal];
- }
+ sb.Append(')');
- public override bool IsDBNull(int ordinal)
- {
- CheckHaveRow();
- return GetValue(ordinal) == DBNull.Value;
- }
+ // if the loop ended without setting first to false, then there will be no results from the query
+ if (first)
+ return null;
- public override bool NextResult()
- {
- if (_results.Count == 0)
- {
- _currentResult = null;
- return false;
- }
- _lastRecordsAffected = (_currentResult = _results.Dequeue()).RecordsAffected;
- return true;
- }
-
- public override bool Read()
- {
- if (_currentResult.Count == 0)
- {
- _currentRow = null;
- return false;
- }
- _currentRow = _currentResult.Dequeue();
- return true;
- }
- }
-} \ No newline at end of file
+ using (NpgsqlConnection connection = _connection.Clone())
+ using (NpgsqlCommand command = new NpgsqlCommand(sb.ToString(), connection))
+ using (NpgsqlDataReader reader = command.ExecuteReader())
+ {
+ Hashtable columnLookup = new Hashtable();
+ int columnCount = reader.FieldCount;
+ while(reader.Read())
+ {
+ object[] values = new object[columnCount];
+ reader.GetValues(values);
+ columnLookup[reader[Columns.table_id].ToString() + "," + reader[Columns.column_num].ToString()] = values;
+ }
+ return columnLookup;
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return new System.Data.Common.DbEnumerator (this);
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlDescribe.cs b/mcs/class/Npgsql/Npgsql/NpgsqlDescribe.cs
index 68dc168846e..9642b1b285e 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlDescribe.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlDescribe.cs
@@ -9,52 +9,61 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Text;
namespace Npgsql
{
- /// <summary>
- /// This class represents the Parse message sent to PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlDescribe : ClientMessage
- {
- private readonly Char _whatToDescribe;
- private readonly String _portalName;
-
- public NpgsqlDescribe(Char whatToDescribe, String portalName)
- {
- _whatToDescribe = whatToDescribe;
- _portalName = portalName;
- }
-
- public override void WriteToStream(Stream outputStream)
- {
- outputStream.WriteByte((byte) FrontEndMessageCode.Describe);
-
- PGUtil.WriteInt32(outputStream, 4 + 1 + UTF8Encoding.GetByteCount(_portalName) + 1);
-
- outputStream.WriteByte((Byte) _whatToDescribe);
- PGUtil.WriteString(_portalName, outputStream);
- }
- }
-} \ No newline at end of file
+
+ /// <summary>
+ /// This class represents the Parse message sent to PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlDescribe
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlDescribe";
+
+ private Char _whatToDescribe;
+ private String _portalName;
+
+ public NpgsqlDescribe(Char whatToDescribe, String portalName)
+ {
+ _whatToDescribe = whatToDescribe;
+ _portalName = portalName;
+
+ }
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+ outputStream.WriteByte((Byte)'D');
+
+ PGUtil.WriteInt32(outputStream, 4 +
+ 1 +
+ encoding.GetByteCount(_portalName) + 1);
+
+ outputStream.WriteByte((Byte)_whatToDescribe);
+ PGUtil.WriteString(_portalName, outputStream, encoding);
+
+
+ }
+
+ }
+}
+
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlError.cs b/mcs/class/Npgsql/Npgsql/NpgsqlError.cs
index 3b4c426345f..d9149c2ece3 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlError.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlError.cs
@@ -9,22 +9,19 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
@@ -32,281 +29,332 @@ using System.Text;
namespace Npgsql
{
- /// <summary>
- /// EventArgs class to send Notice parameters, which are just NpgsqlError's in a lighter context.
- /// </summary>
- public class NpgsqlNoticeEventArgs : EventArgs
- {
- /// <summary>
- /// Notice information.
- /// </summary>
- public NpgsqlError Notice = null;
-
- internal NpgsqlNoticeEventArgs(NpgsqlError eNotice)
- {
- Notice = eNotice;
- }
- }
-
- /// <summary>
- /// This class represents the ErrorResponse and NoticeResponse
- /// message sent from PostgreSQL server.
- /// </summary>
- [Serializable]
- public sealed class NpgsqlError
- {
- private readonly ProtocolVersion protocol_version;
- private readonly String _severity = String.Empty;
- private readonly String _code = String.Empty;
- private readonly String _message = String.Empty;
- private readonly String _detail = String.Empty;
- private readonly String _hint = String.Empty;
- private readonly String _position = String.Empty;
- private readonly String _internalPosition = String.Empty;
- private readonly String _internalQuery = String.Empty;
- private readonly String _where = String.Empty;
- private readonly String _file = String.Empty;
- private readonly String _line = String.Empty;
- private readonly String _routine = String.Empty;
- private String _errorSql = String.Empty;
-
- /// <summary>
- /// Severity code. All versions.
- /// </summary>
- public String Severity
- {
- get { return _severity; }
- }
-
- /// <summary>
- /// Error code. PostgreSQL 7.4 and up.
- /// </summary>
- public String Code
- {
- get { return _code; }
- }
-
- /// <summary>
- /// Terse error message. All versions.
- /// </summary>
- public String Message
- {
- get { return _message; }
- }
-
- /// <summary>
- /// Detailed error message. PostgreSQL 7.4 and up.
- /// </summary>
- public String Detail
- {
- get { return _detail; }
- }
-
- /// <summary>
- /// Suggestion to help resolve the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String Hint
- {
- get { return _hint; }
- }
-
- /// <summary>
- /// Position (one based) within the query string where the error was encounterd. PostgreSQL 7.4 and up.
- /// </summary>
- public String Position
- {
- get { return _position; }
- }
-
- /// <summary>
- /// Position (one based) within the query string where the error was encounterd. This position refers to an internal command executed for example inside a PL/pgSQL function. PostgreSQL 7.4 and up.
- /// </summary>
- public String InternalPosition
- {
- get { return _internalPosition; }
- }
-
- /// <summary>
- /// Internal query string where the error was encounterd. This position refers to an internal command executed for example inside a PL/pgSQL function. PostgreSQL 7.4 and up.
- /// </summary>
- public String InternalQuery
- {
- get { return _internalQuery; }
- }
- /// <summary>
- /// Trace back information. PostgreSQL 7.4 and up.
- /// </summary>
- public String Where
- {
- get { return _where; }
- }
-
- /// <summary>
- /// Source file (in backend) reporting the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String File
- {
- get { return _file; }
- }
-
- /// <summary>
- /// Source file line number (in backend) reporting the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String Line
- {
- get { return _line; }
- }
-
- /// <summary>
- /// Source routine (in backend) reporting the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String Routine
- {
- get { 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>
- public override String ToString()
- {
- StringBuilder B = new StringBuilder();
-
- if (Severity.Length > 0)
- {
- B.AppendFormat("{0}: ", Severity);
- }
- if (Code.Length > 0)
- {
- B.AppendFormat("{0}: ", Code);
- }
- B.AppendFormat("{0}", Message);
- // CHECKME - possibly multi-line, that is yucky
- // if (Hint.Length > 0) {
- // B.AppendFormat(" ({0})", Hint);
- // }
-
- return B.ToString();
- }
-
- internal NpgsqlError(ProtocolVersion protocolVersion, Stream stream)
- {
- switch (protocol_version = protocolVersion)
- {
- case ProtocolVersion.Version2:
- string[] parts = PGUtil.ReadString(stream).Split(new char[] {':'}, 2);
- if (parts.Length == 2)
- {
- _severity = parts[0].Trim();
- _message = parts[1].Trim();
- }
- else
- {
- _severity = string.Empty;
- _message = parts[0].Trim();
- }
- break;
- case ProtocolVersion.Version3:
- // Check the messageLength value. If it is 1178686529, this would be the
- // "FATA" string, which would mean a protocol 2.0 error string.
- if (PGUtil.ReadInt32(stream) == 1178686529)
- {
- string[] v2Parts = ("FATA" + PGUtil.ReadString(stream)).Split(new char[] {':'}, 2);
- if (v2Parts.Length == 2)
- {
- _severity = v2Parts[0].Trim();
- _message = v2Parts[1].Trim();
- }
- else
- {
- _severity = string.Empty;
- _message = v2Parts[0].Trim();
- }
- protocol_version = ProtocolVersion.Version2;
- }
- else
- {
- for (char field = (char) stream.ReadByte(); field != 0; field = (char) stream.ReadByte())
- {
- switch (field)
- {
- case 'S':
- _severity = PGUtil.ReadString(stream);
- ;
- break;
- case 'C':
- _code = PGUtil.ReadString(stream);
- ;
- break;
- case 'M':
- _message = PGUtil.ReadString(stream);
- ;
- break;
- case 'D':
- _detail = PGUtil.ReadString(stream);
- ;
- break;
- case 'H':
- _hint = PGUtil.ReadString(stream);
- ;
- break;
- case 'P':
- _position = PGUtil.ReadString(stream);
- ;
- break;
- case 'p':
- _internalPosition = PGUtil.ReadString(stream);
- ;
- break;
- case 'q':
- _internalQuery = PGUtil.ReadString(stream);
- ;
- break;
- case 'W':
- _where = PGUtil.ReadString(stream);
- ;
- break;
- case 'F':
- _file = PGUtil.ReadString(stream);
- ;
- break;
- case 'L':
- _line = PGUtil.ReadString(stream);
- ;
- break;
- case 'R':
- _routine = PGUtil.ReadString(stream);
- ;
- break;
-
- }
- }
- }
- break;
- }
- }
-
- internal NpgsqlError(ProtocolVersion protocolVersion, String errorMessage)
- {
- protocol_version = protocolVersion;
- _message = errorMessage;
- }
-
- /// <summary>
- /// Backend protocol version in use.
- /// </summary>
- internal ProtocolVersion BackendProtocolVersion
- {
- get { return protocol_version; }
- }
- }
+ /// <summary>
+ /// EventArgs class to send Notice parameters, which are just NpgsqlError's in a lighter context.
+ /// </summary>
+ public class NpgsqlNoticeEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Notice information.
+ /// </summary>
+ public NpgsqlError Notice = null;
+
+ internal NpgsqlNoticeEventArgs(NpgsqlError eNotice)
+ {
+ Notice = eNotice;
+ }
+ }
+
+ /// <summary>
+ /// This class represents the ErrorResponse and NoticeResponse
+ /// message sent from PostgreSQL server.
+ /// </summary>
+ [Serializable]
+ public sealed class NpgsqlError
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlError";
+
+ private ProtocolVersion protocol_version;
+ 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.
+ /// </summary>
+ public String Severity
+ {
+ get
+ {
+ return _severity;
+ }
+ }
+
+ /// <summary>
+ /// Error code. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Code
+ {
+ get
+ {
+ return _code;
+ }
+ }
+
+ /// <summary>
+ /// Terse error message. All versions.
+ /// </summary>
+ public String Message
+ {
+ get
+ {
+ return _message;
+ }
+ }
+
+ /// <summary>
+ /// Detailed error message. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Detail
+ {
+ get
+ {
+ return _detail;
+ }
+ }
+
+ /// <summary>
+ /// Suggestion to help resolve the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Hint
+ {
+ get
+ {
+ return _hint;
+ }
+ }
+
+ /// <summary>
+ /// Position (one based) within the query string where the error was encounterd. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Position
+ {
+ get
+ {
+ return _position;
+ }
+ }
+
+ /// <summary>
+ /// Trace back information. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Where
+ {
+ get
+ {
+ return _where;
+ }
+ }
+
+ /// <summary>
+ /// Source file (in backend) reporting the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String File
+ {
+ get
+ {
+ return _file;
+ }
+ }
+
+ /// <summary>
+ /// Source file line number (in backend) reporting the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Line
+ {
+ get
+ {
+ return _line;
+ }
+ }
+
+ /// <summary>
+ /// Source routine (in backend) reporting the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Routine
+ {
+ get
+ {
+ 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>
+ public override String ToString()
+ {
+ StringBuilder B = new StringBuilder();
+
+ if (Severity.Length > 0)
+ {
+ B.AppendFormat("{0}: ", Severity);
+ }
+ if (Code.Length > 0)
+ {
+ B.AppendFormat("{0}: ", Code);
+ }
+ B.AppendFormat("{0}", Message);
+ // CHECKME - possibly multi-line, that is yucky
+ // if (Hint.Length > 0) {
+ // B.AppendFormat(" ({0})", Hint);
+ // }
+
+ return B.ToString();
+ }
+
+ internal NpgsqlError(ProtocolVersion protocolVersion)
+ {
+ protocol_version = protocolVersion;
+ }
+
+ internal NpgsqlError(ProtocolVersion protocolVersion, String errorMessage)
+ {
+ protocol_version = protocolVersion;
+ _message = errorMessage;
+ }
+
+ /// <summary>
+ /// Backend protocol version in use.
+ /// </summary>
+ internal ProtocolVersion BackendProtocolVersion
+ {
+ get
+ {
+ return protocol_version;
+ }
+ }
+
+ internal void ReadFromStream(Stream inputStream, Encoding encoding)
+ {
+ switch (protocol_version) {
+ case ProtocolVersion.Version2 :
+ ReadFromStream_Ver_2(inputStream, encoding);
+ break;
+
+ case ProtocolVersion.Version3 :
+ ReadFromStream_Ver_3(inputStream, encoding);
+ break;
+
+ }
+ }
+
+ private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
+
+ String Raw;
+ String[] Parts;
+
+ Raw = PGUtil.ReadString(inputStream, encoding);
+
+ Parts = Raw.Split(new char[] {':'}, 2);
+
+ if (Parts.Length == 2)
+ {
+ _severity = Parts[0].Trim();
+ _message = Parts[1].Trim();
+ }
+ else
+ {
+ _message = Parts[0].Trim();
+ }
+ }
+
+ private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
+
+ Int32 messageLength = PGUtil.ReadInt32(inputStream, new Byte[4]);
+
+ // [TODO] Would this be the right way to do?
+ // Check the messageLength value. If it is 1178686529, this would be the
+ // "FATA" string, which would mean a protocol 2.0 error string.
+ if (messageLength == 1178686529)
+ {
+ String Raw;
+ String[] Parts;
+
+ Raw = "FATA" + PGUtil.ReadString(inputStream, encoding);
+
+ Parts = Raw.Split(new char[] {':'}, 2);
+
+ if (Parts.Length == 2)
+ {
+ _severity = Parts[0].Trim();
+ _message = Parts[1].Trim();
+ }
+ else
+ {
+ _message = Parts[0].Trim();
+ }
+
+ protocol_version = ProtocolVersion.Version2;
+
+ return;
+ }
+
+ Char field;
+ String fieldValue;
+
+ field = (Char) inputStream.ReadByte();
+
+ // Now start to read fields.
+ while (field != 0)
+ {
+ fieldValue = PGUtil.ReadString(inputStream, encoding);
+
+ switch (field)
+ {
+ case 'S':
+ _severity = fieldValue;
+ break;
+ case 'C':
+ _code = fieldValue;
+ break;
+ case 'M':
+ _message = fieldValue;
+ break;
+ case 'D':
+ _detail = fieldValue;
+ break;
+ case 'H':
+ _hint = fieldValue;
+ break;
+ case 'P':
+ _position = fieldValue;
+ break;
+ case 'W':
+ _where = fieldValue;
+ break;
+ case 'F':
+ _file = fieldValue;
+ break;
+ case 'L':
+ _line = fieldValue;
+ break;
+ case 'R':
+ _routine = fieldValue;
+ break;
+
+ }
+
+ field = (Char) inputStream.ReadByte();
+
+ }
+ }
+ }
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs b/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs
index 74356e2ba60..e50d070cae6 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlEventLog.cs
@@ -10,381 +10,338 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-using System;
-using System.Diagnostics;
using System.IO;
+using System.Text;
+using System.Diagnostics;
+using System;
using System.Resources;
namespace Npgsql
{
- /// <summary>
- /// The level of verbosity of the NpgsqlEventLog
- /// </summary>
- public enum LogLevel
- {
- /// <summary>
- /// Don't log at all
- /// </summary>
- None = 0,
- /// <summary>
- /// Only log the most common issues
- /// </summary>
- Normal = 1,
- /// <summary>
- /// Log everything
- /// </summary>
- Debug = 2
- }
+
+ /// <summary>
+ /// The level of verbosity of the NpgsqlEventLog
+ /// </summary>
+ public enum LogLevel {
+ /// <summary>
+ /// Don't log at all
+ /// </summary>
+ None = 0,
+ /// <summary>
+ /// Only log the most common issues
+ /// </summary>
+ Normal = 1,
+ /// <summary>
+ /// Log everything
+ /// </summary>
+ Debug = 2
+ }
- /// <summary>
- /// This class handles all the Npgsql event and debug logging
- /// </summary>
- public class NpgsqlEventLog
- {
- // Logging related values
- private static readonly String CLASSNAME = "NpgsqlEventLog";
- private static String logfile;
- private static LogLevel level;
- private static Boolean echomessages;
+ /// <summary>
+ /// This class handles all the Npgsql event and debug logging
+ /// </summary>
+ public class NpgsqlEventLog
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlEventLog";
+ private static String logfile;
+ private static LogLevel level;
+ private static Boolean echomessages;
- private static readonly ResourceManager LogResMan;
+ private static ResourceManager LogResMan;
- private NpgsqlEventLog()
- {
- }
+ private NpgsqlEventLog()
+ {}
+ // static constructor
+ static NpgsqlEventLog()
+ {
+ LogResMan = new ResourceManager(typeof(NpgsqlEventLog));
+ }
- // static constructor
- static NpgsqlEventLog()
- {
- LogResMan = new ResourceManager(typeof(NpgsqlEventLog));
- }
+ ///<summary>
+ /// Sets/Returns the level of information to log to the logfile.
+ /// </summary>
+ /// <value>The current <see cref="Npgsql.LogLevel">LogLevel</see></value>
+ public static LogLevel Level {
+ get
+ {
+ LogPropertyGet(LogLevel.Debug, CLASSNAME, "LogLevel");
+ return level;
+ }
+ set
+ {
+ LogPropertySet(LogLevel.Debug, CLASSNAME, "LogLevel", value);
+ level = value;
+ }
+ }
- ///<summary>
- /// Sets/Returns the level of information to log to the logfile.
- /// </summary>
- /// <value>The current <see cref="Npgsql.LogLevel">LogLevel</see></value>
- public static LogLevel Level
- {
- get
- {
- LogPropertyGet(LogLevel.Debug, CLASSNAME, "LogLevel");
- return level;
- }
- set
- {
- LogPropertySet(LogLevel.Debug, CLASSNAME, "LogLevel", value);
- level = value;
- }
- }
+ ///<summary>
+ /// Sets/Returns the filename to use for logging.
+ /// </summary>
+ /// <value>The filename of the current Log file.</value>
+ public static String LogName {
+ get
+ {
+ LogPropertyGet(LogLevel.Debug, CLASSNAME, "LogName");
+ return logfile;
+ }
+ set
+ {
+ LogPropertySet(LogLevel.Normal, CLASSNAME, "LogName", value);
+ logfile = value;
+ }
+ }
- ///<summary>
- /// Sets/Returns the filename to use for logging.
- /// </summary>
- /// <value>The filename of the current Log file.</value>
- public static String LogName
- {
- get
- {
- LogPropertyGet(LogLevel.Debug, CLASSNAME, "LogName");
- return logfile;
- }
- set
- {
- LogPropertySet(LogLevel.Normal, CLASSNAME, "LogName", value);
- logfile = value;
- }
- }
+ ///<summary>
+ /// Sets/Returns whether Log messages should be echoed to the console
+ /// </summary>
+ /// <value><b>true</b> if Log messages are echoed to the console, otherwise <b>false</b></value>
+ public static Boolean EchoMessages {
+ get
+ {
+ LogPropertyGet(LogLevel.Debug, CLASSNAME, "EchoMessages");
+ return echomessages;
+ }
+ set
+ {
+ LogPropertySet(LogLevel.Normal, CLASSNAME, "EchoMessages", value);
+ echomessages = value;
+ }
+ }
- ///<summary>
- /// Sets/Returns whether Log messages should be echoed to the console
- /// </summary>
- /// <value><b>true</b> if Log messages are echoed to the console, otherwise <b>false</b></value>
- public static Boolean EchoMessages
- {
- get
- {
- LogPropertyGet(LogLevel.Debug, CLASSNAME, "EchoMessages");
- return echomessages;
- }
- set
- {
- LogPropertySet(LogLevel.Normal, CLASSNAME, "EchoMessages", value);
- echomessages = value;
- }
- }
+ // Event/Debug Logging
+ // This method should be private and only used by the internal methods that support localization.
+ /// <summary>
+ /// Writes a string to the Npgsql event log if msglevel is bigger then <see cref="Npgsql.NpgsqlEventLog.Level">NpgsqlEventLog.Level</see>
+ /// </summary>
+ /// <remarks>
+ /// This method is obsolete and should no longer be used.
+ /// It is likely to be removed in future versions of Npgsql
+ /// </remarks>
+ /// <param name="message">The message to write to the event log</param>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ private static void LogMsg(String message, LogLevel msglevel)
+ {
+ if (msglevel > level)
+ return;
- // Event/Debug Logging
- // This method should be private and only used by the internal methods that support localization.
- /// <summary>
- /// Writes a string to the Npgsql event log if msglevel is bigger then <see cref="Npgsql.NpgsqlEventLog.Level">NpgsqlEventLog.Level</see>
- /// </summary>
- /// <remarks>
- /// This method is obsolete and should no longer be used.
- /// It is likely to be removed in future versions of Npgsql
- /// </remarks>
- /// <param name="message">The message to write to the event log</param>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- private static void LogMsg(String message, LogLevel msglevel)
- {
- if (msglevel > level)
- {
- return;
- }
+ Process proc = Process.GetCurrentProcess();
- Process proc = Process.GetCurrentProcess();
+ if (echomessages)
+ {
+ Console.WriteLine(message);
+ }
- if (echomessages)
- {
- Console.WriteLine(message);
- }
+ if (logfile != null)
+ {
+ if (logfile != "")
+ {
+ lock(logfile)
+ {
- if (!string.IsNullOrEmpty(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("{0}\t{1}\t{2}\t{3}", DateTime.Now, proc.Id, msglevel, 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();
+ }
+ }
+ }
+ }
- }
+ /// <summary>
+ /// Writes a string to the Npgsql event log if msglevel is bigger then <see cref="Npgsql.NpgsqlEventLog.Level">NpgsqlEventLog.Level</see>
+ /// </summary>
+ /// <param name="resman">The <see cref="System.Resources.ResourceManager">ResourceManager</see> to get the localized resources</param>
+ /// <param name="ResourceString">The name of the resource that should be fetched by the <see cref="System.Resources.ResourceManager">ResourceManager</see></param>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="Parameters">The additional parameters that shall be included into the log-message (must be compatible with the string in the resource):</param>
+ internal static void LogMsg(ResourceManager resman, string ResourceString, LogLevel msglevel, params Object[] Parameters)
+ {
+ if (msglevel > level)
+ return;
- /// <summary>
- /// Writes a string to the Npgsql event log if msglevel is bigger then <see cref="Npgsql.NpgsqlEventLog.Level">NpgsqlEventLog.Level</see>
- /// </summary>
- /// <param name="resman">The <see cref="System.Resources.ResourceManager">ResourceManager</see> to get the localized resources</param>
- /// <param name="ResourceString">The name of the resource that should be fetched by the <see cref="System.Resources.ResourceManager">ResourceManager</see></param>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="Parameters">The additional parameters that shall be included into the log-message (must be compatible with the string in the resource):</param>
- internal static void LogMsg(ResourceManager resman, string ResourceString, LogLevel msglevel,
- params Object[] Parameters)
- {
- if (msglevel > level)
- {
- return;
- }
+ string message = resman.GetString(ResourceString);
- string message = resman.GetString(ResourceString);
+ if (message == null) {
+ message = String.Format("Unable to find resource string {0} for class {1}", ResourceString, resman.BaseName);
+ } else if (Parameters.Length > 0) {
+ message = String.Format(message, Parameters);
+ }
- if (message == null)
- {
- message = String.Format("Unable to find resource string {0} for class {1}", ResourceString, resman.BaseName);
- }
- else if (Parameters.Length > 0)
- {
- message = String.Format(message, Parameters);
- }
+ LogMsg(message, msglevel);
+ }
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling the Get-part of an Indexer to the log file.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Indexer</param>
+ /// <param name="IndexerParam">The parameter given to the Indexer</param>
+ internal static void LogIndexerGet(LogLevel msglevel, string ClassName, object IndexerParam)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Indexer_Get"), ClassName, IndexerParam);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling the Get-part of an Indexer to the log file.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Indexer</param>
- /// <param name="IndexerParam">The parameter given to the Indexer</param>
- internal static void LogIndexerGet(LogLevel msglevel, string ClassName, object IndexerParam)
- {
- if (msglevel > level)
- {
- return;
- }
- string message = String.Format(LogResMan.GetString("Indexer_Get"), ClassName, IndexerParam);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling the Set-part of an Indexer to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Indexer</param>
+ /// <param name="IndexerParam">The parameter given to the Indexer</param>
+ /// <param name="value">The value the Indexer is set to</param>
+ internal static void LogIndexerSet(LogLevel msglevel, string ClassName, object IndexerParam, object value)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Indexer_Set"), ClassName, IndexerParam, value);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling the Set-part of an Indexer to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Indexer</param>
- /// <param name="IndexerParam">The parameter given to the Indexer</param>
- /// <param name="value">The value the Indexer is set to</param>
- internal static void LogIndexerSet(LogLevel msglevel, string ClassName, object IndexerParam, object value)
- {
- if (msglevel > level)
- {
- return;
- }
- string message = String.Format(LogResMan.GetString("Indexer_Set"), ClassName, IndexerParam, value);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling the Get-part of a Property to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Property</param>
+ /// <param name="PropertyName">The name of the Property</param>
+ internal static void LogPropertyGet(LogLevel msglevel, string ClassName, string PropertyName)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Property_Get"), ClassName, PropertyName);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling the Get-part of a Property to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Property</param>
- /// <param name="PropertyName">The name of the Property</param>
- internal static void LogPropertyGet(LogLevel msglevel, string ClassName, string PropertyName)
- {
- if (msglevel > level)
- {
- return;
- }
- string message = String.Format(LogResMan.GetString("Property_Get"), ClassName, PropertyName);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling the Set-part of a Property to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Property</param>
+ /// <param name="PropertyName">The name of the Property</param>
+ /// <param name="value">The value the Property is set to</param>
+ internal static void LogPropertySet(LogLevel msglevel, string ClassName, string PropertyName, object value)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Property_Set"), ClassName, PropertyName, value);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling the Set-part of a Property to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Property</param>
- /// <param name="PropertyName">The name of the Property</param>
- /// <param name="value">The value the Property is set to</param>
- internal static void LogPropertySet(LogLevel msglevel, string ClassName, string PropertyName, object value)
- {
- if (msglevel > level)
- {
- return;
- }
- string message = String.Format(LogResMan.GetString("Property_Set"), ClassName, PropertyName, value);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling a Method without Arguments to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Method</param>
+ /// <param name="MethodName">The name of the Method</param>
+ internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Method_0P_Enter"), ClassName, MethodName);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling a Method without Arguments to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Method</param>
- /// <param name="MethodName">The name of the Method</param>
- internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName)
- {
- if (msglevel > level)
- {
- return;
- }
- string message = String.Format(LogResMan.GetString("Method_0P_Enter"), ClassName, MethodName);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling a Method with one Argument to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Method</param>
+ /// <param name="MethodName">The name of the Method</param>
+ /// <param name="MethodParameter">The value of the Argument of the Method</param>
+ internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName, object MethodParameter)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Method_1P_Enter"), ClassName, MethodName, MethodParameter);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling a Method with one Argument to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Method</param>
- /// <param name="MethodName">The name of the Method</param>
- /// <param name="MethodParameter">The value of the Argument of the Method</param>
- internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName, object MethodParameter)
- {
- if (msglevel > level)
- {
- return;
- }
- string message = String.Format(LogResMan.GetString("Method_1P_Enter"), ClassName, MethodName, MethodParameter);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling a Method with two Arguments to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Method</param>
+ /// <param name="MethodName">The name of the Method</param>
+ /// <param name="MethodParameter1">The value of the first Argument of the Method</param>
+ /// <param name="MethodParameter2">The value of the second Argument of the Method</param>
+ internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName, object MethodParameter1, object MethodParameter2)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Method_2P_Enter"), ClassName, MethodName, MethodParameter1, MethodParameter2);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling a Method with two Arguments to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Method</param>
- /// <param name="MethodName">The name of the Method</param>
- /// <param name="MethodParameter1">The value of the first Argument of the Method</param>
- /// <param name="MethodParameter2">The value of the second Argument of the Method</param>
- internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName, object MethodParameter1,
- object MethodParameter2)
- {
- if (msglevel > level)
- {
- return;
- }
- string message =
- String.Format(LogResMan.GetString("Method_2P_Enter"), ClassName, MethodName, MethodParameter1, MethodParameter2);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling a Method with three Arguments to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Method</param>
+ /// <param name="MethodName">The name of the Method</param>
+ /// <param name="MethodParameter1">The value of the first Argument of the Method</param>
+ /// <param name="MethodParameter2">The value of the second Argument of the Method</param>
+ /// <param name="MethodParameter3">The value of the third Argument of the Method</param>
+ internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName, object MethodParameter1, object MethodParameter2, object MethodParameter3)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Format(LogResMan.GetString("Method_3P_Enter"), ClassName, MethodName, MethodParameter1, MethodParameter2, MethodParameter3);
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling a Method with three Arguments to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Method</param>
- /// <param name="MethodName">The name of the Method</param>
- /// <param name="MethodParameter1">The value of the first Argument of the Method</param>
- /// <param name="MethodParameter2">The value of the second Argument of the Method</param>
- /// <param name="MethodParameter3">The value of the third Argument of the Method</param>
- internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName, object MethodParameter1,
- object MethodParameter2, object MethodParameter3)
- {
- if (msglevel > level)
- {
- return;
- }
- string message =
- String.Format(LogResMan.GetString("Method_3P_Enter"), ClassName, MethodName, MethodParameter1, MethodParameter2,
- MethodParameter3);
- LogMsg(message, msglevel);
- }
+ /// <summary>
+ /// Writes the default log-message for the action of calling a Method with more than three Arguments to the logfile.
+ /// </summary>
+ /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
+ /// <param name="ClassName">The name of the class that contains the Method</param>
+ /// <param name="MethodName">The name of the Method</param>
+ /// <param name="MethodParameters">A <see cref="System.Object">Object</see>-Array with zero or more Ojects that are Arguments of the Method.</param>
+ internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName, params object[] MethodParameters)
+ {
+ if (msglevel > level)
+ return;
+ string message = String.Empty;
+ switch (MethodParameters.Length)
+ {
+ case 4:
+ message = String.Format(LogResMan.GetString("Method_4P_Enter"), ClassName, MethodName,
+ MethodParameters[0], MethodParameters[1], MethodParameters[2], MethodParameters[3]);
+ break;
+ case 5:
+ message = String.Format(LogResMan.GetString("Method_5P_Enter"), ClassName, MethodName,
+ MethodParameters[0], MethodParameters[1], MethodParameters[2], MethodParameters[3], MethodParameters[4]);
+ break;
+ case 6:
+ message = String.Format(LogResMan.GetString("Method_6P_Enter"), ClassName, MethodName,
+ MethodParameters[0], MethodParameters[1], MethodParameters[2], MethodParameters[3], MethodParameters[4], MethodParameters[5]);
+ break;
+ default:
+ // should always be true - but who knows ;-)
+ if (MethodParameters.Length > 6)
+ message = String.Format(LogResMan.GetString("Method_6P+_Enter"), ClassName, MethodName, MethodParameters[0], MethodParameters[1]);
+ break;
+ }
+ LogMsg(message, msglevel);
+ }
- /// <summary>
- /// Writes the default log-message for the action of calling a Method with more than three Arguments to the logfile.
- /// </summary>
- /// <param name="msglevel">The minimum <see cref="Npgsql.LogLevel">LogLevel</see> for which this message should be logged.</param>
- /// <param name="ClassName">The name of the class that contains the Method</param>
- /// <param name="MethodName">The name of the Method</param>
- /// <param name="MethodParameters">A <see cref="System.Object">Object</see>-Array with zero or more Ojects that are Arguments of the Method.</param>
- internal static void LogMethodEnter(LogLevel msglevel, string ClassName, string MethodName,
- params object[] MethodParameters)
- {
- if (msglevel > level)
- {
- return;
- }
- string message = String.Empty;
- switch (MethodParameters.Length)
- {
- case 4:
- message =
- String.Format(LogResMan.GetString("Method_4P_Enter"), ClassName, MethodName, MethodParameters[0],
- MethodParameters[1], MethodParameters[2], MethodParameters[3]);
- break;
- case 5:
- message =
- String.Format(LogResMan.GetString("Method_5P_Enter"), ClassName, MethodName, MethodParameters[0],
- MethodParameters[1], MethodParameters[2], MethodParameters[3], MethodParameters[4]);
- break;
- case 6:
- message =
- String.Format(LogResMan.GetString("Method_6P_Enter"), ClassName, MethodName, MethodParameters[0],
- MethodParameters[1], MethodParameters[2], MethodParameters[3], MethodParameters[4],
- MethodParameters[5]);
- break;
- default:
- // should always be true - but who knows ;-)
- if (MethodParameters.Length > 6)
- {
- message =
- String.Format(LogResMan.GetString("Method_6P+_Enter"), ClassName, MethodName, MethodParameters[0],
- MethodParameters[1]);
- }
- break;
- }
- LogMsg(message, msglevel);
- }
- }
-} \ No newline at end of file
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlException.cs b/mcs/class/Npgsql/Npgsql/NpgsqlException.cs
index fbbc5bda61a..4201dbc7669 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlException.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlException.cs
@@ -9,231 +9,269 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Collections;
-using System.Data.Common;
-using System.IO;
using System.Resources;
+using System.IO;
+using System.Text;
+using System.Collections;
using System.Runtime.Serialization;
namespace Npgsql
{
- /// <summary>
- /// The exception that is thrown when the PostgreSQL backend reports errors.
- /// </summary>
- [Serializable]
- public sealed class NpgsqlException : DbException
- {
- private readonly IList errors;
-
- // Logging related values
- //private static readonly String CLASSNAME = "NpgsqlException";
- private static readonly ResourceManager resman = new ResourceManager(typeof (NpgsqlException));
-
- // To allow deserialization.
- private NpgsqlException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- errors = (IList) info.GetValue("errors", typeof (IList));
- }
-
- /// <summary>
- /// Construct a backend error exception based on a list of one or more
- /// backend errors. The basic Exception.Message will be built from the
- /// first (usually the only) error in the list.
- /// </summary>
- internal NpgsqlException(IList errors)
- : base(errors[0].ToString())
- {
- NpgsqlEventLog.LogMsg(resman, "Log_ExceptionOccured", LogLevel.Normal, Message);
- this.errors = new ArrayList(errors);
- }
-
-
- internal NpgsqlException(String message)
- : this(message, null)
- {
- }
-
- internal NpgsqlException(String message, Exception innerException)
- : base(message, innerException)
- {
- errors = new ArrayList();
- errors.Add(new NpgsqlError(ProtocolVersion.Unknown, message));
- }
-
-
- public override void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- base.GetObjectData(info, context);
-
- // Add custom data, in this case the list of errors when serializing.
- // Thanks Robert Chartier for info: http://www.15seconds.com/issue/020903.htm
-
- //use the info object to add the items you want serialized
- info.AddValue("errors", errors, typeof (IList));
- }
-
- /// <summary>
- /// Provide access to the entire list of errors provided by the PostgreSQL backend.
- /// </summary>
- public NpgsqlError this[Int32 Index]
- {
- get { return (NpgsqlError) errors[Index]; }
- }
-
-
- /// <summary>
- /// Severity code. All versions.
- /// </summary>
- public String Severity
- {
- get { return this[0].Severity; }
- }
-
- /// <summary>
- /// Error code. PostgreSQL 7.4 and up.
- /// </summary>
- public String Code
- {
- get { return this[0].Code; }
- }
-
- /// <summary>
- /// Basic error message. All versions.
- /// </summary>
- public String BaseMessage
- {
- get { return this[0].Message; }
- }
-
- /// <summary>
- /// Detailed error message. PostgreSQL 7.4 and up.
- /// </summary>
- public String Detail
- {
- get { return this[0].Detail; }
- }
-
- /// <summary>
- /// Suggestion to help resolve the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String Hint
- {
- get { return this[0].Hint; }
- }
-
- /// <summary>
- /// Position (one based) within the query string where the error was encounterd. PostgreSQL 7.4 and up.
- /// </summary>
- public String Position
- {
- get { return this[0].Position; }
- }
-
- /// <summary>
- /// Trace back information. PostgreSQL 7.4 and up.
- /// </summary>
- public String Where
- {
- get { return this[0].Where; }
- }
-
- /// <summary>
- /// Source file (in backend) reporting the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String File
- {
- get { return this[0].File; }
- }
-
- /// <summary>
- /// Source file line number (in backend) reporting the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String Line
- {
- get { return this[0].Line; }
- }
-
- /// <summary>
- /// Source routine (in backend) reporting the error. PostgreSQL 7.4 and up.
- /// </summary>
- public String Routine
- {
- get { 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.
- /// </summary>
- public IList Errors
- {
- get { return errors; }
- }
-
- /// <summary>
- /// Format a .NET style exception string.
- /// Include all errors in the list, including any hints.
- /// </summary>
- public override String ToString()
- {
- if (Errors != null)
- {
- StringWriter S = new StringWriter();
-
- S.WriteLine("{0}:", this.GetType().FullName);
-
- foreach (NpgsqlError PgError in Errors)
- {
- AppendString(S, "{0}", PgError.Message);
- AppendString(S, "Severity: {0}", PgError.Severity);
- AppendString(S, "Code: {0}", PgError.Code);
- AppendString(S, "Hint: {0}", PgError.Hint);
- }
-
- S.Write(StackTrace);
-
- return S.ToString();
- }
-
- return base.ToString();
- }
-
- /// <summary>
- /// Append a line to the given Stream, first checking for zero-length.
- /// </summary>
- private static void AppendString(StringWriter Stream, string Format, string Str)
- {
- if (Str.Length > 0)
- {
- Stream.WriteLine(Format, Str);
- }
- }
- }
-} \ No newline at end of file
+ /// <summary>
+ /// The exception that is thrown when the PostgreSQL backend reports errors.
+ /// </summary>
+ [Serializable]
+ public sealed class NpgsqlException : ApplicationException
+ {
+ private IList errors;
+
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlException";
+ private static ResourceManager resman = new ResourceManager(typeof(NpgsqlException));
+
+ // To allow deserialization.
+ private NpgsqlException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ errors = (IList)info.GetValue("errors", typeof(IList));
+ }
+
+ /// <summary>
+ /// Construct a backend error exception based on a list of one or more
+ /// backend errors. The basic Exception.Message will be built from the
+ /// first (usually the only) error in the list.
+ /// </summary>
+ internal NpgsqlException(IList errors) : base(((NpgsqlError)errors[0]).ToString())
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_ExceptionOccured", LogLevel.Normal, Message);
+ this.errors = new ArrayList(errors);
+
+ }
+
+
+ internal NpgsqlException(String message) : this (message, null)
+ {}
+
+ internal NpgsqlException(String message, Exception innerException) : base (message, innerException)
+ {
+ errors = new ArrayList();
+ errors.Add(new NpgsqlError(ProtocolVersion.Unknown, message));
+ }
+
+
+ override public void GetObjectData(SerializationInfo info,StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+
+ // Add custom data, in this case the list of errors when serializing.
+ // Thanks Robert Chartier for info: http://www.15seconds.com/issue/020903.htm
+
+ //use the info object to add the items you want serialized
+ info.AddValue("errors", errors, typeof(IList));
+
+
+ }
+
+ /// <summary>
+ /// Provide access to the entire list of errors provided by the PostgreSQL backend.
+ /// </summary>
+ public NpgsqlError this[Int32 Index]
+ {
+ get
+ {
+ return (NpgsqlError)errors[Index];
+ }
+ }
+
+
+ /// <summary>
+ /// Severity code. All versions.
+ /// </summary>
+ public String Severity
+ {
+ get
+ {
+ return this[0].Severity;
+ }
+ }
+
+ /// <summary>
+ /// Error code. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Code
+ {
+ get
+ {
+ return this[0].Code;
+ }
+ }
+
+ /// <summary>
+ /// Basic error message. All versions.
+ /// </summary>
+ public String BaseMessage
+ {
+ get
+ {
+ return this[0].Message;
+ }
+ }
+
+ /// <summary>
+ /// Detailed error message. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Detail
+ {
+ get
+ {
+ return this[0].Detail;
+ }
+ }
+
+ /// <summary>
+ /// Suggestion to help resolve the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Hint
+ {
+ get
+ {
+ return this[0].Hint;
+ }
+ }
+
+ /// <summary>
+ /// Position (one based) within the query string where the error was encounterd. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Position
+ {
+ get
+ {
+ return this[0].Position;
+ }
+ }
+
+ /// <summary>
+ /// Trace back information. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Where
+ {
+ get
+ {
+ return this[0].Where;
+ }
+ }
+
+ /// <summary>
+ /// Source file (in backend) reporting the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String File
+ {
+ get
+ {
+ return this[0].File;
+ }
+ }
+
+ /// <summary>
+ /// Source file line number (in backend) reporting the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Line
+ {
+ get
+ {
+ return this[0].Line;
+ }
+ }
+
+ /// <summary>
+ /// Source routine (in backend) reporting the error. PostgreSQL 7.4 and up.
+ /// </summary>
+ public String Routine
+ {
+ get
+ {
+ 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.
+ /// </summary>
+ public IList Errors
+ {
+ get
+ {
+ return errors;
+ }
+ }
+
+ /// <summary>
+ /// Format a .NET style exception string.
+ /// Include all errors in the list, including any hints.
+ /// </summary>
+ public override String ToString()
+ {
+
+ if (Errors != null)
+ {
+ StringWriter S = new StringWriter();
+
+ S.WriteLine("{0}:", this.GetType().FullName);
+
+ foreach (NpgsqlError PgError in Errors)
+ {
+ AppendString(S, "{0}", PgError.Message);
+ AppendString(S, "Severity: {0}", PgError.Severity);
+ AppendString(S, "Code: {0}", PgError.Code);
+ AppendString(S, "Hint: {0}", PgError.Hint);
+ }
+
+ S.Write(StackTrace);
+
+ return S.ToString();
+ }
+
+ return base.ToString();
+
+ }
+
+ /// <summary>
+ /// Append a line to the given Stream, first checking for zero-length.
+ /// </summary>
+ private static void AppendString(StringWriter Stream, string Format, string Str)
+ {
+ if (Str.Length > 0)
+ {
+ Stream.WriteLine(Format, Str);
+ }
+ }
+
+ }
+
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlExecute.cs b/mcs/class/Npgsql/Npgsql/NpgsqlExecute.cs
index d06c3c351a5..8b9f3e7fd2f 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlExecute.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlExecute.cs
@@ -8,58 +8,68 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Text;
namespace Npgsql
{
- /// <summary>
- /// This class represents the Parse message sent to PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlExecute : ClientMessage
- {
- private readonly String _portalName;
- private readonly Int32 _maxRows;
+ /// <summary>
+ /// This class represents the Parse message sent to PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlExecute
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlExecute";
+
+ private String _portalName;
+ private Int32 _maxRows;
+
+
+ public NpgsqlExecute(String portalName, Int32 maxRows)
+ {
+ _portalName = portalName;
+ _maxRows = maxRows;
+ }
+
+ public String PortalName
+ {
+ get
+ {
+ return _portalName;
+ }
+ }
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+ outputStream.WriteByte((Byte)'E');
- public NpgsqlExecute(String portalName, Int32 maxRows)
- {
- _portalName = portalName;
- _maxRows = maxRows;
- }
+ PGUtil.WriteInt32(outputStream, 4 +
+ encoding.GetByteCount(_portalName) + 1 +
+ 4);
- public String PortalName
- {
- get { return _portalName; }
- }
+ PGUtil.WriteString(_portalName, outputStream, encoding);
+ PGUtil.WriteInt32(outputStream, _maxRows);
- public override void WriteToStream(Stream outputStream)
- {
- outputStream.WriteByte((byte) FrontEndMessageCode.Execute);
+ }
- PGUtil.WriteInt32(outputStream, 4 + UTF8Encoding.GetByteCount(_portalName) + 1 + 4);
+ }
+}
- PGUtil.WriteString(_portalName, outputStream);
- PGUtil.WriteInt32(outputStream, _maxRows);
- }
- }
-} \ No newline at end of file
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlFlush.cs b/mcs/class/Npgsql/Npgsql/NpgsqlFlush.cs
index 349842f3da0..4a97a509304 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlFlush.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlFlush.cs
@@ -9,42 +9,45 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
using System.IO;
+using System.Text;
namespace Npgsql
{
- /// <summary>
- /// This class represents the Parse message sent to PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlFlush : ClientMessage
- {
- // Logging related values
- //private static readonly String CLASSNAME = "NpgsqlFlush";
-
- public override void WriteToStream(Stream outputStream)
- {
- outputStream.WriteByte((byte) FrontEndMessageCode.Flush);
-
- PGUtil.WriteInt32(outputStream, 4);
- }
- }
-} \ No newline at end of file
+
+ /// <summary>
+ /// This class represents the Parse message sent to PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlFlush
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlFlush";
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+ outputStream.WriteByte((Byte)'H');
+
+ PGUtil.WriteInt32(outputStream, 4);
+
+ }
+
+ }
+}
+
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs b/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs
index 6e1881cfc11..7a44c4d2613 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlMediator.cs
@@ -9,98 +9,253 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.IO;
+using System.Text;
+using System.Collections;
+using System.Collections.Specialized;
namespace Npgsql
{
- ///<summary>
- /// This class is responsible for serving as bridge between the backend
- /// protocol handling and the core classes. It is used as the mediator for
- /// exchanging data generated/sent from/to backend.
- /// </summary>
- ///
- internal sealed class NpgsqlMediator
- {
- // Stream for user to exchange COPY data
- private Stream _copyStream;
- // Size of data chunks read from user stream and written to server in COPY IN
- private int _copyBufferSize = 8192;
- // Very temporary holder of data received during COPY OUT
- private byte[] _receivedCopyData;
-
-
- //
- // Responses collected from the backend.
- //
- private String _sqlSent;
- private Int32 _commandTimeout;
-
-
- public NpgsqlMediator()
- {
- _sqlSent = String.Empty;
- _commandTimeout = 20;
- }
-
- public void ResetResponses()
- {
- _sqlSent = String.Empty;
- _commandTimeout = 20;
- }
-
- public String SqlSent
- {
- set { _sqlSent = value; }
-
- get { return _sqlSent; }
- }
-
- public Int32 CommandTimeout
- {
- set { _commandTimeout = value; }
-
- get { return _commandTimeout; }
- }
-
- public Stream CopyStream
- {
- get { return _copyStream; }
- set { _copyStream = value; }
- }
-
- public int CopyBufferSize
- {
- get { return _copyBufferSize; }
- set { _copyBufferSize = value; }
- }
-
- public byte[] ReceivedCopyData
- {
- get
- {
- byte[] result = _receivedCopyData;
- _receivedCopyData = null;
- return result;
- }
- set { _receivedCopyData = value; }
- }
- }
-} \ No newline at end of file
+ ///<summary>
+ /// This class is responsible for serving as bridge between the backend
+ /// protocol handling and the core classes. It is used as the mediator for
+ /// exchanging data generated/sent from/to backend.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlMediator
+ {
+ //
+ // Expectations that depend on context.
+ // Non-default values must be set before collecting responses.
+ //
+ // Some kinds of messages only get one response, and do not
+ // expect a ready_for_query response.
+ private bool _require_ready_for_query;
+
+ //
+ // 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 NpgsqlRowDescription _rd;
+ private ArrayList _rows;
+ private String _sqlSent;
+ private Int32 _commandTimeout;
+
+
+ public NpgsqlMediator()
+ {
+ _require_ready_for_query = true;
+
+ _errors = new ArrayList();
+ _notices = new ArrayList();
+ _resultSets = new ArrayList();
+ _responses = new ArrayList();
+ _notifications = new ArrayList();
+ _parameters = new ListDictionary(CaseInsensitiveComparer.Default);
+ _backend_key_data = null;
+ _sqlSent = String.Empty;
+ _commandTimeout = 20;
+ }
+
+ public void ResetExpectations()
+ {
+ _require_ready_for_query = true;
+ }
+
+ public void ResetResponses()
+ {
+ _errors.Clear();
+ _notices.Clear();
+ _resultSets.Clear();
+ _responses.Clear();
+ _notifications.Clear();
+ _parameters.Clear();
+ _backend_key_data = null;
+ _sqlSent = String.Empty;
+ _commandTimeout = 20;
+ }
+
+
+
+
+ public Boolean RequireReadyForQuery
+ {
+ get
+ {
+ return _require_ready_for_query;
+ }
+ set
+ {
+ _require_ready_for_query = value;
+ }
+ }
+
+
+
+ public NpgsqlRowDescription LastRowDescription
+ {
+ get
+ {
+ return _rd;
+ }
+ }
+
+ public ArrayList ResultSets
+ {
+ get
+ {
+ return _resultSets;
+ }
+ }
+
+ public ArrayList CompletedResponses
+ {
+ get
+ {
+ return _responses;
+ }
+ }
+
+ public ArrayList Errors
+ {
+ get
+ {
+ return _errors;
+ }
+ }
+
+ public ArrayList Notices
+ {
+ get
+ {
+ return _notices;
+ }
+ }
+
+ public ArrayList Notifications
+ {
+ get
+ {
+ return _notifications;
+ }
+ }
+
+ public ListDictionary Parameters
+ {
+ get
+ {
+ return _parameters;
+ }
+ }
+
+ public NpgsqlBackEndKeyData BackendKeyData
+ {
+ get
+ {
+ return _backend_key_data;
+ }
+ }
+
+ public String SqlSent
+ {
+ set
+ {
+ _sqlSent = value;
+ }
+
+ get
+ {
+ return _sqlSent;
+ }
+ }
+
+ public Int32 CommandTimeout
+ {
+ set
+ {
+ _commandTimeout = value;
+ }
+
+ get
+ {
+ return _commandTimeout;
+ }
+
+ }
+
+ public void AddNotification(NpgsqlNotificationEventArgs data)
+ {
+ _notifications.Add(data);
+ }
+
+ public void AddCompletedResponse(String response)
+ {
+ if (_rd != null)
+ {
+ // Finished receiving the resultset. Add it to the buffer.
+ _resultSets.Add(new NpgsqlResultSet(_rd, _rows));
+
+ // Add a placeholder response.
+ _responses.Add(null);
+
+ // Discard the RowDescription.
+ _rd = null;
+ }
+ else
+ {
+ // Add a placeholder resultset.
+ _resultSets.Add(null);
+ // It was just a non query string. Just add the response.
+ _responses.Add(response);
+ }
+
+ }
+
+ public void AddRowDescription(NpgsqlRowDescription rowDescription)
+ {
+ _rd = rowDescription;
+ _rows = new ArrayList();
+ }
+
+ public void AddAsciiRow(NpgsqlAsciiRow asciiRow)
+ {
+ _rows.Add(asciiRow);
+ }
+
+ public void AddBinaryRow(NpgsqlBinaryRow binaryRow)
+ {
+ _rows.Add(binaryRow);
+ }
+
+
+ public void SetBackendKeydata(NpgsqlBackEndKeyData keydata)
+ {
+ _backend_key_data = keydata;
+ }
+
+ public void AddParameterStatus(String Key, NpgsqlParameterStatus PS)
+ {
+ _parameters[Key] = PS;
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlMessageTypes.cs b/mcs/class/Npgsql/Npgsql/NpgsqlMessageTypes.cs
index fd031ce2cf4..b223053f8f8 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlMessageTypes.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlMessageTypes.cs
@@ -8,40 +8,136 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+using System;
namespace Npgsql
{
- public enum FrontEndMessageCode :byte
- {
- StartupPacket = (byte) ' ',
- Termination = (byte) 'X',
- CopyFail = (byte) 'f',
- CopyData = (byte) 'd',
- CopyDone = (byte) 'c',
- Flush = (byte) 'H',
- Query = (byte) 'Q',
- Parse = (byte) 'P',
- Bind = (byte) 'B',
- Execute = (byte) 'E',
- Describe = (byte) 'D',
- Close = (byte) 'C',
- Sync = (byte) 'S'
- }
-} \ No newline at end of file
+ /// <summary>
+ /// Class NpgsqlMessageTypes_Ver_2.
+ /// Defines PG frontend/backend protocol message types and parameters used in protocol version 2.
+ /// </summary>
+ internal sealed class NpgsqlMessageTypes_Ver_2
+ {
+ private NpgsqlMessageTypes_Ver_2()
+ {}
+
+ public const Char StartupPacket = ' ';
+ public const Char Terminate = 'X';
+
+ public const Char AsciiRow = 'D';
+ public const Char BinaryRow = 'B';
+
+ public const Char AuthenticationRequest = 'R';
+ // specific Authentication request types
+ public const Int32 AuthenticationOk = 0;
+ public const Int32 AuthenticationKerberosV4 = 1;
+ public const Int32 AuthenticationKerberosV5 = 2;
+ public const Int32 AuthenticationClearTextPassword = 3;
+ public const Int32 AuthenticationCryptPassword = 4;
+ public const Int32 AuthenticationMD5Password = 5;
+ public const Int32 AuthenticationSCMCredential = 6;
+
+ public const Char BackendKeyData = 'K';
+ public const Char CancelRequest = 'F';
+ public const Char CompletedResponse = 'C';
+ public const Char CopyDataRows = ' ';
+ public const Char CopyInResponse = 'G';
+ public const Char CopyOutResponse = 'H';
+ public const Char CursorResponse = 'P';
+ public const Char EmptyQueryResponse = 'I';
+ public const Char ErrorResponse = 'E';
+ public const Char FunctionCall = 'F';
+
+ public const Char FunctionResultResponse = 'V';
+ // specific function result responses
+ public const Char FunctionResultNonEmptyResponse = 'G';
+ public const Char FunctionResultVoidResponse = '0';
+
+ public const Char NoticeResponse = 'N';
+ public const Char NotificationResponse = 'A';
+ public const Char PasswordPacket = ' ';
+ public const Char Query = 'Q';
+ public const Char ReadyForQuery = 'Z';
+ public const Char RowDescription = 'T';
+ public const Char SSLRequest = ' ';
+ }
+
+
+ /// <summary>
+ /// Class NpgsqlMessageTypes_Ver_3.
+ /// Defines PG frontend/backend protocol message types and parameters used in protocol version 3.
+ /// </summary>
+ internal sealed class NpgsqlMessageTypes_Ver_3
+ {
+ private NpgsqlMessageTypes_Ver_3()
+ {}
+
+ public const Char StartupPacket = ' ';
+ public const Char Termination = 'X';
+
+ public const Char DataRow = 'D';
+
+ public const Char AuthenticationRequest = 'R';
+ // specific Authentication request types
+ public const Int32 AuthenticationOk = 0;
+ public const Int32 AuthenticationKerberosV4 = 1;
+ public const Int32 AuthenticationKerberosV5 = 2;
+ public const Int32 AuthenticationClearTextPassword = 3;
+ public const Int32 AuthenticationCryptPassword = 4;
+ public const Int32 AuthenticationMD5Password = 5;
+ public const Int32 AuthenticationSCMCredential = 6;
+
+ public const Char BackendKeyData = 'K';
+ public const Char CancelRequest = 'F';
+ public const Char CompletedResponse = 'C';
+ public const Char CopyDataRows = ' ';
+ public const Char CopyInResponse = 'G';
+ public const Char CopyOutResponse = 'H';
+ public const Char EmptyQueryResponse = 'I';
+ public const Char ErrorResponse = 'E';
+ public const Char FunctionCall = 'F';
+ public const Char FunctionCallResponse = 'V';
+
+ public const Char NoticeResponse = 'N';
+ public const Char NotificationResponse = 'A';
+ public const Char ParameterStatus = 'S';
+ public const Char PasswordPacket = ' ';
+ public const Char Query = 'Q';
+ public const Char ReadyForQuery = 'Z';
+ public const Char RowDescription = 'T';
+ public const Char SSLRequest = ' ';
+
+ // extended query frontend messages
+ public const Char Parse = 'P';
+ public const Char Bind = 'B';
+ public const Char Execute = 'E';
+ public const Char Describe = 'D';
+ public const Char Close = 'C';
+ public const Char Flush = 'H';
+ public const Char Sync = 'S';
+
+ // extended query backend messages
+ public const Char ParseComplete = '1';
+ public const Char BindComplete = '2';
+ public const Char PortalSuspended = 's';
+ public const Char ParameterDescription = 't';
+ public const Char NoData = 'n';
+ public const Char CloseComplete = '3';
+
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlNotificationEventArgs.cs b/mcs/class/Npgsql/Npgsql/NpgsqlNotificationEventArgs.cs
index d6453c7308a..f0e90534a08 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlNotificationEventArgs.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlNotificationEventArgs.cs
@@ -8,54 +8,44 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.IO;
namespace Npgsql
{
- /// <summary>
- /// EventArgs class to send Notification parameters.
- /// </summary>
- public class NpgsqlNotificationEventArgs : EventArgs
- {
- /// <summary>
- /// Process ID of the PostgreSQL backend that sent this notification.
- /// </summary>
- public readonly int PID;
-
- /// <summary>
- /// Condition that triggered that notification.
- /// </summary>
- public readonly string Condition;
+ /// <summary>
+ /// EventArgs class to send Notification parameters.
+ /// </summary>
+ public class NpgsqlNotificationEventArgs : EventArgs
+ {
+ /// <summary>
+ /// Process ID of the PostgreSQL backend that sent this notification.
+ /// </summary>
+ public Int32 PID = 0;
- /// <summary>
- /// Additional Information From Notifiying Process (for future use, currently postgres always sets this to an empty string)
- /// </summary>
- public readonly string AdditionalInformation;
+ /// <summary>
+ /// Condition that triggered that notification.
+ /// </summary>
+ public String Condition = null;
- internal NpgsqlNotificationEventArgs(Stream stream, bool readAdditional)
- {
- PID = PGUtil.ReadInt32(stream);
- Condition = PGUtil.ReadString(stream);
- AdditionalInformation = readAdditional ? PGUtil.ReadString(stream) : string.Empty;
- }
- }
-} \ No newline at end of file
+ internal NpgsqlNotificationEventArgs(Int32 nPID, String nCondition)
+ {
+ PID = nPID;
+ Condition = nCondition;
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs b/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs
index 94debbd8321..af0271f03d3 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlParameter.cs
@@ -3,91 +3,87 @@
// Npgsql.NpgsqlParameter.cs
//
// Author:
-// Francisco Jr. (fxjrlists@yahoo.com.br)
+// Francisco Jr. (fxjrlists@yahoo.com.br)
//
-// Copyright (C) 2002 The Npgsql Development Team
-// npgsql-general@gborg.postgresql.org
-// http://gborg.postgresql.org/project/npgsql/projdisplay.php
+// Copyright (C) 2002 The Npgsql Development Team
+// npgsql-general@gborg.postgresql.org
+// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.ComponentModel;
using System.Data;
-using System.Data.Common;
-using System.Resources;
+using System.ComponentModel;
using NpgsqlTypes;
#if WITHDESIGN
using Npgsql.Design;
#endif
+
namespace Npgsql
{
///<summary>
/// This class represents a parameter to a command that will be sent to server
///</summary>
-#if WITHDESIGN
+ #if WITHDESIGN
[TypeConverter(typeof(NpgsqlParameterConverter))]
-#endif
-
- public sealed class NpgsqlParameter : DbParameter, ICloneable
+ #endif
+
+ public sealed class NpgsqlParameter : MarshalByRefObject, IDbDataParameter, IDataParameter, ICloneable
{
+
// Logging related values
private static readonly String CLASSNAME = "NpgsqlParameter";
// Fields to implement IDbDataParameter interface.
- private byte precision = 0;
- private byte scale = 0;
- private Int32 size = 0;
+ private byte precision = 0;
+ private byte scale = 0;
+ private Int32 size = 0;
// Fields to implement IDataParameter
- //private NpgsqlDbType npgsqldb_type = NpgsqlDbType.Text;
+ //private NpgsqlDbType npgsqldb_type = NpgsqlDbType.Text;
//private DbType db_type = DbType.String;
- private NpgsqlNativeTypeInfo type_info;
- private ParameterDirection direction = ParameterDirection.Input;
- private Boolean is_nullable = false;
- private String m_Name = String.Empty;
- private String source_column = String.Empty;
- private DataRowVersion source_version = DataRowVersion.Current;
- private Object value = DBNull.Value;
- private Boolean sourceColumnNullMapping;
- private readonly ResourceManager resman;
-
- private Boolean useCast = false;
-
+ private NpgsqlNativeTypeInfo type_info;
+ private ParameterDirection direction = ParameterDirection.Input;
+ private Boolean is_nullable = false;
+ private String name = String.Empty;
+ private String source_column = String.Empty;
+ 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.
/// </summary>
public NpgsqlParameter()
{
- resman = new ResourceManager(this.GetType());
+ resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
//type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
}
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>
- /// class with the parameter m_Name and a value of the new <b>NpgsqlParameter</b>.
+ /// class with the parameter name and a value of the new <b>NpgsqlParameter</b>.
/// </summary>
- /// <param m_Name="parameterName">The m_Name of the parameter to map.</param>
- /// <param m_Name="value">An <see cref="System.Object">Object</see> that is the value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.</param>
+ /// <param name="parameterName">The name of the parameter to map.</param>
+ /// <param name="value">An <see cref="System.Object">Object</see> that is the value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.</param>
/// <remarks>
/// <p>When you specify an <see cref="System.Object">Object</see>
/// in the value parameter, the <see cref="System.Data.DbType">DbType</see> is
@@ -98,115 +94,132 @@ namespace Npgsql
/// </remarks>
public NpgsqlParameter(String parameterName, object value)
{
- resman = new ResourceManager(this.GetType());
+ resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, parameterName, value);
this.ParameterName = parameterName;
this.value = value;
- if ((this.value == null) || (this.value == DBNull.Value))
+ if ((this.value == null) || (this.value == DBNull.Value) )
{
// don't really know what to do - leave default and do further exploration
// Default type for null values is String.
this.value = DBNull.Value;
type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
+ return;
}
- else if (!NpgsqlTypesHelper.TryGetNativeTypeInfo(value.GetType(), out type_info))
+ else
{
- throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), value.GetType()));
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(value.GetType());
+ if (type_info == null)
+ {
+ 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, 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 = DBNull.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 m_Name and the data type.
+ /// class with the parameter name and the data type.
/// </summary>
- /// <param m_Name="parameterName">The m_Name of the parameter to map.</param>
- /// <param m_Name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
- public NpgsqlParameter(String parameterName, NpgsqlDbType parameterType)
- : this(parameterName, parameterType, 0, String.Empty)
- {
- }
+ /// <param name="parameterName">The name of the parameter to map.</param>
+ /// <param name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
+ public NpgsqlParameter(String parameterName, NpgsqlDbType parameterType) : this(parameterName, parameterType, 0, String.Empty)
+ {}
- public NpgsqlParameter(String parameterName, DbType parameterType)
- : this(parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, 0, String.Empty)
- {
- }
+ public NpgsqlParameter(String parameterName, DbType parameterType) : this(parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, 0, String.Empty)
+ {}
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>
- /// class with the parameter m_Name, the <see cref="System.Data.DbType">DbType</see>, and the size.
+ /// class with the parameter name, the <see cref="System.Data.DbType">DbType</see>, and the size.
/// </summary>
- /// <param m_Name="parameterName">The m_Name of the parameter to map.</param>
- /// <param m_Name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
- /// <param m_Name="size">The length of the parameter.</param>
- public NpgsqlParameter(String parameterName, NpgsqlDbType parameterType, Int32 size)
- : this(parameterName, parameterType, size, String.Empty)
- {
- }
+ /// <param name="parameterName">The name of the parameter to map.</param>
+ /// <param name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
+ /// <param name="size">The length of the parameter.</param>
+ public NpgsqlParameter(String parameterName, NpgsqlDbType parameterType, Int32 size) : this(parameterName, parameterType, size, String.Empty)
+ {}
- public NpgsqlParameter(String parameterName, DbType parameterType, Int32 size)
- : this(parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, size, String.Empty)
- {
- }
+ public NpgsqlParameter(String parameterName, DbType parameterType, Int32 size) : this(parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, size, String.Empty)
+ {}
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>
- /// class with the parameter m_Name, the <see cref="System.Data.DbType">DbType</see>, the size,
- /// and the source column m_Name.
+ /// class with the parameter name, the <see cref="System.Data.DbType">DbType</see>, the size,
+ /// and the source column name.
/// </summary>
- /// <param m_Name="parameterName">The m_Name of the parameter to map.</param>
- /// <param m_Name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
- /// <param m_Name="size">The length of the parameter.</param>
- /// <param m_Name="sourceColumn">The m_Name of the source column.</param>
+ /// <param name="parameterName">The name of the parameter to map.</param>
+ /// <param name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
+ /// <param name="size">The length of the parameter.</param>
+ /// <param name="sourceColumn">The name of the source column.</param>
public NpgsqlParameter(String parameterName, NpgsqlDbType parameterType, Int32 size, String sourceColumn)
{
- resman = new ResourceManager(this.GetType());
+
+ resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME, parameterName, parameterType, size, source_column);
this.ParameterName = parameterName;
-
- NpgsqlDbType = parameterType; //Allow the setter to catch any exceptions.
+
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(parameterType);
+ if (type_info == null)
+ throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), parameterType));
this.size = size;
source_column = sourceColumn;
- }
- public NpgsqlParameter(String parameterName, DbType parameterType, Int32 size, String sourceColumn)
- : this(parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, size, sourceColumn)
- {
+
}
+ public NpgsqlParameter(String parameterName, DbType parameterType, Int32 size, String sourceColumn) : this(parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, size, sourceColumn)
+ {}
+
+
/// <summary>
/// Initializes a new instance of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>
- /// class with the parameter m_Name, the <see cref="System.Data.DbType">DbType</see>, the size,
- /// the source column m_Name, a <see cref="System.Data.ParameterDirection">ParameterDirection</see>,
+ /// class with the parameter name, the <see cref="System.Data.DbType">DbType</see>, the size,
+ /// the source column name, a <see cref="System.Data.ParameterDirection">ParameterDirection</see>,
/// the precision of the parameter, the scale of the parameter, a
/// <see cref="System.Data.DataRowVersion">DataRowVersion</see> to use, and the
/// value of the parameter.
/// </summary>
- /// <param m_Name="parameterName">The m_Name of the parameter to map.</param>
- /// <param m_Name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
- /// <param m_Name="size">The length of the parameter.</param>
- /// <param m_Name="sourceColumn">The m_Name of the source column.</param>
- /// <param m_Name="direction">One of the <see cref="System.Data.ParameterDirection">ParameterDirection</see> values.</param>
- /// <param m_Name="isNullable"><b>true</b> if the value of the field can be null, otherwise <b>false</b>.</param>
- /// <param m_Name="precision">The total number of digits to the left and right of the decimal point to which
+ /// <param name="parameterName">The name of the parameter to map.</param>
+ /// <param name="parameterType">One of the <see cref="System.Data.DbType">DbType</see> values.</param>
+ /// <param name="size">The length of the parameter.</param>
+ /// <param name="sourceColumn">The name of the source column.</param>
+ /// <param name="direction">One of the <see cref="System.Data.ParameterDirection">ParameterDirection</see> values.</param>
+ /// <param name="isNullable"><b>true</b> if the value of the field can be null, otherwise <b>false</b>.</param>
+ /// <param name="precision">The total number of digits to the left and right of the decimal point to which
/// <see cref="Npgsql.NpgsqlParameter.Value">Value</see> is resolved.</param>
- /// <param m_Name="scale">The total number of decimal places to which
+ /// <param name="scale">The total number of decimal places to which
/// <see cref="Npgsql.NpgsqlParameter.Value">Value</see> is resolved.</param>
- /// <param m_Name="sourceVersion">One of the <see cref="System.Data.DataRowVersion">DataRowVersion</see> values.</param>
- /// <param m_Name="value">An <see cref="System.Object">Object</see> that is the value
+ /// <param name="sourceVersion">One of the <see cref="System.Data.DataRowVersion">DataRowVersion</see> values.</param>
+ /// <param name="value">An <see cref="System.Object">Object</see> that is the value
/// of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.</param>
- public NpgsqlParameter(String parameterName, NpgsqlDbType parameterType, Int32 size, String sourceColumn,
- ParameterDirection direction, bool isNullable, byte precision, byte scale,
- DataRowVersion sourceVersion, object value)
+ public NpgsqlParameter (String parameterName, NpgsqlDbType parameterType, Int32 size, String sourceColumn, ParameterDirection direction, bool isNullable, byte precision, byte scale, DataRowVersion sourceVersion, object value)
{
- resman = new ResourceManager(this.GetType());
+
+ resman = new System.Resources.ResourceManager(this.GetType());
this.ParameterName = parameterName;
this.Size = size;
@@ -225,19 +238,16 @@ namespace Npgsql
}
else
{
- NpgsqlDbType = parameterType; //allow the setter to catch exceptions if necessary.
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(parameterType);
+ if (type_info == null)
+ throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), parameterType));
}
- }
- public NpgsqlParameter(String parameterName, DbType parameterType, Int32 size, String sourceColumn,
- ParameterDirection direction, bool isNullable, byte precision, byte scale,
- DataRowVersion sourceVersion, object value)
- : this(
- parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, size, sourceColumn, direction,
- isNullable, precision, scale, sourceVersion, value)
- {
}
+ public NpgsqlParameter (String parameterName, DbType parameterType, Int32 size, String sourceColumn, ParameterDirection direction, bool isNullable, byte precision, byte scale, DataRowVersion sourceVersion, object value) : this(parameterName, NpgsqlTypesHelper.GetNativeTypeInfo(parameterType).NpgsqlDbType, size, sourceColumn, direction, isNullable, precision, scale, sourceVersion, value)
+ {}
+
// Implementation of IDbDataParameter
/// <summary>
/// Gets or sets the maximum number of digits used to represent the
@@ -262,23 +272,6 @@ namespace Npgsql
precision = value;
}
}
-
-
- public Boolean UseCast
- {
- get
- {
- //return useCast; //&& (value != DBNull.Value);
- // This check for Datetime.minvalue and maxvalue is needed in order to
- // workaround a problem when comparing date values with infinity.
- // This is a known issue with postgresql and it is reported here:
- // http://archives.postgresql.org/pgsql-general/2008-10/msg00535.php
- // Josh's solution to add cast is documented here:
- // http://pgfoundry.org/forum/message.php?msg_id=1004118
-
- return useCast || DateTime.MinValue.Equals(value) || DateTime.MinValue.Equals(value);
- }
- }
/// <summary>
/// Gets or sets the number of decimal places to which
@@ -308,7 +301,7 @@ namespace Npgsql
/// <value>The maximum size, in bytes, of the data within the column.
/// The default value is inferred from the parameter value.</value>
[Category("Data"), DefaultValue(0)]
- public override Int32 Size
+ public Int32 Size
{
get
{
@@ -328,24 +321,22 @@ namespace Npgsql
/// </summary>
/// <value>One of the <see cref="System.Data.DbType">DbType</see> values. The default is <b>String</b>.</value>
[Category("Data"), RefreshProperties(RefreshProperties.All), DefaultValue(DbType.String)]
- public override DbType DbType
+ public DbType DbType
{
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "DbType");
return TypeInfo.DbType;
- } // [TODO] Validate data type.
+ }
+
+ // [TODO] Validate data type.
set
{
-
NpgsqlEventLog.LogPropertySet(LogLevel.Normal, CLASSNAME, "DbType", value);
-
- useCast = value != DbType.Object;
-
- if (!NpgsqlTypesHelper.TryGetNativeTypeInfo(value, out type_info))
- {
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(value);
+ if (type_info == null)
throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), value));
- }
+
}
}
@@ -358,34 +349,30 @@ namespace Npgsql
{
get
{
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "NpgsqlDbType");
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "DbType");
return TypeInfo.NpgsqlDbType;
- } // [TODO] Validate data type.
+ }
+
+ // [TODO] Validate data type.
set
{
- NpgsqlEventLog.LogPropertySet(LogLevel.Normal, CLASSNAME, "NpgsqlDbType", value);
- useCast = true;
- if (value == NpgsqlDbType.Array)
- {
- throw new ArgumentOutOfRangeException(resman.GetString("Exception_ParameterTypeIsOnlyArray"));
- }
- if (!NpgsqlTypesHelper.TryGetNativeTypeInfo(value, out type_info))
- {
+ NpgsqlEventLog.LogPropertySet(LogLevel.Normal, CLASSNAME, "DbType", value);
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(value);
+ if (type_info == null)
throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), value));
- }
+
}
}
+
internal NpgsqlNativeTypeInfo TypeInfo
{
get
{
- if (type_info == null)
- {
- type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
- }
+ if (type_info == null)
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
return type_info;
}
}
@@ -397,7 +384,7 @@ namespace Npgsql
/// <value>One of the <see cref="System.Data.ParameterDirection">ParameterDirection</see>
/// values. The default is <b>Input</b>.</value>
[Category("Data"), DefaultValue(ParameterDirection.Input)]
- public override ParameterDirection Direction
+ public ParameterDirection Direction
{
get
{
@@ -416,12 +403,12 @@ namespace Npgsql
/// Gets or sets a value indicating whether the parameter accepts null values.
/// </summary>
/// <value><b>true</b> if null values are accepted; otherwise, <b>false</b>. The default is <b>false</b>.</value>
-
-#if WITHDESIGN
+
+ #if WITHDESIGN
[EditorBrowsable(EditorBrowsableState.Advanced), Browsable(false), DefaultValue(false), DesignOnly(true)]
-#endif
-
- public override Boolean IsNullable
+ #endif
+
+ public Boolean IsNullable
{
get
{
@@ -437,60 +424,40 @@ namespace Npgsql
}
/// <summary>
- /// Gets or sets the m_Name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.
+ /// Gets or sets the name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.
/// </summary>
- /// <value>The m_Name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.
+ /// <value>The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.
/// The default is an empty string.</value>
[DefaultValue("")]
- public override String ParameterName
+ public String ParameterName
{
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Normal, CLASSNAME, "ParameterName");
- return m_Name;
+ return name;
}
set
{
- m_Name = value;
+ name = value;
if (value == null)
- {
- m_Name = String.Empty;
- }
- // no longer prefix with : so that the m_Name returned is the m_Name set
-
- m_Name = m_Name.Trim();
-
- NpgsqlEventLog.LogPropertySet(LogLevel.Normal, CLASSNAME, "ParameterName", m_Name);
- }
- }
-
- /// <summary>
- /// The m_Name scrubbed of any optional marker
- /// </summary>
- internal string CleanName
- {
- get
- {
- string name = ParameterName;
- if (name[0] == ':' || name[0] == '@')
- {
- return name.Length > 1 ? name.Substring(1) : string.Empty;
- }
- return name;
+ name = String.Empty;
+ if ( (name.Equals(String.Empty)) || ((name[0] != ':') && (name[0] != '@')) )
+ name = ':' + name;
+ NpgsqlEventLog.LogPropertySet(LogLevel.Normal, CLASSNAME, "ParameterName", value);
}
}
/// <summary>
- /// Gets or sets the m_Name of the source column that is mapped to the
+ /// Gets or sets the name of the source column that is mapped to the
/// <see cref="System.Data.DataSet">DataSet</see> and used for loading or
/// returning the <see cref="Npgsql.NpgsqlParameter.Value">Value</see>.
/// </summary>
- /// <value>The m_Name of the source column that is mapped to the
+ /// <value>The name of the source column that is mapped to the
/// <see cref="System.Data.DataSet">DataSet</see>. The default is an empty string.</value>
[Category("Data"), DefaultValue("")]
- public override String SourceColumn
+ public String SourceColumn
{
get
{
@@ -512,7 +479,7 @@ namespace Npgsql
/// <value>One of the <see cref="System.Data.DataRowVersion">DataRowVersion</see> values.
/// The default is <b>Current</b>.</value>
[Category("Data"), DefaultValue(DataRowVersion.Current)]
- public override DataRowVersion SourceVersion
+ public DataRowVersion SourceVersion
{
get
{
@@ -533,69 +500,53 @@ namespace Npgsql
/// <value>An <see cref="System.Object">Object</see> that is the value of the parameter.
/// The default value is null.</value>
[TypeConverter(typeof(StringConverter)), Category("Data")]
- public override Object Value
+ public Object Value
{
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Normal, CLASSNAME, "Value");
return value;
- } // [TODO] Check and validate data type.
+ }
+
+ // [TODO] Check and validate data type.
set
{
NpgsqlEventLog.LogPropertySet(LogLevel.Normal, CLASSNAME, "Value", value);
this.value = value;
- if ((this.value == null) || (this.value == DBNull.Value))
+ if ((this.value == null) || (this.value == DBNull.Value) )
{
// don't really know what to do - leave default and do further exploration
// Default type for null values is String.
this.value = DBNull.Value;
if (type_info == null)
- {
type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
- }
+
}
- else if (type_info == null && !NpgsqlTypesHelper.TryGetNativeTypeInfo(value.GetType(), out type_info))
+ else
{
- throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), value.GetType()));
+ if (type_info == null)
+ {
+ type_info = NpgsqlTypesHelper.GetNativeTypeInfo(value.GetType());
+ if (type_info == null)
+ throw new InvalidCastException(String.Format(resman.GetString("Exception_ImpossibleToCast"), value.GetType()));
+
+ }
+
}
}
}
- public override void ResetDbType()
- {
- type_info = NpgsqlTypesHelper.GetNativeTypeInfo(typeof(String));
- }
-
- public override bool SourceColumnNullMapping
- {
- get { return sourceColumnNullMapping; }
- set { sourceColumnNullMapping = value; }
- }
-
/// <summary>
/// Creates a new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> that
/// is a copy of the current instance.
/// </summary>
/// <returns>A new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> that is a copy of this instance.</returns>
- object ICloneable.Clone()
+ object System.ICloneable.Clone()
{
- // use fields instead of properties
- // to avoid auto-initializing something like type_info
- NpgsqlParameter clone = new NpgsqlParameter();
- clone.precision = precision;
- clone.scale = scale;
- clone.size = size;
- clone.type_info = type_info;
- clone.direction = direction;
- clone.is_nullable = is_nullable;
- clone.m_Name = m_Name;
- clone.source_column = source_column;
- clone.source_version = source_version;
- clone.value = value;
- clone.sourceColumnNullMapping = sourceColumnNullMapping;
-
- return clone;
+ return new NpgsqlParameter(this.ParameterName, this.NpgsqlDbType, this.Size, this.SourceColumn, this.Direction, this.IsNullable, this.Precision, this.Scale, this.SourceVersion, this.Value);
}
+
+
}
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlParameter.resx b/mcs/class/Npgsql/Npgsql/NpgsqlParameter.resx
index f53797bed38..568029414d9 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlParameter.resx
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlParameter.resx
@@ -100,7 +100,4 @@
<data name="Exception_ImpossibleToCast">
<value>Can't cast {0} into any valid DbType.</value>
</data>
- <data name="Exception_ParameterTypeIsOnlyArray">
- <value>Cannot set NpgsqlDbType to just Array, Binary-Or with the element type (e.g. Array of Box is NpgsqlDbType.Array | NpgsqlDbType.Box).</value>
- </data>
-</root>
+</root> \ No newline at end of file
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlParameterCollection.cs b/mcs/class/Npgsql/Npgsql/NpgsqlParameterCollection.cs
index c48c55851ec..03140387ebf 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlParameterCollection.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlParameterCollection.cs
@@ -12,562 +12,466 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
+using System.Reflection;
+using System.Data;
using System.Collections;
-using System.Collections.Generic;
using System.ComponentModel;
-using System.Data.Common;
-using System.Resources;
using NpgsqlTypes;
#if WITHDESIGN
-
+using Npgsql.Design;
#endif
namespace Npgsql
{
- /// <summary>
- /// Represents a collection of parameters relevant to a <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>
- /// as well as their respective mappings to columns in a <see cref="System.Data.DataSet">DataSet</see>.
- /// This class cannot be inherited.
- /// </summary>
-
-#if WITHDESIGN
+ /// <summary>
+ /// Represents a collection of parameters relevant to a <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>
+ /// as well as their respective mappings to columns in a <see cref="System.Data.DataSet">DataSet</see>.
+ /// This class cannot be inherited.
+ /// </summary>
+
+ #if WITHDESIGN
[ListBindable(false)]
[Editor(typeof(NpgsqlParametersEditor), typeof(System.Drawing.Design.UITypeEditor))]
-#endif
-
- public sealed class NpgsqlParameterCollection : DbParameterCollection, IList<NpgsqlParameter>
- {
- private readonly List<NpgsqlParameter> InternalList = new List<NpgsqlParameter>();
-
- // Logging related value
- private static readonly String CLASSNAME = "NpgsqlParameterCollection";
-
- // Our resource manager
- private readonly ResourceManager resman;
-
- /// <summary>
- /// Initializes a new instance of the NpgsqlParameterCollection class.
- /// </summary>
- internal NpgsqlParameterCollection()
- {
- this.resman = new ResourceManager(this.GetType());
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
- }
-
- #region NpgsqlParameterCollection Member
-
- /// <summary>
- /// Gets the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified name.
- /// </summary>
- /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to retrieve.</param>
- /// <value>The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified name, or a null reference if the parameter is not found.</value>
-
-#if WITHDESIGN
+ #endif
+
+ public sealed class NpgsqlParameterCollection : MarshalByRefObject, IDataParameterCollection
+ {
+ private ArrayList InternalList = new ArrayList();
+
+ // Logging related value
+ private static readonly String CLASSNAME = "NpgsqlParameterCollection";
+
+ // Our resource manager
+ private System.Resources.ResourceManager resman;
+
+ /// <summary>
+ /// Initializes a new instance of the NpgsqlParameterCollection class.
+ /// </summary>
+ internal NpgsqlParameterCollection()
+ {
+ this.resman = new System.Resources.ResourceManager(this.GetType());
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+ }
+
+#region NpgsqlParameterCollection Member
+
+ /// <summary>
+ /// Gets the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified name.
+ /// </summary>
+ /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to retrieve.</param>
+ /// <value>The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified name, or a null reference if the parameter is not found.</value>
+
+ #if WITHDESIGN
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-#endif
-
- public new NpgsqlParameter this[string parameterName]
- {
- get
- {
- NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, parameterName);
- return this.InternalList[IndexOf(parameterName)];
- }
- set
- {
- NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, parameterName, value);
- this.InternalList[IndexOf(parameterName)] = value;
- }
- }
-
- /// <summary>
- /// Gets the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> at the specified index.
- /// </summary>
- /// <param name="index">The zero-based index of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to retrieve.</param>
- /// <value>The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> at the specified index.</value>
-
-#if WITHDESIGN
+ #endif
+
+ public NpgsqlParameter this[string parameterName] {
+ get
+ {
+ NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, parameterName);
+ return (NpgsqlParameter)this.InternalList[IndexOf(parameterName)];
+ }
+ set
+ {
+ NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, parameterName, value);
+ this.InternalList[IndexOf(parameterName)] = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> at the specified index.
+ /// </summary>
+ /// <param name="index">The zero-based index of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to retrieve.</param>
+ /// <value>The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> at the specified index.</value>
+
+ #if WITHDESIGN
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-#endif
-
- public new NpgsqlParameter this[int index]
- {
- get
- {
- NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, index);
- return this.InternalList[index];
- }
- set
- {
- NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, index, value);
- this.InternalList[index] = value;
- }
- }
-
- /// <summary>
- /// Adds the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see>.
- /// </summary>
- /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
- /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
- public NpgsqlParameter Add(NpgsqlParameter value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", value);
-
- // Do not allow parameters without name.
-
- this.InternalList.Add(value);
-
- // Check if there is a name. If not, add a name based in the index of parameter.
- if (value.ParameterName.Trim() == String.Empty || (value.ParameterName.Length == 1 && value.ParameterName[0] == ':'))
- {
- value.ParameterName = ":" + "Parameter" + (IndexOf(value) + 1);
- }
-
-
- return value;
- }
-
- /// <summary>
- /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> given the specified parameter name and value.
- /// </summary>
- /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.</param>
- /// <param name="value">The Value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
- /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
- /// <remarks>
- /// Use caution when using this overload of the
- /// <b>Add</b> method to specify integer parameter values.
- /// Because this overload takes a <i>value</i> of type Object,
- /// you must convert the integral value to an <b>Object</b>
- /// type when the value is zero, as the following C# example demonstrates.
- /// <code>parameters.Add(":pname", Convert.ToInt32(0));</code>
- /// If you do not perform this conversion, the compiler will assume you
- /// are attempting to call the NpgsqlParameterCollection.Add(string, DbType) overload.
- /// </remarks>
- public NpgsqlParameter Add(string parameterName, object value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, value);
- return this.Add(new NpgsqlParameter(parameterName, value));
- }
-
- /// <summary>
- /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> given the parameter name and the data type.
- /// </summary>
- /// <param name="parameterName">The name of the parameter.</param>
- /// <param name="parameterType">One of the DbType values.</param>
- /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
- public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType);
- return this.Add(new NpgsqlParameter(parameterName, parameterType));
- }
-
- /// <summary>
- /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> with the parameter name, the data type, and the column length.
- /// </summary>
- /// <param name="parameterName">The name of the parameter.</param>
- /// <param name="parameterType">One of the DbType values.</param>
- /// <param name="size">The length of the column.</param>
- /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
- public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType, size);
- return this.Add(new NpgsqlParameter(parameterName, parameterType, size));
- }
-
- /// <summary>
- /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> with the parameter name, the data type, the column length, and the source column name.
- /// </summary>
- /// <param name="parameterName">The name of the parameter.</param>
- /// <param name="parameterType">One of the DbType values.</param>
- /// <param name="size">The length of the column.</param>
- /// <param name="sourceColumn">The name of the source column.</param>
- /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
- public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size, string sourceColumn)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType, size, sourceColumn);
- return this.Add(new NpgsqlParameter(parameterName, parameterType, size, sourceColumn));
- }
-
- #endregion
-
- #region IDataParameterCollection Member
-
- /// <summary>
- /// Removes the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> from the collection using the parameter name.
- /// </summary>
- /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to retrieve.</param>
- public override void RemoveAt(string parameterName)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "RemoveAt", parameterName);
- this.InternalList.RemoveAt(IndexOf(parameterName));
- }
-
- /// <summary>
- /// Gets a value indicating whether a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified parameter name exists in the collection.
- /// </summary>
- /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
- /// <returns><b>true</b> if the collection contains the parameter; otherwise, <b>false</b>.</returns>
- public override bool Contains(string parameterName)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Contains", parameterName);
- return (IndexOf(parameterName) != -1);
- }
-
- /// <summary>
- /// Gets the location of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> in the collection with a specific parameter name.
- /// </summary>
- /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
- /// <returns>The zero-based location of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> in the collection.</returns>
- public override int IndexOf(string parameterName)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IndexOf", parameterName);
-
- // Iterate values to see what is the index of parameter.
- int index = 0;
- int bestChoose = -1;
- if ((parameterName[0] == ':') || (parameterName[0] == '@'))
- {
- parameterName = parameterName.Remove(0, 1);
- }
-
-
- foreach (NpgsqlParameter parameter in this)
- {
- // allow for optional use of ':' and '@' in the ParameterName property
- string cleanName = parameter.CleanName;
- if(cleanName == parameterName)
- {
- return index;
- }
- if(string.Compare(parameterName, cleanName, StringComparison.InvariantCultureIgnoreCase) == 0)
- {
- bestChoose = index;
- }
- index++;
- }
- return bestChoose;
- }
-
- #endregion
-
- #region IList Member
-
- public override bool IsReadOnly
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsReadOnly");
- return false;
- }
- }
-
- /// <summary>
- /// Removes the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> from the collection using a specific index.
- /// </summary>
- /// <param name="index">The zero-based index of the parameter.</param>
- public override void RemoveAt(int index)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "RemoveAt", index);
- this.InternalList.RemoveAt(index);
- }
-
- /// <summary>
- /// Inserts a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> into the collection at the specified index.
- /// </summary>
- /// <param name="index">The zero-based index where the parameter is to be inserted within the collection.</param>
- /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
- public override void Insert(int index, object value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Insert", index, value);
- CheckType(value);
- this.InternalList.Insert(index, (NpgsqlParameter) value);
- }
-
- /// <summary>
- /// Removes the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> from the collection.
- /// </summary>
- /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to remove from the collection.</param>
- public override void Remove(object value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Remove", value);
- CheckType(value);
- this.InternalList.Remove((NpgsqlParameter) value);
- }
-
- /// <summary>
- /// Gets a value indicating whether a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> exists in the collection.
- /// </summary>
- /// <param name="value">The value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
- /// <returns>true if the collection contains the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object; otherwise, false.</returns>
- public override bool Contains(object value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Contains", value);
- if (!(value is NpgsqlParameter))
- {
- return false;
- }
- return this.InternalList.Contains((NpgsqlParameter) value);
- }
-
-
- /// <summary>
- /// Gets a value indicating whether a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified parameter name exists in the collection.
- /// </summary>
- /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
- /// <param name="parameter">A reference to the requested parameter is returned in this out param if it is found in the list. This value is null if the parameter is not found.</param>
- /// <returns><b>true</b> if the collection contains the parameter and param will contain the parameter; otherwise, <b>false</b>.</returns>
- public bool TryGetValue(string parameterName, out NpgsqlParameter parameter)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "TryGetValue", parameterName);
-
- int index = IndexOf(parameterName);
-
- if (index != -1)
- {
- parameter = this[index];
-
- return true;
- }
-
- else
- {
- parameter = null;
-
- return false;
- }
- }
-
-
- /// <summary>
- /// Removes all items from the collection.
- /// </summary>
- public override void Clear()
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Clear");
- this.InternalList.Clear();
- }
-
- /// <summary>
- /// Gets the location of a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> in the collection.
- /// </summary>
- /// <param name="value">The value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
- /// <returns>The zero-based index of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object in the collection.</returns>
- public override int IndexOf(object value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IndexOf", value);
- CheckType(value);
- return this.InternalList.IndexOf((NpgsqlParameter) value);
- }
-
- /// <summary>
- /// Adds the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see>.
- /// </summary>
- /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
- /// <returns>The zero-based index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
- public override int Add(object value)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", value);
- CheckType(value);
- this.Add((NpgsqlParameter) value);
- return IndexOf(value);
- }
-
- public override bool IsFixedSize
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsFixedSize");
- return false;
- }
- }
-
- #endregion
-
- #region ICollection Member
-
- public override bool IsSynchronized
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsSynchronized");
- return (InternalList as ICollection).IsSynchronized;
- }
- }
-
- /// <summary>
- /// Gets the number of <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects in the collection.
- /// </summary>
- /// <value>The number of <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects in the collection.</value>
-
-#if WITHDESIGN
+ #endif
+
+ public NpgsqlParameter this[int index] {
+ get
+ {
+ NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, index);
+ return (NpgsqlParameter)this.InternalList[index];
+ }
+ set
+ {
+ NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, index, value);
+ this.InternalList[index] = value;
+ }
+ }
+
+ /// <summary>
+ /// Adds the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see>.
+ /// </summary>
+ /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
+ /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
+ public NpgsqlParameter Add(NpgsqlParameter value)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", value);
+
+ // Do not allow parameters without name.
+
+ this.InternalList.Add(value);
+
+ // Check if there is a name. If not, add a name based in the index of parameter.
+ if (value.ParameterName.Trim() == String.Empty ||
+ (value.ParameterName.Length == 1 && value.ParameterName[0] == ':'))
+ value.ParameterName = ":" + "Parameter" + (IndexOf(value) + 1);
+
+
+ return value;
+ }
+
+ /// <summary>
+ /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> given the specified parameter name and value.
+ /// </summary>
+ /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>.</param>
+ /// <param name="value">The Value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
+ /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
+ /// <remarks>
+ /// Use caution when using this overload of the
+ /// <b>Add</b> method to specify integer parameter values.
+ /// Because this overload takes a <i>value</i> of type Object,
+ /// you must convert the integral value to an <b>Object</b>
+ /// type when the value is zero, as the following C# example demonstrates.
+ /// <code>parameters.Add(":pname", Convert.ToInt32(0));</code>
+ /// If you do not perform this conversion, the compiler will assume you
+ /// are attempting to call the NpgsqlParameterCollection.Add(string, DbType) overload.
+ /// </remarks>
+ public NpgsqlParameter Add(string parameterName, object value)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, value);
+ return this.Add(new NpgsqlParameter(parameterName, value));
+ }
+
+ /// <summary>
+ /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> given the parameter name and the data type.
+ /// </summary>
+ /// <param name="parameterName">The name of the parameter.</param>
+ /// <param name="parameterType">One of the DbType values.</param>
+ /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
+ public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType);
+ return this.Add(new NpgsqlParameter(parameterName, parameterType));
+ }
+
+ /// <summary>
+ /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> with the parameter name, the data type, and the column length.
+ /// </summary>
+ /// <param name="parameterName">The name of the parameter.</param>
+ /// <param name="parameterType">One of the DbType values.</param>
+ /// <param name="size">The length of the column.</param>
+ /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
+ public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType, size);
+ return this.Add(new NpgsqlParameter(parameterName, parameterType, size));
+ }
+
+ /// <summary>
+ /// Adds a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> with the parameter name, the data type, the column length, and the source column name.
+ /// </summary>
+ /// <param name="parameterName">The name of the parameter.</param>
+ /// <param name="parameterType">One of the DbType values.</param>
+ /// <param name="size">The length of the column.</param>
+ /// <param name="sourceColumn">The name of the source column.</param>
+ /// <returns>The index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
+ public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size, string sourceColumn)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType, size, sourceColumn);
+ return this.Add(new NpgsqlParameter(parameterName, parameterType, size, sourceColumn));
+ }
+
+#endregion
+
+#region IDataParameterCollection Member
+
+ object System.Data.IDataParameterCollection.this[string parameterName] {
+ get
+ {
+ NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, parameterName);
+ return this.InternalList[IndexOf(parameterName)];
+ }
+ set
+ {
+ NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, parameterName, value);
+ CheckType(value);
+ this.InternalList[IndexOf(parameterName)] = value;
+ }
+ }
+
+ /// <summary>
+ /// Removes the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> from the collection using the parameter name.
+ /// </summary>
+ /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to retrieve.</param>
+ public void RemoveAt(string parameterName)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "RemoveAt", parameterName);
+ this.InternalList.RemoveAt(IndexOf(parameterName));
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified parameter name exists in the collection.
+ /// </summary>
+ /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
+ /// <returns><b>true</b> if the collection contains the parameter; otherwise, <b>false</b>.</returns>
+ public bool Contains(string parameterName)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Contains", parameterName);
+ return (IndexOf(parameterName) != -1);
+ }
+
+ /// <summary>
+ /// Gets the location of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> in the collection with a specific parameter name.
+ /// </summary>
+ /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
+ /// <returns>The zero-based location of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> in the collection.</returns>
+ public int IndexOf(string parameterName)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IndexOf", parameterName);
+
+ // Iterate values to see what is the index of parameter.
+ Int32 index = 0;
+ if ((parameterName[0] == ':') || (parameterName[0] == '@'))
+ parameterName = parameterName.Remove(0, 1);
+
+ foreach (NpgsqlParameter parameter in this)
+ {
+ if (parameter.ParameterName.Remove(0, 1) == parameterName)
+ return index;
+ index++;
+ }
+ return -1;
+ }
+
+#endregion
+
+#region IList Member
+
+ bool IList.IsReadOnly {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsReadOnly");
+ return this.InternalList.IsReadOnly;
+ }
+ }
+
+ object System.Collections.IList.this[int index] {
+ get
+ {
+ NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, index);
+ return (NpgsqlParameter)this.InternalList[index];
+ }
+ set
+ {
+ NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, index, value);
+ CheckType(value);
+ this.InternalList[index] = value;
+ }
+ }
+
+ /// <summary>
+ /// Removes the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> from the collection using a specific index.
+ /// </summary>
+ /// <param name="index">The zero-based index of the parameter.</param>
+ public void RemoveAt(int index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "RemoveAt", index);
+ this.InternalList.RemoveAt(index);
+ }
+
+ /// <summary>
+ /// Inserts a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> into the collection at the specified index.
+ /// </summary>
+ /// <param name="index">The zero-based index where the parameter is to be inserted within the collection.</param>
+ /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
+ public void Insert(int index, object value)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Insert", index, value);
+ CheckType(value);
+ this.InternalList.Insert(index, value);
+ }
+
+ /// <summary>
+ /// Removes the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> from the collection.
+ /// </summary>
+ /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to remove from the collection.</param>
+ public void Remove(object value)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Remove", value);
+ CheckType(value);
+ this.InternalList.Remove(value);
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> exists in the collection.
+ /// </summary>
+ /// <param name="value">The value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
+ /// <returns>true if the collection contains the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object; otherwise, false.</returns>
+ public bool Contains(object value)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Contains", value);
+ CheckType(value);
+ return this.InternalList.Contains(value);
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> with the specified parameter name exists in the collection.
+ /// </summary>
+ /// <param name="parameterName">The name of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
+ /// <param name="parameter">A reference to the requested parameter is returned in this out param if it is found in the list. This value is null if the parameter is not found.</param>
+ /// <returns><b>true</b> if the collection contains the parameter and param will contain the parameter; otherwise, <b>false</b>.</returns>
+ public bool TryGetValue(string parameterName, out NpgsqlParameter parameter)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "TryGetValue", parameterName);
+ int index = IndexOf(parameterName);
+ if (index != -1)
+ {
+ parameter = this[index];
+ return true;
+ }
+ else
+ {
+ parameter = null;
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Removes all items from the collection.
+ /// </summary>
+ public void Clear()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Clear");
+ this.InternalList.Clear();
+ }
+
+ /// <summary>
+ /// Gets the location of a <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> in the collection.
+ /// </summary>
+ /// <param name="value">The value of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to find.</param>
+ /// <returns>The zero-based index of the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object in the collection.</returns>
+ public int IndexOf(object value)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IndexOf", value);
+ CheckType(value);
+ return this.InternalList.IndexOf(value);
+ }
+
+ /// <summary>
+ /// Adds the specified <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object to the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see>.
+ /// </summary>
+ /// <param name="value">The <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> to add to the collection.</param>
+ /// <returns>The zero-based index of the new <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> object.</returns>
+ public int Add(object value)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", value);
+ CheckType(value);
+ this.Add((NpgsqlParameter)value);
+ return IndexOf(value);
+ }
+
+ bool IList.IsFixedSize {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsFixedSize");
+ return this.InternalList.IsFixedSize;
+ }
+ }
+
+#endregion
+
+#region ICollection Member
+
+ bool ICollection.IsSynchronized {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsSynchronized");
+ return this.InternalList.IsSynchronized;
+ }
+ }
+
+ /// <summary>
+ /// Gets the number of <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects in the collection.
+ /// </summary>
+ /// <value>The number of <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects in the collection.</value>
+
+ #if WITHDESIGN
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
-#endif
-
- public override int Count
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Count");
- return this.InternalList.Count;
- }
- }
-
- /// <summary>
- /// Copies <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects from the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> to the specified array.
- /// </summary>
- /// <param name="array">An <see cref="System.Array">Array</see> to which to copy the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects in the collection.</param>
- /// <param name="index">The starting index of the array.</param>
- public override void CopyTo(Array array, int index)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CopyTo", array, index);
- (InternalList as ICollection).CopyTo(array, index);
- IRaiseItemChangedEvents x = InternalList as IRaiseItemChangedEvents;
- }
-
- public override object SyncRoot
- {
- get
- {
- NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "SyncRoot");
- return (InternalList as ICollection).SyncRoot;
- }
- }
-
- #endregion
-
- #region IEnumerable Member
-
- /// <summary>
- /// Returns an enumerator that can iterate through the collection.
- /// </summary>
- /// <returns>An <see cref="System.Collections.IEnumerator">IEnumerator</see> that can be used to iterate through the collection.</returns>
- public override IEnumerator GetEnumerator()
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetEnumerator");
- return this.InternalList.GetEnumerator();
- }
-
- #endregion
-
- public override void AddRange(Array values)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "AddRange", values);
- foreach (NpgsqlParameter parameter in values)
- {
- Add(parameter);
- }
- }
-
- protected override DbParameter GetParameter(string parameterName)
- {
- return this[parameterName];
- }
-
- protected override DbParameter GetParameter(int index)
- {
- return this[index];
- }
-
- protected override void SetParameter(string parameterName, DbParameter value)
- {
- this[parameterName] = (NpgsqlParameter) value;
- }
-
- protected override void SetParameter(int index, DbParameter value)
- {
- this[index] = (NpgsqlParameter) value;
- }
-
- /// <summary>
- /// In methods taking an object as argument this method is used to verify
- /// that the argument has the type <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>
- /// </summary>
- /// <param name="Object">The object to verify</param>
- private void CheckType(object Object)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckType", Object);
- if (!(Object is NpgsqlParameter))
- {
- throw new InvalidCastException(
- String.Format(this.resman.GetString("Exception_WrongType"), Object.GetType()));
- }
- }
-
-/*
- /// <summary>
- /// In methods taking an array as argument this method is used to verify
- /// that the argument has the type <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>[]
- /// </summary>
- /// <param name="array">The array to verify</param>
- private void CheckType(Array array)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckType", array);
- if (array.GetType() != typeof (NpgsqlParameter[]))
- {
- throw new InvalidCastException(
- String.Format(this.resman.GetString("Exception_WrongType"), array.GetType().ToString()));
- }
- }
-*/
-
- NpgsqlParameter IList<NpgsqlParameter>.this[int index]
- {
- get { return InternalList[index]; }
- set { InternalList[index] = value; }
- }
-
- public int IndexOf(NpgsqlParameter item)
- {
- return InternalList.IndexOf(item);
- }
-
- public void Insert(int index, NpgsqlParameter item)
- {
- InternalList.Insert(index, item);
- }
-
- public bool Contains(NpgsqlParameter item)
- {
- return InternalList.Contains(item);
- }
-
- public bool Remove(NpgsqlParameter item)
- {
- return Remove(item);
- }
-
- IEnumerator<NpgsqlParameter> IEnumerable<NpgsqlParameter>.GetEnumerator()
- {
- return InternalList.GetEnumerator();
- }
-
- public void CopyTo(NpgsqlParameter[] array, int arrayIndex)
- {
- InternalList.CopyTo(array, arrayIndex);
- }
-
- void ICollection<NpgsqlParameter>.Add(NpgsqlParameter item)
- {
- Add(item);
- }
- }
+ #endif
+
+ public int Count {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Count");
+ return this.InternalList.Count;
+ }
+ }
+
+ /// <summary>
+ /// Copies <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects from the <see cref="Npgsql.NpgsqlParameterCollection">NpgsqlParameterCollection</see> to the specified array.
+ /// </summary>
+ /// <param name="array">An <see cref="System.Array">Array</see> to which to copy the <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see> objects in the collection.</param>
+ /// <param name="index">The starting index of the array.</param>
+ public void CopyTo(Array array, int index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CopyTo", array, index);
+ this.InternalList.CopyTo(array, index);
+ }
+
+ object ICollection.SyncRoot {
+ get
+ {
+ NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "SyncRoot");
+ return this.InternalList.SyncRoot;
+ }
+ }
+
+#endregion
+
+#region IEnumerable Member
+
+ /// <summary>
+ /// Returns an enumerator that can iterate through the collection.
+ /// </summary>
+ /// <returns>An <see cref="System.Collections.IEnumerator">IEnumerator</see> that can be used to iterate through the collection.</returns>
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetEnumerator");
+ return this.InternalList.GetEnumerator();
+ }
+
+#endregion
+
+ /// <summary>
+ /// In methods taking an object as argument this method is used to verify
+ /// that the argument has the type <see cref="Npgsql.NpgsqlParameter">NpgsqlParameter</see>
+ /// </summary>
+ /// <param name="Object">The object to verify</param>
+ private void CheckType(object Object)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckType", Object);
+ if(Object.GetType() != typeof(NpgsqlParameter))
+ throw new InvalidCastException(String.Format(this.resman.GetString("Exception_WrongType"), Object.GetType().ToString()));
+ }
+
+ }
}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlParameterStatus.cs b/mcs/class/Npgsql/Npgsql/NpgsqlParameterStatus.cs
index 56fa029cd19..6df8f7ef285 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlParameterStatus.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlParameterStatus.cs
@@ -8,43 +8,76 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
+using System.Collections;
using System.IO;
+using System.Text;
+using System.Net;
+using NpgsqlTypes;
+
namespace Npgsql
{
- /// <summary>
- /// This class represents the ParameterStatus message sent from PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlParameterStatus
- {
- public readonly string Parameter;
- public readonly string ParameterValue;
-
- public NpgsqlParameterStatus(Stream stream)
- {
- //Read message length
- PGUtil.EatStreamBytes(stream, 4);
- Parameter = PGUtil.ReadString(stream);
- ParameterValue = PGUtil.ReadString(stream);
- }
- }
-} \ No newline at end of file
+
+ /// <summary>
+ /// This class represents the ParameterStatus message sent from PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlParameterStatus
+ {
+
+ private String _parameter;
+ private String _parameterValue;
+
+
+ public void ReadFromStream(Stream inputStream, Encoding encoding)
+ {
+
+ //Read message length
+ Byte[] inputBuffer = new Byte[4];
+ PGUtil.CheckedStreamRead(inputStream, inputBuffer, 0, 4 );
+
+ Int32 messageLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 0));
+
+ _parameter = PGUtil.ReadString(inputStream, encoding);
+ _parameterValue = PGUtil.ReadString(inputStream, encoding);
+
+
+ }
+
+ public String Parameter
+ {
+ get
+ {
+ return _parameter;
+ }
+ }
+
+ public String ParameterValue
+ {
+ get
+ {
+ return _parameterValue;
+ }
+ }
+
+
+ }
+
+
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlParse.cs b/mcs/class/Npgsql/Npgsql/NpgsqlParse.cs
index 059d12e94dc..129a266a068 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlParse.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlParse.cs
@@ -9,74 +9,79 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
+using System.Collections;
using System.IO;
+using System.Text;
+using System.Net;
+using NpgsqlTypes;
+
namespace Npgsql
{
- /// <summary>
- /// This class represents the Parse message sent to PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlParse : ClientMessage
- {
- // Logging related values
- //private static readonly String CLASSNAME = "NpgsqlParse";
-
- private readonly String _prepareName;
- private readonly String _queryString;
- private readonly Int32[] _parameterIDs;
-
-
- public NpgsqlParse(String prepareName, String queryString, Int32[] parameterIDs)
- {
- _prepareName = prepareName;
- _queryString = queryString;
- _parameterIDs = parameterIDs;
- }
-
- public override void WriteToStream(Stream outputStream)
- {
- outputStream.WriteByte((byte) FrontEndMessageCode.Parse);
-
- // message length =
- // Int32 self
- // name of prepared statement + 1 null string terminator +
- // query string + 1 null string terminator
- // + Int16
- // + Int32 * number of parameters.
- Int32 messageLength = 4 + UTF8Encoding.GetByteCount(_prepareName) + 1 + UTF8Encoding.GetByteCount(_queryString) + 1 +
- 2 + (_parameterIDs.Length*4);
- //Int32 messageLength = 4 + _prepareName.Length + 1 + _queryString.Length + 1 + 2 + (_parameterIDs.Length * 4);
-
- PGUtil.WriteInt32(outputStream, messageLength);
- PGUtil.WriteString(_prepareName, outputStream);
- PGUtil.WriteString(_queryString, outputStream);
- PGUtil.WriteInt16(outputStream, (Int16) _parameterIDs.Length);
-
-
- for (Int32 i = 0; i < _parameterIDs.Length; i++)
- {
- PGUtil.WriteInt32(outputStream, _parameterIDs[i]);
- }
- }
- }
-} \ No newline at end of file
+
+ /// <summary>
+ /// This class represents the Parse message sent to PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlParse
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlParse";
+
+ private String _prepareName;
+ private String _queryString;
+ private Int32[] _parameterIDs;
+
+
+ public NpgsqlParse(String prepareName, String queryString, Int32[] parameterIDs)
+ {
+ _prepareName = prepareName;
+ _queryString = queryString;
+ _parameterIDs = parameterIDs;
+
+ }
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+ outputStream.WriteByte((Byte)'P');
+
+ // message length =
+ // Int32 self
+ // name of prepared statement + 1 null string terminator +
+ // query string + 1 null string terminator
+ // + Int16
+ // + Int32 * number of parameters.
+ Int32 messageLength = 4 + encoding.GetByteCount(_prepareName) + 1 + encoding.GetByteCount(_queryString) + 1 + 2 + (_parameterIDs.Length * 4);
+ //Int32 messageLength = 4 + _prepareName.Length + 1 + _queryString.Length + 1 + 2 + (_parameterIDs.Length * 4);
+
+ PGUtil.WriteInt32(outputStream, messageLength);
+ PGUtil.WriteString(_prepareName, outputStream, encoding);
+ PGUtil.WriteString(_queryString, outputStream, encoding);
+ PGUtil.WriteInt16(outputStream, (Int16)_parameterIDs.Length);
+
+
+ for(Int32 i = 0; i < _parameterIDs.Length; i++)
+ PGUtil.WriteInt32(outputStream, _parameterIDs[i]);
+
+
+
+
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlPasswordPacket.cs b/mcs/class/Npgsql/Npgsql/NpgsqlPasswordPacket.cs
index 2eb14dc4c0a..5b9f498bead 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlPasswordPacket.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlPasswordPacket.cs
@@ -10,76 +10,75 @@
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Text;
+using System.Net;
namespace Npgsql
{
- /// <summary>
- /// This class represents a PasswordPacket message sent to backend
- /// PostgreSQL.
- /// </summary>
- internal sealed class NpgsqlPasswordPacket : ClientMessage
- {
- // Logging related values
- private static readonly String CLASSNAME = "NpgsqlPasswordPacket";
-
- private readonly String password;
- private readonly ProtocolVersion protocolVersion;
-
-
- public NpgsqlPasswordPacket(String password, ProtocolVersion protocolVersion)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
-
- this.password = password;
- this.protocolVersion = protocolVersion;
- }
-
- public override void WriteToStream(Stream outputStream)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream");
-
- switch (protocolVersion)
- {
- case ProtocolVersion.Version2:
- // Write the size of the packet.
- // 4 + (passwordlength + 1) -> Int32 + NULL terminated string.
- // output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(4 + (password.Length + 1))), 0, 4);
- PGUtil.WriteInt32(outputStream, 4 + UTF8Encoding.GetByteCount(password) + 1);
-
- // Write String.
- PGUtil.WriteString(password, outputStream);
-
- break;
-
- case ProtocolVersion.Version3:
- outputStream.WriteByte((Byte) 'p');
- PGUtil.WriteInt32(outputStream, 4 + UTF8Encoding.GetByteCount(password) + 1);
-
- // Write String.
- PGUtil.WriteString(password, outputStream);
-
- break;
- }
- }
- }
-} \ No newline at end of file
+ /// <summary>
+ /// This class represents a PasswordPacket message sent to backend
+ /// PostgreSQL.
+ /// </summary>
+ internal sealed class NpgsqlPasswordPacket
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlPasswordPacket";
+
+ private String password;
+ private ProtocolVersion protocolVersion;
+
+
+ public NpgsqlPasswordPacket(String password, ProtocolVersion protocolVersion)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+
+ this.password = password;
+ this.protocolVersion = protocolVersion;
+ }
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream");
+
+ switch (protocolVersion) {
+ case ProtocolVersion.Version2 :
+ // Write the size of the packet.
+ // 4 + (passwordlength + 1) -> Int32 + NULL terminated string.
+ // output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(4 + (password.Length + 1))), 0, 4);
+ PGUtil.WriteInt32(outputStream, 4 + encoding.GetByteCount(password) + 1);
+
+ // Write String.
+ PGUtil.WriteString(password, outputStream, encoding);
+
+ break;
+
+ case ProtocolVersion.Version3 :
+ outputStream.WriteByte((Byte)'p');
+ PGUtil.WriteInt32(outputStream, 4 + encoding.GetByteCount(password) + 1);
+
+ // Write String.
+ PGUtil.WriteString(password, outputStream, encoding);
+
+ break;
+
+ }
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs b/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs
index b74abfa0197..a8818ea89b0 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlQuery.cs
@@ -7,67 +7,68 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Text;
+using System.Net.Sockets;
namespace Npgsql
{
- /// <summary>
- /// Summary description for NpgsqlQuery
- /// </summary>
- internal sealed class NpgsqlQuery : ClientMessage
- {
- private readonly NpgsqlCommand _command;
- private readonly ProtocolVersion _protocolVersion;
-
- public NpgsqlQuery(NpgsqlCommand command, ProtocolVersion protocolVersion)
- {
- _command = command;
- _protocolVersion = protocolVersion;
- }
+ /// <summary>
+ /// Summary description for NpgsqlQuery
+ /// </summary>
+ internal sealed class NpgsqlQuery
+ {
+ private NpgsqlCommand _command;
+ private ProtocolVersion _protocolVersion;
- public override void WriteToStream(Stream outputStream)
- {
- //NpgsqlEventLog.LogMsg( this.ToString() + _commandText, LogLevel.Debug );
+ public NpgsqlQuery(NpgsqlCommand command, ProtocolVersion protocolVersion)
+ {
+ _command = command;
+ _protocolVersion = protocolVersion;
+ }
+ public void WriteToStream( Stream outputStream, Encoding encoding )
+ {
+ //NpgsqlEventLog.LogMsg( this.ToString() + _commandText, LogLevel.Debug );
- String commandText = _command.GetCommandText();
- // Tell to mediator what command is being sent.
+ 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');
- _command.Connector.Mediator.SqlSent = commandText;
+ if (_protocolVersion == ProtocolVersion.Version3)
+ {
+ // Write message length. Int32 + string length + null terminator.
+ PGUtil.WriteInt32(outputStream, 4 + encoding.GetByteCount(commandText) + 1);
+ }
- // Send the query to server.
- // Write the byte 'Q' to identify a query message.
- outputStream.WriteByte((byte) FrontEndMessageCode.Query);
+ // Write the query. In this case it is the CommandText text.
+ // It is a string terminated by a C NULL character.
+ PGUtil.WriteString(commandText, outputStream, encoding);
+ }
- if (_protocolVersion == ProtocolVersion.Version3)
- {
- // Write message length. Int32 + string length + null terminator.
- PGUtil.WriteInt32(outputStream, 4 + UTF8Encoding.GetByteCount(commandText) + 1);
- }
- // Write the query. In this case it is the CommandText text.
- // It is a string terminated by a C NULL character.
- PGUtil.WriteString(commandText, outputStream);
- }
- }
-} \ No newline at end of file
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs
index 1dec93216ac..0676480c57a 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlReadyState.cs
@@ -7,151 +7,151 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Collections.Generic;
using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Resources;
namespace Npgsql
{
- internal sealed class NpgsqlReadyState : NpgsqlState
- {
- public static readonly NpgsqlReadyState Instance = new NpgsqlReadyState();
-
-
- // Flush and Sync messages. It doesn't need to be created every time it is called.
- private static readonly NpgsqlFlush _flushMessage = new NpgsqlFlush();
-
- private static readonly NpgsqlSync _syncMessage = new NpgsqlSync();
-
- private readonly String CLASSNAME = "NpgsqlReadyState";
-
- private NpgsqlReadyState()
- : base()
- {
- }
-
- public override IEnumerable<IServerResponseObject> QueryEnum(NpgsqlConnector context, NpgsqlCommand command)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "QueryEnum");
-
-
- //String commandText = command.GetCommandText();
- //NpgsqlEventLog.LogMsg(resman, "Log_QuerySent", LogLevel.Debug, commandText);
-
- // Send the query request to backend.
-
- NpgsqlQuery query = new NpgsqlQuery(command, context.BackendProtocolVersion);
-
- query.WriteToStream(context.Stream);
- context.Stream.Flush();
-
- return ProcessBackendResponsesEnum(context);
- }
-
- public override void Parse(NpgsqlConnector context, NpgsqlParse parse)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Parse");
-
- Stream stream = context.Stream;
- parse.WriteToStream(stream);
- //stream.Flush();
- }
-
-
- public override IEnumerable<IServerResponseObject> SyncEnum(NpgsqlConnector context)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Sync");
- _syncMessage.WriteToStream(context.Stream);
- context.Stream.Flush();
- return ProcessBackendResponsesEnum(context);
- }
-
- public override void Flush(NpgsqlConnector context)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Flush");
- _flushMessage.WriteToStream(context.Stream);
- context.Stream.Flush();
- ProcessBackendResponses(context);
- }
-
- public override void Bind(NpgsqlConnector context, NpgsqlBind bind)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Bind");
-
- Stream stream = context.Stream;
-
- bind.WriteToStream(stream);
- //stream.Flush();
- }
-
- public override void Describe(NpgsqlConnector context, NpgsqlDescribe describe)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Describe");
- describe.WriteToStream(context.Stream);
- //context.Stream.Flush();
- }
-
- public override void Execute(NpgsqlConnector context, NpgsqlExecute execute)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Execute");
- NpgsqlDescribe describe = new NpgsqlDescribe('P', execute.PortalName);
- Stream stream = context.Stream;
- describe.WriteToStream(stream);
- execute.WriteToStream(stream);
- //stream.Flush();
- Sync(context);
- }
-
- public override IEnumerable<IServerResponseObject> ExecuteEnum(NpgsqlConnector context, NpgsqlExecute execute)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Execute");
- NpgsqlDescribe describe = new NpgsqlDescribe('P', execute.PortalName);
- Stream stream = context.Stream;
- describe.WriteToStream(stream);
- execute.WriteToStream(stream);
- //stream.Flush();
- return SyncEnum(context);
- }
-
- public override void Close(NpgsqlConnector context)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
- Stream stream = context.Stream;
- stream.WriteByte((byte) FrontEndMessageCode.Termination);
- if (context.BackendProtocolVersion >= ProtocolVersion.Version3)
- {
- PGUtil.WriteInt32(stream, 4);
- }
- stream.Flush();
-
- try
- {
- stream.Close();
- }
- catch
- {
- }
-
- context.Stream = null;
- ChangeState(context, NpgsqlClosedState.Instance);
- }
- }
-} \ No newline at end of file
+
+
+ internal sealed class NpgsqlReadyState : NpgsqlState
+ {
+ private static NpgsqlReadyState _instance = new NpgsqlReadyState();
+
+
+ // Flush and Sync messages. It doesn't need to be created every time it is called.
+ private static readonly NpgsqlFlush _flushMessage = new NpgsqlFlush();
+
+ private static readonly NpgsqlSync _syncMessage = new NpgsqlSync();
+
+ private readonly String CLASSNAME = "NpgsqlReadyState";
+
+ private NpgsqlReadyState() : base()
+ { }
+
+ public static NpgsqlReadyState Instance
+ {
+ get
+ {
+ return _instance;
+ }
+ }
+
+
+
+ public override void Query( NpgsqlConnector context, NpgsqlCommand command )
+ {
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Query");
+
+
+
+ //String commandText = command.GetCommandText();
+ //NpgsqlEventLog.LogMsg(resman, "Log_QuerySent", LogLevel.Debug, commandText);
+
+ // Send the query request to backend.
+
+ NpgsqlQuery query = new NpgsqlQuery(command, context.BackendProtocolVersion);
+
+ query.WriteToStream(context.Stream, context.Encoding);
+ context.Stream.Flush();
+
+ ProcessBackendResponses(context);
+
+ }
+
+ public override void Parse(NpgsqlConnector context, NpgsqlParse parse)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Parse");
+
+ Stream stream = context.Stream;
+ parse.WriteToStream(stream, context.Encoding);
+ //stream.Flush();
+ }
+
+
+ public override void Sync(NpgsqlConnector context)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Sync");
+ _syncMessage.WriteToStream(context.Stream, context.Encoding);
+ context.Stream.Flush();
+ ProcessBackendResponses(context);
+ }
+
+ public override void Flush(NpgsqlConnector context)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Flush");
+ _flushMessage.WriteToStream(context.Stream, context.Encoding);
+ context.Stream.Flush();
+ ProcessBackendResponses(context);
+ }
+
+ public override void Bind(NpgsqlConnector context, NpgsqlBind bind)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Bind");
+
+ Stream stream = context.Stream;
+
+ bind.WriteToStream(stream, context.Encoding);
+ //stream.Flush();
+
+ }
+
+ public override void Describe(NpgsqlConnector context, NpgsqlDescribe describe)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Describe");
+ describe.WriteToStream(context.Stream, context.Encoding);
+ //context.Stream.Flush();
+ }
+
+ public override void Execute(NpgsqlConnector context, NpgsqlExecute execute)
+ {
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Execute");
+ NpgsqlDescribe describe = new NpgsqlDescribe('P', execute.PortalName);
+ Stream stream = context.Stream;
+ describe.WriteToStream(stream, context.Encoding);
+ execute.WriteToStream(stream, context.Encoding);
+ //stream.Flush();
+ Sync(context);
+ }
+
+ public override void Close( NpgsqlConnector context )
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
+ Stream stream = context.Stream;
+ stream.WriteByte((Byte)'X');
+ if (context.BackendProtocolVersion >= ProtocolVersion.Version3)
+ PGUtil.WriteInt32(stream, 4);
+ stream.Flush();
+
+ try
+ {
+ stream.Close();
+ }
+ catch {}
+
+ context.Stream = null;
+ ChangeState( context, NpgsqlClosedState.Instance )
+ ;
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlRow.cs b/mcs/class/Npgsql/Npgsql/NpgsqlRow.cs
index 79c2da8dc4b..848d682066e 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlRow.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlRow.cs
@@ -9,473 +9,70 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Collections.Generic;
+using System.Collections;
using System.IO;
-using System.Reflection;
-using System.Resources;
using System.Text;
+using System.Net;
using NpgsqlTypes;
+
namespace Npgsql
{
- /// <summary>
- /// This is the abstract base class for NpgsqlAsciiRow and NpgsqlBinaryRow.
- /// </summary>
- internal abstract class NpgsqlRow : IStreamOwner
- {
- protected static readonly ResourceManager resman = new ResourceManager(MethodBase.GetCurrentMethod().DeclaringType);
- public abstract object this[int index] { get; }
- public abstract int NumFields { get; }
- public abstract bool IsDBNull(int index);
- public abstract void Dispose();
- public abstract long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length);
- public abstract long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length);
- }
-
- internal sealed class CachingRow : NpgsqlRow
- {
- private readonly List<object> _data = new List<object>();
- private readonly ForwardsOnlyRow _inner;
-
- public CachingRow(ForwardsOnlyRow fo)
- {
- _inner = fo;
- }
-
- public override object this[Int32 index]
- {
- get
- {
- if ((index < 0) || (index >= NumFields))
- {
- throw new IndexOutOfRangeException("this[] index value");
- }
- while (_data.Count <= index)
- {
- _data.Add(_inner[_data.Count]);
- }
- return _data[index];
- }
- }
-
- public override int NumFields
- {
- get { return _inner.NumFields; }
- }
-
- public override bool IsDBNull(int index)
- {
- return this[index] == DBNull.Value;
- }
-
- public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
- {
- byte[] source = (byte[]) this[i];
- if (buffer == null)
- {
- return source.Length - fieldOffset;
- }
- long finalLength = Math.Max(0, Math.Min(length, source.Length - fieldOffset));
- Array.Copy(source, fieldOffset, buffer, bufferoffset, finalLength);
- return finalLength;
- }
-
- public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
- {
- string source = (string) this[i];
- if (buffer == null)
- {
- return source.Length - fieldoffset;
- }
- long finalLength = Math.Max(0, Math.Min(length, source.Length - fieldoffset));
- Array.Copy(source.ToCharArray(), fieldoffset, buffer, bufferoffset, finalLength);
- return finalLength;
- }
-
- public override void Dispose()
- {
- _inner.Dispose();
- }
- }
-
- internal sealed class ForwardsOnlyRow : NpgsqlRow
- {
- private int _lastIndex = -1;
- private readonly RowReader _reader;
-
- public ForwardsOnlyRow(RowReader reader)
- {
- _reader = reader;
- }
-
- private void SetIndex(int index, bool allowCurrent)
- {
- if (index < 0 || index >= NumFields)
- {
- throw new IndexOutOfRangeException();
- }
- if (allowCurrent && _reader.CurrentlyStreaming ? index < _lastIndex : index <= _lastIndex)
- {
- throw new InvalidOperationException(
- string.Format(resman.GetString("Row_Sequential_Field_Error"), index, _lastIndex + 1));
- }
- _reader.Skip(index - _lastIndex - 1);
- _lastIndex = index;
- }
-
- public override object this[int index]
- {
- get
- {
- SetIndex(index, false);
- return _reader.GetNext();
- }
- }
-
- public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
- {
- if (buffer == null)
- {
- throw new NotSupportedException();
- }
- if (!_reader.CanGetByteStream(i))
- {
- throw new InvalidCastException();
- }
- SetIndex(i, true);
- _reader.SkipBytesTo(fieldOffset);
- return _reader.Read(buffer, bufferoffset, length);
- }
-
- public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
- {
- if (buffer == null)
- {
- throw new NotSupportedException();
- }
- if (!_reader.CanGetCharStream(i))
- {
- throw new InvalidCastException();
- }
- SetIndex(i, true);
- _reader.SkipCharsTo(fieldoffset);
- return _reader.Read(buffer, bufferoffset, length);
- }
-
- public override int NumFields
- {
- get { return _reader.NumFields; }
- }
-
- public override bool IsDBNull(int index)
- {
- if (_lastIndex > -1)
- {
- SetIndex(index - 1, true);
- }
- return _reader.IsNextDBNull;
- }
-
- public override void Dispose()
- {
- _reader.Dispose();
- }
- }
-
- /// <summary>
- /// Reads a row, field by field, allowing a DataRow to be built appropriately.
- /// </summary>
- internal abstract class RowReader : IStreamOwner
- {
- /// <summary>
- /// Reads part of a field, as needed (for <see cref="System.Data.IDataRecord.GetChars()"/>
- /// and <see cref="System.Data.IDataRecord.GetBytes()"/>
- /// </summary>
- protected abstract class Streamer : IStreamOwner
- {
- protected readonly Stream _stream;
- protected int _remainingBytes;
- private int _alreadyRead = 0;
-
- protected Streamer(Stream stream, int remainingBytes)
- {
- _stream = stream;
- _remainingBytes = remainingBytes;
- }
-
- public int AlreadyRead
- {
- get { return _alreadyRead; }
- protected set { _alreadyRead = value; }
- }
-
- public void Dispose()
- {
- PGUtil.EatStreamBytes(_stream, _remainingBytes);
- }
- }
-
- /// <summary>
- /// Adds further functionality to stream that is dependant upon the type of data read.
- /// </summary>
- protected abstract class Streamer<T> : Streamer
- {
- protected Streamer(Stream stream, int remainingBytes)
- : base(stream, remainingBytes)
- {
- }
-
- public abstract int DoRead(T[] output, int outputIdx, int length);
- public abstract int DoSkip(int length);
-
- public int Read(T[] output, int outputIdx, int length)
- {
- int ret = DoRead(output, outputIdx, length);
- AlreadyRead += ret;
- return ret;
- }
-
- private void Skip(int length)
- {
- AlreadyRead += DoSkip(length);
- }
-
- public void SkipTo(long position)
- {
- if (position < AlreadyRead)
- {
- throw new InvalidOperationException();
- }
- Skip((int) position - AlreadyRead);
- }
- }
-
- /// <summary>
- /// Completes the implementation of Streamer for char data.
- /// </summary>
- protected sealed class CharStreamer : Streamer<char>
- {
- public CharStreamer(Stream stream, int remainingBytes)
- : base(stream, remainingBytes)
- {
- }
-
- public override int DoRead(char[] output, int outputIdx, int length)
- {
- return PGUtil.ReadChars(_stream, output, length, ref _remainingBytes, outputIdx);
- }
-
- public override int DoSkip(int length)
- {
- return PGUtil.SkipChars(_stream, length, ref _remainingBytes);
- }
- }
-
- /// <summary>
- /// Completes the implementation of Streamer for byte data.
- /// </summary>
- protected sealed class ByteStreamer : Streamer<byte>
- {
- public ByteStreamer(Stream stream, int remainingBytes)
- : base(stream, remainingBytes)
- {
- }
-
- public override int DoRead(byte[] output, int outputIdx, int length)
- {
- return PGUtil.ReadEscapedBytes(_stream, output, length, ref _remainingBytes, outputIdx);
- }
-
- public override int DoSkip(int length)
- {
- return PGUtil.SkipEscapedBytes(_stream, length, ref _remainingBytes);
- }
- }
-
- protected static readonly Encoding UTF8Encoding = Encoding.UTF8;
- private readonly NpgsqlRowDescription _rowDesc;
- private readonly Stream _stream;
- private Streamer _streamer;
- private int _currentField = -1;
-
- public RowReader(NpgsqlRowDescription rowDesc, Stream stream)
- {
- _rowDesc = rowDesc;
- _stream = stream;
- }
-
- protected Streamer CurrentStreamer
- {
- get { return _streamer; }
- set
- {
- if (_streamer != null)
- {
- _streamer.Dispose();
- }
- _streamer = value;
- }
- }
-
- public bool CurrentlyStreaming
- {
- get { return _streamer != null; }
- }
-
- public bool CanGetByteStream(int index)
- {
-//TODO: Add support for byte[] being read as a stream of bytes.
- return _rowDesc[index].TypeInfo.NpgsqlDbType == NpgsqlDbType.Bytea;
- }
-
- public bool CanGetCharStream(int index)
- {
-//TODO: Add support for arrays of string types?
- return _rowDesc[index].TypeInfo.Type.Equals(typeof (string));
- }
-
- protected Streamer<byte> CurrentByteStreamer
- {
- get
- {
- if (CurrentStreamer == null)
- {
- if (!CanGetByteStream(_currentField + 1))
- {
- throw new InvalidCastException();
- }
- ++_currentField;
- return (CurrentStreamer = new ByteStreamer(Stream, GetNextFieldCount())) as ByteStreamer;
- }
- else if (!(CurrentStreamer is Streamer<byte>))
- {
- throw new InvalidOperationException();
- }
- else
- {
- return CurrentStreamer as ByteStreamer;
- }
- }
- }
-
- protected Streamer<char> CurrentCharStreamer
- {
- get
- {
- if (CurrentStreamer == null)
- {
- if (!CanGetCharStream(_currentField + 1))
- {
- throw new InvalidCastException();
- }
- ++_currentField;
- return (CurrentStreamer = new CharStreamer(Stream, GetNextFieldCount())) as CharStreamer;
- }
- else if (!(CurrentStreamer is Streamer<char>))
- {
- throw new InvalidOperationException();
- }
- else
- {
- return CurrentStreamer as CharStreamer;
- }
- }
- }
-
- protected Stream Stream
- {
- get { return _stream; }
- }
-
- protected NpgsqlRowDescription.FieldData FieldData
- {
- get { return _rowDesc[_currentField]; }
- }
-
- public int NumFields
- {
- get { return _rowDesc.NumFields; }
- }
-
- protected int CurrentField
- {
- get { return _currentField; }
- }
-
- protected abstract object ReadNext();
-
- public object GetNext()
- {
- if (++_currentField == _rowDesc.NumFields)
- {
- throw new IndexOutOfRangeException();
- }
- return ReadNext();
- }
-
- public abstract bool IsNextDBNull { get; }
- protected abstract void SkipOne();
-
- public void Skip(int count)
- {
- if (count > 0)
- {
- if (_currentField + count >= _rowDesc.NumFields)
- {
- throw new IndexOutOfRangeException();
- }
- while (count-- > 0)
- {
- ++_currentField;
- SkipOne();
- }
- }
- }
-
- protected abstract int GetNextFieldCount();
-
- public int Read(byte[] output, int outputIdx, int length)
- {
- return CurrentByteStreamer.Read(output, outputIdx, length);
- }
-
- public void SkipBytesTo(long position)
- {
- CurrentByteStreamer.SkipTo(position);
- }
-
- public int Read(char[] output, int outputIdx, int length)
- {
- return CurrentCharStreamer.Read(output, outputIdx, length);
- }
-
- public void SkipCharsTo(long position)
- {
- CurrentCharStreamer.SkipTo(position);
- }
- public void Dispose()
- {
- CurrentStreamer = null;
- Skip(_rowDesc.NumFields - _currentField - 1);
- }
- }
-} \ No newline at end of file
+ /// <summary>
+ /// This is the abstract base class for NpgsqlAsciiRow and NpgsqlBinaryRow.
+ /// </summary>
+ internal abstract class NpgsqlRow
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlRow";
+
+ protected ArrayList data;
+ protected NpgsqlRowDescription row_desc;
+ protected ProtocolVersion protocol_version;
+
+ public NpgsqlRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion)
+ {
+ data = new ArrayList();
+ row_desc = rowDesc;
+ protocol_version = protocolVersion;
+ }
+
+ public virtual void ReadFromStream(Stream inputStream, Encoding encoding)
+ {
+ throw new NotImplementedException("Abstract");
+ }
+
+ /// <summary>
+ /// Provide access to the fields in this row.
+ /// </summary>
+ public virtual Object this[Int32 index]
+ {
+ get
+ {
+ NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, index);
+ if ((index < 0) || (index >= row_desc.NumFields)) {
+ throw new IndexOutOfRangeException("this[] index value");
+ }
+
+ return data[index];
+ }
+ }
+ }
+
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs b/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs
index 32104f38bcb..0aa3c2fc63c 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlRowDescription.cs
@@ -9,207 +9,230 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Collections.Generic;
+using System.Collections;
using System.IO;
+using System.Text;
+using System.Net;
+using System.Globalization;
+
using NpgsqlTypes;
namespace Npgsql
{
- /// <summary>
- /// This class represents a RowDescription message sent from
- /// the PostgreSQL.
- /// </summary>
- ///
- internal abstract class NpgsqlRowDescription : IServerResponseObject
- {
- /// <summary>
- /// This struct represents the internal data of the RowDescription message.
- /// </summary>
- public abstract class FieldData
- {
- private string _name; // Protocol 2/3
- private int _typeOID; // Protocol 2/3
- private short _typeSize; // Protocol 2/3
- private int _typeModifier; // Protocol 2/3
- private int _tableOID; // Protocol 3
- private short _columnAttributeNumber; // Protocol 3
- private FormatCode _formatCode; // Protocol 3. 0 text, 1 binary
- private NpgsqlBackendTypeInfo _typeInfo; // everything we know about this field type
-
- public string Name
- {
- get { return _name; }
- protected set { _name = value; }
- }
-
- public int TypeOID
- {
- get { return _typeOID; }
- protected set { _typeOID = value; }
- }
-
- public short TypeSize
- {
- get { return _typeSize; }
- protected set { _typeSize = value; }
- }
-
- public int TypeModifier
- {
- get { return _typeModifier; }
- protected set { _typeModifier = value; }
- }
-
- public int TableOID
- {
- get { return _tableOID; }
- protected set { _tableOID = value; }
- }
-
- public short ColumnAttributeNumber
- {
- get { return _columnAttributeNumber; }
- protected set { _columnAttributeNumber = value; }
- }
-
- public FormatCode FormatCode
- {
- get { return _formatCode; }
- protected set { _formatCode = value; }
- }
-
- public NpgsqlBackendTypeInfo TypeInfo
- {
- get { return _typeInfo; }
- protected set { _typeInfo = value; }
- }
- }
-
- private readonly FieldData[] fields_data;
- private readonly Dictionary<string, int> field_name_index_table;
- private readonly Dictionary<string, int> caseInsensitiveNameIndexTable;
-
- protected NpgsqlRowDescription(Stream stream, NpgsqlBackendTypeMapping type_mapping)
- {
- int num = ReadNumFields(stream);
- fields_data = new FieldData[num];
- field_name_index_table = new Dictionary<string, int>(num, StringComparer.InvariantCulture);
- caseInsensitiveNameIndexTable = new Dictionary<string, int>(num, StringComparer.InvariantCultureIgnoreCase);
- for (int i = 0; i != num; ++i)
- {
- FieldData fd = BuildFieldData(stream, type_mapping);
- fields_data[i] = fd;
- if (!field_name_index_table.ContainsKey(fd.Name))
- {
- field_name_index_table.Add(fd.Name, i);
- if (!caseInsensitiveNameIndexTable.ContainsKey(fd.Name))
- {
- caseInsensitiveNameIndexTable.Add(fd.Name, i);
- }
- }
- }
- }
-
- protected abstract FieldData BuildFieldData(Stream stream, NpgsqlBackendTypeMapping typeMapping);
- protected abstract int ReadNumFields(Stream stream);
-
- public FieldData this[int index]
- {
- get { return fields_data[index]; }
- }
-
- public int NumFields
- {
- get { return (Int16) fields_data.Length; }
- }
-
- public int FieldIndex(String fieldName)
- {
- int ret = -1;
- return
- field_name_index_table.TryGetValue(fieldName, out ret)
- ? ret
- : (caseInsensitiveNameIndexTable.TryGetValue(fieldName, out ret) ? ret : -1);
- }
- }
-
- internal sealed class NpgsqlRowDescriptionV2 : NpgsqlRowDescription
- {
- public NpgsqlRowDescriptionV2(Stream stream, NpgsqlBackendTypeMapping typeMapping)
- : base(stream, typeMapping)
- {
- }
-
- private sealed class FieldDataV2 : FieldData
- {
- public FieldDataV2(Stream stream, NpgsqlBackendTypeMapping typeMapping)
- {
- Name = PGUtil.ReadString(stream);
- TypeInfo = typeMapping[TypeOID = PGUtil.ReadInt32(stream)];
- TypeSize = PGUtil.ReadInt16(stream);
- TypeModifier = PGUtil.ReadInt32(stream);
- }
- }
-
- protected override FieldData BuildFieldData(Stream stream, NpgsqlBackendTypeMapping type_mapping)
- {
- return new FieldDataV2(stream, type_mapping);
- }
-
- protected override int ReadNumFields(Stream stream)
- {
- return PGUtil.ReadInt16(stream);
- }
- }
-
- internal sealed class NpgsqlRowDescriptionV3 : NpgsqlRowDescription
- {
- private sealed class FieldDataV3 : FieldData
- {
- public FieldDataV3(Stream stream, NpgsqlBackendTypeMapping typeMapping)
- {
- Name = PGUtil.ReadString(stream);
- TableOID = PGUtil.ReadInt32(stream);
- ColumnAttributeNumber = PGUtil.ReadInt16(stream);
- TypeInfo = typeMapping[TypeOID = PGUtil.ReadInt32(stream)];
- TypeSize = PGUtil.ReadInt16(stream);
- TypeModifier = PGUtil.ReadInt32(stream);
- FormatCode = (FormatCode) PGUtil.ReadInt16(stream);
- }
- }
-
- public NpgsqlRowDescriptionV3(Stream stream, NpgsqlBackendTypeMapping typeMapping)
- : base(stream, typeMapping)
- {
- }
-
- protected override FieldData BuildFieldData(Stream stream, NpgsqlBackendTypeMapping typeMapping)
- {
- return new FieldDataV3(stream, typeMapping);
- }
-
- protected override int ReadNumFields(Stream stream)
- {
- PGUtil.EatStreamBytes(stream, 4);
- return PGUtil.ReadInt16(stream);
- }
- }
-} \ No newline at end of file
+
+
+ /// <summary>
+ /// This struct represents the internal data of the RowDescription message.
+ /// </summary>
+ ///
+ // [FIXME] Is this name OK? Does it represent well the struct intent?
+ // Should it be a struct or a class?
+ internal struct NpgsqlRowDescriptionFieldData
+ {
+ public String name; // Protocol 2/3
+ public Int32 table_oid; // Protocol 3
+ public Int16 column_attribute_number; // Protocol 3
+ public Int32 type_oid; // Protocol 2/3
+ public Int16 type_size; // Protocol 2/3
+ public Int32 type_modifier; // Protocol 2/3
+ public FormatCode format_code; // Protocol 3. 0 text, 1 binary
+ public NpgsqlBackendTypeInfo type_info; // everything we know about this field type
+ }
+
+ /// <summary>
+ /// This class represents a RowDescription message sent from
+ /// the PostgreSQL.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlRowDescription
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlRowDescription";
+
+
+ private NpgsqlRowDescriptionFieldData[] fields_data;
+ private string[] fields_index;
+ private Hashtable field_name_index_table;
+
+ private ProtocolVersion protocol_version;
+
+ public NpgsqlRowDescription(ProtocolVersion protocolVersion)
+ {
+ protocol_version = protocolVersion;
+ }
+
+ public void ReadFromStream(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
+ {
+ switch (protocol_version)
+ {
+ case ProtocolVersion.Version2 :
+ ReadFromStream_Ver_2(input_stream, encoding, type_mapping);
+ break;
+
+ case ProtocolVersion.Version3 :
+ ReadFromStream_Ver_3(input_stream, encoding, type_mapping);
+ break;
+
+ }
+ }
+
+ private void ReadFromStream_Ver_2(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
+
+ Byte[] input_buffer = new Byte[10]; // Max read will be 4 + 2 + 4
+
+ // Read the number of fields.
+ input_stream.Read(input_buffer, 0, 2);
+ Int16 num_fields = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 0));
+
+
+ // 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];
+
+ field_name_index_table = new Hashtable(num_fields);
+
+
+ // Now, iterate through each field getting its data.
+ for (Int16 i = 0; i < num_fields; i++)
+ {
+ fd = new NpgsqlRowDescriptionFieldData();
+
+ // Set field name.
+ fd.name = PGUtil.ReadString(input_stream, encoding);
+
+ // Read type_oid(Int32), type_size(Int16), type_modifier(Int32)
+ input_stream.Read(input_buffer, 0, 4 + 2 + 4);
+
+ fd.type_oid = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
+ fd.type_info = type_mapping[fd.type_oid];
+ fd.type_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 4));
+ fd.type_modifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 6));
+
+ // Add field data to array.
+ fields_data[i] = fd;
+
+ fields_index[i] = fd.name;
+
+ if (!field_name_index_table.ContainsKey(fd.name))
+ field_name_index_table.Add(fd.name, i);
+ }
+ }
+
+ private void ReadFromStream_Ver_3(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
+
+ Byte[] input_buffer = new Byte[4]; // Max read will be 4 + 2 + 4 + 2 + 4 + 2
+
+ // Read the length of message.
+ // [TODO] Any use for now?
+ PGUtil.ReadInt32(input_stream, input_buffer);
+ Int16 num_fields = PGUtil.ReadInt16(input_stream, input_buffer);
+
+ // 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];
+ field_name_index_table = new Hashtable(num_fields);
+
+ for (Int16 i = 0; i < num_fields; i++)
+ {
+ fd = new NpgsqlRowDescriptionFieldData();
+
+ fd.name = PGUtil.ReadString(input_stream, encoding);
+ fd.table_oid = PGUtil.ReadInt32(input_stream, input_buffer);
+ fd.column_attribute_number = PGUtil.ReadInt16(input_stream, input_buffer);
+ fd.type_oid = PGUtil.ReadInt32(input_stream, input_buffer);
+ fd.type_info = type_mapping[fd.type_oid];
+ fd.type_size = PGUtil.ReadInt16(input_stream, input_buffer);
+ fd.type_modifier = PGUtil.ReadInt32(input_stream, input_buffer);
+ fd.format_code = (FormatCode)PGUtil.ReadInt16(input_stream, input_buffer);
+
+ fields_data[i] = fd;
+ fields_index[i] = fd.name;
+
+ if (!field_name_index_table.ContainsKey(fd.name))
+ field_name_index_table.Add(fd.name, i);
+ }
+ }
+
+ public NpgsqlRowDescriptionFieldData this[Int32 index]
+ {
+ get
+ {
+ return fields_data[index];
+ }
+ }
+
+ public Int16 NumFields
+ {
+ get
+ {
+ return (Int16)fields_data.Length;
+ }
+ }
+
+ public Int16 FieldIndex(String fieldName)
+ {
+
+
+ // First try to find with hashtable, case sensitive.
+
+ Object result1 = field_name_index_table[fieldName];
+
+ if (result1 != null)
+ return (Int16)result1;
+
+
+ result1 = field_name_index_table[fieldName.ToLower(CultureInfo.InvariantCulture)];
+
+ if (result1 != null)
+ return (Int16)result1;
+
+ // Then 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, CultureInfo.InvariantCulture) == 0)
+ return result;
+ }
+ }
+
+ return -1;
+
+
+ }
+
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs b/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs
index d37cd151849..354d83672f5 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlSchema.cs
@@ -7,27 +7,23 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
using System.Data;
-using System.IO;
-using System.Reflection;
using System.Text;
namespace Npgsql
@@ -36,275 +32,255 @@ namespace Npgsql
/// Provides the underlying mechanism for reading schema information.
/// </summary>
internal sealed class NpgsqlSchema
- {
- private readonly NpgsqlConnection _connection;
-
- /// <summary>
- /// Creates an NpgsqlSchema that can read schema information from the database.
- /// </summary>
- /// <param name="connection">An open database connection for reading metadata.</param>
- internal NpgsqlSchema(NpgsqlConnection connection)
- {
- _connection = connection;
- }
-
- /// <summary>
- /// Returns the MetaDataCollections that lists all possible collections.
- /// </summary>
- /// <returns>The MetaDataCollections</returns>
- internal static DataTable GetMetaDataCollections()
- {
- DataTable metaDataCollections = new DataTable("MetaDataCollections");
-
- metaDataCollections.Columns.AddRange(
- new DataColumn[]
- {
- new DataColumn("CollectionName"), new DataColumn("NumberOfRestrictions", typeof (int)),
- new DataColumn("NumberOfIdentifierParts", typeof (int))
- });
-
- // Add(object[] { CollectionName, NumberOfRestrictions, NumberOfIdentifierParts })
- metaDataCollections.Rows.Add(new object[] {"MetaDataCollections", 0, 0});
- metaDataCollections.Rows.Add(new object[] {"Restrictions", 0, 0});
- metaDataCollections.Rows.Add(new object[] {"Databases", 1, 1});
- metaDataCollections.Rows.Add(new object[] {"Tables", 4, 3});
- metaDataCollections.Rows.Add(new object[] {"Columns", 4, 4});
- metaDataCollections.Rows.Add(new object[] {"Views", 3, 3});
- metaDataCollections.Rows.Add(new object[] {"Users", 1, 1});
-
- return metaDataCollections;
- }
-
- /// <summary>
- /// Returns the Restrictions that contains the meaning and position of the values in the restrictions array.
- /// </summary>
- /// <returns>The Restrictions</returns>
- internal static DataTable GetRestrictions()
- {
- DataTable restrictions = new DataTable("Restrictions");
-
- restrictions.Columns.AddRange(
- new DataColumn[]
- {
- new DataColumn("CollectionName"), new DataColumn("RestrictionName"), new DataColumn("RestrictionDefault"),
- new DataColumn("RestrictionNumber", typeof (int))
- });
-
- restrictions.Rows.Add(new object[] {"Databases", "Name", "Name", 1});
- restrictions.Rows.Add(new object[] {"Tables", "Catalog", "table_catalog", 1});
- restrictions.Rows.Add(new object[] {"Tables", "Schema", "table_schema", 2});
- restrictions.Rows.Add(new object[] {"Tables", "Table", "table_name", 3});
- restrictions.Rows.Add(new object[] {"Tables", "TableType", "table_type", 4});
- restrictions.Rows.Add(new object[] {"Columns", "Catalog", "table_catalog", 1});
- restrictions.Rows.Add(new object[] {"Columns", "Schema", "table_schema", 2});
- restrictions.Rows.Add(new object[] {"Columns", "Table", "table_name", 3});
- restrictions.Rows.Add(new object[] {"Columns", "Column", "column_name", 4});
- restrictions.Rows.Add(new object[] {"Views", "Catalog", "table_catalog", 1});
- restrictions.Rows.Add(new object[] {"Views", "Schema", "table_schema", 2});
- restrictions.Rows.Add(new object[] {"Views", "Table", "table_name", 3});
-
- return restrictions;
- }
-
- private NpgsqlCommand BuildCommand(StringBuilder query, string[] restrictions, params string[] names)
- {
- NpgsqlCommand command = new NpgsqlCommand();
-
- if (restrictions != null && names != null)
- {
- bool addWhere = true;
- for (int i = 0; i < restrictions.Length && i < names.Length; ++i)
- {
- if (restrictions[i] != null && restrictions[i].Length != 0)
- {
- if (addWhere)
- {
- query.Append(" WHERE ");
- addWhere = false;
- }
- else
- {
- query.Append(" AND ");
- }
- query.AppendFormat("{0} = :{0}", names[i]);
-
- command.Parameters.Add(new NpgsqlParameter(names[i], restrictions[i]));
- }
- }
- }
- command.CommandText = query.ToString();
- command.Connection = _connection;
-
- return command;
- }
-
- /// <summary>
- /// Returns the Databases that contains a list of all accessable databases.
- /// </summary>
- /// <param name="restrictions">The restrictions to filter the collection.</param>
- /// <returns>The Databases</returns>
- internal DataTable GetDatabases(string[] restrictions)
- {
- DataTable databases = new DataTable("Databases");
-
- databases.Columns.AddRange(
- new DataColumn[] {new DataColumn("database_name"), new DataColumn("owner"), new DataColumn("encoding")});
-
- StringBuilder getDatabases = new StringBuilder();
-
- getDatabases.Append(
- "SELECT d.datname AS database_name, u.usename AS owner, pg_catalog.pg_encoding_to_char(d.encoding) AS encoding FROM pg_catalog.pg_database d LEFT JOIN pg_catalog.pg_user u ON d.datdba = u.usesysid");
-
- using (NpgsqlCommand command = BuildCommand(getDatabases, restrictions, "datname"))
- {
- using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
- {
- adapter.Fill(databases);
- }
- }
-
- return databases;
- }
-
- /// <summary>
- /// Returns the Tables that contains table and view names and the database and schema they come from.
- /// </summary>
- /// <param name="restrictions">The restrictions to filter the collection.</param>
- /// <returns>The Tables</returns>
- internal DataTable GetTables(string[] restrictions)
- {
- DataTable tables = new DataTable("Tables");
-
- tables.Columns.AddRange(
- new DataColumn[]
- {
- new DataColumn("table_catalog"), new DataColumn("table_schema"), new DataColumn("table_name"),
- new DataColumn("table_type")
- });
-
- StringBuilder getTables = new StringBuilder();
-
- getTables.Append("SELECT table_catalog, table_schema, table_name, table_type FROM information_schema.tables");
-
- using (
- NpgsqlCommand command =
- BuildCommand(getTables, restrictions, "table_catalog", "table_schema", "table_name", "table_type"))
- {
- using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
- {
- adapter.Fill(tables);
- }
- }
-
- return tables;
- }
-
- /// <summary>
- /// Returns the Columns that contains information about columns in tables.
- /// </summary>
- /// <param name="restrictions">The restrictions to filter the collection.</param>
- /// <returns>The Columns.</returns>
- internal DataTable GetColumns(string[] restrictions)
- {
- DataTable columns = new DataTable("Columns");
-
- columns.Columns.AddRange(
- new DataColumn[]
- {
- new DataColumn("table_catalog"), new DataColumn("table_schema"), new DataColumn("table_name"),
- new DataColumn("column_name"), new DataColumn("ordinal_position", typeof (int)), new DataColumn("column_default"),
- new DataColumn("is_nullable"), new DataColumn("data_type"),
- new DataColumn("character_maximum_length", typeof (int)), new DataColumn("character_octet_length", typeof (int)),
- new DataColumn("numeric_precision", typeof (int)), new DataColumn("numeric_precision_radix", typeof (int)),
- new DataColumn("numeric_scale", typeof (int)), new DataColumn("datetime_precision", typeof (int)),
- new DataColumn("character_set_catalog"), new DataColumn("character_set_schema"),
- new DataColumn("character_set_name"), new DataColumn("collation_catalog")
- });
-
- StringBuilder getColumns = new StringBuilder();
-
- getColumns.Append(
- "SELECT table_catalog, table_schema, table_name, column_name, ordinal_position, column_default, is_nullable, udt_name AS data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_precision_radix, numeric_scale, datetime_precision, character_set_catalog, character_set_schema, character_set_name, collation_catalog FROM information_schema.columns");
-
- using (
- NpgsqlCommand command =
- BuildCommand(getColumns, restrictions, "table_catalog", "table_schema", "table_name", "column_name"))
- {
- using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
- {
- adapter.Fill(columns);
- }
- }
-
- return columns;
- }
-
- /// <summary>
- /// Returns the Views that contains view names and the database and schema they come from.
- /// </summary>
- /// <param name="restrictions">The restrictions to filter the collection.</param>
- /// <returns>The Views</returns>
- internal DataTable GetViews(string[] restrictions)
- {
- DataTable views = new DataTable("Views");
-
- views.Columns.AddRange(
- new DataColumn[]
- {
- new DataColumn("table_catalog"), new DataColumn("table_schema"), new DataColumn("table_name"),
- new DataColumn("check_option"), new DataColumn("is_updatable")
- });
-
- StringBuilder getViews = new StringBuilder();
-
- getViews.Append(
- "SELECT table_catalog, table_schema, table_name, check_option, is_updatable FROM information_schema.views");
-
- using (NpgsqlCommand command = BuildCommand(getViews, restrictions, "table_catalog", "table_schema", "table_name"))
- {
- using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
- {
- adapter.Fill(views);
- }
- }
-
- return views;
- }
-
- /// <summary>
- /// Returns the Users containing user names and the sysid of those users.
- /// </summary>
- /// <param name="restrictions">The restrictions to filter the collection.</param>
- /// <returns>The Users.</returns>
- internal DataTable GetUsers(string[] restrictions)
- {
- DataTable users = new DataTable("Users");
-
- users.Columns.AddRange(new DataColumn[] {new DataColumn("user_name"), new DataColumn("user_sysid", typeof (int))});
-
- StringBuilder getUsers = new StringBuilder();
-
- getUsers.Append("SELECT usename as user_name, usesysid as user_sysid FROM pg_catalog.pg_user");
-
- using (NpgsqlCommand command = BuildCommand(getUsers, restrictions, "usename"))
- {
- using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
- {
- adapter.Fill(users);
- }
- }
-
- return users;
- }
-
- internal static DataTable GetDataSourceInformation()
- {
- DataSet ds = new DataSet();
- using (Stream xmlStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Npgsql.NpgsqlMetaData.xml"))
- {
- ds.ReadXml(xmlStream);
- }
- return ds.Tables["DataSourceInformation"].Copy();
- }
+ {
+ private NpgsqlConnection _connection;
+
+ /// <summary>
+ /// Creates an NpgsqlSchema that can read schema information from the database.
+ /// </summary>
+ /// <param name="connection">An open database connection for reading metadata.</param>
+ internal NpgsqlSchema(NpgsqlConnection connection)
+ {
+ _connection = connection;
+ }
+
+ /// <summary>
+ /// Returns the MetaDataCollections that lists all possible collections.
+ /// </summary>
+ /// <returns>The MetaDataCollections</returns>
+ internal static DataTable GetMetaDataCollections()
+ {
+ DataTable metaDataCollections = new DataTable("MetaDataCollections");
+
+ metaDataCollections.Columns.AddRange(new DataColumn[] {
+ new DataColumn("CollectionName"),
+ new DataColumn("NumberOfRestrictions", typeof(int)),
+ new DataColumn("NumberOfIdentifierParts", typeof(int)) });
+
+ // Add(object[] { CollectionName, NumberOfRestrictions, NumberOfIdentifierParts })
+ metaDataCollections.Rows.Add(new object[]{"MetaDataCollections",0,0});
+ metaDataCollections.Rows.Add(new object[]{"Restrictions",0,0});
+ metaDataCollections.Rows.Add(new object[]{"Databases",1,1});
+ metaDataCollections.Rows.Add(new object[]{"Tables",4,3});
+ metaDataCollections.Rows.Add(new object[]{"Columns",4,4});
+ metaDataCollections.Rows.Add(new object[]{"Views",3,3});
+ metaDataCollections.Rows.Add(new object[]{"Users",1,1});
+
+ return metaDataCollections;
+ }
+
+ /// <summary>
+ /// Returns the Restrictions that contains the meaning and position of the values in the restrictions array.
+ /// </summary>
+ /// <returns>The Restrictions</returns>
+ internal static DataTable GetRestrictions()
+ {
+ DataTable restrictions = new DataTable("Restrictions");
+
+ restrictions.Columns.AddRange(new DataColumn[] {
+ new DataColumn("CollectionName"),
+ new DataColumn("RestrictionName"),
+ new DataColumn("RestrictionDefault"),
+ new DataColumn("RestrictionNumber", typeof(int)) });
+
+ restrictions.Rows.Add(new object[]{"Databases","Name","Name",1});
+ restrictions.Rows.Add(new object[]{"Tables","Catalog","table_catalog",1});
+ restrictions.Rows.Add(new object[]{"Tables","Schema","table_schema",2});
+ restrictions.Rows.Add(new object[]{"Tables","Table","table_name",3});
+ restrictions.Rows.Add(new object[]{"Tables","TableType","table_type",4});
+ restrictions.Rows.Add(new object[]{"Columns","Catalog","table_catalog",1});
+ restrictions.Rows.Add(new object[]{"Columns","Schema","table_schema",2});
+ restrictions.Rows.Add(new object[]{"Columns","Table","table_name",3});
+ restrictions.Rows.Add(new object[]{"Columns","Column","column_name",4});
+ restrictions.Rows.Add(new object[]{"Views","Catalog","table_catalog",1});
+ restrictions.Rows.Add(new object[]{"Views","Schema","table_schema",2});
+ restrictions.Rows.Add(new object[]{"Views","Table","table_name",3});
+
+ return restrictions;
+ }
+
+ private NpgsqlCommand BuildCommand(StringBuilder query, string[] restrictions, params string[] names)
+ {
+ NpgsqlCommand command = new NpgsqlCommand();
+
+ if (restrictions != null && names != null)
+ {
+ bool addWhere = true;
+ for(int i=0; i<restrictions.Length && i<names.Length; ++i)
+ {
+ if (restrictions[i] != null && restrictions[i].Length != 0)
+ {
+ if (addWhere)
+ {
+ query.Append(" WHERE ");
+ addWhere = false;
+ }
+ else
+ {
+ query.Append(" AND ");
+ }
+ query.AppendFormat("{0} = :{0}", names[i]);
+
+ command.Parameters.Add(new NpgsqlParameter(names[i], restrictions[i]));
+ }
+ }
+ }
+ command.CommandText = query.ToString();
+ command.Connection = _connection;
+
+ return command;
+ }
+
+ /// <summary>
+ /// Returns the Databases that contains a list of all accessable databases.
+ /// </summary>
+ /// <param name="restrictions">The restrictions to filter the collection.</param>
+ /// <returns>The Databases</returns>
+ internal DataTable GetDatabases(string[] restrictions)
+ {
+ DataTable databases = new DataTable("Databases");
+
+ databases.Columns.AddRange(new DataColumn[] {
+ new DataColumn("database_name"),
+ new DataColumn("owner"),
+ new DataColumn("encoding") });
+
+ StringBuilder getDatabases = new StringBuilder();
+
+ getDatabases.Append("SELECT d.datname AS database_name, u.usename AS owner, pg_catalog.pg_encoding_to_char(d.encoding) AS encoding FROM pg_catalog.pg_database d LEFT JOIN pg_catalog.pg_user u ON d.datdba = u.usesysid");
+
+ using (NpgsqlCommand command = BuildCommand(getDatabases, restrictions, "datname"))
+ using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
+ {
+ adapter.Fill(databases);
+ }
+
+ return databases;
+ }
+
+ /// <summary>
+ /// Returns the Tables that contains table and view names and the database and schema they come from.
+ /// </summary>
+ /// <param name="restrictions">The restrictions to filter the collection.</param>
+ /// <returns>The Tables</returns>
+ internal DataTable GetTables(string[] restrictions)
+ {
+ DataTable tables = new DataTable("Tables");
+
+ tables.Columns.AddRange(new DataColumn[] {
+ new DataColumn("table_catalog"),
+ new DataColumn("table_schema"),
+ new DataColumn("table_name"),
+ new DataColumn("table_type") });
+
+ StringBuilder getTables = new StringBuilder();
+
+ getTables.Append("SELECT table_catalog, table_schema, table_name, table_type FROM information_schema.tables");
+
+ using (NpgsqlCommand command = BuildCommand(getTables, restrictions, "table_catalog", "table_schema", "table_name", "table_type"))
+ using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
+ {
+ adapter.Fill(tables);
+ }
+
+ return tables;
+ }
+
+ /// <summary>
+ /// Returns the Columns that contains information about columns in tables.
+ /// </summary>
+ /// <param name="restrictions">The restrictions to filter the collection.</param>
+ /// <returns>The Columns.</returns>
+ internal DataTable GetColumns(string[] restrictions)
+ {
+ DataTable columns = new DataTable("Columns");
+
+ columns.Columns.AddRange(new DataColumn[] {
+ new DataColumn("table_catalog"),
+ new DataColumn("table_schema"),
+ new DataColumn("table_name"),
+ new DataColumn("column_name"),
+ new DataColumn("ordinal_position", typeof(int)),
+ new DataColumn("column_default"),
+ new DataColumn("is_nullable"),
+ new DataColumn("data_type"),
+ new DataColumn("character_maximum_length", typeof(int)),
+ new DataColumn("character_octet_length", typeof(int)),
+ new DataColumn("numeric_precision", typeof(int)),
+ new DataColumn("numeric_precision_radix", typeof(int)),
+ new DataColumn("numeric_scale", typeof(int)),
+ new DataColumn("datetime_precision", typeof(int)),
+ new DataColumn("character_set_catalog"),
+ new DataColumn("character_set_schema"),
+ new DataColumn("character_set_name"),
+ new DataColumn("collation_catalog") });
+
+ StringBuilder getColumns = new StringBuilder();
+
+ getColumns.Append("SELECT table_catalog, table_schema, table_name, column_name, ordinal_position, column_default, is_nullable, udt_name AS data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_precision_radix, numeric_scale, datetime_precision, character_set_catalog, character_set_schema, character_set_name, collation_catalog FROM information_schema.columns");
+
+ using (NpgsqlCommand command = BuildCommand(getColumns, restrictions, "table_catalog", "table_schema", "table_name", "column_name"))
+ using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
+ {
+ adapter.Fill(columns);
+ }
+
+ return columns;
+ }
+
+ /// <summary>
+ /// Returns the Views that contains view names and the database and schema they come from.
+ /// </summary>
+ /// <param name="restrictions">The restrictions to filter the collection.</param>
+ /// <returns>The Views</returns>
+ internal DataTable GetViews(string[] restrictions)
+ {
+ DataTable views = new DataTable("Views");
+
+ views.Columns.AddRange(new DataColumn[] {
+ new DataColumn("table_catalog"),
+ new DataColumn("table_schema"),
+ new DataColumn("table_name"),
+ new DataColumn("check_option"),
+ new DataColumn("is_updatable") });
+
+ StringBuilder getViews = new StringBuilder();
+
+ getViews.Append("SELECT table_catalog, table_schema, table_name, check_option, is_updatable FROM information_schema.views");
+
+ using (NpgsqlCommand command = BuildCommand(getViews, restrictions, "table_catalog", "table_schema", "table_name"))
+ using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
+ {
+ adapter.Fill(views);
+ }
+
+ return views;
+ }
+
+ /// <summary>
+ /// Returns the Users containing user names and the sysid of those users.
+ /// </summary>
+ /// <param name="restrictions">The restrictions to filter the collection.</param>
+ /// <returns>The Users.</returns>
+ internal DataTable GetUsers(string[] restrictions)
+ {
+ DataTable users = new DataTable("Users");
+
+ users.Columns.AddRange(new DataColumn[] {
+ new DataColumn("user_name"),
+ new DataColumn("user_sysid", typeof(int)) });
+
+ StringBuilder getUsers = new StringBuilder();
+
+ getUsers.Append("SELECT usename as user_name, usesysid as user_sysid FROM pg_catalog.pg_user");
+
+ using (NpgsqlCommand command = BuildCommand(getUsers, restrictions, "usename"))
+ using (NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(command))
+ {
+ adapter.Fill(users);
+ }
+
+ return users;
+ }
}
-} \ No newline at end of file
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlStartupPacket.cs b/mcs/class/Npgsql/Npgsql/NpgsqlStartupPacket.cs
index 223e17e89c4..47ef00f35a2 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlStartupPacket.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlStartupPacket.cs
@@ -10,143 +10,146 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Text;
using System.Net;
namespace Npgsql
{
- /// <summary>
- /// This class represents a StartupPacket message of PostgreSQL
- /// protocol.
- /// </summary>
- ///
- internal sealed class NpgsqlStartupPacket : ClientMessage
- {
- // Logging related values
- private static readonly String CLASSNAME = "NpgsqlStartupPacket";
- // Private fields.
- private readonly Int32 packet_size;
- private readonly ProtocolVersion protocol_version;
- private readonly String database_name;
- private readonly String user_name;
- private readonly String arguments;
- private readonly String unused;
- private readonly String optional_tty;
+ /// <summary>
+ /// This class represents a StartupPacket message of PostgreSQL
+ /// protocol.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlStartupPacket
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlStartupPacket";
+
+ // Private fields.
+ private Int32 packet_size;
+ private ProtocolVersion protocol_version;
+ private String database_name;
+ private String user_name;
+ private String arguments;
+ private String unused;
+ private String optional_tty;
+
+ public NpgsqlStartupPacket(Int32 packet_size,
+ ProtocolVersion protocol_version,
+ String database_name,
+ String user_name,
+ String arguments,
+ String unused,
+ String optional_tty)
+ {
+
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
+ // Just copy the values.
+
+ // [FIXME] Validate params? We are the only clients, so, hopefully, we
+ // know what to send.
- public NpgsqlStartupPacket(Int32 packet_size, ProtocolVersion protocol_version, String database_name, String user_name,
- String arguments, String unused, String optional_tty)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
- // Just copy the values.
+ this.packet_size = packet_size;
+ this.protocol_version = protocol_version;
- // [FIXME] Validate params? We are the only clients, so, hopefully, we
- // know what to send.
+ this.database_name = database_name;
+ this.user_name = user_name;
+ this.arguments = arguments;
+ this.unused = unused;
+ this.optional_tty = optional_tty;
- this.packet_size = packet_size;
- this.protocol_version = protocol_version;
+ }
- this.database_name = database_name;
- this.user_name = user_name;
- this.arguments = arguments;
- this.unused = unused;
- this.optional_tty = optional_tty;
- }
+ public void WriteToStream(Stream output_stream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream");
- public override void WriteToStream(Stream output_stream)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream");
+ switch (protocol_version) {
+ case ProtocolVersion.Version2 :
+ WriteToStream_Ver_2(output_stream, encoding);
+ break;
- switch (protocol_version)
- {
- case ProtocolVersion.Version2:
- WriteToStream_Ver_2(output_stream);
- break;
+ case ProtocolVersion.Version3 :
+ WriteToStream_Ver_3(output_stream, encoding);
+ break;
- case ProtocolVersion.Version3:
- WriteToStream_Ver_3(output_stream);
- break;
- }
- }
+ }
+ }
- private void WriteToStream_Ver_2(Stream output_stream)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream_Ver_2");
+ private void WriteToStream_Ver_2(Stream output_stream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream_Ver_2");
- // Packet length = 296
- output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(this.packet_size)), 0, 4);
+ // Packet length = 296
+ output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(this.packet_size)), 0, 4);
- output_stream.Write(
- BitConverter.GetBytes(IPAddress.HostToNetworkOrder(PGUtil.ConvertProtocolVersion(this.protocol_version))), 0, 4);
+ output_stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(PGUtil.ConvertProtocolVersion(this.protocol_version))), 0, 4);
- // Database name.
- PGUtil.WriteLimString(this.database_name, 64, output_stream);
+ // Database name.
+ PGUtil.WriteLimString(this.database_name, 64, output_stream, encoding);
- // User name.
- PGUtil.WriteLimString(this.user_name, 32, output_stream);
+ // User name.
+ PGUtil.WriteLimString(this.user_name, 32, output_stream, encoding);
- // Arguments.
- PGUtil.WriteLimString(this.arguments, 64, output_stream);
+ // Arguments.
+ PGUtil.WriteLimString(this.arguments, 64, output_stream, encoding);
- // Unused.
- PGUtil.WriteLimString(this.unused, 64, output_stream);
+ // Unused.
+ PGUtil.WriteLimString(this.unused, 64, output_stream, encoding);
- // Optional tty.
- PGUtil.WriteLimString(this.optional_tty, 64, output_stream);
- output_stream.Flush();
- }
+ // Optional tty.
+ PGUtil.WriteLimString(this.optional_tty, 64, output_stream, encoding);
+ output_stream.Flush();
+ }
- private void WriteToStream_Ver_3(Stream output_stream)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream_Ver_3");
+ private void WriteToStream_Ver_3(Stream output_stream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream_Ver_3");
- PGUtil.WriteInt32(output_stream,
- 4 + 4 + 5 + (UTF8Encoding.GetByteCount(user_name) + 1) + 9 +
- (UTF8Encoding.GetByteCount(database_name) + 1) + 10 + 4 + 1);
+ PGUtil.WriteInt32(output_stream, 4 + 4 + 5 + (encoding.GetByteCount(user_name) + 1) + 9 + (encoding.GetByteCount(database_name) + 1) + 10 + 4 + 1);
- PGUtil.WriteInt32(output_stream, PGUtil.ConvertProtocolVersion(this.protocol_version));
+ PGUtil.WriteInt32(output_stream, Npgsql.PGUtil.ConvertProtocolVersion(this.protocol_version));
- // User name.
- PGUtil.WriteString("user", output_stream);
+ // User name.
+ PGUtil.WriteString("user", output_stream, encoding);
- // User name.
- PGUtil.WriteString(user_name, output_stream);
+ // User name.
+ PGUtil.WriteString(user_name, output_stream, encoding);
- // Database name.
- PGUtil.WriteString("database", output_stream);
+ // Database name.
+ PGUtil.WriteString("database", output_stream, encoding);
- // Database name.
- PGUtil.WriteString(database_name, output_stream);
+ // Database name.
+ PGUtil.WriteString(database_name, output_stream, encoding);
- // DateStyle.
- PGUtil.WriteString("DateStyle", output_stream);
+ // DateStyle.
+ PGUtil.WriteString("DateStyle", output_stream, encoding);
- // DateStyle.
- PGUtil.WriteString("ISO", output_stream);
+ // DateStyle.
+ PGUtil.WriteString("ISO", output_stream, encoding);
- output_stream.WriteByte(0);
- output_stream.Flush();
- }
- }
-} \ No newline at end of file
+ output_stream.WriteByte(0);
+ output_stream.Flush();
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlStartupState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlStartupState.cs
index e44737cdad0..dc3793bebba 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlStartupState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlStartupState.cs
@@ -7,47 +7,58 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.IO;
+using System.Net;
+using System.Net.Sockets;
namespace Npgsql
{
- internal sealed class NpgsqlStartupState : NpgsqlState
- {
- public static readonly NpgsqlStartupState Instance = new NpgsqlStartupState();
-
- private readonly String CLASSNAME = "NpgsqlStartupState";
-
- private NpgsqlStartupState()
- : base()
- {
- }
-
- public override void Authenticate(NpgsqlConnector context, string password)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Authenticate");
- NpgsqlPasswordPacket pwpck = new NpgsqlPasswordPacket(password, context.BackendProtocolVersion);
- BufferedStream stream = new BufferedStream(context.Stream);
- pwpck.WriteToStream(stream);
- stream.Flush();
- }
- }
-} \ No newline at end of file
+
+
+ internal sealed class NpgsqlStartupState : NpgsqlState
+ {
+ private static NpgsqlStartupState _instance = null;
+
+ private readonly String CLASSNAME = "NpgsqlStartupState";
+
+ private NpgsqlStartupState() : base()
+ { }
+
+ public static NpgsqlStartupState Instance
+ {
+ get
+ {
+ if ( _instance == null )
+ {
+ _instance = new NpgsqlStartupState();
+ }
+ return _instance;
+ }
+ }
+ public override void Authenticate( NpgsqlConnector context, string password)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Authenticate");
+ NpgsqlPasswordPacket pwpck = new NpgsqlPasswordPacket(password, context.BackendProtocolVersion);
+ BufferedStream stream = new BufferedStream(context.Stream);
+ pwpck.WriteToStream(stream, context.Encoding);
+ stream.Flush();
+
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlState.cs b/mcs/class/Npgsql/Npgsql/NpgsqlState.cs
index 9e46b57f678..e8dcad05163 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlState.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlState.cs
@@ -3,39 +3,36 @@
// Npgsql.NpgsqlState.cs
//
// Author:
-// Dave Joyner <d4ljoyn@yahoo.com>
+// Dave Joyner <d4ljoyn@yahoo.com>
//
-// Copyright (C) 2002 The Npgsql Development Team
-// npgsql-general@gborg.postgresql.org
-// http://gborg.postgresql.org/project/npgsql/projdisplay.php
+// Copyright (C) 2002 The Npgsql Development Team
+// npgsql-general@gborg.postgresql.org
+// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Collections.Generic;
using System.Data;
using System.IO;
+using System.Net;
using System.Net.Sockets;
-using System.Resources;
+using System.Collections;
using System.Text;
-using System.Net;
-using System.Threading;
+using System.Resources;
+
namespace Npgsql
{
@@ -43,11 +40,11 @@ namespace Npgsql
/// implementation.
/// </summary>
///
+
internal abstract class NpgsqlState
{
- protected static readonly Encoding ENCODING_UTF8 = Encoding.UTF8;
private readonly String CLASSNAME = "NpgsqlState";
- protected static ResourceManager resman = new ResourceManager(typeof (NpgsqlState));
+ protected static ResourceManager resman = new ResourceManager(typeof(NpgsqlState));
internal NpgsqlState()
{
@@ -57,247 +54,79 @@ namespace Npgsql
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
public virtual void Startup(NpgsqlConnector context)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
public virtual void Authenticate(NpgsqlConnector context, string password)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
- public virtual IEnumerable<IServerResponseObject> QueryEnum(NpgsqlConnector context, NpgsqlCommand command)
+ public virtual void Query(NpgsqlConnector context, NpgsqlCommand command)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
- public void Query(NpgsqlConnector context, NpgsqlCommand command)
+ public virtual void Ready( NpgsqlConnector context )
{
- IterateThroughAllResponses(QueryEnum(context, command));
+ throw new InvalidOperationException("Internal Error! " + this);
}
-
public virtual void FunctionCall(NpgsqlConnector context, NpgsqlCommand command)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
public virtual void Parse(NpgsqlConnector context, NpgsqlParse parse)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
public virtual void Flush(NpgsqlConnector context)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
- public virtual IEnumerable<IServerResponseObject> SyncEnum(NpgsqlConnector context)
+ public virtual void Sync(NpgsqlConnector context)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
- public void TestNotify(NpgsqlConnector context)
- {
- //ZA Hnotifytest CNOTIFY Z
- //Qlisten notifytest;notify notifytest;
- Stream stm = context.Stream;
- string uuidString = "uuid" + Guid.NewGuid().ToString("N");
- PGUtil.WriteString("Qlisten " + uuidString + ";notify " + uuidString + ";", stm);
- Queue<byte> buffer = new Queue<byte>();
- byte[] convertBuffer = new byte[36];
- for (;;)
- {
- int newByte = stm.ReadByte();
- if (newByte == -1)
- {
- throw new EndOfStreamException();
- }
- buffer.Enqueue((byte) newByte);
- if (buffer.Count > 35)
- {
- buffer.CopyTo(convertBuffer, 0);
- if (ENCODING_UTF8.GetString(convertBuffer) == uuidString)
- {
- for (;;)
- {
- switch (stm.ReadByte())
- {
- case -1:
- throw new EndOfStreamException();
- case 'Z':
- context.Query(new NpgsqlCommand("UNLISTEN *", context));
- return;
- }
- }
- }
- else
- {
- buffer.Dequeue();
- }
- }
- }
- }
-
- public void TestConnector(NpgsqlConnector context)
- {
- switch (context.BackendProtocolVersion)
- {
- case ProtocolVersion.Version2:
- TestNotify(context);
- break;
- case ProtocolVersion.Version3:
- EmptySync(context);
- break;
- default:
- throw new NotSupportedException();
- }
- }
-
- public void EmptySync(NpgsqlConnector context)
- {
- Stream stm = context.Stream;
- new NpgsqlSync().WriteToStream(stm);
- stm.Flush();
- Queue<int> buffer = new Queue<int>();
- //byte[] compareBuffer = new byte[6];
- int[] messageSought = new int[] {'Z', 0, 0, 0, 5};
- int newByte;
- for (;;)
- {
- switch (newByte = stm.ReadByte())
- {
- case -1:
- throw new EndOfStreamException();
- case 'E':
- case 'I':
- case 'T':
- if (buffer.Count > 4)
- {
- bool match = true;
- int i = 0;
- foreach (byte cmp in buffer)
- {
- if (cmp != messageSought[i++])
- {
- match = false;
- break;
- }
- }
- if (match)
- {
- return;
- }
- }
- break;
- default:
- buffer.Enqueue(newByte);
- if (buffer.Count > 5)
- {
- buffer.Dequeue();
- }
- break;
- }
- }
- }
-
- public NpgsqlRowDescription Sync(NpgsqlConnector context)
- {
- NpgsqlRowDescription lastDescription = null;
- foreach (IServerResponseObject obj in SyncEnum(context))
- {
- if (obj is NpgsqlRowDescription)
- {
- lastDescription = obj as NpgsqlRowDescription;
- }
- else
- {
- if (obj is IDisposable)
- {
- (obj as IDisposable).Dispose();
- }
- }
- }
- return lastDescription;
- }
-
public virtual void Bind(NpgsqlConnector context, NpgsqlBind bind)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
public virtual void Execute(NpgsqlConnector context, NpgsqlExecute execute)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
- public virtual IEnumerable<IServerResponseObject> ExecuteEnum(NpgsqlConnector context, NpgsqlExecute execute)
- {
- throw new InvalidOperationException("Internal Error! " + this);
- }
-
+
public virtual void Describe(NpgsqlConnector context, NpgsqlDescribe describe)
{
throw new InvalidOperationException("Internal Error! " + this);
}
-
+
public virtual void CancelRequest(NpgsqlConnector context)
{
throw new InvalidOperationException("Internal Error! " + this);
}
- // COPY methods
-
- protected virtual void StartCopy(NpgsqlConnector context, NpgsqlCopyFormat copyFormat)
- {
- throw new InvalidOperationException("Internal Error! " + this);
- }
-
- public virtual byte[] GetCopyData(NpgsqlConnector context)
- {
- throw new InvalidOperationException("Internal Error! " + this);
- }
-
- public virtual void SendCopyData(NpgsqlConnector context, byte[] buf, int off, int len)
- {
- throw new InvalidOperationException("Internal Error! " + this);
- }
-
- public virtual void SendCopyDone(NpgsqlConnector context)
- {
- throw new InvalidOperationException("Internal Error! " + this);
- }
-
- public virtual void SendCopyFail(NpgsqlConnector context, String message)
- {
- throw new InvalidOperationException("Internal Error! " + this);
- }
-
- public virtual NpgsqlCopyFormat CopyFormat
+ public virtual void Close( NpgsqlConnector context )
{
- get { throw new InvalidOperationException("Internal Error! " + this); }
- }
-
-
- public virtual void Close(NpgsqlConnector context)
- {
- try
- {
- context.Stream.Close();
- }
- catch
+ if (this != NpgsqlClosedState.Instance)
{
+ try
+ {
+ context.Stream.Close();
+ }
+ catch {}
+
+ context.Stream = null;
+ ChangeState( context, NpgsqlClosedState.Instance )
+ ;
}
- context.Stream = null;
- ChangeState(context, NpgsqlClosedState.Instance);
}
///<summary>
///This method is used by the states to change the state of the context.
/// </summary>
- protected static void ChangeState(NpgsqlConnector context, NpgsqlState newState)
+ protected virtual void ChangeState(NpgsqlConnector context, NpgsqlState newState)
{
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ChangeState");
context.CurrentState = newState;
}
@@ -308,735 +137,644 @@ namespace Npgsql
/// to handle backend requests.
/// </summary>
///
- internal void ProcessBackendResponses(NpgsqlConnector context)
+ internal virtual void ProcessBackendResponses( NpgsqlConnector context )
{
- IterateThroughAllResponses(ProcessBackendResponsesEnum(context));
- }
- private static void IterateThroughAllResponses(IEnumerable<IServerResponseObject> ienum)
- {
- foreach (IServerResponseObject obj in ienum) //iterate until finished.
+ try
{
- if (obj is IDisposable)
+
+ // Process commandTimeout behavior.
+
+ if ((context.Mediator.CommandTimeout > 0) && (!context.Socket.Poll(1000000 * context.Mediator.CommandTimeout, SelectMode.SelectRead)))
{
- (obj as IDisposable).Dispose();
+ // If timeout occurs when establishing the session with server then
+ // throw an exception instead of trying to cancel query. This helps to prevent loop as CancelRequest will also try to stablish a connection and sends commands.
+ if ((this is NpgsqlStartupState || this is NpgsqlConnectedState))
+ throw new NpgsqlException(resman.GetString("Exception_ConnectionTimeout"));
+ else
+ context.CancelRequest();
+
}
- }
- }
+
+
+
+ switch (context.BackendProtocolVersion)
+ {
+ case ProtocolVersion.Version2 :
+ ProcessBackendResponses_Ver_2(context);
+ break;
- private class ContextResetter : IDisposable
- {
- private readonly NpgsqlConnector _connector;
+ case ProtocolVersion.Version3 :
+ ProcessBackendResponses_Ver_3(context);
+ break;
- public ContextResetter(NpgsqlConnector connector)
- {
- _connector = connector;
+ }
}
-
- public void Dispose()
+ finally
{
- _connector.RequireReadyForQuery = true;
+ // reset expectations right after getting new responses
+ context.Mediator.ResetExpectations();
}
}
- ///<summary>
- /// This method is responsible to handle all protocol messages sent from the backend.
- /// It holds all the logic to do it.
- /// To exchange data, it uses a Mediator object from which it reads/writes information
- /// to handle backend requests.
- /// </summary>
- ///
- internal IEnumerable<IServerResponseObject> ProcessBackendResponsesEnum(NpgsqlConnector context)
+ protected virtual void ProcessBackendResponses_Ver_2( NpgsqlConnector context )
{
- try
- {
- // Process commandTimeout behavior.
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");
+
+ Stream stream = context.Stream;
+ NpgsqlMediator mediator = context.Mediator;
+
+ // Often used buffer
+ Byte[] inputBuffer = new Byte[ 4 ];
- if ((context.Mediator.CommandTimeout > 0) &&
- (!context.Socket.Poll(1000000*context.Mediator.CommandTimeout, SelectMode.SelectRead)))
+ Boolean readyForQuery = false;
+
+ byte[] asciiRowBytes = new byte[300];
+ char[] asciiRowChars = new char[300];
+
+ while (!readyForQuery)
{
- // If timeout occurs when establishing the session with server then
- // throw an exception instead of trying to cancel query. This helps to prevent loop as CancelRequest will also try to stablish a connection and sends commands.
- if (!((this is NpgsqlStartupState || this is NpgsqlConnectedState)))
+ // Check the first Byte of response.
+ switch ( stream.ReadByte() )
{
- try
+ case NpgsqlMessageTypes_Ver_2.ErrorResponse :
+
{
- context.CancelRequest();
+ NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
+ error.ReadFromStream(stream, context.Encoding);
+ error.ErrorSql = mediator.SqlSent;
+
+ mediator.Errors.Add(error);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
}
- catch
+
+ // Return imediately if it is in the startup state or connected state as
+ // there is no more messages to consume.
+ // Possible error in the NpgsqlStartupState:
+ // Invalid password.
+ // Possible error in the NpgsqlConnectedState:
+ // No pg_hba.conf configured.
+
+ if (! mediator.RequireReadyForQuery)
{
+ return;
}
- //We should have gotten an error from CancelRequest(). Whether we did or not, what we
- //really have is a timeout exception, and that will be less confusing to the user than
- //"operation cancelled by user" or similar, so whatever the case, that is what we'll throw.
- // Changed message again to report about the two possible timeouts: connection or command as the establishment timeout only was confusing users when the timeout was a command timeout.
- }
- throw new NpgsqlException(resman.GetString("Exception_ConnectionOrCommandTimeout"));
- }
- switch (context.BackendProtocolVersion)
- {
- case ProtocolVersion.Version2:
- return ProcessBackendResponses_Ver_2(context);
- case ProtocolVersion.Version3:
- return ProcessBackendResponses_Ver_3(context);
- default:
- throw new NpgsqlException(resman.GetString("Exception_UnknownProtocol"));
- }
-
- }
-
- catch(ThreadAbortException)
- {
- try
- {
- context.CancelRequest();
- context.Close();
- }
- catch {}
-
- throw;
- }
-
- }
- protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_2(NpgsqlConnector context)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");
+ break;
- using (new ContextResetter(context))
- {
- Stream stream = context.Stream;
- NpgsqlMediator mediator = context.Mediator;
- NpgsqlRowDescription lastRowDescription = null;
- List<NpgsqlError> errors = new List<NpgsqlError>();
- for (;;)
- {
- // Check the first Byte of response.
- switch ((BackEndMessageCode) stream.ReadByte())
+ case NpgsqlMessageTypes_Ver_2.AuthenticationRequest :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
+
{
- case BackEndMessageCode.ErrorResponse:
+ Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);
- {
- NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion, stream);
- error.ErrorSql = mediator.SqlSent;
+ if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationOk )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
- errors.Add(error);
+ break;
+ }
- NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
- }
+ if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationClearTextPassword )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
- // Return imediately if it is in the startup state or connected state as
- // there is no more messages to consume.
- // Possible error in the NpgsqlStartupState:
- // Invalid password.
- // Possible error in the NpgsqlConnectedState:
- // No pg_hba.conf configured.
+ // Send the PasswordPacket.
- if (!context.RequireReadyForQuery)
- {
- throw new NpgsqlException(errors);
- }
+ ChangeState( context, NpgsqlStartupState.Instance );
+ context.Authenticate(context.Password);
break;
+ }
- case BackEndMessageCode.AuthenticationRequest:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
- AuthenticationRequestType authType = (AuthenticationRequestType) PGUtil.ReadInt32(stream);
- switch (authType)
- {
- case AuthenticationRequestType.AuthenticationOk:
- NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
- break;
- case AuthenticationRequestType.AuthenticationClearTextPassword:
- NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
- // Send the PasswordPacket.
- ChangeState(context, NpgsqlStartupState.Instance);
- context.Authenticate(context.Password);
- break;
- case AuthenticationRequestType.AuthenticationMD5Password:
- NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
- // Now do the "MD5-Thing"
- // for this the Password has to be:
- // 1. md5-hashed with the username as salt
- // 2. md5-hashed again with the salt we get from the backend
+ if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationMD5Password )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
+ // Now do the "MD5-Thing"
+ // for this the Password has to be:
+ // 1. md5-hashed with the username as salt
+ // 2. md5-hashed again with the salt we get from the backend
- MD5 md5 = MD5.Create();
+ MD5 md5 = MD5.Create();
- // 1.
- byte[] passwd = ENCODING_UTF8.GetBytes(context.Password);
- byte[] saltUserName = ENCODING_UTF8.GetBytes(context.UserName);
+ // 1.
+ byte[] passwd = context.Encoding.GetBytes(context.Password);
+ byte[] saltUserName = context.Encoding.GetBytes(context.UserName);
- byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];
+ byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];
- passwd.CopyTo(crypt_buf, 0);
- saltUserName.CopyTo(crypt_buf, passwd.Length);
+ passwd.CopyTo(crypt_buf, 0);
+ saltUserName.CopyTo(crypt_buf, passwd.Length);
- StringBuilder sb = new StringBuilder();
- byte[] hashResult = md5.ComputeHash(crypt_buf);
- foreach (byte b in hashResult)
- {
- sb.Append(b.ToString("x2"));
- }
+ StringBuilder sb = new StringBuilder ();
+ byte[] hashResult = md5.ComputeHash(crypt_buf);
+ foreach (byte b in hashResult)
+ sb.Append (b.ToString ("x2"));
- String prehash = sb.ToString();
- byte[] prehashbytes = ENCODING_UTF8.GetBytes(prehash);
+ String prehash = sb.ToString();
+ byte[] prehashbytes = context.Encoding.GetBytes(prehash);
- byte[] saltServer = new byte[4];
- stream.Read(saltServer, 0, 4);
- // Send the PasswordPacket.
- ChangeState(context, NpgsqlStartupState.Instance);
- // 2.
+ byte[] saltServer = new byte[4];
+ stream.Read(saltServer, 0, 4);
+ // Send the PasswordPacket.
+ ChangeState( context, NpgsqlStartupState.Instance );
- crypt_buf = new byte[prehashbytes.Length + saltServer.Length];
- prehashbytes.CopyTo(crypt_buf, 0);
- saltServer.CopyTo(crypt_buf, prehashbytes.Length);
- sb = new StringBuilder("md5"); // This is needed as the backend expects md5 result starts with "md5"
- hashResult = md5.ComputeHash(crypt_buf);
- foreach (byte b in hashResult)
- {
- sb.Append(b.ToString("x2"));
- }
+ // 2.
- context.Authenticate(sb.ToString());
+ crypt_buf = new byte[prehashbytes.Length + saltServer.Length];
+ prehashbytes.CopyTo(crypt_buf, 0);
+ saltServer.CopyTo(crypt_buf, prehashbytes.Length);
- break;
- default:
- // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
- errors.Add(
- new NpgsqlError(context.BackendProtocolVersion,
- String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
- throw new NpgsqlException(errors);
- }
- break;
- case BackEndMessageCode.RowDescription:
- yield return lastRowDescription = new NpgsqlRowDescriptionV2(stream, context.OidToNameMapping);
- ;
- break;
- case BackEndMessageCode.DataRow:
- yield return new ForwardsOnlyRow(new StringRowReaderV2(lastRowDescription, stream));
- break;
- case BackEndMessageCode.BinaryRow:
- throw new NotSupportedException();
- case BackEndMessageCode.ReadyForQuery:
- ChangeState(context, NpgsqlReadyState.Instance);
- if (errors.Count != 0)
- {
- throw new NpgsqlException(errors);
- }
- yield break;
- case BackEndMessageCode.BackendKeyData:
- context.BackEndKeyData = new NpgsqlBackEndKeyData(context.BackendProtocolVersion, stream);
- break;
- case BackEndMessageCode.NoticeResponse:
- context.FireNotice(new NpgsqlError(context.BackendProtocolVersion, stream));
- break;
- case BackEndMessageCode.CompletedResponse:
- yield return new CompletedResponse(stream);
- break;
+ sb = new StringBuilder ("md5"); // This is needed as the backend expects md5 result starts with "md5"
+ hashResult = md5.ComputeHash(crypt_buf);
+ foreach (byte b in hashResult)
+ sb.Append (b.ToString ("x2"));
- case BackEndMessageCode.CursorResponse:
- // This is the cursor response message.
- // It is followed by a C NULL terminated string with the name of
- // the cursor in a FETCH case or 'blank' otherwise.
- // In this case it should be always 'blank'.
- // [FIXME] Get another name for this function.
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CursorResponse");
+ context.Authenticate(sb.ToString ());
- String cursorName = PGUtil.ReadString(stream);
- // Continue waiting for ReadyForQuery message.
break;
+ }
- case BackEndMessageCode.EmptyQueryResponse:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
- PGUtil.ReadString(stream);
- break;
+ // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
- case BackEndMessageCode.NotificationResponse:
- context.FireNotification(new NpgsqlNotificationEventArgs(stream, false));
- if (context.IsNotificationThreadRunning)
- {
- yield break;
- }
- break;
- case BackEndMessageCode.IO_ERROR:
- // Connection broken. Mono returns -1 instead of throw an exception as ms.net does.
- throw new IOException();
-
- default:
- // This could mean a number of things
- // We've gotten out of sync with the backend?
- // We need to implement this type?
- // Backend has gone insane?
- throw new DataException("Backend sent unrecognized response type");
+ mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
+ }
+
+ return;
+
+ case NpgsqlMessageTypes_Ver_2.RowDescription:
+ // This is the RowDescription message.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
+
+ {
+ NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
+ rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);
+
+ // Initialize the array list which will contain the data from this rowdescription.
+ mediator.AddRowDescription(rd);
+ }
+
+ // Now wait for the AsciiRow messages.
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.AsciiRow:
+ // This is the AsciiRow message.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");
+
+ {
+ NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
+ asciiRow.ReadFromStream(stream, context.Encoding);
+
+ // Add this row to the rows array.
+ mediator.AddAsciiRow(asciiRow);
}
+
+ // Now wait for CompletedResponse message.
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.BinaryRow:
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BinaryRow");
+
+ {
+ NpgsqlBinaryRow binaryRow = new NpgsqlBinaryRow(context.Mediator.LastRowDescription);
+ binaryRow.ReadFromStream(stream, context.Encoding);
+
+ mediator.AddBinaryRow(binaryRow);
+ }
+
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.ReadyForQuery :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
+ readyForQuery = true;
+ ChangeState( context, NpgsqlReadyState.Instance );
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.BackendKeyData :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
+ // BackendKeyData message.
+ NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion);
+ backend_keydata.ReadFromStream(stream);
+ mediator.SetBackendKeydata(backend_keydata);
+
+
+ // Wait for ReadForQuery message
+ break;
+ ;
+
+ case NpgsqlMessageTypes_Ver_2.NoticeResponse :
+
+ {
+ NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
+ notice.ReadFromStream(stream, context.Encoding);
+
+ mediator.Notices.Add(notice);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
+ }
+
+ // Wait for ReadForQuery message
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.CompletedResponse :
+ // This is the CompletedResponse message.
+ // Get the string returned.
+
+
+ String result = PGUtil.ReadString(stream, context.Encoding);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, result);
+ // Add result from the processing.
+
+ mediator.AddCompletedResponse(result);
+
+ // Now wait for ReadyForQuery message.
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.CursorResponse :
+ // This is the cursor response message.
+ // It is followed by a C NULL terminated string with the name of
+ // the cursor in a FETCH case or 'blank' otherwise.
+ // In this case it should be always 'blank'.
+ // [FIXME] Get another name for this function.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CursorResponse");
+
+ String cursorName = PGUtil.ReadString(stream, context.Encoding);
+ // Continue waiting for ReadyForQuery message.
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.EmptyQueryResponse :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
+ PGUtil.ReadString(stream, context.Encoding);
+ break;
+
+ case NpgsqlMessageTypes_Ver_2.NotificationResponse :
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");
+
+ Int32 PID = PGUtil.ReadInt32(stream, inputBuffer);
+ String notificationResponse = PGUtil.ReadString( stream, context.Encoding );
+ mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));
+
+ if (context.IsNotificationThreadRunning)
+ readyForQuery = true;
+
+ // Wait for ReadForQuery message
+ break;
+
+ case -1:
+ // Connection broken. Mono returns -1 instead of throw an exception as ms.net does.
+ throw new IOException();
+
+ default :
+ // This could mean a number of things
+ // We've gotten out of sync with the backend?
+ // We need to implement this type?
+ // Backend has gone insane?
+ // FIXME
+ // what exception should we really throw here?
+ throw new NotSupportedException("Backend sent unrecognized response type");
+
}
}
}
- private enum BackEndMessageCode
+ protected virtual void ProcessBackendResponses_Ver_3( NpgsqlConnector context )
{
- IO_ERROR = -1, // Connection broken. Mono returns -1 instead of throwing an exception as ms.net does.
-
- CopyData = 'd',
- CopyDone = 'c',
- DataRow = 'D',
- BinaryRow = 'B', //Version 2 only
-
- BackendKeyData = 'K',
- CancelRequest = 'F',
- CompletedResponse = 'C',
- CopyDataRows = ' ',
- CopyInResponse = 'G',
- CopyOutResponse = 'H',
- CursorResponse = 'P', //Version 2 only
- EmptyQueryResponse = 'I',
- ErrorResponse = 'E',
- FunctionCall = 'F',
- FunctionCallResponse = 'V',
-
- AuthenticationRequest = 'R',
-
- NoticeResponse = 'N',
- NotificationResponse = 'A',
- ParameterStatus = 'S',
- PasswordPacket = ' ',
- ReadyForQuery = 'Z',
- RowDescription = 'T',
- SSLRequest = ' ',
-
- // extended query backend messages
- ParseComplete = '1',
- BindComplete = '2',
- PortalSuspended = 's',
- ParameterDescription = 't',
- NoData = 'n',
- CloseComplete = '3'
- }
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");
- private enum AuthenticationRequestType
- {
- AuthenticationOk = 0,
- AuthenticationKerberosV4 = 1,
- AuthenticationKerberosV5 = 2,
- AuthenticationClearTextPassword = 3,
- AuthenticationCryptPassword = 4,
- AuthenticationMD5Password = 5,
- AuthenticationSCMCredential = 6,
- AuthenticationGSS = 7,
- AuthenticationGSSContinue = 8,
- AuthenticationSSPI = 9
- }
+ Stream stream = context.Stream;
+ NpgsqlMediator mediator = context.Mediator;
- protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_3(NpgsqlConnector context)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");
+ // Often used buffers
+ Byte[] inputBuffer = new Byte[ 4 ];
+ String Str;
+
+ Boolean readyForQuery = false;
+
+ byte[] asciiRowBytes = new byte[300];
+ char[] asciiRowChars = new char[300];
- using (new ContextResetter(context))
+ while (!readyForQuery)
{
- Stream stream = context.Stream;
- NpgsqlMediator mediator = context.Mediator;
+ // Check the first Byte of response.
+ Int32 message = stream.ReadByte();
+ switch ( message )
+ {
+ case NpgsqlMessageTypes_Ver_3.ErrorResponse :
- NpgsqlRowDescription lastRowDescription = null;
+ {
+ NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
+ error.ReadFromStream(stream, context.Encoding);
+ error.ErrorSql = mediator.SqlSent;
- List<NpgsqlError> errors = new List<NpgsqlError>();
+ mediator.Errors.Add(error);
- for (;;)
- {
- // Check the first Byte of response.
- BackEndMessageCode message = (BackEndMessageCode) stream.ReadByte();
- switch (message)
+ NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
+ }
+
+ // Return imediately if it is in the startup state or connected state as
+ // there is no more messages to consume.
+ // Possible error in the NpgsqlStartupState:
+ // Invalid password.
+ // Possible error in the NpgsqlConnectedState:
+ // No pg_hba.conf configured.
+
+ if (! mediator.RequireReadyForQuery)
{
- case BackEndMessageCode.ErrorResponse:
+ return;
+ }
- NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion, stream);
- error.ErrorSql = mediator.SqlSent;
+ break;
- errors.Add(error);
- NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
+ case NpgsqlMessageTypes_Ver_3.AuthenticationRequest :
- // Return imediately if it is in the startup state or connected state as
- // there is no more messages to consume.
- // Possible error in the NpgsqlStartupState:
- // Invalid password.
- // Possible error in the NpgsqlConnectedState:
- // No pg_hba.conf configured.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
- if (!context.RequireReadyForQuery)
- {
- throw new NpgsqlException(errors);
- }
+ // Eat length
+ PGUtil.ReadInt32(stream, inputBuffer);
- break;
- case BackEndMessageCode.AuthenticationRequest:
+ {
+ Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
+ if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationOk )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
- // Get the length in case we're getting AuthenticationGSSContinue
- int authDataLength = PGUtil.ReadInt32(stream) - 8;
+ break;
+ }
- AuthenticationRequestType authType = (AuthenticationRequestType) PGUtil.ReadInt32(stream);
- switch (authType)
- {
- case AuthenticationRequestType.AuthenticationOk:
- NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
- break;
- case AuthenticationRequestType.AuthenticationClearTextPassword:
- NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
+ if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationClearTextPassword )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
- // Send the PasswordPacket.
+ // Send the PasswordPacket.
- ChangeState(context, NpgsqlStartupState.Instance);
- context.Authenticate(context.Password);
+ ChangeState( context, NpgsqlStartupState.Instance );
+ context.Authenticate(context.Password);
- break;
- case AuthenticationRequestType.AuthenticationMD5Password:
- NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
- // Now do the "MD5-Thing"
- // for this the Password has to be:
- // 1. md5-hashed with the username as salt
- // 2. md5-hashed again with the salt we get from the backend
+ break;
+ }
- MD5 md5 = MD5.Create();
+ if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationMD5Password )
+ {
+ NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
+ // Now do the "MD5-Thing"
+ // for this the Password has to be:
+ // 1. md5-hashed with the username as salt
+ // 2. md5-hashed again with the salt we get from the backend
- // 1.
- byte[] passwd = ENCODING_UTF8.GetBytes(context.Password);
- byte[] saltUserName = ENCODING_UTF8.GetBytes(context.UserName);
+ MD5 md5 = MD5.Create();
- byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];
- passwd.CopyTo(crypt_buf, 0);
- saltUserName.CopyTo(crypt_buf, passwd.Length);
+ // 1.
+ byte[] passwd = context.Encoding.GetBytes(context.Password);
+ byte[] saltUserName = context.Encoding.GetBytes(context.UserName);
+ byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];
- StringBuilder sb = new StringBuilder();
- byte[] hashResult = md5.ComputeHash(crypt_buf);
- foreach (byte b in hashResult)
- {
- sb.Append(b.ToString("x2"));
- }
+ passwd.CopyTo(crypt_buf, 0);
+ saltUserName.CopyTo(crypt_buf, passwd.Length);
- String prehash = sb.ToString();
- byte[] prehashbytes = ENCODING_UTF8.GetBytes(prehash);
- crypt_buf = new byte[prehashbytes.Length + 4];
+ StringBuilder sb = new StringBuilder ();
+ byte[] hashResult = md5.ComputeHash(crypt_buf);
+ foreach (byte b in hashResult)
+ sb.Append (b.ToString ("x2"));
- stream.Read(crypt_buf, prehashbytes.Length, 4);
- // Send the PasswordPacket.
- ChangeState(context, NpgsqlStartupState.Instance);
+ String prehash = sb.ToString();
+ byte[] prehashbytes = context.Encoding.GetBytes(prehash);
- // 2.
- prehashbytes.CopyTo(crypt_buf, 0);
- sb = new StringBuilder("md5"); // This is needed as the backend expects md5 result starts with "md5"
- hashResult = md5.ComputeHash(crypt_buf);
- foreach (byte b in hashResult)
- {
- sb.Append(b.ToString("x2"));
- }
- context.Authenticate(sb.ToString());
+ stream.Read(inputBuffer, 0, 4);
+ // Send the PasswordPacket.
+ ChangeState( context, NpgsqlStartupState.Instance );
- break;
-#if WINDOWS && UNMANAGED
- case AuthenticationRequestType.AuthenticationSSPI:
- {
- if (context.IntegratedSecurity)
- {
- // For SSPI we have to get the IP-Address (hostname doesn't work)
- string ipAddressString = ((IPEndPoint)context.Socket.RemoteEndPoint).Address.ToString();
- context.SSPI = new SSPIHandler(ipAddressString, "POSTGRES");
- ChangeState(context, NpgsqlStartupState.Instance);
- context.Authenticate(context.SSPI.Continue(null));
- break;
- }
- else
- {
- // TODO: correct exception
- throw new Exception();
- }
- }
+ // 2.
+ crypt_buf = new byte[prehashbytes.Length + 4];
+ prehashbytes.CopyTo(crypt_buf, 0);
+ inputBuffer.CopyTo(crypt_buf, prehashbytes.Length);
- case AuthenticationRequestType.AuthenticationGSSContinue:
- {
- byte[] authData = new byte[authDataLength];
- PGUtil.CheckedStreamRead(stream, authData, 0, authDataLength);
- context.Authenticate(context.SSPI.Continue(authData));
- break;
- }
+ sb = new StringBuilder ("md5"); // This is needed as the backend expects md5 result starts with "md5"
+ hashResult = md5.ComputeHash(crypt_buf);
+ foreach (byte b in hashResult)
+ sb.Append (b.ToString ("x2"));
-#endif
+ context.Authenticate(sb.ToString ());
- default:
- // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
- errors.Add(
- new NpgsqlError(context.BackendProtocolVersion,
- String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
- throw new NpgsqlException(errors);
- }
- break;
- case BackEndMessageCode.RowDescription:
- yield return lastRowDescription = new NpgsqlRowDescriptionV3(stream, context.OidToNameMapping);
break;
- case BackEndMessageCode.ParameterDescription:
+ }
- // Do nothing,for instance, just read...
- int lenght = PGUtil.ReadInt32(stream);
- int nb_param = PGUtil.ReadInt16(stream);
- for (int i = 0; i < nb_param; i++)
- {
- int typeoid = PGUtil.ReadInt32(stream);
- }
+ // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
+ mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
+ }
- break;
+ return;
- case BackEndMessageCode.DataRow:
- yield return new ForwardsOnlyRow(new StringRowReaderV3(lastRowDescription, stream));
- break;
+ case NpgsqlMessageTypes_Ver_3.RowDescription:
+ // This is the RowDescription message.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
+ {
+ NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
+ rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);
- case BackEndMessageCode.ReadyForQuery:
+ mediator.AddRowDescription(rd);
+ }
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
+ // Now wait for the AsciiRow messages.
+ break;
+ case NpgsqlMessageTypes_Ver_3.ParameterDescription:
+
+ // Do nothing,for instance, just read...
+ int lenght = PGUtil.ReadInt32(stream, inputBuffer);
+ int nb_param = PGUtil.ReadInt16(stream, inputBuffer);
+ for (int i=0; i < nb_param; i++)
+ {
+ int typeoid = PGUtil.ReadInt32(stream, inputBuffer);
+ }
+
+ break;
- // Possible status bytes returned:
- // I = Idle (no transaction active).
- // T = In transaction, ready for more.
- // E = Error in transaction, queries will fail until transaction aborted.
- // Just eat the status byte, we have no use for it at this time.
- PGUtil.ReadInt32(stream);
- stream.ReadByte();
+ case NpgsqlMessageTypes_Ver_3.DataRow:
+ // This is the AsciiRow message.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "DataRow");
+ {
+ NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
+ asciiRow.ReadFromStream(stream, context.Encoding);
- ChangeState(context, NpgsqlReadyState.Instance);
+ // Add this row to the rows array.
+ mediator.AddAsciiRow(asciiRow);
+ }
- if (errors.Count != 0)
- {
- throw new NpgsqlException(errors);
- }
+ // Now wait for CompletedResponse message.
+ break;
- yield break;
+ case NpgsqlMessageTypes_Ver_3.ReadyForQuery :
- case BackEndMessageCode.BackendKeyData:
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
- // BackendKeyData message.
- NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion, stream);
- context.BackEndKeyData = backend_keydata;
+ // Possible status bytes returned:
+ // I = Idle (no transaction active).
+ // T = In transaction, ready for more.
+ // E = Error in transaction, queries will fail until transaction aborted.
+ // Just eat the status byte, we have no use for it at this time.
+ PGUtil.ReadInt32(stream, inputBuffer);
+ PGUtil.ReadString(stream, context.Encoding, 1);
+ readyForQuery = true;
+ ChangeState( context, NpgsqlReadyState.Instance );
- // Wait for ReadForQuery message
- break;
+ break;
- case BackEndMessageCode.NoticeResponse:
- // Notices and errors are identical except that we
- // just throw notices away completely ignored.
- context.FireNotice(new NpgsqlError(context.BackendProtocolVersion, stream));
- break;
+ case NpgsqlMessageTypes_Ver_3.BackendKeyData :
- case BackEndMessageCode.CompletedResponse:
- PGUtil.ReadInt32(stream);
- yield return new CompletedResponse(stream);
- break;
- case BackEndMessageCode.ParseComplete:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParseComplete");
- // Just read up the message length.
- PGUtil.ReadInt32(stream);
- yield break;
- case BackEndMessageCode.BindComplete:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
- // Just read up the message length.
- PGUtil.ReadInt32(stream);
- yield break;
- case BackEndMessageCode.EmptyQueryResponse:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
- PGUtil.ReadInt32(stream);
- break;
- case BackEndMessageCode.NotificationResponse:
- // Eat the length
- PGUtil.ReadInt32(stream);
- context.FireNotification(new NpgsqlNotificationEventArgs(stream, true));
- if (context.IsNotificationThreadRunning)
- {
- yield break;
- }
- break;
- case BackEndMessageCode.ParameterStatus:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
- NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus(stream);
-
- NpgsqlEventLog.LogMsg(resman, "Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter,
- parameterStatus.ParameterValue);
-
- context.AddParameterStatus(parameterStatus);
-
- if (parameterStatus.Parameter == "server_version")
- {
- // Deal with this here so that if there are
- // changes in a future backend version, we can handle it here in the
- // protocol handler and leave everybody else put of it.
- string versionString = parameterStatus.ParameterValue.Trim();
- for (int idx = 0; idx != versionString.Length; ++idx)
- {
- char c = parameterStatus.ParameterValue[idx];
- if (!char.IsDigit(c) && c != '.')
- {
- versionString = versionString.Substring(0, idx);
- break;
- }
- }
- context.ServerVersion = new Version(versionString);
- }
- break;
- case BackEndMessageCode.NoData:
- // This nodata message may be generated by prepare commands issued with queries which doesn't return rows
- // for example insert, update or delete.
- // Just eat the message.
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
- PGUtil.ReadInt32(stream);
- break;
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
+ // BackendKeyData message.
+ NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion);
+ backend_keydata.ReadFromStream(stream);
+ mediator.SetBackendKeydata(backend_keydata);
- case BackEndMessageCode.CopyInResponse:
- // Enter COPY sub protocol and start pushing data to server
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyInResponse");
- ChangeState(context, NpgsqlCopyInState.Instance);
- PGUtil.ReadInt32(stream); // length redundant
- context.CurrentState.StartCopy(context, ReadCopyHeader(stream));
- yield break;
- // Either StartCopy called us again to finish the operation or control should be passed for user to feed copy data
-
- case BackEndMessageCode.CopyOutResponse:
- // Enter COPY sub protocol and start pulling data from server
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyOutResponse");
- ChangeState(context, NpgsqlCopyOutState.Instance);
- PGUtil.ReadInt32(stream); // length redundant
- context.CurrentState.StartCopy(context, ReadCopyHeader(stream));
- yield break;
- // Either StartCopy called us again to finish the operation or control should be passed for user to feed copy data
-
- case BackEndMessageCode.CopyData:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyData");
- Int32 len = PGUtil.ReadInt32(stream) - 4;
- byte[] buf = new byte[len];
- stream.Read(buf, 0, len);
- context.Mediator.ReceivedCopyData = buf;
- yield break; // read data from server one chunk at a time while staying in copy operation mode
-
- case BackEndMessageCode.CopyDone:
- NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyDone");
- PGUtil.ReadInt32(stream); // CopyDone can not have content so this is always 4
- // This will be followed by normal CommandComplete + ReadyForQuery so no op needed
- break;
- case BackEndMessageCode.IO_ERROR:
- // Connection broken. Mono returns -1 instead of throwing an exception as ms.net does.
- throw new IOException();
-
- default:
- // This could mean a number of things
- // We've gotten out of sync with the backend?
- // We need to implement this type?
- // Backend has gone insane?
- // FIXME
- // what exception should we really throw here?
- throw new NotSupportedException(String.Format("Backend sent unrecognized response type: {0}", (Char) message));
+ // Wait for ReadForQuery message
+ break;
+
+ case NpgsqlMessageTypes_Ver_3.NoticeResponse :
+
+ // Notices and errors are identical except that we
+ // just throw notices away completely ignored.
+ {
+ NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
+ notice.ReadFromStream(stream, context.Encoding);
+
+ mediator.Notices.Add(notice);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
}
- }
- }
- }
+ // Wait for ReadForQuery message
+ break;
- private static NpgsqlCopyFormat ReadCopyHeader(Stream stream)
- {
- byte copyFormat = (byte) stream.ReadByte();
- Int16 numCopyFields = PGUtil.ReadInt16(stream);
- Int16[] copyFieldFormats = new Int16[numCopyFields];
- for (Int16 i = 0; i < numCopyFields; i++)
- {
- copyFieldFormats[i] = PGUtil.ReadInt16(stream);
- }
- return new NpgsqlCopyFormat(copyFormat, copyFieldFormats);
- }
- }
+ case NpgsqlMessageTypes_Ver_3.CompletedResponse :
+ // This is the CompletedResponse message.
+ // Get the string returned.
- /// <summary>
- /// Represents a completed response message.
- /// </summary>
- internal class CompletedResponse : IServerResponseObject
- {
- private readonly int? _rowsAffected;
- private readonly long? _lastInsertedOID;
+ PGUtil.ReadInt32(stream, inputBuffer);
+ Str = PGUtil.ReadString(stream, context.Encoding);
- public CompletedResponse(Stream stream)
- {
- string[] tokens = PGUtil.ReadString(stream).Split();
- if (tokens.Length > 1)
- {
- int rowsAffected;
- if (int.TryParse(tokens[tokens.Length - 1], out rowsAffected))
- _rowsAffected = rowsAffected;
- else
- _rowsAffected = null;
-
- }
- _lastInsertedOID = (tokens.Length > 2 && tokens[0].Trim().ToUpperInvariant() == "INSERT")
- ? long.Parse(tokens[1])
- : (long?) null;
- }
+ NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, Str);
- public long? LastInsertedOID
- {
- get { return _lastInsertedOID; }
- }
+ // Add result from the processing.
+ mediator.AddCompletedResponse(Str);
- public int? RowsAffected
- {
- get { return _rowsAffected; }
- }
- }
+ break;
- /// <summary>
- /// For classes representing messages sent from the client to the server.
- /// </summary>
- internal abstract class ClientMessage
- {
- protected static readonly Encoding UTF8Encoding = Encoding.UTF8;
- public abstract void WriteToStream(Stream outputStream);
- }
+ case NpgsqlMessageTypes_Ver_3.ParseComplete :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParseComplete");
+ // Just read up the message length.
+ PGUtil.ReadInt32(stream, inputBuffer);
+ readyForQuery = true;
+ break;
- /// <summary>
- /// Marker interface which identifies a class which represents part of
- /// a response from the server.
- internal interface IServerResponseObject
- {
- }
+ case NpgsqlMessageTypes_Ver_3.BindComplete :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
+ // Just read up the message length.
+ PGUtil.ReadInt32(stream, inputBuffer);
+ readyForQuery = true;
+ break;
- /// <summary>
- /// Marker interface which identifies a class which may take possession of a stream for the duration of
- /// it's lifetime (possibly temporarily giving that possession to another class for part of that time.
- ///
- /// It inherits from IDisposable, since any such class must make sure it leaves the stream in a valid state.
- ///
- /// The most important such class is that compiler-generated from ProcessBackendResponsesEnum. Of course
- /// we can't make that inherit from this interface, alas.
- /// </summary>
- internal interface IStreamOwner : IServerResponseObject, IDisposable
- {
+ case NpgsqlMessageTypes_Ver_3.EmptyQueryResponse :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
+ PGUtil.ReadInt32(stream, inputBuffer);
+ break;
+
+ case NpgsqlMessageTypes_Ver_3.NotificationResponse :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");
+
+ // Eat the length
+ PGUtil.ReadInt32(stream, inputBuffer);
+ {
+ // Process ID sending notification
+ Int32 PID = PGUtil.ReadInt32(stream, inputBuffer);
+ // Notification string
+ String notificationResponse = PGUtil.ReadString( stream, context.Encoding );
+ // Additional info, currently not implemented by PG (empty string always), eat it
+ PGUtil.ReadString( stream, context.Encoding );
+ mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));
+ }
+
+ if (context.IsNotificationThreadRunning)
+ readyForQuery = true;
+
+ // Wait for ReadForQuery message
+ break;
+
+ case NpgsqlMessageTypes_Ver_3.ParameterStatus :
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
+ NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus();
+ parameterStatus.ReadFromStream(stream, context.Encoding);
+
+ NpgsqlEventLog.LogMsg(resman, "Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter, parameterStatus.ParameterValue);
+
+ mediator.AddParameterStatus(parameterStatus.Parameter, parameterStatus);
+
+ if (parameterStatus.Parameter == "server_version")
+ {
+ // Add this one under our own name so that if the parameter name
+ // changes in a future backend version, we can handle it here in the
+ // protocol handler and leave everybody else put of it.
+ mediator.AddParameterStatus("__npgsql_server_version", parameterStatus);
+ // context.ServerVersionString = parameterStatus.ParameterValue;
+ }
+
+ break;
+ case NpgsqlMessageTypes_Ver_3.NoData :
+ // This nodata message may be generated by prepare commands issued with queries which doesn't return rows
+ // for example insert, update or delete.
+ // Just eat the message.
+ NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
+ PGUtil.ReadInt32(stream, inputBuffer);
+ break;
+
+
+ case -1:
+ // Connection broken. Mono returns -1 instead of throw an exception as ms.net does.
+ throw new IOException();
+
+ default :
+ // This could mean a number of things
+ // We've gotten out of sync with the backend?
+ // We need to implement this type?
+ // Backend has gone insane?
+ // FIXME
+ // what exception should we really throw here?
+ throw new NotSupportedException(String.Format("Backend sent unrecognized response type: {0}", (Char)message));
+
+ }
+ }
+ }
}
-} \ No newline at end of file
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlState.resx b/mcs/class/Npgsql/Npgsql/NpgsqlState.resx
index 71ea189b2b3..d4071715e8f 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlState.resx
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlState.resx
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<root>
<!--
Microsoft ResX Schema
@@ -140,19 +140,5 @@
<data name="Exception_ConnectionTimeout">
<value>Connection establishment timeout. Increase Timeout value in ConnectionString.</value>
</data>
- <data name="Exception_ConnectionOrCommandTimeout">
- <value>A timeout has occured. If you were establishing a connection, increase Timeout value in ConnectionString. If you were executing a command, increate the CommandTimeout value in ConnectionString or in your NpgsqlCommand object.</value>
- </data>
- <data name="Log_ConnectingTo">
- <value>Attempt to connect to '{0}'.</value>
- </data>
- <data name="Log_FailedConnection">
- <value>Failed to establish a connection to '{0}'.</value>
- </data>
-
- <data name="Exception_FailedConnection">
- <value>Failed to establish a connection to '{0}'.</value>
- </data>
-
</root>
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlSync.cs b/mcs/class/Npgsql/Npgsql/NpgsqlSync.cs
index 801f4a966a4..e8c4e0b3af4 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlSync.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlSync.cs
@@ -9,42 +9,45 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+using System;
using System.IO;
+using System.Text;
namespace Npgsql
{
- /// <summary>
- /// This class represents the Parse message sent to PostgreSQL
- /// server.
- /// </summary>
- ///
- internal sealed class NpgsqlSync : ClientMessage
- {
- // Logging related values
- //private static readonly String CLASSNAME = "NpgsqlSync";
-
- public override void WriteToStream(Stream outputStream)
- {
- outputStream.WriteByte((byte) FrontEndMessageCode.Sync);
-
- PGUtil.WriteInt32(outputStream, 4);
- }
- }
-} \ No newline at end of file
+
+ /// <summary>
+ /// This class represents the Parse message sent to PostgreSQL
+ /// server.
+ /// </summary>
+ ///
+ internal sealed class NpgsqlSync
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlSync";
+
+ public void WriteToStream(Stream outputStream, Encoding encoding)
+ {
+ outputStream.WriteByte((Byte)'S');
+
+ PGUtil.WriteInt32(outputStream, 4);
+
+ }
+
+ }
+}
+
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.cs b/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.cs
index 0fd3c5c3497..832c1156ec6 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.cs
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.cs
@@ -3,71 +3,65 @@
// Npgsql.NpgsqlTransaction.cs
//
// Author:
-// Francisco Jr. (fxjrlists@yahoo.com.br)
+// Francisco Jr. (fxjrlists@yahoo.com.br)
//
-// Copyright (C) 2002 The Npgsql Development Team
-// npgsql-general@gborg.postgresql.org
-// http://gborg.postgresql.org/project/npgsql/projdisplay.php
+// Copyright (C) 2002 The Npgsql Development Team
+// npgsql-general@gborg.postgresql.org
+// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Data;
-using System.Data.Common;
-using System.Resources;
using System.Text;
-using System.Threading;
+using System.Resources;
+using System.Data;
+
namespace Npgsql
{
/// <summary>
/// Represents a transaction to be made in a PostgreSQL database. This class cannot be inherited.
/// </summary>
- public sealed class NpgsqlTransaction : DbTransaction
+ public sealed class NpgsqlTransaction : MarshalByRefObject, IDbTransaction
{
private static readonly String CLASSNAME = "NpgsqlTransaction";
- private static ResourceManager resman = new ResourceManager(typeof (NpgsqlTransaction));
+ private static ResourceManager resman = new ResourceManager(typeof(NpgsqlTransaction));
- private NpgsqlConnection _conn = null;
- private readonly IsolationLevel _isolation = IsolationLevel.ReadCommitted;
- private bool _disposed = false;
+ private NpgsqlConnection _conn = null;
+ private IsolationLevel _isolation = IsolationLevel.ReadCommitted;
+ private bool _disposed = false;
- internal NpgsqlTransaction(NpgsqlConnection conn)
- : this(conn, IsolationLevel.ReadCommitted)
- {
- }
+ internal NpgsqlTransaction(NpgsqlConnection conn) : this(conn, IsolationLevel.ReadCommitted)
+ {}
internal NpgsqlTransaction(NpgsqlConnection conn, IsolationLevel isolation)
{
- resman = new ResourceManager(this.GetType());
+ resman = new System.Resources.ResourceManager(this.GetType());
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
-
+
_conn = conn;
_isolation = isolation;
StringBuilder commandText = new StringBuilder("BEGIN; SET TRANSACTION ISOLATION LEVEL ");
- if ((isolation == IsolationLevel.RepeatableRead) || (isolation == IsolationLevel.Serializable))
- {
+ if ( (isolation == IsolationLevel.RepeatableRead) ||
+ (isolation == IsolationLevel.Serializable)
+ )
commandText.Append("SERIALIZABLE");
- }
else
{
// Set isolation level default to read committed.
@@ -78,7 +72,7 @@ namespace Npgsql
commandText.Append(";");
NpgsqlCommand command = new NpgsqlCommand(commandText.ToString(), conn.Connector);
- command.ExecuteBlind();
+ command.ExecuteNonQuery();
_conn.Connector.Transaction = this;
}
@@ -89,14 +83,21 @@ namespace Npgsql
/// </summary>
/// <value>The <see cref="Npgsql.NpgsqlConnection">NpgsqlConnection</see>
/// object associated with the transaction.</value>
- public new NpgsqlConnection Connection
+ public NpgsqlConnection Connection
{
- get { return _conn; }
+ get
+ {
+ return _conn;
+ }
}
- protected override DbConnection DbConnection
+
+ IDbConnection IDbTransaction.Connection
{
- get { return Connection; }
+ get
+ {
+ return Connection;
+ }
}
/// <summary>
@@ -104,7 +105,7 @@ namespace Npgsql
/// </summary>
/// <value>The <see cref="System.Data.IsolationLevel">IsolationLevel</see> for this transaction.
/// The default is <b>ReadCommitted</b>.</value>
- public override IsolationLevel IsolationLevel
+ public IsolationLevel IsolationLevel
{
get
{
@@ -117,36 +118,33 @@ namespace Npgsql
}
}
- protected override void Dispose(bool disposing)
+ /// <summary>
+ /// Releases the unmanaged resources used by the
+ /// <see cref="Npgsql.NpgsqlTransaction">NpgsqlTransaction</see>
+ /// and optionally releases the managed resources.
+ /// </summary>
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+
+ this.Dispose(true);
+ }
+
+ private void Dispose(Boolean disposing)
{
- if (disposing && this._conn != null)
+ if(disposing && this._conn != null)
{
if (_conn.Connector.Transaction != null)
- {
- if ((Thread.CurrentThread.ThreadState & (ThreadState.Aborted | ThreadState.AbortRequested)) != 0)
- {
- // can't count on Rollback working if the thread has been aborted
- // need to copy since Cancel will set it to null
- NpgsqlConnection conn = _conn;
- Cancel();
- // must close connection since transaction hasn't been rolled back
- conn.Close();
- }
- else
- {
- this.Rollback();
- }
- }
+ this.Rollback();
this._disposed = true;
}
- base.Dispose(disposing);
}
/// <summary>
/// Commits the database transaction.
/// </summary>
- public override void Commit()
+ public void Commit()
{
CheckDisposed();
@@ -158,7 +156,7 @@ namespace Npgsql
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Commit");
NpgsqlCommand command = new NpgsqlCommand("COMMIT", _conn.Connector);
- command.ExecuteBlind();
+ command.ExecuteNonQuery();
_conn.Connector.Transaction = null;
_conn = null;
}
@@ -166,7 +164,7 @@ namespace Npgsql
/// <summary>
/// Rolls back a transaction from a pending state.
/// </summary>
- public override void Rollback()
+ public void Rollback()
{
CheckDisposed();
@@ -178,74 +176,11 @@ namespace Npgsql
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Rollback");
NpgsqlCommand command = new NpgsqlCommand("ROLLBACK", _conn.Connector);
- command.ExecuteBlind();
+ command.ExecuteNonQuery();
_conn.Connector.Transaction = null;
_conn = null;
}
-
- /// <summary>
- /// Rolls back a transaction from a pending savepoint state.
- /// </summary>
- public void Rollback(String savePointName)
- {
-
- CheckDisposed();
-
- if (_conn == null)
- {
- throw new InvalidOperationException(resman.GetString("Exception_NoTransaction"));
- }
-
- if (!_conn.Connector.SupportsSavepoint)
- {
- throw new InvalidOperationException(resman.GetString("Exception_SavePointNotSupported"));
- }
-
-
-
- if (savePointName.Contains(";"))
- {
- throw new InvalidOperationException(resman.GetString("Exception_SavePointWithSemicolon"));
-
- }
-
-
- NpgsqlCommand command = new NpgsqlCommand("ROLLBACK TO SAVEPOINT " + savePointName, _conn.Connector);
- command.ExecuteBlind();
-
- }
-
- /// <summary>
- /// Creates a transaction save point.
- /// </summary>
-
- public void Save(String savePointName)
- {
-
- CheckDisposed();
- if (_conn == null)
- {
- throw new InvalidOperationException(resman.GetString("Exception_NoTransaction"));
- }
-
- if (!_conn.Connector.SupportsSavepoint)
- {
- throw new InvalidOperationException(resman.GetString("Exception_SavePointNotSupported"));
- }
-
-
- if (savePointName.Contains(";"))
- {
- throw new InvalidOperationException(resman.GetString("Exception_SavePointWithSemicolon"));
-
- }
-
-
- NpgsqlCommand command = new NpgsqlCommand("SAVEPOINT " + savePointName, _conn.Connector);
- command.ExecuteBlind();
-
- }
/// <summary>
/// Cancel the transaction without telling the backend about it. This is
/// used to make the transaction go away when closing a connection.
@@ -261,18 +196,25 @@ namespace Npgsql
}
}
- internal bool Disposed
- {
- get { return _disposed; }
+ internal bool Disposed{
+ get
+ {
+ return _disposed;
+ }
}
internal void CheckDisposed()
{
if (_disposed)
- {
throw new ObjectDisposedException(CLASSNAME);
- }
+
}
+
+ ~NpgsqlTransaction()
+ {
+ Dispose(false);
+ }
+
}
-} \ No newline at end of file
+}
diff --git a/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.resx b/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.resx
index 9096729d4e9..ce394ae88d8 100644
--- a/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.resx
+++ b/mcs/class/Npgsql/Npgsql/NpgsqlTransaction.resx
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<root>
<!--
Microsoft ResX Schema
@@ -100,10 +100,4 @@
<data name="Exception_NoTransaction">
<value>No transaction in progress.</value>
</data>
- <data name="Exception_SavePointWithSemicolon">
- <value>Savepoint name cannot have semicolon.</value>
- </data>
- <data name="Exception_SavePointNotSupported">
- <value>Savepoint is not supported by backend.</value>
- </data>
</root>
diff --git a/mcs/class/Npgsql/Npgsql/PGUtil.cs b/mcs/class/Npgsql/Npgsql/PGUtil.cs
index 41d21e1c192..7c6c56739e1 100644
--- a/mcs/class/Npgsql/Npgsql/PGUtil.cs
+++ b/mcs/class/Npgsql/Npgsql/PGUtil.cs
@@ -9,733 +9,382 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.Collections;
-using System.Collections.Generic;
using System.IO;
+using System.Text;
+using System.Net.Sockets;
using System.Net;
-using System.Reflection;
using System.Resources;
-using System.Text;
namespace Npgsql
{
- ///<summary>
- /// This class provides many util methods to handle
- /// reading and writing of PostgreSQL protocol messages.
- /// </summary>
- internal static class PGUtil
- {
- // Logging related values
- private static readonly String CLASSNAME = "PGUtil";
- internal static readonly ResourceManager resman = new ResourceManager(MethodBase.GetCurrentMethod().DeclaringType);
- //TODO: What should this value be?
- //There is an obvious balancing act in setting this value. The larger the value, the fewer times
- //we need to use it and the more efficient we are in that regard. The smaller the value, the
- //less space is used, and the more efficient we are in that regard.
- //Multiples of memory page size are often good, which tends to be 4096 (4kB) and hence 4096 is
- //often used for cases like this (e.g. the default size of the buffer in System.IO.BufferedStream).
- //This is hard to guess, and even harder to guess if any overhead will be involved making a value
- //of 4096 * x - overhead the real ideal with this approach.
- //If this buffer were per-instance in a non-static class then 4096 would probably be the one to go for,
- //but since this buffer is shared we can perhaps afford to go a bit larger.
- //
- //Another potentially useful value, since we will be using a network stream which in turn is using
- //a TCP/IP stream, is the size of the TCP/IP window. This is even harder to predict than
- //memory page size, but is likely to be 1460 * 44 = 64240. It could be lower or higher but experimentation
- //shows that on at least the experimentation machine (.NET on WindowsXP, connecting to postgres server on
- //localhost) if more than 64240 was available only 64240 would be used in each pass), so for at least
- //that machine anything higher than 64240 is a waste.
- //64240 being a bit much, settling for 4096 for now.
- private const int THRASH_CAN_SIZE = 4096;
- //This buffer array is used for reading and ignoring bytes we want to discard.
- //It is thread-safe solely because it is never read from!
- //Any attempt to read from this array deserves to fail.
- //Note that in the cases where we are reading bytes to actually process them, we either
- //have a buffer supplied from elsewhere (the calling method) or we create a small buffer
- //as needed. This is since the buffer being used means that there that the possible performance
- //gain of not creating a new buffer will be cancelled out by whatever buffering will have to be
- //done to actually use the data. This is not the case here - we are pre-assigning a buffer for
- //this case purely because we don't care what gets put into it.
- private static readonly byte[] THRASH_CAN = new byte[THRASH_CAN_SIZE];
- private static readonly Encoding ENCODING_UTF8 = Encoding.UTF8;
-
- ///<summary>
- /// This method takes a ProtocolVersion and returns an integer
- /// version number that the Postgres backend will recognize in a
- /// startup packet.
- /// </summary>
- public static Int32 ConvertProtocolVersion(ProtocolVersion Ver)
- {
- switch (Ver)
- {
- case ProtocolVersion.Version2:
- return (int) ServerVersionCode.ProtocolVersion2;
-
- case ProtocolVersion.Version3:
- return (int) ServerVersionCode.ProtocolVersion3;
- }
-
- throw new ArgumentOutOfRangeException();
- }
-
- /// <summary>
- /// This method takes a version string as returned by SELECT VERSION() and returns
- /// a valid version string ("7.2.2" for example).
- /// This is only needed when running protocol version 2.
- /// This does not do any validity checks.
- /// </summary>
- public static string ExtractServerVersion(string VersionString)
- {
- Int32 Start = 0, End = 0;
-
- // find the first digit and assume this is the start of the version number
- for (; Start < VersionString.Length && !char.IsDigit(VersionString[Start]); Start++)
- {
- ;
- }
-
- End = Start;
-
- // read until hitting whitespace, which should terminate the version number
- for (; End < VersionString.Length && !char.IsWhiteSpace(VersionString[End]); End++)
- {
- ;
- }
-
- // Deal with this here so that if there are
- // changes in a future backend version, we can handle it here in the
- // protocol handler and leave everybody else put of it.
-
- VersionString = VersionString.Substring(Start, End - Start + 1);
-
- for (int idx = 0; idx != VersionString.Length; ++idx)
- {
- char c = VersionString[idx];
- if (!char.IsDigit(c) && c != '.')
- {
- VersionString = VersionString.Substring(0, idx);
- break;
- }
- }
-
- return VersionString;
- }
-
-/*
- /// <summary>
- /// Convert the beginning numeric part of the given string to Int32.
- /// For example:
- /// Strings "12345ABCD" and "12345.54321" would both be converted to int 12345.
- /// </summary>
- private static Int32 ConvertBeginToInt32(String Raw)
- {
- Int32 Length = 0;
- for (; Length < Raw.Length && Char.IsNumber(Raw[Length]); Length++)
- {
- ;
- }
- return Convert.ToInt32(Raw.Substring(0, Length));
- }
-*/
-
- ///<summary>
- /// This method gets a C NULL terminated string from the network stream.
- /// It keeps reading a byte in each time until a NULL byte is returned.
- /// It returns the resultant string of bytes read.
- /// This string is sent from backend.
- /// </summary>
- public static String ReadString(Stream network_stream)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadString");
-
- List<byte> buffer = new List<byte>();
- for (int bRead = network_stream.ReadByte(); bRead != 0; bRead = network_stream.ReadByte())
- {
- if (bRead == -1)
- {
- throw new IOException();
- }
- else
- {
- buffer.Add((byte) bRead);
- }
- }
-
- if (NpgsqlEventLog.Level >= LogLevel.Debug)
- NpgsqlEventLog.LogMsg(resman, "Log_StringRead", LogLevel.Debug, ENCODING_UTF8.GetString(buffer.ToArray()));
-
- return ENCODING_UTF8.GetString(buffer.ToArray());
- }
-
- public static char ReadChar(Stream stream)
- {
- byte[] buffer = new byte[4]; //No character is more than 4 bytes long.
- for (int i = 0; i != 4; ++i)
- {
- int byteRead = stream.ReadByte();
- if (byteRead == -1)
- {
- throw new EndOfStreamException();
- }
- buffer[i] = (byte) byteRead;
- if (ValidUTF8Ending(buffer, 0, i + 1)) //catch multi-byte encodings where we have not yet enough bytes.
- {
- return ENCODING_UTF8.GetChars(buffer)[0];
- }
- }
- throw new InvalidDataException();
- }
-
- public static int ReadChars(Stream stream, char[] output, int maxChars, ref int maxRead, int outputIdx)
- {
- if (maxChars == 0 || maxRead == 0)
- {
- return 0;
- }
- byte[] buffer = new byte[Math.Min(maxRead, maxChars*4)];
- int bytesSoFar = 0;
- int charsSoFar = 0;
- //A string of x chars length will take at least x bytes and at most
- //4x. We set our buffer to 4x in size, but start with only reading x bytes.
- //If we don't have the full string at this point, then we now have a new number
- //of characters to read, and so we try to read one byte per character remaining to read.
- //This hence involves the fewest possible number of passes through CheckedStreamRead
- //without the risk of accidentally reading too far into the stream.
- do
- {
- int toRead = Math.Min(maxRead, maxChars - charsSoFar);
- CheckedStreamRead(stream, buffer, bytesSoFar, toRead);
- maxRead -= toRead;
- bytesSoFar += toRead;
- }
- while (maxRead > 0 && (charsSoFar = PessimisticGetCharCount(buffer, 0, bytesSoFar)) < maxChars);
- return ENCODING_UTF8.GetDecoder().GetChars(buffer, 0, bytesSoFar, output, outputIdx, false);
- }
-
- public static int SkipChars(Stream stream, int maxChars, ref int maxRead)
- {
- //This is the same as ReadChars, but it just discards the characters read.
- if (maxChars == 0 || maxRead == 0)
- {
- return 0;
- }
- byte[] buffer = new byte[Math.Min(maxRead, ENCODING_UTF8.GetMaxByteCount(maxChars))];
- int bytesSoFar = 0;
- int charsSoFar = 0;
- do
- {
- int toRead = Math.Min(maxRead, maxChars - charsSoFar);
- CheckedStreamRead(stream, buffer, bytesSoFar, toRead);
- maxRead -= toRead;
- bytesSoFar += toRead;
- }
- while (maxRead > 0 && (charsSoFar = PessimisticGetCharCount(buffer, 0, bytesSoFar)) < maxChars);
- return charsSoFar;
- }
-
- // Encoding.GetCharCount will count an incomplete character as a character.
- // This makes sense if the user wants to assign a char[] buffer, since the incomplete character
- // might be represented as U+FFFD or a similar approach may be taken.
- // It's not much use though if we know the stream has >= x characters in it and we
- // want to read x complete characters - we need to know that the last character is complete.
- // Therefore we need to check on this.
- // SECURITY CONSIDERATIONS:
- // This function assumes we recieve valid UTF-8 data and as such security considerations
- // must be noticed.
- // In the case of deliberate mal-formed UTF-8 data, this function will not be used
- // in it's interpretation. In the worse case it will result in the stream being mis-read
- // and the operation malfunctioning, but anyone who is acting as a man-in-the-middle
- // on the stream can already do that to us in a variety of interesting ways, so this
- // function does not introduce a security issue in this regard.
- // Therefore the optimisation of assuming valid UTF-8 data is reasonable and not insecure.
- public static bool ValidUTF8Ending(byte[] buffer, int index, int count)
- {
- if (count <= 0)
- {
- return false;
- }
- byte examine = buffer[index + count - 1];
- //simplest case and also the most common with most data- a single-octet character. Handle directly.
- if ((examine & 0x80) == 0)
- {
- return true;
- }
- //if the last byte isn't a trailing byte we're clearly not at the end.
- if ((examine & 0xC0) != 0x80)
- {
- return false;
- }
- byte[] masks = new byte[] {0xE0, 0xF0, 0xF8};
- byte[] matches = new byte[] {0xC0, 0xE0, 0xF0};
- for (int i = 0; i + 2 <= count; ++i)
- {
- examine = buffer[index + count - 2 - i];
- if ((examine & masks[i]) == matches[i])
- {
- return true;
- }
- if ((examine & 0xC0) != 0x80)
- {
- return false;
- }
- }
- return false;
- }
-
- //This is like Encoding.UTF8.GetCharCount() but it ignores a trailing incomplete
- //character. See comments on ValidUTF8Ending()
- public static int PessimisticGetCharCount(byte[] buffer, int index, int count)
- {
- return ENCODING_UTF8.GetCharCount(buffer, index, count) - (ValidUTF8Ending(buffer, index, count) ? 0 : 1);
- }
-
- ///<summary>
- /// This method writes a C NULL terminated string to the network stream.
- /// It appends a NULL terminator to the end of the String.
- /// </summary>
- ///<summary>
- /// This method writes a C NULL terminated string to the network stream.
- /// It appends a NULL terminator to the end of the String.
- /// </summary>
- public static void WriteString(String the_string, Stream network_stream)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteString");
-
- NpgsqlEventLog.LogMsg(resman, "Log_StringWritten", LogLevel.Debug, the_string);
-
- network_stream.Write(ENCODING_UTF8.GetBytes(the_string + '\x00'), 0, ENCODING_UTF8.GetByteCount(the_string) + 1);
- }
-
- ///<summary>
- /// This method writes a C NULL terminated string limited in length to the
- /// backend server.
- /// It pads the string with null bytes to the size specified.
- /// </summary>
- public static void WriteLimString(String the_string, Int32 n, Stream network_stream)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteLimString");
-
- //Note: We do not know the size in bytes until after we have converted the string.
- byte[] bytes = ENCODING_UTF8.GetBytes(the_string);
- if (bytes.Length > n)
- {
- throw new ArgumentOutOfRangeException("the_string", the_string,
- string.Format(resman.GetString("LimStringWriteTooLarge"), the_string, n));
- }
-
- network_stream.Write(bytes, 0, bytes.Length);
-
- //pad with zeros.
- if (bytes.Length < n)
- {
- bytes = new byte[n - bytes.Length];
- network_stream.Write(bytes, 0, bytes.Length);
- }
- }
-
- public static void CheckedStreamRead(Stream stream, Byte[] buffer, Int32 offset, Int32 size)
- {
- Int32 bytes_from_stream = 0;
- Int32 total_bytes_read = 0;
-
- while (size > 0)
- {
- bytes_from_stream = stream.Read(buffer, offset + total_bytes_read, size);
- total_bytes_read += bytes_from_stream;
- size -= bytes_from_stream;
- }
- }
-
- public static void EatStreamBytes(Stream stream, int size)
- {
-//See comment on THRASH_CAN and THRASH_CAN_SIZE.
- while (size > 0)
- {
- size -= stream.Read(THRASH_CAN, 0, size < THRASH_CAN_SIZE ? size : THRASH_CAN_SIZE);
- }
- }
-
- public static int ReadEscapedBytes(Stream stream, byte[] output, int maxBytes, ref int maxRead, int outputIdx)
- {
- maxBytes = maxBytes > output.Length - outputIdx ? output.Length - outputIdx : maxBytes;
- int i;
- for (i = 0; i != maxBytes && maxRead > 0; ++i)
- {
- char c = ReadChar(stream);
- --maxRead;
- if (c == '\\')
- {
- --maxRead;
- switch (c = ReadChar(stream))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- maxRead -= 2;
- output[outputIdx++] =
- (byte)
- ((int.Parse(c.ToString()) << 6) | (int.Parse(ReadChar(stream).ToString()) << 3) |
- int.Parse(ReadChar(stream).ToString()));
- break;
- default:
- output[outputIdx++] = (byte) c;
- break;
- }
- }
- else
- {
- output[outputIdx++] = (byte) c;
- }
- }
- return i;
- }
-
- public static int SkipEscapedBytes(Stream stream, int maxBytes, ref int maxRead)
- {
- int i;
- for (i = 0; i != maxBytes && maxRead > 0; ++i)
- {
- --maxRead;
- if (ReadChar(stream) == '\\')
- {
- --maxRead;
- switch (ReadChar(stream))
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- maxRead -= 2;
- EatStreamBytes(stream, 2); //note assumes all representations of '0' through '9' are single-byte.
- break;
- }
- }
- }
- return i;
- }
-
- /// <summary>
- /// Write a 32-bit integer to the given stream in the correct byte order.
- /// </summary>
- public static void WriteInt32(Stream stream, Int32 value)
- {
- stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), 0, 4);
- }
-
- /// <summary>
- /// Read a 32-bit integer from the given stream in the correct byte order.
- /// </summary>
- public static Int32 ReadInt32(Stream stream)
- {
- byte[] buffer = new byte[4];
- CheckedStreamRead(stream, buffer, 0, 4);
- return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, 0));
- }
-
- /// <summary>
- /// Write a 16-bit integer to the given stream in the correct byte order.
- /// </summary>
- public static void WriteInt16(Stream stream, Int16 value)
- {
- stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), 0, 2);
- }
-
- /// <summary>
- /// Read a 16-bit integer from the given stream in the correct byte order.
- /// </summary>
- public static Int16 ReadInt16(Stream stream)
- {
- byte[] buffer = new byte[2];
- CheckedStreamRead(stream, buffer, 0, 2);
- return IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, 0));
- }
-
- public static int RotateShift(int val, int shift)
- {
- return (val << shift) | (val >> (sizeof (int) - shift));
- }
- }
-
- /// <summary>
- /// Represent the frontend/backend protocol version.
- /// </summary>
- public enum ProtocolVersion
- {
- Unknown,
- Version2,
- Version3
- }
-
- public enum ServerVersionCode
- {
- ProtocolVersion2 = 2 << 16, // 131072
- ProtocolVersion3 = 3 << 16 // 196608
- }
-
- /// <summary>
- /// Represent the backend server version.
- /// As this class offers no functionality beyond that offered by <see cref="System.Version"/> it has been
- /// deprecated in favour of that class.
- /// </summary>
- ///
- [Obsolete("Use System.Version")]
- public sealed class ServerVersion : IEquatable<ServerVersion>, IComparable<ServerVersion>, IComparable, ICloneable
- {
- [Obsolete("Use ServerVersionCode.ProtocolVersion2")] public static readonly Int32 ProtocolVersion2 = 2 << 16;
- // 131072
-
- [Obsolete("Use ServerVersionCode.ProtocolVersion3")] public static readonly Int32 ProtocolVersion3 = 3 << 16;
- // 196608
-
- private readonly Version _version;
-
- private ServerVersion(Version ver)
- {
- _version = ver;
- }
-
- /// <summary>
- /// Server version major number.
- /// </summary>
- public Int32 Major
- {
- get { return _version.Major; }
- }
-
- /// <summary>
- /// Server version minor number.
- /// </summary>
- public Int32 Minor
- {
- get { return _version.Minor; }
- }
-
- /// <summary>
- /// Server version patch level number.
- /// </summary>
- public Int32 Patch
- {
- get { return _version.Build; }
- }
-
- public static implicit operator Version(ServerVersion sv)
- {
- return (object) sv == null ? null : sv._version;
- }
-
- public static implicit operator ServerVersion(Version ver)
- {
- return (object) ver == null ? null : new ServerVersion(ver.Clone() as Version);
- }
-
- public static bool operator ==(ServerVersion One, ServerVersion TheOther)
- {
- return ((Version) One) == ((Version) TheOther);
- }
-
- public static bool operator !=(ServerVersion One, ServerVersion TheOther)
- {
- return (Version) One != (Version) TheOther;
- }
-
- public static bool operator >(ServerVersion One, ServerVersion TheOther)
- {
- return (Version) One > (Version) TheOther;
- }
-
- public static bool operator >=(ServerVersion One, ServerVersion TheOther)
- {
- return (Version) One >= (Version) TheOther;
- }
-
- public static bool operator <(ServerVersion One, ServerVersion TheOther)
- {
- return (Version) One < (Version) TheOther;
- }
-
- public static bool operator <=(ServerVersion One, ServerVersion TheOther)
- {
- return (Version) One <= (Version) TheOther;
- }
-
- public bool Equals(ServerVersion other)
- {
- return other != null && this == other;
- }
-
- public int CompareTo(ServerVersion other)
- {
- return _version.CompareTo(other);
- }
-
- public int CompareTo(object obj)
- {
- return CompareTo(obj as ServerVersion);
- }
-
- public object Clone()
- {
- return new ServerVersion(_version.Clone() as Version);
- }
-
- public override bool Equals(object O)
- {
- return Equals(O as ServerVersion);
- }
-
- public override int GetHashCode()
- {
- //Assume Version has a decent hash code function.
- //If this turns out not to be true do not use _Major ^ _Minor ^ _Patch, but make sure the values are spread throughout the 32bit range more to avoid false clashes.
- return _version.GetHashCode();
- }
-
- /// <summary>
- /// Returns the string representation of this version in three place dot notation (Major.Minor.Patch).
- /// </summary>
- public override String ToString()
- {
- return _version.ToString();
- }
- }
-
- internal enum FormatCode :
- short
- {
- Text = 0,
- Binary = 1
- }
-
- internal class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
- {
- private readonly Dictionary<TKey, TValue> _inner;
-
- public ReadOnlyDictionary(Dictionary<TKey, TValue> inner)
- {
- _inner = inner;
- }
-
- private static void StopWrite()
- {
- throw new NotSupportedException(PGUtil.resman.GetString("Read_Only_Write_Error"));
- }
-
- public TValue this[TKey key]
- {
- get { return _inner[key]; }
- set { StopWrite(); }
- }
-
- public ICollection<TKey> Keys
- {
- get { return _inner.Keys; }
- }
-
- public ICollection<TValue> Values
- {
- get { return _inner.Values; }
- }
-
- public int Count
- {
- get { return _inner.Count; }
- }
-
- public bool IsReadOnly
- {
- get { return true; }
- }
-
- public bool ContainsKey(TKey key)
- {
- return _inner.ContainsKey(key);
- }
-
- public void Add(TKey key, TValue value)
- {
- StopWrite();
- }
-
- public bool Remove(TKey key)
- {
- StopWrite();
- return false;
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- return _inner.TryGetValue(key, out value);
- }
-
- public void Add(KeyValuePair<TKey, TValue> item)
- {
- StopWrite();
- }
-
- public void Clear()
- {
- StopWrite();
- }
-
- public bool Contains(KeyValuePair<TKey, TValue> item)
- {
- return ((IDictionary<TKey, TValue>) _inner).Contains(item);
- }
-
- public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
- {
- ((IDictionary<TKey, TValue>) _inner).CopyTo(array, arrayIndex);
- }
-
- public bool Remove(KeyValuePair<TKey, TValue> item)
- {
- StopWrite();
- return false;
- }
-
- public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
- {
- foreach (KeyValuePair<TKey, TValue> kvp in _inner)
- {
- yield return new KeyValuePair<TKey, TValue>(kvp.Key, kvp.Value); //return copy so changes don't affect our copy.
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return _inner.GetEnumerator();
- }
- }
-} \ No newline at end of file
+ /// <summary>
+ /// Represent the frontend/backend protocol version.
+ /// </summary>
+ public enum ProtocolVersion
+ {
+ Unknown,
+ Version2,
+ Version3
+ }
+
+ /// <summary>
+ /// Represent the backend server version.
+ /// </summary>
+ public sealed class ServerVersion
+ {
+ public static readonly Int32 ProtocolVersion2 = 2 << 16; // 131072
+ public static readonly Int32 ProtocolVersion3 = 3 << 16; // 196608
+
+ private Int32 _Major;
+ private Int32 _Minor;
+ private Int32 _Patch;
+
+ internal ServerVersion(Int32 Major, Int32 Minor, Int32 Patch)
+ {
+ _Major = Major;
+ _Minor = Minor;
+ _Patch = Patch;
+ }
+
+ /// <summary>
+ /// Server version major number.
+ /// </summary>
+ public Int32 Major
+ { get { return _Major; } }
+
+ /// <summary>
+ /// Server version minor number.
+ /// </summary>
+ public Int32 Minor
+ { get { return _Minor; } }
+
+ /// <summary>
+ /// Server version patch level number.
+ /// </summary>
+ public Int32 Patch
+ { get { return _Patch; } }
+
+ public static bool operator == (ServerVersion One, ServerVersion TheOther)
+ {
+ if (((Object)One == null) || ((Object)TheOther == null))
+ return false;
+ return
+ One._Major == TheOther._Major &&
+ One._Minor == TheOther._Minor &&
+ One._Patch == TheOther._Patch;
+ }
+
+ public static bool operator != (ServerVersion One, ServerVersion TheOther)
+ {
+ if (((Object)One == null) || ((Object)TheOther == null))
+ return true;
+
+ return ! (One == TheOther);
+ }
+
+ public static bool operator > (ServerVersion One, ServerVersion TheOther)
+ {
+ return
+ (One._Major > TheOther._Major) ||
+ (One._Major == TheOther._Major && One._Minor > TheOther._Minor) ||
+ (One._Major == TheOther._Major && One._Minor == TheOther._Minor && One._Patch > TheOther._Patch);
+ }
+
+ public static bool operator >= (ServerVersion One, ServerVersion TheOther)
+ {
+ return
+ (One._Major > TheOther._Major) ||
+ (One._Major == TheOther._Major && One._Minor > TheOther._Minor) ||
+ (One._Major == TheOther._Major && One._Minor == TheOther._Minor && One._Patch >= TheOther._Patch);
+ }
+
+ public static bool operator < (ServerVersion One, ServerVersion TheOther)
+ {
+ return
+ (One._Major < TheOther._Major) ||
+ (One._Major == TheOther._Major && One._Minor < TheOther._Minor) ||
+ (One._Major == TheOther._Major && One._Minor == TheOther._Minor && One._Patch < TheOther._Patch);
+ }
+
+ public static bool operator <= (ServerVersion One, ServerVersion TheOther)
+ {
+ return
+ (One._Major < TheOther._Major) ||
+ (One._Major == TheOther._Major && One._Minor < TheOther._Minor) ||
+ (One._Major == TheOther._Major && One._Minor == TheOther._Minor && One._Patch <= TheOther._Patch);
+ }
+
+ public override bool Equals(object O)
+ {
+ if (O == null)
+ return false;
+
+ return (O.GetType() == this.GetType() && this == (ServerVersion)O);
+ }
+
+ public override int GetHashCode()
+ {
+ return _Major ^ _Minor ^ _Patch;
+ }
+
+ /// <summary>
+ /// Returns the string representation of this version in three place dot notation (Major.Minor.Patch).
+ /// </summary>
+ public override String ToString()
+ {
+ return string.Format("{0}.{1}.{2}", _Major, _Minor, _Patch);
+ }
+ }
+
+ internal enum FormatCode:
+ short
+ {
+ Text = 0,
+ Binary = 1
+ }
+
+ ///<summary>
+ /// This class provides many util methods to handle
+ /// reading and writing of PostgreSQL protocol messages.
+ /// </summary>
+ internal abstract class PGUtil
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "PGUtil";
+ private static ResourceManager resman = new ResourceManager(typeof(PGUtil));
+
+ ///<summary>
+ /// This method takes a ProtocolVersion and returns an integer
+ /// version number that the Postgres backend will recognize in a
+ /// startup packet.
+ /// </summary>
+ public static Int32 ConvertProtocolVersion(ProtocolVersion Ver)
+ {
+ switch (Ver) {
+ case ProtocolVersion.Version2 :
+ return ServerVersion.ProtocolVersion2;
+
+ case ProtocolVersion.Version3 :
+ return ServerVersion.ProtocolVersion3;
+
+ }
+
+ // CHECKME
+ // should we throw?
+ return 0;
+ }
+
+ /// <summary>
+ /// This method takes a version string as returned by SELECT VERSION() and returns
+ /// a valid version string ("7.2.2" for example).
+ /// This is only needed when running protocol version 2.
+ /// This does not do any validity checks.
+ /// </summary>
+ public static string ExtractServerVersion (string VersionString)
+ {
+ Int32 Start = 0, End = 0;
+
+ // find the first digit and assume this is the start of the version number
+ for ( ; Start < VersionString.Length && ! char.IsDigit(VersionString[Start]) ; Start++);
+
+ End = Start;
+
+ // read until hitting whitespace, which should terminate the version number
+ for ( ; End < VersionString.Length && ! char.IsWhiteSpace(VersionString[End]) ; End++);
+
+ return VersionString.Substring(Start, End - Start + 1);
+ }
+
+ /// <summary>
+ /// This method takes a version string ("7.4.1" for example) and produces
+ /// the required integer version numbers (7, 4, and 1).
+ /// </summary>
+ public static ServerVersion ParseServerVersion (string VersionString)
+ {
+ String[] Parts;
+
+ Parts = VersionString.Split('.');
+
+ if (Parts.Length < 2) {
+ throw new FormatException(String.Format("Internal: Backend sent bad version string: {0}", VersionString));
+ }
+
+ try {
+ if (Parts.Length == 2) {
+ // Coerce it into a 3-part version.
+ return new ServerVersion(ConvertBeginToInt32(Parts[0]), ConvertBeginToInt32(Parts[1]), 0);
+ } else {
+ // If there are more than 3 parts, just ignore the extras, rather than rejecting it.
+ return new ServerVersion(ConvertBeginToInt32(Parts[0]), ConvertBeginToInt32(Parts[1]), ConvertBeginToInt32(Parts[2]));
+ }
+ } catch (Exception E) {
+ throw new FormatException(String.Format("Internal: Backend sent bad version string: {0}", VersionString), E);
+ }
+ }
+
+ /// <summary>
+ /// Convert the beginning numeric part of the given string to Int32.
+ /// For example:
+ /// Strings "12345ABCD" and "12345.54321" would both be converted to int 12345.
+ /// </summary>
+ private static Int32 ConvertBeginToInt32(String Raw)
+ {
+ Int32 Length = 0;
+ for ( ; Length < Raw.Length && Char.IsNumber(Raw[Length]) ; Length++);
+ return Convert.ToInt32(Raw.Substring(0, Length));
+ }
+
+ ///<summary>
+ /// This method gets a C NULL terminated string from the network stream.
+ /// It keeps reading a byte in each time until a NULL byte is returned.
+ /// It returns the resultant string of bytes read.
+ /// This string is sent from backend.
+ /// </summary>
+ public static String ReadString(Stream network_stream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadString");
+
+ ArrayList buffer = new ArrayList();
+ Byte b;
+ String string_read;
+
+ // [FIXME] Is this cast always safe?
+ b = (Byte)network_stream.ReadByte();
+ while(b != 0)
+ {
+ buffer.Add(b);
+ b = (Byte)network_stream.ReadByte();
+ }
+
+ string_read = encoding.GetString((Byte[])buffer.ToArray(typeof(Byte)));
+ NpgsqlEventLog.LogMsg(resman, "Log_StringRead", LogLevel.Debug, string_read);
+
+ return string_read;
+ }
+
+ ///<summary>
+ /// This method gets a length terminated string from a network stream.
+ /// It returns the resultant string of bytes read.
+ /// This string is sent from backend.
+ /// </summary>
+ public static String ReadString(Stream network_stream, Encoding encoding, Int32 length)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadString");
+
+ ArrayList buffer = new ArrayList();
+ Byte b;
+ String string_read;
+
+ for (int C = 0 ; C < length ; C++)
+ {
+ // [FIXME] Is this cast always safe?
+ b = (Byte)network_stream.ReadByte();
+ buffer.Add(b);
+ }
+
+ string_read = encoding.GetString((Byte[])buffer.ToArray(typeof(Byte)));
+ NpgsqlEventLog.LogMsg(resman, "Log_StringRead", LogLevel.Debug, string_read);
+
+ return string_read;
+ }
+
+ ///<summary>
+ /// This method writes a C NULL terminated string to the network stream.
+ /// It appends a NULL terminator to the end of the String.
+ /// </summary>
+ public static void WriteString(String the_string, Stream network_stream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteString");
+
+ NpgsqlEventLog.LogMsg(resman, "Log_StringWritten", LogLevel.Debug, the_string);
+
+ network_stream.Write(encoding.GetBytes(the_string + '\x00') , 0, encoding.GetByteCount(the_string) + 1);
+ }
+
+ ///<summary>
+ /// This method writes a C NULL terminated string limited in length to the
+ /// backend server.
+ /// It pads the string with null bytes to the size specified.
+ /// </summary>
+ public static void WriteLimString(String the_string, Int32 n, Stream network_stream, Encoding encoding)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteLimString");
+
+ // [FIXME] Parameters should be validated. And what about strings
+ // larger than or equal to n?
+
+ // Pad the string to the specified value.
+ String string_padded = the_string.PadRight(n, '\x00');
+
+ network_stream.Write(encoding.GetBytes(string_padded), 0, n);
+ }
+
+ public static void CheckedStreamRead(Stream stream, Byte[] buffer, Int32 offset, Int32 size)
+ {
+ Int32 bytes_from_stream = 0;
+ Int32 total_bytes_read = 0;
+
+ do
+ {
+ bytes_from_stream = stream.Read(buffer, offset + total_bytes_read, size);
+ total_bytes_read += bytes_from_stream;
+ size -= bytes_from_stream;
+ }
+ while(size > 0);
+ }
+
+
+ /// <summary>
+ /// Write a 32-bit integer to the given stream in the correct byte order.
+ /// </summary>
+ public static void WriteInt32(Stream stream, Int32 value)
+ {
+ stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), 0, 4);
+ }
+
+ /// <summary>
+ /// Read a 32-bit integer from the given stream in the correct byte order.
+ /// </summary>
+ public static Int32 ReadInt32(Stream stream, Byte[] buffer)
+ {
+ CheckedStreamRead(stream, buffer, 0, 4);
+ return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer, 0));
+
+ }
+
+ /// <summary>
+ /// Write a 16-bit integer to the given stream in the correct byte order.
+ /// </summary>
+ public static void WriteInt16(Stream stream, Int16 value)
+ {
+ stream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value)), 0, 2);
+ }
+
+ /// <summary>
+ /// Read a 16-bit integer from the given stream in the correct byte order.
+ /// </summary>
+ public static Int16 ReadInt16(Stream stream, Byte[] buffer)
+ {
+ CheckedStreamRead(stream, buffer, 0, 2);
+ return IPAddress.NetworkToHostOrder(BitConverter.ToInt16(buffer, 0));
+
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/Npgsql/PGUtil.resx b/mcs/class/Npgsql/Npgsql/PGUtil.resx
index 82db1c51fce..794c3a407a1 100644
--- a/mcs/class/Npgsql/Npgsql/PGUtil.resx
+++ b/mcs/class/Npgsql/Npgsql/PGUtil.resx
@@ -1,9 +1,9 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8" ?>
<root>
- <!--
+ <!--
Microsoft ResX Schema
- Version 2.0
+ Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
@@ -14,17 +14,16 @@
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
- <resheader name="version">2.0</resheader>
+ <resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
- <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
- <value>[base64 mime encoded serialized .NET Framework object]</value>
+ [base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
- <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
- <comment>This is a comment</comment>
+ [base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
@@ -36,7 +35,7 @@
Classes that don't support this are serialized and stored with the
mimetype set.
- The mimetype is used for serialized objects, and tells the
+ The mimetype is used forserialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
@@ -46,7 +45,7 @@
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
- : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
@@ -59,71 +58,50 @@
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
- <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
- <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
- <xsd:element name="root" msdata:IsDataSet="true">
- <xsd:complexType>
- <xsd:choice maxOccurs="unbounded">
- <xsd:element name="metadata">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" />
- </xsd:sequence>
- <xsd:attribute name="name" use="required" type="xsd:string" />
- <xsd:attribute name="type" type="xsd:string" />
- <xsd:attribute name="mimetype" type="xsd:string" />
- <xsd:attribute ref="xml:space" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="assembly">
- <xsd:complexType>
- <xsd:attribute name="alias" type="xsd:string" />
- <xsd:attribute name="name" type="xsd:string" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="data">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
- <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
- <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
- <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
- <xsd:attribute ref="xml:space" />
- </xsd:complexType>
- </xsd:element>
- <xsd:element name="resheader">
- <xsd:complexType>
- <xsd:sequence>
- <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required" />
- </xsd:complexType>
- </xsd:element>
- </xsd:choice>
- </xsd:complexType>
- </xsd:element>
- </xsd:schema>
- <resheader name="resmimetype">
- <value>text/microsoft-resx</value>
- </resheader>
- <resheader name="version">
- <value>2.0</value>
- </resheader>
- <resheader name="reader">
- <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </resheader>
- <resheader name="writer">
- <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
- </resheader>
- <data name="Log_StringRead" xml:space="preserve">
- <value>String read: {0}.</value>
- </data>
- <data name="Log_StringWritten" xml:space="preserve">
- <value>String written: {0}.</value>
- </data>
- <data name="Read_Only_Write_Error" xml:space="preserve">
- <value>The collection is read-only</value>
- </data>
-</root> \ No newline at end of file
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>1.3</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="Log_StringRead">
+ <value>String read: {0}.</value>
+ </data>
+ <data name="Log_StringWritten">
+ <value>String written: {0}.</value>
+ </data>
+
+</root>
diff --git a/mcs/class/Npgsql/NpgsqlTypes/FastPath.cs b/mcs/class/Npgsql/NpgsqlTypes/FastPath.cs
index 7dc6650f3f1..ab88f518cde 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/FastPath.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/FastPath.cs
@@ -11,78 +11,74 @@
Changed case of method names to conform to .Net names standard.
Also changed type names to their true names. i.e. int -> Int32
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-------------------------------------------------------------------------
*/
using System;
-using System.Collections.Generic;
-using System.Data;
+using System.Collections;
using System.IO;
+using System.Data;
using Npgsql;
namespace NpgsqlTypes
{
- /*
+
+
+ /*
* This class implements the Fastpath api.
*
*
*
*/
+ public class Fastpath
+ {
+ // This maps the functions names to their id's (possible unique just
+ // to a connection).
+ protected Hashtable func = new Hashtable();
- public class Fastpath
- {
- // This maps the functions names to their id's (possible unique just
- // to a connection).
- protected Dictionary<string, int> func = new Dictionary<string, int>();
+ protected NpgsqlConnection conn; // our connection
+ protected Stream stream; // the network stream
- protected NpgsqlConnection conn; // our connection
- protected Stream stream; // the network stream
-
- /*
+ /*
* Initialises the fastpath system
*
* @param conn BaseConnection to attach to
* @param stream The network stream to the backend
*/
-
- public Fastpath(NpgsqlConnection conn, Stream stream)
- {
- this.conn = conn;
- this.stream = stream;
- }
+ public Fastpath(NpgsqlConnection conn, Stream stream)
+ {
+ this.conn = conn;
+ this.stream = stream;
+ }
- /*
+ /*
* Initialises the fastpath system
*
* @param conn BaseConnection to attach to
* @param stream The network stream to the backend
*/
-
- public Fastpath(NpgsqlConnection conn)
- {
- this.conn = conn;
- // check if the connection is closed ?
- this.stream = conn.Connector.Stream;
- }
-
- /*
+ public Fastpath(NpgsqlConnection conn)
+ {
+ this.conn = conn;
+ // check if the connection is closed ?
+ this.stream = conn.Connector.Stream;
+ }
+
+ /*
* Send a function call to the PostgreSQL backend
*
* @param fnid Function id
@@ -91,277 +87,271 @@ namespace NpgsqlTypes
* @return null if no data, Integer if an integer result, or byte[] otherwise
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public Object FastpathCall(Int32 fnid, Boolean resulttype, FastpathArg[] args)
- {
- try
- {
- if (conn.BackendProtocolVersion == ProtocolVersion.Version3)
- {
- return FastpathV3(fnid, resulttype, args);
- }
- else
- {
- return FastpathV2(fnid, resulttype, args);
- }
- }
- catch (IOException)
- {
- conn.ClearPool();
- throw new NpgsqlException("The Connection is broken.");
- }
- }
-
- private Object FastpathV3(Int32 fnid, Boolean resulttype, FastpathArg[] args)
- {
- // give thread safety
- lock (stream)
- {
- // send the function call
-
- {
- Int32 l_msgLen = 0;
- l_msgLen += 16;
- for (Int32 i = 0; i < args.Length; i++)
- {
- l_msgLen += args[i].SendSize();
- }
-
- stream.WriteByte((Byte) 'F');
- PGUtil.WriteInt32(stream, l_msgLen);
- PGUtil.WriteInt32(stream, fnid);
- PGUtil.WriteInt16(stream, 1);
- PGUtil.WriteInt16(stream, 1);
- PGUtil.WriteInt16(stream, (short) args.Length);
-
- for (Int32 i = 0; i < args.Length; i++)
- {
- args[i].Send(stream);
- }
-
- PGUtil.WriteInt16(stream, 1);
-
- // This is needed, otherwise data can be lost
- stream.Flush();
- }
-
-
- // Now handle the result
-
- // Now loop, reading the results
- Object result = null; // our result
- Exception error = null;
- Int32 c;
- Boolean l_endQuery = false;
-
- while (!l_endQuery)
- {
- c = (Char) stream.ReadByte();
-
- switch (c)
- {
- case 'A': // Asynchronous Notify
- Int32 msglen = PGUtil.ReadInt32(stream);
- Int32 pid = PGUtil.ReadInt32(stream);
- String msg = PGUtil.ReadString(stream);
- PGUtil.ReadString(stream);
- String param = PGUtil.ReadString(stream);
-
- break;
- //------------------------------
- // Error message returned
- case 'E':
- NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion, stream);
- throw new NpgsqlException(e.ToString());
-
- //------------------------------
- // Notice from backend
- case 'N':
- Int32 l_nlen = PGUtil.ReadInt32(stream);
-
- conn.Connector.FireNotice(new NpgsqlError(conn.BackendProtocolVersion, stream));
-
- break;
-
- case 'V':
- Int32 l_msgLen = PGUtil.ReadInt32(stream);
- Int32 l_valueLen = PGUtil.ReadInt32(stream);
-
- if (l_valueLen == -1)
- {
- //null value
- }
- else if (l_valueLen == 0)
- {
- result = new Byte[0];
- }
- else
- {
- // Return an Integer if
- if (resulttype)
- {
- result = PGUtil.ReadInt32(stream);
- }
- else
- {
- Byte[] buf = new Byte[l_valueLen];
-
- Int32 bytes_from_stream = 0;
- Int32 total_bytes_read = 0;
- Int32 size = l_valueLen;
- do
- {
- bytes_from_stream = stream.Read(buf, total_bytes_read, size);
- total_bytes_read += bytes_from_stream;
- size -= bytes_from_stream;
- }
- while (size > 0);
-
- result = buf;
- }
- }
- break;
-
- case 'Z':
- //TODO: use size better
- if (PGUtil.ReadInt32(stream) != 5)
- {
- throw new NpgsqlException("Received Z");
- }
- //TODO: handle transaction status
- Char l_tStatus = (Char) stream.ReadByte();
- l_endQuery = true;
- break;
-
- default:
- throw new NpgsqlException(string.Format("postgresql.fp.protocol received {0}", c));
- }
- }
-
- if (error != null)
- {
- throw error;
- }
-
- return result;
- }
- }
-
- private Object FastpathV2(Int32 fnid, Boolean resulttype, FastpathArg[] args)
- {
- // added Oct 7 1998 to give us thread safety
- lock (stream)
- {
- // send the function call
-
- // 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
- // that confuses the backend. The 0 terminates the command line.
- stream.WriteByte(70);
- stream.WriteByte(0);
-
- PGUtil.WriteInt32(stream, fnid);
- PGUtil.WriteInt32(stream, args.Length);
-
-
- for (Int32 i = 0; i < args.Length; i++)
- {
- args[i].Send(stream);
- }
-
- // This is needed, otherwise data can be lost
- stream.Flush();
-
-
- // Now handle the result
-
- // Now loop, reading the results
- Object result = null; // our result
- String errorMessage = "";
- Int32 c;
- Boolean l_endQuery = false;
- while (!l_endQuery)
- {
- c = (Char) stream.ReadByte();
-
- switch (c)
- {
- case 'A': // Asynchronous Notify
- //TODO: do something with this
- Int32 pid = PGUtil.ReadInt32(stream);
- String msg = PGUtil.ReadString(stream);
-
-
- break;
-
- //------------------------------
- // Error message returned
- case 'E':
- NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion, stream);
- errorMessage += e.Message;
- break;
-
- //------------------------------
- // Notice from backend
- case 'N':
- NpgsqlError notice = new NpgsqlError(conn.BackendProtocolVersion, stream);
- errorMessage += notice.Message;
- break;
-
- case 'V':
- Char l_nextChar = (Char) stream.ReadByte();
- if (l_nextChar == 'G')
- {
- Int32 sz = PGUtil.ReadInt32(stream);
- // Return an Integer if
- if (resulttype)
- {
- result = PGUtil.ReadInt32(stream);
- }
- else
- {
- Byte[] buf = new Byte[sz];
-
- Int32 bytes_from_stream = 0;
- Int32 total_bytes_read = 0;
- Int32 size = sz;
- do
- {
- bytes_from_stream = stream.Read(buf, total_bytes_read, size);
- total_bytes_read += bytes_from_stream;
- size -= bytes_from_stream;
- }
- while (size > 0);
-
- result = buf;
- }
- //There should be a trailing '0'
- Int32 l_endChar = (Char) stream.ReadByte();
- }
- else
- {
- //it must have been a '0', thus no results
- }
- break;
-
- case 'Z':
- l_endQuery = true;
- break;
-
- default:
- throw new NpgsqlException(string.Format("postgresql.fp.protocol {0}", c));
- }
- }
-
- if (errorMessage != null)
- {
- throw new NpgsqlException("postgresql.fp.error" + errorMessage);
- }
-
- return result;
- }
- }
-
- /*
+ public Object FastpathCall(Int32 fnid, Boolean resulttype, FastpathArg[] args)
+ {
+ try
+ {
+ if (conn.BackendProtocolVersion == ProtocolVersion.Version3)
+ {
+ return FastpathV3(fnid, resulttype, args);
+ }
+ else
+ {
+ return FastpathV2(fnid, resulttype, args);
+ }
+ }
+ catch(IOException e)
+ {
+ conn.ClearPool();
+ throw new NpgsqlException("The Connection is broken.");
+ }
+ }
+
+ private Object FastpathV3(Int32 fnid, Boolean resulttype, FastpathArg[] args)
+ {
+ // give thread safety
+ lock (stream)
+ {
+ // send the function call
+
+ {
+ Int32 l_msgLen = 0;
+ l_msgLen += 16;
+ for (Int32 i=0;i < args.Length;i++)
+ l_msgLen += args[i].SendSize();
+
+ stream.WriteByte((Byte)'F');
+ PGUtil.WriteInt32(stream,l_msgLen);
+ PGUtil.WriteInt32(stream,fnid);
+ PGUtil.WriteInt16(stream,1);
+ PGUtil.WriteInt16(stream,1);
+ PGUtil.WriteInt16(stream,(short)args.Length);
+
+ for (Int32 i = 0;i < args.Length;i++)
+ args[i].Send(stream);
+
+ PGUtil.WriteInt16(stream,1);
+
+ // This is needed, otherwise data can be lost
+ stream.Flush();
+ }
+
+
+ // Now handle the result
+
+ // Now loop, reading the results
+ Object result = null; // our result
+ Exception error = null;
+ Int32 c;
+ Boolean l_endQuery = false;
+ Byte[] input_buffer = new Byte[512];
+
+ while (!l_endQuery)
+ {
+ c = (Char)stream.ReadByte();
+
+ switch (c)
+ {
+ case 'A': // Asynchronous Notify
+ Int32 msglen = PGUtil.ReadInt32(stream,input_buffer);
+ Int32 pid = PGUtil.ReadInt32(stream,input_buffer);
+ String msg = PGUtil.ReadString(stream,conn.Connector.Encoding);
+ PGUtil.ReadString(stream,conn.Connector.Encoding);
+ String param = PGUtil.ReadString(stream,conn.Connector.Encoding);
+
+ conn.Connector.CheckErrorsAndNotifications();
+ break;
+ //------------------------------
+ // Error message returned
+ case 'E':
+ NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion);
+ e.ReadFromStream(stream,conn.Connector.Encoding);
+ throw new NpgsqlException(e.ToString());
+
+ //------------------------------
+ // Notice from backend
+ case 'N':
+ Int32 l_nlen = PGUtil.ReadInt32(stream,input_buffer);
+
+ NpgsqlError e1 = new NpgsqlError(conn.BackendProtocolVersion);
+ e1.ReadFromStream(stream,conn.Connector.Encoding);
+ conn.Connector.Mediator.Errors.Add(e1);
+
+ break;
+
+ case 'V':
+ Int32 l_msgLen = PGUtil.ReadInt32(stream,input_buffer);
+ Int32 l_valueLen = PGUtil.ReadInt32(stream,input_buffer);
+
+ if (l_valueLen == -1)
+ {
+ //null value
+ }
+ else if (l_valueLen == 0)
+ {
+ result = new Byte[0];
+ }
+ else
+ {
+ // Return an Integer if
+ if (resulttype)
+
+ result = PGUtil.ReadInt32(stream,input_buffer);
+ else
+ {
+ Byte[] buf = new Byte[l_valueLen];
+
+ Int32 bytes_from_stream = 0;
+ Int32 total_bytes_read = 0;
+ Int32 size = l_valueLen;
+ do
+ {
+ bytes_from_stream = stream.Read(buf, total_bytes_read, size);
+ total_bytes_read += bytes_from_stream;
+ size -= bytes_from_stream;
+ }
+ while(size > 0);
+
+ result = buf;
+ }
+ }
+ break;
+
+ case 'Z':
+ //TODO: use size better
+ if (PGUtil.ReadInt32(stream,input_buffer) != 5)
+ throw new NpgsqlException("Received Z" );
+ //TODO: handle transaction status
+ Char l_tStatus = (Char)stream.ReadByte();
+ l_endQuery = true;
+ break;
+
+ default:
+ throw new NpgsqlException("postgresql.fp.protocol received " + c.ToString());
+ }
+ }
+
+ if ( error != null )
+ throw error;
+
+ return result;
+ }
+ }
+
+ private Object FastpathV2(Int32 fnid, Boolean resulttype, FastpathArg[] args)
+ {
+ // added Oct 7 1998 to give us thread safety
+ lock (stream)
+ {
+ // send the function call
+
+ // 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
+ // that confuses the backend. The 0 terminates the command line.
+ stream.WriteByte((Byte)70);
+ stream.WriteByte((Byte)0);
+
+ PGUtil.WriteInt32(stream,fnid);
+ PGUtil.WriteInt32(stream,args.Length);
+
+
+ for (Int32 i = 0;i < args.Length;i++)
+ args[i].Send(stream);
+
+ // This is needed, otherwise data can be lost
+ stream.Flush();
+
+
+ // Now handle the result
+
+ // Now loop, reading the results
+ Object result = null; // our result
+ String errorMessage = "";
+ Byte[] input_buffer = new Byte[512];
+ Int32 c;
+ Boolean l_endQuery = false;
+ while (!l_endQuery)
+ {
+ c = (Char)stream.ReadByte();
+
+ switch (c)
+ {
+ case 'A': // Asynchronous Notify
+ //TODO: do something with this
+ Int32 pid = PGUtil.ReadInt32(stream,input_buffer);
+ String msg = PGUtil.ReadString(stream,conn.Connector.Encoding);
+
+
+ conn.Connector.CheckErrorsAndNotifications();
+
+ break;
+
+ //------------------------------
+ // Error message returned
+ case 'E':
+ NpgsqlError e = new NpgsqlError(conn.BackendProtocolVersion);
+ e.ReadFromStream(stream,conn.Connector.Encoding);
+ errorMessage += e.Message;
+ break;
+
+ //------------------------------
+ // Notice from backend
+ case 'N':
+ NpgsqlError notice = new NpgsqlError(conn.BackendProtocolVersion);
+ notice.ReadFromStream(stream,conn.Connector.Encoding);
+ errorMessage += notice.Message;
+ break;
+
+ case 'V':
+ Char l_nextChar = (Char)stream.ReadByte();
+ if (l_nextChar == 'G')
+ {
+ Int32 sz = PGUtil.ReadInt32(stream,input_buffer);
+ // Return an Integer if
+ if (resulttype)
+ result = PGUtil.ReadInt32(stream,input_buffer);
+ else
+ {
+ Byte[] buf = new Byte[sz];
+
+ Int32 bytes_from_stream = 0;
+ Int32 total_bytes_read = 0;
+ Int32 size = sz;
+ do
+ {
+ bytes_from_stream = stream.Read(buf, total_bytes_read, size);
+ total_bytes_read += bytes_from_stream;
+ size -= bytes_from_stream;
+ }
+ while(size > 0);
+
+ result = buf;
+ }
+ //There should be a trailing '0'
+ Int32 l_endChar = (Char)stream.ReadByte();
+ }
+ else
+ {
+ //it must have been a '0', thus no results
+ }
+ break;
+
+ case 'Z':
+ l_endQuery = true;
+ break;
+
+ default:
+ throw new NpgsqlException("postgresql.fp.protocol " + c.ToString());
+ }
+ }
+
+ if ( errorMessage != null )
+ throw new NpgsqlException("postgresql.fp.error" + errorMessage);
+
+ return result;
+ }
+ }
+
+ /*
* Send a function call to the PostgreSQL backend by name.
*
* Note: the mapping for the procedure name to function id needs to exist,
@@ -381,41 +371,38 @@ namespace NpgsqlTypes
* occurs.
* @see org.postgresql.largeobject.LargeObject
*/
+ public Object FastpathCall(String name, Boolean resulttype, FastpathArg[] args)
+ {
+ return FastpathCall(GetID(name), resulttype, args);
+ }
- public Object FastpathCall(String name, Boolean resulttype, FastpathArg[] args)
- {
- return FastpathCall(GetID(name), resulttype, args);
- }
-
- /*
+ /*
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return integer result
* @exception NpgsqlException if a database-access error occurs or no result
*/
+ public Int32 GetInteger(String name, FastpathArg[] args)
+ {
+ Int32 i = (Int32)FastpathCall(name, true, args);
- public Int32 GetInteger(String name, FastpathArg[] args)
- {
- Int32 i = (Int32) FastpathCall(name, true, args);
-
- return i;
- }
+ return i;
+ }
- /*
+ /*
* This convenience method assumes that the return value is an Integer
* @param name Function name
* @param args Function arguments
* @return byte[] array containing result
* @exception NpgsqlException if a database-access error occurs or no result
*/
+ public Byte[] GetData(String name, FastpathArg[] args)
+ {
+ return (Byte[])FastpathCall(name, false, args);
+ }
- public Byte[] GetData(String name, FastpathArg[] args)
- {
- return (Byte[]) FastpathCall(name, false, args);
- }
-
- /*
+ /*
* This adds a function to our lookup table.
*
* <p>User code should use the addFunctions method, which is based upon a
@@ -426,13 +413,12 @@ namespace NpgsqlTypes
* @param name Function name
* @param fnid Function id
*/
+ public void AddFunction(String name, Int32 fnid)
+ {
+ func.Add(name, fnid);
+ }
- public void AddFunction(String name, Int32 fnid)
- {
- func.Add(name, fnid);
- }
-
- /*
+ /*
* This takes a ResultSet containing two columns. Column 1 contains the
* function name, Column 2 the oid.
*
@@ -445,7 +431,7 @@ namespace NpgsqlTypes
*
* <p>PostgreSQL stores the function id's and their corresponding names in
* the pg_proc table. To speed things up locally, instead of querying each
- * function from that table when required, a Dictionary is used. Also, only
+ * function from that table when required, a Hashtable is used. Also, only
* the function's required are entered into this table, keeping connection
* times as fast as possible.
*
@@ -464,20 +450,17 @@ namespace NpgsqlTypes
* @exception NpgsqlException if a database-access error occurs.
* @see org.postgresql.largeobject.LargeObjectManager
*/
-
- public void AddFunctions(IDataReader rs)
- {
- while (rs.Read())
- {
- String key = (String) rs[0];
- if (!func.ContainsKey(key))
- {
- func.Add(key, Int32.Parse(rs[1].ToString()));
- }
- }
- }
-
- /*
+ public void AddFunctions(IDataReader rs)
+ {
+ while (rs.Read())
+ {
+ String key = (String)rs[0];
+ if( !func.ContainsKey(key ) )
+ func.Add(key, Int32.Parse(rs[1].ToString()));
+ }
+ }
+
+ /*
* This returns the function id associated by its name
*
* <p>If addFunction() or addFunctions() have not been called for this name,
@@ -487,10 +470,14 @@ namespace NpgsqlTypes
* @return Function ID for fastpath call
* @exception NpgsqlException is function is unknown.
*/
+ public Int32 GetID(String name)
+ {
+ Int32 id = (Int32)func[name];
+
+
+
+ return id;
+ }
+ }
- public Int32 GetID(String name)
- {
- return func[name];
- }
- }
-} \ No newline at end of file
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs b/mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs
index a00fa76f73e..51277265987 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/FastPathArg.cs
@@ -11,23 +11,19 @@
Changed case of method names to conform to .Net names standard.
Also changed type names to their true names. i.e. int -> Int32
- // Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
-
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-------------------------------------------------------------------------
*/
@@ -37,71 +33,67 @@ using Npgsql;
namespace NpgsqlTypes
{
- public class FastpathArg
- {
- /*
+ public class FastpathArg
+ {
+ /*
* Type of argument, true=integer, false=byte[]
*/
- public Boolean type;
+ public Boolean type;
- /*
+ /*
* Integer value if type=true
*/
- public Int32 value;
+ public Int32 value;
- /*
+ /*
* Byte value if type=false;
*/
- public Byte[] bytes;
+ public Byte[] bytes;
- /*
+ /*
* Constructs an argument that consists of an integer value
* @param value int value to set
*/
+ public FastpathArg(Int32 value)
+ {
+ type = true;
+ this.value = value;
+ }
- public FastpathArg(Int32 value)
- {
- type = true;
- this.value = value;
- }
-
- /*
+ /*
* Constructs an argument that consists of an array of bytes
* @param bytes array to store
*/
+ public FastpathArg(Byte[] bytes)
+ {
+ type = false;
+ this.bytes = bytes;
+ }
- public FastpathArg(Byte[] bytes)
- {
- type = false;
- this.bytes = bytes;
- }
-
- /*
+ /*
* Constructs an argument that consists of part of a byte array
* @param buf source array
* @param off offset within array
* @param len length of data to include
*/
-
- public FastpathArg(Byte[] buf, Int32 off, Int32 len)
- {
- type = false;
- bytes = new Byte[len];
- //TODO:
- bytes = buf;
- }
-
- /*
+ public FastpathArg(Byte[] buf, Int32 off, Int32 len)
+ {
+ type = false;
+ bytes = new Byte[len];
+ //TODO:
+ bytes = buf;
+ }
+
+ /*
* Constructs an argument that consists of a String.
* @param s String to store
*/
+ public FastpathArg(String s)
+ {
+ //this(s.ToCharArray());
+ }
- public FastpathArg(String s)
- {
- //this(s.ToCharArray());
- }
-
- /*
+ /*
* This sends this argument down the network stream.
*
* <p>The stream sent consists of the length.int4 then the contents.
@@ -112,33 +104,32 @@ namespace NpgsqlTypes
* @param s output stream
* @exception IOException if something failed on the network stream
*/
-
- public void Send(Stream s)
- {
- if (type)
- {
- // argument is an integer
- PGUtil.WriteInt32(s, 4);
- PGUtil.WriteInt32(s, value); // integer value of argument
- }
- else
- {
- // argument is a byte array
- PGUtil.WriteInt32(s, bytes.Length);
- s.Write(bytes, 0, bytes.Length);
- }
- }
-
- public Int32 SendSize()
- {
- if (type)
- {
- return 8;
- }
- else
- {
- return 4 + bytes.Length;
- }
- }
- }
-} \ No newline at end of file
+ public void Send(Stream s)
+ {
+ if (type)
+ {
+ // argument is an integer
+ PGUtil.WriteInt32(s, 4);
+ PGUtil.WriteInt32(s, value); // integer value of argument
+ }
+ else
+ {
+ // argument is a byte array
+ PGUtil.WriteInt32(s, bytes.Length);
+ s.Write(bytes,0,bytes.Length);
+ }
+ }
+
+ public Int32 SendSize()
+ {
+ if (type)
+ {
+ return 8;
+ }
+ else
+ {
+ return 4+bytes.Length;
+ }
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs b/mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs
index d0595ee296c..bf242a2bd7a 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/LargeObject.cs
@@ -11,53 +11,53 @@
Changed case of method names to conform to .Net names standard.
Also changed type names to their true names. i.e. int -> Int32
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-------------------------------------------------------------------------
*/
using System;
+using System.IO;
+using Npgsql;
namespace NpgsqlTypes
{
- public class LargeObject
- {
- /*
+
+ public class LargeObject
+ {
+ /*
* Indicates a seek from the begining of a file
*/
- public const Int32 SEEK_SET = 0;
+ public const Int32 SEEK_SET = 0;
- /*
+ /*
* Indicates a seek from the current position
*/
- public const Int32 SEEK_CUR = 1;
+ public const Int32 SEEK_CUR = 1;
- /*
+ /*
* Indicates a seek from the end of a file
*/
- public const Int32 SEEK_END = 2;
+ public const Int32 SEEK_END = 2;
- private readonly Fastpath fp; // Fastpath API to use
- private readonly Int32 oid; // OID of this object
- private readonly Int32 fd; // the descriptor of the open large object
+ private Fastpath fp; // Fastpath API to use
+ private Int32 oid; // OID of this object
+ private Int32 fd; // the descriptor of the open large object
- private Boolean closed = false; // true when we are closed
+ private Boolean closed = false; // true when we are closed
- /*
+ /*
* This opens a large object.
*
* <p>If the object does not exist, then an NpgsqlException is thrown.
@@ -69,89 +69,86 @@ namespace NpgsqlTypes
* @exception NpgsqlException if a database-access error occurs.
* @see org.postgresql.largeobject.LargeObjectManager
*/
+ public LargeObject(Fastpath fp, Int32 oid, Int32 mode)
+ {
+ this.fp = fp;
+ this.oid = oid;
- public LargeObject(Fastpath fp, Int32 oid, Int32 mode)
- {
- this.fp = fp;
- this.oid = oid;
+ FastpathArg[] args = new FastpathArg[2];
+ args[0] = new FastpathArg(oid);
+ args[1] = new FastpathArg(mode);
+ this.fd = fp.GetInteger("lo_open", args);
+ }
- FastpathArg[] args = new FastpathArg[2];
- args[0] = new FastpathArg(oid);
- args[1] = new FastpathArg(mode);
- this.fd = fp.GetInteger("lo_open", args);
- }
-
- /*
+ /*
* @return the OID of this LargeObject
*/
+ public Int32 GetOID()
+ {
+ return oid;
+ }
- public Int32 GetOID()
- {
- return oid;
- }
-
- /*
+ /*
* This method closes the object. You must not call methods in this
* object after this is called.
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public void Close()
- {
- if (!closed)
- {
- // finally close
- FastpathArg[] args = new FastpathArg[1];
- args[0] = new FastpathArg(fd);
- fp.FastpathCall("lo_close", false, args); // true here as we dont care!!
- closed = true;
- }
- }
-
- /*
+ public void Close()
+ {
+ if (!closed)
+ {
+
+ // finally close
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(fd);
+ fp.FastpathCall("lo_close", false, args); // true here as we dont care!!
+ closed = true;
+ }
+ }
+
+ /*
* Reads some data from the object, and return as a byte[] array
*
* @param len number of bytes to read
* @return byte[] array containing data read
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public Byte[] Read(Int32 len)
- {
- // This is the original method, where the entire block (len bytes)
- // is retrieved in one go.
- FastpathArg[] args = new FastpathArg[2];
- args[0] = new FastpathArg(fd);
- args[1] = new FastpathArg(len);
- return fp.GetData("loread", args);
-
- // This version allows us to break this down Int32o 4k blocks
- //if (len<=4048) {
- //// handle as before, return the whole block in one go
- //FastpathArg args[] = new FastpathArg[2];
- //args[0] = new FastpathArg(fd);
- //args[1] = new FastpathArg(len);
- //return fp.getData("loread",args);
- //} else {
- //// return in 4k blocks
- //byte[] buf=new byte[len];
- //int off=0;
- //while (len>0) {
- //int bs=4048;
- //len-=bs;
- //if (len<0) {
- //bs+=len;
- //len=0;
- //}
- //read(buf,off,bs);
- //off+=bs;
- //}
- //return buf;
- //}
- }
-
- /*
+ public Byte[] Read(Int32 len)
+ {
+ // This is the original method, where the entire block (len bytes)
+ // is retrieved in one go.
+ FastpathArg[] args = new FastpathArg[2];
+ args[0] = new FastpathArg(fd);
+ args[1] = new FastpathArg(len);
+ return fp.GetData("loread", args);
+
+ // This version allows us to break this down Int32o 4k blocks
+ //if (len<=4048) {
+ //// handle as before, return the whole block in one go
+ //FastpathArg args[] = new FastpathArg[2];
+ //args[0] = new FastpathArg(fd);
+ //args[1] = new FastpathArg(len);
+ //return fp.getData("loread",args);
+ //} else {
+ //// return in 4k blocks
+ //byte[] buf=new byte[len];
+ //int off=0;
+ //while (len>0) {
+ //int bs=4048;
+ //len-=bs;
+ //if (len<0) {
+ //bs+=len;
+ //len=0;
+ //}
+ //read(buf,off,bs);
+ //off+=bs;
+ //}
+ //return buf;
+ //}
+ }
+
+ /*
* Reads some data from the object into an existing array
*
* @param buf destination array
@@ -160,34 +157,30 @@ namespace NpgsqlTypes
* @return the number of bytes actually read
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public Int32 Read(Byte[] buf, Int32 off, Int32 len)
- {
- Byte[] b = Read(len);
- if (b.Length < len)
- {
- len = b.Length;
- }
- Array.Copy(b, 0, buf, off, len);
- return len;
- }
-
- /*
+ public Int32 Read(Byte[] buf, Int32 off, Int32 len)
+ {
+ Byte[] b = Read(len);
+ if (b.Length < len)
+ len = b.Length;
+ Array.Copy(b,0,buf,off,len);
+ return len;
+ }
+
+ /*
* Writes an array to the object
*
* @param buf array to write
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public void Write(Byte[] buf)
- {
- FastpathArg[] args = new FastpathArg[2];
- args[0] = new FastpathArg(fd);
- args[1] = new FastpathArg(buf);
- fp.FastpathCall("lowrite", false, args);
- }
-
- /*
+ public void Write(Byte[] buf)
+ {
+ FastpathArg[] args = new FastpathArg[2];
+ args[0] = new FastpathArg(fd);
+ args[1] = new FastpathArg(buf);
+ fp.FastpathCall("lowrite", false, args);
+ }
+
+ /*
* Writes some data from an array to the object
*
* @param buf destination array
@@ -195,16 +188,15 @@ namespace NpgsqlTypes
* @param len number of bytes to write
* @exception NpgsqlException if a database-access error occurs.
*/
+ public void Write(Byte[] buf, Int32 off, Int32 len)
+ {
+ Byte[] data = new Byte[len];
- public void Write(Byte[] buf, Int32 off, Int32 len)
- {
- Byte[] data = new Byte[len];
+ System.Array.Copy(buf, off, data, 0, len);
+ Write(data);
+ }
- Array.Copy(buf, off, data, 0, len);
- Write(data);
- }
-
- /*
+ /*
* Sets the current position within the object.
*
* <p>This is similar to the fseek() call in the standard C library. It
@@ -214,17 +206,16 @@ namespace NpgsqlTypes
* @param ref Either SEEK_SET, SEEK_CUR or SEEK_END
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public void Seek(Int32 pos, Int32 refi)
- {
- FastpathArg[] args = new FastpathArg[3];
- args[0] = new FastpathArg(fd);
- args[1] = new FastpathArg(pos);
- args[2] = new FastpathArg(refi);
- fp.FastpathCall("lo_lseek", false, args);
- }
-
- /*
+ public void Seek(Int32 pos, Int32 refi)
+ {
+ FastpathArg[] args = new FastpathArg[3];
+ args[0] = new FastpathArg(fd);
+ args[1] = new FastpathArg(pos);
+ args[2] = new FastpathArg(refi);
+ fp.FastpathCall("lo_lseek", false, args);
+ }
+
+ /*
* Sets the current position within the object.
*
* <p>This is similar to the fseek() call in the standard C library. It
@@ -233,25 +224,23 @@ namespace NpgsqlTypes
* @param pos position within object from begining
* @exception NpgsqlException if a database-access error occurs.
*/
+ public void Seek(Int32 pos)
+ {
+ Seek(pos, SEEK_SET);
+ }
- public void Seek(Int32 pos)
- {
- Seek(pos, SEEK_SET);
- }
-
- /*
+ /*
* @return the current position within the object
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public Int32 Tell()
- {
- FastpathArg[] args = new FastpathArg[1];
- args[0] = new FastpathArg(fd);
- return fp.GetInteger("lo_tell", args);
- }
-
- /*
+ public Int32 Tell()
+ {
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(fd);
+ return fp.GetInteger("lo_tell", args);
+ }
+
+ /*
* This method is inefficient, as the only way to find out the size of
* the object is to seek to the end, record the current position, then
* return to the original position.
@@ -261,14 +250,14 @@ namespace NpgsqlTypes
* @return the size of the large object
* @exception NpgsqlException if a database-access error occurs.
*/
-
- public Int32 Size()
- {
- Int32 cp = Tell();
- Seek(0, SEEK_END);
- Int32 sz = Tell();
- Seek(cp, SEEK_SET);
- return sz;
- }
- }
-} \ No newline at end of file
+ public Int32 Size()
+ {
+ Int32 cp = Tell();
+ Seek(0, SEEK_END);
+ Int32 sz = Tell();
+ Seek(cp, SEEK_SET);
+ return sz;
+ }
+
+ }
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs b/mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs
index c247b15b19d..26d082fce77 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/LargeObjectManager.cs
@@ -12,66 +12,59 @@
Changed case of method names to conform to .Net names standard.
Also changed type names to their true names. i.e. int -> Int32
- // Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
-
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-------------------------------------------------------------------------
*/
using System;
using System.Data;
-using System.Text;
using Npgsql;
namespace NpgsqlTypes
{
- /// <summary>
- /// Summary description for LargeObjectManager.
- /// </summary>
- public class LargeObjectManager
- {
- // the fastpath api for this connection
- private readonly Fastpath fp;
-
- /*
+ /// <summary>
+ /// Summary description for LargeObjectManager.
+ /// </summary>
+ public class LargeObjectManager
+ {
+ // the fastpath api for this connection
+ private Fastpath fp;
+
+ /*
* This mode indicates we want to write to an object
*/
- public const Int32 WRITE = 0x00020000;
+ public const Int32 WRITE = 0x00020000;
- /*
+ /*
* This mode indicates we want to read an object
*/
- public static Int32 READ = 0x00040000;
+ public static Int32 READ = 0x00040000;
- /*
+ /*
* This mode is the default. It indicates we want read and write access to
* a large object
*/
- public static Int32 READWRITE = READ | WRITE;
-
+ public static Int32 READWRITE = READ | WRITE;
- private LargeObjectManager()
- {
- /*
- * This prevents us being created by mere mortals
- */
- }
+ /*
+ * This prevents us being created by mere mortals
+ */
+ private LargeObjectManager()
+ {}
- /*
+ /*
* Constructs the LargeObject API.
*
* <p><b>Important Notice</b>
@@ -81,68 +74,55 @@ namespace NpgsqlTypes
* org.postgresql.Connection class keeps track of the various extension API's
* and it's advised you use those to gain access, and not going direct.
*/
-
- public LargeObjectManager(NpgsqlConnection conn)
- {
- // We need Fastpath to do anything
- // Now get the function oid's for the api
- //
- // This is an example of Fastpath.addFunctions();
- //
- //String sql;
- StringBuilder sql = null;
- try
- {
- sql = new StringBuilder();
- if (conn.PostgreSqlVersion > new Version(7, 3, 0))
- {
- sql.Append("SELECT p.proname,p.oid ");
- sql.Append(" FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n ");
- sql.Append(" WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND (");
- }
- else
- {
- sql.Append("SELECT proname,oid FROM pg_proc WHERE ");
- }
- sql.Append(" proname = 'lo_open'");
- sql.Append(" or proname = 'lo_close'");
- sql.Append(" or proname = 'lo_creat'");
- sql.Append(" or proname = 'lo_unlink'");
- sql.Append(" or proname = 'lo_lseek'");
- sql.Append(" or proname = 'lo_tell'");
- sql.Append(" or proname = 'loread'");
- sql.Append(" or proname = 'lowrite'");
-
- if (conn.PostgreSqlVersion > new Version(7, 3, 0))
- {
- sql.Append(")");
- }
-
- using (IDbCommand cmd = new NpgsqlCommand(sql.ToString()))
- {
- cmd.Connection = conn;
-
- this.fp = new Fastpath(conn, conn.Connector.Stream);
-
- using (IDataReader res = cmd.ExecuteReader())
- {
- if (res == null)
- {
- throw new NpgsqlException("postgresql.lo.init");
- }
-
-
- fp.AddFunctions(res);
- }
- }
- }
- finally
- {
- sql = null;
- }
- }
-
- /*
+ public LargeObjectManager(NpgsqlConnection conn)
+ {
+ // We need Fastpath to do anything
+ // Now get the function oid's for the api
+ //
+ // This is an example of Fastpath.addFunctions();
+ //
+ String sql;
+ if (conn.ServerVersion > new ServerVersion(7,3,0) )
+ {
+
+ sql = "SELECT p.proname,p.oid "+
+ " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "+
+ " WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND (";
+ }
+ else
+ {
+ sql = "SELECT proname,oid FROM pg_proc WHERE ";
+ }
+ sql += " proname = 'lo_open'" +
+ " or proname = 'lo_close'" +
+ " or proname = 'lo_creat'" +
+ " or proname = 'lo_unlink'" +
+ " or proname = 'lo_lseek'" +
+ " or proname = 'lo_tell'" +
+ " or proname = 'loread'" +
+ " or proname = 'lowrite'";
+
+ if (conn.ServerVersion > new ServerVersion(7,3,0) )
+ {
+ sql += ")";
+ }
+
+ IDbCommand cmd = new NpgsqlCommand(sql);
+ cmd.Connection = conn;
+
+ this.fp = new Fastpath(conn,conn.Connector.Stream);
+
+ IDataReader res = cmd.ExecuteReader(CommandBehavior.CloseConnection);
+
+
+ if (res == null)
+ throw new NpgsqlException("postgresql.lo.init");
+
+
+ fp.AddFunctions(res);
+ }
+
+ /*
* This opens an existing large object, based on its OID. This method
* assumes that READ and WRITE access is required (the default).
*
@@ -150,13 +130,12 @@ namespace NpgsqlTypes
* @return LargeObject instance providing access to the object
* @exception NpgsqlException on error
*/
+ public LargeObject Open(Int32 oid)
+ {
+ return new LargeObject(fp, oid, READWRITE);
+ }
- public LargeObject Open(Int32 oid)
- {
- return new LargeObject(fp, oid, READWRITE);
- }
-
- /*
+ /*
* This opens an existing large object, based on its OID
*
* @param oid of large object
@@ -164,13 +143,12 @@ namespace NpgsqlTypes
* @return LargeObject instance providing access to the object
* @exception NpgsqlException on error
*/
+ public LargeObject Open(Int32 oid, Int32 mode)
+ {
+ return new LargeObject(fp, oid, mode);
+ }
- public LargeObject Open(Int32 oid, Int32 mode)
- {
- return new LargeObject(fp, oid, mode);
- }
-
- /*
+ /*
* This creates a large object, returning its OID.
*
* <p>It defaults to READWRITE for the new object's attributes.
@@ -178,44 +156,41 @@ namespace NpgsqlTypes
* @return oid of new object
* @exception NpgsqlException on error
*/
-
- public Int32 Create()
- {
- FastpathArg[] args = new FastpathArg[1];
- args[0] = new FastpathArg(READWRITE);
- return fp.GetInteger("lo_creat", args);
- }
-
- /*
+ public Int32 Create()
+ {
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(READWRITE);
+ return fp.GetInteger("lo_creat", args);
+ }
+
+ /*
* This creates a large object, returning its OID
*
* @param mode a bitmask describing different attributes of the new object
* @return oid of new object
* @exception NpgsqlException on error
*/
-
- public Int32 Create(Int32 mode)
- {
- FastpathArg[] args = new FastpathArg[1];
- args[0] = new FastpathArg(mode);
- return fp.GetInteger("lo_creat", args);
- }
-
- /*
+ public Int32 Create(Int32 mode)
+ {
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(mode);
+ return fp.GetInteger("lo_creat", args);
+ }
+
+ /*
* This deletes a large object.
*
* @param oid describing object to delete
* @exception NpgsqlException on error
*/
-
- public void Delete(Int32 oid)
- {
- FastpathArg[] args = new FastpathArg[1];
- args[0] = new FastpathArg(oid);
- fp.FastpathCall("lo_unlink", false, args);
- }
-
- /*
+ public void Delete(Int32 oid)
+ {
+ FastpathArg[] args = new FastpathArg[1];
+ args[0] = new FastpathArg(oid);
+ fp.FastpathCall("lo_unlink", false, args);
+ }
+
+ /*
* This deletes a large object.
*
* <p>It is identical to the delete method, and is supplied as the C API uses
@@ -224,10 +199,11 @@ namespace NpgsqlTypes
* @param oid describing object to delete
* @exception NpgsqlException on error
*/
+ public void Unlink(Int32 oid)
+ {
+ Delete(oid);
+ }
+
+ }
- public void Unlink(Int32 oid)
- {
- Delete(oid);
- }
- }
-} \ No newline at end of file
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlDbType.cs b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlDbType.cs
index a5ec51820fa..d3f8c87d19b 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlDbType.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlDbType.cs
@@ -7,65 +7,58 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+using System;
+using Npgsql;
namespace NpgsqlTypes
{
- public enum NpgsqlDbType
- {
- // This list used to be ordered. But this ordering would break compiled applications
- // as enum values would change after each insertion. Now, just append new types.
-
- // Binary or with other values. E.g. Array of Box is NpgsqlDbType.Array | NpgsqlDbType.Box
+ public enum NpgsqlDbType
+ {
- Array = int.MinValue,
+ // This list used to be ordered. But this ordering would break compiled applications
+ // as enum values would change after each insertion. Now, just append new types.
+
+ Bigint,
+ Boolean,
+ Box,
+ Bytea,
+ Circle,
+ Char,
+ Date,
+ Double,
+ Integer,
+ Line,
+ LSeg,
+ Money,
+ Numeric,
+ Path,
+ Point,
+ Polygon,
+ Real,
+ Smallint,
+ Text,
+ Time,
+ Timestamp,
+ Varchar,
+ Refcursor,
+ Inet,
+ Bit,
+ TimestampTZ
- Bigint = 1,
+ }
- Boolean,
- Box,
- Bytea,
- Circle,
- Char,
- Date,
- Double,
- Integer,
- Line,
- LSeg,
- Money,
- Numeric,
- Path,
- Point,
- Polygon,
- Real,
- Smallint,
- Text,
- Time,
- Timestamp,
- Varchar,
- Refcursor,
- Inet,
- Bit,
- TimestampTZ,
- Uuid,
- Xml,
- Oidvector,
- Interval,
- TimeTZ
- }
-} \ No newline at end of file
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs
index 9bedd242a73..0c3f2e7b75d 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypeConverters.cs
@@ -7,675 +7,574 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// This file provides data type converters between PostgreSQL representations
// and .NET objects.
using System;
-using System.Collections.Generic;
+using System.Collections;
using System.Globalization;
-using System.IO;
-using System.Net;
using System.Text;
+using System.IO;
using System.Text.RegularExpressions;
+using Npgsql;
+
namespace NpgsqlTypes
{
- /// <summary>
- /// Provide event handlers to convert all native supported basic data types from their backend
- /// text representation to a .NET object.
- /// </summary>
- internal abstract class BasicBackendToNativeTypeConverter
- {
- private static readonly String[] DateFormats = new String[] { "yyyy-MM-dd", };
-
- private static readonly String[] TimeFormats =
- new String[]
- {
- "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", "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>
- /// Binary data.
- /// </summary>
- internal static Object ToBinary(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- Int32 octalValue = 0;
- Int32 byteAPosition = 0;
- Int32 byteAStringLength = BackendData.Length;
- MemoryStream ms = new MemoryStream();
+ /// <summary>
+ /// Provide event handlers to convert all native supported basic data types from their backend
+ /// text representation to a .NET object.
+ /// </summary>
+ internal abstract class BasicBackendToNativeTypeConverter
+ {
+ private static readonly String[] DateFormats = new String[]
+ {
+ "yyyy-MM-dd",
+ };
+
+ private static readonly String[] TimeFormats = new String[]
+ {
+ "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",
+ "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>
+ /// Binary data.
+ /// </summary>
+ internal static Object ToBinary(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ Int32 octalValue = 0;
+ Int32 byteAPosition = 0;
+ Int32 byteAStringLength = BackendData.Length;
+ MemoryStream ms = new MemoryStream();
+
+ while (byteAPosition < byteAStringLength)
+ {
+ // The IsDigit is necessary in case we receive a \ as the octal value and not
+ // as the indicator of a following octal value in decimal format.
+ // i.e.: \201\301P\A
+ if (BackendData[byteAPosition] == '\\') {
+
+ if (byteAPosition + 1 == byteAStringLength)
+ {
+ octalValue = '\\';
+ byteAPosition++;
+ }
+ else if (Char.IsDigit(BackendData[byteAPosition + 1]))
+ {
+ octalValue = (Byte.Parse(BackendData[byteAPosition + 1].ToString()) << 6);
+ octalValue |= (Byte.Parse(BackendData[byteAPosition + 2].ToString()) << 3);
+ octalValue |= Byte.Parse(BackendData[byteAPosition + 3].ToString());
+ byteAPosition += 4;
+
+ }
+ else
+ {
+ octalValue = '\\';
+ byteAPosition += 2;
+ }
+
+ } else {
+ octalValue = (Byte)BackendData[byteAPosition];
+ byteAPosition++;
+ }
+
+
+ ms.WriteByte((Byte)octalValue);
+
+ }
+
+ return ms.ToArray();
+ }
- while (byteAPosition < byteAStringLength)
- {
- // The IsDigit is necessary in case we receive a \ as the octal value and not
- // as the indicator of a following octal value in decimal format.
- // i.e.: \201\301P\A
- if (BackendData[byteAPosition] == '\\')
- {
- if (byteAPosition + 1 == byteAStringLength)
- {
- octalValue = '\\';
- byteAPosition++;
- }
- else if (Char.IsDigit(BackendData[byteAPosition + 1]))
- {
- octalValue = Convert.ToByte(BackendData.Substring(byteAPosition + 1, 3), 8);
- //octalValue = (Byte.Parse(BackendData[byteAPosition + 1].ToString()) << 6);
- //octalValue |= (Byte.Parse(BackendData[byteAPosition + 2].ToString()) << 3);
- //octalValue |= Byte.Parse(BackendData[byteAPosition + 3].ToString());
- byteAPosition += 4;
- }
- else
- {
- octalValue = '\\';
- byteAPosition += 2;
- }
- }
- else
- {
- octalValue = (Byte)BackendData[byteAPosition];
- byteAPosition++;
- }
-
-
- ms.WriteByte((Byte)octalValue);
- }
-
- return ms.ToArray();
- }
-
- /// <summary>
- /// Convert a postgresql boolean to a System.Boolean.
- /// </summary>
- internal static Object ToBoolean(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize,
- Int32 TypeModifier)
- {
- return (BackendData.ToLower() == "t" ? true : false);
- }
+ /// <summary>
+ /// Convert a postgresql boolean to a System.Boolean.
+ /// </summary>
+ internal static Object ToBoolean(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ return (BackendData.ToLower() == "t" ? true : false);
+ }
- /// <summary>
- /// Convert a postgresql bit to a System.Boolean.
- /// </summary>
- internal static Object ToBit(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- return (BackendData.ToLower() == "1" ? true : false);
- }
-
- /// <summary>
- /// Convert a postgresql datetime to a System.DateTime.
- /// </summary>
- internal static Object ToDateTime(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize,
- Int32 TypeModifier)
- {
- // Get the date time parsed in all expected formats for timestamp.
+ /// <summary>
+ /// Convert a postgresql bit to a System.Boolean.
+ /// </summary>
+ internal static Object ToBit(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ return (BackendData.ToLower() == "1" ? true : false);
+ }
- // First check for special values infinity and -infinity.
+ /// <summary>
+ /// Convert a postgresql datetime to a System.DateTime.
+ /// </summary>
+ internal static Object ToDateTime(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+
+ // Get the date time parsed in all expected formats for timestamp.
- if (BackendData == "infinity")
- {
- return DateTime.MaxValue;
- }
+ // First check for special values infinity and -infinity.
- if (BackendData == "-infinity")
- {
- return DateTime.MinValue;
- }
-
- return
- DateTime.ParseExact(BackendData, DateTimeFormats, DateTimeFormatInfo.InvariantInfo,
- DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces);
- }
-
- /// <summary>
- /// Convert a postgresql date to a System.DateTime.
- /// </summary>
- internal static Object ToDate(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- return
- DateTime.ParseExact(BackendData, DateFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowWhiteSpaces);
- }
-
- /// <summary>
- /// Convert a postgresql time to a System.DateTime.
- /// </summary>
- internal static Object ToTime(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- return
- DateTime.ParseExact(BackendData, TimeFormats, DateTimeFormatInfo.InvariantInfo,
- DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces);
- }
-
- /// <summary>
- /// Convert a postgresql money to a System.Decimal.
- /// </summary>
- internal static Object ToMoney(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- // It's a number with a $ on the beginning...
- return Convert.ToDecimal(BackendData.Substring(1, BackendData.Length - 1), CultureInfo.InvariantCulture);
- }
- }
-
- /// <summary>
- /// Provide event handlers to convert the basic native supported data types from
- /// native form to backend representation.
- /// </summary>
- internal abstract class BasicNativeToBackendTypeConverter
- {
- /// <summary>
- /// Binary data.
- /// </summary>
- internal static String ToBinary(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- Byte[] byteArray = (Byte[])NativeData;
- int len = byteArray.Length;
- char[] res = new char[len * 5];
+ if (BackendData == "infinity")
+ return DateTime.MaxValue;
- for (int i = 0, o = 0; i < len; ++i, o += 5)
- {
- byte item = byteArray[i];
- res[o] = res[o + 1] = '\\';
- res[o + 2] = (char)('0' + (7 & (item >> 6)));
- res[o + 3] = (char)('0' + (7 & (item >> 3)));
- res[o + 4] = (char)('0' + (7 & item));
- }
-
- return new String(res);
- }
-
- /// <summary>
- /// Convert to a postgresql boolean.
- /// </summary>
- internal static String ToBoolean(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- return ((bool)NativeData) ? "TRUE" : "FALSE";
- }
+ if (BackendData == "-infinity")
+ return DateTime.MinValue;
- /// <summary>
- /// Convert to a postgresql bit.
- /// </summary>
- internal static String ToBit(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- // Convert boolean values to bit or convert int32 values to bit - odd values are 1 and
- // even numbers are 0.
- if (NativeData is Boolean)
- {
- return ((Boolean)NativeData) ? "1" : "0";
- }
- else
- {
- return (((Int32)NativeData) % 2 == 1) ? "1" : "0";
- }
- }
-
- /// <summary>
- /// Convert to a postgresql timestamp.
- /// </summary>
- internal static String ToDateTime(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- if (!(NativeData is DateTime))
- {
- return ExtendedNativeToBackendTypeConverter.ToTimeStamp(TypeInfo, NativeData);
- }
- if (DateTime.MaxValue.Equals(NativeData))
- {
- return "infinity";
- }
- if (DateTime.MinValue.Equals(NativeData))
- {
- return "-infinity";
- }
- return ((DateTime)NativeData).ToString("yyyy-MM-dd HH:mm:ss.ffffff", DateTimeFormatInfo.InvariantInfo);
- }
-
- /// <summary>
- /// Convert to a postgresql date.
- /// </summary>
- internal static String ToDate(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- if (!(NativeData is DateTime))
- {
- return ExtendedNativeToBackendTypeConverter.ToDate(TypeInfo, NativeData);
- }
- return ((DateTime)NativeData).ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
- }
-
- /// <summary>
- /// Convert to a postgresql time.
- /// </summary>
- internal static String ToTime(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- if (!(NativeData is DateTime))
- {
- return ExtendedNativeToBackendTypeConverter.ToTime(TypeInfo, NativeData);
- }
- else
- {
- return ((DateTime)NativeData).ToString("HH:mm:ss.ffffff", DateTimeFormatInfo.InvariantInfo);
- }
- }
-
- /// <summary>
- /// Convert to a postgres money.
- /// </summary>
- internal static String ToMoney(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- return "$" + ((IFormattable)NativeData).ToString(null, CultureInfo.InvariantCulture.NumberFormat);
- }
- }
-
-
- /// <summary>
- /// Provide event handlers to convert extended native supported data types from their backend
- /// text representation to a .NET object.
- /// </summary>
- internal abstract class ExtendedBackendToNativeTypeConverter
- {
- private static readonly Regex pointRegex = new Regex(@"\((-?\d+.?\d*),(-?\d+.?\d*)\)");
- private static readonly Regex boxlsegRegex = new Regex(@"\((-?\d+.?\d*),(-?\d+.?\d*)\),\((-?\d+.?\d*),(-?\d+.?\d*)\)");
- private static readonly Regex pathpolygonRegex = new Regex(@"\((-?\d+.?\d*),(-?\d+.?\d*)\)");
- private static readonly Regex circleRegex = new Regex(@"<\((-?\d+.?\d*),(-?\d+.?\d*)\),(\d+.?\d*)>");
-
-
- /// <summary>
- /// Convert a postgresql point to a System.NpgsqlPoint.
- /// </summary>
- internal static Object ToPoint(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- Match m = pointRegex.Match(BackendData);
+ return DateTime.ParseExact(BackendData,
+ DateTimeFormats,
+ DateTimeFormatInfo.InvariantInfo,
+ DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces);
+ }
- return
- new NpgsqlPoint(Single.Parse(m.Groups[1].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(m.Groups[2].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat));
- }
+ /// <summary>
+ /// Convert a postgresql date to a System.DateTime.
+ /// </summary>
+ internal static Object ToDate(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ return DateTime.ParseExact(BackendData,
+ DateFormats,
+ DateTimeFormatInfo.InvariantInfo,
+ DateTimeStyles.AllowWhiteSpaces);
+ }
- /// <summary>
- /// Convert a postgresql point to a System.RectangleF.
- /// </summary>
- internal static Object ToBox(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- Match m = boxlsegRegex.Match(BackendData);
-
- return
- new NpgsqlBox(
- new NpgsqlPoint(Single.Parse(m.Groups[1].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(m.Groups[2].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)),
- new NpgsqlPoint(Single.Parse(m.Groups[3].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(m.Groups[4].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)));
- }
-
- /// <summary>
- /// LDeg.
- /// </summary>
- internal static Object ToLSeg(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- Match m = boxlsegRegex.Match(BackendData);
-
- return
- new NpgsqlLSeg(
- new NpgsqlPoint(Single.Parse(m.Groups[1].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(m.Groups[2].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)),
- new NpgsqlPoint(Single.Parse(m.Groups[3].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(m.Groups[4].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)));
- }
-
- /// <summary>
- /// Path.
- /// </summary>
- internal static Object ToPath(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- Match m = pathpolygonRegex.Match(BackendData);
- Boolean open = (BackendData[0] == '[');
- List<NpgsqlPoint> points = new List<NpgsqlPoint>();
+ /// <summary>
+ /// Convert a postgresql time to a System.DateTime.
+ /// </summary>
+ internal static Object ToTime(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ return DateTime.ParseExact(BackendData,
+ TimeFormats,
+ DateTimeFormatInfo.InvariantInfo,
+ DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.AllowWhiteSpaces);
+ }
- while (m.Success)
- {
- if (open)
- {
- points.Add(
- new NpgsqlPoint(
- Single.Parse(m.Groups[1].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(m.Groups[2].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)));
- }
- else
- {
- // Here we have to do a little hack, because as of 2004-08-11 mono cvs version, the last group is returned with
- // a trailling ')' only when the last character of the string is a ')' which is the case for closed paths
- // returned by backend. This gives parsing exception when converting to single.
- // I still don't know if this is a bug in mono or in my regular expression.
- // Check if there is this character and remove it.
-
- String group2 = m.Groups[2].ToString();
- if (group2.EndsWith(")"))
- {
- group2 = group2.Remove(group2.Length - 1, 1);
- }
-
- points.Add(
- new NpgsqlPoint(
- Single.Parse(m.Groups[1].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(group2, NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)));
- }
-
- m = m.NextMatch();
- }
-
- NpgsqlPath result = new NpgsqlPath(points.ToArray());
- result.Open = open;
- return result;
- }
-
- /// <summary>
- /// Polygon.
- /// </summary>
- internal static Object ToPolygon(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize,
- Int32 TypeModifier)
- {
- Match m = pathpolygonRegex.Match(BackendData);
- List<NpgsqlPoint> points = new List<NpgsqlPoint>();
+ /// <summary>
+ /// Convert a postgresql money to a System.Decimal.
+ /// </summary>
+ internal static Object ToMoney(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ // It's a number with a $ on the beginning...
+ return Convert.ToDecimal(BackendData.Substring(1, BackendData.Length - 1), CultureInfo.InvariantCulture);
+ }
+
+ }
+
+ /// <summary>
+ /// Provide event handlers to convert the basic native supported data types from
+ /// native form to backend representation.
+ /// </summary>
+ internal abstract class BasicNativeToBackendTypeConverter
+ {
+ /// <summary>
+ /// Binary data.
+ /// </summary>
+ internal static String ToBinary(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ Byte[] byteArray = (Byte[])NativeData;
+ int len = byteArray.Length;
+ char[] res = new char[len * 5];
+
+ for (int i = 0, o = 0; i < len; ++i, o += 5)
+ {
+ byte item = byteArray[i];
+ res[o] = res[o + 1] = '\\';
+ res[o + 2] = (char)('0' + (7 & (item >> 6)));
+ res[o + 3] = (char)('0' + (7 & (item >> 3)));
+ res[o + 4] = (char)('0' + (7 & item));
+ }
+
+ return new String(res);
+ }
- while (m.Success)
- {
- // Here we have to do a little hack, because as of 2004-08-11 mono cvs version, the last group is returned with
- // a trailling ')' only when the last character of the string is a ')' which is the case for closed paths
- // returned by backend. This gives parsing exception when converting to single.
- // I still don't know if this is a bug in mono or in my regular expression.
- // Check if there is this character and remove it.
+ /// <summary>
+ /// Convert to a postgresql boolean.
+ /// </summary>
+ internal static String ToBoolean(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ return ((bool)NativeData) ? "TRUE" : "FALSE";
+ }
- String group2 = m.Groups[2].ToString();
- if (group2.EndsWith(")"))
- {
- group2 = group2.Remove(group2.Length - 1, 1);
- }
+ /// <summary>
+ /// Convert to a postgresql bit.
+ /// </summary>
+ internal static String ToBit(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ // Convert boolean values to bit or convert int32 values to bit - odd values are 1 and
+ // even numbers are 0.
+ if (NativeData is Boolean)
+ return ((Boolean)NativeData) ? "1" : "0";
+ else
+ return (((Int32)NativeData) % 2 == 1) ? "1" : "0";
+ }
- points.Add(
- new NpgsqlPoint(Single.Parse(m.Groups[1].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(group2, NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)));
+ /// <summary>
+ /// Convert to a postgresql timestamp.
+ /// </summary>
+ internal static String ToDateTime(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ if (DateTime.MaxValue.Equals(NativeData))
+ return "infinity";
+ if (DateTime.MinValue.Equals(NativeData))
+ return "-infinity";
+ return ((DateTime)NativeData).ToString("yyyy-MM-dd HH:mm:ss.ffffff", DateTimeFormatInfo.InvariantInfo);
+ }
+ /// <summary>
+ /// Convert to a postgresql date.
+ /// </summary>
+ internal static String ToDate(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ return ((DateTime)NativeData).ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo);
+ }
- m = m.NextMatch();
- }
+ /// <summary>
+ /// Convert to a postgresql time.
+ /// </summary>
+ internal static String ToTime(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ return ((DateTime)NativeData).ToString("HH:mm:ss.ffffff", DateTimeFormatInfo.InvariantInfo);
+ }
- return new NpgsqlPolygon(points);
- }
+ /// <summary>
+ /// Convert to a postgres money.
+ /// </summary>
+ internal static String ToMoney(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ return "$" + ((IFormattable)NativeData).ToString(null, CultureInfo.InvariantCulture.NumberFormat);
+ }
+
+
+ }
+
+
+ /// <summary>
+ /// Provide event handlers to convert extended native supported data types from their backend
+ /// text representation to a .NET object.
+ /// </summary>
+ internal abstract class ExtendedBackendToNativeTypeConverter
+ {
+
+ private static readonly Regex pointRegex = new Regex(@"\((-?\d+.?\d*),(-?\d+.?\d*)\)");
+ private static readonly Regex boxlsegRegex = new Regex(@"\((-?\d+.?\d*),(-?\d+.?\d*)\),\((-?\d+.?\d*),(-?\d+.?\d*)\)");
+ private static readonly Regex pathpolygonRegex = new Regex(@"\((-?\d+.?\d*),(-?\d+.?\d*)\)");
+ private static readonly Regex circleRegex = new Regex(@"<\((-?\d+.?\d*),(-?\d+.?\d*)\),(\d+.?\d*)>");
+
+
+ /// <summary>
+ /// Convert a postgresql point to a System.NpgsqlPoint.
+ /// </summary>
+ internal static Object ToPoint(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+
+ Match m = pointRegex.Match(BackendData);
+
+ return new NpgsqlPoint(
+ Single.Parse(m.Groups[1].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(m.Groups[2].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat));
+
+
+
+ }
- /// <summary>
- /// Circle.
- /// </summary>
- internal static Object ToCircle(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- Match m = circleRegex.Match(BackendData);
- return
- new NpgsqlCircle(
- new NpgsqlPoint(Single.Parse(m.Groups[1].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat),
- Single.Parse(m.Groups[2].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat)),
- Single.Parse(m.Groups[3].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat));
- }
-
- /// <summary>
- /// Inet.
- /// </summary>
- internal static Object ToInet(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- return new NpgsqlInet(BackendData);
- }
-
- internal static Object ToGuid(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ /// <summary>
+ /// Convert a postgresql point to a System.RectangleF.
+ /// </summary>
+ internal static Object ToBox(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
{
- return new Guid(BackendData);
+
+ Match m = boxlsegRegex.Match(BackendData);
+
+ return new NpgsqlBox(
+ new NpgsqlPoint(
+ Single.Parse(m.Groups[1].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(m.Groups[2].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)),
+ new NpgsqlPoint(
+ Single.Parse(m.Groups[3].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(m.Groups[4].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)));
}
- /// <summary>
- /// interval
- /// </summary>
- internal static object ToInterval(NpgsqlBackendTypeInfo typeInfo, String backendData, Int16 typeSize,
- Int32 typeModifier)
- {
- return NpgsqlInterval.Parse(backendData);
- }
+ /// <summary>
+ /// LDeg.
+ /// </summary>
+ internal static Object ToLSeg(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ Match m = boxlsegRegex.Match(BackendData);
+
+ return new NpgsqlLSeg(
+ new NpgsqlPoint(
+ Single.Parse(m.Groups[1].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(m.Groups[2].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)),
+ new NpgsqlPoint(
+ Single.Parse(m.Groups[3].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(m.Groups[4].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)));
+ }
- internal static object ToTime(NpgsqlBackendTypeInfo typeInfo, String backendData, Int16 typeSize, Int32 typeModifier)
- {
- return NpgsqlTime.Parse(backendData);
- }
+ /// <summary>
+ /// Path.
+ /// </summary>
+ internal static Object ToPath(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+
+ Match m = pathpolygonRegex.Match(BackendData);
+ Boolean open = (BackendData[0] == '[');
+ ArrayList points = new ArrayList();
+
+ while (m.Success)
+ {
+
+ if (open)
+ points.Add(new NpgsqlPoint(
+ Single.Parse(m.Groups[1].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(m.Groups[2].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)));
+ else
+ {
+ // Here we have to do a little hack, because as of 2004-08-11 mono cvs version, the last group is returned with
+ // a trailling ')' only when the last character of the string is a ')' which is the case for closed paths
+ // returned by backend. This gives parsing exception when converting to single.
+ // I still don't know if this is a bug in mono or in my regular expression.
+ // Check if there is this character and remove it.
+
+ String group2 = m.Groups[2].ToString();
+ if (group2.EndsWith(")"))
+ group2 = group2.Remove(group2.Length - 1, 1);
+
+ points.Add(new NpgsqlPoint(
+ Single.Parse(m.Groups[1].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(group2, NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)));
+ }
+
+ m = m.NextMatch();
+
+ }
+
+ NpgsqlPath result = new NpgsqlPath((NpgsqlPoint[]) points.ToArray(typeof(NpgsqlPoint)));
+ result.IsOpen = open;
+ return result;
+
+
+ }
- internal static object ToTimeTZ(NpgsqlBackendTypeInfo typeInfo, String backendData, Int16 typeSize, Int32 typeModifier)
- {
- return NpgsqlTimeTZ.Parse(backendData);
- }
+ /// <summary>
+ /// Polygon.
+ /// </summary>
+ internal static Object ToPolygon(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+
+ Match m = pathpolygonRegex.Match(BackendData);
+ ArrayList points = new ArrayList();
+
+ while (m.Success)
+ {
+
+ // Here we have to do a little hack, because as of 2004-08-11 mono cvs version, the last group is returned with
+ // a trailling ')' only when the last character of the string is a ')' which is the case for closed paths
+ // returned by backend. This gives parsing exception when converting to single.
+ // I still don't know if this is a bug in mono or in my regular expression.
+ // Check if there is this character and remove it.
+
+ String group2 = m.Groups[2].ToString();
+ if (group2.EndsWith(")"))
+ group2 = group2.Remove(group2.Length - 1, 1);
+
+ points.Add(new NpgsqlPoint(
+ Single.Parse(m.Groups[1].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(group2, NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)));
+
+
+ m = m.NextMatch();
+
+ }
+
+ return new NpgsqlPolygon((NpgsqlPoint[]) points.ToArray(typeof(NpgsqlPoint)));
+
+ }
- internal static object ToDate(NpgsqlBackendTypeInfo typeInfo, String backendData, Int16 typeSize, Int32 typeModifier)
- {
- return NpgsqlDate.Parse(backendData);
- }
+ /// <summary>
+ /// Circle.
+ /// </summary>
+ internal static Object ToCircle(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ Match m = circleRegex.Match(BackendData);
+ return new NpgsqlCircle(
+ new NpgsqlPoint(
+ Single.Parse(m.Groups[1].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat),
+ Single.Parse(m.Groups[2].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat)),
+ Single.Parse(m.Groups[3].ToString(), NumberStyles.Any,
+ CultureInfo.InvariantCulture.NumberFormat));
+
+ }
- internal static object ToTimeStamp(NpgsqlBackendTypeInfo typeInfo, String backendData, Int16 typeSize,
- Int32 typeModifier)
- {
- return NpgsqlTimeStamp.Parse(backendData);
- }
+ /// <summary>
+ /// Inet.
+ /// </summary>
+ internal static Object ToInet(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ return new NpgsqlInet(BackendData);
+
+ }
+ }
+
+ /// <summary>
+ /// Provide event handlers to convert extended native supported data types from
+ /// native form to backend representation.
+ /// </summary>
+ internal abstract class ExtendedNativeToBackendTypeConverter
+ {
+ /// <summary>
+ /// Point.
+ /// </summary>
+ internal static String ToPoint(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ if (NativeData is NpgsqlPoint)
+ {
+ NpgsqlPoint P = (NpgsqlPoint)NativeData;
+ return String.Format(CultureInfo.InvariantCulture, "({0},{1})", P.X, P.Y);
+ }
+ else
+ {
+ throw new InvalidCastException("Unable to cast data to NpgsqlPoint type");
+ }
+ }
- internal static object ToTimeStampTZ(NpgsqlBackendTypeInfo typeInfo, String backendData, Int16 typeSize,
- Int32 typeModifier)
- {
- return NpgsqlTimeStampTZ.Parse(backendData);
- }
- }
-
- /// <summary>
- /// Provide event handlers to convert extended native supported data types from
- /// native form to backend representation.
- /// </summary>
- internal abstract class ExtendedNativeToBackendTypeConverter
- {
- /// <summary>
- /// Point.
- /// </summary>
- internal static String ToPoint(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- if (NativeData is NpgsqlPoint)
- {
- NpgsqlPoint P = (NpgsqlPoint)NativeData;
- return String.Format(CultureInfo.InvariantCulture, "({0},{1})", P.X, P.Y);
- }
- else
- {
- throw new InvalidCastException("Unable to cast data to NpgsqlPoint type");
- }
- }
-
- /// <summary>
- /// Box.
- /// </summary>
- internal static String ToBox(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- /*if (NativeData.GetType() == typeof(Rectangle)) {
+ /// <summary>
+ /// Box.
+ /// </summary>
+ internal static String ToBox(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ /*if (NativeData.GetType() == typeof(Rectangle)) {
Rectangle R = (Rectangle)NativeData;
return String.Format(CultureInfo.InvariantCulture, "({0},{1}),({2},{3})", R.Left, R.Top, R.Left + R.Width, R.Top + R.Height);
} else if (NativeData.GetType() == typeof(RectangleF)) {
RectangleF R = (RectangleF)NativeData;
return String.Format(CultureInfo.InvariantCulture, "({0},{1}),({2},{3})", R.Left, R.Top, R.Left + R.Width, R.Top + R.Height);*/
+
+ if (NativeData is NpgsqlBox)
+ {
+ NpgsqlBox box = (NpgsqlBox) NativeData;
+ return String.Format(CultureInfo.InvariantCulture, "({0},{1}),({2},{3})", box.LowerLeft.X, box.LowerLeft.Y, box.UpperRight.X, box.UpperRight.Y);
+
+ } else {
+ throw new InvalidCastException("Unable to cast data to Rectangle type");
+ }
+ }
- if (NativeData is NpgsqlBox)
- {
- NpgsqlBox box = (NpgsqlBox)NativeData;
- return
- String.Format(CultureInfo.InvariantCulture, "({0},{1}),({2},{3})", box.LowerLeft.X, box.LowerLeft.Y,
- box.UpperRight.X, box.UpperRight.Y);
- }
- else
- {
- throw new InvalidCastException("Unable to cast data to Rectangle type");
- }
- }
-
- /// <summary>
- /// LSeg.
- /// </summary>
- internal static String ToLSeg(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- NpgsqlLSeg S = (NpgsqlLSeg)NativeData;
- return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", S.Start.X, S.Start.Y, S.End.X, S.End.Y);
- }
-
- /// <summary>
- /// Open path.
- /// </summary>
- internal static String ToPath(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- StringBuilder B = null;
- try
- {
- B =new StringBuilder();
-
- foreach (NpgsqlPoint P in ((NpgsqlPath)NativeData))
- {
- B.AppendFormat(CultureInfo.InvariantCulture, "{0}({1},{2})", (B.Length > 0 ? "," : ""), P.X, P.Y);
- }
-
- return String.Format("[{0}]", B);
- }
- finally
- {
- B = null;
-
- }
-
- }
-
- /// <summary>
- /// Polygon.
- /// </summary>
- internal static String ToPolygon(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- StringBuilder B = new StringBuilder();
-
- foreach (NpgsqlPoint P in ((NpgsqlPolygon)NativeData))
- {
- B.AppendFormat(CultureInfo.InvariantCulture, "{0}({1},{2})", (B.Length > 0 ? "," : ""), P.X, P.Y);
- }
+ /// <summary>
+ /// LSeg.
+ /// </summary>
+ internal static String ToLSeg(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ NpgsqlLSeg S = (NpgsqlLSeg)NativeData;
+ return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", S.Start.X, S.Start.Y, S.End.X, S.End.Y);
+ }
- return String.Format("({0})", B);
- }
+ /// <summary>
+ /// Open path.
+ /// </summary>
+ internal static String ToPath(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ StringBuilder B = new StringBuilder();
- /// <summary>
- /// Circle.
- /// </summary>
- internal static String ToCircle(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- NpgsqlCircle C = (NpgsqlCircle)NativeData;
- return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", C.Center.X, C.Center.Y, C.Radius);
- }
-
- /// <summary>
- /// Convert to a postgres inet.
- /// </summary>
- internal static String ToIPAddress(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- if (NativeData is NpgsqlInet)
- {
- return ((NpgsqlInet)NativeData).ToString();
- }
- return NativeData.ToString();
+ foreach (NpgsqlPoint P in ((NpgsqlPath)NativeData).Points) {
+ B.AppendFormat(CultureInfo.InvariantCulture, "{0}({1},{2})", (B.Length > 0 ? "," : ""), P.X, P.Y);
+ }
- }
+ return String.Format("[{0}]", B.ToString());
+ }
- /// <summary>
- /// Convert to a postgres interval
- /// </summary>
- internal static String ToInterval(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
- {
- return
- ((NativeData is TimeSpan)
- ? ((NpgsqlInterval)(TimeSpan)NativeData).ToString()
- : ((NpgsqlInterval)NativeData).ToString());
- }
+ /// <summary>
+ /// Polygon.
+ /// </summary>
+ internal static String ToPolygon(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ StringBuilder B = new StringBuilder();
- internal static string ToTime(NpgsqlNativeTypeInfo typeInfo, object nativeData)
- {
- if (nativeData is DateTime)
- {
- return BasicNativeToBackendTypeConverter.ToTime(typeInfo, nativeData);
- }
- NpgsqlTime time;
- if (nativeData is TimeSpan)
- {
- time = (NpgsqlTime)(TimeSpan)nativeData;
- }
- else
- {
- time = (NpgsqlTime)nativeData;
- }
- return time.ToString();
- }
+ foreach (NpgsqlPoint P in ((NpgsqlPolygon)NativeData).Points) {
+ B.AppendFormat(CultureInfo.InvariantCulture, "{0}({1},{2})", (B.Length > 0 ? "," : ""), P.X, P.Y);
+ }
- internal static string ToTimeTZ(NpgsqlNativeTypeInfo typeInfo, object nativeData)
- {
- if (nativeData is DateTime)
- {
- return BasicNativeToBackendTypeConverter.ToTime(typeInfo, nativeData);
- }
- NpgsqlTimeTZ time;
- if (nativeData is TimeSpan)
- {
- time = (NpgsqlTimeTZ)(TimeSpan)nativeData;
- }
- else
- {
- time = (NpgsqlTimeTZ)nativeData;
- }
- return time.ToString();
- }
+ return String.Format("({0})", B.ToString());
+ }
- internal static string ToDate(NpgsqlNativeTypeInfo typeInfo, object nativeData)
- {
- if (nativeData is DateTime)
- {
- return BasicNativeToBackendTypeConverter.ToDate(typeInfo, nativeData);
- }
- else
- {
- return nativeData.ToString();
- }
- }
+ /// <summary>
+ /// Circle.
+ /// </summary>
+ internal static String ToCircle(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ NpgsqlCircle C = (NpgsqlCircle)NativeData;
+ return String.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", C.Center.X, C.Center.Y, C.Radius);
+ }
- internal static string ToTimeStamp(NpgsqlNativeTypeInfo typeInfo, object nativeData)
- {
- if (nativeData is DateTime)
- {
- return BasicNativeToBackendTypeConverter.ToDateTime(typeInfo, nativeData);
- }
- else
- {
- return nativeData.ToString();
- }
- }
- }
-} \ No newline at end of file
+ /// <summary>
+ /// Convert to a postgres inet.
+ /// </summary>
+ internal static String ToIPAddress(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
+ {
+ if (NativeData is NpgsqlInet)
+ return ((NpgsqlInet)NativeData).ToString();
+ else
+ return ((System.Net.IPAddress)NativeData).ToString();
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypes.cs b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypes.cs
index 81991b487a5..1eb660f89a7 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypes.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypes.cs
@@ -1,685 +1,276 @@
// NpgsqlTypes.NpgsqlTypesHelper.cs
//
// Author:
-// Glen Parker <glenebob@nwlink.com>
+// Glen Parker <glenebob@nwlink.com>
//
-// Copyright (C) 2004 The Npgsql Development Team
-// npgsql-general@gborg.postgresql.org
-// http://gborg.postgresql.org/project/npgsql/projdisplay.php
+// Copyright (C) 2004 The Npgsql Development Team
+// npgsql-general@gborg.postgresql.org
+// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// This file provides implementations of PostgreSQL specific data types that cannot
// be mapped to standard .NET classes.
using System;
using System.Collections;
-using System.Collections.Generic;
+using System.Globalization;
+using System.Data;
using System.Net;
-using Npgsql;
+using System.Text;
+using System.IO;
+using System.Resources;
namespace NpgsqlTypes
{
+
/// <summary>
/// Represents a PostgreSQL Point type
/// </summary>
- public struct NpgsqlPoint : IEquatable<NpgsqlPoint>
+
+ public struct NpgsqlPoint
{
- private Single _x;
- private Single _y;
+ private Single _X;
+ private Single _Y;
- public NpgsqlPoint(Single x, Single y)
+ public NpgsqlPoint(Single X, Single Y)
{
- _x = x;
- _y = y;
+ _X = X;
+ _Y = Y;
}
-
+
public Single X
{
get
{
- return _x;
+ return _X;
}
-
+
set
{
- _x = value;
+ _X = value;
}
}
-
+
+
public Single Y
{
get
{
- return _y;
+ return _Y;
}
-
+
set
{
- _y = value;
+ _Y = value;
}
}
-
-
- public bool Equals(NpgsqlPoint other)
- {
- return X == other.X && Y == other.Y;
- }
-
- public override bool Equals(object obj)
- {
- return obj != null && obj is NpgsqlPoint && Equals((NpgsqlPoint) obj);
- }
-
- public static bool operator ==(NpgsqlPoint x, NpgsqlPoint y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(NpgsqlPoint x, NpgsqlPoint y)
- {
- return !(x == y);
- }
-
- public override int GetHashCode()
- {
- return X.GetHashCode() ^ PGUtil.RotateShift(Y.GetHashCode(), sizeof (int)/2);
- }
}
- public struct NpgsqlBox : IEquatable<NpgsqlBox>
+ public struct NpgsqlBox
{
-
- private NpgsqlPoint _upperRight;
- private NpgsqlPoint _lowerLeft;
-
- public NpgsqlBox(NpgsqlPoint upperRight, NpgsqlPoint lowerLeft)
- {
- _upperRight = upperRight;
- _lowerLeft = lowerLeft;
- }
+ private NpgsqlPoint _UpperRight;
+ private NpgsqlPoint _LowerLeft;
- public NpgsqlBox(float Top, float Right, float Bottom, float Left)
- : this(new NpgsqlPoint(Right, Top), new NpgsqlPoint(Left, Bottom))
+ public NpgsqlBox(NpgsqlPoint UpperRight, NpgsqlPoint LowerLeft)
{
+ _UpperRight = UpperRight;
+ _LowerLeft = LowerLeft;
}
+
public NpgsqlPoint UpperRight
{
get
{
- return _upperRight;
+ return _UpperRight;
}
-
set
{
- _upperRight = value;
+ _UpperRight = value;
}
-
}
-
+
public NpgsqlPoint LowerLeft
{
get
{
- return _lowerLeft;
+ return _LowerLeft;
}
-
set
{
- _lowerLeft = value;
+ _LowerLeft = value;
}
-
- }
-
- public float Left
- {
- get { return LowerLeft.X; }
- }
-
- public float Right
- {
- get { return UpperRight.X; }
}
- public float Bottom
- {
- get { return LowerLeft.Y; }
- }
-
- public float Top
- {
- get { return UpperRight.Y; }
- }
-
- public float Width
- {
- get { return Right - Left; }
- }
-
- public float Height
- {
- get { return Top - Bottom; }
- }
-
- public bool IsEmpty
- {
- get { return Width == 0 || Height == 0; }
- }
-
- public bool Equals(NpgsqlBox other)
- {
- return UpperRight == other.UpperRight && LowerLeft == other.LowerLeft;
- }
-
- public override bool Equals(object obj)
- {
- return obj != null && obj is NpgsqlBox && Equals((NpgsqlBox) obj);
- }
-
- public static bool operator ==(NpgsqlBox x, NpgsqlBox y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(NpgsqlBox x, NpgsqlBox y)
- {
- return !(x == y);
- }
-
- public override int GetHashCode()
- {
- return
- Top.GetHashCode() ^ PGUtil.RotateShift(Right.GetHashCode(), sizeof (int)/4) ^
- PGUtil.RotateShift(Bottom.GetHashCode(), sizeof (int)/2) ^
- PGUtil.RotateShift(LowerLeft.GetHashCode(), sizeof (int)*3/4);
- }
}
/// <summary>
/// Represents a PostgreSQL Line Segment type.
/// </summary>
- public struct NpgsqlLSeg : IEquatable<NpgsqlLSeg>
+ public struct NpgsqlLSeg
{
- public NpgsqlPoint Start;
- public NpgsqlPoint End;
+ public NpgsqlPoint Start;
+ public NpgsqlPoint End;
- public NpgsqlLSeg(NpgsqlPoint start, NpgsqlPoint end)
+ public NpgsqlLSeg(NpgsqlPoint Start, NpgsqlPoint End)
{
- Start = start;
- End = end;
+ this.Start = Start;
+ this.End = End;
}
public override String ToString()
{
return String.Format("({0}, {1})", Start, End);
}
-
- public override int GetHashCode()
- {
- return
- Start.X.GetHashCode() ^ PGUtil.RotateShift(Start.Y.GetHashCode(), sizeof (int)/4) ^
- PGUtil.RotateShift(End.X.GetHashCode(), sizeof (int)/2) ^ PGUtil.RotateShift(End.Y.GetHashCode(), sizeof (int)*3/4);
- }
-
- public bool Equals(NpgsqlLSeg other)
- {
- return Start == other.Start && End == other.End;
- }
-
- public override bool Equals(object obj)
- {
- return obj != null && obj is NpgsqlLSeg && Equals((NpgsqlLSeg) obj);
- }
-
- public static bool operator ==(NpgsqlLSeg x, NpgsqlLSeg y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(NpgsqlLSeg x, NpgsqlLSeg y)
- {
- return !(x == y);
- }
}
/// <summary>
/// Represents a PostgreSQL Path type.
/// </summary>
- public struct NpgsqlPath : IList<NpgsqlPoint>, IEquatable<NpgsqlPath>
+ public struct NpgsqlPath
{
- private bool _open;
- private readonly List<NpgsqlPoint> _points;
+ internal NpgsqlPoint[] Points;
- public NpgsqlPath(IEnumerable<NpgsqlPoint> points, bool open)
- {
- _points = new List<NpgsqlPoint>(points);
- _open = open;
- }
+ internal Boolean IsOpen;
- public NpgsqlPath(IEnumerable<NpgsqlPoint> points)
- : this(points, false)
- {
- }
-
- public NpgsqlPath(NpgsqlPoint[] points) : this((IEnumerable<NpgsqlPoint>)points, false)
+ public NpgsqlPath(NpgsqlPoint[] Points)
{
+ this.Points = Points;
+ IsOpen = false;
}
- public NpgsqlPath(bool open)
- {
- _points = new List<NpgsqlPoint>();
- _open = open;
- }
+ public Int32 Count
+ { get
+ {
+ return Points.Length;
+ } }
- public NpgsqlPath(int capacity, bool open)
- {
- _points = new List<NpgsqlPoint>(capacity);
- _open = open;
- }
+ public NpgsqlPoint this [Int32 Index]
+ { get
+ {
+ return Points[Index];
+ } }
- public NpgsqlPath(int capacity)
- : this(capacity, false)
- {
- }
-
- public bool Open
+ public Boolean Open
{
get
{
- return _open;
+ return IsOpen;
}
-
- set
- {
- _open = value;
- }
- }
-
- public NpgsqlPoint this[int index]
- {
- get { return _points[index]; }
- set { _points[index] = value; }
- }
-
- public int Count
- {
- get { return _points.Count; }
- }
-
- public bool IsReadOnly
- {
- get { return false; }
- }
-
- public int IndexOf(NpgsqlPoint item)
- {
- return _points.IndexOf(item);
- }
-
- public void Insert(int index, NpgsqlPoint item)
- {
- _points.Insert(index, item);
- }
-
- public void RemoveAt(int index)
- {
- _points.RemoveAt(index);
- }
-
- public void Add(NpgsqlPoint item)
- {
- _points.Add(item);
- }
-
- public void Clear()
- {
- _points.Clear();
- }
-
- public bool Contains(NpgsqlPoint item)
- {
- return _points.Contains(item);
- }
-
- public void CopyTo(NpgsqlPoint[] array, int arrayIndex)
- {
- _points.CopyTo(array, arrayIndex);
- }
-
- public bool Remove(NpgsqlPoint item)
- {
- return _points.Remove(item);
- }
-
- public IEnumerator<NpgsqlPoint> GetEnumerator()
- {
- return _points.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- public bool Equals(NpgsqlPath other)
- {
- if (Open != other.Open || Count != other.Count)
- {
- return false;
- }
- for (int i = 0; i != Count; ++i)
- {
- if (this[i] != other[i])
- {
- return false;
- }
- }
- return true;
- }
-
- public override bool Equals(object obj)
- {
- return obj != null && obj is NpgsqlPath && Equals((NpgsqlPath) obj);
- }
-
- public static bool operator ==(NpgsqlPath x, NpgsqlPath y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(NpgsqlPath x, NpgsqlPath y)
- {
- return !(x == y);
- }
-
- public override int GetHashCode()
- {
- int ret = 0;
- foreach (NpgsqlPoint point in this)
- {
- //The ideal amount to shift each value is one that would evenly spread it throughout
- //the resultant bytes. Using the current result % 32 is essentially using a random value
- //but one that will be the same on subsequent calls.
- ret ^= PGUtil.RotateShift(point.GetHashCode(), ret%sizeof (int));
- }
- return Open ? ret : -ret;
}
}
/// <summary>
/// Represents a PostgreSQL Polygon type.
/// </summary>
- public struct NpgsqlPolygon : IList<NpgsqlPoint>, IEquatable<NpgsqlPolygon>
+ public struct NpgsqlPolygon
{
- private readonly List<NpgsqlPoint> _points;
-
- public NpgsqlPolygon(IEnumerable<NpgsqlPoint> points)
- {
- _points = new List<NpgsqlPoint>(points);
- }
-
- public NpgsqlPolygon(NpgsqlPoint[] points) : this ((IEnumerable<NpgsqlPoint>) points)
- {
- }
-
- public NpgsqlPoint this[int index]
- {
- get { return _points[index]; }
- set { _points[index] = value; }
- }
-
- public int Count
- {
- get { return _points.Count; }
- }
-
- public bool IsReadOnly
- {
- get { return false; }
- }
-
- public int IndexOf(NpgsqlPoint item)
- {
- return _points.IndexOf(item);
- }
-
- public void Insert(int index, NpgsqlPoint item)
- {
- _points.Insert(index, item);
- }
-
- public void RemoveAt(int index)
- {
- _points.RemoveAt(index);
- }
-
- public void Add(NpgsqlPoint item)
- {
- _points.Add(item);
- }
-
- public void Clear()
- {
- _points.Clear();
- }
-
- public bool Contains(NpgsqlPoint item)
- {
- return _points.Contains(item);
- }
-
- public void CopyTo(NpgsqlPoint[] array, int arrayIndex)
- {
- _points.CopyTo(array, arrayIndex);
- }
-
- public bool Remove(NpgsqlPoint item)
- {
- return _points.Remove(item);
- }
-
- public IEnumerator<NpgsqlPoint> GetEnumerator()
- {
- return _points.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- public bool Equals(NpgsqlPolygon other)
- {
- if (Count != other.Count)
- {
- return false;
- }
- for (int i = 0; i != Count; ++i)
- {
- if (this[i] != other[i])
- {
- return false;
- }
- }
- return true;
- }
+ internal NpgsqlPoint[] Points;
- public override bool Equals(object obj)
+ public NpgsqlPolygon(NpgsqlPoint[] Points)
{
- return obj != null && obj is NpgsqlPolygon && Equals((NpgsqlPolygon) obj);
+ this.Points = Points;
}
- public static bool operator ==(NpgsqlPolygon x, NpgsqlPolygon y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(NpgsqlPolygon x, NpgsqlPolygon y)
- {
- return !(x == y);
- }
+ public Int32 Count
+ { get
+ {
+ return Points.Length;
+ } }
- public override int GetHashCode()
- {
- int ret = 0;
- foreach (NpgsqlPoint point in this)
- {
- //The ideal amount to shift each value is one that would evenly spread it throughout
- //the resultant bytes. Using the current result % 32 is essentially using a random value
- //but one that will be the same on subsequent calls.
- ret ^= PGUtil.RotateShift(point.GetHashCode(), ret%sizeof (int));
- }
- return ret;
- }
+ public NpgsqlPoint this [Int32 Index]
+ { get
+ {
+ return Points[Index];
+ } }
}
/// <summary>
/// Represents a PostgreSQL Circle type.
/// </summary>
- public struct NpgsqlCircle : IEquatable<NpgsqlCircle>
+ public struct NpgsqlCircle
{
- public NpgsqlPoint Center;
- public Double Radius;
+ public NpgsqlPoint Center;
+ public Double Radius;
- public NpgsqlCircle(NpgsqlPoint center, Double radius)
+ public NpgsqlCircle(NpgsqlPoint Center, Double Radius)
{
- Center = center;
- Radius = radius;
- }
-
- public bool Equals(NpgsqlCircle other)
- {
- return Center == other.Center && Radius == other.Radius;
- }
-
- public override bool Equals(object obj)
- {
- return obj != null && obj is NpgsqlCircle && Equals((NpgsqlCircle) obj);
+ this.Center = Center;
+ this.Radius = Radius;
}
public override String ToString()
{
return string.Format("({0}), {1}", Center, Radius);
}
-
- public static bool operator ==(NpgsqlCircle x, NpgsqlCircle y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(NpgsqlCircle x, NpgsqlCircle y)
- {
- return !(x == y);
- }
-
- public override int GetHashCode()
- {
- return
- Center.X.GetHashCode() ^ PGUtil.RotateShift(Center.Y.GetHashCode(), sizeof (int)/4) ^
- PGUtil.RotateShift(Radius.GetHashCode(), sizeof (int)/2);
- }
}
- /// <summary>
- /// Represents a PostgreSQL inet type.
- /// </summary>
- public struct NpgsqlInet : IEquatable<NpgsqlInet>
- {
- public IPAddress addr;
- public int mask;
-
- public NpgsqlInet(IPAddress addr, int mask)
- {
- this.addr = addr;
- this.mask = mask;
- }
-
- public NpgsqlInet(IPAddress addr)
- {
- this.addr = addr;
- this.mask = 32;
- }
-
- public NpgsqlInet(string addr)
- {
- if (addr.IndexOf('/') > 0)
- {
- string[] addrbits = addr.Split('/');
- if (addrbits.GetUpperBound(0) != 1)
- {
- throw new FormatException("Invalid number of parts in CIDR specification");
- }
- this.addr = IPAddress.Parse(addrbits[0]);
- this.mask = int.Parse(addrbits[1]);
- }
- else
- {
- this.addr = IPAddress.Parse(addr);
- this.mask = 32;
- }
- }
-
- public override String ToString()
- {
- if (mask != 32)
- {
- return string.Format("{0}/{1}", addr, mask);
- }
- return addr.ToString();
-
- }
-
- public static implicit operator IPAddress(NpgsqlInet x)
- {
- if (x.mask != 32)
- {
- throw new InvalidCastException("Cannot cast CIDR network to address");
- }
- return x.addr;
-
- }
-
- public bool Equals(NpgsqlInet other)
- {
- return addr.Equals(other.addr) && mask == other.mask;
- }
-
- public override bool Equals(object obj)
- {
- return obj != null && obj is NpgsqlInet && Equals((NpgsqlInet) obj);
- }
-
- public override int GetHashCode()
- {
- return PGUtil.RotateShift(addr.GetHashCode(), mask%32);
- }
-
- public static bool operator ==(NpgsqlInet x, NpgsqlInet y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(NpgsqlInet x, NpgsqlInet y)
- {
- return !(x == y);
- }
- }
-} \ No newline at end of file
+ /// <summary>
+ /// Represents a PostgreSQL inet type.
+ /// </summary>
+ public struct NpgsqlInet
+ {
+ public IPAddress addr;
+ public int mask;
+
+ public NpgsqlInet(IPAddress addr, int mask)
+ {
+ this.addr = addr;
+ this.mask = mask;
+ }
+
+ public NpgsqlInet(IPAddress addr)
+ {
+ this.addr = addr;
+ this.mask = 32;
+ }
+
+ public NpgsqlInet(string addr)
+ {
+ if (addr.IndexOf('/') > 0)
+ {
+ string[] addrbits = addr.Split('/');
+ if (addrbits.GetUpperBound(0) != 1)
+ throw new FormatException("Invalid number of parts in CIDR specification");
+ this.addr = IPAddress.Parse(addrbits[0]);
+ this.mask = int.Parse(addrbits[1]);
+ }
+ else
+ {
+ this.addr = IPAddress.Parse(addr);
+ this.mask = 32;
+ }
+ }
+
+ public override String ToString()
+ {
+ if (mask != 32)
+ return string.Format("{0}/{1}", addr.ToString(), mask);
+ else
+ return addr.ToString();
+ }
+
+ public static implicit operator IPAddress(NpgsqlInet x)
+ {
+ if (x.mask != 32)
+ throw new InvalidCastException("Cannot cast CIDR network to address");
+ else
+ return x.addr;
+ }
+ }
+}
diff --git a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
index 290ae6cdbca..3c25d5d4670 100644
--- a/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
+++ b/mcs/class/Npgsql/NpgsqlTypes/NpgsqlTypesHelper.cs
@@ -7,199 +7,107 @@
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
-// Permission to use, copy, modify, and distribute this software and its
-// documentation for any purpose, without fee, and without a written
-// agreement is hereby granted, provided that the above copyright notice
-// and this paragraph and the following two paragraphs appear in all copies.
-//
-// IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY
-// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
-// INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
-// DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF
-// THE POSSIBILITY OF SUCH DAMAGE.
-//
-// THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
-// ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS
-// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
-using System.Collections.Generic;
-using System.Data;
+using System.Collections;
using System.Globalization;
+using System.Data;
using System.Net;
-using System.Resources;
using System.Text;
+using System.Resources;
using Npgsql;
+
namespace NpgsqlTypes
{
- /// <summary>
- /// This class contains helper methods for type conversion between
- /// the .Net type system and postgresql.
- /// </summary>
- internal abstract class NpgsqlTypesHelper
- {
- // Logging related values
- private static readonly String CLASSNAME = "NpgsqlTypesHelper";
- private static ResourceManager resman = new ResourceManager(typeof (NpgsqlTypesHelper));
-
- private struct MappingKey : IEquatable<MappingKey>
- {
- public readonly Version Version;
- public readonly bool UseExtendedTypes;
-
- public MappingKey(Version version, bool useExtendedTypes)
- {
- this.Version = version;
- this.UseExtendedTypes = useExtendedTypes;
- }
-
- public bool Equals(MappingKey other)
- {
- return UseExtendedTypes.Equals(other.UseExtendedTypes) && Version.Equals(other.Version);
- }
-
- public override bool Equals(object obj)
- {
- //Note that Dictionary<T, U> will call IEquatable<T>.Equals() when possible.
- //This is included for completeness (that and second-guessing Mono while coding on .NET!).
- return obj != null && obj is MappingKey && Equals((MappingKey) obj);
- }
-
- public override int GetHashCode()
- {
- return UseExtendedTypes ? ~Version.GetHashCode() : Version.GetHashCode();
- }
- }
-
- /// <summary>
- /// A cache of basic datatype mappings keyed by server version. This way we don't
- /// have to load the basic type mappings for every connection.
- /// </summary>
- private static readonly Dictionary<MappingKey, NpgsqlBackendTypeMapping> BackendTypeMappingCache =
- new Dictionary<MappingKey, NpgsqlBackendTypeMapping>();
-
- private static readonly NpgsqlNativeTypeMapping NativeTypeMapping = PrepareDefaultTypesMap();
-
-
- /// <summary>
- /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
- /// of the given NpgsqlDbType.
- /// </summary>
- public static bool TryGetNativeTypeInfo(NpgsqlDbType dbType, out NpgsqlNativeTypeInfo typeInfo)
- {
- return NativeTypeMapping.TryGetValue(dbType, out typeInfo);
- }
-
- /// <summary>
- /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
- /// of the given DbType.
- /// </summary>
- public static bool TryGetNativeTypeInfo(DbType dbType, out NpgsqlNativeTypeInfo typeInfo)
- {
- return NativeTypeMapping.TryGetValue(dbType, out typeInfo);
- }
-
- public static NpgsqlNativeTypeInfo GetNativeTypeInfo(DbType DbType)
- {
- NpgsqlNativeTypeInfo ret = null;
- return TryGetNativeTypeInfo(DbType, out ret) ? ret : null;
- }
-
- private static bool TestTypedEnumerator(Type type, out Type typeOut)
- {
- if (type.IsArray)
- {
- typeOut = type.GetElementType();
- return true;
- }
- //We can only work out the element type for IEnumerable<T> not for IEnumerable
- //so we are looking for IEnumerable<T> for any value of T.
- //So we want to find an interface type where GetGenericTypeDefinition == typeof(IEnumerable<>);
- //And we can only safely call GetGenericTypeDefinition() if IsGenericType is true, but if it's false
- //then the interface clearly isn't an IEnumerable<T>.
- foreach (Type iface in type.GetInterfaces())
- {
- if (iface.IsGenericType && iface.GetGenericTypeDefinition().Equals(typeof (IEnumerable<>)))
- {
- typeOut = iface.GetGenericArguments()[0];
- return true;
- }
- }
- typeOut = null;
- return false;
- }
-
-
- /// <summary>
- /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
- /// of the given System.Type.
- /// </summary>
- public static bool TryGetNativeTypeInfo(Type type, out NpgsqlNativeTypeInfo typeInfo)
- {
- if (NativeTypeMapping.TryGetValue(type, out typeInfo))
- {
- return true;
- }
- // At this point there is no direct mapping, so we see if we have an array or IEnumerable<T>.
- // Note that we checked for a direct mapping first, so if there is a direct mapping of a class
- // which implements IEnumerable<T> we will use that (currently this is only string, which
- // implements IEnumerable<char>.
-
- Type elementType = null;
- NpgsqlNativeTypeInfo elementTypeInfo = null;
- if (TestTypedEnumerator(type, out elementType) && TryGetNativeTypeInfo(elementType, out elementTypeInfo))
- {
- typeInfo = NpgsqlNativeTypeInfo.ArrayOf(elementTypeInfo);
- return true;
- }
- return false;
- }
-
- public static NpgsqlNativeTypeInfo GetNativeTypeInfo(Type Type)
- {
- NpgsqlNativeTypeInfo ret = null;
- return TryGetNativeTypeInfo(Type, out ret) ? ret : null;
- }
-
-
- public static bool DefinedType(Type type)
-
- {
- return NativeTypeMapping.ContainsType(type);
- }
-
-
- public static bool DefinedType(object item)
-
- {
- return DefinedType(item.GetType());
- }
-
- // CHECKME
- // Not sure what to do with this one. I don't believe we ever ask for a binary
- // formatting, so this shouldn't even be used right now.
- // At some point this will need to be merged into the type converter system somehow?
- public static Object ConvertBackendBytesToSystemType(NpgsqlBackendTypeInfo TypeInfo, Byte[] data, Int32 fieldValueSize,
- Int32 typeModifier)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ConvertBackendBytesToStytemType");
-
-
- // We are never guaranteed to know about every possible data type the server can send us.
- // When we encounter an unknown type, we punt and return the data without modification.
- if (TypeInfo == null)
- {
- return data;
- }
-
- switch (TypeInfo.NpgsqlDbType)
- {
- case NpgsqlDbType.Bytea:
- return data;
- /*case NpgsqlDbType.Boolean:
+ /// <summary>
+ /// This class contains helper methods for type conversion between
+ /// the .Net type system and postgresql.
+ /// </summary>
+ internal abstract class NpgsqlTypesHelper
+ {
+ // Logging related values
+ private static readonly String CLASSNAME = "NpgsqlTypesHelper";
+ private static ResourceManager resman = new ResourceManager(typeof(NpgsqlTypesHelper));
+
+ /// <summary>
+ /// A cache of basic datatype mappings keyed by server version. This way we don't
+ /// have to load the basic type mappings for every connection.
+ /// </summary>
+ private static Hashtable BackendTypeMappingCache = new Hashtable();
+ private static NpgsqlNativeTypeMapping NativeTypeMapping = null;
+
+
+ /// <summary>
+ /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
+ /// of the given NpgsqlDbType.
+ /// </summary>
+ public static NpgsqlNativeTypeInfo GetNativeTypeInfo(NpgsqlDbType NpgsqlDbType)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBackendTypeNameFromNpgsqlDbType");
+
+ VerifyDefaultTypesMap();
+ return NativeTypeMapping[NpgsqlDbType];
+ }
+
+ /// <summary>
+ /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
+ /// of the given DbType.
+ /// </summary>
+ public static NpgsqlNativeTypeInfo GetNativeTypeInfo(DbType DbType)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBackendTypeNameFromNpgsqlDbType");
+
+ VerifyDefaultTypesMap();
+ return NativeTypeMapping[DbType];
+ }
+
+
+
+ /// <summary>
+ /// Find a NpgsqlNativeTypeInfo in the default types map that can handle objects
+ /// of the given System.Type.
+ /// </summary>
+ public static NpgsqlNativeTypeInfo GetNativeTypeInfo(Type Type)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBackendTypeNameFromNpgsqlDbType");
+
+ VerifyDefaultTypesMap();
+ return NativeTypeMapping[Type];
+ }
+
+ // CHECKME
+ // Not sure what to do with this one. I don't believe we ever ask for a binary
+ // formatting, so this shouldn't even be used right now.
+ // At some point this will need to be merged into the type converter system somehow?
+ public static Object ConvertBackendBytesToSystemType(NpgsqlBackendTypeInfo TypeInfo, Byte[] data, Encoding encoding, Int32 fieldValueSize, Int32 typeModifier)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ConvertBackendBytesToStytemType");
+
+
+ // We are never guaranteed to know about every possible data type the server can send us.
+ // When we encounter an unknown type, we punt and return the data without modification.
+ if (TypeInfo == null)
+ return data;
+
+ switch (TypeInfo.NpgsqlDbType)
+ {
+ case NpgsqlDbType.Bytea:
+ return data;
+ /*case NpgsqlDbType.Boolean:
return BitConverter.ToBoolean(data, 0);
case NpgsqlDbType.DateTime:
return DateTime.MinValue.AddTicks(IPAddress.NetworkToHostOrder(BitConverter.ToInt64(data, 0)));
@@ -214,1031 +122,861 @@ namespace NpgsqlTypes
case NpgsqlDbType.AnsiString:
case NpgsqlDbType.StringFixedLength:
return encoding.GetString(data, 0, fieldValueSize);*/
- default:
- throw new InvalidCastException("Type not supported in binary format");
- }
- }
-
- ///<summary>
- /// This method is responsible to convert the string received from the backend
- /// to the corresponding NpgsqlType.
- /// The given TypeInfo is called upon to do the conversion.
- /// If no TypeInfo object is provided, no conversion is performed.
- /// </summary>
- public static Object ConvertBackendStringToSystemType(NpgsqlBackendTypeInfo TypeInfo, String data, Int16 typeSize,
- Int32 typeModifier)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ConvertBackendStringToSystemType");
-
- if (TypeInfo != null)
- {
- return TypeInfo.ConvertToNative(data, typeSize, typeModifier);
- }
- else
- {
- return data;
- }
- }
-
- /// <summary>
- /// Create the one and only native to backend type map.
- /// This map is used when formatting native data
- /// types to backend representations.
- /// </summary>
- private static NpgsqlNativeTypeMapping PrepareDefaultTypesMap()
- {
- NpgsqlNativeTypeMapping nativeTypeMapping = new NpgsqlNativeTypeMapping();
-
-
- nativeTypeMapping.AddType("oidvector", NpgsqlDbType.Oidvector, DbType.String, true, null);
-
- // Conflicting types should have mapped first the non default mappings.
- // For example, char, varchar and text map to DbType.String. As the most
- // common is to use text with string, it has to be the last mapped, in order
- // to type mapping has the last entry, in this case, text, as the map value
- // for DbType.String.
-
- nativeTypeMapping.AddType("refcursor", NpgsqlDbType.Refcursor, DbType.String, true, null);
-
- nativeTypeMapping.AddType("char", NpgsqlDbType.Char, DbType.String, true, null);
-
- nativeTypeMapping.AddTypeAlias("char", typeof (Char));
-
- nativeTypeMapping.AddType("varchar", NpgsqlDbType.Varchar, DbType.String, true, null);
-
- nativeTypeMapping.AddType("text", NpgsqlDbType.Text, DbType.String, true, null);
-
- nativeTypeMapping.AddDbTypeAlias("text", DbType.StringFixedLength);
- nativeTypeMapping.AddDbTypeAlias("text", DbType.AnsiString);
- nativeTypeMapping.AddDbTypeAlias("text", DbType.AnsiStringFixedLength);
-
- nativeTypeMapping.AddTypeAlias("text", typeof (String));
-
-
- nativeTypeMapping.AddType("bytea", NpgsqlDbType.Bytea, DbType.Binary, true,
- new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBinary));
-
- nativeTypeMapping.AddTypeAlias("bytea", typeof (Byte[]));
-
- nativeTypeMapping.AddType("bit", NpgsqlDbType.Bit, DbType.Boolean, false,
- new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBit));
-
- nativeTypeMapping.AddType("bool", NpgsqlDbType.Boolean, DbType.Boolean, false,
- new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBoolean));
-
- nativeTypeMapping.AddTypeAlias("bool", typeof (Boolean));
-
- nativeTypeMapping.AddType("int2", NpgsqlDbType.Smallint, DbType.Int16, false, null);
-
- nativeTypeMapping.AddTypeAlias("int2", typeof (Int16));
-
- nativeTypeMapping.AddDbTypeAlias("int2", DbType.Byte);
+ default:
+ throw new InvalidCastException("Type not supported in binary format");
+ }
+
+ return null;
+ }
+
+ ///<summary>
+ /// This method is responsible to convert the string received from the backend
+ /// to the corresponding NpgsqlType.
+ /// The given TypeInfo is called upon to do the conversion.
+ /// If no TypeInfo object is provided, no conversion is performed.
+ /// </summary>
+ public static Object ConvertBackendStringToSystemType(NpgsqlBackendTypeInfo TypeInfo, String data, Int16 typeSize, Int32 typeModifier)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ConvertBackendStringToSystemType");
+
+ if (TypeInfo != null) {
+ return TypeInfo.ConvertToNative(data, typeSize, typeModifier);
+ } else {
+ return data;
+ }
+ }
+
+ /// <summary>
+ /// Create the one and only native to backend type map.
+ /// This map is used when formatting native data
+ /// types to backend representations.
+ /// </summary>
+ private static void VerifyDefaultTypesMap()
+ {
+ lock(CLASSNAME) {
+ if (NativeTypeMapping != null) {
+ return;
+ }
+
+ NativeTypeMapping = new NpgsqlNativeTypeMapping();
+
+
+ // Conflicting types should have mapped first the non default mappings.
+ // For example, char, varchar and text map to DbType.String. As the most
+ // common is to use text with string, it has to be the last mapped, in order
+ // to type mapping has the last entry, in this case, text, as the map value
+ // for DbType.String.
+
+ NativeTypeMapping.AddType("refcursor", NpgsqlDbType.Refcursor, DbType.String, true, null);
+
+ NativeTypeMapping.AddType("char", NpgsqlDbType.Char, DbType.String, true, null);
+
+ NativeTypeMapping.AddType("varchar", NpgsqlDbType.Varchar, DbType.String, true, null);
- nativeTypeMapping.AddTypeAlias("int2", typeof (Byte));
+ NativeTypeMapping.AddType("text", NpgsqlDbType.Text, DbType.String, true, null);
- nativeTypeMapping.AddType("int4", NpgsqlDbType.Integer, DbType.Int32, false, null);
+ NativeTypeMapping.AddDbTypeAlias("text", DbType.StringFixedLength);
+ NativeTypeMapping.AddDbTypeAlias("text", DbType.AnsiString);
+ NativeTypeMapping.AddDbTypeAlias("text", DbType.AnsiStringFixedLength);
+ NativeTypeMapping.AddTypeAlias("text", typeof(String));
- nativeTypeMapping.AddTypeAlias("int4", typeof (Int32));
+
+ NativeTypeMapping.AddType("bytea", NpgsqlDbType.Bytea, DbType.Binary, true,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBinary));
- nativeTypeMapping.AddType("int8", NpgsqlDbType.Bigint, DbType.Int64, false, null);
+ NativeTypeMapping.AddTypeAlias("bytea", typeof(Byte[]));
+
+ NativeTypeMapping.AddType("bit", NpgsqlDbType.Bit, DbType.Boolean, true,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBit));
+
+ NativeTypeMapping.AddType("bool", NpgsqlDbType.Boolean, DbType.Boolean, false,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToBoolean));
+
+ NativeTypeMapping.AddTypeAlias("bool", typeof(Boolean));
+
+ NativeTypeMapping.AddType("int2", NpgsqlDbType.Smallint, DbType.Int16, false,
+ null);
+
+ NativeTypeMapping.AddTypeAlias("int2", typeof(Int16));
+
+ NativeTypeMapping.AddDbTypeAlias("int2", DbType.Byte);
+
+ NativeTypeMapping.AddTypeAlias("int2", typeof(Byte));
+
+ NativeTypeMapping.AddType("int4", NpgsqlDbType.Integer, DbType.Int32, false,
+ null);
+
+ NativeTypeMapping.AddTypeAlias("int4", typeof(Int32));
+
+ NativeTypeMapping.AddType("int8", NpgsqlDbType.Bigint, DbType.Int64, false,
+ null);
+
+ NativeTypeMapping.AddTypeAlias("int8", typeof(Int64));
+
+ NativeTypeMapping.AddType("float4", NpgsqlDbType.Real, DbType.Single, true,
+ null);
+
+ NativeTypeMapping.AddTypeAlias("float4", typeof(Single));
+
+ NativeTypeMapping.AddType("float8", NpgsqlDbType.Double, DbType.Double, true,
+ null);
+
+ NativeTypeMapping.AddTypeAlias("float8", typeof(Double));
+
+ NativeTypeMapping.AddType("numeric", NpgsqlDbType.Numeric, DbType.Decimal, false,
+ null);
+
+ NativeTypeMapping.AddTypeAlias("numeric", typeof(Decimal));
+
+ NativeTypeMapping.AddType("currency", NpgsqlDbType.Money, DbType.Currency, true,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToMoney));
+
+ NativeTypeMapping.AddType("date", NpgsqlDbType.Date, DbType.Date, true,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToDate));
+
+ NativeTypeMapping.AddType("time", NpgsqlDbType.Time, DbType.Time, true,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToTime));
+
+ NativeTypeMapping.AddType("timestamp", NpgsqlDbType.Timestamp, DbType.DateTime, true,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToDateTime));
+
+ NativeTypeMapping.AddTypeAlias("timestamp", typeof(DateTime));
+
+ NativeTypeMapping.AddType("timestamptz", NpgsqlDbType.TimestampTZ, DbType.DateTime, true,
+ new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToDateTime));
- nativeTypeMapping.AddTypeAlias("int8", typeof (Int64));
+ NativeTypeMapping.AddType("point", NpgsqlDbType.Point, DbType.Object, true,
+ new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPoint));
- nativeTypeMapping.AddType("float4", NpgsqlDbType.Real, DbType.Single, true, null);
+ NativeTypeMapping.AddTypeAlias("point", typeof(NpgsqlPoint));
+
+ NativeTypeMapping.AddType("box", NpgsqlDbType.Box, DbType.Object, true,
+ new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToBox));
- nativeTypeMapping.AddTypeAlias("float4", typeof (Single));
+ NativeTypeMapping.AddTypeAlias("box", typeof(NpgsqlBox));
+
+ NativeTypeMapping.AddType("lseg", NpgsqlDbType.LSeg, DbType.Object, true,
+ new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToLSeg));
- nativeTypeMapping.AddType("float8", NpgsqlDbType.Double, DbType.Double, true, null);
+ NativeTypeMapping.AddTypeAlias("lseg", typeof(NpgsqlLSeg));
- nativeTypeMapping.AddTypeAlias("float8", typeof (Double));
+ NativeTypeMapping.AddType("path", NpgsqlDbType.Path, DbType.Object, true,
+ new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPath));
- nativeTypeMapping.AddType("numeric", NpgsqlDbType.Numeric, DbType.Decimal, true, null);
+ NativeTypeMapping.AddTypeAlias("path", typeof(NpgsqlPath));
- nativeTypeMapping.AddTypeAlias("numeric", typeof (Decimal));
+ NativeTypeMapping.AddType("polygon", NpgsqlDbType.Polygon, DbType.Object, true,
+ new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPolygon));
- nativeTypeMapping.AddType("money", NpgsqlDbType.Money, DbType.Currency, true,
- new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToMoney));
+ NativeTypeMapping.AddTypeAlias("polygon", typeof(NpgsqlPolygon));
- nativeTypeMapping.AddType("date", NpgsqlDbType.Date, DbType.Date, true,
- new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToDate));
+ NativeTypeMapping.AddType("circle", NpgsqlDbType.Circle, DbType.Object, true,
+ new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToCircle));
- nativeTypeMapping.AddTypeAlias("date", typeof (NpgsqlDate));
+ NativeTypeMapping.AddTypeAlias("circle", typeof(NpgsqlCircle));
- nativeTypeMapping.AddType("timetz", NpgsqlDbType.TimeTZ, DbType.Time, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToTimeTZ));
+ NativeTypeMapping.AddType("inet", NpgsqlDbType.Inet, DbType.Object, true,
+ new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToIPAddress));
- nativeTypeMapping.AddTypeAlias("timetz", typeof (NpgsqlTimeTZ));
+ NativeTypeMapping.AddTypeAlias("inet", typeof(IPAddress));
+ NativeTypeMapping.AddTypeAlias("inet", typeof(NpgsqlInet));
+ }
+ }
- nativeTypeMapping.AddType("time", NpgsqlDbType.Time, DbType.Time, true,
- new ConvertNativeToBackendHandler(BasicNativeToBackendTypeConverter.ToTime));
+ ///<summary>
+ /// This method creates (or retrieves from cache) a mapping between type and OID
+ /// of all natively supported postgresql data types.
+ /// This is needed as from one version to another, this mapping can be changed and
+ /// so we avoid hardcoding them.
+ /// </summary>
+ /// <returns>NpgsqlTypeMapping containing all known data types. The mapping must be
+ /// cloned before it is modified because it is cached; changes made by one connection may
+ /// effect another connection.</returns>
+ public static NpgsqlBackendTypeMapping CreateAndLoadInitialTypesMapping(NpgsqlConnector conn)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "LoadTypesMapping");
- nativeTypeMapping.AddTypeAlias("time", typeof (NpgsqlTime));
+ // [TODO] Verify another way to get higher concurrency.
+ lock(CLASSNAME)
+ {
+ // Check the cache for an initial types map.
+ NpgsqlBackendTypeMapping oidToNameMapping = (NpgsqlBackendTypeMapping) BackendTypeMappingCache[conn.ServerVersion];
- nativeTypeMapping.AddType("timestamp", NpgsqlDbType.Timestamp, DbType.DateTime, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToTimeStamp));
+ if (oidToNameMapping != null)
+ {
+ return oidToNameMapping;
+ }
- nativeTypeMapping.AddTypeAlias("timestamp", typeof (DateTime));
- nativeTypeMapping.AddTypeAlias("timestamp", typeof (NpgsqlTimeStamp));
+ // Not in cache, create a new one.
+ oidToNameMapping = new NpgsqlBackendTypeMapping();
- nativeTypeMapping.AddType("timestamptz", NpgsqlDbType.TimestampTZ, DbType.DateTime, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToTimeStamp));
+ // Create a list of all natively supported postgresql data types.
+ NpgsqlBackendTypeInfo[] TypeInfoList = new NpgsqlBackendTypeInfo[]
+ {
+ new NpgsqlBackendTypeInfo(0, "unknown", NpgsqlDbType.Text, DbType.String, typeof(String),
+ null),
- nativeTypeMapping.AddTypeAlias("timestamptz", typeof (NpgsqlTimeStampTZ));
-
- nativeTypeMapping.AddType("point", NpgsqlDbType.Point, DbType.Object, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPoint));
-
- nativeTypeMapping.AddTypeAlias("point", typeof (NpgsqlPoint));
-
- nativeTypeMapping.AddType("box", NpgsqlDbType.Box, DbType.Object, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToBox));
-
- nativeTypeMapping.AddTypeAlias("box", typeof (NpgsqlBox));
-
- nativeTypeMapping.AddType("lseg", NpgsqlDbType.LSeg, DbType.Object, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToLSeg));
-
- nativeTypeMapping.AddTypeAlias("lseg", typeof (NpgsqlLSeg));
-
- nativeTypeMapping.AddType("path", NpgsqlDbType.Path, DbType.Object, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPath));
-
- nativeTypeMapping.AddTypeAlias("path", typeof (NpgsqlPath));
-
- nativeTypeMapping.AddType("polygon", NpgsqlDbType.Polygon, DbType.Object, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToPolygon));
-
- nativeTypeMapping.AddTypeAlias("polygon", typeof (NpgsqlPolygon));
-
- nativeTypeMapping.AddType("circle", NpgsqlDbType.Circle, DbType.Object, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToCircle));
-
- nativeTypeMapping.AddTypeAlias("circle", typeof (NpgsqlCircle));
-
- nativeTypeMapping.AddType("inet", NpgsqlDbType.Inet, DbType.Object, true,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToIPAddress));
-
- nativeTypeMapping.AddTypeAlias("inet", typeof (IPAddress));
- nativeTypeMapping.AddTypeAlias("inet", typeof (NpgsqlInet));
-
- nativeTypeMapping.AddType("uuid", NpgsqlDbType.Uuid, DbType.Guid, true, null);
- nativeTypeMapping.AddTypeAlias("uuid", typeof (Guid));
-
- nativeTypeMapping.AddType("xml", NpgsqlDbType.Xml, DbType.Xml, true, null);
-
- nativeTypeMapping.AddType("interval", NpgsqlDbType.Interval, DbType.Object, false,
- new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToInterval));
-
- nativeTypeMapping.AddTypeAlias("interval", typeof (NpgsqlInterval));
- nativeTypeMapping.AddTypeAlias("interval", typeof (TimeSpan));
-
- nativeTypeMapping.AddDbTypeAlias("text", DbType.Object);
+ new NpgsqlBackendTypeInfo(0, "refcursor", NpgsqlDbType.Refcursor, DbType.String, typeof(String),
+ null),
-
- return nativeTypeMapping;
- }
+ new NpgsqlBackendTypeInfo(0, "char", NpgsqlDbType.Char, DbType.String, typeof(String),
+ null),
+
+ new NpgsqlBackendTypeInfo(0, "bpchar", NpgsqlDbType.Text, DbType.String, typeof(String),
+ null),
- private static IEnumerable<NpgsqlBackendTypeInfo> TypeInfoList(bool useExtendedTypes)
- {
- yield return new NpgsqlBackendTypeInfo(0, "oidvector", NpgsqlDbType.Text, DbType.String, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "varchar", NpgsqlDbType.Varchar, DbType.String, typeof(String),
+ null),
- yield return new NpgsqlBackendTypeInfo(0, "unknown", NpgsqlDbType.Text, DbType.String, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "text", NpgsqlDbType.Text, DbType.String, typeof(String),
+ null),
+
+ new NpgsqlBackendTypeInfo(0, "name", NpgsqlDbType.Text, DbType.String, typeof(String),
+ null),
- yield return new NpgsqlBackendTypeInfo(0, "refcursor", NpgsqlDbType.Refcursor, DbType.String, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "bytea", NpgsqlDbType.Bytea, DbType.Binary, typeof(Byte[]),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBinary)),
- yield return new NpgsqlBackendTypeInfo(0, "char", NpgsqlDbType.Char, DbType.String, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "bit", NpgsqlDbType.Bit, DbType.Boolean, typeof(Boolean),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBit)),
- yield return new NpgsqlBackendTypeInfo(0, "bpchar", NpgsqlDbType.Text, DbType.String, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "bool", NpgsqlDbType.Boolean, DbType.Boolean, typeof(Boolean),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBoolean)),
- yield return new NpgsqlBackendTypeInfo(0, "varchar", NpgsqlDbType.Varchar, DbType.String, typeof (String), null);
- yield return new NpgsqlBackendTypeInfo(0, "text", NpgsqlDbType.Text, DbType.String, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "int2", NpgsqlDbType.Smallint, DbType.Int16, typeof(Int16),
+ null),
- yield return new NpgsqlBackendTypeInfo(0, "name", NpgsqlDbType.Text, DbType.String, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "int4", NpgsqlDbType.Integer, DbType.Int32, typeof(Int32),
+ null),
- yield return
- new NpgsqlBackendTypeInfo(0, "bytea", NpgsqlDbType.Bytea, DbType.Binary, typeof (Byte[]),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBinary));
+ new NpgsqlBackendTypeInfo(0, "int8", NpgsqlDbType.Bigint, DbType.Int64, typeof(Int64),
+ null),
- yield return
- new NpgsqlBackendTypeInfo(0, "bit", NpgsqlDbType.Bit, DbType.Boolean, typeof (Boolean),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBit));
+ new NpgsqlBackendTypeInfo(0, "oid", NpgsqlDbType.Bigint, DbType.Int64, typeof(Int64),
+ null),
- yield return
- new NpgsqlBackendTypeInfo(0, "bool", NpgsqlDbType.Boolean, DbType.Boolean, typeof (Boolean),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToBoolean));
- yield return new NpgsqlBackendTypeInfo(0, "int2", NpgsqlDbType.Smallint, DbType.Int16, typeof (Int16), null);
+ new NpgsqlBackendTypeInfo(0, "float4", NpgsqlDbType.Real, DbType.Single, typeof(Single),
+ null),
- yield return new NpgsqlBackendTypeInfo(0, "int4", NpgsqlDbType.Integer, DbType.Int32, typeof (Int32), null);
+ new NpgsqlBackendTypeInfo(0, "float8", NpgsqlDbType.Double, DbType.Double, typeof(Double),
+ null),
- yield return new NpgsqlBackendTypeInfo(0, "int8", NpgsqlDbType.Bigint, DbType.Int64, typeof (Int64), null);
+ new NpgsqlBackendTypeInfo(0, "numeric", NpgsqlDbType.Numeric, DbType.Decimal, typeof(Decimal),
+ null),
- yield return new NpgsqlBackendTypeInfo(0, "oid", NpgsqlDbType.Bigint, DbType.Int64, typeof (Int64), null);
+ new NpgsqlBackendTypeInfo(0, "inet", NpgsqlDbType.Inet, DbType.Object, typeof(NpgsqlInet), new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToInet)),
- yield return new NpgsqlBackendTypeInfo(0, "float4", NpgsqlDbType.Real, DbType.Single, typeof (Single), null);
+ new NpgsqlBackendTypeInfo(0, "money", NpgsqlDbType.Money, DbType.Decimal, typeof(Decimal),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToMoney)),
- yield return new NpgsqlBackendTypeInfo(0, "float8", NpgsqlDbType.Double, DbType.Double, typeof (Double), null);
- yield return new NpgsqlBackendTypeInfo(0, "numeric", NpgsqlDbType.Numeric, DbType.Decimal, typeof (Decimal), null);
+ new NpgsqlBackendTypeInfo(0, "date", NpgsqlDbType.Date, DbType.Date, typeof(DateTime),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDate)),
- yield return
- new NpgsqlBackendTypeInfo(0, "inet", NpgsqlDbType.Inet, DbType.Object, typeof (NpgsqlInet),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToInet));
+ new NpgsqlBackendTypeInfo(0, "time", NpgsqlDbType.Time, DbType.Time, typeof(DateTime),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToTime)),
- yield return
- new NpgsqlBackendTypeInfo(0, "money", NpgsqlDbType.Money, DbType.Currency, typeof (Decimal),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToMoney));
+ new NpgsqlBackendTypeInfo(0, "timetz", NpgsqlDbType.Time, DbType.Time, typeof(DateTime),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToTime)),
- yield return
- new NpgsqlBackendTypeInfo(0, "point", NpgsqlDbType.Point, DbType.Object, typeof (NpgsqlPoint),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPoint));
+ new NpgsqlBackendTypeInfo(0, "timestamp", NpgsqlDbType.Timestamp, DbType.DateTime, typeof(DateTime),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDateTime)),
- yield return
- new NpgsqlBackendTypeInfo(0, "lseg", NpgsqlDbType.LSeg, DbType.Object, typeof (NpgsqlLSeg),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToLSeg));
+ new NpgsqlBackendTypeInfo(0, "timestamptz", NpgsqlDbType.Timestamp, DbType.DateTime, typeof(DateTime),
+ new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDateTime)),
- yield return
- new NpgsqlBackendTypeInfo(0, "path", NpgsqlDbType.Path, DbType.Object, typeof (NpgsqlPath),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPath));
- yield return
- new NpgsqlBackendTypeInfo(0, "box", NpgsqlDbType.Box, DbType.Object, typeof (NpgsqlBox),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToBox));
+ new NpgsqlBackendTypeInfo(0, "point", NpgsqlDbType.Point, DbType.Object, typeof(NpgsqlPoint),
+ new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPoint)),
- yield return
- new NpgsqlBackendTypeInfo(0, "circle", NpgsqlDbType.Circle, DbType.Object, typeof (NpgsqlCircle),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToCircle));
+ new NpgsqlBackendTypeInfo(0, "lseg", NpgsqlDbType.LSeg, DbType.Object, typeof(NpgsqlLSeg),
+ new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToLSeg)),
- yield return
- new NpgsqlBackendTypeInfo(0, "polygon", NpgsqlDbType.Polygon, DbType.Object, typeof (NpgsqlPolygon),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPolygon));
+ new NpgsqlBackendTypeInfo(0, "path", NpgsqlDbType.Path, DbType.Object, typeof(NpgsqlPath),
+ new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPath)),
- yield return new NpgsqlBackendTypeInfo(0, "uuid", NpgsqlDbType.Uuid, DbType.Guid, typeof (Guid), new
-ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToGuid));
+ new NpgsqlBackendTypeInfo(0, "box", NpgsqlDbType.Box, DbType.Object, typeof(NpgsqlBox),
+ new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToBox)),
- yield return new NpgsqlBackendTypeInfo(0, "xml", NpgsqlDbType.Xml, DbType.Xml, typeof (String), null);
+ new NpgsqlBackendTypeInfo(0, "circle", NpgsqlDbType.Circle, DbType.Object, typeof(NpgsqlCircle),
+ new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToCircle)),
- yield return
- new NpgsqlBackendTypeInfo(0, "interval", NpgsqlDbType.Interval, DbType.Object, typeof (NpgsqlInterval),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToInterval));
+ new NpgsqlBackendTypeInfo(0, "polygon", NpgsqlDbType.Polygon, DbType.Object, typeof(NpgsqlPolygon),
+ new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToPolygon)),
+ };
- if (useExtendedTypes)
- {
- yield return
- new NpgsqlBackendTypeInfo(0, "date", NpgsqlDbType.Date, DbType.Date, typeof (NpgsqlDate),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToDate));
+ // Attempt to map each type info in the list to an OID on the backend and
+ // add each mapped type to the new type mapping object.
+ LoadTypesMappings(conn, oidToNameMapping, TypeInfoList);
- yield return
- new NpgsqlBackendTypeInfo(0, "time", NpgsqlDbType.Time, DbType.Time, typeof (NpgsqlTime),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToTime));
+ // Add this mapping to the per-server-version cache so we don't have to
+ // do these expensive queries on every connection startup.
+ BackendTypeMappingCache.Add(conn.ServerVersion, oidToNameMapping);
- yield return
- new NpgsqlBackendTypeInfo(0, "timetz", NpgsqlDbType.TimeTZ, DbType.Time, typeof (NpgsqlTimeTZ),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToTimeTZ));
+ return oidToNameMapping;
+ }
- yield return
- new NpgsqlBackendTypeInfo(0, "timestamp", NpgsqlDbType.Timestamp, DbType.DateTime, typeof (NpgsqlTimeStamp),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToTimeStamp));
- yield return
- new NpgsqlBackendTypeInfo(0, "timestamptz", NpgsqlDbType.TimestampTZ, DbType.DateTime, typeof (NpgsqlTimeStampTZ),
- new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToTimeStampTZ));
- }
- else
- {
- yield return
- new NpgsqlBackendTypeInfo(0, "date", NpgsqlDbType.Date, DbType.Date, typeof (DateTime),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDate));
-
- yield return
- new NpgsqlBackendTypeInfo(0, "time", NpgsqlDbType.Time, DbType.Time, typeof (DateTime),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToTime));
-
- yield return
- new NpgsqlBackendTypeInfo(0, "timetz", NpgsqlDbType.TimeTZ, DbType.Time, typeof (DateTime),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToTime));
-
- yield return
- new NpgsqlBackendTypeInfo(0, "timestamp", NpgsqlDbType.Timestamp, DbType.DateTime, typeof (DateTime),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDateTime));
-
- yield return
- new NpgsqlBackendTypeInfo(0, "timestamptz", NpgsqlDbType.TimestampTZ, DbType.DateTime, typeof (DateTime),
- new ConvertBackendToNativeHandler(BasicBackendToNativeTypeConverter.ToDateTime));
- }
- }
-
- ///<summary>
- /// This method creates (or retrieves from cache) a mapping between type and OID
- /// of all natively supported postgresql data types.
- /// This is needed as from one version to another, this mapping can be changed and
- /// so we avoid hardcoding them.
- /// </summary>
- /// <returns>NpgsqlTypeMapping containing all known data types. The mapping must be
- /// cloned before it is modified because it is cached; changes made by one connection may
- /// effect another connection.</returns>
- public static NpgsqlBackendTypeMapping CreateAndLoadInitialTypesMapping(NpgsqlConnector conn)
- {
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "LoadTypesMapping");
-
- // [TODO] Verify another way to get higher concurrency.
- lock (CLASSNAME)
- {
- // Check the cache for an initial types map.
- NpgsqlBackendTypeMapping oidToNameMapping = null;
-
- if (
- BackendTypeMappingCache.TryGetValue(new MappingKey(conn.ServerVersion, conn.UseExtendedTypes), out oidToNameMapping))
- {
- return oidToNameMapping;
- }
-
- // Not in cache, create a new one.
- oidToNameMapping = new NpgsqlBackendTypeMapping();
-
- // Create a list of all natively supported postgresql data types.
-
- // Attempt to map each type info in the list to an OID on the backend and
- // add each mapped type to the new type mapping object.
- LoadTypesMappings(conn, oidToNameMapping, TypeInfoList(conn.UseExtendedTypes));
-
- // Add this mapping to the per-server-version cache so we don't have to
- // do these expensive queries on every connection startup.
- BackendTypeMappingCache.Add(new MappingKey(conn.ServerVersion, conn.UseExtendedTypes), oidToNameMapping);
-
- return oidToNameMapping;
- }
- }
-
- //Take a NpgsqlBackendTypeInfo for a type and return the NpgsqlBackendTypeInfo for
-
- //an array of that type.
-
- private static NpgsqlBackendTypeInfo ArrayTypeInfo(NpgsqlBackendTypeInfo elementInfo)
-
- {
- return
- new NpgsqlBackendTypeInfo(0, "_" + elementInfo.Name, NpgsqlDbType.Array | elementInfo.NpgsqlDbType, DbType.Object,
- elementInfo.Type.MakeArrayType(),
- new ConvertBackendToNativeHandler(
- new ArrayBackendToNativeTypeConverter(elementInfo).ToArray));
- }
-
-
- /// <summary>
- /// Attempt to map types by issuing a query against pg_type.
- /// This function takes a list of NpgsqlTypeInfo and attempts to resolve the OID field
- /// of each by querying pg_type. If the mapping is found, the type info object is
- /// updated (OID) and added to the provided NpgsqlTypeMapping object.
- /// </summary>
- /// <param name="conn">NpgsqlConnector to send query through.</param>
- /// <param name="TypeMappings">Mapping object to add types too.</param>
- /// <param name="TypeInfoList">List of types that need to have OID's mapped.</param>
- public static void LoadTypesMappings(NpgsqlConnector conn, NpgsqlBackendTypeMapping TypeMappings,
- IEnumerable<NpgsqlBackendTypeInfo> TypeInfoList)
- {
- StringBuilder InList = new StringBuilder();
- Dictionary<string, NpgsqlBackendTypeInfo> NameIndex = new Dictionary<string, NpgsqlBackendTypeInfo>();
-
- // Build a clause for the SELECT statement.
- // Build a name->typeinfo mapping so we can match the results of the query
- // with the list of type objects efficiently.
- foreach (NpgsqlBackendTypeInfo TypeInfo in TypeInfoList)
- {
- NameIndex.Add(TypeInfo.Name, TypeInfo);
- InList.AppendFormat("{0}'{1}'", ((InList.Length > 0) ? ", " : ""), TypeInfo.Name);
-
- //do the same for the equivalent array type.
-
- NameIndex.Add("_" + TypeInfo.Name, ArrayTypeInfo(TypeInfo));
-
- InList.Append(", '_").Append(TypeInfo.Name).Append('\'');
- }
-
- if (InList.Length == 0)
- {
- return;
- }
-
- using (
- NpgsqlCommand command =
- new NpgsqlCommand(string.Format("SELECT typname, oid FROM pg_type WHERE typname IN ({0})", InList), conn))
- {
- using (NpgsqlDataReader dr = command.GetReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
- {
- while (dr.Read())
- {
- NpgsqlBackendTypeInfo TypeInfo = NameIndex[dr[0].ToString()];
-
- TypeInfo._OID = Convert.ToInt32(dr[1]);
-
- TypeMappings.AddType(TypeInfo);
- }
- }
- }
- }
- }
-
- /// <summary>
- /// Delegate called to convert the given backend data to its native representation.
- /// </summary>
- internal delegate Object ConvertBackendToNativeHandler(
- NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier);
-
- /// <summary>
- /// Delegate called to convert the given native data to its backand representation.
- /// </summary>
- internal delegate String ConvertNativeToBackendHandler(NpgsqlNativeTypeInfo TypeInfo, Object NativeData);
-
- /// <summary>
- /// Represents a backend data type.
- /// This class can be called upon to convert a backend field representation to a native object.
- /// </summary>
- internal class NpgsqlBackendTypeInfo
- {
- private readonly ConvertBackendToNativeHandler _ConvertBackendToNative;
-
- internal Int32 _OID;
- private readonly String _Name;
- private readonly NpgsqlDbType _NpgsqlDbType;
- private readonly DbType _DbType;
- private readonly Type _Type;
-
-
- /// <summary>
- /// Construct a new NpgsqlTypeInfo with the given attributes and conversion handlers.
- /// </summary>
- /// <param name="OID">Type OID provided by the backend server.</param>
- /// <param name="Name">Type name provided by the backend server.</param>
- /// <param name="NpgsqlDbType">NpgsqlDbType</param>
- /// <param name="Type">System type to convert fields of this type to.</param>
- /// <param name="ConvertBackendToNative">Data conversion handler.</param>
- public NpgsqlBackendTypeInfo(Int32 OID, String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Type Type,
- ConvertBackendToNativeHandler ConvertBackendToNative)
- {
- if (Type == null)
- throw new ArgumentNullException("Type");
- _OID = OID;
- _Name = Name;
- _NpgsqlDbType = NpgsqlDbType;
- _DbType = DbType;
- _Type = Type;
- _ConvertBackendToNative = ConvertBackendToNative;
- }
-
- /// <summary>
- /// Type OID provided by the backend server.
- /// </summary>
- public Int32 OID
- {
- get { return _OID; }
- }
-
- /// <summary>
- /// Type name provided by the backend server.
- /// </summary>
- public String Name
- {
- get { return _Name; }
- }
-
- /// <summary>
- /// NpgsqlDbType.
- /// </summary>
- public NpgsqlDbType NpgsqlDbType
- {
- get { return _NpgsqlDbType; }
- }
-
- /// <summary>
- /// NpgsqlDbType.
- /// </summary>
- public DbType DbType
- {
- get { return _DbType; }
- }
-
- /// <summary>
- /// System type to convert fields of this type to.
- /// </summary>
- public Type Type
- {
- get { return _Type; }
- }
-
- /// <summary>
- /// Perform a data conversion from a backend representation to
- /// a native object.
- /// </summary>
- /// <param name="BackendData">Data sent from the backend.</param>
- /// <param name="TypeModifier">Type modifier field sent from the backend.</param>
- public Object ConvertToNative(String BackendData, Int16 TypeSize, Int32 TypeModifier)
- {
- if (_ConvertBackendToNative != null)
- {
- return _ConvertBackendToNative(this, BackendData, TypeSize, TypeModifier);
- }
- else
- {
- try
- {
- return Convert.ChangeType(BackendData, Type, CultureInfo.InvariantCulture);
- }
- catch
- {
- return BackendData;
- }
- }
- }
- }
-
- /// <summary>
- /// Represents a backend data type.
- /// This class can be called upon to convert a native object to its backend field representation,
- /// </summary>
- internal class NpgsqlNativeTypeInfo
- {
- private static readonly NumberFormatInfo ni;
-
- private readonly ConvertNativeToBackendHandler _ConvertNativeToBackend;
-
- private readonly String _Name;
- private readonly string _CastName;
- private readonly NpgsqlDbType _NpgsqlDbType;
- private readonly DbType _DbType;
- private readonly Boolean _Quote;
- private readonly Boolean _UseSize;
- private Boolean _IsArray = false;
-
- /// <summary>
- /// Returns an NpgsqlNativeTypeInfo for an array where the elements are of the type
- /// described by the NpgsqlNativeTypeInfo supplied.
- /// </summary>
- public static NpgsqlNativeTypeInfo ArrayOf(NpgsqlNativeTypeInfo elementType)
-
- {
- if (elementType._IsArray)
- //we've an array of arrays. It's the inner most elements whose type we care about, so the type we have is fine.
- {
- return elementType;
- }
-
- NpgsqlNativeTypeInfo copy =
- new NpgsqlNativeTypeInfo("_" + elementType.Name, NpgsqlDbType.Array | elementType.NpgsqlDbType, elementType.DbType,
- false,
- new ConvertNativeToBackendHandler(
- new ArrayNativeToBackendTypeConverter(elementType).FromArray));
-
- copy._IsArray = true;
-
- return copy;
- }
-
-
- static NpgsqlNativeTypeInfo()
- {
- ni = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone();
- ni.NumberDecimalDigits = 15;
- }
-
- /// <summary>
- /// Construct a new NpgsqlTypeInfo with the given attributes and conversion handlers.
- /// </summary>
- /// <param name="Name">Type name provided by the backend server.</param>
- /// <param name="NpgsqlDbType">NpgsqlDbType</param>
- /// <param name="ConvertNativeToBackend">Data conversion handler.</param>
- public NpgsqlNativeTypeInfo(String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Boolean Quote,
- ConvertNativeToBackendHandler ConvertNativeToBackend)
- {
- _Name = Name;
- _CastName = Name.StartsWith("_") ? Name.Substring(1) + "[]" : Name;
- _NpgsqlDbType = NpgsqlDbType;
- _DbType = DbType;
- _Quote = Quote;
- _ConvertNativeToBackend = ConvertNativeToBackend;
-
-
- // The only parameters types which use length currently supported are char and varchar. Check for them.
-
- if ((NpgsqlDbType == NpgsqlDbType.Char) || (NpgsqlDbType == NpgsqlDbType.Varchar))
- {
- _UseSize = true;
- }
- else
- {
- _UseSize = false;
- }
- }
-
- /// <summary>
- /// Type name provided by the backend server.
- /// </summary>
- public String Name
- {
- get { return _Name; }
- }
-
- public string CastName
-
- {
- get { return _CastName; }
- }
-
- public bool IsArray
-
- {
- get { return _IsArray; }
- }
-
- /// <summary>
- /// NpgsqlDbType.
- /// </summary>
- public NpgsqlDbType NpgsqlDbType
- {
- get { return _NpgsqlDbType; }
- }
-
- /// <summary>
- /// DbType.
- /// </summary>
- public DbType DbType
- {
- get { return _DbType; }
- }
-
-
- /// <summary>
- /// Apply quoting.
- /// </summary>
- public Boolean Quote
- {
- get { return _Quote; }
- }
-
- /// <summary>
- /// Use parameter size information.
- /// </summary>
- public Boolean UseSize
- {
- get { return _UseSize; }
- }
-
-
- /// <summary>
- /// Perform a data conversion from a native object to
- /// a backend representation.
- /// DBNull and null values are handled differently depending if a plain query is used
- /// When
- /// </summary>
- /// <param name="NativeData">Native .NET object to be converted.</param>
- /// <param name="ForExtendedQuery">Flag indicating if the conversion has to be done for
+ }
+
+ /// <summary>
+ /// Attempt to map types by issuing a query against pg_type.
+ /// This function takes a list of NpgsqlTypeInfo and attempts to resolve the OID field
+ /// of each by querying pg_type. If the mapping is found, the type info object is
+ /// updated (OID) and added to the provided NpgsqlTypeMapping object.
+ /// </summary>
+ /// <param name="conn">NpgsqlConnector to send query through.</param>
+ /// <param name="TypeMappings">Mapping object to add types too.</param>
+ /// <param name="TypeInfoList">List of types that need to have OID's mapped.</param>
+ public static void LoadTypesMappings(NpgsqlConnector conn, NpgsqlBackendTypeMapping TypeMappings, IList TypeInfoList)
+ {
+ StringBuilder InList = new StringBuilder();
+ Hashtable NameIndex = new Hashtable();
+
+ // Build a clause for the SELECT statement.
+ // Build a name->typeinfo mapping so we can match the results of the query
+ /// with the list of type objects efficiently.
+ foreach (NpgsqlBackendTypeInfo TypeInfo in TypeInfoList) {
+ NameIndex.Add(TypeInfo.Name, TypeInfo);
+ InList.AppendFormat("{0}'{1}'", ((InList.Length > 0) ? ", " : ""), TypeInfo.Name);
+ }
+
+ if (InList.Length == 0) {
+ return;
+ }
+
+ NpgsqlCommand command = new NpgsqlCommand("SELECT oid, typname FROM pg_type WHERE typname IN (" + InList.ToString() + ")", conn);
+ NpgsqlDataReader dr = command.ExecuteReader();
+
+ while (dr.Read()) {
+ NpgsqlBackendTypeInfo TypeInfo = (NpgsqlBackendTypeInfo)NameIndex[dr[1].ToString()];
+
+ TypeInfo._OID = Convert.ToInt32(dr[0]);
+
+ TypeMappings.AddType(TypeInfo);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Delegate called to convert the given backend data to its native representation.
+ /// </summary>
+ internal delegate Object ConvertBackendToNativeHandler(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier);
+ /// <summary>
+ /// Delegate called to convert the given native data to its backand representation.
+ /// </summary>
+ internal delegate String ConvertNativeToBackendHandler(NpgsqlNativeTypeInfo TypeInfo, Object NativeData);
+
+ /// <summary>
+ /// Represents a backend data type.
+ /// This class can be called upon to convert a backend field representation to a native object.
+ /// </summary>
+ internal class NpgsqlBackendTypeInfo
+ {
+ private ConvertBackendToNativeHandler _ConvertBackendToNative;
+
+ internal Int32 _OID;
+ private String _Name;
+ private NpgsqlDbType _NpgsqlDbType;
+ private DbType _DbType;
+ private Type _Type;
+
+ /// <summary>
+ /// Construct a new NpgsqlTypeInfo with the given attributes and conversion handlers.
+ /// </summary>
+ /// <param name="OID">Type OID provided by the backend server.</param>
+ /// <param name="Name">Type name provided by the backend server.</param>
+ /// <param name="NpgsqlDbType">NpgsqlDbType</param>
+ /// <param name="Type">System type to convert fields of this type to.</param>
+ /// <param name="ConvertBackendToNative">Data conversion handler.</param>
+ public NpgsqlBackendTypeInfo(Int32 OID, String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Type Type, ConvertBackendToNativeHandler ConvertBackendToNative)
+ {
+ _OID = OID;
+ _Name = Name;
+ _NpgsqlDbType = NpgsqlDbType;
+ _DbType = DbType;
+ _Type = Type;
+ _ConvertBackendToNative = ConvertBackendToNative;
+ }
+
+ /// <summary>
+ /// Type OID provided by the backend server.
+ /// </summary>
+ public Int32 OID
+ {
+ get { return _OID; }
+ }
+
+ /// <summary>
+ /// Type name provided by the backend server.
+ /// </summary>
+ public String Name
+ { get { return _Name; } }
+
+ /// <summary>
+ /// NpgsqlDbType.
+ /// </summary>
+ public NpgsqlDbType NpgsqlDbType
+ { get { return _NpgsqlDbType; } }
+
+ /// <summary>
+ /// NpgsqlDbType.
+ /// </summary>
+ public DbType DbType
+ { get { return _DbType; } }
+
+ /// <summary>
+ /// System type to convert fields of this type to.
+ /// </summary>
+ public Type Type
+ { get { return _Type; } }
+
+ /// <summary>
+ /// Perform a data conversion from a backend representation to
+ /// a native object.
+ /// </summary>
+ /// <param name="BackendData">Data sent from the backend.</param>
+ /// <param name="TypeModifier">Type modifier field sent from the backend.</param>
+ public Object ConvertToNative(String BackendData, Int16 TypeSize, Int32 TypeModifier)
+ {
+ if (_ConvertBackendToNative != null) {
+ return _ConvertBackendToNative(this, BackendData, TypeSize, TypeModifier);
+ } else {
+ try {
+ return Convert.ChangeType(BackendData, Type, CultureInfo.InvariantCulture);
+ } catch {
+ return BackendData;
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Represents a backend data type.
+ /// This class can be called upon to convert a native object to its backend field representation,
+ /// </summary>
+ internal class NpgsqlNativeTypeInfo
+ {
+ private static NumberFormatInfo ni;
+
+ private ConvertNativeToBackendHandler _ConvertNativeToBackend;
+
+ private String _Name;
+ private NpgsqlDbType _NpgsqlDbType;
+ private DbType _DbType;
+ private Boolean _Quote;
+ private Boolean _UseSize;
+
+ static NpgsqlNativeTypeInfo()
+ {
+ ni = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone();
+ ni.NumberDecimalDigits = 15;
+ }
+
+ /// <summary>
+ /// Construct a new NpgsqlTypeInfo with the given attributes and conversion handlers.
+ /// </summary>
+ /// <param name="OID">Type OID provided by the backend server.</param>
+ /// <param name="Name">Type name provided by the backend server.</param>
+ /// <param name="NpgsqlDbType">NpgsqlDbType</param>
+ /// <param name="Type">System type to convert fields of this type to.</param>
+ /// <param name="ConvertBackendToNative">Data conversion handler.</param>
+ /// <param name="ConvertNativeToBackend">Data conversion handler.</param>
+ public NpgsqlNativeTypeInfo(String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Boolean Quote, ConvertNativeToBackendHandler ConvertNativeToBackend)
+ {
+ _Name = Name;
+ _NpgsqlDbType = NpgsqlDbType;
+ _DbType = DbType;
+ _Quote = Quote;
+ _ConvertNativeToBackend = ConvertNativeToBackend;
+
+
+ // The only parameters types which use length currently supported are char and varchar. Check for them.
+
+ if ( (NpgsqlDbType == NpgsqlDbType.Char)
+ || (NpgsqlDbType == NpgsqlDbType.Varchar))
+
+ _UseSize = true;
+ else
+ _UseSize = false;
+ }
+
+ /// <summary>
+ /// Type name provided by the backend server.
+ /// </summary>
+ public String Name
+ { get { return _Name; } }
+
+ /// <summary>
+ /// NpgsqlDbType.
+ /// </summary>
+ public NpgsqlDbType NpgsqlDbType
+ { get { return _NpgsqlDbType; } }
+
+ /// <summary>
+ /// DbType.
+ /// </summary>
+ public DbType DbType
+ { get { return _DbType; } }
+
+
+ /// <summary>
+ /// Apply quoting.
+ /// </summary>
+ public Boolean Quote
+ { get { return _Quote; } }
+
+ /// <summary>
+ /// Use parameter size information.
+ /// </summary>
+ public Boolean UseSize
+ { get { return _UseSize; } }
+
+
+ /// <summary>
+ /// Perform a data conversion from a native object to
+ /// a backend representation.
+ /// DBNull and null values are handled differently depending if a plain query is used
+ /// When
+ /// </summary>
+ /// <param name="NativeData">Native .NET object to be converted.</param>
+ /// <param name="ForExtendedQuery">Flag indicating if the conversion has to be done for
/// plain queries or extended queries</param>
- public String ConvertToBackend(Object NativeData, Boolean ForExtendedQuery)
- {
- if (ForExtendedQuery)
- {
- return ConvertToBackendExtendedQuery(NativeData);
- }
- else
- {
- return ConvertToBackendPlainQuery(NativeData);
- }
- }
-
- private String ConvertToBackendPlainQuery(Object NativeData)
- {
- if ((NativeData == DBNull.Value) || (NativeData == null))
- {
- return "NULL"; // Plain queries exptects null values as string NULL.
- }
-
- if (_ConvertNativeToBackend != null)
- {
- return
- (this.Quote ? QuoteString(_ConvertNativeToBackend(this, NativeData)) : _ConvertNativeToBackend(this, NativeData));
- }
- else
- {
- if (NativeData is Enum)
- {
- // Do a special handling of Enum values.
- // Translate enum value to its underlying type.
- return
- QuoteString(
- (String)
- Convert.ChangeType(Enum.Format(NativeData.GetType(), NativeData, "d"), typeof (String),
- CultureInfo.InvariantCulture));
- }
- else if (NativeData is IFormattable)
- {
- return
- (this.Quote
- ? QuoteString(((IFormattable) NativeData).ToString(null, ni).Replace("'", "''").Replace("\\", "\\\\"))
- : ((IFormattable) NativeData).ToString(null, ni).Replace("'", "''").Replace("\\", "\\\\"));
- }
-
- // Do special handling of strings when in simple query. Escape quotes and backslashes.
- return
- (this.Quote
- ? QuoteString(NativeData.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace("\0", "\\0"))
- : NativeData.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace("\0", "\\0"));
- }
- }
-
- private String ConvertToBackendExtendedQuery(Object NativeData)
- {
- if ((NativeData == DBNull.Value) || (NativeData == null))
- {
- return null; // Extended query expects null values be represented as null.
- }
-
- if (_ConvertNativeToBackend != null)
- {
- return _ConvertNativeToBackend(this, NativeData);
- }
- else
- {
- if (NativeData is Enum)
- {
- // Do a special handling of Enum values.
- // Translate enum value to its underlying type.
- return
- (String)
- Convert.ChangeType(Enum.Format(NativeData.GetType(), NativeData, "d"), typeof (String),
- CultureInfo.InvariantCulture);
- }
- else if (NativeData is IFormattable)
- {
- return ((IFormattable) NativeData).ToString(null, ni);
- }
-
- return NativeData.ToString();
- }
- }
-
- internal static String QuoteString(String S)
- {
- return String.Format("'{0}'", S);
- }
- }
-
- /// <summary>
- /// Provide mapping between type OID, type name, and a NpgsqlBackendTypeInfo object that represents it.
- /// </summary>
- internal class NpgsqlBackendTypeMapping
- {
- private readonly Dictionary<int, NpgsqlBackendTypeInfo> OIDIndex;
- private readonly Dictionary<string, NpgsqlBackendTypeInfo> NameIndex;
-
- /// <summary>
- /// Construct an empty mapping.
- /// </summary>
- public NpgsqlBackendTypeMapping()
- {
- OIDIndex = new Dictionary<int, NpgsqlBackendTypeInfo>();
- NameIndex = new Dictionary<string, NpgsqlBackendTypeInfo>();
- }
-
- /// <summary>
- /// Copy constuctor.
- /// </summary>
- private NpgsqlBackendTypeMapping(NpgsqlBackendTypeMapping Other)
- {
- OIDIndex = new Dictionary<int, NpgsqlBackendTypeInfo>(Other.OIDIndex);
- NameIndex = new Dictionary<string, NpgsqlBackendTypeInfo>(Other.NameIndex);
- }
-
- /// <summary>
- /// Add the given NpgsqlBackendTypeInfo to this mapping.
- /// </summary>
- public void AddType(NpgsqlBackendTypeInfo T)
- {
- if (OIDIndex.ContainsKey(T.OID))
- {
- throw new Exception("Type already mapped");
- }
-
- OIDIndex[T.OID] = T;
- NameIndex[T.Name] = T;
- }
-
- /// <summary>
- /// Add a new NpgsqlBackendTypeInfo with the given attributes and conversion handlers to this mapping.
- /// </summary>
- /// <param name="OID">Type OID provided by the backend server.</param>
- /// <param name="Name">Type name provided by the backend server.</param>
- /// <param name="NpgsqlDbType">NpgsqlDbType</param>
- /// <param name="Type">System type to convert fields of this type to.</param>
- /// <param name="BackendConvert">Data conversion handler.</param>
- public void AddType(Int32 OID, String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Type Type,
- ConvertBackendToNativeHandler BackendConvert)
- {
- AddType(new NpgsqlBackendTypeInfo(OID, Name, NpgsqlDbType, DbType, Type, BackendConvert));
- }
-
- /// <summary>
- /// Get the number of type infos held.
- /// </summary>
- public Int32 Count
- {
- get { return NameIndex.Count; }
- }
-
- public bool TryGetValue(int oid, out NpgsqlBackendTypeInfo value)
- {
- return OIDIndex.TryGetValue(oid, out value);
- }
-
- /// <summary>
- /// Retrieve the NpgsqlBackendTypeInfo with the given backend type OID, or null if none found.
- /// </summary>
- public NpgsqlBackendTypeInfo this[Int32 OID]
- {
- get
- {
- NpgsqlBackendTypeInfo ret = null;
- return TryGetValue(OID, out ret) ? ret : null;
- }
- }
-
- /// <summary>
- /// Retrieve the NpgsqlBackendTypeInfo with the given backend type name, or null if none found.
- /// </summary>
- public NpgsqlBackendTypeInfo this[String Name]
- {
- get
- {
- NpgsqlBackendTypeInfo ret = null;
- return NameIndex.TryGetValue(Name, out ret) ? ret : null;
- }
- }
-
- /// <summary>
- /// Make a shallow copy of this type mapping.
- /// </summary>
- public NpgsqlBackendTypeMapping Clone()
- {
- return new NpgsqlBackendTypeMapping(this);
- }
-
- /// <summary>
- /// Determine if a NpgsqlBackendTypeInfo with the given backend type OID exists in this mapping.
- /// </summary>
- public Boolean ContainsOID(Int32 OID)
- {
- return OIDIndex.ContainsKey(OID);
- }
-
- /// <summary>
- /// Determine if a NpgsqlBackendTypeInfo with the given backend type name exists in this mapping.
- /// </summary>
- public Boolean ContainsName(String Name)
- {
- return NameIndex.ContainsKey(Name);
- }
- }
-
-
- /// <summary>
- /// Provide mapping between type Type, NpgsqlDbType and a NpgsqlNativeTypeInfo object that represents it.
- /// </summary>
- internal class NpgsqlNativeTypeMapping
- {
- private readonly Dictionary<string, NpgsqlNativeTypeInfo> NameIndex = new Dictionary<string, NpgsqlNativeTypeInfo>();
-
- private readonly Dictionary<NpgsqlDbType, NpgsqlNativeTypeInfo> NpgsqlDbTypeIndex =
- new Dictionary<NpgsqlDbType, NpgsqlNativeTypeInfo>();
-
- private readonly Dictionary<DbType, NpgsqlNativeTypeInfo> DbTypeIndex = new Dictionary<DbType, NpgsqlNativeTypeInfo>();
- private readonly Dictionary<Type, NpgsqlNativeTypeInfo> TypeIndex = new Dictionary<Type, NpgsqlNativeTypeInfo>();
-
- /// <summary>
- /// Add the given NpgsqlNativeTypeInfo to this mapping.
- /// </summary>
- public void AddType(NpgsqlNativeTypeInfo T)
- {
- if (NameIndex.ContainsKey(T.Name))
- {
- throw new Exception("Type already mapped");
- }
-
- NameIndex[T.Name] = T;
- NpgsqlDbTypeIndex[T.NpgsqlDbType] = T;
- DbTypeIndex[T.DbType] = T;
- if (!T.IsArray)
-
- {
- NpgsqlNativeTypeInfo arrayType = NpgsqlNativeTypeInfo.ArrayOf(T);
- NameIndex[arrayType.Name] = arrayType;
-
- NameIndex[arrayType.CastName] = arrayType;
- NpgsqlDbTypeIndex[arrayType.NpgsqlDbType] = arrayType;
- }
- }
-
- /// <summary>
- /// Add a new NpgsqlNativeTypeInfo with the given attributes and conversion handlers to this mapping.
- /// </summary>
- /// <param name="Name">Type name provided by the backend server.</param>
- /// <param name="NpgsqlDbType">NpgsqlDbType</param>
- /// <param name="NativeConvert">Data conversion handler.</param>
- public void AddType(String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Boolean Quote,
- ConvertNativeToBackendHandler NativeConvert)
- {
- AddType(new NpgsqlNativeTypeInfo(Name, NpgsqlDbType, DbType, Quote, NativeConvert));
- }
-
- public void AddNpgsqlDbTypeAlias(String Name, NpgsqlDbType NpgsqlDbType)
- {
- if (NpgsqlDbTypeIndex.ContainsKey(NpgsqlDbType))
- {
- throw new Exception("NpgsqlDbType already aliased");
- }
-
- NpgsqlDbTypeIndex[NpgsqlDbType] = NameIndex[Name];
- }
-
- public void AddDbTypeAlias(String Name, DbType DbType)
- {
- /*if (DbTypeIndex.ContainsKey(DbType))
- {
- throw new Exception("DbType already aliased");
- }*/
-
- DbTypeIndex[DbType] = NameIndex[Name];
- }
-
- public void AddTypeAlias(String Name, Type Type)
- {
- if (TypeIndex.ContainsKey(Type))
- {
- throw new Exception("Type already aliased");
- }
-
- TypeIndex[Type] = NameIndex[Name];
- }
-
- /// <summary>
- /// Get the number of type infos held.
- /// </summary>
- public Int32 Count
- {
- get { return NameIndex.Count; }
- }
-
- public bool TryGetValue(string name, out NpgsqlNativeTypeInfo typeInfo)
- {
- return NameIndex.TryGetValue(name, out typeInfo);
- }
-
- /// <summary>
- /// Retrieve the NpgsqlNativeTypeInfo with the given NpgsqlDbType.
- /// </summary>
- public bool TryGetValue(NpgsqlDbType dbType, out NpgsqlNativeTypeInfo typeInfo)
- {
- return NpgsqlDbTypeIndex.TryGetValue(dbType, out typeInfo);
- }
-
- /// <summary>
- /// Retrieve the NpgsqlNativeTypeInfo with the given DbType.
- /// </summary>
- public bool TryGetValue(DbType dbType, out NpgsqlNativeTypeInfo typeInfo)
- {
- return DbTypeIndex.TryGetValue(dbType, out typeInfo);
- }
-
-
- /// <summary>
- /// Retrieve the NpgsqlNativeTypeInfo with the given Type.
- /// </summary>
- public bool TryGetValue(Type type, out NpgsqlNativeTypeInfo typeInfo)
- {
- return TypeIndex.TryGetValue(type, out typeInfo);
- }
-
- /// <summary>
- /// Determine if a NpgsqlNativeTypeInfo with the given backend type name exists in this mapping.
- /// </summary>
- public Boolean ContainsName(String Name)
- {
- return NameIndex.ContainsKey(Name);
- }
-
- /// <summary>
- /// Determine if a NpgsqlNativeTypeInfo with the given NpgsqlDbType exists in this mapping.
- /// </summary>
- public Boolean ContainsNpgsqlDbType(NpgsqlDbType NpgsqlDbType)
- {
- return NpgsqlDbTypeIndex.ContainsKey(NpgsqlDbType);
- }
-
- /// <summary>
- /// Determine if a NpgsqlNativeTypeInfo with the given Type name exists in this mapping.
- /// </summary>
- public Boolean ContainsType(Type Type)
- {
- return TypeIndex.ContainsKey(Type);
- }
- }
-} \ No newline at end of file
+ public String ConvertToBackend(Object NativeData, Boolean ForExtendedQuery)
+ {
+ if (ForExtendedQuery)
+ return ConvertToBackendExtendedQuery(NativeData);
+ else
+ return ConvertToBackendPlainQuery(NativeData);
+
+ }
+
+ private String ConvertToBackendPlainQuery(Object NativeData)
+ {
+ if ((NativeData == DBNull.Value) || (NativeData == null))
+ return "NULL"; // Plain queries exptects null values as string NULL.
+
+ if (_ConvertNativeToBackend != null)
+ return (this.Quote ? QuoteString(_ConvertNativeToBackend(this, NativeData)) : _ConvertNativeToBackend(this, NativeData));
+ else
+ {
+
+
+ if (NativeData is System.Enum)
+ {
+ // Do a special handling of Enum values.
+ // Translate enum value to its underlying type.
+ return QuoteString((String)Convert.ChangeType(Enum.Format(NativeData.GetType(), NativeData, "d"), typeof(String), CultureInfo.InvariantCulture));
+ }
+ else if (NativeData is IFormattable)
+ {
+ return (this.Quote ? QuoteString(((IFormattable) NativeData).ToString(null, ni).Replace("'", "''").Replace("\\", "\\\\")) :
+ ((IFormattable) NativeData).ToString(null, ni).Replace("'", "''").Replace("\\", "\\\\"));
+
+ }
+
+ // Do special handling of strings when in simple query. Escape quotes and backslashes.
+ return (this.Quote ? QuoteString(NativeData.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace("\0", "\\0")) :
+ NativeData.ToString().Replace("'", "''").Replace("\\", "\\\\").Replace("\0", "\\0"));
+
+ }
+
+ }
+
+ private String ConvertToBackendExtendedQuery(Object NativeData)
+ {
+ if ((NativeData == DBNull.Value) || (NativeData == null))
+ return null; // Extended query expects null values be represented as null.
+
+ if (_ConvertNativeToBackend != null)
+ return _ConvertNativeToBackend(this, NativeData);
+ else
+ {
+ if (NativeData is System.Enum)
+ {
+ // Do a special handling of Enum values.
+ // Translate enum value to its underlying type.
+ return (String)Convert.ChangeType(Enum.Format(NativeData.GetType(), NativeData, "d"), typeof(String), CultureInfo.InvariantCulture);
+ }
+ else if (NativeData is IFormattable)
+ {
+ return ((IFormattable)NativeData).ToString(null, ni);
+
+ }
+
+ return NativeData.ToString();
+
+ }
+
+ }
+
+ private static String QuoteString(String S)
+ {
+ return String.Format("E'{0}'", S);
+
+ }
+ }
+
+ /// <summary>
+ /// Provide mapping between type OID, type name, and a NpgsqlBackendTypeInfo object that represents it.
+ /// </summary>
+ internal class NpgsqlBackendTypeMapping
+ {
+ private Hashtable OIDIndex;
+ private Hashtable NameIndex;
+
+ /// <summary>
+ /// Construct an empty mapping.
+ /// </summary>
+ public NpgsqlBackendTypeMapping()
+ {
+ OIDIndex = new Hashtable();
+ NameIndex = new Hashtable();
+ }
+
+ /// <summary>
+ /// Copy constuctor.
+ /// </summary>
+ private NpgsqlBackendTypeMapping(NpgsqlBackendTypeMapping Other)
+ {
+ OIDIndex = (Hashtable)Other.OIDIndex.Clone();
+ NameIndex = (Hashtable)Other.NameIndex.Clone();
+ }
+
+ /// <summary>
+ /// Add the given NpgsqlBackendTypeInfo to this mapping.
+ /// </summary>
+ public void AddType(NpgsqlBackendTypeInfo T)
+ {
+ if (OIDIndex.Contains(T.OID)) {
+ throw new Exception("Type already mapped");
+ }
+
+ OIDIndex[T.OID] = T;
+ NameIndex[T.Name] = T;
+ }
+
+ /// <summary>
+ /// Add a new NpgsqlBackendTypeInfo with the given attributes and conversion handlers to this mapping.
+ /// </summary>
+ /// <param name="OID">Type OID provided by the backend server.</param>
+ /// <param name="Name">Type name provided by the backend server.</param>
+ /// <param name="NpgsqlDbType">NpgsqlDbType</param>
+ /// <param name="Type">System type to convert fields of this type to.</param>
+ /// <param name="ConvertBackendToNative">Data conversion handler.</param>
+ public void AddType(Int32 OID, String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Type Type,
+ ConvertBackendToNativeHandler BackendConvert)
+ {
+ AddType(new NpgsqlBackendTypeInfo(OID, Name, NpgsqlDbType, DbType, Type, BackendConvert));
+ }
+
+ /// <summary>
+ /// Get the number of type infos held.
+ /// </summary>
+ public Int32 Count
+ { get { return NameIndex.Count; } }
+
+ /// <summary>
+ /// Retrieve the NpgsqlBackendTypeInfo with the given backend type OID, or null if none found.
+ /// </summary>
+ public NpgsqlBackendTypeInfo this [Int32 OID]
+ {
+ get
+ {
+ return (NpgsqlBackendTypeInfo)OIDIndex[OID];
+ }
+ }
+
+ /// <summary>
+ /// Retrieve the NpgsqlBackendTypeInfo with the given backend type name, or null if none found.
+ /// </summary>
+ public NpgsqlBackendTypeInfo this [String Name]
+ {
+ get
+ {
+ return (NpgsqlBackendTypeInfo)NameIndex[Name];
+ }
+ }
+
+ /// <summary>
+ /// Make a shallow copy of this type mapping.
+ /// </summary>
+ public NpgsqlBackendTypeMapping Clone()
+ {
+ return new NpgsqlBackendTypeMapping(this);
+ }
+
+ /// <summary>
+ /// Determine if a NpgsqlBackendTypeInfo with the given backend type OID exists in this mapping.
+ /// </summary>
+ public Boolean ContainsOID(Int32 OID)
+ {
+ return OIDIndex.ContainsKey(OID);
+ }
+
+ /// <summary>
+ /// Determine if a NpgsqlBackendTypeInfo with the given backend type name exists in this mapping.
+ /// </summary>
+ public Boolean ContainsName(String Name)
+ {
+ return NameIndex.ContainsKey(Name);
+ }
+ }
+
+
+
+ /// <summary>
+ /// Provide mapping between type Type, NpgsqlDbType and a NpgsqlNativeTypeInfo object that represents it.
+ /// </summary>
+ internal class NpgsqlNativeTypeMapping
+ {
+ private Hashtable NameIndex;
+ private Hashtable NpgsqlDbTypeIndex;
+ private Hashtable DbTypeIndex;
+ private Hashtable TypeIndex;
+
+ /// <summary>
+ /// Construct an empty mapping.
+ /// </summary>
+ public NpgsqlNativeTypeMapping()
+ {
+ NameIndex = new Hashtable();
+ NpgsqlDbTypeIndex = new Hashtable();
+ DbTypeIndex = new Hashtable();
+ TypeIndex = new Hashtable();
+ }
+
+ /// <summary>
+ /// Add the given NpgsqlNativeTypeInfo to this mapping.
+ /// </summary>
+ public void AddType(NpgsqlNativeTypeInfo T)
+ {
+ if (NameIndex.Contains(T.Name)) {
+ throw new Exception("Type already mapped");
+ }
+
+ NameIndex[T.Name] = T;
+ NpgsqlDbTypeIndex[T.NpgsqlDbType] = T;
+ DbTypeIndex[T.DbType] = T;
+ }
+
+ /// <summary>
+ /// Add a new NpgsqlNativeTypeInfo with the given attributes and conversion handlers to this mapping.
+ /// </summary>
+ /// <param name="OID">Type OID provided by the backend server.</param>
+ /// <param name="Name">Type name provided by the backend server.</param>
+ /// <param name="NpgsqlDbType">NpgsqlDbType</param>
+ /// <param name="ConvertBackendToNative">Data conversion handler.</param>
+ /// <param name="ConvertNativeToBackend">Data conversion handler.</param>
+ public void AddType(String Name, NpgsqlDbType NpgsqlDbType, DbType DbType, Boolean Quote,
+ ConvertNativeToBackendHandler NativeConvert)
+ {
+ AddType(new NpgsqlNativeTypeInfo(Name, NpgsqlDbType, DbType, Quote, NativeConvert));
+ }
+
+ public void AddNpgsqlDbTypeAlias(String Name, NpgsqlDbType NpgsqlDbType)
+ {
+ if (NpgsqlDbTypeIndex.Contains(NpgsqlDbType)) {
+ throw new Exception("NpgsqlDbType already aliased");
+ }
+
+ NpgsqlDbTypeIndex[NpgsqlDbType] = NameIndex[Name];
+ }
+
+ public void AddDbTypeAlias(String Name, DbType DbType)
+ {
+ if (DbTypeIndex.Contains(DbType)) {
+ throw new Exception("NpgsqlDbType already aliased");
+ }
+
+ DbTypeIndex[DbType] = NameIndex[Name];
+ }
+
+ public void AddTypeAlias(String Name, Type Type)
+ {
+ if (TypeIndex.Contains(Type)) {
+ throw new Exception("Type already aliased");
+ }
+
+ TypeIndex[Type] = NameIndex[Name];
+ }
+
+ /// <summary>
+ /// Get the number of type infos held.
+ /// </summary>
+ public Int32 Count
+ { get { return NameIndex.Count; } }
+
+ /// <summary>
+ /// Retrieve the NpgsqlNativeTypeInfo with the given backend type name, or null if none found.
+ /// </summary>
+ public NpgsqlNativeTypeInfo this [String Name]
+ {
+ get
+ {
+ return (NpgsqlNativeTypeInfo)NameIndex[Name];
+ }
+ }
+
+ /// <summary>
+ /// Retrieve the NpgsqlNativeTypeInfo with the given NpgsqlDbType, or null if none found.
+ /// </summary>
+ public NpgsqlNativeTypeInfo this [NpgsqlDbType NpgsqlDbType]
+ {
+ get
+ {
+ return (NpgsqlNativeTypeInfo)NpgsqlDbTypeIndex[NpgsqlDbType];
+ }
+ }
+
+ /// <summary>
+ /// Retrieve the NpgsqlNativeTypeInfo with the given DbType, or null if none found.
+ /// </summary>
+ public NpgsqlNativeTypeInfo this [DbType DbType]
+ {
+ get
+ {
+ return (NpgsqlNativeTypeInfo)DbTypeIndex[DbType];
+ }
+ }
+
+
+
+ /// <summary>
+ /// Retrieve the NpgsqlNativeTypeInfo with the given Type, or null if none found.
+ /// </summary>
+ public NpgsqlNativeTypeInfo this [Type Type]
+ {
+ get
+ {
+ return (NpgsqlNativeTypeInfo)TypeIndex[Type];
+ }
+ }
+
+ /// <summary>
+ /// Determine if a NpgsqlNativeTypeInfo with the given backend type name exists in this mapping.
+ /// </summary>
+ public Boolean ContainsName(String Name)
+ {
+ return NameIndex.ContainsKey(Name);
+ }
+
+ /// <summary>
+ /// Determine if a NpgsqlNativeTypeInfo with the given NpgsqlDbType exists in this mapping.
+ /// </summary>
+ public Boolean ContainsNpgsqlDbType(NpgsqlDbType NpgsqlDbType)
+ {
+ return NpgsqlDbTypeIndex.ContainsKey(NpgsqlDbType);
+ }
+
+ /// <summary>
+ /// Determine if a NpgsqlNativeTypeInfo with the given Type name exists in this mapping.
+ /// </summary>
+ public Boolean ContainsType(Type Type)
+ {
+ return TypeIndex.ContainsKey(Type);
+ }
+ }
+}