Skip to content

Use native ZPP for callable parameters in ext/sqlite3 #5988

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 13 additions & 38 deletions ext/sqlite3/sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -952,12 +952,13 @@ PHP_METHOD(SQLite3, createFunction)
php_sqlite3_func *func;
char *sql_func;
size_t sql_func_len;
zval *callback_func;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
zend_long sql_func_num_args = -1;
zend_long flags = 0;
db_obj = Z_SQLITE3_DB_P(object);

if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|ll", &sql_func, &sql_func_len, &callback_func, &sql_func_num_args, &flags) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sf|ll", &sql_func, &sql_func_len, &fci, &fcc, &sql_func_num_args, &flags) == FAILURE) {
RETURN_THROWS();
}

Expand All @@ -967,19 +968,12 @@ PHP_METHOD(SQLite3, createFunction)
RETURN_FALSE;
}

if (!zend_is_callable(callback_func, 0, NULL)) {
zend_string *callback_name = zend_get_callable_name(callback_func);
php_sqlite3_error(db_obj, "Not a valid callback function %s", ZSTR_VAL(callback_name));
zend_string_release_ex(callback_name, 0);
RETURN_FALSE;
}

func = (php_sqlite3_func *)ecalloc(1, sizeof(*func));

if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, flags | SQLITE_UTF8, func, php_sqlite3_callback_func, NULL, NULL) == SQLITE_OK) {
func->func_name = estrdup(sql_func);

ZVAL_COPY(&func->func, callback_func);
ZVAL_COPY(&func->func, &fci.function_name);

func->argc = sql_func_num_args;
func->next = db_obj->funcs;
Expand All @@ -1001,11 +995,12 @@ PHP_METHOD(SQLite3, createAggregate)
php_sqlite3_func *func;
char *sql_func;
size_t sql_func_len;
zval *step_callback, *fini_callback;
zend_fcall_info step_fci, fini_fci;
zend_fcall_info_cache step_fcc, fini_fcc;
zend_long sql_func_num_args = -1;
db_obj = Z_SQLITE3_DB_P(object);

if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &sql_func, &sql_func_len, &step_callback, &fini_callback, &sql_func_num_args) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sff|l", &sql_func, &sql_func_len, &step_fci, &step_fcc, &fini_fci, &fini_fcc, &sql_func_num_args) == FAILURE) {
RETURN_THROWS();
}

Expand All @@ -1015,27 +1010,13 @@ PHP_METHOD(SQLite3, createAggregate)
RETURN_FALSE;
}

if (!zend_is_callable(step_callback, 0, NULL)) {
zend_string *callback_name = zend_get_callable_name(step_callback);
php_sqlite3_error(db_obj, "Not a valid callback function %s", ZSTR_VAL(callback_name));
zend_string_release_ex(callback_name, 0);
RETURN_FALSE;
}

if (!zend_is_callable(fini_callback, 0, NULL)) {
zend_string *callback_name = zend_get_callable_name(fini_callback);
php_sqlite3_error(db_obj, "Not a valid callback function %s", ZSTR_VAL(callback_name));
zend_string_release_ex(callback_name, 0);
RETURN_FALSE;
}

func = (php_sqlite3_func *)ecalloc(1, sizeof(*func));

if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, SQLITE_UTF8, func, NULL, php_sqlite3_callback_step, php_sqlite3_callback_final) == SQLITE_OK) {
func->func_name = estrdup(sql_func);

ZVAL_COPY(&func->step, step_callback);
ZVAL_COPY(&func->fini, fini_callback);
ZVAL_COPY(&func->step, &step_fci.function_name);
ZVAL_COPY(&func->fini, &fini_fci.function_name);

func->argc = sql_func_num_args;
func->next = db_obj->funcs;
Expand All @@ -1057,10 +1038,11 @@ PHP_METHOD(SQLite3, createCollation)
php_sqlite3_collation *collation;
char *collation_name;
size_t collation_name_len;
zval *callback_func;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
db_obj = Z_SQLITE3_DB_P(object);

if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &collation_name, &collation_name_len, &callback_func) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sf", &collation_name, &collation_name_len, &fci, &fcc) == FAILURE) {
RETURN_THROWS();
}

Expand All @@ -1070,18 +1052,11 @@ PHP_METHOD(SQLite3, createCollation)
RETURN_FALSE;
}

if (!zend_is_callable(callback_func, 0, NULL)) {
zend_string *callback_name = zend_get_callable_name(callback_func);
php_sqlite3_error(db_obj, "Not a valid callback function %s", ZSTR_VAL(callback_name));
zend_string_release_ex(callback_name, 0);
RETURN_FALSE;
}

collation = (php_sqlite3_collation *)ecalloc(1, sizeof(*collation));
if (sqlite3_create_collation(db_obj->db, collation_name, SQLITE_UTF8, collation, php_sqlite3_callback_compare) == SQLITE_OK) {
collation->collation_name = estrdup(collation_name);

ZVAL_COPY(&collation->cmp_func, callback_func);
ZVAL_COPY(&collation->cmp_func, &fci.function_name);

collation->next = db_obj->collations;
db_obj->collations = collation;
Expand Down
26 changes: 8 additions & 18 deletions ext/sqlite3/sqlite3.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,14 @@ public function query(string $query) {}
/** @return mixed */
public function querySingle(string $query, bool $entire_row = false) {}

/**
* @param callable $callback
* @return bool
*/
public function createFunction(string $name, $callback, int $argument_count = -1, int $flags = 0) {}

/**
* @param callable $step_callback
* @param callable $final_callback
* @return bool
*/
public function createAggregate(string $name, $step_callback, $final_callback, int $argument_count = -1) {}

/**
* @param callable $callback
* @return bool
*/
public function createCollation(string $name, $callback) {}
/** @return bool */
public function createFunction(string $name, callable $callback, int $argument_count = -1, int $flags = 0) {}

/** @return bool */
public function createAggregate(string $name, callable $step_callback, callable $final_callback, int $argument_count = -1) {}

/** @return bool */
public function createCollation(string $name, callable $callback) {}

/** @return resource|false */
public function openBlob(string $table, string $column, int $rowid, string $dbname = "main", int $flags = SQLITE3_OPEN_READONLY) {}
Expand Down
10 changes: 5 additions & 5 deletions ext/sqlite3/sqlite3_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: cc36f3299089a453fac76179377b68647c33786c */
* Stub hash: d40496bbba4787b192a58896a9ca4858dc59dc76 */

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
Expand Down Expand Up @@ -61,21 +61,21 @@ ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3_createFunction, 0, 0, 2)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
ZEND_ARG_INFO(0, callback)
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, argument_count, IS_LONG, 0, "-1")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3_createAggregate, 0, 0, 3)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
ZEND_ARG_INFO(0, step_callback)
ZEND_ARG_INFO(0, final_callback)
ZEND_ARG_TYPE_INFO(0, step_callback, IS_CALLABLE, 0)
ZEND_ARG_TYPE_INFO(0, final_callback, IS_CALLABLE, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, argument_count, IS_LONG, 0, "-1")
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3_createCollation, 0, 0, 2)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
ZEND_ARG_INFO(0, callback)
ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3_openBlob, 0, 0, 3)
Expand Down
21 changes: 15 additions & 6 deletions ext/sqlite3/tests/sqlite3_33_createAggregate_notcallable.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,26 @@ function aggregate_final ($var) { return $var; }

$db = new SQLite3(':memory:');

$db->createAggregate ('TESTAGGREGATE', 'aggregate_test_step', 'aggregate_final');
$db->createAggregate ('TESTAGGREGATE2', 'aggregate_step', 'aggregate_test_final');
try {
$db->createAggregate('TESTAGGREGATE', 'aggregate_test_step', 'aggregate_final');
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}

try {
$db->createAggregate('TESTAGGREGATE2', 'aggregate_step', 'aggregate_test_final');
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}

var_dump($db->createAggregate ('TESTAGGREGATE3', 'aggregate_step', 'aggregate_final'));

$db->close();

echo "Done"
?>
--EXPECTF--
Warning: SQLite3::createAggregate(): Not a valid callback function aggregate_test_step in %s on line %d

Warning: SQLite3::createAggregate(): Not a valid callback function aggregate_test_final in %s on line %d
--EXPECT--
SQLite3::createAggregate(): Argument #2 ($step_callback) must be a valid callback, function "aggregate_test_step" not found or invalid function name
SQLite3::createAggregate(): Argument #3 ($final_callback) must be a valid callback, function "aggregate_test_final" not found or invalid function name
bool(true)
Done