From 15b51a215ac08fa72aa6ea44755f7134710f9004 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 10 Dec 2020 15:51:17 +0100 Subject: [PATCH] Fixed bug #79131 When a driver reports an error during EVT_ALLOC (and some over EVTs), make sure we handle it as usual, i.e. warn or throw. This requires some adjustments in PDO PgSQL to stop manually doing this through an impl error. Unfortunately the PDO PgSQL error messages regress because of this, as they now include a completely arbitrary error code. There doesn't seem to be an ability to skip it right now. --- NEWS | 2 ++ ext/pdo/pdo_stmt.c | 9 +++++---- .../tests/pdo_mysql_prepare_emulated_anonymous.phpt | 4 +++- .../pdo_mysql_prepare_native_named_placeholder.phpt | 3 ++- ext/pdo_pgsql/pgsql_statement.c | 6 ++++-- ext/pdo_pgsql/php_pdo_pgsql_int.h | 3 ++- ext/pdo_pgsql/tests/bug36727.phpt | 2 +- ext/pdo_pgsql/tests/bug69344.phpt | 2 +- ext/pdo_pgsql/tests/bug71573.phpt | 2 +- 9 files changed, 21 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index 0a91136d763..536b028fd9b 100644 --- a/NEWS +++ b/NEWS @@ -52,6 +52,8 @@ PHP NEWS . Fixed bug #76815 (PDOStatement cannot be GCed/closeCursor-ed when a PROCEDURE resultset SIGNAL). (Nikita) . Fixed bug #79872 (Can't execute query with pending result sets). (Nikita) + . Fixed bug #79131 (PDO does not throw an exception when parameter values are + missing). (Nikita) - Phar: . Fixed bug #73809 (Phar Zip parse crash - mmap fail). (cmb) diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index d4c60866904..68ec99160a6 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -341,8 +341,8 @@ static bool really_register_bound_param(struct pdo_bound_param_data *param, pdo_ * a reference to param, as it resides in transient storage only * at this time. */ if (stmt->methods->param_hook) { - if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE - )) { + if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE)) { + PDO_HANDLE_STMT_ERR(); if (param->name) { zend_string_release_ex(param->name, 0); param->name = NULL; @@ -367,8 +367,8 @@ static bool really_register_bound_param(struct pdo_bound_param_data *param, pdo_ /* tell the driver we just created a parameter */ if (stmt->methods->param_hook) { - if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC - )) { + if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC)) { + PDO_HANDLE_STMT_ERR(); /* undo storage allocation; the hash will free the parameter * name if required */ if (pparam->name) { @@ -479,6 +479,7 @@ PHP_METHOD(PDOStatement, execute) } if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST)) { + PDO_HANDLE_STMT_ERR(); RETURN_FALSE; } diff --git a/ext/pdo_mysql/tests/pdo_mysql_prepare_emulated_anonymous.phpt b/ext/pdo_mysql/tests/pdo_mysql_prepare_emulated_anonymous.phpt index abd2615ce89..5d403c0caac 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_prepare_emulated_anonymous.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_prepare_emulated_anonymous.phpt @@ -64,7 +64,7 @@ require __DIR__ . '/mysql_pdo_test.inc'; $db = MySQLPDOTest::factory(); $db->exec('DROP TABLE IF EXISTS test'); ?> ---EXPECT-- +--EXPECTF-- array(1) { [0]=> array(2) { @@ -75,6 +75,8 @@ array(1) { } } now the same with native PS + +Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number in %s on line %d [005] Execute has failed, 'HY093' array ( 0 => 'HY093', 1 => NULL, diff --git a/ext/pdo_mysql/tests/pdo_mysql_prepare_native_named_placeholder.phpt b/ext/pdo_mysql/tests/pdo_mysql_prepare_native_named_placeholder.phpt index 6b553375d63..ea4d097809d 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_prepare_native_named_placeholder.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_prepare_native_named_placeholder.phpt @@ -72,7 +72,8 @@ require __DIR__ . '/mysql_pdo_test.inc'; $db = MySQLPDOTest::factory(); $db->exec('DROP TABLE IF EXISTS test'); ?> ---EXPECT-- +--EXPECTF-- +Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number in %s on line %d [003] Execute has failed, 'HY093' array ( 0 => 'HY093', 1 => NULL, diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index 88031622a43..149e1e6b51e 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -282,7 +282,8 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * ZEND_ATOL(param->paramno, namevar + 1); param->paramno--; } else { - pdo_raise_impl_error(stmt->dbh, stmt, "HY093", ZSTR_VAL(param->name)); + pdo_pgsql_error_stmt_msg( + stmt, PGRES_FATAL_ERROR, "HY093", ZSTR_VAL(param->name)); return 0; } } @@ -294,7 +295,8 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data * return 1; } if (!zend_hash_index_exists(stmt->bound_param_map, param->paramno)) { - pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined"); + pdo_pgsql_error_stmt_msg( + stmt, PGRES_FATAL_ERROR, "HY093", "parameter was not defined"); return 0; } case PDO_PARAM_EVT_EXEC_POST: diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h index 07dfa8ce276..bc31c9cdeee 100644 --- a/ext/pdo_pgsql/php_pdo_pgsql_int.h +++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h @@ -79,7 +79,8 @@ extern int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const #define pdo_pgsql_error(d,e,z) _pdo_pgsql_error(d, NULL, e, z, NULL, __FILE__, __LINE__) #define pdo_pgsql_error_msg(d,e,m) _pdo_pgsql_error(d, NULL, e, NULL, m, __FILE__, __LINE__) #define pdo_pgsql_error_stmt(s,e,z) _pdo_pgsql_error(s->dbh, s, e, z, NULL, __FILE__, __LINE__) -#define pdo_pgsql_error_stmt_msg(s,e,m) _pdo_pgsql_error(s->dbh, s, e, NULL, m, __FILE__, __LINE__) +#define pdo_pgsql_error_stmt_msg(stmt, e, sqlstate, msg) \ + _pdo_pgsql_error(stmt->dbh, stmt, e, sqlstate, msg, __FILE__, __LINE__) extern const struct pdo_stmt_methods pgsql_stmt_methods; diff --git a/ext/pdo_pgsql/tests/bug36727.phpt b/ext/pdo_pgsql/tests/bug36727.phpt index e6b5ab7f283..4c9716d1415 100644 --- a/ext/pdo_pgsql/tests/bug36727.phpt +++ b/ext/pdo_pgsql/tests/bug36727.phpt @@ -19,6 +19,6 @@ var_dump($stmt->bindValue(':test', 1, PDO::PARAM_INT)); echo "Done\n"; ?> --EXPECTF-- -Warning: PDOStatement::bindValue(): SQLSTATE[HY093]: Invalid parameter number: :test in %sbug36727.php on line %d +Warning: PDOStatement::bindValue(): SQLSTATE[HY093]: Invalid parameter number: 7 :test in %s on line %d bool(false) Done diff --git a/ext/pdo_pgsql/tests/bug69344.phpt b/ext/pdo_pgsql/tests/bug69344.phpt index f544518455f..e2522653f50 100644 --- a/ext/pdo_pgsql/tests/bug69344.phpt +++ b/ext/pdo_pgsql/tests/bug69344.phpt @@ -39,5 +39,5 @@ $test(); ?> --EXPECT-- -SQLSTATE[HY093]: Invalid parameter number: parameter was not defined +SQLSTATE[HY093]: Invalid parameter number: 7 parameter was not defined SQLSTATE[HY093]: Invalid parameter number: parameter was not defined diff --git a/ext/pdo_pgsql/tests/bug71573.phpt b/ext/pdo_pgsql/tests/bug71573.phpt index 66562344ef3..d9e4fe75143 100644 --- a/ext/pdo_pgsql/tests/bug71573.phpt +++ b/ext/pdo_pgsql/tests/bug71573.phpt @@ -18,4 +18,4 @@ $statement->execute([ 'test', 'test', 'test' ]); ?> --EXPECTF-- -Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in %sbug71573.php on line %d +Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: 7 parameter was not defined in %s on line %d