@@ -233,6 +233,10 @@ class SpannerSQLCompiler(SQLCompiler):
233233
234234 compound_keywords = _compound_keywords
235235
236+ def __init__ (self , * args , ** kwargs ):
237+ self .tablealiases = {}
238+ super ().__init__ (* args , ** kwargs )
239+
236240 def get_from_hint_text (self , _ , text ):
237241 """Return a hint text.
238242
@@ -378,8 +382,10 @@ def limit_clause(self, select, **kw):
378382 return text
379383
380384 def returning_clause (self , stmt , returning_cols , ** kw ):
385+ # Set include_table=False because although table names are allowed in
386+ # RETURNING clauses, schema names are not.
381387 columns = [
382- self ._label_select_column (None , c , True , False , {})
388+ self ._label_select_column (None , c , True , False , {}, include_table = False )
383389 for c in expression ._select_iterables (returning_cols )
384390 ]
385391
@@ -391,6 +397,66 @@ def visit_sequence(self, seq, **kw):
391397 seq
392398 )
393399
400+ def visit_table (self , table , spanner_aliased = False , iscrud = False , ** kwargs ):
401+ """Build the table name.
402+
403+ Schema names are not allowed in Spanner SELECT statements. When selecting
404+ from a schema-qualified table, alias the table to produce SQL like:
405+
406+ SELECT tbl_1.id, tbl_1.col
407+ FROM schema.tbl AS tbl_1
408+ """
409+ # This closely code mirrors the mssql dialect which also
410+ # avoids schema-qualified columns in SELECTs, although the
411+ # behaviour is currently behind a deprecated
412+ # 'legacy_schema_aliasing' flag.
413+ if spanner_aliased is table or iscrud :
414+ return super ().visit_table (table , ** kwargs )
415+
416+ # alias schema-qualified tables
417+ alias = self ._schema_aliased_table (table )
418+ if alias is not None :
419+ return self .process (alias , spanner_aliased = table , ** kwargs )
420+ else :
421+ return super ().visit_table (table , ** kwargs )
422+
423+ def visit_alias (self , alias , ** kw ):
424+ # translate for schema-qualified table aliases
425+ kw ["spanner_aliased" ] = alias .element
426+ return super ().visit_alias (alias , ** kw )
427+
428+ def visit_column (self , column , add_to_result_map = None , ** kw ):
429+ if (
430+ column .table is not None
431+ and (not self .isupdate and not self .isdelete and not self .isinsert )
432+ or self .is_subquery ()
433+ ):
434+ # translate for schema-qualified table aliases
435+ t = self ._schema_aliased_table (column .table )
436+ if t is not None :
437+ converted = elements ._corresponding_column_or_error (t , column )
438+ if add_to_result_map is not None :
439+ add_to_result_map (
440+ column .name ,
441+ column .name ,
442+ (column , column .name , column .key ),
443+ column .type ,
444+ )
445+
446+ return super ().visit_column (converted , ** kw )
447+
448+ return super ().visit_column (
449+ column , add_to_result_map = add_to_result_map , ** kw
450+ )
451+
452+ def _schema_aliased_table (self , table ):
453+ if getattr (table , "schema" , None ) is not None :
454+ if table not in self .tablealiases :
455+ self .tablealiases [table ] = table .alias ()
456+ return self .tablealiases [table ]
457+ else :
458+ return None
459+
394460
395461class SpannerDDLCompiler (DDLCompiler ):
396462 """Spanner DDL statements compiler."""
0 commit comments