Просмотр исходного кода

2002-05-04 Daniel Morgan <[email protected]>

	* System.Data.SqlClient/PostgresLibrary.cs
	* System.Data.SqlClient/SqlCommand.cs
	* System.Data.SqlClient/SqlConnection.cs
	* System.Data.SqlClient/SqlDataReader.cs
	oid should not be hard coded because they
	can change from one version of PostgreSQL
	to the next.  Use the typname's instead.
	The PostgreSQL type data retrieves
	at database connection time.  Any unimplemented
	types just default to string.  These were things
	suggested by Gonzalo.

	* Test/ReadPostgresData.cs - stuff
	* Test/TestSqlDataReader.cs - stuff

	* System.Data.SqlTypes/SqlInt32.cs - added a using

svn path=/trunk/mcs/; revision=4281
Daniel Morgan 24 лет назад
Родитель
Сommit
0410d300b8

+ 66 - 58
mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/PgSqlCommand.cs

@@ -5,7 +5,18 @@
 //   Rodrigo Moya ([email protected])
 //   Daniel Morgan ([email protected])
 //
-// (C) Ximian, Inc 2002
+// (C) Ximian, Inc 2002 http://www.ximian.com/
+// (C) Daniel Morgan, 2002
+//
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
 //
 
 // use #define DEBUG_SqlCommand if you want to spew debug messages
@@ -18,15 +29,13 @@ using System.Data.Common;
 using System.Runtime.InteropServices;
 using System.Xml;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	/// <summary>
 	/// Represents a SQL statement that is executed 
 	/// while connected to a SQL database.
 	/// </summary>
 	// public sealed class SqlCommand : Component, IDbCommand, ICloneable
-	public sealed class SqlCommand : IDbCommand
-	{
+	public sealed class SqlCommand : IDbCommand {
 		// FIXME: Console.WriteLine() is used for debugging throughout
 
 		#region Fields
@@ -47,25 +56,21 @@ namespace System.Data.SqlClient
 
 		#region Constructors
 
-		public SqlCommand()
-		{
+		public SqlCommand() {
 			sql = "";
 		}
 
-		public SqlCommand (string cmdText)
-		{
+		public SqlCommand (string cmdText) {
 			sql = cmdText;
 		}
 
-		public SqlCommand (string cmdText, SqlConnection connection)
-		{
+		public SqlCommand (string cmdText, SqlConnection connection) {
 			sql = cmdText;
 			conn = connection;
 		}
 
 		public SqlCommand (string cmdText, SqlConnection connection, 
-						SqlTransaction transaction)
-		{
+			SqlTransaction transaction) {
 			sql = cmdText;
 			conn = connection;
 			trans = transaction;
@@ -76,27 +81,23 @@ namespace System.Data.SqlClient
 		#region Methods
 
 		[MonoTODO]
-		public void Cancel ()
-		{
+		public void Cancel () {
 			// FIXME: use non-blocking Exec for this
 			throw new NotImplementedException ();
 		}
 
 		// FIXME: is this the correct way to return a stronger type?
 		[MonoTODO]
-		IDbDataParameter IDbCommand.CreateParameter ()
-		{
+		IDbDataParameter IDbCommand.CreateParameter () {
 			return CreateParameter ();
 		}
 
 		[MonoTODO]
-		public SqlParameter CreateParameter ()
-		{
+		public SqlParameter CreateParameter () {
 			return new SqlParameter ();
 		}
 
-		public int ExecuteNonQuery ()
-		{	
+		public int ExecuteNonQuery () {	
 			IntPtr pgResult; // PGresult
 			int rowsAffected = -1;
 			ExecStatusType execStatus;
@@ -117,11 +118,10 @@ namespace System.Data.SqlClient
 			pgResult = PostgresLibrary.
 				PQexec (conn.PostgresConnection, sql);
 
-                        execStatus = PostgresLibrary.
-					PQresultStatus (pgResult);
+			execStatus = PostgresLibrary.
+				PQresultStatus (pgResult);
 			
-			if(execStatus == ExecStatusType.PGRES_COMMAND_OK)
-			{
+			if(execStatus == ExecStatusType.PGRES_COMMAND_OK) {
 				rowsAffectedString = PostgresLibrary.
 					PQcmdTuples (pgResult);
 
@@ -131,8 +131,7 @@ namespace System.Data.SqlClient
 
 				PostgresLibrary.PQclear (pgResult);
 			}
-			else
-			{
+			else {
 				String errorMessage;
 				
 				errorMessage = PostgresLibrary.
@@ -142,35 +141,31 @@ namespace System.Data.SqlClient
 					PQresultErrorMessage(pgResult);
 				
 				throw new SqlException(0, 0,
-						  errorMessage, 0, "",
-						  conn.DataSource, "SqlCommand", 0);
+					errorMessage, 0, "",
+					conn.DataSource, "SqlCommand", 0);
 			}
 			
 			return rowsAffected;
 		}
 		
 		[MonoTODO]
-		IDataReader IDbCommand.ExecuteReader ()
-		{
+		IDataReader IDbCommand.ExecuteReader () {
 			return ExecuteReader ();
 		}
 
 		[MonoTODO]
-		SqlDataReader ExecuteReader ()
-		{
+		public SqlDataReader ExecuteReader () {
 			return ExecuteReader(CommandBehavior.Default);
 		}
 
 		[MonoTODO]
 		IDataReader IDbCommand.ExecuteReader (
-					CommandBehavior behavior)
-		{
+			CommandBehavior behavior) {
 			return ExecuteReader (behavior);
 		}
 
 		[MonoTODO]
-		public SqlDataReader ExecuteReader (CommandBehavior behavior)
-		{
+		public SqlDataReader ExecuteReader (CommandBehavior behavior) {
 			// FIXME: currently only works for a 
 			//        single result set
 			//        ExecuteReader can be used 
@@ -201,15 +196,15 @@ namespace System.Data.SqlClient
 			if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
 				DataTable dt = null;
 				int rows, cols;
-				int[] oids;
+				string[] types;
 				
 				// FIXME: maybe i should move the
 				//        BuildTableSchema code
 				//        to the SqlDataReader?
 				dt = BuildTableSchema(pgResult, 
-					out rows, out cols, out oids);
+					out rows, out cols, out types);
 				dataReader = new SqlDataReader(this, dt, pgResult,
-					rows, cols, oids);
+					rows, cols, types);
 			}
 			else {
 				String errorMessage;
@@ -229,9 +224,9 @@ namespace System.Data.SqlClient
 		}
 
 		internal DataTable BuildTableSchema (IntPtr pgResult, 
-					out int nRows, 
-					out int nFields, 
-					out int[] oids) {
+			out int nRows, 
+			out int nFields, 
+			out string[] types) {
 
 			int nCol;
 			
@@ -243,18 +238,24 @@ namespace System.Data.SqlClient
 			nFields = PostgresLibrary.
 				PQnfields(pgResult);
 			
-			oids = new int[nFields];
+			int oid;
+			types = new string[nFields];
 
 			for(nCol = 0; nCol < nFields; nCol++) {						
+				
+				DbType dbType;
+
 				// get column name
 				String fieldName;
 				fieldName = PostgresLibrary.
 					PQfname(pgResult, nCol);
 
 				// get PostgreSQL data type (OID)
-				oids[nCol] = PostgresLibrary.
+				oid = PostgresLibrary.
 					PQftype(pgResult, nCol);
-
+				types[nCol] = PostgresHelper.
+					OidToTypname (oid, conn.Types);
+				
 				int definedSize;
 				// get defined size of column
 				definedSize = PostgresLibrary.
@@ -262,7 +263,11 @@ namespace System.Data.SqlClient
 								
 				// build the data column and add it the table
 				DataColumn dc = new DataColumn(fieldName);
-				dc.DataType = PostgresHelper.OidToType(oids[nCol]);
+
+				dbType = PostgresHelper.
+						TypnameToSqlDbType(types[nCol]);
+				dc.DataType = PostgresHelper.
+						DbTypeToSystemType(dbType);
 				dc.MaxLength = definedSize;
 				dc.SetTable(dt);
 				
@@ -272,8 +277,7 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public object ExecuteScalar ()
-		{
+		public object ExecuteScalar () {
 			IntPtr pgResult; // PGresult
 			ExecStatusType execStatus;	
 			object obj = null; // return
@@ -316,9 +320,15 @@ namespace System.Data.SqlClient
 					//	PQfname(pgResult, nCol);
 
 					int oid;
+					string sType;
+					DbType dbType;
 					// get PostgreSQL data type (OID)
 					oid = PostgresLibrary.
 						PQftype(pgResult, nCol);
+					sType = PostgresHelper.
+						OidToTypname (oid, conn.Types);
+					dbType = PostgresHelper.
+						TypnameToSqlDbType(sType);
 
 					int definedSize;
 					// get defined size of column
@@ -344,7 +354,9 @@ namespace System.Data.SqlClient
 						nRow, nCol);
 						
 					obj = PostgresHelper.
-						ConvertPgTypeToSystem (oid, value);
+						ConvertDbTypeToSystem (
+						dbType,
+						value);
 				}
 
 				// close result set
@@ -369,21 +381,18 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public XmlReader ExecuteXmlReader ()
-		{
+		public XmlReader ExecuteXmlReader () {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public void Prepare ()
-		{
+		public void Prepare () {
 			// FIXME: parameters have to be implemented for this
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public SqlCommand Clone ()
-		{
+		public SqlCommand Clone () {
 			throw new NotImplementedException ();
 		}
 
@@ -538,8 +547,7 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		~SqlCommand()
-		{
+		~SqlCommand() {
 			// FIXME: need proper way to release resources
 			// Dispose(false);
 		}

+ 191 - 65
mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/PgSqlConnection.cs

@@ -6,20 +6,31 @@
 //   Daniel Morgan ([email protected])
 //
 // (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
+//
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
 //
 
 // use #define DEBUG_SqlConnection if you want to spew debug messages
 // #define DEBUG_SqlConnection
 
 using System;
+using System.Collections;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
 using System.Runtime.InteropServices;
 using System.Text;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	// using PGconn = IntPtr; 
 	// PGconn is native C library type in libpq for Postgres Connection
 
@@ -31,13 +42,14 @@ namespace System.Data.SqlClient
 	/// </summary>
 	//public sealed class SqlConnection : Component, IDbConnection,
 	//	ICloneable
-	public sealed class SqlConnection : IDbConnection
-	{
+
+	public sealed class SqlConnection : IDbConnection {
 		// FIXME: Need to implement class Component, 
 		// and interfaces: ICloneable and IDisposable	
 
 		#region Fields
 
+		private PostgresTypes types;
 		private IntPtr pgConn = IntPtr.Zero;    
 		// PGConn (Postgres Connection)
 		private string connectionString = "";    
@@ -103,14 +115,12 @@ namespace System.Data.SqlClient
 		*/
 		// A lot of the defaults were initialized in the Fields
 		[MonoTODO]
-		public SqlConnection ()
-		{
+		public SqlConnection () {
 
 		}
 	
 		[MonoTODO]
-		public SqlConnection (String connectionString)
-		{
+		public SqlConnection (String connectionString) {
 			SetConnectionString (connectionString);
 		}
 
@@ -128,8 +138,7 @@ namespace System.Data.SqlClient
 		// aka Finalize
 		// [ClassInterface(ClassInterfaceType.AutoDual)]
 		[MonoTODO]
-		~SqlConnection()
-		{
+		~SqlConnection() {
 			// FIXME: this class need 
 			//        a destructor to release resources
 			//        Also, take a look at Dispose
@@ -140,24 +149,20 @@ namespace System.Data.SqlClient
 
 		#region Public Methods
 
-		IDbTransaction IDbConnection.BeginTransaction ()
-		{
+		IDbTransaction IDbConnection.BeginTransaction () {
 			return BeginTransaction ();
 		}
 
-		public SqlTransaction BeginTransaction ()
-		{
+		public SqlTransaction BeginTransaction () {
 			return TransactionBegin (); // call private method
 		}
 
 		IDbTransaction IDbConnection.BeginTransaction (IsolationLevel 
-						il)
-		{
+			il) {
 			return BeginTransaction (il);
 		}
 
-		public SqlTransaction BeginTransaction (IsolationLevel il)
-		{
+		public SqlTransaction BeginTransaction (IsolationLevel il) {
 			return TransactionBegin (il); // call private method
 		}
 
@@ -170,54 +175,37 @@ namespace System.Data.SqlClient
 
 		[Obsolete]
 		public SqlTransaction BeginTransaction(IsolationLevel iso,
-						string transactionName) {
+			string transactionName) {
 			return TransactionBegin (iso); // call private method
 		}
 
 		[MonoTODO]
-		public void ChangeDatabase (string databaseName)
-		{
+		public void ChangeDatabase (string databaseName) {
 			throw new NotImplementedException ();
 		}
 				
 		[MonoTODO]
-		public void Close ()
-		{
+		public void Close () {
 			CloseDataSource ();
 		}
 
-		IDbCommand IDbConnection.CreateCommand ()
-		{
+		IDbCommand IDbConnection.CreateCommand () {
 			return CreateCommand ();
 		}
 
-		public SqlCommand CreateCommand ()
-		{
+		public SqlCommand CreateCommand () {
 			SqlCommand sqlcmd = new SqlCommand ("", this);
 
 			return sqlcmd;
 		}
 
 		[MonoTODO]
-		public void Open ()
-		{
+		public void Open () {
 			OpenDataSource ();
 		}
 
 		#endregion // Public Methods
 
-		#region Internal Methods
-
-		// this is for System.Data.SqlClient classes
-		// to get the Postgres connection
-		internal IntPtr PostgresConnection {
-			get {
-				return pgConn;
-			}
-		}
-
-		#endregion // Internal Methods
-
 		#region Protected Methods
 
 		// FIXME: protected override void Dispose overrides Component
@@ -234,8 +222,7 @@ namespace System.Data.SqlClient
 
 		#region Private Methods
 
-		private void OpenDataSource ()
-		{
+		private void OpenDataSource () {
 			if(dbname.Equals(""))
 				throw new InvalidOperationException(
 					"dbname missing");
@@ -250,7 +237,7 @@ namespace System.Data.SqlClient
 			//        otherwise, throw an exception
 
 			pgConn = PostgresLibrary.PQconnectdb 
-					(pgConnectionString);
+				(pgConnectionString);
 
 			// FIXME: should we use PQconnectStart/PQconnectPoll
 			//        instead of PQconnectdb?  
@@ -258,13 +245,14 @@ namespace System.Data.SqlClient
 			// PQconnectStart/PQconnectPoll is non-blocking
 			
 			connStatus = PostgresLibrary.PQstatus (pgConn);
-			if(connStatus == ConnStatusType.CONNECTION_OK)
-			{
+			if(connStatus == ConnStatusType.CONNECTION_OK) {
 				// Successfully Connected
 				conState = ConnectionState.Open;
+				// FIXME: load types into hashtable
+				types = new PostgresTypes(this);
+				types.Load();
 			}
-			else
-			{
+			else {
 				String errorMessage = PostgresLibrary.
 					PQerrorMessage (pgConn);
 				errorMessage += ": Could not connect to database.";
@@ -275,22 +263,20 @@ namespace System.Data.SqlClient
 			}
 		}
 
-		private void CloseDataSource ()
-		{
+		private void CloseDataSource () {
 			// FIXME: just a quick hack
 			conState = ConnectionState.Closed;
 			PostgresLibrary.PQfinish (pgConn);
 		}
 
-		private void SetConnectionString (string connectionString)
-		{
+		private void SetConnectionString (string connectionString) {
 			// FIXME: perform error checking on string
 			// while translating string from 
 			// OLE DB format to PostgreSQL 
 			// connection string format
 			//
-	//     OLE DB: "host=localhost;dbname=test;user=joe;password=smoe"
-	// PostgreSQL: "host=localhost dbname=test user=joe password=smoe"
+			//     OLE DB: "host=localhost;dbname=test;user=joe;password=smoe"
+			// PostgreSQL: "host=localhost dbname=test user=joe password=smoe"
 			//
 			// For OLE DB, you would have the additional 
 			// "provider=postgresql"
@@ -320,8 +306,7 @@ namespace System.Data.SqlClient
 		}
 
 		private String ConvertStringToPostgres (String 
-			oleDbConnectionString)
-		{
+			oleDbConnectionString) {
 			StringBuilder postgresConnection = 
 				new StringBuilder();
 			string result;
@@ -355,15 +340,14 @@ namespace System.Data.SqlClient
 					BreakConnectionParameter (sParameter);
 					postgresConnection.
 						Append (sParameter + 
-							" ");
+						" ");
 				}
 			}
 			result = postgresConnection.ToString ();
 			return result;
 		}
 
-		private bool BreakConnectionParameter (String sParameter)
-		{	
+		private bool BreakConnectionParameter (String sParameter) {	
 			bool addParm = true;
 			int index;
 
@@ -402,7 +386,7 @@ namespace System.Data.SqlClient
 
 				case "password":
 					password = parmValue;
-				//	addParm = false;
+					//	addParm = false;
 					break;
 
 				case "options":
@@ -421,8 +405,7 @@ namespace System.Data.SqlClient
 			return addParm;
 		}
 
-		private SqlTransaction TransactionBegin ()
-		{
+		private SqlTransaction TransactionBegin () {
 			// FIXME: need to keep track of 
 			// transaction in-progress
 			trans = new SqlTransaction ();
@@ -433,8 +416,7 @@ namespace System.Data.SqlClient
 			return trans;
 		}
 
-		private SqlTransaction TransactionBegin (IsolationLevel il)
-		{
+		private SqlTransaction TransactionBegin (IsolationLevel il) {
 			// FIXME: need to keep track of 
 			// transaction in-progress
 			TransactionBegin();
@@ -445,7 +427,7 @@ namespace System.Data.SqlClient
 
 		#endregion
 
-		#region Properties
+		#region Public Properties
 
 		[MonoTODO]
 		public ConnectionState State 		{
@@ -502,12 +484,30 @@ namespace System.Data.SqlClient
 			}
 		}
 
+		#region Internal Properties
+
 		internal SqlTransaction Transaction {
 			get {
 				return trans;
 			}
 		}
 
+		// this is for System.Data.SqlClient classes
+		// to get the Postgres connection
+		internal IntPtr PostgresConnection {
+			get {
+				return pgConn;
+			}
+		}
+
+		internal ArrayList Types {
+			get {
+				return types.List;
+			}
+		}
+
+		#endregion // Internal Properties
+
 		#endregion
 
 		#region Events and Delegates
@@ -528,5 +528,131 @@ namespace System.Data.SqlClient
 		*/
 
 		#endregion
+
+		#region Classes
+
+		private class PostgresTypes {
+			// TODO: create hashtable for 
+			// PostgreSQL types to .NET types
+			// containing: oid, typname, SqlDbType
+
+			private Hashtable hashTypes;
+			private ArrayList pgTypes;
+			private SqlConnection con;
+
+			// Got this SQL with the permission from 
+			// the authors of libgda
+			private const string SEL_SQL_GetTypes = 
+				"SELECT oid, typname FROM pg_type " +
+				"WHERE typrelid = 0 AND typname !~ '^_' " +
+				" AND  typname not in ('SET', 'cid', " +
+				"'int2vector', 'oidvector', 'regproc', " +
+				"'smgr', 'tid', 'unknown', 'xid') " +
+				"ORDER BY typname";
+
+			internal PostgresTypes(SqlConnection sqlcon) {
+				
+				con = sqlcon;
+				hashTypes = new Hashtable();
+			}
+
+			private void BuildTypes(IntPtr pgResult, 
+				int nRows, int nFields) {
+
+				String value;
+
+				int r, c;
+				for(r = 0; r < nRows; r++) {
+					PostgresType pgType = 
+						new PostgresType();
+
+					for(c = 0; c < nFields; c++) {
+						// get data value
+						value = PostgresLibrary.
+							PQgetvalue(
+							pgResult,
+							r, c);
+						
+						if(c == 0) {
+							pgType.oid = Int32.Parse(value);
+						}
+						else if(c == 1) {
+							pgType.typname = String.Copy(value);
+							pgType.dbType = PostgresHelper.
+								TypnameToSqlDbType(
+								pgType.typname);
+
+							pgTypes.Add(pgType);
+						}
+						// FIXME: needs to be Read Only
+						// pgTypes = ArrayList.ReadOnly(pgTypes);
+
+					}
+				}
+			}
+
+			internal void Load() {
+				pgTypes = new ArrayList();
+				IntPtr pgResult; // PGresult
+				ExecStatusType execStatus;	
+
+				if(con.State != ConnectionState.Open)
+					throw new InvalidOperationException(
+						"ConnnectionState is not Open");
+
+				// FIXME: PQexec blocks 
+				// while PQsendQuery is non-blocking
+				// which is better to use?
+				// int PQsendQuery(PGconn *conn,
+				//        const char *query);
+
+				// execute SQL command
+				// uses internal property to get the PGConn IntPtr
+				pgResult = PostgresLibrary.
+					PQexec (con.PostgresConnection, SEL_SQL_GetTypes);
+
+				execStatus = PostgresLibrary.
+					PQresultStatus (pgResult);
+			
+				if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
+					int nRows;
+					int nFields;
+
+					nRows = PostgresLibrary.
+						PQntuples(pgResult);
+
+					nFields = PostgresLibrary.
+						PQnfields(pgResult);
+
+					BuildTypes (pgResult, nRows, nFields);
+
+					// close result set
+					PostgresLibrary.PQclear (pgResult);
+
+				}
+				else {
+					String errorMessage;
+				
+					errorMessage = PostgresLibrary.
+						PQresStatus(execStatus);
+
+					errorMessage += " " + PostgresLibrary.
+						PQresultErrorMessage(pgResult);
+				
+					throw new SqlException(0, 0,
+						errorMessage, 0, "",
+						con.DataSource, "SqlConnection", 0);
+				}
+
+			}
+
+			public ArrayList List {
+				get {
+					return pgTypes;
+				}
+			}
+		}
+
+		#endregion
 	}
 }

+ 71 - 78
mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/PgSqlDataReader.cs

@@ -6,14 +6,25 @@
 //   Daniel Morgan ([email protected])
 //
 // (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
 //
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
+//
+
 using System;
 using System.Collections;
 using System.ComponentModel;
 using System.Data;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	/// <summary>
 	/// Provides a means of reading one or more forward-only streams
 	/// of result sets obtained by executing a command 
@@ -22,15 +33,15 @@ namespace System.Data.SqlClient
 	//public sealed class SqlDataReader : MarshalByRefObject,
 	//	IEnumerable, IDataReader, IDisposable, IDataRecord
 	public sealed class SqlDataReader : IEnumerable, 
-		IDataReader, IDataRecord
-	{
+		IDataReader, IDataRecord {
 		#region Fields
 
 		private SqlCommand cmd;
 		private DataTable table;
 
 		private object[] fields;
-		private int[] oid; // PostgreSQL Type
+		private string[] types; // PostgreSQL Type
+		private bool[] isNull;
 				
 		private bool open = false;
 		IntPtr pgResult; // PGresult
@@ -45,14 +56,15 @@ namespace System.Data.SqlClient
 
 		internal SqlDataReader (SqlCommand sqlCmd, 
 			DataTable dataTableSchema, IntPtr pg_result,
-			int rowCount, int fieldCount, int[] oids) {
+			int rowCount, int fieldCount, string[] pgtypes) {
 
 			cmd = sqlCmd;
 			table = dataTableSchema;
 			pgResult = pg_result;
 			rows = rowCount;
 			cols = fieldCount;
-			oid = oids;
+			types = pgtypes;
+			open = true;
 		}
 
 		#endregion
@@ -60,31 +72,28 @@ namespace System.Data.SqlClient
 		#region Public Methods
 
 		[MonoTODO]
-		public void Close()
-		{
+		public void Close() {
 			// close result set
 			PostgresLibrary.PQclear (pgResult);
-
+			open = false;
 			// TODO: change busy state on SqlConnection to not busy
 		}
 
 		[MonoTODO]
-		public DataTable GetSchemaTable()
-		{
+		public DataTable GetSchemaTable() {
 			return table;
 		}
 
 		[MonoTODO]
-		public bool NextResult()
-		{
+		public bool NextResult() {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool Read()
-	        {
+		public bool Read() {
 			string value;
 			fields = new object[cols]; // re-init row
+			DbType dbType;
 
 			if(currentRow < rows - 1)  {
 				currentRow++;
@@ -109,8 +118,13 @@ namespace System.Data.SqlClient
 						PQgetlength(pgResult,
 						currentRow, c);
 						
+					dbType = PostgresHelper.
+						TypnameToSqlDbType(types[c]);
+
 					fields[c] = PostgresHelper.
-						ConvertPgTypeToSystem (oid[c], value);
+						ConvertDbTypeToSystem (
+							dbType,
+							value);
 				}
 				return true;
 			}
@@ -118,139 +132,117 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public byte GetByte(int i)
-		{
+		public byte GetByte(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
 		public long GetBytes(int i, long fieldOffset, 
 			byte[] buffer, int bufferOffset, 
-			int length)
-		{
+			int length) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public char GetChar(int i)
-		{
+		public char GetChar(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
 		public long GetChars(int i, long fieldOffset, 
 			char[] buffer, int bufferOffset, 
-			int length)
-		{
+			int length) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public IDataReader GetData(int i)
-		{
+		public IDataReader GetData(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public string GetDataTypeName(int i)
-		{
+		public string GetDataTypeName(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public DateTime GetDateTime(int i)
-		{
+		public DateTime GetDateTime(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public decimal GetDecimal(int i)
-		{
-			throw new NotImplementedException ();
+		public decimal GetDecimal(int i) {
+			return (decimal) fields[i];
 		}
 
 		[MonoTODO]
-		public double GetDouble(int i)
-		{
-			throw new NotImplementedException ();
+		public double GetDouble(int i) {
+			return (double) fields[i];
 		}
 
 		[MonoTODO]
-		public Type GetFieldType(int i)
-		{
+		public Type GetFieldType(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public float GetFloat(int i)
-		{
-			throw new NotImplementedException ();
+		public float GetFloat(int i) {
+			return (float) fields[i];
 		}
 
 		[MonoTODO]
-		public Guid GetGuid(int i)
-		{
+		public Guid GetGuid(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public short GetInt16(int i)
-		{
+		public short GetInt16(int i) {
 			return (short) fields[i];
 		}
 
 		[MonoTODO]
-		public int GetInt32(int i)
-		{
+		public int GetInt32(int i) {
 			return (int) fields[i];
 		}
 
 		[MonoTODO]
-		public long GetInt64(int i)
-		{
+		public long GetInt64(int i) {
 			return (long) fields[i];
 		}
 
 		[MonoTODO]
-		public string GetName(int i)
-		{
+		public string GetName(int i) {
 			return table.Columns[i].ColumnName;
 		}
 
 		[MonoTODO]
-		public int GetOrdinal(string name)
-		{
+		public int GetOrdinal(string name) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public string GetString(int i)
-		{
+		public string GetString(int i) {
 			return (string) fields[i];
 		}
 
 		[MonoTODO]
-		public object GetValue(int i)
-		{
+		public object GetValue(int i) {
 			return fields[i];
 		}
 
 		[MonoTODO]
-		public int GetValues(object[] values)
-		{
+		public int GetValues(object[] values) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool IsDBNull(int i)
-		{
+		public bool IsDBNull(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool GetBoolean(int i)
-		{
-			throw new NotImplementedException ();
+		public bool GetBoolean(int i) {
+			return (bool) fields[i];
 		}
 
 		[MonoTODO]
@@ -284,7 +276,10 @@ namespace System.Data.SqlClient
 		public bool IsClosed {
 			[MonoTODO]
 			get {
-				throw new NotImplementedException (); 
+				if(open == false)
+					return true;
+				else
+					return false;
 			}
 		}
 
@@ -312,28 +307,26 @@ namespace System.Data.SqlClient
 					}
 
 				}
-				
-				if(i == cols) {
-					for(i = 0; i < cols; i++) {
-						string ta;
-						string n;
+	
+				for(i = 0; i < cols; i++) {
+					string ta;
+					string n;
 						
-						ta = table.Columns[i].ColumnName.ToUpper();
-						n = name.ToUpper();
+					ta = table.Columns[i].ColumnName.ToUpper();
+					n = name.ToUpper();
 						
-						if(ta.Equals(n)) {
-							return fields[i];
-						}
+					if(ta.Equals(n)) {
+						return fields[i];
 					}
 				}
+			
 				throw new MissingFieldException("Missing field: " + name);
 			}
 		}
 
 		public object this[int i] {
 			[MonoTODO]
-			get 
-			{ 
+			get { 
 				return fields[i];
 			}
 		}

+ 234 - 80
mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/PostgresLibrary.cs

@@ -18,52 +18,11 @@ using System;
 using System.Data;
 using System.Runtime.InteropServices;
 using System.Diagnostics;
+using System.Collections;
 
 namespace System.Data.SqlClient {
 
-	// PostgreSQL Type (oid and typname from pg_type)
-	internal enum PgType {
-		ABSTIME = 702,
-		ACLITEM = 1033,
-		BIT = 1560,
-		BOOL = 16,
-		BOX = 603,
-		BPCHAR = 1042,
-		BYTEA = 17,
-		CHAR = 18,
-		CIDR = 650,
-		CIRCLE = 718,
-		DATE = 1082,
-		FLOAT4 = 700,
-		FLOAT8 = 701,
-		INET = 869,
-		INT2 = 21,
-		INT4 = 23,
-		INT8 = 20,
-		INTERVAL = 1186,
-		LINE = 628,
-		LSEG = 601,
-		MACADDR = 829,
-		MONEY = 790,
-		NAME = 19,
-		NUMERIC = 1700,
-		OID = 26,
-		PATH = 602,
-		POINT = 600,
-		POLYGON = 604,
-		REFCURSOR = 1790,
-		RELTIME = 703,
-		TEXT = 25,
-		TIME = 1083,
-		TIMESTAMP = 1114,
-		TIMESTAMPTZ = 1184,
-		TIMETZ = 1266,
-		TINTERVAL = 704,
-		VARBIT = 1562,
-		VARCHAR = 1043
-	}
-
-	/* IMPORTANT: DO NOT CHANGE ANY OF THESE ENUMS */
+	/* IMPORTANT: DO NOT CHANGE ANY OF THESE ENUMS BELOW */
 	
 	internal enum ConnStatusType
 	{
@@ -97,15 +56,181 @@ namespace System.Data.SqlClient {
 		PGRES_FATAL_ERROR
 	}
 
+	internal struct PostgresType {
+		public int oid;
+		public string typname;
+		public DbType dbType;
+	}
+
 	sealed internal class PostgresHelper {
 
-		/// <summary>
-		/// Convert a PostgreSQL Type to a .NET System type.
-		/// </summary>
-		/// <param name="oid"></param>
-		/// <param name="value"></param>
-		/// <returns></returns>
-		public static object ConvertPgTypeToSystem (int oid, String value) {
+		// translates the PostgreSQL typname to System.Data.DbType
+		public static DbType TypnameToSqlDbType(string typname) {
+			DbType sqlType;
+			
+			switch(typname) {
+
+			case "abstime":
+				sqlType = DbType.Int32;
+				break;
+
+			case "aclitem":
+				sqlType = DbType.String;
+				break;
+
+			case "bit":
+				sqlType = DbType.String;
+				break;
+
+			case "bool":
+				sqlType = DbType.Boolean;
+				break;
+
+			case "box":
+				sqlType = DbType.String;
+				break;
+
+			case "bpchar":
+				sqlType = DbType.String;
+				break;
+
+			case "bytea":
+				sqlType = DbType.String;
+				break;
+
+			case "char":
+				sqlType = DbType.String;
+				break;
+
+			case "cidr":
+				sqlType = DbType.String;
+				break;
+
+			case "circle":
+				sqlType = DbType.String;
+				break;
+
+			case "date":
+				sqlType = DbType.String;
+				break;
+
+			case "float4":
+				sqlType = DbType.Single;
+				break;
+
+			case "float8":
+				sqlType = DbType.Double;
+				break;
+
+			case "inet":
+				sqlType = DbType.String;
+				break;
+
+			case "int2":
+				sqlType = DbType.Int16;
+				break;
+
+			case "int4":
+				sqlType = DbType.Int32;
+				break;
+
+			case "int8":
+				sqlType = DbType.Int64;
+				break;
+
+			case "interval":
+				sqlType = DbType.String;
+				break;
+
+			case "line":
+				sqlType = DbType.String;
+				break;
+
+			case "lseg":
+				sqlType = DbType.String;
+				break;
+
+			case "macaddr":
+				sqlType = DbType.String;
+				break;
+
+			case "money":
+				sqlType = DbType.Decimal;
+				break;
+
+			case "name":
+				sqlType = DbType.String;
+				break;
+
+			case "numeric":
+				sqlType = DbType.Decimal;
+				break;
+
+			case "oid":
+				sqlType = DbType.Int32;
+				break;
+
+			case "path":
+				sqlType = DbType.String;
+				break;
+
+			case "point":
+				sqlType = DbType.String;
+				break;
+
+			case "polygon":
+				sqlType = DbType.String;
+				break;
+
+			case "refcursor":
+				sqlType = DbType.String;
+				break;
+
+			case "reltime":
+				sqlType = DbType.String;
+				break;
+
+			case "text":
+				sqlType = DbType.String;
+				break;
+
+			case "time":
+				sqlType = DbType.String;
+				break;
+
+			case "timestamp":
+				sqlType = DbType.String;
+				break;
+
+			case "timestamptz":
+				sqlType = DbType.String;
+				break;
+
+			case "timetz":
+				sqlType = DbType.String;
+				break;
+
+			case "tinterval":
+				sqlType = DbType.String;
+				break;
+
+			case "varbit":
+				sqlType = DbType.String;
+				break;
+
+			case "varchar":
+				sqlType = DbType.String;
+				break;
+
+			default:
+				sqlType = DbType.String;
+				break;
+			}
+			return sqlType;
+		}
+		
+		// Converts data value from database to .NET System type.
+		public static object ConvertDbTypeToSystem (DbType typ, String value) {
 			object obj = null;
 
 			// FIXME: more types need 
@@ -113,40 +238,41 @@ namespace System.Data.SqlClient {
 			//        from PostgreSQL oid type
 			//        to .NET System.<type>
 
-			switch((PgType) oid) {
-			case PgType.VARCHAR:
-			case PgType.BPCHAR:
-			case PgType.TEXT:
-			case PgType.CHAR:
+			switch(typ) {
+			case DbType.String:
 				obj = (object) String.Copy(value); 
 				break;
-			case PgType.BOOL:
+			case DbType.Boolean:
 				obj = (object) Boolean.Parse(value);
 				break;
-			case PgType.INT2:
+			case DbType.Int16:
 				obj = (object) Int16.Parse(value);
 				break;
-			case PgType.INT4:
+			case DbType.Int32:
 				obj = (object) Int32.Parse(value);
 				break;
-			case PgType.INT8:
+			case DbType.Int64:
 				obj = (object) Int64.Parse(value);
 				break;
+			case DbType.Decimal:
+				obj = (object) Decimal.Parse(value);
+				break;
+			case DbType.Single:
+				obj = (object) Single.Parse(value);
+				break;
+			case DbType.Double:
+				obj = (object) Double.Parse(value);
+				break;
 			default:
-				throw new NotImplementedException(
-					"PGNI1: PostgreSQL oid data type " + oid +
-					" not mapped to .NET System data type.");
+				obj = (object) String.Copy(value);
+				break;
 			}
 
 			return obj;
 		}
 		
-		/// <summary>
-		/// Convert the PostgreSQL Type oid to the .NET System.Type.
-		/// </summary>
-		/// <param name="oid"></param>
-		/// <returns></returns>
-		public static Type OidToType (int oid) {
+		// Translates System.Data.DbType to System.Type
+		public static Type DbTypeToSystemType (DbType dType) {
 			// FIXME: more types need 
 			//        to be mapped
 			//        from PostgreSQL oid type
@@ -154,32 +280,60 @@ namespace System.Data.SqlClient {
 
 			Type typ = null;
 
-			switch((PgType) oid) {
-			case PgType.VARCHAR:
-			case PgType.BPCHAR:
-			case PgType.TEXT:
-			case PgType.CHAR:
+			switch(dType) {
+			case DbType.String:
 				typ = typeof(String);
 				break;
-			case PgType.BOOL:
+			case DbType.Boolean:
 				typ = typeof(Boolean);
 				break;
-			case PgType.INT2:
+			case DbType.Int16: 
 				typ = typeof(Int16);
 				break;
-			case PgType.INT4:
+			case DbType.Int32:
 				typ = typeof(Int32);
 				break;
-			case PgType.INT8:
+			case DbType.Int64:
 				typ = typeof(Int64);
 				break;
+			case DbType.Decimal:
+				typ = typeof(Decimal);
+				break;
+			case DbType.Single:
+				typ = typeof(Single);
+				break;
+			case DbType.Double:
+				typ = typeof(Double);
+				break;
 			default:
-				throw new NotImplementedException(
-					"PGNI2: PostgreSQL oid type " + oid +
-					" not mapped to .NET System Type.");
+				typ = typeof(String);
+				break;
 			}
 			return typ;
 		}
+
+		// Find DbType for oid
+		// which requires a look up of PostgresTypes
+		// DbType <-> typname <-> oid
+		public static string OidToTypname (int oid, ArrayList pgTypes) {
+			// FIXME: more types need 
+			//        to be mapped
+			//        from PostgreSQL oid type
+			//        to .NET System.<type>
+			
+			string typname = "text"; // default
+			int i;
+			for(i = 0; i < pgTypes.Count; i++) {
+				PostgresType pt = (PostgresType) pgTypes[i];
+				if(pt.oid == oid) {
+					typname = pt.typname;
+					break; 
+				}
+			}
+
+			return typname;
+		}
+
 	}
 
 	sealed internal class PostgresLibrary

+ 66 - 58
mcs/class/Mono.Data.PostgreSqlClient/PgSqlCommand.cs

@@ -5,7 +5,18 @@
 //   Rodrigo Moya ([email protected])
 //   Daniel Morgan ([email protected])
 //
-// (C) Ximian, Inc 2002
+// (C) Ximian, Inc 2002 http://www.ximian.com/
+// (C) Daniel Morgan, 2002
+//
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
 //
 
 // use #define DEBUG_SqlCommand if you want to spew debug messages
@@ -18,15 +29,13 @@ using System.Data.Common;
 using System.Runtime.InteropServices;
 using System.Xml;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	/// <summary>
 	/// Represents a SQL statement that is executed 
 	/// while connected to a SQL database.
 	/// </summary>
 	// public sealed class SqlCommand : Component, IDbCommand, ICloneable
-	public sealed class SqlCommand : IDbCommand
-	{
+	public sealed class SqlCommand : IDbCommand {
 		// FIXME: Console.WriteLine() is used for debugging throughout
 
 		#region Fields
@@ -47,25 +56,21 @@ namespace System.Data.SqlClient
 
 		#region Constructors
 
-		public SqlCommand()
-		{
+		public SqlCommand() {
 			sql = "";
 		}
 
-		public SqlCommand (string cmdText)
-		{
+		public SqlCommand (string cmdText) {
 			sql = cmdText;
 		}
 
-		public SqlCommand (string cmdText, SqlConnection connection)
-		{
+		public SqlCommand (string cmdText, SqlConnection connection) {
 			sql = cmdText;
 			conn = connection;
 		}
 
 		public SqlCommand (string cmdText, SqlConnection connection, 
-						SqlTransaction transaction)
-		{
+			SqlTransaction transaction) {
 			sql = cmdText;
 			conn = connection;
 			trans = transaction;
@@ -76,27 +81,23 @@ namespace System.Data.SqlClient
 		#region Methods
 
 		[MonoTODO]
-		public void Cancel ()
-		{
+		public void Cancel () {
 			// FIXME: use non-blocking Exec for this
 			throw new NotImplementedException ();
 		}
 
 		// FIXME: is this the correct way to return a stronger type?
 		[MonoTODO]
-		IDbDataParameter IDbCommand.CreateParameter ()
-		{
+		IDbDataParameter IDbCommand.CreateParameter () {
 			return CreateParameter ();
 		}
 
 		[MonoTODO]
-		public SqlParameter CreateParameter ()
-		{
+		public SqlParameter CreateParameter () {
 			return new SqlParameter ();
 		}
 
-		public int ExecuteNonQuery ()
-		{	
+		public int ExecuteNonQuery () {	
 			IntPtr pgResult; // PGresult
 			int rowsAffected = -1;
 			ExecStatusType execStatus;
@@ -117,11 +118,10 @@ namespace System.Data.SqlClient
 			pgResult = PostgresLibrary.
 				PQexec (conn.PostgresConnection, sql);
 
-                        execStatus = PostgresLibrary.
-					PQresultStatus (pgResult);
+			execStatus = PostgresLibrary.
+				PQresultStatus (pgResult);
 			
-			if(execStatus == ExecStatusType.PGRES_COMMAND_OK)
-			{
+			if(execStatus == ExecStatusType.PGRES_COMMAND_OK) {
 				rowsAffectedString = PostgresLibrary.
 					PQcmdTuples (pgResult);
 
@@ -131,8 +131,7 @@ namespace System.Data.SqlClient
 
 				PostgresLibrary.PQclear (pgResult);
 			}
-			else
-			{
+			else {
 				String errorMessage;
 				
 				errorMessage = PostgresLibrary.
@@ -142,35 +141,31 @@ namespace System.Data.SqlClient
 					PQresultErrorMessage(pgResult);
 				
 				throw new SqlException(0, 0,
-						  errorMessage, 0, "",
-						  conn.DataSource, "SqlCommand", 0);
+					errorMessage, 0, "",
+					conn.DataSource, "SqlCommand", 0);
 			}
 			
 			return rowsAffected;
 		}
 		
 		[MonoTODO]
-		IDataReader IDbCommand.ExecuteReader ()
-		{
+		IDataReader IDbCommand.ExecuteReader () {
 			return ExecuteReader ();
 		}
 
 		[MonoTODO]
-		SqlDataReader ExecuteReader ()
-		{
+		public SqlDataReader ExecuteReader () {
 			return ExecuteReader(CommandBehavior.Default);
 		}
 
 		[MonoTODO]
 		IDataReader IDbCommand.ExecuteReader (
-					CommandBehavior behavior)
-		{
+			CommandBehavior behavior) {
 			return ExecuteReader (behavior);
 		}
 
 		[MonoTODO]
-		public SqlDataReader ExecuteReader (CommandBehavior behavior)
-		{
+		public SqlDataReader ExecuteReader (CommandBehavior behavior) {
 			// FIXME: currently only works for a 
 			//        single result set
 			//        ExecuteReader can be used 
@@ -201,15 +196,15 @@ namespace System.Data.SqlClient
 			if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
 				DataTable dt = null;
 				int rows, cols;
-				int[] oids;
+				string[] types;
 				
 				// FIXME: maybe i should move the
 				//        BuildTableSchema code
 				//        to the SqlDataReader?
 				dt = BuildTableSchema(pgResult, 
-					out rows, out cols, out oids);
+					out rows, out cols, out types);
 				dataReader = new SqlDataReader(this, dt, pgResult,
-					rows, cols, oids);
+					rows, cols, types);
 			}
 			else {
 				String errorMessage;
@@ -229,9 +224,9 @@ namespace System.Data.SqlClient
 		}
 
 		internal DataTable BuildTableSchema (IntPtr pgResult, 
-					out int nRows, 
-					out int nFields, 
-					out int[] oids) {
+			out int nRows, 
+			out int nFields, 
+			out string[] types) {
 
 			int nCol;
 			
@@ -243,18 +238,24 @@ namespace System.Data.SqlClient
 			nFields = PostgresLibrary.
 				PQnfields(pgResult);
 			
-			oids = new int[nFields];
+			int oid;
+			types = new string[nFields];
 
 			for(nCol = 0; nCol < nFields; nCol++) {						
+				
+				DbType dbType;
+
 				// get column name
 				String fieldName;
 				fieldName = PostgresLibrary.
 					PQfname(pgResult, nCol);
 
 				// get PostgreSQL data type (OID)
-				oids[nCol] = PostgresLibrary.
+				oid = PostgresLibrary.
 					PQftype(pgResult, nCol);
-
+				types[nCol] = PostgresHelper.
+					OidToTypname (oid, conn.Types);
+				
 				int definedSize;
 				// get defined size of column
 				definedSize = PostgresLibrary.
@@ -262,7 +263,11 @@ namespace System.Data.SqlClient
 								
 				// build the data column and add it the table
 				DataColumn dc = new DataColumn(fieldName);
-				dc.DataType = PostgresHelper.OidToType(oids[nCol]);
+
+				dbType = PostgresHelper.
+						TypnameToSqlDbType(types[nCol]);
+				dc.DataType = PostgresHelper.
+						DbTypeToSystemType(dbType);
 				dc.MaxLength = definedSize;
 				dc.SetTable(dt);
 				
@@ -272,8 +277,7 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public object ExecuteScalar ()
-		{
+		public object ExecuteScalar () {
 			IntPtr pgResult; // PGresult
 			ExecStatusType execStatus;	
 			object obj = null; // return
@@ -316,9 +320,15 @@ namespace System.Data.SqlClient
 					//	PQfname(pgResult, nCol);
 
 					int oid;
+					string sType;
+					DbType dbType;
 					// get PostgreSQL data type (OID)
 					oid = PostgresLibrary.
 						PQftype(pgResult, nCol);
+					sType = PostgresHelper.
+						OidToTypname (oid, conn.Types);
+					dbType = PostgresHelper.
+						TypnameToSqlDbType(sType);
 
 					int definedSize;
 					// get defined size of column
@@ -344,7 +354,9 @@ namespace System.Data.SqlClient
 						nRow, nCol);
 						
 					obj = PostgresHelper.
-						ConvertPgTypeToSystem (oid, value);
+						ConvertDbTypeToSystem (
+						dbType,
+						value);
 				}
 
 				// close result set
@@ -369,21 +381,18 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public XmlReader ExecuteXmlReader ()
-		{
+		public XmlReader ExecuteXmlReader () {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public void Prepare ()
-		{
+		public void Prepare () {
 			// FIXME: parameters have to be implemented for this
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public SqlCommand Clone ()
-		{
+		public SqlCommand Clone () {
 			throw new NotImplementedException ();
 		}
 
@@ -538,8 +547,7 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		~SqlCommand()
-		{
+		~SqlCommand() {
 			// FIXME: need proper way to release resources
 			// Dispose(false);
 		}

+ 191 - 65
mcs/class/Mono.Data.PostgreSqlClient/PgSqlConnection.cs

@@ -6,20 +6,31 @@
 //   Daniel Morgan ([email protected])
 //
 // (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
+//
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
 //
 
 // use #define DEBUG_SqlConnection if you want to spew debug messages
 // #define DEBUG_SqlConnection
 
 using System;
+using System.Collections;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
 using System.Runtime.InteropServices;
 using System.Text;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	// using PGconn = IntPtr; 
 	// PGconn is native C library type in libpq for Postgres Connection
 
@@ -31,13 +42,14 @@ namespace System.Data.SqlClient
 	/// </summary>
 	//public sealed class SqlConnection : Component, IDbConnection,
 	//	ICloneable
-	public sealed class SqlConnection : IDbConnection
-	{
+
+	public sealed class SqlConnection : IDbConnection {
 		// FIXME: Need to implement class Component, 
 		// and interfaces: ICloneable and IDisposable	
 
 		#region Fields
 
+		private PostgresTypes types;
 		private IntPtr pgConn = IntPtr.Zero;    
 		// PGConn (Postgres Connection)
 		private string connectionString = "";    
@@ -103,14 +115,12 @@ namespace System.Data.SqlClient
 		*/
 		// A lot of the defaults were initialized in the Fields
 		[MonoTODO]
-		public SqlConnection ()
-		{
+		public SqlConnection () {
 
 		}
 	
 		[MonoTODO]
-		public SqlConnection (String connectionString)
-		{
+		public SqlConnection (String connectionString) {
 			SetConnectionString (connectionString);
 		}
 
@@ -128,8 +138,7 @@ namespace System.Data.SqlClient
 		// aka Finalize
 		// [ClassInterface(ClassInterfaceType.AutoDual)]
 		[MonoTODO]
-		~SqlConnection()
-		{
+		~SqlConnection() {
 			// FIXME: this class need 
 			//        a destructor to release resources
 			//        Also, take a look at Dispose
@@ -140,24 +149,20 @@ namespace System.Data.SqlClient
 
 		#region Public Methods
 
-		IDbTransaction IDbConnection.BeginTransaction ()
-		{
+		IDbTransaction IDbConnection.BeginTransaction () {
 			return BeginTransaction ();
 		}
 
-		public SqlTransaction BeginTransaction ()
-		{
+		public SqlTransaction BeginTransaction () {
 			return TransactionBegin (); // call private method
 		}
 
 		IDbTransaction IDbConnection.BeginTransaction (IsolationLevel 
-						il)
-		{
+			il) {
 			return BeginTransaction (il);
 		}
 
-		public SqlTransaction BeginTransaction (IsolationLevel il)
-		{
+		public SqlTransaction BeginTransaction (IsolationLevel il) {
 			return TransactionBegin (il); // call private method
 		}
 
@@ -170,54 +175,37 @@ namespace System.Data.SqlClient
 
 		[Obsolete]
 		public SqlTransaction BeginTransaction(IsolationLevel iso,
-						string transactionName) {
+			string transactionName) {
 			return TransactionBegin (iso); // call private method
 		}
 
 		[MonoTODO]
-		public void ChangeDatabase (string databaseName)
-		{
+		public void ChangeDatabase (string databaseName) {
 			throw new NotImplementedException ();
 		}
 				
 		[MonoTODO]
-		public void Close ()
-		{
+		public void Close () {
 			CloseDataSource ();
 		}
 
-		IDbCommand IDbConnection.CreateCommand ()
-		{
+		IDbCommand IDbConnection.CreateCommand () {
 			return CreateCommand ();
 		}
 
-		public SqlCommand CreateCommand ()
-		{
+		public SqlCommand CreateCommand () {
 			SqlCommand sqlcmd = new SqlCommand ("", this);
 
 			return sqlcmd;
 		}
 
 		[MonoTODO]
-		public void Open ()
-		{
+		public void Open () {
 			OpenDataSource ();
 		}
 
 		#endregion // Public Methods
 
-		#region Internal Methods
-
-		// this is for System.Data.SqlClient classes
-		// to get the Postgres connection
-		internal IntPtr PostgresConnection {
-			get {
-				return pgConn;
-			}
-		}
-
-		#endregion // Internal Methods
-
 		#region Protected Methods
 
 		// FIXME: protected override void Dispose overrides Component
@@ -234,8 +222,7 @@ namespace System.Data.SqlClient
 
 		#region Private Methods
 
-		private void OpenDataSource ()
-		{
+		private void OpenDataSource () {
 			if(dbname.Equals(""))
 				throw new InvalidOperationException(
 					"dbname missing");
@@ -250,7 +237,7 @@ namespace System.Data.SqlClient
 			//        otherwise, throw an exception
 
 			pgConn = PostgresLibrary.PQconnectdb 
-					(pgConnectionString);
+				(pgConnectionString);
 
 			// FIXME: should we use PQconnectStart/PQconnectPoll
 			//        instead of PQconnectdb?  
@@ -258,13 +245,14 @@ namespace System.Data.SqlClient
 			// PQconnectStart/PQconnectPoll is non-blocking
 			
 			connStatus = PostgresLibrary.PQstatus (pgConn);
-			if(connStatus == ConnStatusType.CONNECTION_OK)
-			{
+			if(connStatus == ConnStatusType.CONNECTION_OK) {
 				// Successfully Connected
 				conState = ConnectionState.Open;
+				// FIXME: load types into hashtable
+				types = new PostgresTypes(this);
+				types.Load();
 			}
-			else
-			{
+			else {
 				String errorMessage = PostgresLibrary.
 					PQerrorMessage (pgConn);
 				errorMessage += ": Could not connect to database.";
@@ -275,22 +263,20 @@ namespace System.Data.SqlClient
 			}
 		}
 
-		private void CloseDataSource ()
-		{
+		private void CloseDataSource () {
 			// FIXME: just a quick hack
 			conState = ConnectionState.Closed;
 			PostgresLibrary.PQfinish (pgConn);
 		}
 
-		private void SetConnectionString (string connectionString)
-		{
+		private void SetConnectionString (string connectionString) {
 			// FIXME: perform error checking on string
 			// while translating string from 
 			// OLE DB format to PostgreSQL 
 			// connection string format
 			//
-	//     OLE DB: "host=localhost;dbname=test;user=joe;password=smoe"
-	// PostgreSQL: "host=localhost dbname=test user=joe password=smoe"
+			//     OLE DB: "host=localhost;dbname=test;user=joe;password=smoe"
+			// PostgreSQL: "host=localhost dbname=test user=joe password=smoe"
 			//
 			// For OLE DB, you would have the additional 
 			// "provider=postgresql"
@@ -320,8 +306,7 @@ namespace System.Data.SqlClient
 		}
 
 		private String ConvertStringToPostgres (String 
-			oleDbConnectionString)
-		{
+			oleDbConnectionString) {
 			StringBuilder postgresConnection = 
 				new StringBuilder();
 			string result;
@@ -355,15 +340,14 @@ namespace System.Data.SqlClient
 					BreakConnectionParameter (sParameter);
 					postgresConnection.
 						Append (sParameter + 
-							" ");
+						" ");
 				}
 			}
 			result = postgresConnection.ToString ();
 			return result;
 		}
 
-		private bool BreakConnectionParameter (String sParameter)
-		{	
+		private bool BreakConnectionParameter (String sParameter) {	
 			bool addParm = true;
 			int index;
 
@@ -402,7 +386,7 @@ namespace System.Data.SqlClient
 
 				case "password":
 					password = parmValue;
-				//	addParm = false;
+					//	addParm = false;
 					break;
 
 				case "options":
@@ -421,8 +405,7 @@ namespace System.Data.SqlClient
 			return addParm;
 		}
 
-		private SqlTransaction TransactionBegin ()
-		{
+		private SqlTransaction TransactionBegin () {
 			// FIXME: need to keep track of 
 			// transaction in-progress
 			trans = new SqlTransaction ();
@@ -433,8 +416,7 @@ namespace System.Data.SqlClient
 			return trans;
 		}
 
-		private SqlTransaction TransactionBegin (IsolationLevel il)
-		{
+		private SqlTransaction TransactionBegin (IsolationLevel il) {
 			// FIXME: need to keep track of 
 			// transaction in-progress
 			TransactionBegin();
@@ -445,7 +427,7 @@ namespace System.Data.SqlClient
 
 		#endregion
 
-		#region Properties
+		#region Public Properties
 
 		[MonoTODO]
 		public ConnectionState State 		{
@@ -502,12 +484,30 @@ namespace System.Data.SqlClient
 			}
 		}
 
+		#region Internal Properties
+
 		internal SqlTransaction Transaction {
 			get {
 				return trans;
 			}
 		}
 
+		// this is for System.Data.SqlClient classes
+		// to get the Postgres connection
+		internal IntPtr PostgresConnection {
+			get {
+				return pgConn;
+			}
+		}
+
+		internal ArrayList Types {
+			get {
+				return types.List;
+			}
+		}
+
+		#endregion // Internal Properties
+
 		#endregion
 
 		#region Events and Delegates
@@ -528,5 +528,131 @@ namespace System.Data.SqlClient
 		*/
 
 		#endregion
+
+		#region Classes
+
+		private class PostgresTypes {
+			// TODO: create hashtable for 
+			// PostgreSQL types to .NET types
+			// containing: oid, typname, SqlDbType
+
+			private Hashtable hashTypes;
+			private ArrayList pgTypes;
+			private SqlConnection con;
+
+			// Got this SQL with the permission from 
+			// the authors of libgda
+			private const string SEL_SQL_GetTypes = 
+				"SELECT oid, typname FROM pg_type " +
+				"WHERE typrelid = 0 AND typname !~ '^_' " +
+				" AND  typname not in ('SET', 'cid', " +
+				"'int2vector', 'oidvector', 'regproc', " +
+				"'smgr', 'tid', 'unknown', 'xid') " +
+				"ORDER BY typname";
+
+			internal PostgresTypes(SqlConnection sqlcon) {
+				
+				con = sqlcon;
+				hashTypes = new Hashtable();
+			}
+
+			private void BuildTypes(IntPtr pgResult, 
+				int nRows, int nFields) {
+
+				String value;
+
+				int r, c;
+				for(r = 0; r < nRows; r++) {
+					PostgresType pgType = 
+						new PostgresType();
+
+					for(c = 0; c < nFields; c++) {
+						// get data value
+						value = PostgresLibrary.
+							PQgetvalue(
+							pgResult,
+							r, c);
+						
+						if(c == 0) {
+							pgType.oid = Int32.Parse(value);
+						}
+						else if(c == 1) {
+							pgType.typname = String.Copy(value);
+							pgType.dbType = PostgresHelper.
+								TypnameToSqlDbType(
+								pgType.typname);
+
+							pgTypes.Add(pgType);
+						}
+						// FIXME: needs to be Read Only
+						// pgTypes = ArrayList.ReadOnly(pgTypes);
+
+					}
+				}
+			}
+
+			internal void Load() {
+				pgTypes = new ArrayList();
+				IntPtr pgResult; // PGresult
+				ExecStatusType execStatus;	
+
+				if(con.State != ConnectionState.Open)
+					throw new InvalidOperationException(
+						"ConnnectionState is not Open");
+
+				// FIXME: PQexec blocks 
+				// while PQsendQuery is non-blocking
+				// which is better to use?
+				// int PQsendQuery(PGconn *conn,
+				//        const char *query);
+
+				// execute SQL command
+				// uses internal property to get the PGConn IntPtr
+				pgResult = PostgresLibrary.
+					PQexec (con.PostgresConnection, SEL_SQL_GetTypes);
+
+				execStatus = PostgresLibrary.
+					PQresultStatus (pgResult);
+			
+				if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
+					int nRows;
+					int nFields;
+
+					nRows = PostgresLibrary.
+						PQntuples(pgResult);
+
+					nFields = PostgresLibrary.
+						PQnfields(pgResult);
+
+					BuildTypes (pgResult, nRows, nFields);
+
+					// close result set
+					PostgresLibrary.PQclear (pgResult);
+
+				}
+				else {
+					String errorMessage;
+				
+					errorMessage = PostgresLibrary.
+						PQresStatus(execStatus);
+
+					errorMessage += " " + PostgresLibrary.
+						PQresultErrorMessage(pgResult);
+				
+					throw new SqlException(0, 0,
+						errorMessage, 0, "",
+						con.DataSource, "SqlConnection", 0);
+				}
+
+			}
+
+			public ArrayList List {
+				get {
+					return pgTypes;
+				}
+			}
+		}
+
+		#endregion
 	}
 }

+ 71 - 78
mcs/class/Mono.Data.PostgreSqlClient/PgSqlDataReader.cs

@@ -6,14 +6,25 @@
 //   Daniel Morgan ([email protected])
 //
 // (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
 //
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
+//
+
 using System;
 using System.Collections;
 using System.ComponentModel;
 using System.Data;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	/// <summary>
 	/// Provides a means of reading one or more forward-only streams
 	/// of result sets obtained by executing a command 
@@ -22,15 +33,15 @@ namespace System.Data.SqlClient
 	//public sealed class SqlDataReader : MarshalByRefObject,
 	//	IEnumerable, IDataReader, IDisposable, IDataRecord
 	public sealed class SqlDataReader : IEnumerable, 
-		IDataReader, IDataRecord
-	{
+		IDataReader, IDataRecord {
 		#region Fields
 
 		private SqlCommand cmd;
 		private DataTable table;
 
 		private object[] fields;
-		private int[] oid; // PostgreSQL Type
+		private string[] types; // PostgreSQL Type
+		private bool[] isNull;
 				
 		private bool open = false;
 		IntPtr pgResult; // PGresult
@@ -45,14 +56,15 @@ namespace System.Data.SqlClient
 
 		internal SqlDataReader (SqlCommand sqlCmd, 
 			DataTable dataTableSchema, IntPtr pg_result,
-			int rowCount, int fieldCount, int[] oids) {
+			int rowCount, int fieldCount, string[] pgtypes) {
 
 			cmd = sqlCmd;
 			table = dataTableSchema;
 			pgResult = pg_result;
 			rows = rowCount;
 			cols = fieldCount;
-			oid = oids;
+			types = pgtypes;
+			open = true;
 		}
 
 		#endregion
@@ -60,31 +72,28 @@ namespace System.Data.SqlClient
 		#region Public Methods
 
 		[MonoTODO]
-		public void Close()
-		{
+		public void Close() {
 			// close result set
 			PostgresLibrary.PQclear (pgResult);
-
+			open = false;
 			// TODO: change busy state on SqlConnection to not busy
 		}
 
 		[MonoTODO]
-		public DataTable GetSchemaTable()
-		{
+		public DataTable GetSchemaTable() {
 			return table;
 		}
 
 		[MonoTODO]
-		public bool NextResult()
-		{
+		public bool NextResult() {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool Read()
-	        {
+		public bool Read() {
 			string value;
 			fields = new object[cols]; // re-init row
+			DbType dbType;
 
 			if(currentRow < rows - 1)  {
 				currentRow++;
@@ -109,8 +118,13 @@ namespace System.Data.SqlClient
 						PQgetlength(pgResult,
 						currentRow, c);
 						
+					dbType = PostgresHelper.
+						TypnameToSqlDbType(types[c]);
+
 					fields[c] = PostgresHelper.
-						ConvertPgTypeToSystem (oid[c], value);
+						ConvertDbTypeToSystem (
+							dbType,
+							value);
 				}
 				return true;
 			}
@@ -118,139 +132,117 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public byte GetByte(int i)
-		{
+		public byte GetByte(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
 		public long GetBytes(int i, long fieldOffset, 
 			byte[] buffer, int bufferOffset, 
-			int length)
-		{
+			int length) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public char GetChar(int i)
-		{
+		public char GetChar(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
 		public long GetChars(int i, long fieldOffset, 
 			char[] buffer, int bufferOffset, 
-			int length)
-		{
+			int length) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public IDataReader GetData(int i)
-		{
+		public IDataReader GetData(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public string GetDataTypeName(int i)
-		{
+		public string GetDataTypeName(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public DateTime GetDateTime(int i)
-		{
+		public DateTime GetDateTime(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public decimal GetDecimal(int i)
-		{
-			throw new NotImplementedException ();
+		public decimal GetDecimal(int i) {
+			return (decimal) fields[i];
 		}
 
 		[MonoTODO]
-		public double GetDouble(int i)
-		{
-			throw new NotImplementedException ();
+		public double GetDouble(int i) {
+			return (double) fields[i];
 		}
 
 		[MonoTODO]
-		public Type GetFieldType(int i)
-		{
+		public Type GetFieldType(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public float GetFloat(int i)
-		{
-			throw new NotImplementedException ();
+		public float GetFloat(int i) {
+			return (float) fields[i];
 		}
 
 		[MonoTODO]
-		public Guid GetGuid(int i)
-		{
+		public Guid GetGuid(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public short GetInt16(int i)
-		{
+		public short GetInt16(int i) {
 			return (short) fields[i];
 		}
 
 		[MonoTODO]
-		public int GetInt32(int i)
-		{
+		public int GetInt32(int i) {
 			return (int) fields[i];
 		}
 
 		[MonoTODO]
-		public long GetInt64(int i)
-		{
+		public long GetInt64(int i) {
 			return (long) fields[i];
 		}
 
 		[MonoTODO]
-		public string GetName(int i)
-		{
+		public string GetName(int i) {
 			return table.Columns[i].ColumnName;
 		}
 
 		[MonoTODO]
-		public int GetOrdinal(string name)
-		{
+		public int GetOrdinal(string name) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public string GetString(int i)
-		{
+		public string GetString(int i) {
 			return (string) fields[i];
 		}
 
 		[MonoTODO]
-		public object GetValue(int i)
-		{
+		public object GetValue(int i) {
 			return fields[i];
 		}
 
 		[MonoTODO]
-		public int GetValues(object[] values)
-		{
+		public int GetValues(object[] values) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool IsDBNull(int i)
-		{
+		public bool IsDBNull(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool GetBoolean(int i)
-		{
-			throw new NotImplementedException ();
+		public bool GetBoolean(int i) {
+			return (bool) fields[i];
 		}
 
 		[MonoTODO]
@@ -284,7 +276,10 @@ namespace System.Data.SqlClient
 		public bool IsClosed {
 			[MonoTODO]
 			get {
-				throw new NotImplementedException (); 
+				if(open == false)
+					return true;
+				else
+					return false;
 			}
 		}
 
@@ -312,28 +307,26 @@ namespace System.Data.SqlClient
 					}
 
 				}
-				
-				if(i == cols) {
-					for(i = 0; i < cols; i++) {
-						string ta;
-						string n;
+	
+				for(i = 0; i < cols; i++) {
+					string ta;
+					string n;
 						
-						ta = table.Columns[i].ColumnName.ToUpper();
-						n = name.ToUpper();
+					ta = table.Columns[i].ColumnName.ToUpper();
+					n = name.ToUpper();
 						
-						if(ta.Equals(n)) {
-							return fields[i];
-						}
+					if(ta.Equals(n)) {
+						return fields[i];
 					}
 				}
+			
 				throw new MissingFieldException("Missing field: " + name);
 			}
 		}
 
 		public object this[int i] {
 			[MonoTODO]
-			get 
-			{ 
+			get { 
 				return fields[i];
 			}
 		}

+ 234 - 80
mcs/class/Mono.Data.PostgreSqlClient/PostgresLibrary.cs

@@ -18,52 +18,11 @@ using System;
 using System.Data;
 using System.Runtime.InteropServices;
 using System.Diagnostics;
+using System.Collections;
 
 namespace System.Data.SqlClient {
 
-	// PostgreSQL Type (oid and typname from pg_type)
-	internal enum PgType {
-		ABSTIME = 702,
-		ACLITEM = 1033,
-		BIT = 1560,
-		BOOL = 16,
-		BOX = 603,
-		BPCHAR = 1042,
-		BYTEA = 17,
-		CHAR = 18,
-		CIDR = 650,
-		CIRCLE = 718,
-		DATE = 1082,
-		FLOAT4 = 700,
-		FLOAT8 = 701,
-		INET = 869,
-		INT2 = 21,
-		INT4 = 23,
-		INT8 = 20,
-		INTERVAL = 1186,
-		LINE = 628,
-		LSEG = 601,
-		MACADDR = 829,
-		MONEY = 790,
-		NAME = 19,
-		NUMERIC = 1700,
-		OID = 26,
-		PATH = 602,
-		POINT = 600,
-		POLYGON = 604,
-		REFCURSOR = 1790,
-		RELTIME = 703,
-		TEXT = 25,
-		TIME = 1083,
-		TIMESTAMP = 1114,
-		TIMESTAMPTZ = 1184,
-		TIMETZ = 1266,
-		TINTERVAL = 704,
-		VARBIT = 1562,
-		VARCHAR = 1043
-	}
-
-	/* IMPORTANT: DO NOT CHANGE ANY OF THESE ENUMS */
+	/* IMPORTANT: DO NOT CHANGE ANY OF THESE ENUMS BELOW */
 	
 	internal enum ConnStatusType
 	{
@@ -97,15 +56,181 @@ namespace System.Data.SqlClient {
 		PGRES_FATAL_ERROR
 	}
 
+	internal struct PostgresType {
+		public int oid;
+		public string typname;
+		public DbType dbType;
+	}
+
 	sealed internal class PostgresHelper {
 
-		/// <summary>
-		/// Convert a PostgreSQL Type to a .NET System type.
-		/// </summary>
-		/// <param name="oid"></param>
-		/// <param name="value"></param>
-		/// <returns></returns>
-		public static object ConvertPgTypeToSystem (int oid, String value) {
+		// translates the PostgreSQL typname to System.Data.DbType
+		public static DbType TypnameToSqlDbType(string typname) {
+			DbType sqlType;
+			
+			switch(typname) {
+
+			case "abstime":
+				sqlType = DbType.Int32;
+				break;
+
+			case "aclitem":
+				sqlType = DbType.String;
+				break;
+
+			case "bit":
+				sqlType = DbType.String;
+				break;
+
+			case "bool":
+				sqlType = DbType.Boolean;
+				break;
+
+			case "box":
+				sqlType = DbType.String;
+				break;
+
+			case "bpchar":
+				sqlType = DbType.String;
+				break;
+
+			case "bytea":
+				sqlType = DbType.String;
+				break;
+
+			case "char":
+				sqlType = DbType.String;
+				break;
+
+			case "cidr":
+				sqlType = DbType.String;
+				break;
+
+			case "circle":
+				sqlType = DbType.String;
+				break;
+
+			case "date":
+				sqlType = DbType.String;
+				break;
+
+			case "float4":
+				sqlType = DbType.Single;
+				break;
+
+			case "float8":
+				sqlType = DbType.Double;
+				break;
+
+			case "inet":
+				sqlType = DbType.String;
+				break;
+
+			case "int2":
+				sqlType = DbType.Int16;
+				break;
+
+			case "int4":
+				sqlType = DbType.Int32;
+				break;
+
+			case "int8":
+				sqlType = DbType.Int64;
+				break;
+
+			case "interval":
+				sqlType = DbType.String;
+				break;
+
+			case "line":
+				sqlType = DbType.String;
+				break;
+
+			case "lseg":
+				sqlType = DbType.String;
+				break;
+
+			case "macaddr":
+				sqlType = DbType.String;
+				break;
+
+			case "money":
+				sqlType = DbType.Decimal;
+				break;
+
+			case "name":
+				sqlType = DbType.String;
+				break;
+
+			case "numeric":
+				sqlType = DbType.Decimal;
+				break;
+
+			case "oid":
+				sqlType = DbType.Int32;
+				break;
+
+			case "path":
+				sqlType = DbType.String;
+				break;
+
+			case "point":
+				sqlType = DbType.String;
+				break;
+
+			case "polygon":
+				sqlType = DbType.String;
+				break;
+
+			case "refcursor":
+				sqlType = DbType.String;
+				break;
+
+			case "reltime":
+				sqlType = DbType.String;
+				break;
+
+			case "text":
+				sqlType = DbType.String;
+				break;
+
+			case "time":
+				sqlType = DbType.String;
+				break;
+
+			case "timestamp":
+				sqlType = DbType.String;
+				break;
+
+			case "timestamptz":
+				sqlType = DbType.String;
+				break;
+
+			case "timetz":
+				sqlType = DbType.String;
+				break;
+
+			case "tinterval":
+				sqlType = DbType.String;
+				break;
+
+			case "varbit":
+				sqlType = DbType.String;
+				break;
+
+			case "varchar":
+				sqlType = DbType.String;
+				break;
+
+			default:
+				sqlType = DbType.String;
+				break;
+			}
+			return sqlType;
+		}
+		
+		// Converts data value from database to .NET System type.
+		public static object ConvertDbTypeToSystem (DbType typ, String value) {
 			object obj = null;
 
 			// FIXME: more types need 
@@ -113,40 +238,41 @@ namespace System.Data.SqlClient {
 			//        from PostgreSQL oid type
 			//        to .NET System.<type>
 
-			switch((PgType) oid) {
-			case PgType.VARCHAR:
-			case PgType.BPCHAR:
-			case PgType.TEXT:
-			case PgType.CHAR:
+			switch(typ) {
+			case DbType.String:
 				obj = (object) String.Copy(value); 
 				break;
-			case PgType.BOOL:
+			case DbType.Boolean:
 				obj = (object) Boolean.Parse(value);
 				break;
-			case PgType.INT2:
+			case DbType.Int16:
 				obj = (object) Int16.Parse(value);
 				break;
-			case PgType.INT4:
+			case DbType.Int32:
 				obj = (object) Int32.Parse(value);
 				break;
-			case PgType.INT8:
+			case DbType.Int64:
 				obj = (object) Int64.Parse(value);
 				break;
+			case DbType.Decimal:
+				obj = (object) Decimal.Parse(value);
+				break;
+			case DbType.Single:
+				obj = (object) Single.Parse(value);
+				break;
+			case DbType.Double:
+				obj = (object) Double.Parse(value);
+				break;
 			default:
-				throw new NotImplementedException(
-					"PGNI1: PostgreSQL oid data type " + oid +
-					" not mapped to .NET System data type.");
+				obj = (object) String.Copy(value);
+				break;
 			}
 
 			return obj;
 		}
 		
-		/// <summary>
-		/// Convert the PostgreSQL Type oid to the .NET System.Type.
-		/// </summary>
-		/// <param name="oid"></param>
-		/// <returns></returns>
-		public static Type OidToType (int oid) {
+		// Translates System.Data.DbType to System.Type
+		public static Type DbTypeToSystemType (DbType dType) {
 			// FIXME: more types need 
 			//        to be mapped
 			//        from PostgreSQL oid type
@@ -154,32 +280,60 @@ namespace System.Data.SqlClient {
 
 			Type typ = null;
 
-			switch((PgType) oid) {
-			case PgType.VARCHAR:
-			case PgType.BPCHAR:
-			case PgType.TEXT:
-			case PgType.CHAR:
+			switch(dType) {
+			case DbType.String:
 				typ = typeof(String);
 				break;
-			case PgType.BOOL:
+			case DbType.Boolean:
 				typ = typeof(Boolean);
 				break;
-			case PgType.INT2:
+			case DbType.Int16: 
 				typ = typeof(Int16);
 				break;
-			case PgType.INT4:
+			case DbType.Int32:
 				typ = typeof(Int32);
 				break;
-			case PgType.INT8:
+			case DbType.Int64:
 				typ = typeof(Int64);
 				break;
+			case DbType.Decimal:
+				typ = typeof(Decimal);
+				break;
+			case DbType.Single:
+				typ = typeof(Single);
+				break;
+			case DbType.Double:
+				typ = typeof(Double);
+				break;
 			default:
-				throw new NotImplementedException(
-					"PGNI2: PostgreSQL oid type " + oid +
-					" not mapped to .NET System Type.");
+				typ = typeof(String);
+				break;
 			}
 			return typ;
 		}
+
+		// Find DbType for oid
+		// which requires a look up of PostgresTypes
+		// DbType <-> typname <-> oid
+		public static string OidToTypname (int oid, ArrayList pgTypes) {
+			// FIXME: more types need 
+			//        to be mapped
+			//        from PostgreSQL oid type
+			//        to .NET System.<type>
+			
+			string typname = "text"; // default
+			int i;
+			for(i = 0; i < pgTypes.Count; i++) {
+				PostgresType pt = (PostgresType) pgTypes[i];
+				if(pt.oid == oid) {
+					typname = pt.typname;
+					break; 
+				}
+			}
+
+			return typname;
+		}
+
 	}
 
 	sealed internal class PostgresLibrary

+ 19 - 0
mcs/class/System.Data/ChangeLog

@@ -1,3 +1,22 @@
+2002-05-04  Daniel Morgan <[email protected]>
+	
+	* System.Data.SqlClient/PostgresLibrary.cs
+	* System.Data.SqlClient/SqlCommand.cs
+	* System.Data.SqlClient/SqlConnection.cs
+	* System.Data.SqlClient/SqlDataReader.cs
+	oid should not be hard coded because they
+	can change from one version of PostgreSQL
+	to the next.  Use the typname's instead.
+	The PostgreSQL type data retrieves
+	at database connection time.  Any unimplemented
+	types just default to string.  These were things
+	suggested by Gonzalo.
+	
+	* Test/ReadPostgresData.cs - stuff
+	* Test/TestSqlDataReader.cs - stuff
+	
+	* System.Data.SqlTypes/SqlInt32.cs - added a using
+
 2002-05-03  Tim Coleman <[email protected]>
 	* System.Data.build: Fix the build so that test depends on build
 

+ 234 - 80
mcs/class/System.Data/System.Data.SqlClient/PostgresLibrary.cs

@@ -18,52 +18,11 @@ using System;
 using System.Data;
 using System.Runtime.InteropServices;
 using System.Diagnostics;
+using System.Collections;
 
 namespace System.Data.SqlClient {
 
-	// PostgreSQL Type (oid and typname from pg_type)
-	internal enum PgType {
-		ABSTIME = 702,
-		ACLITEM = 1033,
-		BIT = 1560,
-		BOOL = 16,
-		BOX = 603,
-		BPCHAR = 1042,
-		BYTEA = 17,
-		CHAR = 18,
-		CIDR = 650,
-		CIRCLE = 718,
-		DATE = 1082,
-		FLOAT4 = 700,
-		FLOAT8 = 701,
-		INET = 869,
-		INT2 = 21,
-		INT4 = 23,
-		INT8 = 20,
-		INTERVAL = 1186,
-		LINE = 628,
-		LSEG = 601,
-		MACADDR = 829,
-		MONEY = 790,
-		NAME = 19,
-		NUMERIC = 1700,
-		OID = 26,
-		PATH = 602,
-		POINT = 600,
-		POLYGON = 604,
-		REFCURSOR = 1790,
-		RELTIME = 703,
-		TEXT = 25,
-		TIME = 1083,
-		TIMESTAMP = 1114,
-		TIMESTAMPTZ = 1184,
-		TIMETZ = 1266,
-		TINTERVAL = 704,
-		VARBIT = 1562,
-		VARCHAR = 1043
-	}
-
-	/* IMPORTANT: DO NOT CHANGE ANY OF THESE ENUMS */
+	/* IMPORTANT: DO NOT CHANGE ANY OF THESE ENUMS BELOW */
 	
 	internal enum ConnStatusType
 	{
@@ -97,15 +56,181 @@ namespace System.Data.SqlClient {
 		PGRES_FATAL_ERROR
 	}
 
+	internal struct PostgresType {
+		public int oid;
+		public string typname;
+		public DbType dbType;
+	}
+
 	sealed internal class PostgresHelper {
 
-		/// <summary>
-		/// Convert a PostgreSQL Type to a .NET System type.
-		/// </summary>
-		/// <param name="oid"></param>
-		/// <param name="value"></param>
-		/// <returns></returns>
-		public static object ConvertPgTypeToSystem (int oid, String value) {
+		// translates the PostgreSQL typname to System.Data.DbType
+		public static DbType TypnameToSqlDbType(string typname) {
+			DbType sqlType;
+			
+			switch(typname) {
+
+			case "abstime":
+				sqlType = DbType.Int32;
+				break;
+
+			case "aclitem":
+				sqlType = DbType.String;
+				break;
+
+			case "bit":
+				sqlType = DbType.String;
+				break;
+
+			case "bool":
+				sqlType = DbType.Boolean;
+				break;
+
+			case "box":
+				sqlType = DbType.String;
+				break;
+
+			case "bpchar":
+				sqlType = DbType.String;
+				break;
+
+			case "bytea":
+				sqlType = DbType.String;
+				break;
+
+			case "char":
+				sqlType = DbType.String;
+				break;
+
+			case "cidr":
+				sqlType = DbType.String;
+				break;
+
+			case "circle":
+				sqlType = DbType.String;
+				break;
+
+			case "date":
+				sqlType = DbType.String;
+				break;
+
+			case "float4":
+				sqlType = DbType.Single;
+				break;
+
+			case "float8":
+				sqlType = DbType.Double;
+				break;
+
+			case "inet":
+				sqlType = DbType.String;
+				break;
+
+			case "int2":
+				sqlType = DbType.Int16;
+				break;
+
+			case "int4":
+				sqlType = DbType.Int32;
+				break;
+
+			case "int8":
+				sqlType = DbType.Int64;
+				break;
+
+			case "interval":
+				sqlType = DbType.String;
+				break;
+
+			case "line":
+				sqlType = DbType.String;
+				break;
+
+			case "lseg":
+				sqlType = DbType.String;
+				break;
+
+			case "macaddr":
+				sqlType = DbType.String;
+				break;
+
+			case "money":
+				sqlType = DbType.Decimal;
+				break;
+
+			case "name":
+				sqlType = DbType.String;
+				break;
+
+			case "numeric":
+				sqlType = DbType.Decimal;
+				break;
+
+			case "oid":
+				sqlType = DbType.Int32;
+				break;
+
+			case "path":
+				sqlType = DbType.String;
+				break;
+
+			case "point":
+				sqlType = DbType.String;
+				break;
+
+			case "polygon":
+				sqlType = DbType.String;
+				break;
+
+			case "refcursor":
+				sqlType = DbType.String;
+				break;
+
+			case "reltime":
+				sqlType = DbType.String;
+				break;
+
+			case "text":
+				sqlType = DbType.String;
+				break;
+
+			case "time":
+				sqlType = DbType.String;
+				break;
+
+			case "timestamp":
+				sqlType = DbType.String;
+				break;
+
+			case "timestamptz":
+				sqlType = DbType.String;
+				break;
+
+			case "timetz":
+				sqlType = DbType.String;
+				break;
+
+			case "tinterval":
+				sqlType = DbType.String;
+				break;
+
+			case "varbit":
+				sqlType = DbType.String;
+				break;
+
+			case "varchar":
+				sqlType = DbType.String;
+				break;
+
+			default:
+				sqlType = DbType.String;
+				break;
+			}
+			return sqlType;
+		}
+		
+		// Converts data value from database to .NET System type.
+		public static object ConvertDbTypeToSystem (DbType typ, String value) {
 			object obj = null;
 
 			// FIXME: more types need 
@@ -113,40 +238,41 @@ namespace System.Data.SqlClient {
 			//        from PostgreSQL oid type
 			//        to .NET System.<type>
 
-			switch((PgType) oid) {
-			case PgType.VARCHAR:
-			case PgType.BPCHAR:
-			case PgType.TEXT:
-			case PgType.CHAR:
+			switch(typ) {
+			case DbType.String:
 				obj = (object) String.Copy(value); 
 				break;
-			case PgType.BOOL:
+			case DbType.Boolean:
 				obj = (object) Boolean.Parse(value);
 				break;
-			case PgType.INT2:
+			case DbType.Int16:
 				obj = (object) Int16.Parse(value);
 				break;
-			case PgType.INT4:
+			case DbType.Int32:
 				obj = (object) Int32.Parse(value);
 				break;
-			case PgType.INT8:
+			case DbType.Int64:
 				obj = (object) Int64.Parse(value);
 				break;
+			case DbType.Decimal:
+				obj = (object) Decimal.Parse(value);
+				break;
+			case DbType.Single:
+				obj = (object) Single.Parse(value);
+				break;
+			case DbType.Double:
+				obj = (object) Double.Parse(value);
+				break;
 			default:
-				throw new NotImplementedException(
-					"PGNI1: PostgreSQL oid data type " + oid +
-					" not mapped to .NET System data type.");
+				obj = (object) String.Copy(value);
+				break;
 			}
 
 			return obj;
 		}
 		
-		/// <summary>
-		/// Convert the PostgreSQL Type oid to the .NET System.Type.
-		/// </summary>
-		/// <param name="oid"></param>
-		/// <returns></returns>
-		public static Type OidToType (int oid) {
+		// Translates System.Data.DbType to System.Type
+		public static Type DbTypeToSystemType (DbType dType) {
 			// FIXME: more types need 
 			//        to be mapped
 			//        from PostgreSQL oid type
@@ -154,32 +280,60 @@ namespace System.Data.SqlClient {
 
 			Type typ = null;
 
-			switch((PgType) oid) {
-			case PgType.VARCHAR:
-			case PgType.BPCHAR:
-			case PgType.TEXT:
-			case PgType.CHAR:
+			switch(dType) {
+			case DbType.String:
 				typ = typeof(String);
 				break;
-			case PgType.BOOL:
+			case DbType.Boolean:
 				typ = typeof(Boolean);
 				break;
-			case PgType.INT2:
+			case DbType.Int16: 
 				typ = typeof(Int16);
 				break;
-			case PgType.INT4:
+			case DbType.Int32:
 				typ = typeof(Int32);
 				break;
-			case PgType.INT8:
+			case DbType.Int64:
 				typ = typeof(Int64);
 				break;
+			case DbType.Decimal:
+				typ = typeof(Decimal);
+				break;
+			case DbType.Single:
+				typ = typeof(Single);
+				break;
+			case DbType.Double:
+				typ = typeof(Double);
+				break;
 			default:
-				throw new NotImplementedException(
-					"PGNI2: PostgreSQL oid type " + oid +
-					" not mapped to .NET System Type.");
+				typ = typeof(String);
+				break;
 			}
 			return typ;
 		}
+
+		// Find DbType for oid
+		// which requires a look up of PostgresTypes
+		// DbType <-> typname <-> oid
+		public static string OidToTypname (int oid, ArrayList pgTypes) {
+			// FIXME: more types need 
+			//        to be mapped
+			//        from PostgreSQL oid type
+			//        to .NET System.<type>
+			
+			string typname = "text"; // default
+			int i;
+			for(i = 0; i < pgTypes.Count; i++) {
+				PostgresType pt = (PostgresType) pgTypes[i];
+				if(pt.oid == oid) {
+					typname = pt.typname;
+					break; 
+				}
+			}
+
+			return typname;
+		}
+
 	}
 
 	sealed internal class PostgresLibrary

+ 66 - 58
mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs

@@ -5,7 +5,18 @@
 //   Rodrigo Moya ([email protected])
 //   Daniel Morgan ([email protected])
 //
-// (C) Ximian, Inc 2002
+// (C) Ximian, Inc 2002 http://www.ximian.com/
+// (C) Daniel Morgan, 2002
+//
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
 //
 
 // use #define DEBUG_SqlCommand if you want to spew debug messages
@@ -18,15 +29,13 @@ using System.Data.Common;
 using System.Runtime.InteropServices;
 using System.Xml;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	/// <summary>
 	/// Represents a SQL statement that is executed 
 	/// while connected to a SQL database.
 	/// </summary>
 	// public sealed class SqlCommand : Component, IDbCommand, ICloneable
-	public sealed class SqlCommand : IDbCommand
-	{
+	public sealed class SqlCommand : IDbCommand {
 		// FIXME: Console.WriteLine() is used for debugging throughout
 
 		#region Fields
@@ -47,25 +56,21 @@ namespace System.Data.SqlClient
 
 		#region Constructors
 
-		public SqlCommand()
-		{
+		public SqlCommand() {
 			sql = "";
 		}
 
-		public SqlCommand (string cmdText)
-		{
+		public SqlCommand (string cmdText) {
 			sql = cmdText;
 		}
 
-		public SqlCommand (string cmdText, SqlConnection connection)
-		{
+		public SqlCommand (string cmdText, SqlConnection connection) {
 			sql = cmdText;
 			conn = connection;
 		}
 
 		public SqlCommand (string cmdText, SqlConnection connection, 
-						SqlTransaction transaction)
-		{
+			SqlTransaction transaction) {
 			sql = cmdText;
 			conn = connection;
 			trans = transaction;
@@ -76,27 +81,23 @@ namespace System.Data.SqlClient
 		#region Methods
 
 		[MonoTODO]
-		public void Cancel ()
-		{
+		public void Cancel () {
 			// FIXME: use non-blocking Exec for this
 			throw new NotImplementedException ();
 		}
 
 		// FIXME: is this the correct way to return a stronger type?
 		[MonoTODO]
-		IDbDataParameter IDbCommand.CreateParameter ()
-		{
+		IDbDataParameter IDbCommand.CreateParameter () {
 			return CreateParameter ();
 		}
 
 		[MonoTODO]
-		public SqlParameter CreateParameter ()
-		{
+		public SqlParameter CreateParameter () {
 			return new SqlParameter ();
 		}
 
-		public int ExecuteNonQuery ()
-		{	
+		public int ExecuteNonQuery () {	
 			IntPtr pgResult; // PGresult
 			int rowsAffected = -1;
 			ExecStatusType execStatus;
@@ -117,11 +118,10 @@ namespace System.Data.SqlClient
 			pgResult = PostgresLibrary.
 				PQexec (conn.PostgresConnection, sql);
 
-                        execStatus = PostgresLibrary.
-					PQresultStatus (pgResult);
+			execStatus = PostgresLibrary.
+				PQresultStatus (pgResult);
 			
-			if(execStatus == ExecStatusType.PGRES_COMMAND_OK)
-			{
+			if(execStatus == ExecStatusType.PGRES_COMMAND_OK) {
 				rowsAffectedString = PostgresLibrary.
 					PQcmdTuples (pgResult);
 
@@ -131,8 +131,7 @@ namespace System.Data.SqlClient
 
 				PostgresLibrary.PQclear (pgResult);
 			}
-			else
-			{
+			else {
 				String errorMessage;
 				
 				errorMessage = PostgresLibrary.
@@ -142,35 +141,31 @@ namespace System.Data.SqlClient
 					PQresultErrorMessage(pgResult);
 				
 				throw new SqlException(0, 0,
-						  errorMessage, 0, "",
-						  conn.DataSource, "SqlCommand", 0);
+					errorMessage, 0, "",
+					conn.DataSource, "SqlCommand", 0);
 			}
 			
 			return rowsAffected;
 		}
 		
 		[MonoTODO]
-		IDataReader IDbCommand.ExecuteReader ()
-		{
+		IDataReader IDbCommand.ExecuteReader () {
 			return ExecuteReader ();
 		}
 
 		[MonoTODO]
-		SqlDataReader ExecuteReader ()
-		{
+		public SqlDataReader ExecuteReader () {
 			return ExecuteReader(CommandBehavior.Default);
 		}
 
 		[MonoTODO]
 		IDataReader IDbCommand.ExecuteReader (
-					CommandBehavior behavior)
-		{
+			CommandBehavior behavior) {
 			return ExecuteReader (behavior);
 		}
 
 		[MonoTODO]
-		public SqlDataReader ExecuteReader (CommandBehavior behavior)
-		{
+		public SqlDataReader ExecuteReader (CommandBehavior behavior) {
 			// FIXME: currently only works for a 
 			//        single result set
 			//        ExecuteReader can be used 
@@ -201,15 +196,15 @@ namespace System.Data.SqlClient
 			if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
 				DataTable dt = null;
 				int rows, cols;
-				int[] oids;
+				string[] types;
 				
 				// FIXME: maybe i should move the
 				//        BuildTableSchema code
 				//        to the SqlDataReader?
 				dt = BuildTableSchema(pgResult, 
-					out rows, out cols, out oids);
+					out rows, out cols, out types);
 				dataReader = new SqlDataReader(this, dt, pgResult,
-					rows, cols, oids);
+					rows, cols, types);
 			}
 			else {
 				String errorMessage;
@@ -229,9 +224,9 @@ namespace System.Data.SqlClient
 		}
 
 		internal DataTable BuildTableSchema (IntPtr pgResult, 
-					out int nRows, 
-					out int nFields, 
-					out int[] oids) {
+			out int nRows, 
+			out int nFields, 
+			out string[] types) {
 
 			int nCol;
 			
@@ -243,18 +238,24 @@ namespace System.Data.SqlClient
 			nFields = PostgresLibrary.
 				PQnfields(pgResult);
 			
-			oids = new int[nFields];
+			int oid;
+			types = new string[nFields];
 
 			for(nCol = 0; nCol < nFields; nCol++) {						
+				
+				DbType dbType;
+
 				// get column name
 				String fieldName;
 				fieldName = PostgresLibrary.
 					PQfname(pgResult, nCol);
 
 				// get PostgreSQL data type (OID)
-				oids[nCol] = PostgresLibrary.
+				oid = PostgresLibrary.
 					PQftype(pgResult, nCol);
-
+				types[nCol] = PostgresHelper.
+					OidToTypname (oid, conn.Types);
+				
 				int definedSize;
 				// get defined size of column
 				definedSize = PostgresLibrary.
@@ -262,7 +263,11 @@ namespace System.Data.SqlClient
 								
 				// build the data column and add it the table
 				DataColumn dc = new DataColumn(fieldName);
-				dc.DataType = PostgresHelper.OidToType(oids[nCol]);
+
+				dbType = PostgresHelper.
+						TypnameToSqlDbType(types[nCol]);
+				dc.DataType = PostgresHelper.
+						DbTypeToSystemType(dbType);
 				dc.MaxLength = definedSize;
 				dc.SetTable(dt);
 				
@@ -272,8 +277,7 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public object ExecuteScalar ()
-		{
+		public object ExecuteScalar () {
 			IntPtr pgResult; // PGresult
 			ExecStatusType execStatus;	
 			object obj = null; // return
@@ -316,9 +320,15 @@ namespace System.Data.SqlClient
 					//	PQfname(pgResult, nCol);
 
 					int oid;
+					string sType;
+					DbType dbType;
 					// get PostgreSQL data type (OID)
 					oid = PostgresLibrary.
 						PQftype(pgResult, nCol);
+					sType = PostgresHelper.
+						OidToTypname (oid, conn.Types);
+					dbType = PostgresHelper.
+						TypnameToSqlDbType(sType);
 
 					int definedSize;
 					// get defined size of column
@@ -344,7 +354,9 @@ namespace System.Data.SqlClient
 						nRow, nCol);
 						
 					obj = PostgresHelper.
-						ConvertPgTypeToSystem (oid, value);
+						ConvertDbTypeToSystem (
+						dbType,
+						value);
 				}
 
 				// close result set
@@ -369,21 +381,18 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public XmlReader ExecuteXmlReader ()
-		{
+		public XmlReader ExecuteXmlReader () {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public void Prepare ()
-		{
+		public void Prepare () {
 			// FIXME: parameters have to be implemented for this
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public SqlCommand Clone ()
-		{
+		public SqlCommand Clone () {
 			throw new NotImplementedException ();
 		}
 
@@ -538,8 +547,7 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		~SqlCommand()
-		{
+		~SqlCommand() {
 			// FIXME: need proper way to release resources
 			// Dispose(false);
 		}

+ 191 - 65
mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs

@@ -6,20 +6,31 @@
 //   Daniel Morgan ([email protected])
 //
 // (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
+//
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
 //
 
 // use #define DEBUG_SqlConnection if you want to spew debug messages
 // #define DEBUG_SqlConnection
 
 using System;
+using System.Collections;
 using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
 using System.Runtime.InteropServices;
 using System.Text;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	// using PGconn = IntPtr; 
 	// PGconn is native C library type in libpq for Postgres Connection
 
@@ -31,13 +42,14 @@ namespace System.Data.SqlClient
 	/// </summary>
 	//public sealed class SqlConnection : Component, IDbConnection,
 	//	ICloneable
-	public sealed class SqlConnection : IDbConnection
-	{
+
+	public sealed class SqlConnection : IDbConnection {
 		// FIXME: Need to implement class Component, 
 		// and interfaces: ICloneable and IDisposable	
 
 		#region Fields
 
+		private PostgresTypes types;
 		private IntPtr pgConn = IntPtr.Zero;    
 		// PGConn (Postgres Connection)
 		private string connectionString = "";    
@@ -103,14 +115,12 @@ namespace System.Data.SqlClient
 		*/
 		// A lot of the defaults were initialized in the Fields
 		[MonoTODO]
-		public SqlConnection ()
-		{
+		public SqlConnection () {
 
 		}
 	
 		[MonoTODO]
-		public SqlConnection (String connectionString)
-		{
+		public SqlConnection (String connectionString) {
 			SetConnectionString (connectionString);
 		}
 
@@ -128,8 +138,7 @@ namespace System.Data.SqlClient
 		// aka Finalize
 		// [ClassInterface(ClassInterfaceType.AutoDual)]
 		[MonoTODO]
-		~SqlConnection()
-		{
+		~SqlConnection() {
 			// FIXME: this class need 
 			//        a destructor to release resources
 			//        Also, take a look at Dispose
@@ -140,24 +149,20 @@ namespace System.Data.SqlClient
 
 		#region Public Methods
 
-		IDbTransaction IDbConnection.BeginTransaction ()
-		{
+		IDbTransaction IDbConnection.BeginTransaction () {
 			return BeginTransaction ();
 		}
 
-		public SqlTransaction BeginTransaction ()
-		{
+		public SqlTransaction BeginTransaction () {
 			return TransactionBegin (); // call private method
 		}
 
 		IDbTransaction IDbConnection.BeginTransaction (IsolationLevel 
-						il)
-		{
+			il) {
 			return BeginTransaction (il);
 		}
 
-		public SqlTransaction BeginTransaction (IsolationLevel il)
-		{
+		public SqlTransaction BeginTransaction (IsolationLevel il) {
 			return TransactionBegin (il); // call private method
 		}
 
@@ -170,54 +175,37 @@ namespace System.Data.SqlClient
 
 		[Obsolete]
 		public SqlTransaction BeginTransaction(IsolationLevel iso,
-						string transactionName) {
+			string transactionName) {
 			return TransactionBegin (iso); // call private method
 		}
 
 		[MonoTODO]
-		public void ChangeDatabase (string databaseName)
-		{
+		public void ChangeDatabase (string databaseName) {
 			throw new NotImplementedException ();
 		}
 				
 		[MonoTODO]
-		public void Close ()
-		{
+		public void Close () {
 			CloseDataSource ();
 		}
 
-		IDbCommand IDbConnection.CreateCommand ()
-		{
+		IDbCommand IDbConnection.CreateCommand () {
 			return CreateCommand ();
 		}
 
-		public SqlCommand CreateCommand ()
-		{
+		public SqlCommand CreateCommand () {
 			SqlCommand sqlcmd = new SqlCommand ("", this);
 
 			return sqlcmd;
 		}
 
 		[MonoTODO]
-		public void Open ()
-		{
+		public void Open () {
 			OpenDataSource ();
 		}
 
 		#endregion // Public Methods
 
-		#region Internal Methods
-
-		// this is for System.Data.SqlClient classes
-		// to get the Postgres connection
-		internal IntPtr PostgresConnection {
-			get {
-				return pgConn;
-			}
-		}
-
-		#endregion // Internal Methods
-
 		#region Protected Methods
 
 		// FIXME: protected override void Dispose overrides Component
@@ -234,8 +222,7 @@ namespace System.Data.SqlClient
 
 		#region Private Methods
 
-		private void OpenDataSource ()
-		{
+		private void OpenDataSource () {
 			if(dbname.Equals(""))
 				throw new InvalidOperationException(
 					"dbname missing");
@@ -250,7 +237,7 @@ namespace System.Data.SqlClient
 			//        otherwise, throw an exception
 
 			pgConn = PostgresLibrary.PQconnectdb 
-					(pgConnectionString);
+				(pgConnectionString);
 
 			// FIXME: should we use PQconnectStart/PQconnectPoll
 			//        instead of PQconnectdb?  
@@ -258,13 +245,14 @@ namespace System.Data.SqlClient
 			// PQconnectStart/PQconnectPoll is non-blocking
 			
 			connStatus = PostgresLibrary.PQstatus (pgConn);
-			if(connStatus == ConnStatusType.CONNECTION_OK)
-			{
+			if(connStatus == ConnStatusType.CONNECTION_OK) {
 				// Successfully Connected
 				conState = ConnectionState.Open;
+				// FIXME: load types into hashtable
+				types = new PostgresTypes(this);
+				types.Load();
 			}
-			else
-			{
+			else {
 				String errorMessage = PostgresLibrary.
 					PQerrorMessage (pgConn);
 				errorMessage += ": Could not connect to database.";
@@ -275,22 +263,20 @@ namespace System.Data.SqlClient
 			}
 		}
 
-		private void CloseDataSource ()
-		{
+		private void CloseDataSource () {
 			// FIXME: just a quick hack
 			conState = ConnectionState.Closed;
 			PostgresLibrary.PQfinish (pgConn);
 		}
 
-		private void SetConnectionString (string connectionString)
-		{
+		private void SetConnectionString (string connectionString) {
 			// FIXME: perform error checking on string
 			// while translating string from 
 			// OLE DB format to PostgreSQL 
 			// connection string format
 			//
-	//     OLE DB: "host=localhost;dbname=test;user=joe;password=smoe"
-	// PostgreSQL: "host=localhost dbname=test user=joe password=smoe"
+			//     OLE DB: "host=localhost;dbname=test;user=joe;password=smoe"
+			// PostgreSQL: "host=localhost dbname=test user=joe password=smoe"
 			//
 			// For OLE DB, you would have the additional 
 			// "provider=postgresql"
@@ -320,8 +306,7 @@ namespace System.Data.SqlClient
 		}
 
 		private String ConvertStringToPostgres (String 
-			oleDbConnectionString)
-		{
+			oleDbConnectionString) {
 			StringBuilder postgresConnection = 
 				new StringBuilder();
 			string result;
@@ -355,15 +340,14 @@ namespace System.Data.SqlClient
 					BreakConnectionParameter (sParameter);
 					postgresConnection.
 						Append (sParameter + 
-							" ");
+						" ");
 				}
 			}
 			result = postgresConnection.ToString ();
 			return result;
 		}
 
-		private bool BreakConnectionParameter (String sParameter)
-		{	
+		private bool BreakConnectionParameter (String sParameter) {	
 			bool addParm = true;
 			int index;
 
@@ -402,7 +386,7 @@ namespace System.Data.SqlClient
 
 				case "password":
 					password = parmValue;
-				//	addParm = false;
+					//	addParm = false;
 					break;
 
 				case "options":
@@ -421,8 +405,7 @@ namespace System.Data.SqlClient
 			return addParm;
 		}
 
-		private SqlTransaction TransactionBegin ()
-		{
+		private SqlTransaction TransactionBegin () {
 			// FIXME: need to keep track of 
 			// transaction in-progress
 			trans = new SqlTransaction ();
@@ -433,8 +416,7 @@ namespace System.Data.SqlClient
 			return trans;
 		}
 
-		private SqlTransaction TransactionBegin (IsolationLevel il)
-		{
+		private SqlTransaction TransactionBegin (IsolationLevel il) {
 			// FIXME: need to keep track of 
 			// transaction in-progress
 			TransactionBegin();
@@ -445,7 +427,7 @@ namespace System.Data.SqlClient
 
 		#endregion
 
-		#region Properties
+		#region Public Properties
 
 		[MonoTODO]
 		public ConnectionState State 		{
@@ -502,12 +484,30 @@ namespace System.Data.SqlClient
 			}
 		}
 
+		#region Internal Properties
+
 		internal SqlTransaction Transaction {
 			get {
 				return trans;
 			}
 		}
 
+		// this is for System.Data.SqlClient classes
+		// to get the Postgres connection
+		internal IntPtr PostgresConnection {
+			get {
+				return pgConn;
+			}
+		}
+
+		internal ArrayList Types {
+			get {
+				return types.List;
+			}
+		}
+
+		#endregion // Internal Properties
+
 		#endregion
 
 		#region Events and Delegates
@@ -528,5 +528,131 @@ namespace System.Data.SqlClient
 		*/
 
 		#endregion
+
+		#region Classes
+
+		private class PostgresTypes {
+			// TODO: create hashtable for 
+			// PostgreSQL types to .NET types
+			// containing: oid, typname, SqlDbType
+
+			private Hashtable hashTypes;
+			private ArrayList pgTypes;
+			private SqlConnection con;
+
+			// Got this SQL with the permission from 
+			// the authors of libgda
+			private const string SEL_SQL_GetTypes = 
+				"SELECT oid, typname FROM pg_type " +
+				"WHERE typrelid = 0 AND typname !~ '^_' " +
+				" AND  typname not in ('SET', 'cid', " +
+				"'int2vector', 'oidvector', 'regproc', " +
+				"'smgr', 'tid', 'unknown', 'xid') " +
+				"ORDER BY typname";
+
+			internal PostgresTypes(SqlConnection sqlcon) {
+				
+				con = sqlcon;
+				hashTypes = new Hashtable();
+			}
+
+			private void BuildTypes(IntPtr pgResult, 
+				int nRows, int nFields) {
+
+				String value;
+
+				int r, c;
+				for(r = 0; r < nRows; r++) {
+					PostgresType pgType = 
+						new PostgresType();
+
+					for(c = 0; c < nFields; c++) {
+						// get data value
+						value = PostgresLibrary.
+							PQgetvalue(
+							pgResult,
+							r, c);
+						
+						if(c == 0) {
+							pgType.oid = Int32.Parse(value);
+						}
+						else if(c == 1) {
+							pgType.typname = String.Copy(value);
+							pgType.dbType = PostgresHelper.
+								TypnameToSqlDbType(
+								pgType.typname);
+
+							pgTypes.Add(pgType);
+						}
+						// FIXME: needs to be Read Only
+						// pgTypes = ArrayList.ReadOnly(pgTypes);
+
+					}
+				}
+			}
+
+			internal void Load() {
+				pgTypes = new ArrayList();
+				IntPtr pgResult; // PGresult
+				ExecStatusType execStatus;	
+
+				if(con.State != ConnectionState.Open)
+					throw new InvalidOperationException(
+						"ConnnectionState is not Open");
+
+				// FIXME: PQexec blocks 
+				// while PQsendQuery is non-blocking
+				// which is better to use?
+				// int PQsendQuery(PGconn *conn,
+				//        const char *query);
+
+				// execute SQL command
+				// uses internal property to get the PGConn IntPtr
+				pgResult = PostgresLibrary.
+					PQexec (con.PostgresConnection, SEL_SQL_GetTypes);
+
+				execStatus = PostgresLibrary.
+					PQresultStatus (pgResult);
+			
+				if(execStatus == ExecStatusType.PGRES_TUPLES_OK) {
+					int nRows;
+					int nFields;
+
+					nRows = PostgresLibrary.
+						PQntuples(pgResult);
+
+					nFields = PostgresLibrary.
+						PQnfields(pgResult);
+
+					BuildTypes (pgResult, nRows, nFields);
+
+					// close result set
+					PostgresLibrary.PQclear (pgResult);
+
+				}
+				else {
+					String errorMessage;
+				
+					errorMessage = PostgresLibrary.
+						PQresStatus(execStatus);
+
+					errorMessage += " " + PostgresLibrary.
+						PQresultErrorMessage(pgResult);
+				
+					throw new SqlException(0, 0,
+						errorMessage, 0, "",
+						con.DataSource, "SqlConnection", 0);
+				}
+
+			}
+
+			public ArrayList List {
+				get {
+					return pgTypes;
+				}
+			}
+		}
+
+		#endregion
 	}
 }

+ 71 - 78
mcs/class/System.Data/System.Data.SqlClient/SqlDataReader.cs

@@ -6,14 +6,25 @@
 //   Daniel Morgan ([email protected])
 //
 // (C) Ximian, Inc 2002
+// (C) Daniel Morgan 2002
 //
+// Credits:
+//    SQL and concepts were used from libgda 0.8.190 (GNOME Data Access)
+//    http://www.gnome-db.org/
+//    with permission from the authors of the
+//    PostgreSQL provider in libgda:
+//        Michael Lausch <[email protected]>
+//        Rodrigo Moya <[email protected]>
+//        Vivien Malerba <[email protected]>
+//        Gonzalo Paniagua Javier <[email protected]>
+//
+
 using System;
 using System.Collections;
 using System.ComponentModel;
 using System.Data;
 
-namespace System.Data.SqlClient
-{
+namespace System.Data.SqlClient {
 	/// <summary>
 	/// Provides a means of reading one or more forward-only streams
 	/// of result sets obtained by executing a command 
@@ -22,15 +33,15 @@ namespace System.Data.SqlClient
 	//public sealed class SqlDataReader : MarshalByRefObject,
 	//	IEnumerable, IDataReader, IDisposable, IDataRecord
 	public sealed class SqlDataReader : IEnumerable, 
-		IDataReader, IDataRecord
-	{
+		IDataReader, IDataRecord {
 		#region Fields
 
 		private SqlCommand cmd;
 		private DataTable table;
 
 		private object[] fields;
-		private int[] oid; // PostgreSQL Type
+		private string[] types; // PostgreSQL Type
+		private bool[] isNull;
 				
 		private bool open = false;
 		IntPtr pgResult; // PGresult
@@ -45,14 +56,15 @@ namespace System.Data.SqlClient
 
 		internal SqlDataReader (SqlCommand sqlCmd, 
 			DataTable dataTableSchema, IntPtr pg_result,
-			int rowCount, int fieldCount, int[] oids) {
+			int rowCount, int fieldCount, string[] pgtypes) {
 
 			cmd = sqlCmd;
 			table = dataTableSchema;
 			pgResult = pg_result;
 			rows = rowCount;
 			cols = fieldCount;
-			oid = oids;
+			types = pgtypes;
+			open = true;
 		}
 
 		#endregion
@@ -60,31 +72,28 @@ namespace System.Data.SqlClient
 		#region Public Methods
 
 		[MonoTODO]
-		public void Close()
-		{
+		public void Close() {
 			// close result set
 			PostgresLibrary.PQclear (pgResult);
-
+			open = false;
 			// TODO: change busy state on SqlConnection to not busy
 		}
 
 		[MonoTODO]
-		public DataTable GetSchemaTable()
-		{
+		public DataTable GetSchemaTable() {
 			return table;
 		}
 
 		[MonoTODO]
-		public bool NextResult()
-		{
+		public bool NextResult() {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool Read()
-	        {
+		public bool Read() {
 			string value;
 			fields = new object[cols]; // re-init row
+			DbType dbType;
 
 			if(currentRow < rows - 1)  {
 				currentRow++;
@@ -109,8 +118,13 @@ namespace System.Data.SqlClient
 						PQgetlength(pgResult,
 						currentRow, c);
 						
+					dbType = PostgresHelper.
+						TypnameToSqlDbType(types[c]);
+
 					fields[c] = PostgresHelper.
-						ConvertPgTypeToSystem (oid[c], value);
+						ConvertDbTypeToSystem (
+							dbType,
+							value);
 				}
 				return true;
 			}
@@ -118,139 +132,117 @@ namespace System.Data.SqlClient
 		}
 
 		[MonoTODO]
-		public byte GetByte(int i)
-		{
+		public byte GetByte(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
 		public long GetBytes(int i, long fieldOffset, 
 			byte[] buffer, int bufferOffset, 
-			int length)
-		{
+			int length) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public char GetChar(int i)
-		{
+		public char GetChar(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
 		public long GetChars(int i, long fieldOffset, 
 			char[] buffer, int bufferOffset, 
-			int length)
-		{
+			int length) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public IDataReader GetData(int i)
-		{
+		public IDataReader GetData(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public string GetDataTypeName(int i)
-		{
+		public string GetDataTypeName(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public DateTime GetDateTime(int i)
-		{
+		public DateTime GetDateTime(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public decimal GetDecimal(int i)
-		{
-			throw new NotImplementedException ();
+		public decimal GetDecimal(int i) {
+			return (decimal) fields[i];
 		}
 
 		[MonoTODO]
-		public double GetDouble(int i)
-		{
-			throw new NotImplementedException ();
+		public double GetDouble(int i) {
+			return (double) fields[i];
 		}
 
 		[MonoTODO]
-		public Type GetFieldType(int i)
-		{
+		public Type GetFieldType(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public float GetFloat(int i)
-		{
-			throw new NotImplementedException ();
+		public float GetFloat(int i) {
+			return (float) fields[i];
 		}
 
 		[MonoTODO]
-		public Guid GetGuid(int i)
-		{
+		public Guid GetGuid(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public short GetInt16(int i)
-		{
+		public short GetInt16(int i) {
 			return (short) fields[i];
 		}
 
 		[MonoTODO]
-		public int GetInt32(int i)
-		{
+		public int GetInt32(int i) {
 			return (int) fields[i];
 		}
 
 		[MonoTODO]
-		public long GetInt64(int i)
-		{
+		public long GetInt64(int i) {
 			return (long) fields[i];
 		}
 
 		[MonoTODO]
-		public string GetName(int i)
-		{
+		public string GetName(int i) {
 			return table.Columns[i].ColumnName;
 		}
 
 		[MonoTODO]
-		public int GetOrdinal(string name)
-		{
+		public int GetOrdinal(string name) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public string GetString(int i)
-		{
+		public string GetString(int i) {
 			return (string) fields[i];
 		}
 
 		[MonoTODO]
-		public object GetValue(int i)
-		{
+		public object GetValue(int i) {
 			return fields[i];
 		}
 
 		[MonoTODO]
-		public int GetValues(object[] values)
-		{
+		public int GetValues(object[] values) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool IsDBNull(int i)
-		{
+		public bool IsDBNull(int i) {
 			throw new NotImplementedException ();
 		}
 
 		[MonoTODO]
-		public bool GetBoolean(int i)
-		{
-			throw new NotImplementedException ();
+		public bool GetBoolean(int i) {
+			return (bool) fields[i];
 		}
 
 		[MonoTODO]
@@ -284,7 +276,10 @@ namespace System.Data.SqlClient
 		public bool IsClosed {
 			[MonoTODO]
 			get {
-				throw new NotImplementedException (); 
+				if(open == false)
+					return true;
+				else
+					return false;
 			}
 		}
 
@@ -312,28 +307,26 @@ namespace System.Data.SqlClient
 					}
 
 				}
-				
-				if(i == cols) {
-					for(i = 0; i < cols; i++) {
-						string ta;
-						string n;
+	
+				for(i = 0; i < cols; i++) {
+					string ta;
+					string n;
 						
-						ta = table.Columns[i].ColumnName.ToUpper();
-						n = name.ToUpper();
+					ta = table.Columns[i].ColumnName.ToUpper();
+					n = name.ToUpper();
 						
-						if(ta.Equals(n)) {
-							return fields[i];
-						}
+					if(ta.Equals(n)) {
+						return fields[i];
 					}
 				}
+			
 				throw new MissingFieldException("Missing field: " + name);
 			}
 		}
 
 		public object this[int i] {
 			[MonoTODO]
-			get 
-			{ 
+			get { 
 				return fields[i];
 			}
 		}

+ 2 - 0
mcs/class/System.Data/System.Data.SqlTypes/SqlInt32.cs

@@ -8,6 +8,8 @@
 // (C) Ximian, Inc. 2002
 //
 
+using System;
+
 namespace System.Data.SqlTypes
 {
 

+ 2 - 2
mcs/class/System.Data/Test/ReadPostgresData.cs

@@ -553,9 +553,9 @@ namespace LearnToCreateSqlDataReader
 		[STAThread]
 		static void Main(string[] args)
 		{
-			Test();
+			// Test();
 
-			TestExecuteScalar();
+			// TestExecuteScalar();
 
 			Type t;
 			int oid;

+ 4 - 1
mcs/class/System.Data/Test/TestSqlDataReader.cs

@@ -64,7 +64,7 @@ namespace TestSystemDataSqlClient
 				Console.WriteLine("         Type: " +
 					dt.Columns[c].DataType);
 			}
-
+			int nRows = 0;
 			// Read and display the rows
 			while(rdr.Read()) {
 				Console.WriteLine("Row: " +
@@ -78,7 +78,10 @@ namespace TestSystemDataSqlClient
 				Console.WriteLine("2: " + rdr.GetString(1));
 				Console.WriteLine("3: " + rdr.GetInt32(2));
 				Console.WriteLine("4: " + rdr.GetString(3));
+				nRows++;
 			}
+			Console.WriteLine("Rows: " + 
+				nRows);
 			
 			rdr.Close();
 			con.Close();