Commit 7f1e8cb37b1 for php
commit 7f1e8cb37b1e6da736070d5501b06d2d1763ef12
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Tue Sep 29 11:38:23 2026 -0400
ext/pdo: Throw a ValueError from bindColumn() for an unknown column (#23835)
A column name that is not in the result set is a programming error, so
report it the way the method already reports an empty name or an index
below one, rather than through PDO::ATTR_ERRMODE. The equivalent parameter
failure in bindParam() and bindValue() stays an ERRMODE error: its site in
rewrite_name_to_position() is only reachable once execute() has populated
bound_param_map, never from the bind methods themselves.
Closes GH-23835
diff --git a/UPGRADING b/UPGRADING
index 5d551005042..27dc06f12d2 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -19,6 +19,11 @@ PHP 8.7 UPGRADE NOTES
1. Backward Incompatible Changes
========================================
+- PDO:
+ . PDOStatement::bindColumn() now throws a ValueError when the column name is
+ not present in the result set. It previously reported the condition
+ through PDO::ATTR_ERRMODE and returned false.
+
- Standard:
. The number of filters that can be chained in a php://filter URL is limited
to 16 by default. Set the stream context option max_filter_count to change
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
index 1e9e1052d28..9774b197b7d 100644
--- a/ext/pdo/pdo_stmt.c
+++ b/ext/pdo/pdo_stmt.c
@@ -295,12 +295,7 @@ static bool really_register_bound_param(struct pdo_bound_param_data *param, pdo_
/* if you prepare and then execute passing an array of params keyed by names,
* then this will trigger, and we don't want that */
if (param->paramno == -1) {
- /* Should this always be an Error? */
- char *tmp;
- /* TODO Error? */
- spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", ZSTR_VAL(param->name));
- pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp);
- efree(tmp);
+ zend_argument_value_error(1, "must refer to a column present in the result set, \"%s\" given", ZSTR_VAL(param->name));
return false;
}
}
diff --git a/ext/pdo/tests/pdo_bindcolumn_unknown_column.phpt b/ext/pdo/tests/pdo_bindcolumn_unknown_column.phpt
index 44e85ec07c3..3e3ba30e8c4 100644
--- a/ext/pdo/tests/pdo_bindcolumn_unknown_column.phpt
+++ b/ext/pdo/tests/pdo_bindcolumn_unknown_column.phpt
@@ -1,5 +1,5 @@
--TEST--
-PDO: bindColumn() must fail for a column name that is not in the result set
+PDO: bindColumn() must throw for a column name that is not in the result set
--EXTENSIONS--
pdo
--SKIPIF--
@@ -17,16 +17,20 @@
$db = PDOTest::factory();
$db->exec('CREATE TABLE pdo_bindcolumn_unknown_column (name varchar(255))');
-$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
-$stmt = $db->query('SELECT name FROM pdo_bindcolumn_unknown_column');
-var_dump(@$stmt->bindColumn('nosuchcolumn', $var));
-
-$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-try {
- $stmt->bindColumn('nosuchcolumn', $var);
-} catch (PDOException $e) {
- echo $e::class, ": ", $e->getMessage(), PHP_EOL;
+// The error mode must not affect a ValueError.
+foreach ([PDO::ERRMODE_SILENT, PDO::ERRMODE_WARNING, PDO::ERRMODE_EXCEPTION] as $mode) {
+ $db->setAttribute(PDO::ATTR_ERRMODE, $mode);
+ $stmt = $db->query('SELECT name FROM pdo_bindcolumn_unknown_column');
+ try {
+ $stmt->bindColumn('nosuchcolumn', $var);
+ } catch (ValueError $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
}
+
+// A column that does exist still binds.
+$stmt = $db->query('SELECT name FROM pdo_bindcolumn_unknown_column');
+var_dump($stmt->bindColumn('name', $var));
?>
--CLEAN--
<?php
@@ -37,5 +41,7 @@
$db->exec('DROP TABLE pdo_bindcolumn_unknown_column');
?>
--EXPECT--
-bool(false)
-PDOException: SQLSTATE[HY000]: General error: Did not find column name 'nosuchcolumn' in the defined columns; it will not be bound
+ValueError: PDOStatement::bindColumn(): Argument #1 ($column) must refer to a column present in the result set, "nosuchcolumn" given
+ValueError: PDOStatement::bindColumn(): Argument #1 ($column) must refer to a column present in the result set, "nosuchcolumn" given
+ValueError: PDOStatement::bindColumn(): Argument #1 ($column) must refer to a column present in the result set, "nosuchcolumn" given
+bool(true)
diff --git a/ext/pdo_sqlite/tests/pdo_driver_options_weakref.phpt b/ext/pdo_sqlite/tests/pdo_driver_options_weakref.phpt
index 16dc9a3c466..15cafa656e7 100644
--- a/ext/pdo_sqlite/tests/pdo_driver_options_weakref.phpt
+++ b/ext/pdo_sqlite/tests/pdo_driver_options_weakref.phpt
@@ -19,17 +19,20 @@ class Tracked {}
$stmt = $db->prepare('SELECT ? AS value');
$stmt->execute();
-$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$value = null;
$driverOptions = [new Tracked()];
$weakReference = WeakReference::create($driverOptions[0]);
-var_dump(@$stmt->bindColumn('missing', $value, PDO::PARAM_STR, 0, $driverOptions));
-unset($driverOptions);
+try {
+ $stmt->bindColumn('missing', $value, PDO::PARAM_STR, 0, $driverOptions);
+} catch (ValueError $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+unset($e, $driverOptions);
var_dump($weakReference->get());
unset($value, $stmt);
?>
--EXPECT--
bool(true)
NULL
-bool(false)
+ValueError: PDOStatement::bindColumn(): Argument #1 ($column) must refer to a column present in the result set, "missing" given
NULL