Bug #64531 [PATCH]: SQLite3Result::fetchArray runs the query again.

From: Date: Mon, 24 Feb 2020 11:56:59 +0000
Subject: Bug #64531 [PATCH]: SQLite3Result::fetchArray runs the query again.
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-225688@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=64531&edit=1

 ID:                 64531
 Patch added by:     cmb@php.net
 Reported by:        phplists at stanvassilev dot com
 Summary:            SQLite3Result::fetchArray runs the query again.
 Status:             Verified
 Type:               Bug
 Package:            SQLite related
 Operating System:   Windows XP SP3 32bit
 PHP Version:        5.4.13
 Block user comment: N
 Private report:     N

 New Comment:

The following pull request has been associated:

Patch Name: [POC] Fix #64531: SQLite3Result::fetchArray runs the query again
On GitHub:  https://github.com/php/php-src/pull/5204
Patch:      https://github.com/php/php-src/pull/5204.patch


Previous Comments:
------------------------------------------------------------------------
[2020-02-01 00:13:34] antoni at friki dot cat

The following patch has been added/updated:

Patch Name: fix64531-sqlite3-fetchArray-skipNoColumns
Revision:   1580516014
URL:        https://bugs.php.net/patch-display.php?bug=64531&patch=fix64531-sqlite3-fetchArray-skipNoColumns&revision=1580516014

------------------------------------------------------------------------
[2020-01-31 23:23:44] antoni at friki dot cat

I think that small patch should fix most problems on fetchArray() usage.
It's not a breaking change as no one expects re-run insert/update/create statements using a
function to acquire a row of data. IMAO

--- php-7.4.2/ext/sqlite3/sqlite3.c	2020-01-21 12:35:21.000000000 +0100
+++ php-7.4.2-sqlite3fixed2/ext/sqlite3/sqlite3.c	2020-01-31 23:37:17.449123405 +0100
@@ -2007,6 +2007,10 @@ PHP_METHOD(sqlite3result, fetchArray)
 		return;
 	}
 
+	if (sqlite3_column_count(result_obj->stmt_obj->stmt) == 0) {
+                return;
+        }
+
 	ret = sqlite3_step(result_obj->stmt_obj->stmt);
 	switch (ret) {
 		case SQLITE_ROW:

------------------------------------------------------------------------
[2020-01-31 22:20:19] antoni at friki dot cat

Here an PHP example reproducing the weird issue.

Find some commented out alternatives to avoid problems with current php-sqlite3 implementation:
  https://pastebin.com/kCvb65FH

The key point using current SQLite3 version is not to call sqlite3_step() on a statement if previous
sqlite3_step() over same statement returned !=SQLITE_ROW.

The key point using current PHP version is not to call fetchArray() on query/execute $result. Using
if numColumns()!==0 you can figure out if you want to run fetchArray() data after execute()/query().

Regards,

------------------------------------------------------------------------
[2020-01-31 21:20:35] antoni at friki dot cat

Hi,

today I've faced that problem.

Here my patch:
--- php-7.4.2/ext/sqlite3/sqlite3.c	2020-01-21 12:35:21.000000000 +0100
+++ php-7.4.2-sqlite3fixed/ext/sqlite3/sqlite3.c	2020-01-31 22:12:56.599653191 +0100
@@ -612,8 +612,11 @@
 	return_code = sqlite3_step(result->stmt_obj->stmt);
 
 	switch (return_code) {
-		case SQLITE_ROW: /* Valid Row */
 		case SQLITE_DONE: /* Valid but no results */
+                {
+			result->complete = 1;
+                }
+		case SQLITE_ROW: /* Valid Row */
 		{
 			php_sqlite3_free_list *free_item;
 			free_item = emalloc(sizeof(php_sqlite3_free_list));
@@ -624,6 +627,7 @@
 			break;
 		}
 		default:
+			result->complete = 1;
 			if (!EG(exception)) {
 				php_sqlite3_error(db_obj, "Unable to execute statement: %s",
sqlite3_errmsg(db_obj->db));
 			}
@@ -713,6 +717,9 @@
 	return_code = sqlite3_step(stmt);
 
 	switch (return_code) {
+	        php_sqlite3_result *result_obj;
+	        zval *object = ZEND_THIS;
+	        result_obj = Z_SQLITE3_RESULT_P(object);
 		case SQLITE_ROW: /* Valid Row */
 		{
 			if (!entire_row) {
@@ -730,6 +737,8 @@
 		}
 		case SQLITE_DONE: /* Valid but no results */
 		{
+			result_obj->complete = 1;
+
 			if (!entire_row) {
 				RETVAL_NULL();
 			} else {
@@ -738,10 +747,12 @@
 			break;
 		}
 		default:
-		if (!EG(exception)) {
-			php_sqlite3_error(db_obj, "Unable to execute statement: %s",
sqlite3_errmsg(db_obj->db));
-		}
-		RETVAL_FALSE;
+		        result_obj->complete = 1;
+
+		        if (!EG(exception)) {
+		        	php_sqlite3_error(db_obj, "Unable to execute statement: %s",
sqlite3_errmsg(db_obj->db));
+		        }
+		        RETVAL_FALSE;
 	}
 	sqlite3_finalize(stmt);
 }
@@ -1844,14 +1855,16 @@
 
 	return_code = sqlite3_step(stmt_obj->stmt);
 
+	sqlite3_reset(stmt_obj->stmt);
+	object_init_ex(return_value, php_sqlite3_result_entry);
+	result = Z_SQLITE3_RESULT_P(return_value);
 	switch (return_code) {
-		case SQLITE_ROW: /* Valid Row */
 		case SQLITE_DONE: /* Valid but no results */
+                {
+			result->complete = 1;
+                }
+		case SQLITE_ROW: /* Valid Row */
 		{
-			sqlite3_reset(stmt_obj->stmt);
-			object_init_ex(return_value, php_sqlite3_result_entry);
-			result = Z_SQLITE3_RESULT_P(return_value);
-
 			result->is_prepared_statement = 1;
 			result->db_obj = stmt_obj->db_obj;
 			result->stmt_obj = stmt_obj;
@@ -1861,9 +1874,11 @@
 			break;
 		}
 		case SQLITE_ERROR:
+			result->complete = 1;
 			sqlite3_reset(stmt_obj->stmt);
 
 		default:
+			result->complete = 1;
 			if (!EG(exception)) {
 				php_sqlite3_error(stmt_obj->db_obj, "Unable to execute statement: %s",
sqlite3_errmsg(sqlite3_db_handle(stmt_obj->stmt)));
 			}
@@ -1939,6 +1954,10 @@
 		return;
 	}
 
+	if (result_obj->complete) {
+		RETURN_FALSE;
+	}
+
 	RETURN_LONG(sqlite3_column_count(result_obj->stmt_obj->stmt));
 }
 /* }}} */
@@ -1958,6 +1977,11 @@
 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &column) == FAILURE) {
 		return;
 	}
+
+	if (result_obj->complete) {
+		RETURN_FALSE;
+	}
+
 	column_name = (char*) sqlite3_column_name(result_obj->stmt_obj->stmt, column);
 
 	if (column_name == NULL) {
@@ -2007,6 +2031,10 @@
 		return;
 	}
 
+        if (result_obj->complete==1) {
+		return;
+        }
+
 	ret = sqlite3_step(result_obj->stmt_obj->stmt);
 	switch (ret) {
 		case SQLITE_ROW:
@@ -2043,6 +2071,7 @@
 			break;
 
 		default:
+			result_obj->complete = 1;
 			php_sqlite3_error(result_obj->db_obj, "Unable to execute statement: %s",
sqlite3_errmsg(sqlite3_db_handle(result_obj->stmt_obj->stmt)));
 	}
 }

------------------------------------------------------------------------
[2019-11-11 13:17:01] cmb@php.net

Related To: Bug #77977

------------------------------------------------------------------------


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    https://bugs.php.net/bug.php?id=64531


--
Edit this bug report at https://bugs.php.net/bug.php?id=64531&edit=1


Thread (16 messages)

« previous php.bugs (#225688) next »