From 6d48f18efb00ce4eac1f3146b8d6b394d2a808a8 Mon Sep 17 00:00:00 2001 From: bohwaz Date: Mon, 24 Oct 2022 02:36:26 +0200 Subject: [PATCH] Add an optional array parameter to SQLite3Stmt::execute() method, like in PDOStatement --- ext/sqlite3/sqlite3.c | 42 +++++++++++++++- ext/sqlite3/sqlite3.stub.php | 2 +- ext/sqlite3/sqlite3_arginfo.h | 3 +- .../sqlite3_41_prepared_stmt_params.phpt | 49 +++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 ext/sqlite3/tests/sqlite3_41_prepared_stmt_params.phpt diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index 1d00bc758ff0e..5ea47eb4c4dd0 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -1762,18 +1762,58 @@ PHP_METHOD(SQLite3Stmt, execute) php_sqlite3_stmt *stmt_obj; php_sqlite3_result *result; zval *object = ZEND_THIS; + zval *input_params = NULL; int return_code = 0; int bind_rc = 0; stmt_obj = Z_SQLITE3_STMT_P(object); - ZEND_PARSE_PARAMETERS_NONE(); + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(input_params) + ZEND_PARSE_PARAMETERS_END(); SQLITE3_CHECK_INITIALIZED(stmt_obj->db_obj, stmt_obj->initialised, SQLite3); /* Always reset statement before execution, see bug #77051 */ sqlite3_reset(stmt_obj->stmt); + if (input_params) { + struct php_sqlite3_bound_param param = {0}; + zval *tmp; + zend_string *key = NULL; + zend_ulong num_index; + + if (stmt_obj->bound_params) { + zend_hash_destroy(stmt_obj->bound_params); + FREE_HASHTABLE(stmt_obj->bound_params); + stmt_obj->bound_params = NULL; + } + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input_params), num_index, key, tmp) { + memset(¶m, 0, sizeof(param)); + + param.param_number = -1; + param.type = SQLITE3_TEXT; + ZVAL_COPY(¶m.parameter, tmp); + + if (key) { + param.name = key; + } else { + /* for easier use, we are zero-based here */ + param.param_number = num_index + 1; + } + + if (!register_bound_parameter_to_sqlite(¶m, stmt_obj)) { + if (!Z_ISUNDEF(param.parameter)) { + zval_ptr_dtor(&(param.parameter)); + ZVAL_UNDEF(¶m.parameter); + } + RETURN_FALSE; + } + } ZEND_HASH_FOREACH_END(); + } + /* Bind parameters to the statement */ bind_rc = php_sqlite3_bind_params(stmt_obj); diff --git a/ext/sqlite3/sqlite3.stub.php b/ext/sqlite3/sqlite3.stub.php index 8c8bf7edce5df..64b661a1ae2e7 100644 --- a/ext/sqlite3/sqlite3.stub.php +++ b/ext/sqlite3/sqlite3.stub.php @@ -363,7 +363,7 @@ public function clear(): bool {} public function close(): bool {} /** @tentative-return-type */ - public function execute(): SQLite3Result|false {} + public function execute(?array $params = null): SQLite3Result|false {} /** @tentative-return-type */ public function getSQL(bool $expand = false): string|false {} diff --git a/ext/sqlite3/sqlite3_arginfo.h b/ext/sqlite3/sqlite3_arginfo.h index 4091374dee78c..d7d7a364f003f 100644 --- a/ext/sqlite3/sqlite3_arginfo.h +++ b/ext/sqlite3/sqlite3_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: bdee592c8babbc221080c6ea2d73f94b2b79274a */ + * Stub hash: 4f6d32d3dd6893501e2e462ea7aee7a2080831a9 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -132,6 +132,7 @@ ZEND_END_ARG_INFO() #define arginfo_class_SQLite3Stmt_close arginfo_class_SQLite3Stmt_clear ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_SQLite3Stmt_execute, 0, 0, SQLite3Result, MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, params, IS_ARRAY, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_SQLite3Stmt_getSQL, 0, 0, MAY_BE_STRING|MAY_BE_FALSE) diff --git a/ext/sqlite3/tests/sqlite3_41_prepared_stmt_params.phpt b/ext/sqlite3/tests/sqlite3_41_prepared_stmt_params.phpt new file mode 100644 index 0000000000000..8bf66462f8517 --- /dev/null +++ b/ext/sqlite3/tests/sqlite3_41_prepared_stmt_params.phpt @@ -0,0 +1,49 @@ +--TEST-- +SQLite3::prepare and execute with parameters as array +--EXTENSIONS-- +sqlite3 +--FILE-- +exec('CREATE TABLE test (time INTEGER, id STRING)')); + +echo "INSERT into table\n"; +var_dump($db->exec("INSERT INTO test (time, id) VALUES (" . TIMENOW . ", 'a')")); +var_dump($db->exec("INSERT INTO test (time, id) VALUES (" . TIMENOW . ", 'b')")); + +echo "SELECTING results\n"; +$stmt = $db->prepare("SELECT * FROM test WHERE id = ? ORDER BY id ASC"); +$foo = 'a'; +echo "BINDING Value\n"; +$results = $stmt->execute([$foo]); +while ($result = $results->fetchArray(SQLITE3_NUM)) +{ + var_dump($result); +} +$results->finalize(); + +echo "Closing database\n"; +var_dump($db->close()); +echo "Done\n"; +?> +--EXPECTF-- +Creating Table +bool(true) +INSERT into table +bool(true) +bool(true) +SELECTING results +BINDING Value +array(2) { + [0]=> + int(%d) + [1]=> + string(1) "a" +} +Closing database +bool(true) +Done