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 ? */