]> granicus.if.org Git - php/commitdiff
Fixed bug #72759 Regression in pgo_pgsql
authorAnatol Belski <ab@php.net>
Sun, 14 Aug 2016 17:33:24 +0000 (19:33 +0200)
committerAnatol Belski <ab@php.net>
Sun, 14 Aug 2016 17:33:24 +0000 (19:33 +0200)
This is caused by the fix for #72633. Namely, lastval() throws an error,
if no nextval() was called earlier in the same session. This is by all
means correct so far, however inside a transaction it leads to an abort.
This is the opposite to MySQL's last_insert_id() which doesn't produce
any error no matter something were autoincremented or not.

To avoid existing scripts breakage in the stable branches, the previous
patch is extended to revert the transaction to the state before the lastval()
call in case of error. It is done only for 5.6 and 7.0 to retain BC. For 7.1+,
the clean behavior should persist. This is already the current behavior, when
the sequence name is explicitly passed. So there's no reason to obfuscate the
errors where this breakage is valid.

ext/pdo_pgsql/pgsql_driver.c

index 5b78bcc438153424784ca39ae2eb47dee58653b1..b27753b47f61bafab3d5fc9e0e84d5acd8910eff 100644 (file)
@@ -360,8 +360,15 @@ static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned
        char *id = NULL;
        PGresult *res;
        ExecStatusType status;
+       zend_bool savepoint = 0;
 
        if (name == NULL) {
+               savepoint = pgsql_handle_in_transaction(dbh);
+
+               if (savepoint) {
+                       /* The savepoint is overwritten every time. */
+                       (void)PQexec(H->server, "SAVEPOINT _php_lastid_savepoint");
+               }
                res = PQexec(H->server, "SELECT LASTVAL()");
        } else {
                const char *q[1];
@@ -375,10 +382,17 @@ static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned
                id = estrdup((char *)PQgetvalue(res, 0, 0));
                *len = PQgetlength(res, 0, 0);
        } else {
+               if (savepoint) {
+                       (void)PQexec(H->server, "ROLLBACK TO SAVEPOINT _php_lastid_savepoint");
+               }
                pdo_pgsql_error(dbh, status, pdo_pgsql_sqlstate(res));
                *len = spprintf(&id, 0, "%ld", (long) H->pgoid);
        }
 
+       if (savepoint) {
+               (void)PQexec(H->server, "RELEASE SAVEPOINT _php_lastid_savepoint");
+       }
+
        if (res) {
                PQclear(res);
        }