[php-src] master: ext/pdo_pgsql: Fix PDO::CURSOR_SCROLL statements failing under lazy fetching

武田 憲太郎 via David Carlier <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: 武田 憲太郎 (KentarouTakeda)
Committer: David Carlier (devnexen)
Date: 2026-08-27T05:09:43+01:00

Commit: https://github.com/php/php-src/commit/197bdc0a40586be9583c5b77de35e9900b6a912e
Raw diff: https://github.com/php/php-src/commit/197bdc0a40586be9583c5b77de35e9900b6a912e.diff

ext/pdo_pgsql: Fix PDO::CURSOR_SCROLL statements failing under lazy fetching

A statement prepared with PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL and lazy
fetching (PDO::ATTR_PREFETCH => 0) failed at execute() with
SQLSTATE[HY000]: General error: 7 and no message. Either option alone
worked.

A cursor does not stream its result, but S->is_unbuffered stayed set, so
execute() called PQgetResult() with nothing in flight. Clear the flag when
the statement has a cursor.

Close GH-23471

Changed paths:
  A  ext/pdo_pgsql/tests/cursor_scroll_lazy_fetch.phpt
  M  NEWS
  M  ext/pdo_pgsql/pgsql_driver.c


Diff:

diff --git a/NEWS b/NEWS
index 149fea347077..466321cf1029 100644
--- a/NEWS
+++ b/NEWS
@@ -48,6 +48,10 @@ PHP                                                                        NEWS
   . Fixed a leak when a persistent connection failed a liveness check
     with no other live PDO handle. (iliaal)
 
+- PDO_PGSQL:
+  . Fixed PDO::CURSOR_SCROLL statements failing under lazy fetching
+    (PDO::ATTR_PREFETCH => 0). (KentarouTakeda)
+
 - Phar:
   . Fixed bug GH-23418 (Use-after-free when looking up mounted directories).
     (Weilin Du)
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
index 54b2e25f72f6..060b8d687765 100644
--- a/ext/pdo_pgsql/pgsql_driver.c
+++ b/ext/pdo_pgsql/pgsql_driver.c
@@ -287,7 +287,16 @@ static bool pgsql_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *
 	scrollable = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
 		PDO_CURSOR_FWDONLY) == PDO_CURSOR_SCROLL;
 
+	S->is_unbuffered =
+		driver_options
+		&& (val = zend_hash_index_find(Z_ARRVAL_P(driver_options), PDO_ATTR_PREFETCH))
+		&& pdo_get_long_param(&lval, val)
+		? !lval
+		: H->default_fetching_laziness
+	;
+
 	if (scrollable) {
+		S->is_unbuffered = false;
 		if (S->cursor_name) {
 			efree(S->cursor_name);
 		}
@@ -312,14 +321,6 @@ static bool pgsql_handle_preparer(pdo_dbh_t *dbh, zend_string *sql, pdo_stmt_t *
 		stmt->named_rewrite_template = "$%d";
 	}
 
-	S->is_unbuffered =
-		driver_options
-		&& (val = zend_hash_index_find(Z_ARRVAL_P(driver_options), PDO_ATTR_PREFETCH))
-		&& pdo_get_long_param(&lval, val)
-		? !lval
-		: H->default_fetching_laziness
-	;
-
 	ret = pdo_parse_params(stmt, sql, &nsql);
 
 	if (ret == -1) {
diff --git a/ext/pdo_pgsql/tests/cursor_scroll_lazy_fetch.phpt b/ext/pdo_pgsql/tests/cursor_scroll_lazy_fetch.phpt
new file mode 100644
index 000000000000..df4be41b8532
--- /dev/null
+++ b/ext/pdo_pgsql/tests/cursor_scroll_lazy_fetch.phpt
@@ -0,0 +1,33 @@
+--TEST--
+PDO PgSQL a scrollable cursor is unaffected by lazy fetching
+--EXTENSIONS--
+pdo_pgsql
+--SKIPIF--
+<?php
+require __DIR__ . '/config.inc';
+require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+
+require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
+$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt');
+$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+$sql = "SELECT * FROM generate_series(1, 3)";
+$scrollable = [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL];
+
+$stmt = $pdo->prepare($sql, $scrollable + [PDO::ATTR_PREFETCH => 0]);
+$stmt->execute();
+echo 'lazy on the statement: ', implode(',', $stmt->fetchAll(PDO::FETCH_COLUMN)), PHP_EOL;
+
+$pdo->setAttribute(PDO::ATTR_PREFETCH, 0);
+$stmt = $pdo->prepare($sql, $scrollable);
+$stmt->execute();
+echo 'lazy on the connection: ', implode(',', $stmt->fetchAll(PDO::FETCH_COLUMN)), PHP_EOL;
+
+?>
+--EXPECT--
+lazy on the statement: 1,2,3
+lazy on the connection: 1,2,3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.