activerecord-oracle_enhanced-adapter 6.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +112 -0
  3. data/README.md +12 -1
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +3 -4
  6. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +0 -1
  7. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +0 -9
  8. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +64 -47
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +4 -5
  10. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +0 -1
  11. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +3 -4
  12. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +1 -2
  13. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +12 -7
  14. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +0 -1
  15. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +38 -3
  16. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +3 -4
  17. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +1 -1
  18. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +16 -4
  19. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +65 -59
  20. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +35 -34
  21. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +2 -1
  22. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +64 -21
  23. data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
  24. data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
  25. data/lib/arel/visitors/oracle.rb +217 -0
  26. data/lib/arel/visitors/oracle12.rb +124 -0
  27. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +35 -3
  28. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +6 -1
  29. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +0 -1
  30. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +28 -1
  31. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +2 -1
  32. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +122 -0
  33. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +4 -2
  34. data/spec/spec_config.yaml.template +2 -2
  35. data/spec/spec_helper.rb +13 -4
  36. metadata +28 -26
@@ -18,13 +18,12 @@ module ActiveRecord #:nodoc:
18
18
  module ClassMethods
19
19
  def lob_columns
20
20
  columns.select do |column|
21
- column.sql_type_metadata.sql_type =~ /LOB$/
21
+ column.sql_type_metadata.sql_type.end_with?("LOB")
22
22
  end
23
23
  end
24
24
  end
25
25
 
26
26
  private
27
-
28
27
  def enhanced_write_lobs
29
28
  if self.class.connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter) &&
30
29
  !(self.class.custom_create_method || self.class.custom_update_method)
@@ -97,6 +97,10 @@ module ActiveRecord
97
97
  @raw_connection.exec(sql, *bindvars, &block)
98
98
  end
99
99
 
100
+ def with_retry(&block)
101
+ @raw_connection.with_retry(&block)
102
+ end
103
+
100
104
  def prepare(sql)
101
105
  Cursor.new(self, @raw_connection.parse(sql))
102
106
  end
@@ -265,7 +269,6 @@ module ActiveRecord
265
269
  end
266
270
 
267
271
  private
268
-
269
272
  def date_without_time?(value)
270
273
  case value
271
274
  when OraDate
@@ -319,9 +322,9 @@ module ActiveRecord
319
322
  # connection using host, port and database name
320
323
  elsif host || port
321
324
  host ||= "localhost"
322
- host = "[#{host}]" if host =~ /^[^\[].*:/ # IPv6
325
+ host = "[#{host}]" if /^[^\[].*:/.match?(host) # IPv6
323
326
  port ||= 1521
324
- database = "/#{database}" unless database.match(/^\//)
327
+ database = "/#{database}" unless database.start_with?("/")
325
328
  "//#{host}:#{port}#{database}"
326
329
  # if no host is specified then assume that
327
330
  # database parameter is TNS alias or TNS connection string
@@ -423,13 +426,11 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
423
426
  LOST_CONNECTION_ERROR_CODES = [ 28, 1012, 3113, 3114, 3135 ] #:nodoc:
424
427
 
425
428
  # Adds auto-recovery functionality.
426
- #
427
- # See: http://www.jiubao.org/ruby-oci8/api.en.html#label-11
428
- def exec(sql, *bindvars, &block) #:nodoc:
429
+ def with_retry #:nodoc:
429
430
  should_retry = self.class.auto_retry? && autocommit?
430
431
 
431
432
  begin
432
- @connection.exec(sql, *bindvars, &block)
433
+ yield
433
434
  rescue OCIException => e
434
435
  raise unless e.is_a?(OCIError) && LOST_CONNECTION_ERROR_CODES.include?(e.code)
435
436
  @active = false
@@ -439,5 +440,9 @@ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
439
440
  retry
440
441
  end
441
442
  end
443
+
444
+ def exec(sql, *bindvars, &block) #:nodoc:
445
+ with_retry { @connection.exec(sql, *bindvars, &block) }
446
+ end
442
447
  end
443
448
  #:startdoc:
@@ -97,7 +97,6 @@ module ActiveRecord #:nodoc:
97
97
  end
98
98
 
99
99
  private
100
-
101
100
  # Creates a record with custom create method
102
101
  # and returns its id.
103
102
  def _create_record
@@ -132,8 +132,43 @@ module ActiveRecord
132
132
  end
133
133
  end
134
134
 
135
- private
135
+ def column_name_matcher
136
+ COLUMN_NAME
137
+ end
138
+
139
+ def column_name_with_order_matcher
140
+ COLUMN_NAME_WITH_ORDER
141
+ end
142
+
143
+ COLUMN_NAME = /
144
+ \A
145
+ (
146
+ (?:
147
+ # "table_name"."column_name" | function(one or no argument)
148
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
149
+ )
150
+ (?:(?:\s+AS)?\s+(?:\w+|"\w+"))?
151
+ )
152
+ (?:\s*,\s*\g<1>)*
153
+ \z
154
+ /ix
155
+
156
+ COLUMN_NAME_WITH_ORDER = /
157
+ \A
158
+ (
159
+ (?:
160
+ # "table_name"."column_name" | function(one or no argument)
161
+ ((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")) | \w+\((?:|\g<2>)\)
162
+ )
163
+ (?:\s+ASC|\s+DESC)?
164
+ (?:\s+NULLS\s+(?:FIRST|LAST))?
165
+ )
166
+ (?:\s*,\s*\g<1>)*
167
+ \z
168
+ /ix
169
+ private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
136
170
 
171
+ private
137
172
  def oracle_downcase(column_name)
138
173
  return nil if column_name.nil?
139
174
  /[a-z]/.match?(column_name) ? column_name : column_name.downcase
@@ -143,8 +178,8 @@ module ActiveRecord
143
178
  end
144
179
  end
145
180
 
146
- # if MRI or YARV
147
- if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
181
+ # if MRI or YARV or TruffleRuby
182
+ if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby"
148
183
  require "active_record/connection_adapters/oracle_enhanced/oci_quoting"
149
184
  # if JRuby
150
185
  elsif RUBY_ENGINE == "jruby"
@@ -3,11 +3,10 @@
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module OracleEnhanced
6
- class SchemaCreation < AbstractAdapter::SchemaCreation
6
+ class SchemaCreation < SchemaCreation
7
7
  private
8
-
9
8
  def visit_ColumnDefinition(o)
10
- if [:blob, :clob, :nclob].include?(sql_type = type_to_sql(o.type, o.options).downcase.to_sym)
9
+ if [:blob, :clob, :nclob].include?(sql_type = type_to_sql(o.type, **o.options).downcase.to_sym)
11
10
  if (tablespace = default_tablespace_for(sql_type))
12
11
  @lob_tablespaces ||= {}
13
12
  @lob_tablespaces[o.name] = tablespace
@@ -36,7 +35,7 @@ module ActiveRecord
36
35
  create_sql << " TABLESPACE #{tablespace}"
37
36
  end
38
37
  end
39
- add_table_options!(create_sql, table_options(o))
38
+ add_table_options!(create_sql, o)
40
39
  create_sql << " AS #{to_sql(o.as)}" if o.as
41
40
  create_sql
42
41
  end
@@ -17,7 +17,7 @@ module ActiveRecord
17
17
  ].each do |column_type|
18
18
  module_eval <<-CODE, __FILE__, __LINE__ + 1
19
19
  def #{column_type}(*args, **options)
20
- args.each { |name| column(name, :#{column_type}, options) }
20
+ args.each { |name| column(name, :#{column_type}, **options) }
21
21
  end
22
22
  CODE
23
23
  end
@@ -4,7 +4,15 @@ module ActiveRecord #:nodoc:
4
4
  module ConnectionAdapters #:nodoc:
5
5
  module OracleEnhanced #:nodoc:
6
6
  class SchemaDumper < ConnectionAdapters::SchemaDumper #:nodoc:
7
+ DEFAULT_PRIMARY_KEY_COLUMN_SPEC = { precision: "38", null: "false" }.freeze
8
+ private_constant :DEFAULT_PRIMARY_KEY_COLUMN_SPEC
9
+
7
10
  private
11
+ def column_spec_for_primary_key(column)
12
+ spec = super
13
+ spec.except!(:precision) if prepare_column_options(column) == DEFAULT_PRIMARY_KEY_COLUMN_SPEC
14
+ spec
15
+ end
8
16
 
9
17
  def tables(stream)
10
18
  # do not include materialized views in schema dump - they should be created separately after schema creation
@@ -51,6 +59,7 @@ module ActiveRecord #:nodoc:
51
59
  else
52
60
  statement_parts = [ ("add_context_index " + remove_prefix_and_suffix(table).inspect) ]
53
61
  statement_parts << index.columns.inspect
62
+ statement_parts << ("sync: " + $1.inspect) if index.parameters =~ /SYNC\((.*?)\)/
54
63
  statement_parts << ("name: " + index.name.inspect)
55
64
  end
56
65
  else
@@ -72,7 +81,7 @@ module ActiveRecord #:nodoc:
72
81
  index_statements = indexes.map do |index|
73
82
  " t.index #{index_parts(index).join(', ')}" unless index.type == "CTXSYS.CONTEXT"
74
83
  end
75
- stream.puts index_statements.sort.join("\n")
84
+ stream.puts index_statements.compact.sort.join("\n")
76
85
  end
77
86
  end
78
87
 
@@ -107,7 +116,10 @@ module ActiveRecord #:nodoc:
107
116
  tbl.print ", primary_key: #{pk.inspect}" unless pk == "id"
108
117
  pkcol = columns.detect { |c| c.name == pk }
109
118
  pkcolspec = column_spec_for_primary_key(pkcol)
110
- if pkcolspec.present?
119
+ unless pkcolspec.empty?
120
+ if pkcolspec != pkcolspec.slice(:id, :default)
121
+ pkcolspec = { id: { type: pkcolspec.delete(:id), **pkcolspec }.compact }
122
+ end
111
123
  tbl.print ", #{format_colspec(pkcolspec)}"
112
124
  end
113
125
  when Array
@@ -168,8 +180,8 @@ module ActiveRecord #:nodoc:
168
180
 
169
181
  def extract_expression_for_virtual_column(column)
170
182
  column_name = column.name
171
- @connection.select_value(<<~SQL.squish, "Table comment", [bind_string("table_name", table_name.upcase), bind_string("column_name", column_name.upcase)]).inspect
172
- select data_default from all_tab_columns
183
+ @connection.select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name.upcase), bind_string("column_name", column_name.upcase)]).inspect
184
+ select /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ data_default from all_tab_columns
173
185
  where owner = SYS_CONTEXT('userenv', 'current_schema')
174
186
  and table_name = :table_name
175
187
  and column_name = :column_name
@@ -11,8 +11,9 @@ module ActiveRecord
11
11
  # see: abstract/schema_statements.rb
12
12
 
13
13
  def tables #:nodoc:
14
- select_values(<<~SQL.squish, "tables")
15
- SELECT DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name)
14
+ select_values(<<~SQL.squish, "SCHEMA")
15
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
16
+ DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name)
16
17
  FROM all_tables
17
18
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
18
19
  AND secondary = 'N'
@@ -43,8 +44,8 @@ module ActiveRecord
43
44
  table_owner, table_name = default_owner, real_name
44
45
  end
45
46
 
46
- select_values(<<~SQL.squish, "table exists", [bind_string("owner", table_owner), bind_string("table_name", table_name)]).any?
47
- SELECT owner, table_name
47
+ select_values(<<~SQL.squish, "SCHEMA", [bind_string("owner", table_owner), bind_string("table_name", table_name)]).any?
48
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ owner, table_name
48
49
  FROM all_tables
49
50
  WHERE owner = :owner
50
51
  AND table_name = :table_name
@@ -59,21 +60,23 @@ module ActiveRecord
59
60
  end
60
61
 
61
62
  def views # :nodoc:
62
- select_values(<<~SQL.squish, "views")
63
- SELECT LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
63
+ select_values(<<~SQL.squish, "SCHEMA")
64
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
65
+ LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
64
66
  SQL
65
67
  end
66
68
 
67
69
  def materialized_views #:nodoc:
68
- select_values(<<~SQL.squish, "materialized views")
69
- SELECT LOWER(mview_name) FROM all_mviews WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
70
+ select_values(<<~SQL.squish, "SCHEMA")
71
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
72
+ LOWER(mview_name) FROM all_mviews WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
70
73
  SQL
71
74
  end
72
75
 
73
76
  # get synonyms for schema dump
74
77
  def synonyms
75
- result = select_all(<<~SQL.squish, "synonyms")
76
- SELECT synonym_name, table_owner, table_name
78
+ result = select_all(<<~SQL.squish, "SCHEMA")
79
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ synonym_name, table_owner, table_name
77
80
  FROM all_synonyms where owner = SYS_CONTEXT('userenv', 'current_schema')
78
81
  SQL
79
82
 
@@ -87,8 +90,8 @@ module ActiveRecord
87
90
  (_owner, table_name) = @connection.describe(table_name)
88
91
  default_tablespace_name = default_tablespace
89
92
 
90
- result = select_all(<<~SQL.squish, "indexes", [bind_string("table_name", table_name)])
91
- SELECT LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
93
+ result = select_all(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
94
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
92
95
  i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
93
96
  LOWER(i.tablespace_name) AS tablespace_name,
94
97
  LOWER(c.column_name) AS column_name, e.column_expression,
@@ -117,8 +120,8 @@ module ActiveRecord
117
120
  statement_parameters = nil
118
121
  if row["index_type"] == "DOMAIN" && row["ityp_owner"] == "CTXSYS" && row["ityp_name"] == "CONTEXT"
119
122
  procedure_name = default_datastore_procedure(row["index_name"])
120
- source = select_values(<<~SQL.squish, "procedure", [bind_string("procedure_name", procedure_name.upcase)]).join
121
- SELECT text
123
+ source = select_values(<<~SQL.squish, "SCHEMA", [bind_string("procedure_name", procedure_name.upcase)]).join
124
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ text
122
125
  FROM all_source
123
126
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
124
127
  AND name = :procedure_name
@@ -196,19 +199,19 @@ module ActiveRecord
196
199
  # t.string :last_name, :comment => “Surname”
197
200
  # end
198
201
 
199
- def create_table(table_name, **options)
200
- create_sequence = options[:id] != false
201
- td = create_table_definition table_name, options
202
+ def create_table(table_name, id: :primary_key, primary_key: nil, force: nil, **options)
203
+ create_sequence = id != false
204
+ td = create_table_definition(
205
+ table_name, **options.extract!(:temporary, :options, :as, :comment, :tablespace, :organization)
206
+ )
202
207
 
203
- if options[:id] != false && !options[:as]
204
- pk = options.fetch(:primary_key) do
205
- Base.get_primary_key table_name.to_s.singularize
206
- end
208
+ if id && !td.as
209
+ pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
207
210
 
208
211
  if pk.is_a?(Array)
209
212
  td.primary_keys pk
210
213
  else
211
- td.primary_key pk, options.fetch(:id, :primary_key), options
214
+ td.primary_key pk, id, **options
212
215
  end
213
216
  end
214
217
 
@@ -226,8 +229,10 @@ module ActiveRecord
226
229
  yield td if block_given?
227
230
  create_sequence = create_sequence || td.create_sequence
228
231
 
229
- if options[:force] && data_source_exists?(table_name)
230
- drop_table(table_name, options)
232
+ if force && data_source_exists?(table_name)
233
+ drop_table(table_name, force: force, if_exists: true)
234
+ else
235
+ schema_cache.clear_data_source_cache!(table_name.to_s)
231
236
  end
232
237
 
233
238
  execute schema_creation.accept td
@@ -235,14 +240,14 @@ module ActiveRecord
235
240
  create_sequence_and_trigger(table_name, options) if create_sequence
236
241
 
237
242
  if supports_comments? && !supports_comments_in_create?
238
- if table_comment = options[:comment].presence
243
+ if table_comment = td.comment.presence
239
244
  change_table_comment(table_name, table_comment)
240
245
  end
241
246
  td.columns.each do |column|
242
247
  change_column_comment(table_name, column.name, column.comment) if column.comment.present?
243
248
  end
244
249
  end
245
- td.indexes.each { |c, o| add_index table_name, c, o }
250
+ td.indexes.each { |c, o| add_index table_name, c, **o }
246
251
 
247
252
  rebuild_primary_key_index_to_default_tablespace(table_name, options)
248
253
  end
@@ -251,13 +256,16 @@ module ActiveRecord
251
256
  if new_name.to_s.length > DatabaseLimits::IDENTIFIER_MAX_LENGTH
252
257
  raise ArgumentError, "New table name '#{new_name}' is too long; the limit is #{DatabaseLimits::IDENTIFIER_MAX_LENGTH} characters"
253
258
  end
259
+ schema_cache.clear_data_source_cache!(table_name.to_s)
260
+ schema_cache.clear_data_source_cache!(new_name.to_s)
254
261
  execute "RENAME #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
255
262
  execute "RENAME #{quote_table_name("#{table_name}_seq")} TO #{default_sequence_name(new_name)}" rescue nil
256
263
 
257
264
  rename_table_indexes(table_name, new_name)
258
265
  end
259
266
 
260
- def drop_table(table_name, options = {}) #:nodoc:
267
+ def drop_table(table_name, **options) #:nodoc:
268
+ schema_cache.clear_data_source_cache!(table_name.to_s)
261
269
  execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE CONSTRAINTS' if options[:force] == :cascade}"
262
270
  seq_name = options[:sequence_name] || default_sequence_name(table_name)
263
271
  execute "DROP SEQUENCE #{quote_table_name(seq_name)}" rescue nil
@@ -287,8 +295,8 @@ module ActiveRecord
287
295
  end
288
296
  end
289
297
 
290
- def add_index(table_name, column_name, options = {}) #:nodoc:
291
- index_name, index_type, quoted_column_names, tablespace, index_options = add_index_options(table_name, column_name, options)
298
+ def add_index(table_name, column_name, **options) #:nodoc:
299
+ index_name, index_type, quoted_column_names, tablespace, index_options = add_index_options(table_name, column_name, **options)
292
300
  execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{index_options}"
293
301
  if index_type == "UNIQUE"
294
302
  unless /\(.*\)/.match?(quoted_column_names)
@@ -306,13 +314,11 @@ module ActiveRecord
306
314
  index_type = options[:unique] ? "UNIQUE" : ""
307
315
  index_name = options[:name].to_s if options.key?(:name)
308
316
  tablespace = tablespace_for(:index, options[:tablespace])
309
- max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
310
- # TODO: This option is used for NOLOGGING, needs better argumetn name
317
+ # TODO: This option is used for NOLOGGING, needs better argument name
311
318
  index_options = options[:options]
312
319
 
313
- if index_name.to_s.length > max_index_length
314
- raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
315
- end
320
+ validate_index_length!(table_name, index_name, options.fetch(:internal, false))
321
+
316
322
  if table_exists?(table_name) && index_name_exists?(table_name, index_name)
317
323
  raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
318
324
  end
@@ -323,8 +329,8 @@ module ActiveRecord
323
329
 
324
330
  # Remove the given index from the table.
325
331
  # Gives warning if index does not exist
326
- def remove_index(table_name, options = {}) #:nodoc:
327
- index_name = index_name_for_remove(table_name, options)
332
+ def remove_index(table_name, column_name = nil, **options) #:nodoc:
333
+ index_name = index_name_for_remove(table_name, column_name, options)
328
334
  # TODO: It should execute only when index_type == "UNIQUE"
329
335
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
330
336
  execute "DROP INDEX #{quote_column_name(index_name)}"
@@ -361,8 +367,8 @@ module ActiveRecord
361
367
  # Will always query database and not index cache.
362
368
  def index_name_exists?(table_name, index_name)
363
369
  (_owner, table_name) = @connection.describe(table_name)
364
- result = select_value(<<~SQL.squish, "index name exists")
365
- SELECT 1 FROM all_indexes i
370
+ result = select_value(<<~SQL.squish, "SCHEMA")
371
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ 1 FROM all_indexes i
366
372
  WHERE i.owner = SYS_CONTEXT('userenv', 'current_schema')
367
373
  AND i.table_owner = SYS_CONTEXT('userenv', 'current_schema')
368
374
  AND i.table_name = '#{table_name}'
@@ -402,14 +408,14 @@ module ActiveRecord
402
408
  execute "DROP SYNONYM #{quote_table_name(name)}"
403
409
  end
404
410
 
405
- def add_reference(table_name, *args)
406
- OracleEnhanced::ReferenceDefinition.new(*args).add_to(update_table_definition(table_name, self))
411
+ def add_reference(table_name, ref_name, **options)
412
+ OracleEnhanced::ReferenceDefinition.new(ref_name, **options).add_to(update_table_definition(table_name, self))
407
413
  end
408
414
 
409
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
415
+ def add_column(table_name, column_name, type, **options) #:nodoc:
410
416
  type = aliased_types(type.to_s, type)
411
417
  at = create_alter_table table_name
412
- at.add_column(column_name, type, options)
418
+ at.add_column(column_name, type, **options)
413
419
  add_column_sql = schema_creation.accept at
414
420
  add_column_sql << tablespace_for((type_to_sql(type).downcase.to_sym), nil, table_name, column_name)
415
421
  execute add_column_sql
@@ -440,7 +446,7 @@ module ActiveRecord
440
446
  change_column table_name, column_name, column.sql_type, null: null
441
447
  end
442
448
 
443
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
449
+ def change_column(table_name, column_name, type, **options) #:nodoc:
444
450
  column = column_for(table_name, column_name)
445
451
 
446
452
  # remove :null option if its value is the same as current column definition
@@ -453,7 +459,7 @@ module ActiveRecord
453
459
  end
454
460
 
455
461
  td = create_table_definition(table_name)
456
- cd = td.new_column_definition(column.name, type, options)
462
+ cd = td.new_column_definition(column.name, type, **options)
457
463
  change_column_stmt = schema_creation.accept cd
458
464
  change_column_stmt << tablespace_for((type_to_sql(type).downcase.to_sym), nil, options[:table_name], options[:column_name]) if type
459
465
  change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{change_column_stmt}"
@@ -494,9 +500,10 @@ module ActiveRecord
494
500
  end
495
501
 
496
502
  def table_comment(table_name) #:nodoc:
503
+ # TODO
497
504
  (_owner, table_name) = @connection.describe(table_name)
498
- select_value(<<~SQL.squish, "Table comment", [bind_string("table_name", table_name)])
499
- SELECT comments FROM all_tab_comments
505
+ select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
506
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_tab_comments
500
507
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
501
508
  AND table_name = :table_name
502
509
  SQL
@@ -511,8 +518,8 @@ module ActiveRecord
511
518
  def column_comment(table_name, column_name) #:nodoc:
512
519
  # TODO: it does not exist in Abstract adapter
513
520
  (_owner, table_name) = @connection.describe(table_name)
514
- select_value(<<~SQL.squish, "Column comment", [bind_string("table_name", table_name), bind_string("column_name", column_name.upcase)])
515
- SELECT comments FROM all_col_comments
521
+ select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name), bind_string("column_name", column_name.upcase)])
522
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_col_comments
516
523
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
517
524
  AND table_name = :table_name
518
525
  AND column_name = :column_name
@@ -528,8 +535,8 @@ module ActiveRecord
528
535
  end
529
536
 
530
537
  def tablespace(table_name)
531
- select_value(<<~SQL.squish, "tablespace")
532
- SELECT tablespace_name
538
+ select_value(<<~SQL.squish, "SCHEMA")
539
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ tablespace_name
533
540
  FROM all_tables
534
541
  WHERE table_name='#{table_name.to_s.upcase}'
535
542
  AND owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -540,8 +547,8 @@ module ActiveRecord
540
547
  def foreign_keys(table_name) #:nodoc:
541
548
  (_owner, desc_table_name) = @connection.describe(table_name)
542
549
 
543
- fk_info = select_all(<<~SQL.squish, "Foreign Keys", [bind_string("desc_table_name", desc_table_name)])
544
- SELECT r.table_name to_table
550
+ fk_info = select_all(<<~SQL.squish, "SCHEMA", [bind_string("desc_table_name", desc_table_name)])
551
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ r.table_name to_table
545
552
  ,rc.column_name references_column
546
553
  ,cc.column_name
547
554
  ,c.constraint_name name
@@ -582,8 +589,8 @@ module ActiveRecord
582
589
  # REFERENTIAL INTEGRITY ====================================
583
590
 
584
591
  def disable_referential_integrity(&block) #:nodoc:
585
- old_constraints = select_all(<<~SQL.squish, "Foreign Keys to disable and enable")
586
- SELECT constraint_name, owner, table_name
592
+ old_constraints = select_all(<<~SQL.squish, "SCHEMA")
593
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ constraint_name, owner, table_name
587
594
  FROM all_constraints
588
595
  WHERE constraint_type = 'R'
589
596
  AND status = 'ENABLED'
@@ -614,13 +621,12 @@ module ActiveRecord
614
621
  end
615
622
 
616
623
  private
617
-
618
624
  def schema_creation
619
625
  OracleEnhanced::SchemaCreation.new self
620
626
  end
621
627
 
622
- def create_table_definition(*args)
623
- OracleEnhanced::TableDefinition.new(self, *args)
628
+ def create_table_definition(name, **options)
629
+ OracleEnhanced::TableDefinition.new(self, name, **options)
624
630
  end
625
631
 
626
632
  def new_column_from_field(table_name, field)
@@ -642,7 +648,7 @@ module ActiveRecord
642
648
  # If a default contains a newline these cleanup regexes need to
643
649
  # match newlines.
644
650
  field["data_default"].sub!(/^'(.*)'$/m, '\1')
645
- field["data_default"] = nil if field["data_default"] =~ /^(null|empty_[bc]lob\(\))$/i
651
+ field["data_default"] = nil if /^(null|empty_[bc]lob\(\))$/i.match?(field["data_default"])
646
652
  # TODO: Needs better fix to fallback "N" to false
647
653
  field["data_default"] = false if field["data_default"] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings
648
654
  end
@@ -699,7 +705,7 @@ module ActiveRecord
699
705
  return unless tablespace
700
706
 
701
707
  index_name = select_value(<<~SQL.squish, "Index name for primary key", [bind_string("table_name", table_name.upcase)])
702
- SELECT index_name FROM all_constraints
708
+ SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ index_name FROM all_constraints
703
709
  WHERE table_name = :table_name
704
710
  AND constraint_type = 'P'
705
711
  AND owner = SYS_CONTEXT('userenv', 'current_schema')