activerecord-oracle_enhanced-adapter 6.0.5 → 6.1.2

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +109 -4
  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 +9 -7
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +8 -9
  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 +2 -3
  14. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +0 -1
  15. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +2 -3
  16. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +2 -3
  17. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +15 -3
  18. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +43 -40
  19. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +19 -19
  20. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +2 -1
  21. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +52 -33
  22. data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
  23. data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
  24. data/lib/arel/visitors/oracle.rb +217 -0
  25. data/lib/arel/visitors/oracle12.rb +124 -0
  26. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +9 -3
  27. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +5 -0
  28. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +0 -1
  29. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +27 -0
  30. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +2 -2
  31. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +122 -0
  32. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +4 -2
  33. data/spec/spec_config.yaml.template +2 -2
  34. data/spec/spec_helper.rb +13 -2
  35. metadata +22 -20
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  # see: abstract/schema_statements.rb
12
12
 
13
13
  def tables #:nodoc:
14
- select_values(<<~SQL.squish, "tables")
14
+ select_values(<<~SQL.squish, "SCHEMA")
15
15
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
16
16
  DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name)
17
17
  FROM all_tables
@@ -44,7 +44,7 @@ module ActiveRecord
44
44
  table_owner, table_name = default_owner, real_name
45
45
  end
46
46
 
47
- select_values(<<~SQL.squish, "table exists", [bind_string("owner", table_owner), bind_string("table_name", table_name)]).any?
47
+ select_values(<<~SQL.squish, "SCHEMA", [bind_string("owner", table_owner), bind_string("table_name", table_name)]).any?
48
48
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ owner, table_name
49
49
  FROM all_tables
50
50
  WHERE owner = :owner
@@ -60,14 +60,14 @@ module ActiveRecord
60
60
  end
61
61
 
62
62
  def views # :nodoc:
63
- select_values(<<~SQL.squish, "views")
63
+ select_values(<<~SQL.squish, "SCHEMA")
64
64
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
65
65
  LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
66
66
  SQL
67
67
  end
68
68
 
69
69
  def materialized_views #:nodoc:
70
- select_values(<<~SQL.squish, "materialized views")
70
+ select_values(<<~SQL.squish, "SCHEMA")
71
71
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
72
72
  LOWER(mview_name) FROM all_mviews WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
73
73
  SQL
@@ -75,8 +75,8 @@ module ActiveRecord
75
75
 
76
76
  # get synonyms for schema dump
77
77
  def synonyms
78
- result = select_all(<<~SQL.squish, "synonyms")
79
- SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ synonym_name, table_owner, table_name
78
+ result = select_all(<<~SQL.squish, "SCHEMA")
79
+ SELECT synonym_name, table_owner, table_name
80
80
  FROM all_synonyms where owner = SYS_CONTEXT('userenv', 'current_schema')
81
81
  SQL
82
82
 
@@ -90,7 +90,7 @@ module ActiveRecord
90
90
  (_owner, table_name) = @connection.describe(table_name)
91
91
  default_tablespace_name = default_tablespace
92
92
 
93
- result = select_all(<<~SQL.squish, "indexes", [bind_string("table_name", table_name)])
93
+ result = select_all(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
94
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,
95
95
  i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
96
96
  LOWER(i.tablespace_name) AS tablespace_name,
@@ -120,7 +120,7 @@ module ActiveRecord
120
120
  statement_parameters = nil
121
121
  if row["index_type"] == "DOMAIN" && row["ityp_owner"] == "CTXSYS" && row["ityp_name"] == "CONTEXT"
122
122
  procedure_name = default_datastore_procedure(row["index_name"])
123
- source = select_values(<<~SQL.squish, "procedure", [bind_string("procedure_name", procedure_name.upcase)]).join
123
+ source = select_values(<<~SQL.squish, "SCHEMA", [bind_string("procedure_name", procedure_name.upcase)]).join
124
124
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ text
125
125
  FROM all_source
126
126
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -199,19 +199,19 @@ module ActiveRecord
199
199
  # t.string :last_name, :comment => “Surname”
200
200
  # end
201
201
 
202
- def create_table(table_name, **options)
203
- create_sequence = options[:id] != false
204
- 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
+ )
205
207
 
206
- if options[:id] != false && !options[:as]
207
- pk = options.fetch(:primary_key) do
208
- Base.get_primary_key table_name.to_s.singularize
209
- end
208
+ if id && !td.as
209
+ pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
210
210
 
211
211
  if pk.is_a?(Array)
212
212
  td.primary_keys pk
213
213
  else
214
- td.primary_key pk, options.fetch(:id, :primary_key), **options
214
+ td.primary_key pk, id, **options
215
215
  end
216
216
  end
217
217
 
@@ -229,8 +229,10 @@ module ActiveRecord
229
229
  yield td if block_given?
230
230
  create_sequence = create_sequence || td.create_sequence
231
231
 
232
- if options[:force] && data_source_exists?(table_name)
233
- 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)
234
236
  end
235
237
 
236
238
  execute schema_creation.accept td
@@ -238,14 +240,14 @@ module ActiveRecord
238
240
  create_sequence_and_trigger(table_name, options) if create_sequence
239
241
 
240
242
  if supports_comments? && !supports_comments_in_create?
241
- if table_comment = options[:comment].presence
243
+ if table_comment = td.comment.presence
242
244
  change_table_comment(table_name, table_comment)
243
245
  end
244
246
  td.columns.each do |column|
245
247
  change_column_comment(table_name, column.name, column.comment) if column.comment.present?
246
248
  end
247
249
  end
248
- td.indexes.each { |c, o| add_index table_name, c, o }
250
+ td.indexes.each { |c, o| add_index table_name, c, **o }
249
251
 
250
252
  rebuild_primary_key_index_to_default_tablespace(table_name, options)
251
253
  end
@@ -254,13 +256,16 @@ module ActiveRecord
254
256
  if new_name.to_s.length > DatabaseLimits::IDENTIFIER_MAX_LENGTH
255
257
  raise ArgumentError, "New table name '#{new_name}' is too long; the limit is #{DatabaseLimits::IDENTIFIER_MAX_LENGTH} characters"
256
258
  end
259
+ schema_cache.clear_data_source_cache!(table_name.to_s)
260
+ schema_cache.clear_data_source_cache!(new_name.to_s)
257
261
  execute "RENAME #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
258
262
  execute "RENAME #{quote_table_name("#{table_name}_seq")} TO #{default_sequence_name(new_name)}" rescue nil
259
263
 
260
264
  rename_table_indexes(table_name, new_name)
261
265
  end
262
266
 
263
- 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)
264
269
  execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE CONSTRAINTS' if options[:force] == :cascade}"
265
270
  seq_name = options[:sequence_name] || default_sequence_name(table_name)
266
271
  execute "DROP SEQUENCE #{quote_table_name(seq_name)}" rescue nil
@@ -290,7 +295,7 @@ module ActiveRecord
290
295
  end
291
296
  end
292
297
 
293
- def add_index(table_name, column_name, options = {}) #:nodoc:
298
+ def add_index(table_name, column_name, **options) #:nodoc:
294
299
  index_name, index_type, quoted_column_names, tablespace, index_options = add_index_options(table_name, column_name, **options)
295
300
  execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{index_options}"
296
301
  if index_type == "UNIQUE"
@@ -309,13 +314,11 @@ module ActiveRecord
309
314
  index_type = options[:unique] ? "UNIQUE" : ""
310
315
  index_name = options[:name].to_s if options.key?(:name)
311
316
  tablespace = tablespace_for(:index, options[:tablespace])
312
- max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length
313
- # TODO: This option is used for NOLOGGING, needs better argumetn name
317
+ # TODO: This option is used for NOLOGGING, needs better argument name
314
318
  index_options = options[:options]
315
319
 
316
- if index_name.to_s.length > max_index_length
317
- raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
318
- end
320
+ validate_index_length!(table_name, index_name, options.fetch(:internal, false))
321
+
319
322
  if table_exists?(table_name) && index_name_exists?(table_name, index_name)
320
323
  raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
321
324
  end
@@ -326,8 +329,8 @@ module ActiveRecord
326
329
 
327
330
  # Remove the given index from the table.
328
331
  # Gives warning if index does not exist
329
- def remove_index(table_name, options = {}) #:nodoc:
330
- 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)
331
334
  # TODO: It should execute only when index_type == "UNIQUE"
332
335
  execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
333
336
  execute "DROP INDEX #{quote_column_name(index_name)}"
@@ -364,7 +367,7 @@ module ActiveRecord
364
367
  # Will always query database and not index cache.
365
368
  def index_name_exists?(table_name, index_name)
366
369
  (_owner, table_name) = @connection.describe(table_name)
367
- result = select_value(<<~SQL.squish, "index name exists")
370
+ result = select_value(<<~SQL.squish, "SCHEMA")
368
371
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ 1 FROM all_indexes i
369
372
  WHERE i.owner = SYS_CONTEXT('userenv', 'current_schema')
370
373
  AND i.table_owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -443,7 +446,7 @@ module ActiveRecord
443
446
  change_column table_name, column_name, column.sql_type, null: null
444
447
  end
445
448
 
446
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
449
+ def change_column(table_name, column_name, type, **options) #:nodoc:
447
450
  column = column_for(table_name, column_name)
448
451
 
449
452
  # remove :null option if its value is the same as current column definition
@@ -497,8 +500,9 @@ module ActiveRecord
497
500
  end
498
501
 
499
502
  def table_comment(table_name) #:nodoc:
503
+ # TODO
500
504
  (_owner, table_name) = @connection.describe(table_name)
501
- select_value(<<~SQL.squish, "Table comment", [bind_string("table_name", table_name)])
505
+ select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
502
506
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_tab_comments
503
507
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
504
508
  AND table_name = :table_name
@@ -514,7 +518,7 @@ module ActiveRecord
514
518
  def column_comment(table_name, column_name) #:nodoc:
515
519
  # TODO: it does not exist in Abstract adapter
516
520
  (_owner, table_name) = @connection.describe(table_name)
517
- select_value(<<~SQL.squish, "Column comment", [bind_string("table_name", table_name), bind_string("column_name", column_name.upcase)])
521
+ select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name), bind_string("column_name", column_name.upcase)])
518
522
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_col_comments
519
523
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
520
524
  AND table_name = :table_name
@@ -531,7 +535,7 @@ module ActiveRecord
531
535
  end
532
536
 
533
537
  def tablespace(table_name)
534
- select_value(<<~SQL.squish, "tablespace")
538
+ select_value(<<~SQL.squish, "SCHEMA")
535
539
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ tablespace_name
536
540
  FROM all_tables
537
541
  WHERE table_name='#{table_name.to_s.upcase}'
@@ -543,7 +547,7 @@ module ActiveRecord
543
547
  def foreign_keys(table_name) #:nodoc:
544
548
  (_owner, desc_table_name) = @connection.describe(table_name)
545
549
 
546
- fk_info = select_all(<<~SQL.squish, "Foreign Keys", [bind_string("desc_table_name", desc_table_name)])
550
+ fk_info = select_all(<<~SQL.squish, "SCHEMA", [bind_string("desc_table_name", desc_table_name)])
547
551
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ r.table_name to_table
548
552
  ,rc.column_name references_column
549
553
  ,cc.column_name
@@ -585,7 +589,7 @@ module ActiveRecord
585
589
  # REFERENTIAL INTEGRITY ====================================
586
590
 
587
591
  def disable_referential_integrity(&block) #:nodoc:
588
- old_constraints = select_all(<<~SQL.squish, "Foreign Keys to disable and enable")
592
+ old_constraints = select_all(<<~SQL.squish, "SCHEMA")
589
593
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ constraint_name, owner, table_name
590
594
  FROM all_constraints
591
595
  WHERE constraint_type = 'R'
@@ -617,13 +621,12 @@ module ActiveRecord
617
621
  end
618
622
 
619
623
  private
620
-
621
624
  def schema_creation
622
625
  OracleEnhanced::SchemaCreation.new self
623
626
  end
624
627
 
625
- def create_table_definition(*args, **options)
626
- OracleEnhanced::TableDefinition.new(self, *args, **options)
628
+ def create_table_definition(name, **options)
629
+ OracleEnhanced::TableDefinition.new(self, name, **options)
627
630
  end
628
631
 
629
632
  def new_column_from_field(table_name, field)
@@ -645,7 +648,7 @@ module ActiveRecord
645
648
  # If a default contains a newline these cleanup regexes need to
646
649
  # match newlines.
647
650
  field["data_default"].sub!(/^'(.*)'$/m, '\1')
648
- 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"])
649
652
  # TODO: Needs better fix to fallback "N" to false
650
653
  field["data_default"] = false if field["data_default"] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings
651
654
  end
@@ -8,7 +8,7 @@ module ActiveRecord #:nodoc:
8
8
  STATEMENT_TOKEN = "\n\n/\n\n"
9
9
 
10
10
  def structure_dump #:nodoc:
11
- sequences = select(<<~SQL.squish, "sequences to dump at structure dump")
11
+ sequences = select(<<~SQL.squish, "SCHEMA")
12
12
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
13
13
  sequence_name, min_value, max_value, increment_by, order_flag, cycle_flag
14
14
  FROM all_sequences
@@ -18,7 +18,7 @@ module ActiveRecord #:nodoc:
18
18
  structure = sequences.map do |result|
19
19
  "CREATE SEQUENCE #{quote_table_name(result["sequence_name"])} MINVALUE #{result["min_value"]} MAXVALUE #{result["max_value"]} INCREMENT BY #{result["increment_by"]} #{result["order_flag"] == 'Y' ? "ORDER" : "NOORDER"} #{result["cycle_flag"] == 'Y' ? "CYCLE" : "NOCYCLE"}"
20
20
  end
21
- tables = select_values(<<~SQL.squish, "tables at structure dump")
21
+ tables = select_values(<<~SQL.squish, "SCHEMA")
22
22
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name FROM all_tables t
23
23
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
24
24
  AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
@@ -30,7 +30,7 @@ module ActiveRecord #:nodoc:
30
30
  tables.each do |table_name|
31
31
  virtual_columns = virtual_columns_for(table_name) if supports_virtual_columns?
32
32
  ddl = +"CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n"
33
- columns = select_all(<<~SQL.squish, "columns at structure dump")
33
+ columns = select_all(<<~SQL.squish, "SCHEMA")
34
34
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ column_name, data_type, data_length, char_used, char_length,
35
35
  data_precision, data_scale, data_default, nullable
36
36
  FROM all_tab_columns
@@ -55,8 +55,9 @@ module ActiveRecord #:nodoc:
55
55
  structure << structure_dump_column_comments(table_name)
56
56
  end
57
57
 
58
- join_with_statement_token(structure) << structure_dump_fk_constraints
59
- join_with_statement_token(structure) << structure_dump_views
58
+ join_with_statement_token(structure) <<
59
+ structure_dump_fk_constraints <<
60
+ structure_dump_views
60
61
  end
61
62
 
62
63
  def structure_dump_column(column) #:nodoc:
@@ -90,7 +91,7 @@ module ActiveRecord #:nodoc:
90
91
 
91
92
  def structure_dump_primary_key(table) #:nodoc:
92
93
  opts = { name: "", cols: [] }
93
- pks = select_all(<<~SQL.squish, "Primary Keys")
94
+ pks = select_all(<<~SQL.squish, "SCHEMA")
94
95
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ a.constraint_name, a.column_name, a.position
95
96
  FROM all_cons_columns a
96
97
  JOIN all_constraints c
@@ -109,7 +110,7 @@ module ActiveRecord #:nodoc:
109
110
 
110
111
  def structure_dump_unique_keys(table) #:nodoc:
111
112
  keys = {}
112
- uks = select_all(<<~SQL.squish, "Primary Keys")
113
+ uks = select_all(<<~SQL.squish, "SCHEMA")
113
114
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ a.constraint_name, a.column_name, a.position
114
115
  FROM all_cons_columns a
115
116
  JOIN all_constraints c
@@ -145,7 +146,7 @@ module ActiveRecord #:nodoc:
145
146
  end
146
147
 
147
148
  def structure_dump_fk_constraints #:nodoc:
148
- foreign_keys = select_all(<<~SQL.squish, "foreign keys at structure dump")
149
+ foreign_keys = select_all(<<~SQL.squish, "SCHEMA")
149
150
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name FROM all_tables
150
151
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
151
152
  SQL
@@ -173,7 +174,7 @@ module ActiveRecord #:nodoc:
173
174
 
174
175
  def structure_dump_column_comments(table_name)
175
176
  comments = []
176
- columns = select_values(<<~SQL.squish, "column comments at structure dump")
177
+ columns = select_values(<<~SQL.squish, "SCHEMA")
177
178
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ column_name FROM user_tab_columns
178
179
  WHERE table_name = '#{table_name}' ORDER BY column_id
179
180
  SQL
@@ -207,7 +208,7 @@ module ActiveRecord #:nodoc:
207
208
  # Extract all stored procedures, packages, synonyms.
208
209
  def structure_dump_db_stored_code #:nodoc:
209
210
  structure = []
210
- all_source = select_all(<<~SQL.squish, "stored program at structure dump")
211
+ all_source = select_all(<<~SQL.squish, "SCHEMA")
211
212
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ DISTINCT name, type
212
213
  FROM all_source
213
214
  WHERE type IN ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
@@ -239,7 +240,7 @@ module ActiveRecord #:nodoc:
239
240
 
240
241
  def structure_dump_views #:nodoc:
241
242
  structure = []
242
- views = select_all(<<~SQL.squish, "views at structure dump")
243
+ views = select_all(<<~SQL.squish, "SCHEMA")
243
244
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ view_name, text FROM all_views
244
245
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY view_name ASC
245
246
  SQL
@@ -251,7 +252,7 @@ module ActiveRecord #:nodoc:
251
252
 
252
253
  def structure_dump_synonyms #:nodoc:
253
254
  structure = []
254
- synonyms = select_all(<<~SQL.squish, "synonyms at structure dump")
255
+ synonyms = select_all(<<~SQL.squish, "SCHEMA")
255
256
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ owner, synonym_name, table_name, table_owner
256
257
  FROM all_synonyms
257
258
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -264,14 +265,14 @@ module ActiveRecord #:nodoc:
264
265
  end
265
266
 
266
267
  def structure_drop #:nodoc:
267
- sequences = select_values(<<~SQL.squish, "sequences to drop at structure dump")
268
+ sequences = select_values(<<~SQL.squish, "SCHEMA")
268
269
  SELECT/*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
269
270
  sequence_name FROM all_sequences where sequence_owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY 1
270
271
  SQL
271
272
  statements = sequences.map do |seq|
272
273
  "DROP SEQUENCE \"#{seq}\""
273
274
  end
274
- tables = select_values(<<~SQL.squish, "tables to drop at structure dump")
275
+ tables = select_values(<<~SQL.squish, "SCHEMA")
275
276
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name from all_tables t
276
277
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
277
278
  AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv
@@ -287,7 +288,7 @@ module ActiveRecord #:nodoc:
287
288
  end
288
289
 
289
290
  def temp_table_drop #:nodoc:
290
- temporary_tables = select_values(<<~SQL.squish, "temporary tables to drop at structure dump")
291
+ temporary_tables = select_values(<<~SQL.squish, "SCHEMA")
291
292
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ table_name FROM all_tables
292
293
  WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
293
294
  AND secondary = 'N' AND temporary = 'Y' ORDER BY 1
@@ -318,11 +319,10 @@ module ActiveRecord #:nodoc:
318
319
  end
319
320
 
320
321
  private
321
-
322
322
  # Called only if `supports_virtual_columns?` returns true
323
323
  # return [{'column_name' => 'FOOS', 'data_default' => '...'}, ...]
324
324
  def virtual_columns_for(table)
325
- select_all(<<~SQL.squish, "virtual columns for")
325
+ select_all(<<~SQL.squish, "SCHEMA")
326
326
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ column_name, data_default
327
327
  FROM all_tab_cols
328
328
  WHERE virtual_column = 'YES'
@@ -333,7 +333,7 @@ module ActiveRecord #:nodoc:
333
333
 
334
334
  def drop_sql_for_feature(type)
335
335
  short_type = type == "materialized view" ? "mview" : type
336
- features = select_values(<<~SQL.squish, "features to drop")
336
+ features = select_values(<<~SQL.squish, "SCHEMA")
337
337
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ #{short_type}_name FROM all_#{short_type.tableize}
338
338
  where owner = SYS_CONTEXT('userenv', 'current_schema')
339
339
  SQL
@@ -344,7 +344,7 @@ module ActiveRecord #:nodoc:
344
344
  end
345
345
 
346
346
  def drop_sql_for_object(type)
347
- objects = select_values(<<~SQL.squish, "objects to drop")
347
+ objects = select_values(<<~SQL.squish, "SCHEMA")
348
348
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ object_name FROM all_objects
349
349
  WHERE object_type = '#{type.upcase}' and owner = SYS_CONTEXT('userenv', 'current_schema')
350
350
  SQL
@@ -4,6 +4,8 @@ module ActiveRecord
4
4
  module ConnectionAdapters #:nodoc:
5
5
  module OracleEnhanced
6
6
  class TypeMetadata < DelegateClass(ActiveRecord::ConnectionAdapters::SqlTypeMetadata) # :nodoc:
7
+ include Deduplicable
8
+
7
9
  attr_reader :virtual
8
10
 
9
11
  def initialize(type_metadata, virtual: nil)
@@ -23,7 +25,6 @@ module ActiveRecord
23
25
  end
24
26
 
25
27
  protected
26
-
27
28
  def attributes_for_hash
28
29
  [self.class, @type_metadata, virtual]
29
30
  end
@@ -30,6 +30,9 @@
30
30
  # contribution.
31
31
  # portions Copyright 2005 Graham Jenkins
32
32
 
33
+ require "arel/visitors/oracle"
34
+ require "arel/visitors/oracle12"
35
+ require "active_record/connection_adapters"
33
36
  require "active_record/connection_adapters/abstract_adapter"
34
37
  require "active_record/connection_adapters/statement_pool"
35
38
  require "active_record/connection_adapters/oracle_enhanced/connection"
@@ -213,13 +216,24 @@ module ActiveRecord
213
216
  cattr_accessor :use_shorter_identifier
214
217
  self.use_shorter_identifier = false
215
218
 
219
+ ##
220
+ # :singleton-method:
221
+ # By default, OracleEnhanced adapter will grant unlimited tablespace, create session, create table, create view,
222
+ # and create sequence when running the rake task db:create.
223
+ #
224
+ # If you wish to change these permissions you can add the following line to your initializer file:
225
+ #
226
+ # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.permissions =
227
+ # ["create session", "create table", "create view", "create sequence", "create trigger", "ctxapp"]
228
+ cattr_accessor :permissions
229
+ self.permissions = ["create session", "create table", "create view", "create sequence"]
230
+
216
231
  ##
217
232
  # :singleton-method:
218
233
  # Specify default sequence start with value (by default 1 if not explicitly set), e.g.:
219
234
 
220
235
  class StatementPool < ConnectionAdapters::StatementPool
221
236
  private
222
-
223
237
  def dealloc(stmt)
224
238
  stmt.close
225
239
  end
@@ -238,6 +252,14 @@ module ActiveRecord
238
252
  ADAPTER_NAME
239
253
  end
240
254
 
255
+ # Oracle enhanced adapter has no implementation because
256
+ # Oracle Database cannot detect `NoDatabaseError`.
257
+ # Please refer to the following discussion for details.
258
+ # https://github.com/rsim/oracle-enhanced/pull/1900
259
+ def self.database_exists?(config)
260
+ raise NotImplementedError
261
+ end
262
+
241
263
  def arel_visitor # :nodoc:
242
264
  if supports_fetch_first_n_rows_and_offset?
243
265
  Arel::Visitors::Oracle12.new(self)
@@ -266,6 +288,10 @@ module ActiveRecord
266
288
  true
267
289
  end
268
290
 
291
+ def supports_common_table_expressions?
292
+ true
293
+ end
294
+
269
295
  def supports_views?
270
296
  true
271
297
  end
@@ -438,6 +464,7 @@ module ActiveRecord
438
464
  end
439
465
 
440
466
  def discard!
467
+ super
441
468
  @connection = nil
442
469
  end
443
470
 
@@ -451,7 +478,7 @@ module ActiveRecord
451
478
  # if sequence_name is set to :autogenerated then it means that primary key will be populated by trigger
452
479
  raise ArgumentError.new "Trigger based primary key is not supported" if sequence_name == AUTOGENERATED_SEQUENCE_NAME
453
480
  # call directly connection method to avoid prepared statement which causes fetching of next sequence value twice
454
- select_value(<<~SQL.squish, "next sequence value")
481
+ select_value(<<~SQL.squish, "SCHEMA")
455
482
  SELECT #{quote_table_name(sequence_name)}.NEXTVAL FROM dual
456
483
  SQL
457
484
  end
@@ -489,7 +516,7 @@ module ActiveRecord
489
516
  end
490
517
 
491
518
  if primary_key && sequence_name
492
- new_start_value = select_value(<<~SQL.squish, "new start value")
519
+ new_start_value = select_value(<<~SQL.squish, "SCHEMA")
493
520
  select NVL(max(#{quote_column_name(primary_key)}),0) + 1 from #{quote_table_name(table_name)}
494
521
  SQL
495
522
 
@@ -500,32 +527,32 @@ module ActiveRecord
500
527
 
501
528
  # Current database name
502
529
  def current_database
503
- select_value(<<~SQL.squish, "current database on CDB ")
530
+ select_value(<<~SQL.squish, "SCHEMA")
504
531
  SELECT SYS_CONTEXT('userenv', 'con_name') FROM dual
505
532
  SQL
506
533
  rescue ActiveRecord::StatementInvalid
507
- select_value(<<~SQL.squish, "current database")
534
+ select_value(<<~SQL.squish, "SCHEMA")
508
535
  SELECT SYS_CONTEXT('userenv', 'db_name') FROM dual
509
536
  SQL
510
537
  end
511
538
 
512
539
  # Current database session user
513
540
  def current_user
514
- select_value(<<~SQL.squish, "current user")
541
+ select_value(<<~SQL.squish, "SCHEMA")
515
542
  SELECT SYS_CONTEXT('userenv', 'session_user') FROM dual
516
543
  SQL
517
544
  end
518
545
 
519
546
  # Current database session schema
520
547
  def current_schema
521
- select_value(<<~SQL.squish, "current schema")
548
+ select_value(<<~SQL.squish, "SCHEMA")
522
549
  SELECT SYS_CONTEXT('userenv', 'current_schema') FROM dual
523
550
  SQL
524
551
  end
525
552
 
526
553
  # Default tablespace name of current user
527
554
  def default_tablespace
528
- select_value(<<~SQL.squish, "default tablespace")
555
+ select_value(<<~SQL.squish, "SCHEMA")
529
556
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ LOWER(default_tablespace) FROM user_users
530
557
  WHERE username = SYS_CONTEXT('userenv', 'current_schema')
531
558
  SQL
@@ -534,7 +561,7 @@ module ActiveRecord
534
561
  def column_definitions(table_name)
535
562
  (owner, desc_table_name) = @connection.describe(table_name)
536
563
 
537
- select_all(<<~SQL.squish, "Column definitions")
564
+ select_all(<<~SQL.squish, "SCHEMA")
538
565
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cols.column_name AS name, cols.data_type AS sql_type,
539
566
  cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
540
567
  cols.data_type_owner AS sql_type_owner,
@@ -566,7 +593,7 @@ module ActiveRecord
566
593
  def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil) #:nodoc:
567
594
  (owner, desc_table_name) = @connection.describe(table_name)
568
595
 
569
- seqs = select_values(<<~SQL.squish, "Sequence")
596
+ seqs = select_values(<<~SQL.squish, "SCHEMA")
570
597
  select /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ us.sequence_name
571
598
  from all_sequences us
572
599
  where us.sequence_owner = '#{owner}'
@@ -574,7 +601,7 @@ module ActiveRecord
574
601
  SQL
575
602
 
576
603
  # changed back from user_constraints to all_constraints for consistency
577
- pks = select_values(<<~SQL.squish, "Primary Key")
604
+ pks = select_values(<<~SQL.squish, "SCHEMA")
578
605
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
579
606
  FROM all_constraints c, all_cons_columns cc
580
607
  WHERE c.owner = '#{owner}'
@@ -608,7 +635,7 @@ module ActiveRecord
608
635
  def primary_keys(table_name) # :nodoc:
609
636
  (_owner, desc_table_name) = @connection.describe(table_name)
610
637
 
611
- pks = select_values(<<~SQL.squish, "Primary Keys", [bind_string("table_name", desc_table_name)])
638
+ pks = select_values(<<~SQL.squish, "SCHEMA", [bind_string("table_name", desc_table_name)])
612
639
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
613
640
  FROM all_constraints c, all_cons_columns cc
614
641
  WHERE c.owner = SYS_CONTEXT('userenv', 'current_schema')
@@ -628,7 +655,7 @@ module ActiveRecord
628
655
  #
629
656
  # It does not construct DISTINCT clause. Just return column names for distinct.
630
657
  order_columns = orders.reject(&:blank?).map { |s|
631
- s = s.to_sql unless s.is_a?(String)
658
+ s = visitor.compile(s) unless s.is_a?(String)
632
659
  # remove any ASC/DESC modifiers
633
660
  s.gsub(/\s+(ASC|DESC)\s*?/i, "")
634
661
  }.reject(&:blank?).map.with_index { |column, i|
@@ -638,7 +665,7 @@ module ActiveRecord
638
665
  end
639
666
 
640
667
  def temporary_table?(table_name) #:nodoc:
641
- select_value(<<~SQL.squish, "temporary table", [bind_string("table_name", table_name.upcase)]) == "Y"
668
+ select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name.upcase)]) == "Y"
642
669
  SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
643
670
  temporary FROM all_tables WHERE table_name = :table_name and owner = SYS_CONTEXT('userenv', 'current_schema')
644
671
  SQL
@@ -748,25 +775,17 @@ module ActiveRecord
748
775
  autoload :OracleEnhancedProcedures, "active_record/connection_adapters/oracle_enhanced/procedures"
749
776
  end
750
777
 
751
- # Backport #2070 into relese60 branch by adding some dirty monkey patch
752
- # Because #2002 has been merged to release61 branch or newer, not available for release60 branch.
753
- module Arel # :nodoc: all
754
- module Visitors
755
- class Oracle < Arel::Visitors::ToSql
756
- private
757
- def build_subselect(key, o)
758
- stmt = super
759
- stmt.orders = [] # `orders` will never be set to prevent `ORA-00907`.
760
- stmt
761
- end
762
- end
763
- class Oracle12 < Arel::Visitors::ToSql
764
- private
765
- def build_subselect(key, o)
766
- stmt = super
767
- stmt.orders = [] # `orders` will never be set to prevent `ORA-00907`.
768
- stmt
769
- end
778
+ # Workaround for https://github.com/jruby/jruby/issues/6267
779
+ if RUBY_ENGINE == "jruby"
780
+ require "jruby"
781
+
782
+ class org.jruby::RubyObjectSpace::WeakMap
783
+ field_reader :map
784
+ end
785
+
786
+ class ObjectSpace::WeakMap
787
+ def values
788
+ JRuby.ref(self).map.values.reject(&:nil?)
770
789
  end
771
790
  end
772
791
  end