]> granicus.if.org Git - php/commitdiff
Retry on failed prepare resulting from duplicate statement name.
authorIlia Alshanetsky <iliaa@php.net>
Sat, 17 Dec 2005 17:59:05 +0000 (17:59 +0000)
committerIlia Alshanetsky <iliaa@php.net>
Sat, 17 Dec 2005 17:59:05 +0000 (17:59 +0000)
ext/pdo_pgsql/pgsql_statement.c
ext/pdo_pgsql/php_pdo_pgsql_int.h

index aaf3664b6bfe54dc68ab53468596a805be9bf2de..441ebd39aef339416526945c13dd2cc3b55e8393 100644 (file)
@@ -126,7 +126,8 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
        if (S->stmt_name) {
                /* using a prepared statement */
 
-               if (!stmt->executed) {
+               if (!S->is_prepared) {
+stmt_retry:
                        /* we deferred the prepare until now, because we didn't
                         * know anything about the parameter types; now we do */
                        S->result = PQprepare(H->server, S->stmt_name, S->query, 
@@ -137,12 +138,31 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
                                case PGRES_COMMAND_OK:
                                case PGRES_TUPLES_OK:
                                        /* it worked */
+                                       S->is_prepared = 1;
                                        PQclear(S->result);
                                        break;
-                               default:
-                                       pdo_pgsql_error_stmt(stmt, status,
-                                                       pdo_pgsql_sqlstate(S->result));
-                                       return 0;
+                               default: {
+                                       char *sqlstate = pdo_pgsql_sqlstate(S->result);
+                                       /* 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 chanche 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)
+                                        */
+                                       if (!strcmp(sqlstate, "42P05")) {
+                                               char buf[100]; /* stmt_name == "pdo_pgsql_cursor_%08x" */
+                                               PGresult *res;
+                                               snprintf(buf, sizeof(buf), "DEALLOCATE %s", S->stmt_name);
+                                               res = PQexec(H->server, buf);
+                                               if (res) {
+                                                       PQclear(res);
+                                               }
+                                               goto stmt_retry;
+                                       } else {
+                                               pdo_pgsql_error_stmt(stmt, status, sqlstate);
+                                               return 0;
+                                       }
+                               }
                        }
                }
                S->result = PQexecPrepared(H->server, S->stmt_name,
index 5f799161cd62cdade44af2958fbfb969b9dcbbe7..e91f5e0b58b42e5e69f730c24967822acf4bde37 100644 (file)
@@ -65,6 +65,7 @@ typedef struct {
        int *param_lengths;
        int *param_formats;
        Oid *param_types;
+       zend_bool is_prepared;
 #endif
 } pdo_pgsql_stmt;