require 'sequel' Sequel.require 'adapters/shared/oracle' # The oracle_schemata extension adds some schema related methods to the Oracle database adapater. module Sequel module Oracle module DatabaseMethods # Returns the indexes for the given +table+ (or +schema.table+), as an array of hashes. # By default, it does not return primary keys. # # * :valid - Only look for indexes that are valid (true) or unusable (false). By default (nil), # looks for any matching index. # * :all - Returns all indexes, even ones used for primary keys. def indexes(qualified_table, options={}) ds, result = metadata_dataset, [] outm = lambda{|k| ds.send :output_identifier, k} schema, table = ds.schema_and_table(qualified_table).map{|k| k.to_s.send(ds.identifier_input_method) if k} # Build the dataset and apply filters for introspection of indexes. ds = ds.select(:i__index_name, :i__status, :i__uniqueness, :i__visibility, :i__index_type, :i__join_index, :ic__column_name). from(:"all_indexes___i"). join(:"all_ind_columns___ic", [ [:index_owner,:owner], [:index_name,:index_name] ]). where(:i__table_name=>table, :i__dropped=>'NO'). order(:status.desc, :index_name, :ic__column_position) unless schema.nil? ds = ds.where :i__owner => schema end unless (z = options[:valid]).nil? ds = ds.where :i__status => (z ? 'VALID' : 'UNUSABLE') end if options[:all] pk = from(:all_constraints.as(:c)).where(:c__constraint_type=>'P'). where(:c__index_name=>:i__index_name, :c__owner=>:i__owner) ds = ds.where ~pk.exists end # Return the table constraints as an array of hashes, including a column list. hash = Hash.new do |h,k| result.push :index_name=>outm[k], :table_name=>outm[table], :columns=>[] h[k] = result.last end ds.each do |row| ref = hash[row[:index_name]] ref[:index_type] ||= row[:index_type] ref[:join_index] ||= row[:join_index]=='YES' ref[:valid] ||= row[:status]=='VALID' ref[:uniqueness] ||= row[:uniqueness]=='UNIQUE' ref[:visibility] ||= row[:visibility]=='VISIBLE' ref[:columns] << outm[row[:column_name]] end result end # Returns the primary key for the given +table+ (or +schema.table+), as a hash. # # * :enabled - Only look for keys that are enabled (true) or disabled (false). By default (nil), # looks for any matching key. # * :all - Return an array of matching keys, instead of the first matching key. # def primary_key(qualified_table, options={}) result = table_constraints qualified_table, 'P', options options[:all] ? result : result.first end # Returns unique constraints defined on the given +table+ (or +schema.table+), as an array of hashes. # # * :enabled - Only look for keys that are enabled (true) or disabled (false). By default (nil), # looks for all matching keys. def unique_keys(qualified_table, options={}) table_constraints qualified_table, 'U', options end # Returns foreign keys defined on the given +table+ (or +schema.table+), as an array of hashes. # # * :enabled - Only look for keys that are enabled (true) or disabled (false). By default (nil), # looks for all matching keys. def foreign_keys(qualified_table, options={}) table_constraints qualified_table, 'R', options end # Returns foreign keys that refer to the given +table+ (or +schema.table+), as an array of hashes. # # * :enabled - Only look for keys that are enabled (true) or disabled (false). By default (nil), # looks for all matching keys. def references(qualified_table, options={}) table_constraints qualified_table, 'R', options.merge(:table_name_column=>:t__table_name) end private # Internal helper method for introspection of table constraints. def table_constraints(qualified_table, constraint_type, options={}) ds, result = metadata_dataset, [] outm = lambda{|k| ds.send :output_identifier, k} schema, table = ds.schema_and_table(qualified_table).map{|k| k.to_s.send(ds.identifier_input_method) if k} x_cons = schema.nil? ? 'user_cons' : 'all_cons' # Build the dataset and apply filters for introspection of constraints. # Also allows the caller to customize the dataset. ds = ds.select(:c__constraint_name, :c__table_name, :c__rely, :c__status, :c__validated, :cc__column_name). from(:"#{x_cons}traints___c"). join(:"#{x_cons}_columns___cc", [ [:owner,:owner], [:constraint_name,:constraint_name] ]). where((options[:table_name_column]||:c__table_name)=>table, :c__constraint_type=>constraint_type). order(:table_name, :status.desc, :constraint_name, :cc__position) unless schema.nil? ds = ds.where :c__owner => schema end unless (z = options[:enabled]).nil? ds = ds.where :c__status => (z ? 'ENABLED' : 'DISABLED') end if constraint_type == 'R' ds = ds.select_more(:c__r_constraint_name, :t__table_name.as(:r_table_name)). join(:"#{x_cons}traints___t", [ [:owner,:c__r_owner], [:constraint_name,:c__r_constraint_name] ]). where(:t__constraint_type=>'P') else ds = ds.select_more(:c__index_name) end ds = yield ds, table if block_given? # Return the table constraints as an array of hashes, including a column list. hash = Hash.new do |h,k| result.push :constraint_name=>outm[k], :constraint_type=>constraint_type, :columns=>[] h[k] = result.last end ds.each do |row| ref = hash[row[:constraint_name]] ref[:table_name] ||= outm[row[:table_name]] ref[:rely] ||= row[:rely]=='RELY' ref[:enabled] ||= row[:status]=='ENABLED' ref[:validated] ||= row[:validated]=='VALIDATED' ref[:columns] << outm[row[:column_name]] if row.include? :r_constraint_name ref[:r_constraint_name] ||= outm[row[:r_constraint_name]] ref[:r_table_name] ||= outm[row[:r_table_name]] end if row[:index_name] ref[:index_name] ||= outm[row[:index_name]] end end result end end end end