activerecord-oracle_enhanced-adapter 5.2.8 → 7.0.3
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.
- checksums.yaml +4 -4
- data/History.md +390 -21
- data/README.md +35 -8
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +42 -37
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +59 -60
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +5 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +86 -81
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +9 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +37 -16
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +5 -6
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +58 -49
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +6 -7
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +75 -51
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +13 -14
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +14 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +27 -24
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +156 -155
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +103 -90
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +3 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +261 -161
- data/lib/active_record/type/oracle_enhanced/boolean.rb +0 -1
- data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
- data/lib/active_record/type/oracle_enhanced/integer.rb +0 -1
- data/lib/arel/visitors/oracle.rb +221 -0
- data/lib/arel/visitors/oracle12.rb +128 -0
- data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +0 -2
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +78 -26
- data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +7 -15
- data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +5 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +17 -17
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +7 -10
- data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +0 -15
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +33 -36
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +77 -258
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +38 -39
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +273 -85
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +7 -8
- data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +2 -4
- data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +43 -0
- data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
- data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
- data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +1 -1
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +2 -2
- data/spec/active_record/oracle_enhanced/type/json_spec.rb +0 -1
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +6 -5
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +2 -4
- data/spec/spec_config.yaml.template +2 -2
- data/spec/spec_helper.rb +13 -2
- metadata +52 -30
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +0 -28
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "openssl"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
6
|
module ConnectionAdapters
|
@@ -10,13 +10,18 @@ module ActiveRecord
|
|
10
10
|
#
|
11
11
|
# see: abstract/schema_statements.rb
|
12
12
|
|
13
|
-
def tables
|
14
|
-
select_values(
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def tables # :nodoc:
|
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)
|
17
|
+
FROM all_tables
|
18
|
+
WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
|
19
|
+
AND secondary = 'N'
|
20
|
+
minus
|
21
|
+
SELECT DECODE(mview_name, UPPER(mview_name), LOWER(mview_name), mview_name)
|
22
|
+
FROM all_mviews
|
23
|
+
WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
|
24
|
+
SQL
|
20
25
|
end
|
21
26
|
|
22
27
|
def data_sources
|
@@ -39,64 +44,66 @@ module ActiveRecord
|
|
39
44
|
table_owner, table_name = default_owner, real_name
|
40
45
|
end
|
41
46
|
|
42
|
-
select_values(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
49
|
+
FROM all_tables
|
50
|
+
WHERE owner = :owner
|
51
|
+
AND table_name = :table_name
|
52
|
+
SQL
|
48
53
|
end
|
49
54
|
|
50
55
|
def data_source_exists?(table_name)
|
51
|
-
(_owner,
|
56
|
+
(_owner, _table_name) = @connection.describe(table_name)
|
52
57
|
true
|
53
58
|
rescue
|
54
59
|
false
|
55
60
|
end
|
56
61
|
|
57
62
|
def views # :nodoc:
|
58
|
-
select_values(
|
59
|
-
SELECT
|
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')
|
60
66
|
SQL
|
61
67
|
end
|
62
68
|
|
63
|
-
def materialized_views
|
64
|
-
select_values(
|
65
|
-
SELECT
|
69
|
+
def materialized_views # :nodoc:
|
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')
|
66
73
|
SQL
|
67
74
|
end
|
68
75
|
|
69
76
|
# get synonyms for schema dump
|
70
77
|
def synonyms
|
71
|
-
result = select_all(
|
72
|
-
|
73
|
-
|
74
|
-
|
78
|
+
result = select_all(<<~SQL.squish, "SCHEMA")
|
79
|
+
SELECT synonym_name, table_owner, table_name
|
80
|
+
FROM all_synonyms where owner = SYS_CONTEXT('userenv', 'current_schema')
|
81
|
+
SQL
|
75
82
|
|
76
83
|
result.collect do |row|
|
77
84
|
OracleEnhanced::SynonymDefinition.new(oracle_downcase(row["synonym_name"]),
|
78
|
-
oracle_downcase(row["table_owner"]), oracle_downcase(row["table_name"])
|
85
|
+
oracle_downcase(row["table_owner"]), oracle_downcase(row["table_name"]))
|
79
86
|
end
|
80
87
|
end
|
81
88
|
|
82
|
-
def indexes(table_name)
|
83
|
-
(
|
89
|
+
def indexes(table_name) # :nodoc:
|
90
|
+
(_owner, table_name) = @connection.describe(table_name)
|
84
91
|
default_tablespace_name = default_tablespace
|
85
92
|
|
86
|
-
result = select_all(
|
87
|
-
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,
|
88
95
|
i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
|
89
96
|
LOWER(i.tablespace_name) AS tablespace_name,
|
90
97
|
LOWER(c.column_name) AS column_name, e.column_expression,
|
91
98
|
atc.virtual_column
|
92
|
-
FROM all_indexes
|
93
|
-
JOIN all_ind_columns
|
94
|
-
LEFT OUTER JOIN all_ind_expressions
|
99
|
+
FROM all_indexes i
|
100
|
+
JOIN all_ind_columns c ON c.index_name = i.index_name AND c.index_owner = i.owner
|
101
|
+
LEFT OUTER JOIN all_ind_expressions e ON e.index_name = i.index_name AND
|
95
102
|
e.index_owner = i.owner AND e.column_position = c.column_position
|
96
|
-
LEFT OUTER JOIN all_tab_cols
|
103
|
+
LEFT OUTER JOIN all_tab_cols atc ON i.table_name = atc.table_name AND
|
97
104
|
c.column_name = atc.column_name AND i.owner = atc.owner AND atc.hidden_column = 'NO'
|
98
|
-
WHERE i.owner =
|
99
|
-
AND i.table_owner =
|
105
|
+
WHERE i.owner = SYS_CONTEXT('userenv', 'current_schema')
|
106
|
+
AND i.table_owner = SYS_CONTEXT('userenv', 'current_schema')
|
100
107
|
AND i.table_name = :table_name
|
101
108
|
AND NOT EXISTS (SELECT uc.index_name FROM all_constraints uc
|
102
109
|
WHERE uc.index_name = i.index_name AND uc.owner = i.owner AND uc.constraint_type = 'P')
|
@@ -113,10 +120,10 @@ module ActiveRecord
|
|
113
120
|
statement_parameters = nil
|
114
121
|
if row["index_type"] == "DOMAIN" && row["ityp_owner"] == "CTXSYS" && row["ityp_name"] == "CONTEXT"
|
115
122
|
procedure_name = default_datastore_procedure(row["index_name"])
|
116
|
-
source = select_values(
|
117
|
-
SELECT text
|
118
|
-
FROM all_source
|
119
|
-
WHERE owner =
|
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
|
125
|
+
FROM all_source
|
126
|
+
WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
|
120
127
|
AND name = :procedure_name
|
121
128
|
ORDER BY line
|
122
129
|
SQL
|
@@ -192,19 +199,19 @@ module ActiveRecord
|
|
192
199
|
# t.string :last_name, :comment => “Surname”
|
193
200
|
# end
|
194
201
|
|
195
|
-
def create_table(table_name,
|
196
|
-
create_sequence =
|
197
|
-
td = create_table_definition
|
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
|
+
)
|
198
207
|
|
199
|
-
if
|
200
|
-
pk =
|
201
|
-
Base.get_primary_key table_name.to_s.singularize
|
202
|
-
end
|
208
|
+
if id && !td.as
|
209
|
+
pk = primary_key || Base.get_primary_key(table_name.to_s.singularize)
|
203
210
|
|
204
211
|
if pk.is_a?(Array)
|
205
212
|
td.primary_keys pk
|
206
213
|
else
|
207
|
-
td.primary_key pk,
|
214
|
+
td.primary_key pk, id, **options
|
208
215
|
end
|
209
216
|
end
|
210
217
|
|
@@ -222,8 +229,10 @@ module ActiveRecord
|
|
222
229
|
yield td if block_given?
|
223
230
|
create_sequence = create_sequence || td.create_sequence
|
224
231
|
|
225
|
-
if
|
226
|
-
drop_table(table_name,
|
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)
|
227
236
|
end
|
228
237
|
|
229
238
|
execute schema_creation.accept td
|
@@ -231,27 +240,32 @@ module ActiveRecord
|
|
231
240
|
create_sequence_and_trigger(table_name, options) if create_sequence
|
232
241
|
|
233
242
|
if supports_comments? && !supports_comments_in_create?
|
234
|
-
|
243
|
+
if table_comment = td.comment.presence
|
244
|
+
change_table_comment(table_name, table_comment)
|
245
|
+
end
|
235
246
|
td.columns.each do |column|
|
236
247
|
change_column_comment(table_name, column.name, column.comment) if column.comment.present?
|
237
248
|
end
|
238
249
|
end
|
239
|
-
td.indexes.each { |c, o| add_index table_name, c, o }
|
250
|
+
td.indexes.each { |c, o| add_index table_name, c, **o }
|
240
251
|
|
241
252
|
rebuild_primary_key_index_to_default_tablespace(table_name, options)
|
242
253
|
end
|
243
254
|
|
244
|
-
def rename_table(table_name, new_name)
|
245
|
-
if new_name.to_s.length >
|
246
|
-
raise ArgumentError, "New table name '#{new_name}' is too long; the limit is #{
|
255
|
+
def rename_table(table_name, new_name) # :nodoc:
|
256
|
+
if new_name.to_s.length > DatabaseLimits::IDENTIFIER_MAX_LENGTH
|
257
|
+
raise ArgumentError, "New table name '#{new_name}' is too long; the limit is #{DatabaseLimits::IDENTIFIER_MAX_LENGTH} characters"
|
247
258
|
end
|
259
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
260
|
+
schema_cache.clear_data_source_cache!(new_name.to_s)
|
248
261
|
execute "RENAME #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
|
249
262
|
execute "RENAME #{quote_table_name("#{table_name}_seq")} TO #{default_sequence_name(new_name)}" rescue nil
|
250
263
|
|
251
264
|
rename_table_indexes(table_name, new_name)
|
252
265
|
end
|
253
266
|
|
254
|
-
def drop_table(table_name, options
|
267
|
+
def drop_table(table_name, **options) # :nodoc:
|
268
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
255
269
|
execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE CONSTRAINTS' if options[:force] == :cascade}"
|
256
270
|
seq_name = options[:sequence_name] || default_sequence_name(table_name)
|
257
271
|
execute "DROP SEQUENCE #{quote_table_name(seq_name)}" rescue nil
|
@@ -265,7 +279,7 @@ module ActiveRecord
|
|
265
279
|
sm_table = quote_table_name(ActiveRecord::SchemaMigration.table_name)
|
266
280
|
|
267
281
|
if supports_multi_insert?
|
268
|
-
versions.inject("INSERT ALL\n"
|
282
|
+
versions.inject(+"INSERT ALL\n") { |sql, version|
|
269
283
|
sql << "INTO #{sm_table} (version) VALUES (#{quote(version)})\n"
|
270
284
|
} << "SELECT * FROM DUAL\n"
|
271
285
|
else
|
@@ -281,17 +295,17 @@ module ActiveRecord
|
|
281
295
|
end
|
282
296
|
end
|
283
297
|
|
284
|
-
def add_index(table_name, column_name, options
|
285
|
-
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)
|
286
300
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{index_options}"
|
287
301
|
if index_type == "UNIQUE"
|
288
|
-
unless
|
302
|
+
unless /\(.*\)/.match?(quoted_column_names)
|
289
303
|
execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names})"
|
290
304
|
end
|
291
305
|
end
|
292
306
|
end
|
293
307
|
|
294
|
-
def add_index_options(table_name, column_name, comment: nil, **options)
|
308
|
+
def add_index_options(table_name, column_name, comment: nil, **options) # :nodoc:
|
295
309
|
column_names = Array(column_name)
|
296
310
|
index_name = index_name(table_name, column: column_names)
|
297
311
|
|
@@ -300,13 +314,11 @@ module ActiveRecord
|
|
300
314
|
index_type = options[:unique] ? "UNIQUE" : ""
|
301
315
|
index_name = options[:name].to_s if options.key?(:name)
|
302
316
|
tablespace = tablespace_for(:index, options[:tablespace])
|
303
|
-
|
304
|
-
# TODO: This option is used for NOLOGGING, needs better argumetn name
|
317
|
+
# TODO: This option is used for NOLOGGING, needs better argument name
|
305
318
|
index_options = options[:options]
|
306
319
|
|
307
|
-
|
308
|
-
|
309
|
-
end
|
320
|
+
validate_index_length!(table_name, index_name, options.fetch(:internal, false))
|
321
|
+
|
310
322
|
if table_exists?(table_name) && index_name_exists?(table_name, index_name)
|
311
323
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
312
324
|
end
|
@@ -317,15 +329,17 @@ module ActiveRecord
|
|
317
329
|
|
318
330
|
# Remove the given index from the table.
|
319
331
|
# Gives warning if index does not exist
|
320
|
-
def remove_index(table_name,
|
321
|
-
|
332
|
+
def remove_index(table_name, column_name = nil, **options) # :nodoc:
|
333
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
334
|
+
|
335
|
+
index_name = index_name_for_remove(table_name, column_name, options)
|
322
336
|
# TODO: It should execute only when index_type == "UNIQUE"
|
323
337
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
|
324
338
|
execute "DROP INDEX #{quote_column_name(index_name)}"
|
325
339
|
end
|
326
340
|
|
327
341
|
# returned shortened index name if default is too large
|
328
|
-
def index_name(table_name, options)
|
342
|
+
def index_name(table_name, options) # :nodoc:
|
329
343
|
default_name = super(table_name, options).to_s
|
330
344
|
# sometimes options can be String or Array with column names
|
331
345
|
options = {} unless options.is_a?(Hash)
|
@@ -341,7 +355,7 @@ module ActiveRecord
|
|
341
355
|
end
|
342
356
|
# generate unique name using hash function
|
343
357
|
if shortened_name.length > identifier_max_length
|
344
|
-
shortened_name = "i" + Digest::SHA1.hexdigest(default_name)[0, identifier_max_length - 1]
|
358
|
+
shortened_name = "i" + OpenSSL::Digest::SHA1.hexdigest(default_name)[0, identifier_max_length - 1]
|
345
359
|
end
|
346
360
|
@logger.warn "#{adapter_name} shortened default index name #{default_name} to #{shortened_name}" if @logger
|
347
361
|
shortened_name
|
@@ -354,18 +368,18 @@ module ActiveRecord
|
|
354
368
|
#
|
355
369
|
# Will always query database and not index cache.
|
356
370
|
def index_name_exists?(table_name, index_name)
|
357
|
-
(
|
358
|
-
result = select_value(
|
359
|
-
SELECT 1 FROM all_indexes
|
360
|
-
WHERE i.owner = '
|
361
|
-
AND i.table_owner = '
|
362
|
-
AND i.table_name =
|
363
|
-
AND i.index_name =
|
371
|
+
(_owner, table_name) = @connection.describe(table_name)
|
372
|
+
result = select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name), bind_string("index_name", index_name.to_s.upcase)])
|
373
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ 1 FROM all_indexes i
|
374
|
+
WHERE i.owner = SYS_CONTEXT('userenv', 'current_schema')
|
375
|
+
AND i.table_owner = SYS_CONTEXT('userenv', 'current_schema')
|
376
|
+
AND i.table_name = :table_name
|
377
|
+
AND i.index_name = :index_name
|
364
378
|
SQL
|
365
379
|
result == 1
|
366
380
|
end
|
367
381
|
|
368
|
-
def rename_index(table_name, old_name, new_name)
|
382
|
+
def rename_index(table_name, old_name, new_name) # :nodoc:
|
369
383
|
validate_index_length!(table_name, new_name)
|
370
384
|
execute "ALTER INDEX #{quote_column_name(old_name)} rename to #{quote_column_name(new_name)}"
|
371
385
|
end
|
@@ -376,10 +390,10 @@ module ActiveRecord
|
|
376
390
|
#
|
377
391
|
# add_synonym :posts, "blog.posts"
|
378
392
|
# add_synonym :posts_seq, "blog.posts_seq"
|
379
|
-
# add_synonym :employees, "hr.employees
|
393
|
+
# add_synonym :employees, "hr.employees", :force => true
|
380
394
|
#
|
381
395
|
def add_synonym(name, table_name, options = {})
|
382
|
-
sql = "CREATE"
|
396
|
+
sql = +"CREATE"
|
383
397
|
if options[:force] == true
|
384
398
|
sql << " OR REPLACE"
|
385
399
|
end
|
@@ -396,14 +410,14 @@ module ActiveRecord
|
|
396
410
|
execute "DROP SYNONYM #{quote_table_name(name)}"
|
397
411
|
end
|
398
412
|
|
399
|
-
def add_reference(table_name,
|
400
|
-
OracleEnhanced::ReferenceDefinition.new(
|
413
|
+
def add_reference(table_name, ref_name, **options)
|
414
|
+
OracleEnhanced::ReferenceDefinition.new(ref_name, **options).add_to(update_table_definition(table_name, self))
|
401
415
|
end
|
402
416
|
|
403
|
-
def add_column(table_name, column_name, type, options
|
417
|
+
def add_column(table_name, column_name, type, **options) # :nodoc:
|
404
418
|
type = aliased_types(type.to_s, type)
|
405
419
|
at = create_alter_table table_name
|
406
|
-
at.add_column(column_name, type, options)
|
420
|
+
at.add_column(column_name, type, **options)
|
407
421
|
add_column_sql = schema_creation.accept at
|
408
422
|
add_column_sql << tablespace_for((type_to_sql(type).downcase.to_sym), nil, table_name, column_name)
|
409
423
|
execute add_column_sql
|
@@ -417,14 +431,14 @@ module ActiveRecord
|
|
417
431
|
fallback
|
418
432
|
end
|
419
433
|
|
420
|
-
def change_column_default(table_name, column_name, default_or_changes)
|
434
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
421
435
|
default = extract_new_default_value(default_or_changes)
|
422
436
|
execute "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
|
423
437
|
ensure
|
424
438
|
clear_table_columns_cache(table_name)
|
425
439
|
end
|
426
440
|
|
427
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
441
|
+
def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
|
428
442
|
column = column_for(table_name, column_name)
|
429
443
|
|
430
444
|
unless null || default.nil?
|
@@ -434,7 +448,7 @@ module ActiveRecord
|
|
434
448
|
change_column table_name, column_name, column.sql_type, null: null
|
435
449
|
end
|
436
450
|
|
437
|
-
def change_column(table_name, column_name, type, options
|
451
|
+
def change_column(table_name, column_name, type, **options) # :nodoc:
|
438
452
|
column = column_for(table_name, column_name)
|
439
453
|
|
440
454
|
# remove :null option if its value is the same as current column definition
|
@@ -447,7 +461,7 @@ module ActiveRecord
|
|
447
461
|
end
|
448
462
|
|
449
463
|
td = create_table_definition(table_name)
|
450
|
-
cd = td.new_column_definition(column.name, type, options)
|
464
|
+
cd = td.new_column_definition(column.name, type, **options)
|
451
465
|
change_column_stmt = schema_creation.accept cd
|
452
466
|
change_column_stmt << tablespace_for((type_to_sql(type).downcase.to_sym), nil, options[:table_name], options[:column_name]) if type
|
453
467
|
change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{change_column_stmt}"
|
@@ -458,21 +472,30 @@ module ActiveRecord
|
|
458
472
|
clear_table_columns_cache(table_name)
|
459
473
|
end
|
460
474
|
|
461
|
-
def rename_column(table_name, column_name, new_column_name)
|
475
|
+
def rename_column(table_name, column_name, new_column_name) # :nodoc:
|
462
476
|
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} to #{quote_column_name(new_column_name)}"
|
463
477
|
rename_column_indexes(table_name, column_name, new_column_name)
|
464
478
|
ensure
|
465
479
|
clear_table_columns_cache(table_name)
|
466
480
|
end
|
467
481
|
|
468
|
-
def remove_column(table_name, column_name, type = nil, options = {})
|
482
|
+
def remove_column(table_name, column_name, type = nil, options = {}) # :nodoc:
|
469
483
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)} CASCADE CONSTRAINTS"
|
470
484
|
ensure
|
471
485
|
clear_table_columns_cache(table_name)
|
472
486
|
end
|
473
487
|
|
474
|
-
def
|
488
|
+
def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
|
489
|
+
quoted_column_names = column_names.map { |column_name| quote_column_name(column_name) }.join(", ")
|
490
|
+
|
491
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} DROP (#{quoted_column_names}) CASCADE CONSTRAINTS"
|
492
|
+
ensure
|
493
|
+
clear_table_columns_cache(table_name)
|
494
|
+
end
|
495
|
+
|
496
|
+
def change_table_comment(table_name, comment_or_changes)
|
475
497
|
clear_cache!
|
498
|
+
comment = extract_new_comment_value(comment_or_changes)
|
476
499
|
if comment.nil?
|
477
500
|
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS ''"
|
478
501
|
else
|
@@ -480,16 +503,18 @@ module ActiveRecord
|
|
480
503
|
end
|
481
504
|
end
|
482
505
|
|
483
|
-
def change_column_comment(table_name, column_name,
|
506
|
+
def change_column_comment(table_name, column_name, comment_or_changes)
|
484
507
|
clear_cache!
|
508
|
+
comment = extract_new_comment_value(comment_or_changes)
|
485
509
|
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS '#{comment}'"
|
486
510
|
end
|
487
511
|
|
488
|
-
def table_comment(table_name)
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
512
|
+
def table_comment(table_name) # :nodoc:
|
513
|
+
# TODO
|
514
|
+
(_owner, table_name) = @connection.describe(table_name)
|
515
|
+
select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name)])
|
516
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_tab_comments
|
517
|
+
WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
|
493
518
|
AND table_name = :table_name
|
494
519
|
SQL
|
495
520
|
end
|
@@ -500,19 +525,19 @@ module ActiveRecord
|
|
500
525
|
end
|
501
526
|
end
|
502
527
|
|
503
|
-
def column_comment(table_name, column_name)
|
528
|
+
def column_comment(table_name, column_name) # :nodoc:
|
504
529
|
# TODO: it does not exist in Abstract adapter
|
505
|
-
(
|
506
|
-
select_value(
|
507
|
-
SELECT comments FROM all_col_comments
|
508
|
-
WHERE owner =
|
530
|
+
(_owner, table_name) = @connection.describe(table_name)
|
531
|
+
select_value(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name), bind_string("column_name", column_name.upcase)])
|
532
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ comments FROM all_col_comments
|
533
|
+
WHERE owner = SYS_CONTEXT('userenv', 'current_schema')
|
509
534
|
AND table_name = :table_name
|
510
535
|
AND column_name = :column_name
|
511
536
|
SQL
|
512
537
|
end
|
513
538
|
|
514
539
|
# Maps logical Rails types to Oracle-specific data types.
|
515
|
-
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
|
540
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) # :nodoc:
|
516
541
|
# Ignore options for :text, :ntext and :binary columns
|
517
542
|
return super(type) if ["text", "ntext", "binary"].include?(type.to_s)
|
518
543
|
|
@@ -520,27 +545,27 @@ module ActiveRecord
|
|
520
545
|
end
|
521
546
|
|
522
547
|
def tablespace(table_name)
|
523
|
-
select_value(
|
524
|
-
SELECT tablespace_name
|
548
|
+
select_value(<<~SQL.squish, "SCHEMA")
|
549
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ tablespace_name
|
525
550
|
FROM all_tables
|
526
551
|
WHERE table_name='#{table_name.to_s.upcase}'
|
527
|
-
AND owner = SYS_CONTEXT('userenv', '
|
552
|
+
AND owner = SYS_CONTEXT('userenv', 'current_schema')
|
528
553
|
SQL
|
529
554
|
end
|
530
555
|
|
531
556
|
# get table foreign keys for schema dump
|
532
|
-
def foreign_keys(table_name)
|
533
|
-
(
|
557
|
+
def foreign_keys(table_name) # :nodoc:
|
558
|
+
(_owner, desc_table_name) = @connection.describe(table_name)
|
534
559
|
|
535
|
-
fk_info = select_all(
|
536
|
-
SELECT r.table_name to_table
|
560
|
+
fk_info = select_all(<<~SQL.squish, "SCHEMA", [bind_string("desc_table_name", desc_table_name)])
|
561
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ r.table_name to_table
|
537
562
|
,rc.column_name references_column
|
538
563
|
,cc.column_name
|
539
564
|
,c.constraint_name name
|
540
565
|
,c.delete_rule
|
541
|
-
FROM all_constraints
|
542
|
-
all_constraints
|
543
|
-
WHERE c.owner =
|
566
|
+
FROM all_constraints c, all_cons_columns cc,
|
567
|
+
all_constraints r, all_cons_columns rc
|
568
|
+
WHERE c.owner = SYS_CONTEXT('userenv', 'current_schema')
|
544
569
|
AND c.table_name = :desc_table_name
|
545
570
|
AND c.constraint_type = 'R'
|
546
571
|
AND cc.owner = c.owner
|
@@ -573,13 +598,13 @@ module ActiveRecord
|
|
573
598
|
|
574
599
|
# REFERENTIAL INTEGRITY ====================================
|
575
600
|
|
576
|
-
def disable_referential_integrity(&block)
|
577
|
-
old_constraints = select_all(
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
601
|
+
def disable_referential_integrity(&block) # :nodoc:
|
602
|
+
old_constraints = select_all(<<~SQL.squish, "SCHEMA")
|
603
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ constraint_name, owner, table_name
|
604
|
+
FROM all_constraints
|
605
|
+
WHERE constraint_type = 'R'
|
606
|
+
AND status = 'ENABLED'
|
607
|
+
AND owner = SYS_CONTEXT('userenv', 'current_schema')
|
583
608
|
SQL
|
584
609
|
begin
|
585
610
|
old_constraints.each do |constraint|
|
@@ -594,7 +619,7 @@ module ActiveRecord
|
|
594
619
|
end
|
595
620
|
|
596
621
|
def create_alter_table(name)
|
597
|
-
OracleEnhanced::AlterTable.new create_table_definition(name
|
622
|
+
OracleEnhanced::AlterTable.new create_table_definition(name)
|
598
623
|
end
|
599
624
|
|
600
625
|
def update_table_definition(table_name, base)
|
@@ -606,13 +631,12 @@ module ActiveRecord
|
|
606
631
|
end
|
607
632
|
|
608
633
|
private
|
609
|
-
|
610
634
|
def schema_creation
|
611
635
|
OracleEnhanced::SchemaCreation.new self
|
612
636
|
end
|
613
637
|
|
614
|
-
def create_table_definition(
|
615
|
-
OracleEnhanced::TableDefinition.new(
|
638
|
+
def create_table_definition(name, **options)
|
639
|
+
OracleEnhanced::TableDefinition.new(self, name, **options)
|
616
640
|
end
|
617
641
|
|
618
642
|
def new_column_from_field(table_name, field)
|
@@ -634,9 +658,9 @@ module ActiveRecord
|
|
634
658
|
# If a default contains a newline these cleanup regexes need to
|
635
659
|
# match newlines.
|
636
660
|
field["data_default"].sub!(/^'(.*)'$/m, '\1')
|
637
|
-
field["data_default"] = nil if
|
661
|
+
field["data_default"] = nil if /^(null|empty_[bc]lob\(\))$/i.match?(field["data_default"])
|
638
662
|
# TODO: Needs better fix to fallback "N" to false
|
639
|
-
field["data_default"] = false if
|
663
|
+
field["data_default"] = false if field["data_default"] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings
|
640
664
|
end
|
641
665
|
|
642
666
|
type_metadata = fetch_type_metadata(field["sql_type"], is_virtual)
|
@@ -646,9 +670,8 @@ module ActiveRecord
|
|
646
670
|
default_value,
|
647
671
|
type_metadata,
|
648
672
|
field["nullable"] == "Y",
|
649
|
-
|
650
|
-
|
651
|
-
)
|
673
|
+
comment: field["column_comment"]
|
674
|
+
)
|
652
675
|
end
|
653
676
|
|
654
677
|
def fetch_type_metadata(sql_type, virtual = nil)
|
@@ -656,7 +679,7 @@ module ActiveRecord
|
|
656
679
|
end
|
657
680
|
|
658
681
|
def tablespace_for(obj_type, tablespace_option, table_name = nil, column_name = nil)
|
659
|
-
tablespace_sql = ""
|
682
|
+
tablespace_sql = +""
|
660
683
|
if tablespace = (tablespace_option || default_tablespace_for(obj_type))
|
661
684
|
if [:blob, :clob, :nclob].include?(obj_type.to_sym)
|
662
685
|
tablespace_sql << " LOB (#{quote_column_name(column_name)}) STORE AS #{column_name.to_s[0..10]}_#{table_name.to_s[0..14]}_ls (TABLESPACE #{tablespace})"
|
@@ -679,33 +702,11 @@ module ActiveRecord
|
|
679
702
|
end
|
680
703
|
|
681
704
|
def create_sequence_and_trigger(table_name, options)
|
705
|
+
# TODO: Needs rename since no triggers created
|
706
|
+
# This method will be removed since sequence will not be created separately
|
682
707
|
seq_name = options[:sequence_name] || default_sequence_name(table_name)
|
683
708
|
seq_start_value = options[:sequence_start_value] || default_sequence_start_value
|
684
709
|
execute "CREATE SEQUENCE #{quote_table_name(seq_name)} START WITH #{seq_start_value}"
|
685
|
-
|
686
|
-
create_primary_key_trigger(table_name, options) if options[:primary_key_trigger]
|
687
|
-
end
|
688
|
-
|
689
|
-
def create_primary_key_trigger(table_name, options)
|
690
|
-
seq_name = options[:sequence_name] || default_sequence_name(table_name)
|
691
|
-
trigger_name = options[:trigger_name] || default_trigger_name(table_name)
|
692
|
-
primary_key = options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)
|
693
|
-
execute <<-SQL
|
694
|
-
CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
|
695
|
-
BEFORE INSERT ON #{quote_table_name(table_name)} FOR EACH ROW
|
696
|
-
BEGIN
|
697
|
-
IF inserting THEN
|
698
|
-
IF :new.#{quote_column_name(primary_key)} IS NULL THEN
|
699
|
-
SELECT #{quote_table_name(seq_name)}.NEXTVAL INTO :new.#{quote_column_name(primary_key)} FROM dual;
|
700
|
-
END IF;
|
701
|
-
END IF;
|
702
|
-
END;
|
703
|
-
SQL
|
704
|
-
end
|
705
|
-
|
706
|
-
def default_trigger_name(table_name)
|
707
|
-
# truncate table name if necessary to fit in max length of identifier
|
708
|
-
"#{table_name.to_s[0, table_name_length - 4]}_pkt"
|
709
710
|
end
|
710
711
|
|
711
712
|
def rebuild_primary_key_index_to_default_tablespace(table_name, options)
|
@@ -713,8 +714,8 @@ module ActiveRecord
|
|
713
714
|
|
714
715
|
return unless tablespace
|
715
716
|
|
716
|
-
index_name = select_value(
|
717
|
-
SELECT index_name FROM all_constraints
|
717
|
+
index_name = select_value(<<~SQL.squish, "Index name for primary key", [bind_string("table_name", table_name.upcase)])
|
718
|
+
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ index_name FROM all_constraints
|
718
719
|
WHERE table_name = :table_name
|
719
720
|
AND constraint_type = 'P'
|
720
721
|
AND owner = SYS_CONTEXT('userenv', 'current_schema')
|