mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Speed up SQLite3Result::fetchArray() by caching column names
Closes GH-7505.
This commit is contained in:
parent
1ea58832e2
commit
1487dd03bc
3 changed files with 81 additions and 5 deletions
|
@ -107,6 +107,11 @@ struct _php_sqlite3_result_object {
|
||||||
php_sqlite3_stmt *stmt_obj;
|
php_sqlite3_stmt *stmt_obj;
|
||||||
zval stmt_obj_zval;
|
zval stmt_obj_zval;
|
||||||
|
|
||||||
|
/* Cache of column names to speed up repeated fetchArray(SQLITE3_ASSOC) calls.
|
||||||
|
* Cache is cleared on reset() and finalize() calls. */
|
||||||
|
int column_count;
|
||||||
|
zend_string **column_names;
|
||||||
|
|
||||||
int is_prepared_statement;
|
int is_prepared_statement;
|
||||||
zend_object zo;
|
zend_object zo;
|
||||||
};
|
};
|
||||||
|
|
|
@ -586,6 +586,8 @@ PHP_METHOD(SQLite3, query)
|
||||||
result = Z_SQLITE3_RESULT_P(return_value);
|
result = Z_SQLITE3_RESULT_P(return_value);
|
||||||
result->db_obj = db_obj;
|
result->db_obj = db_obj;
|
||||||
result->stmt_obj = stmt_obj;
|
result->stmt_obj = stmt_obj;
|
||||||
|
result->column_names = NULL;
|
||||||
|
result->column_count = -1;
|
||||||
ZVAL_OBJ(&result->stmt_obj_zval, Z_OBJ(stmt));
|
ZVAL_OBJ(&result->stmt_obj_zval, Z_OBJ(stmt));
|
||||||
|
|
||||||
return_code = sqlite3_step(result->stmt_obj->stmt);
|
return_code = sqlite3_step(result->stmt_obj->stmt);
|
||||||
|
@ -1792,6 +1794,8 @@ PHP_METHOD(SQLite3Stmt, execute)
|
||||||
result->is_prepared_statement = 1;
|
result->is_prepared_statement = 1;
|
||||||
result->db_obj = stmt_obj->db_obj;
|
result->db_obj = stmt_obj->db_obj;
|
||||||
result->stmt_obj = stmt_obj;
|
result->stmt_obj = stmt_obj;
|
||||||
|
result->column_names = NULL;
|
||||||
|
result->column_count = -1;
|
||||||
ZVAL_OBJ_COPY(&result->stmt_obj_zval, Z_OBJ_P(object));
|
ZVAL_OBJ_COPY(&result->stmt_obj_zval, Z_OBJ_P(object));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1945,11 +1949,25 @@ PHP_METHOD(SQLite3Result, fetchArray)
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result_obj->column_count == -1) {
|
||||||
|
result_obj->column_count = sqlite3_column_count(result_obj->stmt_obj->stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int n_cols = result_obj->column_count;
|
||||||
|
|
||||||
|
/* Cache column names to speed up repeated fetchArray calls. */
|
||||||
|
if (mode & PHP_SQLITE3_ASSOC && !result_obj->column_names) {
|
||||||
|
result_obj->column_names = emalloc(n_cols * sizeof(zend_string*));
|
||||||
|
|
||||||
|
for (int i = 0; i < n_cols; i++) {
|
||||||
|
const char *column = sqlite3_column_name(result_obj->stmt_obj->stmt, i);
|
||||||
|
result_obj->column_names[i] = zend_string_init(column, strlen(column), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
array_init(return_value);
|
array_init(return_value);
|
||||||
|
|
||||||
int column_count = sqlite3_data_count(result_obj->stmt_obj->stmt);
|
for (i = 0; i < n_cols; i++) {
|
||||||
|
|
||||||
for (i = 0; i < column_count; i++) {
|
|
||||||
zval data;
|
zval data;
|
||||||
|
|
||||||
sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data);
|
sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data);
|
||||||
|
@ -1964,7 +1982,7 @@ PHP_METHOD(SQLite3Result, fetchArray)
|
||||||
Z_ADDREF(data);
|
Z_ADDREF(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_assoc_zval(return_value, (char*)sqlite3_column_name(result_obj->stmt_obj->stmt, i), &data);
|
zend_symtable_add_new(Z_ARR_P(return_value), result_obj->column_names[i], &data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1979,6 +1997,17 @@ PHP_METHOD(SQLite3Result, fetchArray)
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
static void sqlite3result_clear_column_names_cache(php_sqlite3_result *result) {
|
||||||
|
if (result->column_names) {
|
||||||
|
for (int i = 0; i < result->column_count; i++) {
|
||||||
|
zend_string_release(result->column_names[i]);
|
||||||
|
}
|
||||||
|
efree(result->column_names);
|
||||||
|
}
|
||||||
|
result->column_names = NULL;
|
||||||
|
result->column_count = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* {{{ Resets the result set back to the first row. */
|
/* {{{ Resets the result set back to the first row. */
|
||||||
PHP_METHOD(SQLite3Result, reset)
|
PHP_METHOD(SQLite3Result, reset)
|
||||||
{
|
{
|
||||||
|
@ -1990,6 +2019,8 @@ PHP_METHOD(SQLite3Result, reset)
|
||||||
|
|
||||||
SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result)
|
SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result)
|
||||||
|
|
||||||
|
sqlite3result_clear_column_names_cache(result_obj);
|
||||||
|
|
||||||
if (sqlite3_reset(result_obj->stmt_obj->stmt) != SQLITE_OK) {
|
if (sqlite3_reset(result_obj->stmt_obj->stmt) != SQLITE_OK) {
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -2009,6 +2040,8 @@ PHP_METHOD(SQLite3Result, finalize)
|
||||||
|
|
||||||
SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result)
|
SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result)
|
||||||
|
|
||||||
|
sqlite3result_clear_column_names_cache(result_obj);
|
||||||
|
|
||||||
/* We need to finalize an internal statement */
|
/* We need to finalize an internal statement */
|
||||||
if (result_obj->is_prepared_statement == 0) {
|
if (result_obj->is_prepared_statement == 0) {
|
||||||
zend_llist_del_element(&(result_obj->db_obj->free_list), &result_obj->stmt_obj_zval,
|
zend_llist_del_element(&(result_obj->db_obj->free_list), &result_obj->stmt_obj_zval,
|
||||||
|
@ -2235,6 +2268,8 @@ static void php_sqlite3_result_object_free_storage(zend_object *object) /* {{{ *
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlite3result_clear_column_names_cache(intern);
|
||||||
|
|
||||||
if (!Z_ISNULL(intern->stmt_obj_zval)) {
|
if (!Z_ISNULL(intern->stmt_obj_zval)) {
|
||||||
if (intern->stmt_obj && intern->stmt_obj->initialised) {
|
if (intern->stmt_obj && intern->stmt_obj->initialised) {
|
||||||
sqlite3_reset(intern->stmt_obj->stmt);
|
sqlite3_reset(intern->stmt_obj->stmt);
|
||||||
|
|
36
ext/sqlite3/tests/sqlite3_rename_column.phpt
Normal file
36
ext/sqlite3/tests/sqlite3_rename_column.phpt
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
--TEST--
|
||||||
|
SQLite3 - rename column while SQLite3Result is open
|
||||||
|
--EXTENSIONS--
|
||||||
|
sqlite3
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (SQLite3::version()['versionNumber'] < 3025000) {
|
||||||
|
die("skip: sqlite3 library version < 3.25: no support for rename column");
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$db = new SQLite3(':memory:');
|
||||||
|
|
||||||
|
$db->exec('CREATE TABLE tbl (orig text)');
|
||||||
|
$db->exec('insert into tbl values ("one"), ("two")');
|
||||||
|
|
||||||
|
$res1 = $db->prepare('select * from tbl')->execute();
|
||||||
|
$res2 = $db->prepare('select * from tbl')->execute();
|
||||||
|
|
||||||
|
var_dump(array_key_first($res1->fetchArray(SQLITE3_ASSOC)));
|
||||||
|
var_dump(array_key_first($res2->fetchArray(SQLITE3_ASSOC)));
|
||||||
|
|
||||||
|
$db->exec('alter table tbl rename column orig to changed');
|
||||||
|
|
||||||
|
$res1->reset();
|
||||||
|
var_dump(array_key_first($res1->fetchArray(SQLITE3_ASSOC)));
|
||||||
|
var_dump(array_key_first($res2->fetchArray(SQLITE3_ASSOC)));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
string(4) "orig"
|
||||||
|
string(4) "orig"
|
||||||
|
string(7) "changed"
|
||||||
|
string(4) "orig"
|
Loading…
Add table
Add a link
Reference in a new issue