diff options
author | Rasmus Lerdorf <rasmus@php.net> | 2012-01-29 04:22:23 +0000 |
---|---|---|
committer | Rasmus Lerdorf <rasmus@php.net> | 2012-01-29 04:22:23 +0000 |
commit | 9111a8a58a2559e3905ad304e03141c0c9ed7dee (patch) | |
tree | 80408d9a7172a73175ac96cdcd1440f1f116d273 /ext/pdo_sqlite | |
parent | 9722bff0c337f015ecda5d072049ca599e2f7e71 (diff) | |
download | php-git-9111a8a58a2559e3905ad304e03141c0c9ed7dee.tar.gz |
createCollation() for pdo_sqlite as well
Closes bug #55226
Diffstat (limited to 'ext/pdo_sqlite')
-rw-r--r-- | ext/pdo_sqlite/php_pdo_sqlite_int.h | 9 | ||||
-rw-r--r-- | ext/pdo_sqlite/sqlite_driver.c | 126 | ||||
-rw-r--r-- | ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt | 38 |
3 files changed, 173 insertions, 0 deletions
diff --git a/ext/pdo_sqlite/php_pdo_sqlite_int.h b/ext/pdo_sqlite/php_pdo_sqlite_int.h index 9a8d117535..8da419674f 100644 --- a/ext/pdo_sqlite/php_pdo_sqlite_int.h +++ b/ext/pdo_sqlite/php_pdo_sqlite_int.h @@ -46,10 +46,19 @@ struct pdo_sqlite_func { struct pdo_sqlite_fci afunc, astep, afini; }; +struct pdo_sqlite_collation { + struct pdo_sqlite_collation *next; + + const char *name; + zval *callback; + struct pdo_sqlite_fci fc; +}; + typedef struct { sqlite3 *db; pdo_sqlite_error_info einfo; struct pdo_sqlite_func *funcs; + struct pdo_sqlite_collation *collations; } pdo_sqlite_db_handle; typedef struct { diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 1bea23f53e..5a08e22c8e 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -129,6 +129,28 @@ static void pdo_sqlite_cleanup_callbacks(pdo_sqlite_db_handle *H TSRMLS_DC) } efree(func); } + + struct pdo_sqlite_collation *collation; + + while (H->collations) { + collation = H->collations; + H->collations = collation->next; + + if (H->db) { + /* delete the collation from the handle */ + sqlite3_create_collation(H->db, + collation->name, + SQLITE_UTF8, + collation, + NULL); + } + + efree((char*)collation->name); + if (collation->callback) { + zval_ptr_dtor(&collation->callback); + } + efree(collation); + } } static int sqlite_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */ @@ -457,6 +479,57 @@ static void php_sqlite3_func_final_callback(sqlite3_context *context) do_callback(&func->afini, func->fini, 0, NULL, context, 1 TSRMLS_CC); } +static int php_sqlite3_collation_callback(void *context, + int string1_len, const void *string1, + int string2_len, const void *string2) +{ + int ret; + zval *zstring1, *zstring2; + zval **zargs[2]; + zval *retval = NULL; + struct pdo_sqlite_collation *collation = (struct pdo_sqlite_collation*) context; + TSRMLS_FETCH(); + + collation->fc.fci.size = sizeof(collation->fc.fci); + collation->fc.fci.function_table = EG(function_table); + collation->fc.fci.function_name = collation->callback; + collation->fc.fci.symbol_table = NULL; + collation->fc.fci.object_ptr = NULL; + collation->fc.fci.retval_ptr_ptr = &retval; + + // Prepare the arguments. + MAKE_STD_ZVAL(zstring1); + ZVAL_STRINGL(zstring1, (char *) string1, string1_len, 1); + zargs[0] = &zstring1; + MAKE_STD_ZVAL(zstring2); + ZVAL_STRINGL(zstring2, (char *) string2, string2_len, 1); + zargs[1] = &zstring2; + collation->fc.fci.param_count = 2; + collation->fc.fci.params = zargs; + + if ((ret = zend_call_function(&collation->fc.fci, &collation->fc.fcc TSRMLS_CC)) == FAILURE) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the callback"); + } + else if (retval) { + if (Z_TYPE_P(retval) != IS_LONG) { + convert_to_long_ex(&retval); + } + ret = 0; + if (Z_LVAL_P(retval) > 0) { + ret = 1; + } + else if (Z_LVAL_P(retval) < 0) { + ret = -1; + } + zval_ptr_dtor(&retval); + } + + zval_ptr_dtor(zargs[0]); + zval_ptr_dtor(zargs[1]); + + return ret; +} + /* {{{ bool SQLite::sqliteCreateFunction(string name, mixed callback [, int argcount]) Registers a UDF with the sqlite db handle */ static PHP_METHOD(SQLite, sqliteCreateFunction) @@ -590,9 +663,62 @@ static PHP_METHOD(SQLite, sqliteCreateAggregate) RETURN_FALSE; } /* }}} */ + +/* {{{ bool SQLite::sqliteCreateCollation(string name, mixed callback) + Registers a collation with the sqlite db handle */ +static PHP_METHOD(SQLite, sqliteCreateCollation) +{ + struct pdo_sqlite_collation *collation; + zval *callback; + char *collation_name; + int collation_name_len; + char *cbname = NULL; + pdo_dbh_t *dbh; + pdo_sqlite_db_handle *H; + int ret; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", + &collation_name, &collation_name_len, &callback)) { + RETURN_FALSE; + } + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + if (!zend_is_callable(callback, 0, &cbname TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "function '%s' is not callable", cbname); + efree(cbname); + RETURN_FALSE; + } + efree(cbname); + + H = (pdo_sqlite_db_handle *)dbh->driver_data; + + collation = (struct pdo_sqlite_collation*)ecalloc(1, sizeof(*collation)); + + ret = sqlite3_create_collation(H->db, collation_name, SQLITE_UTF8, collation, php_sqlite3_collation_callback); + if (ret == SQLITE_OK) { + collation->name = estrdup(collation_name); + + MAKE_STD_ZVAL(collation->callback); + MAKE_COPY_ZVAL(&callback, collation->callback); + + collation->next = H->collations; + H->collations = collation; + + RETURN_TRUE; + } + + efree(collation); + RETURN_FALSE; +} +/* }}} */ + + static const zend_function_entry dbh_methods[] = { PHP_ME(SQLite, sqliteCreateFunction, NULL, ZEND_ACC_PUBLIC) PHP_ME(SQLite, sqliteCreateAggregate, NULL, ZEND_ACC_PUBLIC) + PHP_ME(SQLite, sqliteCreateCollation, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt new file mode 100644 index 0000000000..c35e3637ac --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt @@ -0,0 +1,38 @@ +--TEST-- +PDO_sqlite: Testing sqliteCreateCollation() +--SKIPIF-- +<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?> +--FILE-- +<?php + +$db = new pdo('sqlite::memory:'); +$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +$db->query('CREATE TABLE IF NOT EXISTS foobar (id INT AUTO INCREMENT, name TEXT)'); + +$db->query('INSERT INTO foobar VALUES (NULL, "1")'); +$db->query('INSERT INTO foobar VALUES (NULL, "2")'); +$db->query('INSERT INTO foobar VALUES (NULL, "10")'); + +$db->sqliteCreateCollation('MYCOLLATE', function($a, $b) { return strnatcmp($a, $b); }); + +$result = $db->query('SELECT name FROM foobar ORDER BY name COLLATE MYCOLLATE'); +foreach ($result as $row) { + echo $row['name'] . "\n"; +} + +$result = $db->query('SELECT name FROM foobar ORDER BY name'); +foreach ($result as $row) { + echo $row['name'] . "\n"; +} + +$db->query('DROP TABLE foobar'); + +?> +--EXPECTF-- +1 +2 +10 +1 +10 +2 |