From cf51a687d42b6a213408c36234ae2887048076c8 Mon Sep 17 00:00:00 2001 From: Samuel de Rougemont Date: Mon, 12 Oct 2026 19:10:27 +0200 Subject: [PATCH 1/2] Fix FOUND_ROWS() for more than nine rows without SQL_CALC_FOUND_ROWS After a SELECT without SQL_CALC_FOUND_ROWS or after a SHOW statement, FOUND_ROWS() counts the rows of the previous query. The count was read with fetchColumn()[0], which takes the first character of a stringified count, so FOUND_ROWS() returned "1" for 12 rows. Without stringified fetches, indexing the integer count returned null, and the result was 0. Use the fetched count directly. Co-Authored-By: Claude Opus 5.5 --- .../src/sqlite/class-wp-mysql-on-sqlite.php | 4 ++-- .../tests/WP_MySQL_On_SQLite_Tests.php | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php index 5b053ea89..5c31f6bf4 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-mysql-on-sqlite.php @@ -5169,12 +5169,12 @@ private function translate_function_call( WP_Parser_Node $node ): string { } elseif ( is_string( $found_rows ) ) { return (int) $this->execute_sqlite_query( sprintf( 'SELECT COUNT(*) FROM (%s)', $found_rows ) - )->fetchColumn()[0]; + )->fetchColumn(); } elseif ( is_array( $found_rows ) && isset( $found_rows[0] ) ) { return (int) $this->execute_sqlite_query( sprintf( 'SELECT COUNT(*) FROM (%s)', $found_rows[0] ), $found_rows[1] ?? array() - )->fetchColumn()[0]; + )->fetchColumn(); } else { return 0; } diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php index 3f1a57e6c..981ceca07 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php @@ -4186,6 +4186,24 @@ public function testCalcFoundRows() { ); } + public function testFoundRowsWithoutSqlCalcFoundRowsAboveNine(): void { + $this->assertQuery( 'CREATE TABLE t (id INT)' ); + $this->assertQuery( 'INSERT INTO t (id) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)' ); + for ( $i = 1; $i <= 10; $i++ ) { + $this->assertQuery( "CREATE TABLE t$i (id INT)" ); + } + + // SELECT + $this->assertQuery( 'SELECT * FROM t' ); + $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); + $this->assertSame( '12', $result[0]->{'FOUND_ROWS()'} ); + + // SHOW TABLES ("_dates", "_options", "t", and "t1" to "t10") + $this->assertQuery( 'SHOW TABLES' ); + $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); + $this->assertSame( '13', $result[0]->{'FOUND_ROWS()'} ); + } + public function testFoundRowsWithoutSqlCalcFoundRows(): void { $this->assertQuery( 'DROP TABLE _dates' ); $this->assertQuery( 'DROP TABLE _options' ); From 3bed95e76799394241f32d19f7648ffdde5295de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jakes=CC=8C?= Date: Wed, 14 Oct 2026 16:05:49 +0200 Subject: [PATCH 2/2] Test FOUND_ROWS() with two-digit counts and without stringified fetches Fold the separate above-nine test into testFoundRowsWithoutSqlCalcFoundRows. The SELECT and SHOW TABLES checks now return 12 and 11 rows, which covers both the query and the query-with-params paths. The test no longer counts the setUp fixture tables, as the existing test drops them. Run the test with stringified fetches on and off. Without stringification, the old code returned 0 and emitted a warning. --- .../tests/WP_MySQL_On_SQLite_Tests.php | 58 ++++++++----------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php index 981ceca07..659d38b1d 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Tests.php @@ -4186,97 +4186,87 @@ public function testCalcFoundRows() { ); } - public function testFoundRowsWithoutSqlCalcFoundRowsAboveNine(): void { - $this->assertQuery( 'CREATE TABLE t (id INT)' ); - $this->assertQuery( 'INSERT INTO t (id) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)' ); - for ( $i = 1; $i <= 10; $i++ ) { - $this->assertQuery( "CREATE TABLE t$i (id INT)" ); - } - - // SELECT - $this->assertQuery( 'SELECT * FROM t' ); - $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '12', $result[0]->{'FOUND_ROWS()'} ); - - // SHOW TABLES ("_dates", "_options", "t", and "t1" to "t10") - $this->assertQuery( 'SHOW TABLES' ); - $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '13', $result[0]->{'FOUND_ROWS()'} ); - } + /** + * @dataProvider stringifyFetchesProvider + */ + public function testFoundRowsWithoutSqlCalcFoundRows( bool $stringify_fetches ): void { + $this->engine->setAttribute( PDO::ATTR_STRINGIFY_FETCHES, $stringify_fetches ); - public function testFoundRowsWithoutSqlCalcFoundRows(): void { $this->assertQuery( 'DROP TABLE _dates' ); $this->assertQuery( 'DROP TABLE _options' ); // CREATE TABLE $this->assertQuery( 'CREATE TABLE t (id INT PRIMARY KEY, value TEXT, INDEX idx_value (value))' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '0', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 0, $result[0]->{'FOUND_ROWS()'} ); // INSERT - $this->assertQuery( 'INSERT INTO t (id) VALUES (1), (2), (3)' ); + $this->assertQuery( 'INSERT INTO t (id) VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '0', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 0, $result[0]->{'FOUND_ROWS()'} ); // SELECT $this->assertQuery( 'SELECT * FROM t' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '3', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 12, $result[0]->{'FOUND_ROWS()'} ); // DESCRIBE $this->assertQuery( 'DESCRIBE t' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '2', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 2, $result[0]->{'FOUND_ROWS()'} ); // SHOW COLLATION $this->assertQuery( 'SHOW COLLATION' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '8', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 8, $result[0]->{'FOUND_ROWS()'} ); // SHOW DATABASES $this->assertQuery( 'SHOW DATABASES' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '2', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 2, $result[0]->{'FOUND_ROWS()'} ); // SHOW COLUMNS $this->assertQuery( 'SHOW COLUMNS FROM t' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '2', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 2, $result[0]->{'FOUND_ROWS()'} ); // SHOW CREATE TABLE $this->assertQuery( 'SHOW CREATE TABLE t' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '1', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 1, $result[0]->{'FOUND_ROWS()'} ); // SHOW CREATE TABLE with non-existent table $this->assertQuery( 'SHOW CREATE TABLE non_existent_table' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '0', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 0, $result[0]->{'FOUND_ROWS()'} ); // SHOW INDEX $this->assertQuery( 'SHOW INDEX FROM t' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '2', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 2, $result[0]->{'FOUND_ROWS()'} ); // SHOW GRANTS $this->assertQuery( 'SHOW GRANTS' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '1', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 1, $result[0]->{'FOUND_ROWS()'} ); // SHOW TABLE STATUS $r = $this->assertQuery( 'SHOW TABLE STATUS' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '1', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 1, $result[0]->{'FOUND_ROWS()'} ); - // SHOW TABLES + // SHOW TABLES (with a two-digit count) + for ( $i = 1; $i <= 10; $i++ ) { + $this->assertQuery( "CREATE TABLE t$i (id INT)" ); + } $this->assertQuery( 'SHOW TABLES' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '1', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 11, $result[0]->{'FOUND_ROWS()'} ); // SHOW VARIABLES $this->assertQuery( 'SHOW VARIABLES' ); $result = $this->assertQuery( 'SELECT FOUND_ROWS()' ); - $this->assertSame( '2', $result[0]->{'FOUND_ROWS()'} ); + $this->assertEquals( 2, $result[0]->{'FOUND_ROWS()'} ); } public function testComplexSelectBasedOnDates() {