From e3cfa4bcae8b476e9d0192f938de579caed9f6a0 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 7 Jun 2025 16:35:30 +0100 Subject: [PATCH] ext/pdo_sqlite: PDO::sqliteCreateCollection return type strenghtening. Is supposed to be Pdo_Sqlite::createCollation but behavior differs in regard of return type checks. close GH-18799 --- NEWS | 2 ++ UPGRADING | 3 +++ ext/pdo_sqlite/pdo_sqlite.c | 4 ++-- ext/pdo_sqlite/sqlite_driver.c | 12 ++++++++---- ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt | 8 ++++++++ 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 88ba1f1e5bc..9e6d47ed2a0 100644 --- a/NEWS +++ b/NEWS @@ -141,6 +141,8 @@ PHP NEWS - PDO_SQLITE: . throw on null bytes / resolve GH-13952 (divinity76). . Implement GH-17321: Add setAuthorizer to Pdo\Sqlite. (nielsdos) + . PDO::sqliteCreateCollation now throws a TypeError if the callback + has a wrong return type. (David Carlier) - PGSQL: . Added pg_close_stmt to close a prepared statement while allowing diff --git a/UPGRADING b/UPGRADING index 7cb73a1271d..aebda12cf50 100644 --- a/UPGRADING +++ b/UPGRADING @@ -268,6 +268,9 @@ PHP 8.5 UPGRADE NOTES - PDO_SQLITE: . SQLite PDO::quote() will now throw an exception or emit a warning, depending on the error mode, if the string contains a null byte. + . PDO::sqliteCreateCollation will now throw an exception + if the callback has the wrong return type, making it more + in line with Pdo_Sqlite::createCollation behavior. - PGSQL: . pg_copy_from also supports inputs as Iterable. diff --git a/ext/pdo_sqlite/pdo_sqlite.c b/ext/pdo_sqlite/pdo_sqlite.c index 02fbf0d3e9e..fbbb336c1af 100644 --- a/ext/pdo_sqlite/pdo_sqlite.c +++ b/ext/pdo_sqlite/pdo_sqlite.c @@ -385,14 +385,14 @@ static int php_sqlite_collation_callback(void *context, int string1_len, const v zend_type_error("%s(): Return value of the collation callback must be of type int, %s returned", ZSTR_VAL(func_name), zend_zval_value_name(&retval)); zend_string_release(func_name); - zval_ptr_dtor(&retval); - return FAILURE; + ret = FAILURE; } if (Z_LVAL(retval) > 0) { ret = 1; } else if (Z_LVAL(retval) < 0) { ret = -1; } + zval_ptr_dtor(&retval); } return ret; diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index ddf25d4965f..d06d255c14c 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -483,9 +483,16 @@ static int php_sqlite3_collation_callback(void *context, int string1_len, const zend_call_known_fcc(&collation->callback, &retval, /* argc */ 2, zargs, /* named_params */ NULL); + zval_ptr_dtor(&zargs[0]); + zval_ptr_dtor(&zargs[1]); + if (!Z_ISUNDEF(retval)) { if (Z_TYPE(retval) != IS_LONG) { - convert_to_long(&retval); + zend_string *func_name = get_active_function_or_method_name(); + zend_type_error("%s(): Return value of the collation callback must be of type int, %s returned", + ZSTR_VAL(func_name), zend_zval_value_name(&retval)); + zend_string_release(func_name); + ret = FAILURE; } if (Z_LVAL(retval) > 0) { ret = 1; @@ -495,9 +502,6 @@ static int php_sqlite3_collation_callback(void *context, int string1_len, const zval_ptr_dtor(&retval); } - zval_ptr_dtor(&zargs[0]); - zval_ptr_dtor(&zargs[1]); - return ret; } diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt index 9e4751e33aa..fdfb8dda448 100644 --- a/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt +++ b/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt @@ -24,6 +24,13 @@ foreach ($result as $row) { echo $row['name'] . "\n"; } +$db->sqliteCreateCollation('MYCOLLATEBAD', function($a, $b) { return $a; }); + +try { + $db->query('SELECT name FROM test_pdo_sqlite_createcollation ORDER BY name COLLATE MYCOLLATEBAD'); +} catch (\TypeError $e) { + echo $e->getMessage(), PHP_EOL; +} ?> --EXPECT-- 1 @@ -32,3 +39,4 @@ foreach ($result as $row) { 1 10 2 +PDO::query(): Return value of the collation callback must be of type int, string returned