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 37d4a4c78..391a1233e 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 @@ -5466,8 +5466,8 @@ private function translate_table_ref( WP_Parser_Node $node ): string { } } - $table_is_temporary = $this->information_schema_builder->temporary_table_exists( $table_name ); - $sqlite_table_name = $this->information_schema_builder->get_table_name( $table_is_temporary, $table_name ); + // Temporary tables are not listed in the information schema. + $sqlite_table_name = $this->information_schema_builder->get_table_name( false, $table_name ); // We need to fetch the SQLite column information, because the information // schema tables don't contain records for the information schema itself. diff --git a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php index 12b34be10..0b4540d37 100644 --- a/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php +++ b/packages/mysql-on-sqlite/src/sqlite/class-wp-sqlite-information-schema-builder.php @@ -381,12 +381,16 @@ public function temporary_table_exists( string $table_name ): bool { /* * We could search in the "{$this->temporary_table_prefix}tables" table, * but it may not exist yet, so using "sqlite_temp_master" is simpler. + * + * The name is matched case-insensitively, as it is in the information + * schema tables. The fetched value is not compared to a string, because + * PDO SQLite returns native types when fetches are not stringified. */ $stmt = $this->connection->query( - "SELECT 1 FROM sqlite_temp_master WHERE type = 'table' AND name = ?", + "SELECT 1 FROM sqlite_temp_master WHERE type = 'table' AND name = ? COLLATE NOCASE", array( $table_name ) ); - return $stmt->fetchColumn() === '1'; + return false !== $stmt->fetchColumn(); } /** 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 a5c927824..b81d767ec 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 @@ -5842,7 +5842,31 @@ public function getInformationSchemaIsReadonlyWithUseTestData(): array { ); } - public function testTemporaryTableHasPriorityOverStandardTable(): void { + public function testTemporaryTableIsFoundByDifferentlyCasedName(): void { + // Create a standard and a temporary table with the same name. + $this->assertQuery( 'CREATE TABLE t (a INT)' ); + $this->assertQuery( 'CREATE TEMPORARY TABLE t (b INT)' ); + + // ALTER TABLE will use the temporary table. + $this->assertQuery( 'ALTER TABLE T ADD COLUMN c INT' ); + $result = $this->assertQuery( 'SHOW COLUMNS FROM T' ); + $this->assertCount( 2, $result ); + $this->assertEquals( 'b', $result[0]->Field ); + $this->assertEquals( 'c', $result[1]->Field ); + + // DROP TABLE will remove the temporary table and keep the standard table. + $this->assertQuery( 'DROP TABLE T' ); + $result = $this->assertQuery( 'SHOW COLUMNS FROM T' ); + $this->assertCount( 1, $result ); + $this->assertEquals( 'a', $result[0]->Field ); + } + + /** + * @dataProvider stringifyFetchesProvider + */ + public function testTemporaryTableHasPriorityOverStandardTable( bool $stringify_fetches ): void { + $this->engine->setAttribute( PDO::ATTR_STRINGIFY_FETCHES, $stringify_fetches ); + // Create a standard and a temporary table with the same name. $this->assertQuery( 'CREATE TABLE t (a INT, INDEX ia(a))' ); $this->assertQuery( 'CREATE TEMPORARY TABLE t (b INT, INDEX ib(b))' ); @@ -5883,6 +5907,7 @@ public function testTemporaryTableHasPriorityOverStandardTable(): void { // First DROP TABLE removes the temporary table. $this->assertQuery( 'DROP TABLE t' ); $result = $this->assertQuery( 'SHOW COLUMNS FROM t' ); + $this->assertCount( 1, $result ); $this->assertEquals( 'a', $result[0]->Field ); // Second DROP TABLE removes the standard table. @@ -5892,6 +5917,38 @@ public function testTemporaryTableHasPriorityOverStandardTable(): void { $result = $this->assertQuery( 'SHOW COLUMNS FROM t' ); } + public function stringifyFetchesProvider(): array { + return array( + 'stringification disabled' => array( false ), + 'stringification enabled' => array( true ), + ); + } + + public function testTemporaryTableNamedLikeInformationSchemaTable(): void { + // Create a standard table and temporary tables named like information schema tables. + $this->assertQuery( 'CREATE TABLE t (a INT, INDEX ia(a))' ); + $this->assertQuery( 'CREATE TEMPORARY TABLE tables (b INT)' ); + $this->assertQuery( 'CREATE TEMPORARY TABLE COLUMNS (b INT)' ); + $this->assertQuery( 'CREATE TEMPORARY TABLE Statistics (b INT, INDEX ib(b))' ); + + // The information schema shows the standard table only. + $table_names = "('t', 'tables', 'columns', 'statistics')"; + + $result = $this->assertQuery( "SELECT table_name FROM information_schema.tables WHERE table_name IN $table_names" ); + $this->assertCount( 1, $result ); + $this->assertEquals( 't', $result[0]->TABLE_NAME ); + + $result = $this->assertQuery( "SELECT table_name, column_name FROM information_schema.columns WHERE table_name IN $table_names" ); + $this->assertCount( 1, $result ); + $this->assertEquals( 't', $result[0]->TABLE_NAME ); + $this->assertEquals( 'a', $result[0]->COLUMN_NAME ); + + $result = $this->assertQuery( "SELECT table_name, index_name FROM information_schema.statistics WHERE table_name IN $table_names" ); + $this->assertCount( 1, $result ); + $this->assertEquals( 't', $result[0]->TABLE_NAME ); + $this->assertEquals( 'ia', $result[0]->INDEX_NAME ); + } + public function testStrictSqlModeNullWithoutDefault(): void { $this->assertQuery( "SET SESSION sql_mode = 'STRICT_ALL_TABLES'" ); diff --git a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Translation_Tests.php b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Translation_Tests.php index 020f3adc9..ec24ac419 100644 --- a/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Translation_Tests.php +++ b/packages/mysql-on-sqlite/tests/WP_MySQL_On_SQLite_Translation_Tests.php @@ -2157,7 +2157,7 @@ private function assertQuery( $expected, string $query ): void { array_filter( $executed_queries, function ( $query ) { - return "SELECT 1 FROM sqlite_temp_master WHERE type = 'table' AND name = ?" !== $query; + return "SELECT 1 FROM sqlite_temp_master WHERE type = 'table' AND name = ? COLLATE NOCASE" !== $query; } ) );