@@ -1637,7 +1637,30 @@ private function translate( $node ): ?string {
16371637 return implode ( ' ' , $ parts );
16381638 }
16391639 return $ this ->translate_sequence ( $ node ->get_children () );
1640+ case 'schemaRef ' :
1641+ return $ this ->translate_schema_identifier ( $ node );
16401642 case 'qualifiedIdentifier ' :
1643+ case 'tableRefWithWildcard ' :
1644+ $ parts = $ node ->get_descendant_nodes ( 'identifier ' );
1645+ if ( count ( $ parts ) === 2 ) {
1646+ return $ this ->translate_qualified_identifier ( $ parts [0 ], $ parts [1 ] );
1647+ }
1648+ return $ this ->translate_qualified_identifier ( null , $ parts [0 ] );
1649+ case 'fieldIdentifier ' :
1650+ case 'simpleIdentifier ' :
1651+ $ parts = $ node ->get_descendant_nodes ( 'identifier ' );
1652+ if ( count ( $ parts ) === 3 ) {
1653+ return $ this ->translate_qualified_identifier ( $ parts [0 ], $ parts [1 ], $ parts [2 ] );
1654+ } elseif ( count ( $ parts ) === 2 ) {
1655+ return $ this ->translate_qualified_identifier ( null , $ parts [0 ], $ parts [1 ] );
1656+ }
1657+ return $ this ->translate_qualified_identifier ( null , null , $ parts [0 ] );
1658+ case 'tableWild ' :
1659+ $ parts = $ node ->get_descendant_nodes ( 'identifier ' );
1660+ if ( count ( $ parts ) === 2 ) {
1661+ return $ this ->translate_qualified_identifier ( $ parts [0 ], $ parts [1 ] ) . '.* ' ;
1662+ }
1663+ return $ this ->translate_qualified_identifier ( null , $ parts [0 ] ) . '.* ' ;
16411664 case 'dotIdentifier ' :
16421665 return $ this ->translate_sequence ( $ node ->get_children (), '' );
16431666 case 'identifierKeyword ' :
@@ -1904,6 +1927,60 @@ private function translate_pure_identifier( WP_Parser_Node $node ): string {
19041927 return '` ' . str_replace ( '` ' , '`` ' , $ value ) . '` ' ;
19051928 }
19061929
1930+ /**
1931+ * Translate a qualified MySQL identifier to SQLite.
1932+ *
1933+ * The identifier can be composed of 1 to 3 parts (schema, object, child).
1934+ *
1935+ * @param WP_Parser_Node|null $schema_node An identifier node representing a schema name (database).
1936+ * @param WP_Parser_Node|null $object_node An identifier node representing a database-level object name
1937+ * (table, view, procedure, trigger, etc.).
1938+ * @param WP_Parser_Node|null $child_node An identifier node representing an object child name (column, index, etc.).
1939+ * @return string The translated value.
1940+ * @throws WP_SQLite_Driver_Exception When the translation fails.
1941+ */
1942+ private function translate_qualified_identifier (
1943+ ?WP_Parser_Node $ schema_node ,
1944+ ?WP_Parser_Node $ object_node = null ,
1945+ ?WP_Parser_Node $ child_node = null
1946+ ): string {
1947+ $ parts = array ();
1948+
1949+ // Database name.
1950+ $ is_information_schema = false ;
1951+ if ( null !== $ schema_node ) {
1952+ $ schema_name = $ this ->unquote_sqlite_identifier (
1953+ $ this ->translate_sequence ( $ schema_node ->get_children () )
1954+ );
1955+ if ( 'information_schema ' === strtolower ( $ schema_name ) ) {
1956+ $ is_information_schema = true ;
1957+ } else {
1958+ throw $ this ->new_driver_exception (
1959+ sprintf ( 'Unsupported schema: "%s" ' , $ schema_name )
1960+ );
1961+ }
1962+ }
1963+
1964+ // Database-level object name (table, view, procedure, trigger, etc.).
1965+ if ( null !== $ object_node ) {
1966+ if ( $ is_information_schema ) {
1967+ $ object_name = $ this ->unquote_sqlite_identifier (
1968+ $ this ->translate_sequence ( $ object_node ->get_children () )
1969+ );
1970+ $ parts [] = $ this ->information_schema_builder ->get_table_name ( $ object_name );
1971+ } else {
1972+ $ parts [] = $ this ->translate ( $ object_node );
1973+ }
1974+ }
1975+
1976+ // Object child name (column, index, etc.).
1977+ if ( null !== $ child_node ) {
1978+ $ parts [] = $ this ->translate ( $ child_node );
1979+ }
1980+
1981+ return implode ( '. ' , $ parts );
1982+ }
1983+
19071984 /**
19081985 * Translate a MySQL simple expression to SQLite.
19091986 *
0 commit comments