From 6a664d5349ffd0cd079d2dd5585e96aa0f14ef26 Mon Sep 17 00:00:00 2001 From: Philip Hofstetter Date: Tue, 10 Aug 2021 15:28:29 +0200 Subject: [PATCH 1/2] fix bug 81343: inconsistent type conversion after closeCursor S->cols is already freed in the statement destructor and since caa710037e663fd78f67533b29611183090068b2 the column data is only populated on the first execute() which means that on subsequent execute()s after closeCursor was called, all meta-data for column types was removed and never restored --- ext/pdo_pgsql/pgsql_statement.c | 6 ------ ext/pdo_pgsql/tests/bug81343.phpt | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 ext/pdo_pgsql/tests/bug81343.phpt diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index 3ef50d3be4738..b6b9800117343 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -674,12 +674,6 @@ static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *r static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt) { - pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; - - if (S->cols != NULL){ - efree(S->cols); - S->cols = NULL; - } return 1; } diff --git a/ext/pdo_pgsql/tests/bug81343.phpt b/ext/pdo_pgsql/tests/bug81343.phpt new file mode 100644 index 0000000000000..76903b76e472a --- /dev/null +++ b/ext/pdo_pgsql/tests/bug81343.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #81343 pdo_pgsql: Inconsitent boolean conversion after calling closeCursor() +--EXTENSIONS-- +pdo +pdo_pgsql +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); +$sth = $pdo->prepare("select false where 2=?"); + +for ($i = 0; $i < 2; $i++) { + $sth->execute([2]); + var_dump($sth->fetchColumn(0)); + $sth->closeCursor(); +} +?> +--EXPECT-- +bool(false) +bool(false) From 6d01ae87d73201c8bc5ce9f8fc9771f11c6f22c2 Mon Sep 17 00:00:00 2001 From: Philip Hofstetter Date: Tue, 10 Aug 2021 16:42:37 +0200 Subject: [PATCH 2/2] only allocate metadata storage if needed now that the describer is only called for the initial execution, the column metadata needs to stay around even after closeCursor is called (which resets stmt->executed back to 0) This is not correct in light of multiple result sets, but the PDO postgres driver does not provide any support for those --- ext/pdo_pgsql/pgsql_statement.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index b6b9800117343..03ac14c32db9a 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -240,8 +240,8 @@ static int pgsql_stmt_execute(pdo_stmt_t *stmt) return 0; } - if (!stmt->executed && (!stmt->column_count || S->cols == NULL)) { - stmt->column_count = (int) PQnfields(S->result); + stmt->column_count = (int) PQnfields(S->result); + if (S->cols == NULL) { S->cols = ecalloc(stmt->column_count, sizeof(pdo_pgsql_column)); }