]> granicus.if.org Git - php/commitdiff
Implement FR #74217: deterministic sqlite functions
authorandrewnester <andrew.nester.dev@gmail.com>
Fri, 10 Mar 2017 17:34:23 +0000 (20:34 +0300)
committerNikita Popov <nikita.ppv@gmail.com>
Sun, 12 Mar 2017 16:03:00 +0000 (17:03 +0100)
NEWS
ext/pdo_sqlite/pdo_sqlite.c
ext/pdo_sqlite/sqlite_driver.c
ext/pdo_sqlite/tests/pdo_sqlite_createfunction_with_flags.phpt [new file with mode: 0644]
ext/sqlite3/sqlite3.c
ext/sqlite3/tests/sqlite3_37_createfunction_flags.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 65815160536a77305ad79826be9781ae1156895f..d8271efa882c68c18d864017de7e58cb4e0f54ca 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,10 @@ PHP                                                                        NEWS
 - SPL:
   . Fixed bug #74058 (ArrayObject can not notice changes). (Andrew Nester)
 
+- Sqlite:
+  . Implemented FR #74217 (Allow creation of deterministic sqlite functions).
+    (Andrew Nester)
+
 . Streams:
   . Fixed bug #74216 (Correctly fail on invalid IP address ports). (Sara)
 
index c5bba02d07a85d6031f2d6a0ceefef55bbfbfc83..621123b39ab6608dc4947d8906e465ffd575ce9f 100644 (file)
@@ -69,6 +69,8 @@ ZEND_GET_MODULE(pdo_sqlite)
 /* {{{ PHP_MINIT_FUNCTION */
 PHP_MINIT_FUNCTION(pdo_sqlite)
 {
+       REGISTER_PDO_CLASS_CONST_LONG("SQLITE_DETERMINISTIC", (zend_long)SQLITE_DETERMINISTIC);
+
        return php_pdo_register_driver(&pdo_sqlite_driver);
 }
 /* }}} */
index 3f9b51d121dc0012b6d64198170cc2648664a63a..71bac8580afe70794e1b17b9af14cb6bfcfbd765 100644 (file)
@@ -505,7 +505,7 @@ static int php_sqlite3_collation_callback(void *context,
        return ret;
 }
 
-/* {{{ bool SQLite::sqliteCreateFunction(string name, mixed callback [, int argcount])
+/* {{{ bool SQLite::sqliteCreateFunction(string name, mixed callback [, int argcount, int flags])
    Registers a UDF with the sqlite db handle */
 static PHP_METHOD(SQLite, sqliteCreateFunction)
 {
@@ -514,13 +514,14 @@ static PHP_METHOD(SQLite, sqliteCreateFunction)
        char *func_name;
        size_t func_name_len;
        zend_long argc = -1;
+       zend_long flags = 0;
        zend_string *cbname = NULL;
        pdo_dbh_t *dbh;
        pdo_sqlite_db_handle *H;
        int ret;
 
-       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sz|l",
-                       &func_name, &func_name_len, &callback, &argc)) {
+       if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "sz|ll",
+                       &func_name, &func_name_len, &callback, &argc, &flags)) {
                RETURN_FALSE;
        }
 
@@ -538,7 +539,7 @@ static PHP_METHOD(SQLite, sqliteCreateFunction)
 
        func = (struct pdo_sqlite_func*)ecalloc(1, sizeof(*func));
 
-       ret = sqlite3_create_function(H->db, func_name, argc, SQLITE_UTF8,
+       ret = sqlite3_create_function(H->db, func_name, argc, flags | SQLITE_UTF8,
                        func, php_sqlite3_func_callback, NULL, NULL);
        if (ret == SQLITE_OK) {
                func->funcname = estrdup(func_name);
diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_createfunction_with_flags.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_createfunction_with_flags.phpt
new file mode 100644 (file)
index 0000000..4f0b675
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+PDO_sqlite: Testing sqliteCreateFunction() with flags
+--SKIPIF--
+<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
+--FILE--
+<?php
+
+$db = new pdo('sqlite::memory:');
+
+$db->query('CREATE TABLE IF NOT EXISTS foobar (id INT AUTO INCREMENT, name TEXT)');
+
+$db->query('INSERT INTO foobar VALUES (NULL, "PHP")');
+$db->query('INSERT INTO foobar VALUES (NULL, "PHP6")');
+
+
+$db->sqliteCreateFunction('testing', function($v) { return strtolower($v); }, 1, PDO::SQLITE_DETERMINISTIC);
+
+
+foreach ($db->query('SELECT testing(name) FROM foobar') as $row) {
+       var_dump($row);
+}
+
+$db->query('DROP TABLE foobar');
+
+?>
+--EXPECTF--
+array(2) {
+  ["testing(name)"]=>
+  string(3) "php"
+  [0]=>
+  string(3) "php"
+}
+array(2) {
+  ["testing(name)"]=>
+  string(4) "php6"
+  [0]=>
+  string(4) "php6"
+}
index f9476748bf87652b73612272e876af96876f40df..5a796e1bbf67c9fb217f856c7b15024c29306272 100644 (file)
@@ -891,7 +891,7 @@ static int php_sqlite3_callback_compare(void *coll, int a_len, const void *a, in
 }
 /* }}} */
 
-/* {{{ proto bool SQLite3::createFunction(string name, mixed callback [, int argcount])
+/* {{{ proto bool SQLite3::createFunction(string name, mixed callback [, int argcount, int flags])
    Allows registration of a PHP function as a SQLite UDF that can be called within SQL statements. */
 PHP_METHOD(sqlite3, createFunction)
 {
@@ -903,11 +903,12 @@ PHP_METHOD(sqlite3, createFunction)
        zval *callback_func;
        zend_string *callback_name;
        zend_long sql_func_num_args = -1;
+       zend_long flags = 0;
        db_obj = Z_SQLITE3_DB_P(object);
 
        SQLITE3_CHECK_INITIALIZED(db_obj, db_obj->initialised, SQLite3)
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|l", &sql_func, &sql_func_len, &callback_func, &sql_func_num_args) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|ll", &sql_func, &sql_func_len, &callback_func, &sql_func_num_args, &flags) == FAILURE) {
                return;
        }
 
@@ -924,7 +925,7 @@ PHP_METHOD(sqlite3, createFunction)
 
        func = (php_sqlite3_func *)ecalloc(1, sizeof(*func));
 
-       if (sqlite3_create_function(db_obj->db, sql_func, sql_func_num_args, SQLITE_UTF8, func, php_sqlite3_callback_func, NULL, NULL) == SQLITE_OK) {
+       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);
@@ -1894,6 +1895,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3_createfunction, 0, 0, 2)
        ZEND_ARG_INFO(0, name)
        ZEND_ARG_INFO(0, callback)
        ZEND_ARG_INFO(0, argument_count)
+       ZEND_ARG_INFO(0, flags)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3_createaggregate, 0, 0, 3)
@@ -2281,6 +2283,8 @@ PHP_MINIT_FUNCTION(sqlite3)
        REGISTER_LONG_CONSTANT("SQLITE3_OPEN_READWRITE", SQLITE_OPEN_READWRITE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLITE3_OPEN_CREATE", SQLITE_OPEN_CREATE, CONST_CS | CONST_PERSISTENT);
 
+       REGISTER_LONG_CONSTANT("SQLITE3_DETERMINISTIC", SQLITE_DETERMINISTIC, CONST_CS | CONST_PERSISTENT);
+
        return SUCCESS;
 }
 /* }}} */
diff --git a/ext/sqlite3/tests/sqlite3_37_createfunction_flags.phpt b/ext/sqlite3/tests/sqlite3_37_createfunction_flags.phpt
new file mode 100644 (file)
index 0000000..31fd42b
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+SQLite3::createFunction - Test with flags
+--SKIPIF--
+<?php require_once(__DIR__ . '/skipif.inc'); ?>
+--FILE--
+<?php
+
+require_once(__DIR__ . '/new_db.inc');
+
+$func = 'strtoupper';
+var_dump($db->createfunction($func, $func, 1, SQLITE3_DETERMINISTIC));
+var_dump($db->querySingle('SELECT strtoupper("test")'));
+
+$func2 = 'strtolower';
+var_dump($db->createfunction($func2, $func2, 1, SQLITE3_DETERMINISTIC));
+var_dump($db->querySingle('SELECT strtolower("TEST")'));
+
+var_dump($db->createfunction($func, $func2, 1, SQLITE3_DETERMINISTIC));
+var_dump($db->querySingle('SELECT strtoupper("tEst")'));
+
+
+?>
+--EXPECTF--
+bool(true)
+string(4) "TEST"
+bool(true)
+string(4) "test"
+bool(true)
+string(4) "test"