Skip to content

Commit fbf0e05

Browse files
andrewnesternikic
authored andcommitted
Implement FR #74217: deterministic sqlite functions
1 parent 280e8da commit fbf0e05

File tree

6 files changed

+85
-7
lines changed

6 files changed

+85
-7
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ PHP NEWS
2323
- SPL:
2424
. Fixed bug #74058 (ArrayObject can not notice changes). (Andrew Nester)
2525

26+
- Sqlite:
27+
. Implemented FR #74217 (Allow creation of deterministic sqlite functions).
28+
(Andrew Nester)
29+
2630
. Streams:
2731
. Fixed bug #74216 (Correctly fail on invalid IP address ports). (Sara)
2832

ext/pdo_sqlite/pdo_sqlite.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ ZEND_GET_MODULE(pdo_sqlite)
6969
/* {{{ PHP_MINIT_FUNCTION */
7070
PHP_MINIT_FUNCTION(pdo_sqlite)
7171
{
72+
REGISTER_PDO_CLASS_CONST_LONG("SQLITE_DETERMINISTIC", (zend_long)SQLITE_DETERMINISTIC);
73+
7274
return php_pdo_register_driver(&pdo_sqlite_driver);
7375
}
7476
/* }}} */

ext/pdo_sqlite/sqlite_driver.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ static int php_sqlite3_collation_callback(void *context,
505505
return ret;
506506
}
507507

508-
/* {{{ bool SQLite::sqliteCreateFunction(string name, mixed callback [, int argcount])
508+
/* {{{ bool SQLite::sqliteCreateFunction(string name, mixed callback [, int argcount, int flags])
509509
Registers a UDF with the sqlite db handle */
510510
static PHP_METHOD(SQLite, sqliteCreateFunction)
511511
{
@@ -514,13 +514,14 @@ static PHP_METHOD(SQLite, sqliteCreateFunction)
514514
char *func_name;
515515
size_t func_name_len;
516516
zend_long argc = -1;
517+
zend_long flags = 0;
517518
zend_string *cbname = NULL;
518519
pdo_dbh_t *dbh;
519520
pdo_sqlite_db_handle *H;
520521
int ret;
521522

522-
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sz|l",
523-
&func_name, &func_name_len, &callback, &argc)) {
523+
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sz|ll",
524+
&func_name, &func_name_len, &callback, &argc, &flags)) {
524525
RETURN_FALSE;
525526
}
526527

@@ -538,7 +539,7 @@ static PHP_METHOD(SQLite, sqliteCreateFunction)
538539

539540
func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
540541

541-
ret = sqlite3_create_function(H->db, func_name, argc, SQLITE_UTF8,
542+
ret = sqlite3_create_function(H->db, func_name, argc, flags | SQLITE_UTF8,
542543
func, php_sqlite3_func_callback, NULL, NULL);
543544
if (ret == SQLITE_OK) {
544545
func->funcname = estrdup(func_name);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
PDO_sqlite: Testing sqliteCreateFunction() with flags
3+
--SKIPIF--
4+
<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
5+
--FILE--
6+
<?php
7+
8+
$db = new pdo('sqlite::memory:');
9+
10+
$db->query('CREATE TABLE IF NOT EXISTS foobar (id INT AUTO INCREMENT, name TEXT)');
11+
12+
$db->query('INSERT INTO foobar VALUES (NULL, "PHP")');
13+
$db->query('INSERT INTO foobar VALUES (NULL, "PHP6")');
14+
15+
16+
$db->sqliteCreateFunction('testing', function($v) { return strtolower($v); }, 1, PDO::SQLITE_DETERMINISTIC);
17+
18+
19+
foreach ($db->query('SELECT testing(name) FROM foobar') as $row) {
20+
var_dump($row);
21+
}
22+
23+
$db->query('DROP TABLE foobar');
24+
25+
?>
26+
--EXPECTF--
27+
array(2) {
28+
["testing(name)"]=>
29+
string(3) "php"
30+
[0]=>
31+
string(3) "php"
32+
}
33+
array(2) {
34+
["testing(name)"]=>
35+
string(4) "php6"
36+
[0]=>
37+
string(4) "php6"
38+
}

ext/sqlite3/sqlite3.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ static int php_sqlite3_callback_compare(void *coll, int a_len, const void *a, in
891891
}
892892
/* }}} */
893893

894-
/* {{{ proto bool SQLite3::createFunction(string name, mixed callback [, int argcount])
894+
/* {{{ proto bool SQLite3::createFunction(string name, mixed callback [, int argcount, int flags])
895895
Allows registration of a PHP function as a SQLite UDF that can be called within SQL statements. */
896896
PHP_METHOD(sqlite3, createFunction)
897897
{
@@ -903,11 +903,12 @@ PHP_METHOD(sqlite3, createFunction)
903903
zval *callback_func;
904904
zend_string *callback_name;
905905
zend_long sql_func_num_args = -1;
906+
zend_long flags = 0;
906907
db_obj = Z_SQLITE3_DB_P(object);
907908

908909
SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3)
909910

910-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|l", &sql_func, &sql_func_len, &callback_func, &sql_func_num_args) == FAILURE) {
911+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|ll", &sql_func, &sql_func_len, &callback_func, &sql_func_num_args, &flags) == FAILURE) {
911912
return;
912913
}
913914

@@ -924,7 +925,7 @@ PHP_METHOD(sqlite3, createFunction)
924925

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

927-
if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, SQLITE_UTF8, func, php_sqlite3_callback_func, NULL, NULL) == SQLITE_OK) {
928+
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) {
928929
func->func_name = estrdup(sql_func);
929930

930931
ZVAL_COPY(&func->func, callback_func);
@@ -1894,6 +1895,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3_createfunction, 0, 0, 2)
18941895
ZEND_ARG_INFO(0, name)
18951896
ZEND_ARG_INFO(0, callback)
18961897
ZEND_ARG_INFO(0, argument_count)
1898+
ZEND_ARG_INFO(0, flags)
18971899
ZEND_END_ARG_INFO()
18981900

18991901
ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3_createaggregate, 0, 0, 3)
@@ -2281,6 +2283,8 @@ PHP_MINIT_FUNCTION(sqlite3)
22812283
REGISTER_LONG_CONSTANT("SQLITE3_OPEN_READWRITE", SQLITE_OPEN_READWRITE, CONST_CS | CONST_PERSISTENT);
22822284
REGISTER_LONG_CONSTANT("SQLITE3_OPEN_CREATE", SQLITE_OPEN_CREATE, CONST_CS | CONST_PERSISTENT);
22832285

2286+
REGISTER_LONG_CONSTANT("SQLITE3_DETERMINISTIC", SQLITE_DETERMINISTIC, CONST_CS | CONST_PERSISTENT);
2287+
22842288
return SUCCESS;
22852289
}
22862290
/* }}} */
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
SQLite3::createFunction - Test with flags
3+
--SKIPIF--
4+
<?php require_once(__DIR__ . '/skipif.inc'); ?>
5+
--FILE--
6+
<?php
7+
8+
require_once(__DIR__ . '/new_db.inc');
9+
10+
$func = 'strtoupper';
11+
var_dump($db->createfunction($func, $func, 1, SQLITE3_DETERMINISTIC));
12+
var_dump($db->querySingle('SELECT strtoupper("test")'));
13+
14+
$func2 = 'strtolower';
15+
var_dump($db->createfunction($func2, $func2, 1, SQLITE3_DETERMINISTIC));
16+
var_dump($db->querySingle('SELECT strtolower("TEST")'));
17+
18+
var_dump($db->createfunction($func, $func2, 1, SQLITE3_DETERMINISTIC));
19+
var_dump($db->querySingle('SELECT strtoupper("tEst")'));
20+
21+
22+
?>
23+
--EXPECTF--
24+
bool(true)
25+
string(4) "TEST"
26+
bool(true)
27+
string(4) "test"
28+
bool(true)
29+
string(4) "test"

0 commit comments

Comments
 (0)