diff --git a/tests/WP_SQLite_Driver_Tests.php b/tests/WP_SQLite_Driver_Tests.php index 542c5ea2..94839437 100644 --- a/tests/WP_SQLite_Driver_Tests.php +++ b/tests/WP_SQLite_Driver_Tests.php @@ -3799,7 +3799,7 @@ public function testHavingWithoutGroupBy() { $this->assertEquals( array( (object) array( - "'T'" => 'T', + 'T' => 'T', ), ), $result diff --git a/tests/WP_SQLite_Driver_Translation_Tests.php b/tests/WP_SQLite_Driver_Translation_Tests.php index 59ec6b53..83f7717d 100644 --- a/tests/WP_SQLite_Driver_Translation_Tests.php +++ b/tests/WP_SQLite_Driver_Translation_Tests.php @@ -1680,7 +1680,7 @@ public function testSelectOrderByAmbiguousColumnResolution(): void { // Test a complex query with CTEs. $this->assertQuery( 'WITH' - . " `cte1` ( `name` ) AS ( SELECT 'a' UNION ALL SELECT 'b' ) ," + . " `cte1` ( `name` ) AS ( SELECT 'a' AS `a` UNION ALL SELECT 'b' AS `b` ) ," . ' `cte2` ( `name` ) AS ( SELECT `t2`.`name` FROM `t2` JOIN `t1` ON `t1`.`id` = `t2`.`id` ORDER BY `t2`.`name` )' . ' SELECT `t1`.`name` , ( SELECT `name` FROM `cte1` WHERE `id` = 1 ) AS `cte1_name` , ( SELECT `name` FROM `cte2` WHERE `id` = 2 ) AS `cte2_name`' . ' FROM `t1`' diff --git a/wp-includes/sqlite-ast/class-wp-sqlite-driver.php b/wp-includes/sqlite-ast/class-wp-sqlite-driver.php index 3a9c13e6..835cc778 100644 --- a/wp-includes/sqlite-ast/class-wp-sqlite-driver.php +++ b/wp-includes/sqlite-ast/class-wp-sqlite-driver.php @@ -4100,6 +4100,22 @@ public function translate_select_item( WP_Parser_Node $node ): string { return $item; } + /* + * When the select item is a text string literal, we need to use an alias + * to ensure that the column name is the same as it would be in MySQL. + * In MySQL, the column name is the original text string literal value + * without quotes and escaping, but in SQLite, it is the quoted value. + * + * For example, for "SELECT 'abc'", the resulting column name is "abc" + * in MySQL, but would be "'abc'" in SQLite if an alias was not used. + */ + $text_string_literal = $node->get_first_descendant_node( 'textStringLiteral' ); + $is_text_string_literal = $text_string_literal && $item === $this->translate( $text_string_literal ); + if ( $is_text_string_literal ) { + $alias = $text_string_literal->get_first_child_token()->get_value(); + return sprintf( '%s AS %s', $item, $this->quote_sqlite_identifier( $alias ) ); + } + /* * When the select item has no explicit alias, we need to ensure that the * returned column name is equivalent to what MySQL infers from the input.