mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
ext/sqlite3: Sqlite3Result::fetchAll()
support associative and indexes arrays for results. close GH-1884
This commit is contained in:
parent
22bd2ae63f
commit
375316d0e2
6 changed files with 205 additions and 25 deletions
2
NEWS
2
NEWS
|
@ -249,6 +249,8 @@ PHP NEWS
|
|||
(David Carlier)
|
||||
. Added Sqlite3Stmt::explain to produce a explain query plan from
|
||||
the statement. (David Carlier)
|
||||
. Added Sqlite3Result::fetchAll to returns all results at once from a query.
|
||||
(David Carlier)
|
||||
|
||||
- Standard:
|
||||
. Fixed crypt() tests on musl when using --with-external-libcrypt
|
||||
|
|
|
@ -212,6 +212,11 @@ PHP 8.5 UPGRADE NOTES
|
|||
now have an optional $lang parameter.
|
||||
This support solves compatibility with .NET SOAP clients.
|
||||
|
||||
- Sqlite:
|
||||
. Added class constants Sqlite3Stmt::EXPLAIN_MODE_PREPARED,
|
||||
Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN and
|
||||
Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN.
|
||||
|
||||
- XSL:
|
||||
. The $namespace argument of XSLTProcessor::getParameter(),
|
||||
XSLTProcessor::setParameter() and XSLTProcessor::removeParameter()
|
||||
|
|
|
@ -39,6 +39,7 @@ static PHP_GINIT_FUNCTION(sqlite3);
|
|||
static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, const char *arg2, const char *arg3, const char *arg4);
|
||||
static void sqlite3_param_dtor(zval *data);
|
||||
static int php_sqlite3_compare_stmt_free(php_sqlite3_stmt **stmt_obj_ptr, sqlite3_stmt *statement);
|
||||
static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_result *result_obj, zend_long mode, zval *result);
|
||||
|
||||
#define SQLITE3_CHECK_INITIALIZED(db_obj, member, class_name) \
|
||||
if (!(db_obj) || !(member)) { \
|
||||
|
@ -1991,7 +1992,7 @@ PHP_METHOD(SQLite3Result, fetchArray)
|
|||
{
|
||||
php_sqlite3_result *result_obj;
|
||||
zval *object = ZEND_THIS;
|
||||
int i, ret;
|
||||
int ret;
|
||||
zend_long mode = PHP_SQLITE3_BOTH;
|
||||
result_obj = Z_SQLITE3_RESULT_P(object);
|
||||
|
||||
|
@ -2028,26 +2029,8 @@ PHP_METHOD(SQLite3Result, fetchArray)
|
|||
|
||||
array_init(return_value);
|
||||
|
||||
for (i = 0; i < n_cols; i++) {
|
||||
zval data;
|
||||
php_sqlite3_fetch_one(n_cols, result_obj, mode, return_value);
|
||||
|
||||
sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data);
|
||||
|
||||
if (mode & PHP_SQLITE3_NUM) {
|
||||
add_index_zval(return_value, i, &data);
|
||||
}
|
||||
|
||||
if (mode & PHP_SQLITE3_ASSOC) {
|
||||
if (mode & PHP_SQLITE3_NUM) {
|
||||
if (Z_REFCOUNTED(data)) {
|
||||
Z_ADDREF(data);
|
||||
}
|
||||
}
|
||||
/* Note: we can't use the "add_new" variant here instead of "update" because
|
||||
* when the same column name is encountered, the last result should be taken. */
|
||||
zend_symtable_update(Z_ARR_P(return_value), result_obj->column_names[i], &data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SQLITE_DONE:
|
||||
|
@ -2071,6 +2054,61 @@ static void sqlite3result_clear_column_names_cache(php_sqlite3_result *result) {
|
|||
result->column_count = -1;
|
||||
}
|
||||
|
||||
PHP_METHOD(SQLite3Result, fetchAll)
|
||||
{
|
||||
int i, nb_cols;
|
||||
bool done = false;
|
||||
php_sqlite3_result *result_obj;
|
||||
zval *object = ZEND_THIS;
|
||||
zend_long mode = PHP_SQLITE3_BOTH;
|
||||
result_obj = Z_SQLITE3_RESULT_P(object);
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(0, 1)
|
||||
Z_PARAM_OPTIONAL
|
||||
Z_PARAM_LONG(mode)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result)
|
||||
|
||||
nb_cols = sqlite3_column_count(result_obj->stmt_obj->stmt);
|
||||
if (mode & PHP_SQLITE3_ASSOC) {
|
||||
sqlite3result_clear_column_names_cache(result_obj);
|
||||
result_obj->column_names = emalloc(nb_cols * sizeof(zend_string*));
|
||||
|
||||
for (i = 0; i < nb_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);
|
||||
}
|
||||
}
|
||||
result_obj->column_count = nb_cols;
|
||||
array_init(return_value);
|
||||
|
||||
while (!done) {
|
||||
int step = sqlite3_step(result_obj->stmt_obj->stmt);
|
||||
|
||||
switch (step) {
|
||||
case SQLITE_ROW: {
|
||||
zval result;
|
||||
array_init_size(&result, result_obj->column_count);
|
||||
|
||||
php_sqlite3_fetch_one(result_obj->column_count, result_obj, mode, &result);
|
||||
|
||||
add_next_index_zval(return_value, &result);
|
||||
break;
|
||||
}
|
||||
case SQLITE_DONE:
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
if (!EG(exception)) {
|
||||
php_sqlite3_error(result_obj->db_obj, sqlite3_errcode(sqlite3_db_handle(result_obj->stmt_obj->stmt)), "Unable to execute statement: %s", sqlite3_errmsg(sqlite3_db_handle(result_obj->stmt_obj->stmt)));
|
||||
}
|
||||
zval_ptr_dtor(return_value);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{ Resets the result set back to the first row. */
|
||||
PHP_METHOD(SQLite3Result, reset)
|
||||
{
|
||||
|
@ -2429,6 +2467,29 @@ static void sqlite3_param_dtor(zval *data) /* {{{ */
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_result *result_obj, zend_long mode, zval *result)
|
||||
{
|
||||
for (int i = 0; i < n_cols; i ++) {
|
||||
zval data;
|
||||
sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data);
|
||||
|
||||
if (mode & PHP_SQLITE3_NUM) {
|
||||
add_index_zval(result, i, &data);
|
||||
}
|
||||
|
||||
if (mode & PHP_SQLITE3_ASSOC) {
|
||||
if (mode & PHP_SQLITE3_NUM) {
|
||||
if (Z_REFCOUNTED(data)) {
|
||||
Z_ADDREF(data);
|
||||
}
|
||||
}
|
||||
/* Note: we can't use the "add_new" variant here instead of "update" because
|
||||
* when the same column name is encountered, the last result should be taken. */
|
||||
zend_symtable_update(Z_ARR_P(result), result_obj->column_names[i], &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* {{{ PHP_MINIT_FUNCTION */
|
||||
PHP_MINIT_FUNCTION(sqlite3)
|
||||
{
|
||||
|
|
|
@ -302,6 +302,8 @@ class SQLite3Result
|
|||
/** @tentative-return-type */
|
||||
public function fetchArray(int $mode = SQLITE3_BOTH): array|false {}
|
||||
|
||||
public function fetchAll(int $mode = SQLITE3_BOTH): array|false {}
|
||||
|
||||
/** @tentative-return-type */
|
||||
public function reset(): bool {}
|
||||
|
||||
|
|
12
ext/sqlite3/sqlite3_arginfo.h
generated
12
ext/sqlite3/sqlite3_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: c3216eada9881743cbd3aa1510f1200b7ce0d942 */
|
||||
* Stub hash: da91c32c6070c808d6e1b01894b5f8beedda7b45 */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SQLite3___construct, 0, 0, 1)
|
||||
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
|
||||
|
@ -173,6 +173,10 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_MASK_EX(arginfo_class_SQLite3Result_fe
|
|||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "SQLITE3_BOTH")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_SQLite3Result_fetchAll, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_LONG, 0, "SQLITE3_BOTH")
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_class_SQLite3Result_reset arginfo_class_SQLite3_close
|
||||
|
||||
#define arginfo_class_SQLite3Result_finalize arginfo_class_SQLite3Stmt_close
|
||||
|
@ -224,6 +228,7 @@ ZEND_METHOD(SQLite3Result, numColumns);
|
|||
ZEND_METHOD(SQLite3Result, columnName);
|
||||
ZEND_METHOD(SQLite3Result, columnType);
|
||||
ZEND_METHOD(SQLite3Result, fetchArray);
|
||||
ZEND_METHOD(SQLite3Result, fetchAll);
|
||||
ZEND_METHOD(SQLite3Result, reset);
|
||||
ZEND_METHOD(SQLite3Result, finalize);
|
||||
|
||||
|
@ -284,6 +289,7 @@ static const zend_function_entry class_SQLite3Result_methods[] = {
|
|||
ZEND_ME(SQLite3Result, columnName, arginfo_class_SQLite3Result_columnName, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SQLite3Result, columnType, arginfo_class_SQLite3Result_columnType, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SQLite3Result, fetchArray, arginfo_class_SQLite3Result_fetchArray, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SQLite3Result, fetchAll, arginfo_class_SQLite3Result_fetchAll, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SQLite3Result, reset, arginfo_class_SQLite3Result_reset, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(SQLite3Result, finalize, arginfo_class_SQLite3Result_finalize, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
|
@ -564,16 +570,12 @@ static zend_class_entry *register_class_SQLite3Stmt(void)
|
|||
zend_string *const_EXPLAIN_MODE_PREPARED_name = zend_string_init_interned("EXPLAIN_MODE_PREPARED", sizeof("EXPLAIN_MODE_PREPARED") - 1, 1);
|
||||
zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_PREPARED_name, &const_EXPLAIN_MODE_PREPARED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_string_release(const_EXPLAIN_MODE_PREPARED_name);
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3043000
|
||||
|
||||
zval const_EXPLAIN_MODE_EXPLAIN_value;
|
||||
ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_value, 1);
|
||||
zend_string *const_EXPLAIN_MODE_EXPLAIN_name = zend_string_init_interned("EXPLAIN_MODE_EXPLAIN", sizeof("EXPLAIN_MODE_EXPLAIN") - 1, 1);
|
||||
zend_declare_typed_class_constant(class_entry, const_EXPLAIN_MODE_EXPLAIN_name, &const_EXPLAIN_MODE_EXPLAIN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
|
||||
zend_string_release(const_EXPLAIN_MODE_EXPLAIN_name);
|
||||
#endif
|
||||
#if SQLITE_VERSION_NUMBER >= 3043000
|
||||
|
||||
zval const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value;
|
||||
ZVAL_LONG(&const_EXPLAIN_MODE_EXPLAIN_QUERY_PLAN_value, 2);
|
||||
|
|
108
ext/sqlite3/tests/sqlite3_fetch_all.phpt
Normal file
108
ext/sqlite3/tests/sqlite3_fetch_all.phpt
Normal file
|
@ -0,0 +1,108 @@
|
|||
--TEST--
|
||||
SQLite3Result::fetchAll usage
|
||||
--EXTENSIONS--
|
||||
sqlite3
|
||||
--FILE--
|
||||
<?php
|
||||
$conn = new sqlite3(':memory:');
|
||||
$conn->query('CREATE TABLE users (id INTEGER NOT NULL, num INTEGER NOT NULL, PRIMARY KEY(id))');
|
||||
|
||||
$stmt = $conn->query('insert into users (id, num) values (1, 1)');
|
||||
$stmt = $conn->query('insert into users (id, num) values (2, 2)');
|
||||
|
||||
$stmt = $conn->query('SELECT * FROM users');
|
||||
$rowall = $stmt->fetchAll();
|
||||
var_dump($rowall);
|
||||
$stmt->reset();
|
||||
$rowfetch = [];
|
||||
while (($row = $stmt->fetchArray())) $rowfetch[] = $row;
|
||||
var_dump($rowfetch);
|
||||
var_dump($rowall == $rowfetch);
|
||||
$stmt->reset();
|
||||
var_dump($stmt->fetchAll(SQLITE3_NUM));
|
||||
$stmt->reset();
|
||||
var_dump($stmt->fetchAll(SQLITE3_ASSOC));
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(4) {
|
||||
[0]=>
|
||||
int(1)
|
||||
["id"]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(1)
|
||||
["num"]=>
|
||||
int(1)
|
||||
}
|
||||
[1]=>
|
||||
array(4) {
|
||||
[0]=>
|
||||
int(2)
|
||||
["id"]=>
|
||||
int(2)
|
||||
[1]=>
|
||||
int(2)
|
||||
["num"]=>
|
||||
int(2)
|
||||
}
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(4) {
|
||||
[0]=>
|
||||
int(1)
|
||||
["id"]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(1)
|
||||
["num"]=>
|
||||
int(1)
|
||||
}
|
||||
[1]=>
|
||||
array(4) {
|
||||
[0]=>
|
||||
int(2)
|
||||
["id"]=>
|
||||
int(2)
|
||||
[1]=>
|
||||
int(2)
|
||||
["num"]=>
|
||||
int(2)
|
||||
}
|
||||
}
|
||||
bool(true)
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(1)
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(2)
|
||||
[1]=>
|
||||
int(2)
|
||||
}
|
||||
}
|
||||
array(2) {
|
||||
[0]=>
|
||||
array(2) {
|
||||
["id"]=>
|
||||
int(1)
|
||||
["num"]=>
|
||||
int(1)
|
||||
}
|
||||
[1]=>
|
||||
array(2) {
|
||||
["id"]=>
|
||||
int(2)
|
||||
["num"]=>
|
||||
int(2)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue