Skip to content

Commit 168da62

Browse files
committed
wip
1 parent e46ad75 commit 168da62

File tree

2 files changed

+100
-25
lines changed

2 files changed

+100
-25
lines changed

tests/WP_SQLite_Driver_Tests.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11238,4 +11238,15 @@ public function testVersionFunction(): void {
1123811238
$result = $this->engine->query( 'SELECT VERSION()' );
1123911239
$this->assertSame( '8.0.38', $result[0]->{'VERSION()'} );
1124011240
}
11241+
11242+
public function testResultColumnNameCase(): void {
11243+
$this->assertQuery( 'CREATE TABLE t (id INT)' );
11244+
$this->assertQuery( 'INSERT INTO t (id) VALUES (1)' );
11245+
11246+
$result = $this->assertQuery( 'SELECT ID FROM t' );
11247+
$this->assertEquals( (object) array( 'ID' => 1 ), $result[0] );
11248+
11249+
$result = $this->assertQuery( 'SELECT id FROM (SELECT * FROM t) x JOIN information_schema.tables it ON TRUE LIMIT 1' );
11250+
$this->assertEquals( (object) array( 'id' => 1 ), $result[0] );
11251+
}
1124111252
}

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

Lines changed: 89 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3250,8 +3250,6 @@ private function translate( $node ): ?string {
32503250
throw $this->new_not_supported_exception(
32513251
sprintf( 'data type: %s', $child->get_value() )
32523252
);
3253-
case 'selectItem':
3254-
return $this->translate_select_item( $node );
32553253
case 'fromClause':
32563254
// FROM DUAL is MySQL-specific syntax that means "FROM no tables"
32573255
// and it is equivalent to omitting the FROM clause entirely.
@@ -3678,9 +3676,52 @@ private function translate_query_expression( WP_Parser_Node $node ): string {
36783676
* @return string|null
36793677
*/
36803678
private function translate_query_specification( WP_Parser_Node $node ): string {
3679+
$from = $node->get_first_child_node( 'fromClause' );
36813680
$group_by = $node->get_first_child_node( 'groupByClause' );
36823681
$having = $node->get_first_child_node( 'havingClause' );
36833682

3683+
$table_reference_list = $from ? $from->get_first_child_node( 'tableReferenceList' ) : null;
3684+
if ( $table_reference_list ) {
3685+
$table_reference_map = $this->create_table_reference_map( $table_reference_list );
3686+
}
3687+
var_dump($table_reference_map);
3688+
3689+
// Check if there is an information schema used in FROM or JOIN clauses.
3690+
$information_schema_table_columns_map = array();
3691+
foreach ( $table_reference_map ?? array() as $table_data ) {
3692+
if (
3693+
null === $table_data['database']
3694+
|| 'information_schema' !== strtolower( $table_data['database'] )
3695+
) {
3696+
continue;
3697+
}
3698+
3699+
$table_name = strtoupper( $table_data['table_name'] );
3700+
if ( 'character_sets' === $table_name ) {
3701+
$information_schema_table_columns_map['CHARACTER_SET_NAME'] = true;
3702+
$information_schema_table_columns_map['DEFAULT_COLLATE_NAME'] = true;
3703+
$information_schema_table_columns_map['DESCRIPTION'] = true;
3704+
$information_schema_table_columns_map['MAXLEN'] = true;
3705+
} elseif ( 'collations' === $table_name ) {
3706+
$information_schema_table_columns_map['COLLATION_NAME'] = true;
3707+
$information_schema_table_columns_map['CHARACTER_SET_NAME'] = true;
3708+
$information_schema_table_columns_map['ID'] = true;
3709+
$information_schema_table_columns_map['IS_DEFAULT'] = true;
3710+
$information_schema_table_columns_map['IS_COMPILED'] = true;
3711+
$information_schema_table_columns_map['SORTLEN'] = true;
3712+
$information_schema_table_columns_map['PAD_ATTRIBUTE'] = true;
3713+
} else {
3714+
$columns = $this->execute_sqlite_query(
3715+
'SELECT name FROM pragma_table_info(?)',
3716+
array( $this->information_schema_builder->get_table_name( false, $table_name ) )
3717+
)->fetchAll( PDO::FETCH_COLUMN );
3718+
3719+
foreach ( $columns as $column ) {
3720+
$information_schema_table_columns_map[ $column ] = $column;
3721+
}
3722+
}
3723+
}
3724+
36843725
/*
36853726
* When the GROUP BY or HAVING clause is present, we need to disambiguate
36863727
* the items to ensure they don't cause an "ambiguous column name" error.
@@ -3729,30 +3770,43 @@ private function translate_query_specification( WP_Parser_Node $node ): string {
37293770
}
37303771
$having_clause = 'HAVING ' . implode( ' ', $disambiguated_having_list );
37313772
}
3773+
}
37323774

3733-
// Translate the query specification, replacing the ORDER BY/HAVING
3734-
// items with the ones that were disambiguated using the SELECT list.
3735-
$parts = array();
3736-
foreach ( $node->get_children() as $child ) {
3737-
if ( $child instanceof WP_Parser_Node && 'groupByClause' === $child->rule_name ) {
3738-
$parts[] = $group_by_clause;
3739-
} elseif ( $child instanceof WP_Parser_Node && 'havingClause' === $child->rule_name ) {
3740-
// SQLite doesn't allow using the "HAVING" clause without "GROUP BY".
3741-
// In such cases, let's prefix the "HAVING" clause with "GROUP BY 1".
3742-
if ( ! $group_by ) {
3743-
$parts[] = 'GROUP BY 1';
3744-
}
3745-
$parts[] = $having_clause;
3746-
} else {
3747-
$part = $this->translate( $child );
3748-
if ( null !== $part ) {
3749-
$parts[] = $part;
3775+
// Translate the query specification, replacing the ORDER BY/HAVING
3776+
// items with the ones that were disambiguated using the SELECT list.
3777+
$parts = array();
3778+
foreach ( $node->get_children() as $child ) {
3779+
if ( $child instanceof WP_Parser_Node && 'selectItemList' === $child->rule_name ) {
3780+
$items = array();
3781+
foreach ( $child->get_children() as $select_item ) {
3782+
if ( $select_item instanceof WP_MySQL_Token ) {
3783+
if ( WP_MySQL_Lexer::COMMA_SYMBOL === $select_item->id ) {
3784+
continue;
3785+
} else {
3786+
$items[] = $this->translate( $select_item );
3787+
}
3788+
} else {
3789+
$items[] = $this->translate_select_item( $select_item, $information_schema_table_columns_map );
37503790
}
37513791
}
3792+
$parts[] = implode( ', ', $items );
3793+
} elseif ( $child instanceof WP_Parser_Node && 'groupByClause' === $child->rule_name ) {
3794+
$parts[] = $group_by_clause;
3795+
} elseif ( $child instanceof WP_Parser_Node && 'havingClause' === $child->rule_name ) {
3796+
// SQLite doesn't allow using the "HAVING" clause without "GROUP BY".
3797+
// In such cases, let's prefix the "HAVING" clause with "GROUP BY 1".
3798+
if ( ! $group_by ) {
3799+
$parts[] = 'GROUP BY 1';
3800+
}
3801+
$parts[] = $having_clause;
3802+
} else {
3803+
$part = $this->translate( $child );
3804+
if ( null !== $part ) {
3805+
$parts[] = $part;
3806+
}
37523807
}
3753-
return implode( ' ', $parts );
37543808
}
3755-
return $this->translate_sequence( $node->get_children() );
3809+
return implode( ' ', $parts );
37563810
}
37573811

37583812
/**
@@ -4063,7 +4117,7 @@ private function translate_datetime_literal( string $value ): string {
40634117
* @param WP_Parser_Node $node The "selectItem" AST node.
40644118
* @return string The translated expression.
40654119
*/
4066-
public function translate_select_item( WP_Parser_Node $node ): string {
4120+
public function translate_select_item( WP_Parser_Node $node, array $information_schema_table_columns_map = array() ): string {
40674121
/*
40684122
* First, let's translate the select item subtree.
40694123
*
@@ -4097,7 +4151,13 @@ public function translate_select_item( WP_Parser_Node $node ): string {
40974151
$column_ref = $node->get_first_descendant_node( 'columnRef' );
40984152
$is_column_ref = $column_ref && $item === $this->translate( $column_ref );
40994153
if ( $is_column_ref ) {
4100-
return $item;
4154+
$identifiers = $column_ref->get_descendant_nodes( 'identifier' );
4155+
$column_name = $this->unquote_sqlite_identifier( $this->translate( end( $identifiers ) ) );
4156+
if ( isset( $information_schema_table_columns_map[ strtoupper( $column_name ) ] ) ) {
4157+
return $item;
4158+
}
4159+
4160+
$node = end( $identifiers );
41014161
}
41024162

41034163
/*
@@ -4115,8 +4175,9 @@ public function translate_select_item( WP_Parser_Node $node ): string {
41154175
if ( $alias === $item || $raw_alias === $item ) {
41164176
// For the simple case of selecting only columns ("SELECT id FROM t"),
41174177
// let's avoid unnecessary aliases ("SELECT `id` AS `id` FROM t").
4118-
return $item;
4178+
//return $item;
41194179
}
4180+
var_dump(sprintf( '%s AS %s', $item, $alias ));
41204181
return sprintf( '%s AS %s', $item, $alias );
41214182
}
41224183

@@ -5035,9 +5096,12 @@ private function create_table_reference_map( WP_Parser_Node $node ): array {
50355096
$alias_node = $child->get_first_child_node( 'tableAlias' );
50365097
$alias = $alias_node ? $this->translate( $alias_node->get_first_child_node( 'identifier' ) ) : null;
50375098

5099+
$identifiers = $table_ref->get_descendant_nodes( 'identifier' );
5100+
$name =$this->unquote_sqlite_identifier( $this->translate( end( $identifiers ) ) );
5101+
50385102
$table_map[ $this->unquote_sqlite_identifier( $alias ?? $name ) ] = array(
50395103
'database' => $this->get_database_name( $table_ref ),
5040-
'table_name' => $this->unquote_sqlite_identifier( $name ),
5104+
'table_name' => $name,
50415105
'table_expr' => null,
50425106
'join_expr' => $this->translate( $join_expr ),
50435107
);

0 commit comments

Comments
 (0)