I have patched DBD::Pg to make it work slighty better.  Version 1.01
will pass garbage connection handles to postgres library routines, with
undefined consequences.  In my improved version, DBD::Pg will only pass
valid connections to the postgres library.  The patch is attached. 
Please test it and let me know if it works for you.

Is the DBD::Pg maintained?  It's documentation is rotting slightly.  If
Edmund wants to hand it off, I'd be pleased to take it on.

Aside:  It seems that DBI is willing to call into the DBD implementation
to fetch (dbd_st_fetch) even on handles which have been invalidated by
disconnection.  Should not these statement handles have Active marked
FALSE upon dbh disconnection?  The DBI detects and carps about this
situation but doesn't do anything about it.

Regards,
Jeffrey


--- DBD-Pg-1.01/dbdimp.c        Wed Jun 27 10:54:58 2001
+++ DBD-Pg-1.01-jwb/dbdimp.c    Sun Feb 17 13:26:36 2002
@@ -4,7 +4,10 @@
 
    Copyright (c) 1997,1998,1999,2000 Edmund Mergl
    Portions Copyright (c) 1994,1995,1996,1997 Tim Bunce
-
+   
+   Contributors:
+      Jeffrey W. Baker <[EMAIL PROTECTED]>: Crash fixes
+   
    You may distribute under the terms of either the GNU General Public
    License or the Artistic License, as specified in the Perl README file.
 
@@ -208,15 +211,19 @@
 
     if (dbis->debug >= 1) { fprintf(DBILOGFP, "dbd_db_ping\n"); }
 
-    result = PQexec(imp_dbh->conn, " ");
-    status = result ? PQresultStatus(result) : -1;
-    PQclear(result);
+    if (NULL != imp_dbh->conn) {
+        result = PQexec(imp_dbh->conn, " ");
+        status = result ? PQresultStatus(result) : -1;
+        PQclear(result);
 
-    if (PGRES_EMPTY_QUERY != status) {
-        return 0;
-    }
+        if (PGRES_EMPTY_QUERY != status) {
+            return 0;
+        }
 
-    return 1;
+        return 1;
+    }
+    
+    return 0;
 }
 
 
@@ -225,10 +232,6 @@
     SV *dbh;
     imp_dbh_t *imp_dbh;
 {
-    PGresult* result = 0;
-    ExecStatusType status;
-    int retval = 1;
-
     if (dbis->debug >= 1) { fprintf(DBILOGFP, "dbd_db_commit\n"); }
 
     /* no commit if AutoCommit = on */
@@ -236,19 +239,22 @@
         return 0;
     }
 
-    /* execute commit */
-    result = PQexec(imp_dbh->conn, "commit");
-    status = result ? PQresultStatus(result) : -1;
-    PQclear(result);
-
-    /* check result */
-    if (status != PGRES_COMMAND_OK) {
-        pg_error(dbh, status, "commit failed\n");
-        return 0;
-    }
+    if (NULL != imp_dbh->conn) {
+        PGresult* result = 0;
+        ExecStatusType status;
+
+        /* execute commit */
+        result = PQexec(imp_dbh->conn, "commit");
+        status = result ? PQresultStatus(result) : -1;
+        PQclear(result);
 
-    /* start new transaction if AutoCommit = off */
-    if (DBIc_has(imp_dbh, DBIcf_AutoCommit) == FALSE) {
+        /* check result */
+        if (status != PGRES_COMMAND_OK) {
+            pg_error(dbh, status, "commit failed\n");
+            return 0;
+        }
+
+        /* start new transaction.  AutoCommit must be FALSE, ref. 20 lines up */
         result = PQexec(imp_dbh->conn, "begin");
         status = result ? PQresultStatus(result) : -1;
         PQclear(result);
@@ -256,9 +262,11 @@
             pg_error(dbh, status, "begin failed\n");
             return 0;
         }
+        
+        return 1;
     }
-
-    return retval;
+    
+    return 0;
 }
 
 
@@ -267,10 +275,6 @@
     SV *dbh;
     imp_dbh_t *imp_dbh;
 {
-    PGresult* result = 0;
-    ExecStatusType status;
-    int retval = 1;
-
     if (dbis->debug >= 1) { fprintf(DBILOGFP, "dbd_db_rollback\n"); }
 
     /* no rollback if AutoCommit = on */
@@ -278,19 +282,22 @@
         return 0;
     }
 
-    /* execute rollback */
-    result = PQexec(imp_dbh->conn, "rollback");
-    status = result ? PQresultStatus(result) : -1;
-    PQclear(result);
-
-    /* check result */
-    if (status != PGRES_COMMAND_OK) {
-        pg_error(dbh, status, "rollback failed\n");
-        return 0;
-    }
+    if (NULL != imp_dbh->conn) {
+        PGresult* result = 0;
+        ExecStatusType status;
+        
+        /* execute rollback */
+        result = PQexec(imp_dbh->conn, "rollback");
+        status = result ? PQresultStatus(result) : -1;
+        PQclear(result);
 
-    /* start new transaction if AutoCommit = off */
-    if (DBIc_has(imp_dbh, DBIcf_AutoCommit) == FALSE) {
+        /* check result */
+        if (status != PGRES_COMMAND_OK) {
+            pg_error(dbh, status, "rollback failed\n");
+            return 0;
+        }
+
+        /* start new transaction.  AutoCommit must be FALSE, ref. 20 lines up */
         result = PQexec(imp_dbh->conn, "begin");
         status = result ? PQresultStatus(result) : -1;
         PQclear(result);
@@ -298,9 +305,11 @@
             pg_error(dbh, status, "begin failed\n");
             return 0;
         }
+        
+        return 1;
     }
 
-    return retval;
+    return 0;
 }
 
 
@@ -317,22 +326,26 @@
     /* since most errors imply already disconnected.   */
     DBIc_ACTIVE_off(imp_dbh);
 
-    /* rollback if AutoCommit = off */
-    if (DBIc_has(imp_dbh, DBIcf_AutoCommit) == FALSE) {
-        PGresult* result = 0;
-        ExecStatusType status;
-        result = PQexec(imp_dbh->conn, "rollback");
-        status = result ? PQresultStatus(result) : -1;
-        PQclear(result);
-        if (status != PGRES_COMMAND_OK) {
-            pg_error(dbh, status, "rollback failed\n");
-            return 0;
+    if (NULL != imp_dbh->conn) {
+        /* rollback if AutoCommit = off */
+        if (DBIc_has(imp_dbh, DBIcf_AutoCommit) == FALSE) {
+            PGresult* result = 0;
+            ExecStatusType status;
+            result = PQexec(imp_dbh->conn, "rollback");
+            status = result ? PQresultStatus(result) : -1;
+            PQclear(result);
+            if (status != PGRES_COMMAND_OK) {
+                pg_error(dbh, status, "rollback failed\n");
+                return 0;
+            }
+            if (dbis->debug >= 2) { fprintf(DBILOGFP, "dbd_db_disconnect: 
+AutoCommit=off -> rollback\n"); }
         }
-        if (dbis->debug >= 2) { fprintf(DBILOGFP, "dbd_db_disconnect: AutoCommit=off 
-> rollback\n"); }
-    }
-
-    PQfinish(imp_dbh->conn);
 
+        PQfinish(imp_dbh->conn);
+        
+        imp_dbh->conn = NULL;
+    }
+    
     /* We don't free imp_dbh since a reference still exists    */
     /* The DESTROY method is the only one to 'free' memory.    */
     /* Note that statement objects may still exists for this dbh!      */
@@ -376,27 +389,31 @@
             /* do nothing, fall through */
             if (dbis->debug >= 2) { fprintf(DBILOGFP, "dbd_db_STORE: initialize 
AutoCommit to on\n"); }
         } else if (oldval == FALSE && newval != FALSE) {
-            /* commit any outstanding changes */
-            PGresult* result = 0;
-            ExecStatusType status;
-            result = PQexec(imp_dbh->conn, "commit");
-            status = result ? PQresultStatus(result) : -1;
-            PQclear(result);
-            if (status != PGRES_COMMAND_OK) {
-                pg_error(dbh, status, "commit failed\n");
-                return 0;
-            }
+            if (NULL != imp_dbh->conn) {
+                /* commit any outstanding changes */
+                PGresult* result = 0;
+                ExecStatusType status;
+                result = PQexec(imp_dbh->conn, "commit");
+                status = result ? PQresultStatus(result) : -1;
+                PQclear(result);
+                if (status != PGRES_COMMAND_OK) {
+                    pg_error(dbh, status, "commit failed\n");
+                    return 0;
+                }
+            }            
             if (dbis->debug >= 2) { fprintf(DBILOGFP, "dbd_db_STORE: switch 
AutoCommit to on: commit\n"); }
         } else if ((oldval != FALSE && newval == FALSE) || (oldval == FALSE && newval 
== FALSE && imp_dbh->init_commit)) {
-            /* start new transaction */
-            PGresult* result = 0;
-            ExecStatusType status;
-            result = PQexec(imp_dbh->conn, "begin");
-            status = result ? PQresultStatus(result) : -1;
-            PQclear(result);
-            if (status != PGRES_COMMAND_OK) {
-                pg_error(dbh, status, "begin failed\n");
-                return 0;
+            if (NULL != imp_dbh->conn) {
+                /* start new transaction */
+                PGresult* result = 0;
+                ExecStatusType status;
+                result = PQexec(imp_dbh->conn, "begin");
+                status = result ? PQresultStatus(result) : -1;
+                PQclear(result);
+                if (status != PGRES_COMMAND_OK) {
+                    pg_error(dbh, status, "begin failed\n");
+                    return 0;
+                }
             }
             if (dbis->debug >= 2) { fprintf(DBILOGFP, "dbd_db_STORE: switch 
AutoCommit to off: begin\n"); }
         }
@@ -1020,6 +1037,11 @@
     statement = SvPV(*svp, na);
     */
 
+    if (NULL == imp_dbh->conn) {
+        pg_error(sth, -1, "execute on disconnected handle");        
+        return -2;
+    }   
+    
     statement = imp_sth->statement;
     if (! statement) {
         /* are we prepared ? */

Reply via email to