]> granicus.if.org Git - php/commitdiff
- Fixed bug #49985 (pdo_pgsql prepare() re-use previous aborted transaction).
authorIlia Alshanetsky <iliaa@php.net>
Mon, 26 Oct 2009 02:02:28 +0000 (02:02 +0000)
committerIlia Alshanetsky <iliaa@php.net>
Mon, 26 Oct 2009 02:02:28 +0000 (02:02 +0000)
ext/pdo_pgsql/pgsql_statement.c

index f19a6646c6bd0c4471c4e0c750859fc487f7dd0f..cee7add1d091ef2fcbf0333e5a7e4d5b8e5e224e 100644 (file)
@@ -162,6 +162,14 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
                /* using a prepared statement */
 
                if (!S->is_prepared) {
+                       /* don't break the whole current transaction when the first
+                        * prepare tentative fails (happens when the prepared statement
+                        * already exists). ignore those SAVEPOINT queries results because 
+                        * we don't care (may be outside transaction?).
+                        */
+                       char buf[100]; /* stmt_name == "pdo_pgsql_cursor_%08x" */
+                       snprintf(buf, sizeof(buf), "SAVEPOINT %s", S->stmt_name);
+                       PQexec(H->server, buf);
 stmt_retry:
                        /* we deferred the prepare until now, because we didn't
                         * know anything about the parameter types; now we do */
@@ -181,12 +189,14 @@ stmt_retry:
                                        /* 42P05 means that the prepared statement already existed. this can happen if you use 
                                         * a connection pooling software line pgpool which doesn't close the db-connection once 
                                         * php disconnects. if php dies (no chance to run RSHUTDOWN) during execution it has no 
-                                        * chance to DEALLOCATE the prepared statements it has created. so, if we hit a 42P05 we 
-                                        * deallocate it and retry ONCE (thies 2005.12.15)
+                                        * chance to DEALLOCATE the prepared statements it has created. Also happens if we tried
+                                        * to DEALLOCATE the same statement name in an aborted transaction. so, if we hit a 42P05
+                                        * we deallocate it and retry ONCE (thies 2005.12.15)
                                         */
                                        if (!strcmp(sqlstate, "42P05")) {
-                                               char buf[100]; /* stmt_name == "pdo_crsr_%016lx" */
                                                PGresult *res;
+                                               snprintf(buf, sizeof(buf), "ROLLBACK TO SAVEPOINT %s", S->stmt_name);
+                                               PQexec(H->server, buf);
                                                snprintf(buf, sizeof(buf), "DEALLOCATE %s", S->stmt_name);
                                                res = PQexec(H->server, buf);
                                                if (res) {
@@ -194,11 +204,15 @@ stmt_retry:
                                                }
                                                goto stmt_retry;
                                        } else {
+                                               snprintf(buf, sizeof(buf), "RELEASE SAVEPOINT %s", S->stmt_name);
+                                               PQexec(H->server, buf);
                                                pdo_pgsql_error_stmt(stmt, status, sqlstate);
                                                return 0;
                                        }
                                }
                        }
+                       snprintf(buf, sizeof(buf), "RELEASE SAVEPOINT %s", S->stmt_name);
+                       PQexec(H->server, buf);
                }
                S->result = PQexecPrepared(H->server, S->stmt_name,
                                stmt->bound_params ?