mirror of
https://github.com/php/php-src.git
synced 2024-12-17 05:50:14 +08:00
parent
d8b312845c
commit
dc27324dd9
@ -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 {
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
38
ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt
Normal file
38
ext/pdo_sqlite/tests/pdo_sqlite_createcollation.phpt
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user