@@ -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