[Mono-list] Re: Postgresql client on Windows - VERY STRANGE

Jaroslaw Kowalski jarek@atm.com.pl
Thu, 9 Jan 2003 00:53:49 +0100


This is a multi-part message in MIME format.

------=_NextPart_000_0011_01C2B779.92381530
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 8bit

I've been trying to investigate this problem (running
Mono.Data.PostgreSqlClient compiled with CSC under .NET on Windows) and
almost managed to solve it (well, kind of) ;-)

I've discovered the following problems (patch for cases 1,3 is attached, but
consider it highly experimental - don't commit):

1. PostgresLibrary.cs fails to marshal string return values correctly. MS
docs/samples say that when you declare a function that returns a pointer to
internal buffer, like getenv() under Unix or GetCommandLine() under Win32,
you cannot marshal is as "[DllImport()] static string whatever();", but
instead you must use the following construct (taken from my patched
PostgreSqlClient)

===========================================
[DllImport("pq",EntryPoint="PQresultErrorMessage")]
private static extern IntPtr PQresultErrorMessage0 (IntPtr res);

public static string PQresultErrorMessage(IntPtr res)
{
    return Marshal.PtrToStringAnsi(PQresultErrorMessage0(res));
}

===========================================

When you write "static string function(parameters)" the function is expected
to ALLOCATE the returned string on task heap (using CoTaskMemAlloc() under
Windows), so CLR will happily free the string when it's no longer used, but
unfortunately when you return the static pointer to the CLR, it will attempt
to free an unallocated memory block, which is a big BOOM.

Source:
FrameworkSDK/Samples/Technologies/Interop/PlatformInvoke/WinAPIs/CS/Buffers.
cs

2. This also means that mono's marshalling is somehow broken, or the memory
isn't properly released in this case. I didn't look deep into it, so I
cannot tell you more.

3. The third (very minor) problem with PostgreSql under windows are the
lines in PgSqlCommand.cs which cause exception (I don't remember what it
was, but swapping the rows helped eliminate the exception).

      schemaRow.AcceptChanges();
      dataTableSchema.Rows.Add (schemaRow);

4. The last, but the BIGGEST PROBLEM still remains unsolved. The whole thing
works in Debug mode but not in Release under Windows. In release it seems to
corrupt the memory, so that String.Format() returns an exception. Maybe the
corruption also occurs in Debug mode, but is somehow masked, I don't know.

The following (the simplest one I could come up with) snippet fails under
Release but works under Debug

IntPtr ip = Mono.Data.PostgreSqlClient.PostgresLibrary.PQconndefaults();
Console.WriteLine("test {0}", 1);

with

Unhandled Exception: System.IO.IOException: The handle is invalid.

   at System.IO.__Error.WinIOError(Int32 errorCode, String str)
   at System.IO.__ConsoleStream.Write(Byte[] buffer, Int32 offset, Int32
count)
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean
flushEncoder)
   at System.IO.StreamWriter.Write(Char[] buffer, Int32 index, Int32 count)
   at System.IO.TextWriter.WriteLine(String value)
   at System.IO.TextWriter.WriteLine(String format, Object arg0)
   at System.IO.SyncTextWriter.WriteLine(String format, Object arg0)
   at DBTool.DBToolMain.Test()
   at DBTool.DBToolMain.Main(String[] args)

I've got no clue here. Anyone can help?

Jarek

----- Original Message -----
From: "Weiss-Graef Dieter" <Dieter.Weiss@fh-bonn-rhein-sieg.de>
To: <jarek@atm.com.pl>
Sent: Wednesday, January 08, 2003 6:52 PM
Subject: Postgresql client on Windows


Hi,

have you found any solutions for this (I have the same problems):

http://lists.ximian.com/archives/public/mono-list/2002-November/003625.html
?

Dieter

-------------------------------------------
Fachhochschule Bonn-Rhein-Sieg
University of Applied Sciences
Dieter Weiß-Gräf

Grantham Allee 20
53757 Sankt Augustin (Germany)
Tel: +49 (2241) 865 - 635
Fax: +49 (2241) 865 - 8635
http://www.fh-rhein-sieg.de
mailto:dieter.weiss@fh-bonn-rhein-sieg.de

------=_NextPart_000_0011_01C2B779.92381530
Content-Type: application/octet-stream;
	name="postgresql.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="postgresql.patch"

Index: PgSqlCommand.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: =
/mono/mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/PgS=
qlCommand.cs,v=0A=
retrieving revision 1.31=0A=
diff -u -r1.31 PgSqlCommand.cs=0A=
--- PgSqlCommand.cs	6 Dec 2002 12:34:22 -0000	1.31=0A=
+++ PgSqlCommand.cs	8 Jan 2003 23:23:35 -0000=0A=
@@ -886,8 +886,9 @@=0A=
 					schemaRow["IsHidden"] =3D false;=0A=
 					schemaRow["IsLong"] =3D false;=0A=
 					schemaRow["IsReadOnly"] =3D false;=0A=
-					schemaRow.AcceptChanges();=0A=
+=0A=
 					dataTableSchema.Rows.Add (schemaRow);=0A=
+					schemaRow.AcceptChanges();=0A=
 				}=0A=
 				=0A=
 #if DEBUG_SqlCommand=0A=
Index: PgSqlConnection.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: =
/mono/mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/PgS=
qlConnection.cs,v=0A=
retrieving revision 1.22=0A=
diff -u -r1.22 PgSqlConnection.cs=0A=
--- PgSqlConnection.cs	14 Nov 2002 12:40:40 -0000	1.22=0A=
+++ PgSqlConnection.cs	8 Jan 2003 23:23:36 -0000=0A=
@@ -214,7 +214,7 @@=0A=
 					"ConnnectionState is already Open");=0A=
 =0A=
 			ConnStatusType connStatus;=0A=
-=0A=
+			=0A=
 			// FIXME: check to make sure we have =0A=
 			//        everything to connect,=0A=
 			//        otherwise, throw an exception=0A=
Index: PostgresLibrary.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: =
/mono/mcs/class/Mono.Data.PostgreSqlClient/Mono.Data.PostgreSqlClient/Pos=
tgresLibrary.cs,v=0A=
retrieving revision 1.14=0A=
diff -u -r1.14 PostgresLibrary.cs=0A=
--- PostgresLibrary.cs	6 Dec 2002 12:34:22 -0000	1.14=0A=
+++ PostgresLibrary.cs	8 Jan 2003 23:23:36 -0000=0A=
@@ -117,41 +117,45 @@=0A=
 		// int PQrequestCancel(PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQdb (IntPtr conn);=0A=
+		private static extern IntPtr PQdb0 (IntPtr conn);=0A=
 		// char *PQdb(const PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQuser (IntPtr conn);=0A=
+		private static extern IntPtr PQuser0 (IntPtr conn);=0A=
 		// char *PQuser(const PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQpass (IntPtr conn);=0A=
+		private static extern IntPtr PQpass0 (IntPtr conn);=0A=
 		// char *PQpass(const PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQhost (IntPtr conn);=0A=
+		private static extern IntPtr PQhost0 (IntPtr conn);=0A=
 		// char *PQhost(const PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQport (IntPtr conn);=0A=
+		private static extern IntPtr PQport0 (IntPtr conn);=0A=
 		// char *PQport(const PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQtty (IntPtr conn);=0A=
+		private static extern IntPtr PQtty0 (IntPtr conn);=0A=
 		// char *PQtty(const PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQoptions (IntPtr conn);=0A=
+		private static extern IntPtr PQoptions0 (IntPtr conn);=0A=
 		// char *PQoptions(const PGconn *conn);=0A=
 =0A=
 		[DllImport("pq")]=0A=
 		public static extern ConnStatusType PQstatus (IntPtr conn);=0A=
 		// ConnStatusType PQstatus(const PGconn *conn);=0A=
 =0A=
-		[DllImport("pq")]=0A=
-		public static extern string PQerrorMessage (IntPtr conn);=0A=
+		[DllImport("pq",EntryPoint=3D"PQerrorMessage")]=0A=
+		private static extern IntPtr PQerrorMessage0 (IntPtr conn);=0A=
 		// char *PQerrorMessage(const PGconn *conn);=0A=
 =0A=
+		public static string PQerrorMessage(IntPtr conn)=0A=
+		{=0A=
+			return Marshal.PtrToStringAnsi(PQerrorMessage0(conn));=0A=
+		}=0A=
 		[DllImport("pq")]=0A=
 		public static extern int PQsocket (IntPtr conn);=0A=
 		// int PQsocket(const PGconn *conn);=0A=
@@ -290,12 +294,22 @@=0A=
 		public static extern ExecStatusType PQresultStatus (IntPtr res);=0A=
 		// ExecStatusType PQresultStatus(const PGresult *res);=0A=
 =0A=
-		[DllImport("pq")]=0A=
-		public static extern string PQresStatus (ExecStatusType status);=0A=
+		[DllImport("pq",EntryPoint=3D"PQresStatus")]=0A=
+		private static extern IntPtr PQresStatus0 (ExecStatusType status);=0A=
 		// char *PQresStatus(ExecStatusType status);=0A=
 =0A=
-		[DllImport("pq")]=0A=
-		public static extern string PQresultErrorMessage (IntPtr res);=0A=
+		public static string PQresStatus(ExecStatusType status)=0A=
+		{=0A=
+			return Marshal.PtrToStringAnsi(PQresStatus0(status));=0A=
+		}=0A=
+=0A=
+		[DllImport("pq",EntryPoint=3D"PQresultErrorMessage")]=0A=
+		private static extern IntPtr PQresultErrorMessage0 (IntPtr res);=0A=
+=0A=
+		public static string PQresultErrorMessage(IntPtr res)=0A=
+		{=0A=
+			return Marshal.PtrToStringAnsi(PQresultErrorMessage0(res));=0A=
+		}=0A=
 		// char *PQresultErrorMessage(const PGresult *res);=0A=
 =0A=
 		[DllImport("pq")]=0A=
@@ -310,12 +324,17 @@=0A=
 		public static extern int PQbinaryTuples (IntPtr res);=0A=
 		// int PQbinaryTuples(const PGresult *res);=0A=
 =0A=
-		[DllImport("pq")]=0A=
-		public static extern string PQfname (IntPtr res,=0A=
+		[DllImport("pq",EntryPoint=3D"PQfname")]=0A=
+		private static extern IntPtr PQfname0 (IntPtr res,=0A=
                         int field_num);=0A=
 		// char *PQfname(const PGresult *res,=0A=
                 //      int field_num);=0A=
 =0A=
+		public static string PQfname(IntPtr res, int field_num)=0A=
+		{=0A=
+			return Marshal.PtrToStringAnsi(PQfname0(res, field_num));=0A=
+		}=0A=
+=0A=
 		[DllImport("pq")]=0A=
 		public static extern int PQfnumber (IntPtr res,=0A=
                         string field_name);=0A=
@@ -339,27 +358,37 @@=0A=
 		// int PQfmod(const PGresult *res, int field_num);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQcmdStatus (IntPtr res);=0A=
+		private static extern IntPtr PQcmdStatus0 (IntPtr res);=0A=
 		// char *PQcmdStatus(PGresult *res);=0A=
 =0A=
 		[DllImport("pq")]=0A=
-		public static extern string PQoidStatus (IntPtr res);=0A=
+		private static extern IntPtr PQoidStatus0 (IntPtr res);=0A=
 		// char *PQoidStatus(const PGresult *res);=0A=
 =0A=
 		[DllImport("pq")]=0A=
 		public static extern int PQoidValue (IntPtr res);=0A=
 		// Oid PQoidValue(const PGresult *res);=0A=
 =0A=
-		[DllImport("pq")]=0A=
-		public static extern string PQcmdTuples (IntPtr res);=0A=
+		[DllImport("pq",EntryPoint=3D"PQcmdTuples")]=0A=
+		private static extern IntPtr PQcmdTuples0 (IntPtr res);=0A=
+=0A=
+		public static string PQcmdTuples(IntPtr res)=0A=
+		{=0A=
+			return Marshal.PtrToStringAnsi(PQcmdTuples0(res));=0A=
+		}=0A=
 		// char *PQcmdTuples(PGresult *res);=0A=
 =0A=
-		[DllImport("pq")]=0A=
-		public static extern string PQgetvalue (IntPtr res,=0A=
+		[DllImport("pq",EntryPoint=3D"PQgetvalue")]=0A=
+		private static extern IntPtr PQgetvalue0 (IntPtr res,=0A=
                         int tup_num, int field_num);=0A=
 		// char *PQgetvalue(const PGresult *res,=0A=
                 //      int tup_num, int field_num);=0A=
 =0A=
+		public static string PQgetvalue(IntPtr res,=0A=
+			int tup_num, int field_num)=0A=
+		{=0A=
+			return Marshal.PtrToStringAnsi(PQgetvalue0(res, tup_num, field_num));=0A=
+		}=0A=
 		[DllImport("pq")]=0A=
 		public static extern int PQgetlength (IntPtr res,=0A=
                         int tup_num, int field_num);=0A=

------=_NextPart_000_0011_01C2B779.92381530--