Skip to content

Commit 375316d

Browse files
committed
ext/sqlite3: Sqlite3Result::fetchAll()
support associative and indexes arrays for results. close GH-1884
1 parent 22bd2ae commit 375316d

File tree

6 files changed

+205
-25
lines changed

6 files changed

+205
-25
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ PHP NEWS
249249
(David Carlier)
250250
. Added Sqlite3Stmt::explain to produce a explain query plan from
251251
the statement. (David Carlier)
252+
. Added Sqlite3Result::fetchAll to returns all results at once from a query.
253+
(David Carlier)
252254

253255
- Standard:
254256
. Fixed crypt() tests on musl when using --with-external-libcrypt

UPGRADING

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ PHP 8.5 UPGRADE NOTES
212212
now have an optional $lang parameter.
213213
This support solves compatibility with .NET SOAP clients.
214214

215+
- Sqlite:
216+
. Added class constants Sqlite3Stmt::EXPLAIN_MODE_PREPARED,
217+
Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN and
218+
Sqlite3Stmt::EXPLAIN_MODE_EXPLAIN_QUERY_PLAN.
219+
215220
- XSL:
216221
. The $namespace argument of XSLTProcessor::getParameter(),
217222
XSLTProcessor::setParameter() and XSLTProcessor::removeParameter()

ext/sqlite3/sqlite3.c

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static PHP_GINIT_FUNCTION(sqlite3);
3939
static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, const char *arg2, const char *arg3, const char *arg4);
4040
static void sqlite3_param_dtor(zval *data);
4141
static int php_sqlite3_compare_stmt_free(php_sqlite3_stmt **stmt_obj_ptr, sqlite3_stmt *statement);
42+
static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_result *result_obj, zend_long mode, zval *result);
4243

4344
#define SQLITE3_CHECK_INITIALIZED(db_obj, member, class_name) \
4445
if (!(db_obj) || !(member)) { \
@@ -1991,7 +1992,7 @@ PHP_METHOD(SQLite3Result, fetchArray)
19911992
{
19921993
php_sqlite3_result *result_obj;
19931994
zval *object = ZEND_THIS;
1994-
int i, ret;
1995+
int ret;
19951996
zend_long mode = PHP_SQLITE3_BOTH;
19961997
result_obj = Z_SQLITE3_RESULT_P(object);
19971998

@@ -2028,26 +2029,8 @@ PHP_METHOD(SQLite3Result, fetchArray)
20282029

20292030
array_init(return_value);
20302031

2031-
for (i = 0; i < n_cols; i++) {
2032-
zval data;
2033-
2034-
sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data);
2035-
2036-
if (mode & PHP_SQLITE3_NUM) {
2037-
add_index_zval(return_value, i, &data);
2038-
}
2032+
php_sqlite3_fetch_one(n_cols, result_obj, mode, return_value);
20392033

2040-
if (mode & PHP_SQLITE3_ASSOC) {
2041-
if (mode & PHP_SQLITE3_NUM) {
2042-
if (Z_REFCOUNTED(data)) {
2043-
Z_ADDREF(data);
2044-
}
2045-
}
2046-
/* Note: we can't use the "add_new" variant here instead of "update" because
2047-
* when the same column name is encountered, the last result should be taken. */
2048-
zend_symtable_update(Z_ARR_P(return_value), result_obj->column_names[i], &data);
2049-
}
2050-
}
20512034
break;
20522035

20532036
case SQLITE_DONE:
@@ -2071,6 +2054,61 @@ static void sqlite3result_clear_column_names_cache(php_sqlite3_result *result) {
20712054
result->column_count = -1;
20722055
}
20732056

2057+
PHP_METHOD(SQLite3Result, fetchAll)
2058+
{
2059+
int i, nb_cols;
2060+
bool done = false;
2061+
php_sqlite3_result *result_obj;
2062+
zval *object = ZEND_THIS;
2063+
zend_long mode = PHP_SQLITE3_BOTH;
2064+
result_obj = Z_SQLITE3_RESULT_P(object);
2065+
2066+
ZEND_PARSE_PARAMETERS_START(0, 1)
2067+
Z_PARAM_OPTIONAL
2068+
Z_PARAM_LONG(mode)
2069+
ZEND_PARSE_PARAMETERS_END();
2070+
2071+
SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result)
2072+
2073+
nb_cols = sqlite3_column_count(result_obj->stmt_obj->stmt);
2074+
if (mode & PHP_SQLITE3_ASSOC) {
2075+
sqlite3result_clear_column_names_cache(result_obj);
2076+
result_obj->column_names = emalloc(nb_cols * sizeof(zend_string*));
2077+
2078+
for (i = 0; i < nb_cols; i++) {
2079+
const char *column = sqlite3_column_name(result_obj->stmt_obj->stmt, i);
2080+
result_obj->column_names[i] = zend_string_init(column, strlen(column), 0);
2081+
}
2082+
}
2083+
result_obj->column_count = nb_cols;
2084+
array_init(return_value);
2085+
2086+
while (!done) {
2087+
int step = sqlite3_step(result_obj->stmt_obj->stmt);
2088+
2089+
switch (step) {
2090+
case SQLITE_ROW: {
2091+
zval result;
2092+
array_init_size(&result, result_obj->column_count);
2093+
2094+
php_sqlite3_fetch_one(result_obj->column_count, result_obj, mode, &result);
2095+
2096+
add_next_index_zval(return_value, &result);
2097+
break;
2098+
}
2099+
case SQLITE_DONE:
2100+
done = true;
2101+
break;
2102+
default:
2103+
if (!EG(exception)) {
2104+
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)));
2105+
}
2106+
zval_ptr_dtor(return_value);
2107+
RETURN_FALSE;
2108+
}
2109+
}
2110+
}
2111+
20742112
/* {{{ Resets the result set back to the first row. */
20752113
PHP_METHOD(SQLite3Result, reset)
20762114
{
@@ -2429,6 +2467,29 @@ static void sqlite3_param_dtor(zval *data) /* {{{ */
24292467
}
24302468
/* }}} */
24312469

2470+
static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_result *result_obj, zend_long mode, zval *result)
2471+
{
2472+
for (int i = 0; i < n_cols; i ++) {
2473+
zval data;
2474+
sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data);
2475+
2476+
if (mode & PHP_SQLITE3_NUM) {
2477+
add_index_zval(result, i, &data);
2478+
}
2479+
2480+
if (mode & PHP_SQLITE3_ASSOC) {
2481+
if (mode & PHP_SQLITE3_NUM) {
2482+
if (Z_REFCOUNTED(data)) {
2483+
Z_ADDREF(data);
2484+
}
2485+
}
2486+
/* Note: we can't use the "add_new" variant here instead of "update" because
2487+
* when the same column name is encountered, the last result should be taken. */
2488+
zend_symtable_update(Z_ARR_P(result), result_obj->column_names[i], &data);
2489+
}
2490+
}
2491+
}
2492+
24322493
/* {{{ PHP_MINIT_FUNCTION */
24332494
PHP_MINIT_FUNCTION(sqlite3)
24342495
{

ext/sqlite3/sqlite3.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ public function columnType(int $column): int|false {}
302302
/** @tentative-return-type */
303303
public function fetchArray(int $mode = SQLITE3_BOTH): array|false {}
304304

305+
public function fetchAll(int $mode = SQLITE3_BOTH): array|false {}
306+
305307
/** @tentative-return-type */
306308
public function reset(): bool {}
307309

ext/sqlite3/sqlite3_arginfo.h

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
--TEST--
2+
SQLite3Result::fetchAll usage
3+
--EXTENSIONS--
4+
sqlite3
5+
--FILE--
6+
<?php
7+
$conn = new sqlite3(':memory:');
8+
$conn->query('CREATE TABLE users (id INTEGER NOT NULL, num INTEGER NOT NULL, PRIMARY KEY(id))');
9+
10+
$stmt = $conn->query('insert into users (id, num) values (1, 1)');
11+
$stmt = $conn->query('insert into users (id, num) values (2, 2)');
12+
13+
$stmt = $conn->query('SELECT * FROM users');
14+
$rowall = $stmt->fetchAll();
15+
var_dump($rowall);
16+
$stmt->reset();
17+
$rowfetch = [];
18+
while (($row = $stmt->fetchArray())) $rowfetch[] = $row;
19+
var_dump($rowfetch);
20+
var_dump($rowall == $rowfetch);
21+
$stmt->reset();
22+
var_dump($stmt->fetchAll(SQLITE3_NUM));
23+
$stmt->reset();
24+
var_dump($stmt->fetchAll(SQLITE3_ASSOC));
25+
26+
?>
27+
--EXPECT--
28+
array(2) {
29+
[0]=>
30+
array(4) {
31+
[0]=>
32+
int(1)
33+
["id"]=>
34+
int(1)
35+
[1]=>
36+
int(1)
37+
["num"]=>
38+
int(1)
39+
}
40+
[1]=>
41+
array(4) {
42+
[0]=>
43+
int(2)
44+
["id"]=>
45+
int(2)
46+
[1]=>
47+
int(2)
48+
["num"]=>
49+
int(2)
50+
}
51+
}
52+
array(2) {
53+
[0]=>
54+
array(4) {
55+
[0]=>
56+
int(1)
57+
["id"]=>
58+
int(1)
59+
[1]=>
60+
int(1)
61+
["num"]=>
62+
int(1)
63+
}
64+
[1]=>
65+
array(4) {
66+
[0]=>
67+
int(2)
68+
["id"]=>
69+
int(2)
70+
[1]=>
71+
int(2)
72+
["num"]=>
73+
int(2)
74+
}
75+
}
76+
bool(true)
77+
array(2) {
78+
[0]=>
79+
array(2) {
80+
[0]=>
81+
int(1)
82+
[1]=>
83+
int(1)
84+
}
85+
[1]=>
86+
array(2) {
87+
[0]=>
88+
int(2)
89+
[1]=>
90+
int(2)
91+
}
92+
}
93+
array(2) {
94+
[0]=>
95+
array(2) {
96+
["id"]=>
97+
int(1)
98+
["num"]=>
99+
int(1)
100+
}
101+
[1]=>
102+
array(2) {
103+
["id"]=>
104+
int(2)
105+
["num"]=>
106+
int(2)
107+
}
108+
}

0 commit comments

Comments
 (0)