[php-src] master: ext/pdo_pgsql: Convert integer columns without strtoll()
| From: | Matthias Dötsch via David Carlier | Date: | Thu, 22 Oct 2026 13:25:40 +0000 |
| Subject: | [php-src] master: ext/pdo_pgsql: Convert integer columns without strtoll() | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-142574@lists.php.net to get a copy of this message | ||
Author: Matthias Dötsch (brainexe)
Committer: David Carlier (devnexen)
Date: 2026-10-22T14:25:10+01:00
Commit: https://github.com/php/php-src/commit/c0018beb1185031bcf40cffa2ffd00d66873f517
Raw diff: https://github.com/php/php-src/commit/c0018beb1185031bcf40cffa2ffd00d66873f517.diff
ext/pdo_pgsql: Convert integer columns without strtoll()
PostgreSQL sends int2/int4/int8 values in text format in canonical
decimal form: an optional minus sign followed by digits without leading
zeros. That is exactly what ZEND_HANDLE_NUMERIC_STR() accepts for
numeric array keys, including the range check. Use it instead of
calling strtoll() through ZEND_ATOL() for every value, and keep
ZEND_ATOL() as fallback for anything else.
fetchAll(PDO::FETCH_ASSOC) of 1M rows with 4 integer columns:
-11% instructions, -9% cycles.
Close GH-24385
Changed paths:
A ext/pdo_pgsql/tests/fetch_integers.phpt
M NEWS
M UPGRADING
M ext/pdo_pgsql/pgsql_statement.c
Diff:
diff --git a/NEWS b/NEWS
index 67896bb73a85..5155d8ede346 100644
--- a/NEWS
+++ b/NEWS
@@ -91,6 +91,7 @@ PHP NEWS
- PDO_PGSQL:
. Improved performance of the SQL parser that handles placeholders.
(brainexe)
+ . Improved performance of fetching integer columns. (brainexe)
- PGSQL:
. Fixed pg_lo_write() rejecting data containing null bytes. (Ilia Alshanetsky)
diff --git a/UPGRADING b/UPGRADING
index 60b7020cb1e3..a232e35aa00c 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -176,3 +176,4 @@ PHP 8.7 UPGRADE NOTES
- PDO_PGSQL:
. Improved performance of the SQL parser that handles placeholders in
PDO::prepare() and, with emulated prepares, PDOStatement::execute().
+ . Improved performance of fetching integer columns.
diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c
index de7d03bc7264..15d9916a5c2e 100644
--- a/ext/pdo_pgsql/pgsql_statement.c
+++ b/ext/pdo_pgsql/pgsql_statement.c
@@ -758,8 +758,17 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum
pd
#if SIZEOF_ZEND_LONG >= 8
case INT8OID:
#endif
- ZVAL_LONG(result, ZEND_ATOL(ptr));
+ {
+ /* PostgreSQL sends integers in canonical decimal form, which the numeric array key
+ * parser handles without the overhead of strtoll() */
+ zend_ulong lval;
+ if (EXPECTED(ZEND_HANDLE_NUMERIC_STR(ptr, len, lval))) {
+ ZVAL_LONG(result, (zend_long) lval);
+ } else {
+ ZVAL_LONG(result, ZEND_ATOL(ptr));
+ }
break;
+ }
case FLOAT4OID:
case FLOAT8OID:
if (strncmp(ptr, "Infinity", len) == 0) {
diff --git a/ext/pdo_pgsql/tests/fetch_integers.phpt b/ext/pdo_pgsql/tests/fetch_integers.phpt
new file mode 100644
index 000000000000..54287dc200ea
--- /dev/null
+++ b/ext/pdo_pgsql/tests/fetch_integers.phpt
@@ -0,0 +1,56 @@
+--TEST--
+PDO PgSQL: integer columns at their boundaries
+--EXTENSIONS--
+pdo_pgsql
+--SKIPIF--
+<?php
+if (PHP_INT_SIZE < 8) die('skip 64-bit only');
+require __DIR__ . '/config.inc';
+require dirname(__DIR__, 2) . '/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(__DIR__ . '/common.phpt');
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
+
+$stmt = $db->query(<<<'SQL'
+SELECT 0::int2, (-1)::int2, (-32768)::int2, 32767::int2,
+ (-2147483648)::int4, 2147483647::int4, 7::int4,
+ 999999999999999999::int8, (-999999999999999999)::int8,
+ 1000000000000000000::int8, (-1000000000000000000)::int8,
+ 9223372036854775807::int8, '-9223372036854775808'::int8
+SQL);
+var_dump($stmt->fetch(PDO::FETCH_NUM));
+?>
+--EXPECT--
+array(13) {
+ [0]=>
+ int(0)
+ [1]=>
+ int(-1)
+ [2]=>
+ int(-32768)
+ [3]=>
+ int(32767)
+ [4]=>
+ int(-2147483648)
+ [5]=>
+ int(2147483647)
+ [6]=>
+ int(7)
+ [7]=>
+ int(999999999999999999)
+ [8]=>
+ int(-999999999999999999)
+ [9]=>
+ int(1000000000000000000)
+ [10]=>
+ int(-1000000000000000000)
+ [11]=>
+ int(9223372036854775807)
+ [12]=>
+ int(-9223372036854775808)
+}