diff --git a/ext/sqlite3/php_sqlite3_structs.h b/ext/sqlite3/php_sqlite3_structs.h index 15cb8a8cb303d..847228eddf32a 100644 --- a/ext/sqlite3/php_sqlite3_structs.h +++ b/ext/sqlite3/php_sqlite3_structs.h @@ -106,6 +106,11 @@ struct _php_sqlite3_result_object { php_sqlite3_db_object *db_obj; php_sqlite3_stmt *stmt_obj; zval stmt_obj_zval; + + /* START */ + /* Store the last step error code from Sqlite3::query(), SQlite3Stmt::execute() to passe it to SQLite3Result::fetchArray() */ + int last_error; + /* END */ /* Cache of column names to speed up repeated fetchArray(SQLITE3_ASSOC) calls. * Cache is cleared on reset() and finalize() calls. */ diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index f06d373c56f09..91b1cb5c3f209 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -591,6 +591,10 @@ PHP_METHOD(SQLite3, query) ZVAL_OBJ(&result->stmt_obj_zval, Z_OBJ(stmt)); return_code = sqlite3_step(result->stmt_obj->stmt); + /* START */ + /* Copy step error code in result struct to pass it to SQLite3Result::fetcharray() */ + result->last_error = return_code; + /* END */ switch (return_code) { case SQLITE_ROW: /* Valid Row */ @@ -601,7 +605,11 @@ PHP_METHOD(SQLite3, query) free_item->stmt_obj = stmt_obj; free_item->stmt_obj_zval = stmt; zend_llist_add_element(&(db_obj->free_list), &free_item); - sqlite3_reset(result->stmt_obj->stmt); + /* START */ + /* Main problem. This resets the query and forces SQLite3Result::fetcharray() to execute it again */ + /* So we have to disable it to avoid a double execution of the query */ + /*sqlite3_reset(result->stmt_obj->stmt);*/ + /* END */ break; } default: @@ -1787,7 +1795,10 @@ PHP_METHOD(SQLite3Stmt, execute) case SQLITE_ROW: /* Valid Row */ case SQLITE_DONE: /* Valid but no results */ { - sqlite3_reset(stmt_obj->stmt); + /* START */ + /* Main problem. This resets the query and forces SQLite3Result::fetcharray() to execute it again */ + /*sqlite3_reset(stmt_obj->stmt);*/ + /* END */ object_init_ex(return_value, php_sqlite3_result_entry); result = Z_SQLITE3_RESULT_P(return_value); @@ -1796,6 +1807,10 @@ PHP_METHOD(SQLite3Stmt, execute) result->stmt_obj = stmt_obj; result->column_names = NULL; result->column_count = -1; + /* START */ + /* Do not reset the query just pass the step error code in 'result' struct to SQLite3Result::fetcharray() */ + result->last_error = return_code; + /* END */ ZVAL_OBJ_COPY(&result->stmt_obj_zval, Z_OBJ_P(object)); break; @@ -1941,7 +1956,17 @@ PHP_METHOD(SQLite3Result, fetchArray) SQLITE3_CHECK_INITIALIZED(result_obj->db_obj, result_obj->stmt_obj->initialised, SQLite3Result) - ret = sqlite3_step(result_obj->stmt_obj->stmt); + /* START */ + /* Get result code stored in 'result_obj' struct, initialized by Sqlite3::query(), SQLite3Stmt::execute() */ + /* The first time we call SQLite3Result->fetchArray(), skip step and process the step result of Sqlite3::query() or SQLite3Stmt::execute() */ + /* The first time we call SQLite3Result->fetchArray(), the step result stored in 'last_error' can only be SQLITE_ROW or SQLITE_DONE */ + /* From the second call to SQLite3Result->fetchArray() onwards, 'last_error' will be -1 and therefore step will be executed */ + ret = result_obj->last_error; + if (ret == -1) { + ret = sqlite3_step(result_obj->stmt_obj->stmt); + } + /* END */ + switch (ret) { case SQLITE_ROW: /* If there was no return value then just skip fetching */ @@ -1985,6 +2010,12 @@ PHP_METHOD(SQLite3Result, fetchArray) zend_symtable_add_new(Z_ARR_P(return_value), result_obj->column_names[i], &data); } } + + /* START */ + /* Intialize to -1 so on the second call to SQLite3Result->fetchArray() onwards, step is executed */ + result_obj->last_error = -1; + /* END */ + break; case SQLITE_DONE: