diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index 8f3dd5237b5a..cec83ce8b005 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -79,9 +79,18 @@ static int pgsql_stmt_dtor(pdo_stmt_t *stmt) // TODO (??) libpq does not support close statement protocol < postgres 17 // check if we can circumvent this. char *q = NULL; - spprintf(&q, 0, "DEALLOCATE %s", S->stmt_name); - res = PQexec(H->server, q); - efree(q); + PGTransactionStatusType tstatus = PQtransactionStatus(H->server); + + if (tstatus == PQTRANS_IDLE) { + spprintf(&q, 0, "DEALLOCATE %s", S->stmt_name); + res = PQexec(H->server, q); + efree(q); + } else { + /* Outside PQTRANS_IDLE, skip DEALLOCATE: on libpq < 17 some servers + * (e.g. Aurora DSQL) reject it and poison the tx (GH-21869). The + * statement is session-scoped, so it's freed on disconnect. */ + res = NULL; + } #else res = PQclosePrepared(H->server, S->stmt_name); #endif diff --git a/ext/pdo_pgsql/tests/gh21869.phpt b/ext/pdo_pgsql/tests/gh21869.phpt new file mode 100644 index 000000000000..2c64b6a674f6 --- /dev/null +++ b/ext/pdo_pgsql/tests/gh21869.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-21869 pdo_pgsql: DEALLOCATE failure in destructor must not poison the enclosing transaction +--EXTENSIONS-- +pdo +pdo_pgsql +--SKIPIF-- +getAttribute(PDO::ATTR_CLIENT_VERSION), '17', '>=')) { + die('skip libpq >= 17 uses PQclosePrepared instead of the DEALLOCATE query'); +} +?> +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + +$pdo->exec('CREATE TABLE gh21869 (a integer not null)'); + +$pdo->beginTransaction(); +$stmt = $pdo->prepare('INSERT INTO gh21869 (a) VALUES (?)'); +$stmt->execute([1]); + +foreach ($pdo->query('SELECT name FROM pg_prepared_statements') as $row) { + $pdo->exec('DEALLOCATE ' . $row['name']); +} + +unset($stmt); + +$pdo->commit(); + +var_dump((int) $pdo->query('SELECT count(*) FROM gh21869')->fetchColumn()); +?> +--CLEAN-- +exec('DROP TABLE IF EXISTS gh21869'); +?> +--EXPECT-- +int(1)