@@ -53,7 +53,7 @@ def table_exists?(table_name)
5353 end
5454
5555 def data_source_exists? ( table_name )
56- ( _owner , _table_name ) = _connection . describe ( table_name )
56+ ( _owner , _table_name ) = resolve_data_source_name ( table_name )
5757 true
5858 rescue
5959 false
@@ -87,7 +87,7 @@ def synonyms
8787 end
8888
8989 def indexes ( table_name ) # :nodoc:
90- ( _owner , table_name ) = _connection . describe ( table_name )
90+ ( _owner , table_name ) = resolve_data_source_name ( table_name )
9191 default_tablespace_name = default_tablespace
9292
9393 result = select_all ( <<~SQL . squish , "SCHEMA" , [ bind_string ( "table_name" , table_name ) ] )
@@ -368,7 +368,7 @@ def index_name(table_name, options) # :nodoc:
368368 #
369369 # Will always query database and not index cache.
370370 def index_name_exists? ( table_name , index_name )
371- ( _owner , table_name ) = _connection . describe ( table_name )
371+ ( _owner , table_name ) = resolve_data_source_name ( table_name )
372372 result = select_value ( <<~SQL . squish , "SCHEMA" , [ bind_string ( "table_name" , table_name ) , bind_string ( "index_name" , index_name . to_s . upcase ) ] )
373373 SELECT 1 FROM all_indexes i
374374 WHERE i.owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -511,7 +511,7 @@ def change_column_comment(table_name, column_name, comment_or_changes)
511511
512512 def table_comment ( table_name ) # :nodoc:
513513 # TODO
514- ( _owner , table_name ) = _connection . describe ( table_name )
514+ ( _owner , table_name ) = resolve_data_source_name ( table_name )
515515 select_value ( <<~SQL . squish , "SCHEMA" , [ bind_string ( "table_name" , table_name ) ] )
516516 SELECT comments FROM all_tab_comments
517517 WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -527,7 +527,7 @@ def table_options(table_name) # :nodoc:
527527
528528 def column_comment ( table_name , column_name ) # :nodoc:
529529 # TODO: it does not exist in Abstract adapter
530- ( _owner , table_name ) = _connection . describe ( table_name )
530+ ( _owner , table_name ) = resolve_data_source_name ( table_name )
531531 select_value ( <<~SQL . squish , "SCHEMA" , [ bind_string ( "table_name" , table_name ) , bind_string ( "column_name" , column_name . upcase ) ] )
532532 SELECT comments FROM all_col_comments
533533 WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -555,7 +555,7 @@ def tablespace(table_name)
555555
556556 # get table foreign keys for schema dump
557557 def foreign_keys ( table_name ) # :nodoc:
558- ( _owner , desc_table_name ) = _connection . describe ( table_name )
558+ ( _owner , desc_table_name ) = resolve_data_source_name ( table_name )
559559
560560 fk_info = select_all ( <<~SQL . squish , "SCHEMA" , [ bind_string ( "desc_table_name" , desc_table_name ) ] )
561561 SELECT r.table_name to_table
@@ -733,6 +733,73 @@ def rebuild_primary_key_index_to_default_tablespace(table_name, options)
733733
734734 execute ( "ALTER INDEX #{ quote_column_name ( index_name ) } REBUILD TABLESPACE #{ tablespace } " )
735735 end
736+
737+ # Resolves an Oracle data-source name to its underlying [owner, table_name]
738+ # by following synonyms through the catalog. Defaults the schema to
739+ # `_connection.owner` (the adapter's configured default schema, taken
740+ # from `config[:schema]` or `config[:username]`) when the name is not
741+ # schema-qualified. This is distinct from
742+ # `SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')`, which can differ after
743+ # `ALTER SESSION SET CURRENT_SCHEMA`.
744+ # Raises OracleEnhanced::ConnectionException if the object does not
745+ # exist or if synonym resolution produces a looping chain.
746+ def resolve_data_source_name ( name )
747+ visited = Set . new
748+ loop do
749+ schema , identifier = extract_schema_qualified_name ( name )
750+ real_name = schema ? "#{ schema } .#{ identifier } " : identifier
751+ owner = schema || _connection . owner
752+
753+ unless visited . add? ( [ owner , identifier ] )
754+ raise OracleEnhanced ::ConnectionException ,
755+ %Q{"DESC #{ name } " failed; looping chain of synonyms}
756+ end
757+
758+ binds = [
759+ bind_string ( "table_owner" , owner ) ,
760+ bind_string ( "table_name" , identifier ) ,
761+ bind_string ( "table_owner" , owner ) ,
762+ bind_string ( "table_name" , identifier ) ,
763+ bind_string ( "table_owner" , owner ) ,
764+ bind_string ( "table_name" , identifier ) ,
765+ bind_string ( "real_name" , real_name ) ,
766+ ]
767+ result = select_one ( <<~SQL . squish , "SCHEMA" , binds )
768+ SELECT owner, table_name, 'TABLE' name_type
769+ FROM all_tables WHERE owner = :table_owner AND table_name = :table_name
770+ UNION ALL
771+ SELECT owner, view_name table_name, 'VIEW' name_type
772+ FROM all_views WHERE owner = :table_owner AND view_name = :table_name
773+ UNION ALL
774+ SELECT table_owner, table_name, 'SYNONYM' name_type
775+ FROM all_synonyms WHERE owner = :table_owner AND synonym_name = :table_name
776+ UNION ALL
777+ SELECT table_owner, table_name, 'SYNONYM' name_type
778+ FROM all_synonyms WHERE owner = 'PUBLIC' AND synonym_name = :real_name
779+ SQL
780+
781+ raise OracleEnhanced ::ConnectionException , %Q{"DESC #{ name } " failed; does it exist?} unless result
782+
783+ if result [ "name_type" ] == "SYNONYM"
784+ name = "#{ result [ 'owner' ] && "#{ result [ 'owner' ] } ." } #{ result [ 'table_name' ] } "
785+ else
786+ return [ result [ "owner" ] , result [ "table_name" ] ]
787+ end
788+ end
789+ end
790+
791+ # Splits "schema.identifier" into its parts, returning [schema, identifier].
792+ # Mirrors Rails' PostgreSQL/MySQL adapters: a non-qualified name yields
793+ # schema = nil. Oracle-specific bits: rejects db links and upcases valid
794+ # identifiers so catalog lookups match the stored upper-case names.
795+ def extract_schema_qualified_name ( string )
796+ string = string . to_s
797+ raise ArgumentError , "db link is not supported" if string . include? ( "@" )
798+
799+ string = string . upcase if OracleEnhanced ::Quoting . valid_table_name? ( string )
800+ schema , identifier = string . split ( "." ) if string . include? ( "." )
801+ [ schema , identifier || string ]
802+ end
736803 end
737804 end
738805 end
0 commit comments