activerecord-oracle_enhanced-adapter 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data/History.txt +34 -0
  2. data/README.rdoc +10 -5
  3. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
  4. data/lib/active_record/connection_adapters/oracle_enhanced.rake +4 -0
  5. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +534 -170
  6. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +53 -3
  7. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +10 -10
  8. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +3 -3
  9. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +3 -3
  10. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +86 -58
  11. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +105 -68
  12. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +27 -1
  13. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +164 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +122 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +224 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +2 -2
  17. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -1
  18. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +230 -455
  19. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +37 -1
  20. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +1 -1
  21. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +6 -2
  22. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +21 -4
  23. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +63 -0
  24. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +1 -1
  25. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
  26. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +1 -1
  27. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +255 -0
  28. data/spec/active_record/connection_adapters/oracle_enhanced_schema_spec.rb +720 -0
  29. data/spec/spec_helper.rb +38 -7
  30. metadata +13 -15
@@ -12,16 +12,42 @@ module ActiveRecord #:nodoc:
12
12
  module OracleEnhancedProcedures #:nodoc:
13
13
 
14
14
  module ClassMethods
15
+ # Specify custom create method which should be used instead of Rails generated INSERT statement.
16
+ # Provided block should return ID of new record.
17
+ # Example:
18
+ # set_create_method do
19
+ # plsql.employees_pkg.create_employee(
20
+ # :p_first_name => first_name,
21
+ # :p_last_name => last_name,
22
+ # :p_employee_id => nil
23
+ # )[:p_employee_id]
24
+ # end
15
25
  def set_create_method(&block)
16
26
  include_with_custom_methods
17
27
  self.custom_create_method = block
18
28
  end
19
29
 
30
+ # Specify custom update method which should be used instead of Rails generated UPDATE statement.
31
+ # Example:
32
+ # set_update_method do
33
+ # plsql.employees_pkg.update_employee(
34
+ # :p_employee_id => id,
35
+ # :p_first_name => first_name,
36
+ # :p_last_name => last_name
37
+ # )
38
+ # end
20
39
  def set_update_method(&block)
21
40
  include_with_custom_methods
22
41
  self.custom_update_method = block
23
42
  end
24
43
 
44
+ # Specify custom delete method which should be used instead of Rails generated DELETE statement.
45
+ # Example:
46
+ # set_delete_method do
47
+ # plsql.employees_pkg.delete_employee(
48
+ # :p_employee_id => id
49
+ # )
50
+ # end
25
51
  def set_delete_method(&block)
26
52
  include_with_custom_methods
27
53
  self.custom_delete_method = block
@@ -35,7 +61,7 @@ module ActiveRecord #:nodoc:
35
61
  end
36
62
  end
37
63
 
38
- module InstanceMethods
64
+ module InstanceMethods #:nodoc:
39
65
  def self.included(base)
40
66
  base.instance_eval do
41
67
  if private_instance_methods.include?('create_without_callbacks') || private_instance_methods.include?(:create_without_callbacks)
@@ -0,0 +1,164 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ class OracleEnhancedForeignKeyDefinition < Struct.new(:from_table, :to_table, :options) #:nodoc:
4
+ end
5
+
6
+ class OracleEnhancedSynonymDefinition < Struct.new(:name, :table_owner, :table_name, :db_link) #:nodoc:
7
+ end
8
+
9
+ module OracleEnhancedSchemaDefinitions #:nodoc:
10
+ def self.included(base)
11
+ base::TableDefinition.class_eval do
12
+ include OracleEnhancedTableDefinition
13
+ end
14
+
15
+ base::Table.class_eval do
16
+ include OracleEnhancedTable
17
+ end
18
+ end
19
+ end
20
+
21
+ module OracleEnhancedTableDefinition
22
+ class ForeignKey < Struct.new(:base, :to_table, :options) #:nodoc:
23
+ def to_sql
24
+ base.foreign_key_definition(to_table, options)
25
+ end
26
+ alias to_s :to_sql
27
+ end
28
+
29
+ def self.included(base) #:nodoc:
30
+ base.class_eval do
31
+ alias_method_chain :references, :foreign_keys
32
+ alias_method_chain :to_sql, :foreign_keys
33
+ end
34
+ end
35
+
36
+ # Adds a :foreign_key option to TableDefinition.references.
37
+ # If :foreign_key is true, a foreign key constraint is added to the table.
38
+ # You can also specify a hash, which is passed as foreign key options.
39
+ #
40
+ # ===== Examples
41
+ # ====== Add goat_id column and a foreign key to the goats table.
42
+ # t.references(:goat, :foreign_key => true)
43
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
44
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
45
+ #
46
+ # Note: No foreign key is created if :polymorphic => true is used.
47
+ # Note: If no name is specified, the database driver creates one for you!
48
+ def references_with_foreign_keys(*args)
49
+ options = args.extract_options!
50
+ fk_options = options.delete(:foreign_key)
51
+
52
+ if fk_options && !options[:polymorphic]
53
+ fk_options = {} if fk_options == true
54
+ args.each { |to_table| foreign_key(to_table, fk_options) }
55
+ end
56
+
57
+ references_without_foreign_keys(*(args << options))
58
+ end
59
+
60
+ # Defines a foreign key for the table. +to_table+ can be a single Symbol, or
61
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
62
+ #
63
+ # ===== Examples
64
+ # ====== Creating a simple foreign key
65
+ # t.foreign_key(:people)
66
+ # ====== Defining the column
67
+ # t.foreign_key(:people, :column => :sender_id)
68
+ # ====== Creating a named foreign key
69
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
70
+ # ====== Defining the column of the +to_table+.
71
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
72
+ def foreign_key(to_table, options = {})
73
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
74
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
75
+ foreign_keys << ForeignKey.new(@base, to_table, options)
76
+ else
77
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
78
+ end
79
+ end
80
+
81
+ def to_sql_with_foreign_keys #:nodoc:
82
+ sql = to_sql_without_foreign_keys
83
+ sql << ', ' << (foreign_keys * ', ') if foreign_keys.present?
84
+ sql
85
+ end
86
+
87
+ private
88
+ def foreign_keys
89
+ @foreign_keys ||= []
90
+ end
91
+ end
92
+
93
+ module OracleEnhancedTable
94
+ def self.included(base) #:nodoc:
95
+ base.class_eval do
96
+ alias_method_chain :references, :foreign_keys
97
+ end
98
+ end
99
+
100
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
101
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
102
+ #
103
+ # ===== Examples
104
+ # ====== Creating a simple foreign key
105
+ # t.foreign_key(:people)
106
+ # ====== Defining the column
107
+ # t.foreign_key(:people, :column => :sender_id)
108
+ # ====== Creating a named foreign key
109
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
110
+ # ====== Defining the column of the +to_table+.
111
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
112
+ def foreign_key(to_table, options = {})
113
+ if @base.respond_to?(:supports_foreign_keys?) && @base.supports_foreign_keys?
114
+ to_table = to_table.to_s.pluralize if ActiveRecord::Base.pluralize_table_names
115
+ @base.add_foreign_key(@table_name, to_table, options)
116
+ else
117
+ raise ArgumentError, "this ActiveRecord adapter is not supporting foreign_key definition"
118
+ end
119
+ end
120
+
121
+ # Remove the given foreign key from the table.
122
+ #
123
+ # ===== Examples
124
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
125
+ # t.remove_foreign_key :companies
126
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
127
+ # remove_foreign_key :column => :branch_id
128
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
129
+ # remove_index :name => :party_foreign_key
130
+ def remove_foreign_key(options = {})
131
+ @base.remove_foreign_key(@table_name, options)
132
+ end
133
+
134
+ # Adds a :foreign_key option to TableDefinition.references.
135
+ # If :foreign_key is true, a foreign key constraint is added to the table.
136
+ # You can also specify a hash, which is passed as foreign key options.
137
+ #
138
+ # ===== Examples
139
+ # ====== Add goat_id column and a foreign key to the goats table.
140
+ # t.references(:goat, :foreign_key => true)
141
+ # ====== Add goat_id column and a cascading foreign key to the goats table.
142
+ # t.references(:goat, :foreign_key => {:dependent => :delete})
143
+ #
144
+ # Note: No foreign key is created if :polymorphic => true is used.
145
+ def references_with_foreign_keys(*args)
146
+ options = args.extract_options!
147
+ polymorphic = options[:polymorphic]
148
+ fk_options = options.delete(:foreign_key)
149
+
150
+ references_without_foreign_keys(*(args << options))
151
+ # references_without_foreign_keys adds {:type => :integer}
152
+ args.extract_options!
153
+ if fk_options && !polymorphic
154
+ fk_options = {} if fk_options == true
155
+ args.each { |to_table| foreign_key(to_table, fk_options) }
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ ActiveRecord::ConnectionAdapters.class_eval do
163
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDefinitions
164
+ end
@@ -0,0 +1,122 @@
1
+ module ActiveRecord #:nodoc:
2
+ module ConnectionAdapters #:nodoc:
3
+ module OracleEnhancedSchemaDumper #:nodoc:
4
+
5
+ def self.included(base) #:nodoc:
6
+ base.class_eval do
7
+ private
8
+ alias_method_chain :tables, :oracle_enhanced
9
+ alias_method_chain :indexes, :oracle_enhanced
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def tables_with_oracle_enhanced(stream)
16
+ @connection.tables.sort.each do |tbl|
17
+ # add table prefix or suffix for schema_migrations
18
+ next if [ActiveRecord::Migrator.proper_table_name('schema_migrations'), ignore_tables].flatten.any? do |ignored|
19
+ case ignored
20
+ when String; tbl == ignored
21
+ when Regexp; tbl =~ ignored
22
+ else
23
+ raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
24
+ end
25
+ end
26
+ # change table name inspect method
27
+ tbl.extend TableInspect
28
+ table(tbl, stream)
29
+ # add primary key trigger if table has it
30
+ primary_key_trigger(tbl, stream)
31
+ # add foreign keys if table has them
32
+ foreign_keys(tbl, stream)
33
+ end
34
+ synonyms(stream)
35
+ end
36
+
37
+ def primary_key_trigger(table_name, stream)
38
+ if @connection.respond_to?(:has_primary_key_trigger?) && @connection.has_primary_key_trigger?(table_name)
39
+ pk, pk_seq = @connection.pk_and_sequence_for(table_name)
40
+ stream.print " add_primary_key_trigger #{table_name.inspect}"
41
+ stream.print ", :primary_key => \"#{pk}\"" if pk != 'id'
42
+ stream.print "\n\n"
43
+ end
44
+ end
45
+
46
+ def foreign_keys(table_name, stream)
47
+ if (foreign_keys = @connection.foreign_keys(table_name)).any?
48
+ add_foreign_key_statements = foreign_keys.map do |foreign_key|
49
+ statement_parts = [ ('add_foreign_key ' + foreign_key.from_table.inspect) ]
50
+ statement_parts << foreign_key.to_table.inspect
51
+ statement_parts << (':name => ' + foreign_key.options[:name].inspect)
52
+
53
+ if foreign_key.options[:column] != "#{foreign_key.to_table.singularize}_id"
54
+ statement_parts << (':column => ' + foreign_key.options[:column].inspect)
55
+ end
56
+ if foreign_key.options[:primary_key] != 'id'
57
+ statement_parts << (':primary_key => ' + foreign_key.options[:primary_key].inspect)
58
+ end
59
+ if foreign_key.options[:dependent].present?
60
+ statement_parts << (':dependent => ' + foreign_key.options[:dependent].inspect)
61
+ end
62
+
63
+ ' ' + statement_parts.join(', ')
64
+ end
65
+
66
+ stream.puts add_foreign_key_statements.sort.join("\n")
67
+ stream.puts
68
+ end
69
+ end
70
+
71
+ def synonyms(stream)
72
+ syns = @connection.synonyms
73
+ syns.each do |syn|
74
+ table_name = syn.table_name
75
+ table_name = "#{syn.table_owner}.#{table_name}" if syn.table_owner
76
+ table_name = "#{table_name}@#{syn.db_link}" if syn.db_link
77
+ stream.print " add_synonym #{syn.name.inspect}, #{table_name.inspect}, :force => true"
78
+ stream.puts
79
+ end
80
+ stream.puts unless syns.empty?
81
+ end
82
+
83
+ def indexes_with_oracle_enhanced(table, stream)
84
+ if (indexes = @connection.indexes(table)).any?
85
+ add_index_statements = indexes.map do |index|
86
+ # use table.inspect as it will remove prefix and suffix
87
+ statment_parts = [ ('add_index ' + table.inspect) ]
88
+ statment_parts << index.columns.inspect
89
+ statment_parts << (':name => ' + index.name.inspect)
90
+ statment_parts << ':unique => true' if index.unique
91
+
92
+ ' ' + statment_parts.join(', ')
93
+ end
94
+
95
+ stream.puts add_index_statements.sort.join("\n")
96
+ stream.puts
97
+ end
98
+ end
99
+
100
+ # remove table name prefix and suffix when doing #inspect (which is used in tables method)
101
+ module TableInspect #:nodoc:
102
+ def inspect
103
+ remove_prefix_and_suffix(self)
104
+ end
105
+
106
+ private
107
+ def remove_prefix_and_suffix(table_name)
108
+ if table_name =~ /\A#{ActiveRecord::Base.table_name_prefix}(.*)#{ActiveRecord::Base.table_name_suffix}\Z/
109
+ "\"#{$1}\""
110
+ else
111
+ "\"#{table_name}\""
112
+ end
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
119
+
120
+ ActiveRecord::SchemaDumper.class_eval do
121
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaDumper
122
+ end
@@ -0,0 +1,224 @@
1
+ require 'digest/sha1'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module OracleEnhancedSchemaStatementsExt
6
+ def supports_foreign_keys? #:nodoc:
7
+ true
8
+ end
9
+
10
+ # Create primary key trigger (so that you can skip primary key value in INSERT statement).
11
+ # By default trigger name will be "table_name_pkt", you can override the name with
12
+ # :trigger_name option (but it is not recommended to override it as then this trigger will
13
+ # not be detected by ActiveRecord model and it will still do prefetching of sequence value).
14
+ #
15
+ # add_primary_key_trigger :users
16
+ #
17
+ # You can also create primary key trigger using +create_table+ with :primary_key_trigger
18
+ # option:
19
+ #
20
+ # create_table :users, :primary_key_trigger => true do |t|
21
+ # # ...
22
+ # end
23
+ #
24
+ def add_primary_key_trigger(table_name, options)
25
+ # call the same private method that is used for create_table :primary_key_trigger => true
26
+ create_primary_key_trigger(table_name, options)
27
+ end
28
+
29
+ # Adds a new foreign key to the +from_table+, referencing the primary key of +to_table+
30
+ # (syntax and partial implementation taken from http://github.com/matthuhiggins/foreigner)
31
+ #
32
+ # The foreign key will be named after the from and to tables unless you pass
33
+ # <tt>:name</tt> as an option.
34
+ #
35
+ # === Examples
36
+ # ==== Creating a foreign key
37
+ # add_foreign_key(:comments, :posts)
38
+ # generates
39
+ # ALTER TABLE comments ADD CONSTRAINT
40
+ # comments_post_id_fk FOREIGN KEY (post_id) REFERENCES posts (id)
41
+ #
42
+ # ==== Creating a named foreign key
43
+ # add_foreign_key(:comments, :posts, :name => 'comments_belongs_to_posts')
44
+ # generates
45
+ # ALTER TABLE comments ADD CONSTRAINT
46
+ # comments_belongs_to_posts FOREIGN KEY (post_id) REFERENCES posts (id)
47
+ #
48
+ # ==== Creating a cascading foreign_key on a custom column
49
+ # add_foreign_key(:people, :people, :column => 'best_friend_id', :dependent => :nullify)
50
+ # generates
51
+ # ALTER TABLE people ADD CONSTRAINT
52
+ # people_best_friend_id_fk FOREIGN KEY (best_friend_id) REFERENCES people (id)
53
+ # ON DELETE SET NULL
54
+ #
55
+ # === Supported options
56
+ # [:column]
57
+ # Specify the column name on the from_table that references the to_table. By default this is guessed
58
+ # to be the singular name of the to_table with "_id" suffixed. So a to_table of :posts will use "post_id"
59
+ # as the default <tt>:column</tt>.
60
+ # [:primary_key]
61
+ # Specify the column name on the to_table that is referenced by this foreign key. By default this is
62
+ # assumed to be "id".
63
+ # [:name]
64
+ # Specify the name of the foreign key constraint. This defaults to use from_table and foreign key column.
65
+ # [:dependent]
66
+ # If set to <tt>:delete</tt>, the associated records in from_table are deleted when records in to_table table are deleted.
67
+ # If set to <tt>:nullify</tt>, the foreign key column is set to +NULL+.
68
+ def add_foreign_key(from_table, to_table, options = {})
69
+ column = options[:column] || "#{to_table.to_s.singularize}_id"
70
+ constraint_name = foreign_key_constraint_name(from_table, column, options)
71
+ sql = "ALTER TABLE #{quote_table_name(from_table)} ADD CONSTRAINT #{quote_column_name(constraint_name)} "
72
+ sql << foreign_key_definition(to_table, options)
73
+ execute sql
74
+ end
75
+
76
+ def foreign_key_definition(to_table, options = {}) #:nodoc:
77
+ column = options[:column] || "#{to_table.to_s.singularize}_id"
78
+ primary_key = options[:primary_key] || "id"
79
+ sql = "FOREIGN KEY (#{quote_column_name(column)}) REFERENCES #{quote_table_name(to_table)}(#{primary_key})"
80
+ case options[:dependent]
81
+ when :nullify
82
+ sql << " ON DELETE SET NULL"
83
+ when :delete
84
+ sql << " ON DELETE CASCADE"
85
+ end
86
+ sql
87
+ end
88
+
89
+ # Remove the given foreign key from the table.
90
+ #
91
+ # ===== Examples
92
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
93
+ # remove_foreign_key :suppliers, :companies
94
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
95
+ # remove_foreign_key :accounts, :column => :branch_id
96
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
97
+ # remove_foreign_key :accounts, :name => :party_foreign_key
98
+ def remove_foreign_key(from_table, options)
99
+ if Hash === options
100
+ constraint_name = foreign_key_constraint_name(from_table, options[:column], options)
101
+ else
102
+ constraint_name = foreign_key_constraint_name(from_table, "#{options.to_s.singularize}_id")
103
+ end
104
+ execute "ALTER TABLE #{quote_table_name(from_table)} DROP CONSTRAINT #{quote_column_name(constraint_name)}"
105
+ end
106
+
107
+ private
108
+
109
+ def foreign_key_constraint_name(table_name, column, options = {})
110
+ constraint_name = original_name = options[:name] || "#{table_name}_#{column}_fk"
111
+ return constraint_name if constraint_name.length <= OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH
112
+ # leave just first three letters from each word
113
+ constraint_name = constraint_name.split('_').map{|w| w[0,3]}.join('_')
114
+ # generate unique name using hash function
115
+ if constraint_name.length > OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH
116
+ constraint_name = 'c'+Digest::SHA1.hexdigest(original_name)[0,OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH-1]
117
+ end
118
+ @logger.warn "#{adapter_name} shortened foreign key constraint name #{original_name} to #{constraint_name}" if @logger
119
+ constraint_name
120
+ end
121
+
122
+
123
+ public
124
+
125
+ # get table foreign keys for schema dump
126
+ def foreign_keys(table_name) #:nodoc:
127
+ (owner, desc_table_name, db_link) = @connection.describe(table_name)
128
+
129
+ fk_info = select_all(<<-SQL, 'Foreign Keys')
130
+ SELECT r.table_name to_table
131
+ ,rc.column_name primary_key
132
+ ,cc.column_name
133
+ ,c.constraint_name name
134
+ ,c.delete_rule
135
+ FROM user_constraints#{db_link} c, user_cons_columns#{db_link} cc,
136
+ user_constraints#{db_link} r, user_cons_columns#{db_link} rc
137
+ WHERE c.owner = '#{owner}'
138
+ AND c.table_name = '#{desc_table_name}'
139
+ AND c.constraint_type = 'R'
140
+ AND cc.owner = c.owner
141
+ AND cc.constraint_name = c.constraint_name
142
+ AND r.constraint_name = c.r_constraint_name
143
+ AND r.owner = c.owner
144
+ AND rc.owner = r.owner
145
+ AND rc.constraint_name = r.constraint_name
146
+ AND rc.position = cc.position
147
+ SQL
148
+
149
+ fk_info.map do |row|
150
+ options = {:column => oracle_downcase(row['column_name']), :name => oracle_downcase(row['name']),
151
+ :primary_key => oracle_downcase(row['primary_key'])}
152
+ case row['delete_rule']
153
+ when 'CASCADE'
154
+ options[:dependent] = :delete
155
+ when 'SET NULL'
156
+ options[:dependent] = :nullify
157
+ end
158
+ OracleEnhancedForeignKeyDefinition.new(table_name, oracle_downcase(row['to_table']), options)
159
+ end
160
+ end
161
+
162
+ # REFERENTIAL INTEGRITY ====================================
163
+
164
+ def disable_referential_integrity(&block) #:nodoc:
165
+ sql_constraints = <<-SQL
166
+ SELECT constraint_name, owner, table_name
167
+ FROM user_constraints
168
+ WHERE constraint_type = 'R'
169
+ AND status = 'ENABLED'
170
+ SQL
171
+ old_constraints = select_all(sql_constraints)
172
+ begin
173
+ old_constraints.each do |constraint|
174
+ execute "ALTER TABLE #{constraint["table_name"]} DISABLE CONSTRAINT #{constraint["constraint_name"]}"
175
+ end
176
+ yield
177
+ ensure
178
+ old_constraints.each do |constraint|
179
+ execute "ALTER TABLE #{constraint["table_name"]} ENABLE CONSTRAINT #{constraint["constraint_name"]}"
180
+ end
181
+ end
182
+ end
183
+
184
+ # Add synonym to existing table or view or sequence. Can be used to create local synonym to
185
+ # remote table in other schema or in other database
186
+ # Examples:
187
+ #
188
+ # add_synonym :posts, "blog.posts"
189
+ # add_synonym :posts_seq, "blog.posts_seq"
190
+ # add_synonym :employees, "hr.employees@dblink", :force => true
191
+ #
192
+ def add_synonym(name, table_name, options = {})
193
+ sql = "CREATE"
194
+ if options[:force] == true
195
+ sql << " OR REPLACE"
196
+ end
197
+ sql << " SYNONYM #{quote_table_name(name)} FOR #{quote_table_name(table_name)}"
198
+ execute sql
199
+ end
200
+
201
+ # Remove existing synonym to table or view or sequence
202
+ # Example:
203
+ #
204
+ # remove_synonym :posts, "blog.posts"
205
+ #
206
+ def remove_synonym(name)
207
+ execute "DROP SYNONYM #{quote_table_name(name)}"
208
+ end
209
+
210
+ # get synonyms for schema dump
211
+ def synonyms #:nodoc:
212
+ select_all("SELECT synonym_name, table_owner, table_name, db_link FROM user_synonyms").collect do |row|
213
+ OracleEnhancedSynonymDefinition.new(oracle_downcase(row['synonym_name']),
214
+ oracle_downcase(row['table_owner']), oracle_downcase(row['table_name']), oracle_downcase(row['db_link']))
215
+ end
216
+ end
217
+
218
+ end
219
+ end
220
+ end
221
+
222
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
223
+ include ActiveRecord::ConnectionAdapters::OracleEnhancedSchemaStatementsExt
224
+ end