Skip to content

Commit 24ecc7b

Browse files
authored
Fix incorrect column names for string literals without alias (#296)
It turns out that when selecting a string literal, the resulting column name differs between MySQL and SQLite. For example, with a query such as `SELECT 'abc'`: - In MySQL, the returned column name is `abc` (the unquoted string value). - In SQLite, the returned column name is `'abc'` (the quoted string). To address that, we need to use "SELECT 'abc' AS \`abc\`" in these cases.
2 parents 8bad00d + de10767 commit 24ecc7b

File tree

3 files changed

+18
-2
lines changed

3 files changed

+18
-2
lines changed

tests/WP_SQLite_Driver_Tests.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3738,7 +3738,7 @@ public function testHavingWithoutGroupBy() {
37383738
$this->assertEquals(
37393739
array(
37403740
(object) array(
3741-
"'T'" => 'T',
3741+
'T' => 'T',
37423742
),
37433743
),
37443744
$result

tests/WP_SQLite_Driver_Translation_Tests.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1680,7 +1680,7 @@ public function testSelectOrderByAmbiguousColumnResolution(): void {
16801680
// Test a complex query with CTEs.
16811681
$this->assertQuery(
16821682
'WITH'
1683-
. " `cte1` ( `name` ) AS ( SELECT 'a' UNION ALL SELECT 'b' ) ,"
1683+
. " `cte1` ( `name` ) AS ( SELECT 'a' AS `a` UNION ALL SELECT 'b' AS `b` ) ,"
16841684
. ' `cte2` ( `name` ) AS ( SELECT `t2`.`name` FROM `t2` JOIN `t1` ON `t1`.`id` = `t2`.`id` ORDER BY `t2`.`name` )'
16851685
. ' SELECT `t1`.`name` , ( SELECT `name` FROM `cte1` WHERE `id` = 1 ) AS `cte1_name` , ( SELECT `name` FROM `cte2` WHERE `id` = 2 ) AS `cte2_name`'
16861686
. ' FROM `t1`'

wp-includes/sqlite-ast/class-wp-sqlite-driver.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4246,6 +4246,22 @@ public function translate_select_item( WP_Parser_Node $node ): string {
42464246
return $item;
42474247
}
42484248

4249+
/*
4250+
* When the select item is a text string literal, we need to use an alias
4251+
* to ensure that the column name is the same as it would be in MySQL.
4252+
* In MySQL, the column name is the original text string literal value
4253+
* without quotes and escaping, but in SQLite, it is the quoted value.
4254+
*
4255+
* For example, for "SELECT 'abc'", the resulting column name is "abc"
4256+
* in MySQL, but would be "'abc'" in SQLite if an alias was not used.
4257+
*/
4258+
$text_string_literal = $node->get_first_descendant_node( 'textStringLiteral' );
4259+
$is_text_string_literal = $text_string_literal && $item === $this->translate( $text_string_literal );
4260+
if ( $is_text_string_literal ) {
4261+
$alias = $text_string_literal->get_first_child_token()->get_value();
4262+
return sprintf( '%s AS %s', $item, $this->quote_sqlite_identifier( $alias ) );
4263+
}
4264+
42494265
/*
42504266
* When the select item has no explicit alias, we need to ensure that the
42514267
* returned column name is equivalent to what MySQL infers from the input.

0 commit comments

Comments
 (0)