activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1
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/.rspec +2 -0
- data/Gemfile +20 -11
- data/History.md +123 -4
- data/RUNNING_TESTS.md +79 -55
- data/Rakefile +13 -19
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +16 -17
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -59
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -50
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +11 -11
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -117
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +30 -23
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +48 -70
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +51 -69
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +76 -76
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +13 -42
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -64
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -47
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +146 -159
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +94 -132
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +65 -100
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +250 -487
- data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -10
- data/lib/active_record/oracle_enhanced/type/integer.rb +3 -4
- data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -1
- data/lib/active_record/oracle_enhanced/type/raw.rb +2 -3
- data/lib/active_record/oracle_enhanced/type/string.rb +2 -2
- data/lib/active_record/oracle_enhanced/type/text.rb +2 -2
- data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +57 -131
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +32 -34
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -42
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +83 -85
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +205 -286
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +42 -49
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -71
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +51 -92
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +221 -327
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +16 -18
- data/spec/spec_helper.rb +59 -57
- metadata +10 -10
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "digest/sha1"
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
@@ -80,10 +80,10 @@ module ActiveRecord
|
|
80
80
|
if supports_comments? && !supports_comments_in_create?
|
81
81
|
change_table_comment(table_name, comment) if comment
|
82
82
|
td.columns.each do |column|
|
83
|
-
change_column_comment(table_name, column.name, column.comment) if column.comment
|
83
|
+
change_column_comment(table_name, column.name, column.comment) if column.comment.present?
|
84
84
|
end
|
85
85
|
end
|
86
|
-
td.indexes.each { |c,o| add_index table_name, c, o }
|
86
|
+
td.indexes.each { |c, o| add_index table_name, c, o }
|
87
87
|
|
88
88
|
rebuild_primary_key_index_to_default_tablespace(table_name, options)
|
89
89
|
end
|
@@ -113,10 +113,6 @@ module ActiveRecord
|
|
113
113
|
self.all_schema_indexes = nil
|
114
114
|
end
|
115
115
|
|
116
|
-
def dump_schema_information #:nodoc:
|
117
|
-
super
|
118
|
-
end
|
119
|
-
|
120
116
|
def insert_versions_sql(versions) # :nodoc:
|
121
117
|
sm_table = quote_table_name(ActiveRecord::Migrator.schema_migrations_table_name)
|
122
118
|
|
@@ -137,18 +133,10 @@ module ActiveRecord
|
|
137
133
|
end
|
138
134
|
end
|
139
135
|
|
140
|
-
def initialize_schema_migrations_table
|
141
|
-
super
|
142
|
-
end
|
143
|
-
|
144
|
-
def update_table_definition(table_name, base) #:nodoc:
|
145
|
-
OracleEnhanced::Table.new(table_name, base)
|
146
|
-
end
|
147
|
-
|
148
136
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
149
137
|
index_name, index_type, quoted_column_names, tablespace, index_options = add_index_options(table_name, column_name, options)
|
150
138
|
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})#{tablespace} #{index_options}"
|
151
|
-
if index_type ==
|
139
|
+
if index_type == "UNIQUE"
|
152
140
|
unless quoted_column_names =~ /\(.*\)/
|
153
141
|
execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_column_name(index_name)} #{index_type} (#{quoted_column_names})"
|
154
142
|
end
|
@@ -173,29 +161,18 @@ module ActiveRecord
|
|
173
161
|
if index_name.to_s.length > max_index_length
|
174
162
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
|
175
163
|
end
|
176
|
-
if index_name_exists?(table_name, index_name
|
164
|
+
if table_exists?(table_name) && index_name_exists?(table_name, index_name)
|
177
165
|
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
|
178
166
|
end
|
179
167
|
|
180
168
|
quoted_column_names = column_names.map { |e| quote_column_name_or_expression(e) }.join(", ")
|
181
|
-
|
169
|
+
[index_name, index_type, quoted_column_names, tablespace, index_options]
|
182
170
|
end
|
183
171
|
|
184
172
|
# Remove the given index from the table.
|
185
173
|
# Gives warning if index does not exist
|
186
174
|
def remove_index(table_name, options = {}) #:nodoc:
|
187
175
|
index_name = index_name_for_remove(table_name, options)
|
188
|
-
unless index_name_exists?(table_name, index_name, true)
|
189
|
-
# sometimes options can be String or Array with column names
|
190
|
-
options = {} unless options.is_a?(Hash)
|
191
|
-
if options.has_key? :name
|
192
|
-
options_without_column = options.dup
|
193
|
-
options_without_column.delete :column
|
194
|
-
index_name_without_column = index_name(table_name, options_without_column)
|
195
|
-
return index_name_without_column if index_name_exists?(table_name, index_name_without_column, false)
|
196
|
-
end
|
197
|
-
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
|
198
|
-
end
|
199
176
|
#TODO: It should execute only when index_type == "UNIQUE"
|
200
177
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(index_name)}" rescue nil
|
201
178
|
execute "DROP INDEX #{quote_column_name(index_name)}"
|
@@ -216,11 +193,11 @@ module ActiveRecord
|
|
216
193
|
|
217
194
|
# leave just first three letters from each word
|
218
195
|
if shortened_name.length > identifier_max_length
|
219
|
-
shortened_name = shortened_name.split(
|
196
|
+
shortened_name = shortened_name.split("_").map { |w| w[0, 3] }.join("_")
|
220
197
|
end
|
221
198
|
# generate unique name using hash function
|
222
199
|
if shortened_name.length > identifier_max_length
|
223
|
-
shortened_name =
|
200
|
+
shortened_name = "i" + Digest::SHA1.hexdigest(default_name)[0, identifier_max_length - 1]
|
224
201
|
end
|
225
202
|
@logger.warn "#{adapter_name} shortened default index name #{default_name} to #{shortened_name}" if @logger
|
226
203
|
shortened_name
|
@@ -232,7 +209,12 @@ module ActiveRecord
|
|
232
209
|
# as there's no way to determine the correct answer in that case.
|
233
210
|
#
|
234
211
|
# Will always query database and not index cache.
|
235
|
-
def index_name_exists?(table_name, index_name, default)
|
212
|
+
def index_name_exists?(table_name, index_name, default = nil)
|
213
|
+
unless default.nil?
|
214
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
215
|
+
Passing default to #index_name_exists? is deprecated without replacement.
|
216
|
+
MSG
|
217
|
+
end
|
236
218
|
(owner, table_name, db_link) = @connection.describe(table_name)
|
237
219
|
result = select_value(<<-SQL)
|
238
220
|
SELECT 1 FROM all_indexes#{db_link} i
|
@@ -245,31 +227,23 @@ module ActiveRecord
|
|
245
227
|
end
|
246
228
|
|
247
229
|
def rename_index(table_name, old_name, new_name) #:nodoc:
|
248
|
-
|
249
|
-
raise ArgumentError, "Index name '#{old_name}' on table '#{table_name}' does not exist"
|
250
|
-
end
|
251
|
-
if new_name.length > allowed_index_name_length
|
252
|
-
raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters"
|
253
|
-
end
|
230
|
+
validate_index_length!(table_name, new_name)
|
254
231
|
execute "ALTER INDEX #{quote_column_name(old_name)} rename to #{quote_column_name(new_name)}"
|
255
232
|
ensure
|
256
233
|
self.all_schema_indexes = nil
|
257
234
|
end
|
258
235
|
|
236
|
+
def add_reference(table_name, *args)
|
237
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::ReferenceDefinition.new(*args).add_to(update_table_definition(table_name, self))
|
238
|
+
end
|
239
|
+
|
259
240
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
260
|
-
if type.to_sym == :virtual
|
261
|
-
type = options[:type]
|
262
|
-
end
|
263
241
|
type = aliased_types(type.to_s, type)
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
add_column_sql << tablespace_for((type_to_sql(type).downcase.to_sym), nil, table_name, column_name) if type
|
270
|
-
|
271
|
-
execute(add_column_sql)
|
272
|
-
|
242
|
+
at = create_alter_table table_name
|
243
|
+
at.add_column(column_name, type, options)
|
244
|
+
add_column_sql = schema_creation.accept at
|
245
|
+
add_column_sql << tablespace_for((type_to_sql(type).downcase.to_sym), nil, table_name, column_name)
|
246
|
+
execute add_column_sql
|
273
247
|
create_sequence_and_trigger(table_name, options) if type && type.to_sym == :primary_key
|
274
248
|
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
275
249
|
ensure
|
@@ -294,7 +268,7 @@ module ActiveRecord
|
|
294
268
|
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
|
295
269
|
end
|
296
270
|
|
297
|
-
change_column table_name, column_name, column.sql_type, :
|
271
|
+
change_column table_name, column_name, column.sql_type, null: null
|
298
272
|
end
|
299
273
|
|
300
274
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
@@ -308,14 +282,15 @@ module ActiveRecord
|
|
308
282
|
if type.to_sym == :virtual
|
309
283
|
type = options[:type]
|
310
284
|
end
|
311
|
-
change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} "
|
312
|
-
change_column_sql << "#{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" if type
|
313
|
-
|
314
|
-
add_column_options!(change_column_sql, options.merge(:type=>type, :column_name=>column_name, :table_name=>table_name))
|
315
|
-
|
316
|
-
change_column_sql << tablespace_for((type_to_sql(type).downcase.to_sym), nil, options[:table_name], options[:column_name]) if type
|
317
285
|
|
286
|
+
td = create_table_definition(table_name)
|
287
|
+
cd = td.new_column_definition(column.name, type, options)
|
288
|
+
change_column_stmt = schema_creation.accept cd
|
289
|
+
change_column_stmt << tablespace_for((type_to_sql(type).downcase.to_sym), nil, options[:table_name], options[:column_name]) if type
|
290
|
+
change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{change_column_stmt}"
|
318
291
|
execute(change_column_sql)
|
292
|
+
|
293
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
319
294
|
ensure
|
320
295
|
clear_table_columns_cache(table_name)
|
321
296
|
end
|
@@ -366,9 +341,9 @@ module ActiveRecord
|
|
366
341
|
end
|
367
342
|
|
368
343
|
# Maps logical Rails types to Oracle-specific data types.
|
369
|
-
def type_to_sql(type, limit
|
344
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **) #:nodoc:
|
370
345
|
# Ignore options for :text and :binary columns
|
371
|
-
return super(type
|
346
|
+
return super(type) if ["text", "binary"].include?(type.to_s)
|
372
347
|
|
373
348
|
super
|
374
349
|
end
|
@@ -382,28 +357,11 @@ module ActiveRecord
|
|
382
357
|
SQL
|
383
358
|
end
|
384
359
|
|
385
|
-
def add_foreign_key(from_table, to_table, options = {})
|
386
|
-
if options[:dependent]
|
387
|
-
ActiveSupport::Deprecation.warn "`:dependent` option will be deprecated. Please use `:on_delete` option"
|
388
|
-
end
|
389
|
-
case options[:dependent]
|
390
|
-
when :delete then options[:on_delete] = :cascade
|
391
|
-
when :nullify then options[:on_delete] = :nullify
|
392
|
-
else
|
393
|
-
end
|
394
|
-
|
395
|
-
super
|
396
|
-
end
|
397
|
-
|
398
|
-
def remove_foreign_key(from_table, options_or_to_table = {})
|
399
|
-
super
|
400
|
-
end
|
401
|
-
|
402
360
|
# get table foreign keys for schema dump
|
403
361
|
def foreign_keys(table_name) #:nodoc:
|
404
362
|
(owner, desc_table_name, db_link) = @connection.describe(table_name)
|
405
363
|
|
406
|
-
fk_info = select_all(<<-SQL,
|
364
|
+
fk_info = select_all(<<-SQL, "Foreign Keys")
|
407
365
|
SELECT r.table_name to_table
|
408
366
|
,rc.column_name references_column
|
409
367
|
,cc.column_name
|
@@ -412,7 +370,7 @@ module ActiveRecord
|
|
412
370
|
FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc,
|
413
371
|
all_constraints#{db_link} r, all_cons_columns#{db_link} rc
|
414
372
|
WHERE c.owner = '#{owner}'
|
415
|
-
AND c.table_name = '#{desc_table_name}'
|
373
|
+
AND c.table_name = q'[#{desc_table_name}]'
|
416
374
|
AND c.constraint_type = 'R'
|
417
375
|
AND cc.owner = c.owner
|
418
376
|
AND cc.constraint_name = c.constraint_name
|
@@ -426,19 +384,19 @@ module ActiveRecord
|
|
426
384
|
|
427
385
|
fk_info.map do |row|
|
428
386
|
options = {
|
429
|
-
column: oracle_downcase(row[
|
430
|
-
name: oracle_downcase(row[
|
431
|
-
primary_key: oracle_downcase(row[
|
387
|
+
column: oracle_downcase(row["column_name"]),
|
388
|
+
name: oracle_downcase(row["name"]),
|
389
|
+
primary_key: oracle_downcase(row["references_column"])
|
432
390
|
}
|
433
|
-
options[:on_delete] = extract_foreign_key_action(row[
|
434
|
-
|
391
|
+
options[:on_delete] = extract_foreign_key_action(row["delete_rule"])
|
392
|
+
ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(oracle_downcase(table_name), oracle_downcase(row["to_table"]), options)
|
435
393
|
end
|
436
394
|
end
|
437
395
|
|
438
396
|
def extract_foreign_key_action(specifier) # :nodoc:
|
439
397
|
case specifier
|
440
|
-
when
|
441
|
-
when
|
398
|
+
when "CASCADE"; :cascade
|
399
|
+
when "SET NULL"; :nullify
|
442
400
|
end
|
443
401
|
end
|
444
402
|
|
@@ -465,48 +423,52 @@ module ActiveRecord
|
|
465
423
|
end
|
466
424
|
end
|
467
425
|
|
468
|
-
private
|
469
|
-
|
470
426
|
def create_alter_table(name)
|
471
|
-
OracleEnhanced::AlterTable.new create_table_definition(name, false, {})
|
427
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::AlterTable.new create_table_definition(name, false, {})
|
472
428
|
end
|
473
429
|
|
474
|
-
def
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
430
|
+
def update_table_definition(table_name, base)
|
431
|
+
ActiveRecord::ConnectionAdapters::OracleEnhanced::Table.new(table_name, base)
|
432
|
+
end
|
433
|
+
|
434
|
+
private
|
435
|
+
|
436
|
+
def tablespace_for(obj_type, tablespace_option, table_name = nil, column_name = nil)
|
437
|
+
tablespace_sql = ""
|
438
|
+
if tablespace = (tablespace_option || default_tablespace_for(obj_type))
|
439
|
+
if [:blob, :clob].include?(obj_type.to_sym)
|
440
|
+
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})"
|
441
|
+
else
|
442
|
+
tablespace_sql << " TABLESPACE #{tablespace}"
|
443
|
+
end
|
481
444
|
end
|
445
|
+
tablespace_sql
|
482
446
|
end
|
483
|
-
tablespace_sql
|
484
|
-
end
|
485
447
|
|
486
|
-
|
487
|
-
|
488
|
-
|
448
|
+
def default_tablespace_for(type)
|
449
|
+
(default_tablespaces[type] || default_tablespaces[native_database_types[type][:name]]) rescue nil
|
450
|
+
end
|
489
451
|
|
490
|
-
|
491
|
-
|
492
|
-
|
452
|
+
def column_for(table_name, column_name)
|
453
|
+
unless column = columns(table_name).find { |c| c.name == column_name.to_s }
|
454
|
+
raise "No such column: #{table_name}.#{column_name}"
|
455
|
+
end
|
456
|
+
column
|
493
457
|
end
|
494
|
-
column
|
495
|
-
end
|
496
458
|
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
459
|
+
def create_sequence_and_trigger(table_name, options)
|
460
|
+
seq_name = options[:sequence_name] || default_sequence_name(table_name)
|
461
|
+
seq_start_value = options[:sequence_start_value] || default_sequence_start_value
|
462
|
+
execute "CREATE SEQUENCE #{quote_table_name(seq_name)} START WITH #{seq_start_value}"
|
501
463
|
|
502
|
-
|
503
|
-
|
464
|
+
create_primary_key_trigger(table_name, options) if options[:primary_key_trigger]
|
465
|
+
end
|
504
466
|
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
467
|
+
def create_primary_key_trigger(table_name, options)
|
468
|
+
seq_name = options[:sequence_name] || default_sequence_name(table_name)
|
469
|
+
trigger_name = options[:trigger_name] || default_trigger_name(table_name)
|
470
|
+
primary_key = options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)
|
471
|
+
execute compress_lines(<<-SQL)
|
510
472
|
CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
|
511
473
|
BEFORE INSERT ON #{quote_table_name(table_name)} FOR EACH ROW
|
512
474
|
BEGIN
|
@@ -517,28 +479,28 @@ module ActiveRecord
|
|
517
479
|
END IF;
|
518
480
|
END;
|
519
481
|
SQL
|
520
|
-
|
482
|
+
end
|
521
483
|
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
484
|
+
def default_trigger_name(table_name)
|
485
|
+
# truncate table name if necessary to fit in max length of identifier
|
486
|
+
"#{table_name.to_s[0, table_name_length - 4]}_pkt"
|
487
|
+
end
|
526
488
|
|
527
|
-
|
528
|
-
|
489
|
+
def rebuild_primary_key_index_to_default_tablespace(table_name, options)
|
490
|
+
tablespace = default_tablespace_for(:index)
|
529
491
|
|
530
|
-
|
492
|
+
return unless tablespace
|
531
493
|
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
494
|
+
index_name = Base.connection.select_value(
|
495
|
+
"SELECT index_name FROM all_constraints
|
496
|
+
WHERE table_name = #{quote(table_name.upcase)}
|
497
|
+
AND constraint_type = 'P'
|
498
|
+
AND owner = SYS_CONTEXT('userenv', 'current_schema')")
|
537
499
|
|
538
|
-
|
500
|
+
return unless index_name
|
539
501
|
|
540
|
-
|
541
|
-
|
502
|
+
execute("ALTER INDEX #{quote_column_name(index_name)} REBUILD TABLESPACE #{tablespace}")
|
503
|
+
end
|
542
504
|
end
|
543
505
|
end
|
544
506
|
end
|
@@ -16,7 +16,7 @@ module ActiveRecord
|
|
16
16
|
# # ...
|
17
17
|
# end
|
18
18
|
#
|
19
|
-
def add_primary_key_trigger(table_name, options={})
|
19
|
+
def add_primary_key_trigger(table_name, options = {})
|
20
20
|
# call the same private method that is used for create_table :primary_key_trigger => true
|
21
21
|
create_primary_key_trigger(table_name, options)
|
22
22
|
end
|
@@ -50,8 +50,8 @@ module ActiveRecord
|
|
50
50
|
# get synonyms for schema dump
|
51
51
|
def synonyms #:nodoc:
|
52
52
|
select_all("SELECT synonym_name, table_owner, table_name, db_link FROM all_synonyms where owner = SYS_CONTEXT('userenv', 'session_user')").collect do |row|
|
53
|
-
OracleEnhanced::SynonymDefinition.new(oracle_downcase(row[
|
54
|
-
oracle_downcase(row[
|
53
|
+
OracleEnhanced::SynonymDefinition.new(oracle_downcase(row["synonym_name"]),
|
54
|
+
oracle_downcase(row["table_owner"]), oracle_downcase(row["table_name"]), oracle_downcase(row["db_link"]))
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -15,15 +15,15 @@ module ActiveRecord #:nodoc:
|
|
15
15
|
ORDER BY 1").each do |table_name|
|
16
16
|
virtual_columns = virtual_columns_for(table_name)
|
17
17
|
ddl = "CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n"
|
18
|
-
cols = select_all(
|
18
|
+
cols = select_all("
|
19
19
|
SELECT column_name, data_type, data_length, char_used, char_length, data_precision, data_scale, data_default, nullable
|
20
20
|
FROM all_tab_columns
|
21
21
|
WHERE table_name = '#{table_name}'
|
22
22
|
AND owner = SYS_CONTEXT('userenv', 'session_user')
|
23
23
|
ORDER BY column_id
|
24
|
-
|
25
|
-
if(v = virtual_columns.find {|col| col[
|
26
|
-
structure_dump_virtual_column(row, v[
|
24
|
+
").map do |row|
|
25
|
+
if (v = virtual_columns.find { |col| col["column_name"] == row["column_name"] })
|
26
|
+
structure_dump_virtual_column(row, v["data_default"])
|
27
27
|
else
|
28
28
|
structure_dump_column(row)
|
29
29
|
end
|
@@ -43,35 +43,35 @@ module ActiveRecord #:nodoc:
|
|
43
43
|
|
44
44
|
def structure_dump_column(column) #:nodoc:
|
45
45
|
col = "\"#{column['column_name']}\" #{column['data_type']}"
|
46
|
-
if column[
|
46
|
+
if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
|
47
47
|
col << "(#{column['data_precision'].to_i}"
|
48
|
-
col << ",#{column['data_scale'].to_i}" if !column[
|
49
|
-
col <<
|
50
|
-
elsif column[
|
51
|
-
length = column[
|
52
|
-
col <<
|
48
|
+
col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
|
49
|
+
col << ")"
|
50
|
+
elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
|
51
|
+
length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
|
52
|
+
col << "(#{length})"
|
53
53
|
end
|
54
|
-
col << " DEFAULT #{column['data_default']}" if !column[
|
55
|
-
col <<
|
54
|
+
col << " DEFAULT #{column['data_default']}" if !column["data_default"].nil?
|
55
|
+
col << " NOT NULL" if column["nullable"] == "N"
|
56
56
|
col
|
57
57
|
end
|
58
58
|
|
59
59
|
def structure_dump_virtual_column(column, data_default) #:nodoc:
|
60
|
-
data_default = data_default.gsub(/"/,
|
60
|
+
data_default = data_default.gsub(/"/, "")
|
61
61
|
col = "\"#{column['column_name']}\" #{column['data_type']}"
|
62
|
-
if column[
|
62
|
+
if (column["data_type"] == "NUMBER") && !column["data_precision"].nil?
|
63
63
|
col << "(#{column['data_precision'].to_i}"
|
64
|
-
col << ",#{column['data_scale'].to_i}" if !column[
|
65
|
-
col <<
|
66
|
-
elsif column[
|
67
|
-
length = column[
|
68
|
-
col <<
|
64
|
+
col << ",#{column['data_scale'].to_i}" if !column["data_scale"].nil?
|
65
|
+
col << ")"
|
66
|
+
elsif column["data_type"].include?("CHAR") || column["data_type"] == "RAW"
|
67
|
+
length = column["char_used"] == "C" ? column["char_length"].to_i : column["data_length"].to_i
|
68
|
+
col << "(#{length})"
|
69
69
|
end
|
70
70
|
col << " GENERATED ALWAYS AS (#{data_default}) VIRTUAL"
|
71
71
|
end
|
72
72
|
|
73
73
|
def structure_dump_primary_key(table) #:nodoc:
|
74
|
-
opts = {:
|
74
|
+
opts = { name: "", cols: [] }
|
75
75
|
pks = select_all(<<-SQL, "Primary Keys")
|
76
76
|
SELECT a.constraint_name, a.column_name, a.position
|
77
77
|
FROM all_cons_columns a
|
@@ -83,10 +83,10 @@ module ActiveRecord #:nodoc:
|
|
83
83
|
AND c.owner = SYS_CONTEXT('userenv', 'current_schema')
|
84
84
|
SQL
|
85
85
|
pks.each do |row|
|
86
|
-
opts[:name] = row[
|
87
|
-
opts[:cols][row[
|
86
|
+
opts[:name] = row["constraint_name"]
|
87
|
+
opts[:cols][row["position"] - 1] = row["column_name"]
|
88
88
|
end
|
89
|
-
opts[:cols].length > 0 ? ",\n CONSTRAINT #{opts[:name]} PRIMARY KEY (#{opts[:cols].join(',')})" :
|
89
|
+
opts[:cols].length > 0 ? ",\n CONSTRAINT #{opts[:name]} PRIMARY KEY (#{opts[:cols].join(',')})" : ""
|
90
90
|
end
|
91
91
|
|
92
92
|
def structure_dump_unique_keys(table) #:nodoc:
|
@@ -102,10 +102,10 @@ module ActiveRecord #:nodoc:
|
|
102
102
|
AND c.owner = SYS_CONTEXT('userenv', 'current_schema')
|
103
103
|
SQL
|
104
104
|
uks.each do |uk|
|
105
|
-
keys[uk[
|
106
|
-
keys[uk[
|
105
|
+
keys[uk["constraint_name"]] ||= []
|
106
|
+
keys[uk["constraint_name"]][uk["position"] - 1] = uk["column_name"]
|
107
107
|
end
|
108
|
-
keys.map do |k,v|
|
108
|
+
keys.map do |k, v|
|
109
109
|
"ALTER TABLE #{table.upcase} ADD CONSTRAINT #{k} UNIQUE (#{v.join(',')})"
|
110
110
|
end
|
111
111
|
end
|
@@ -113,8 +113,8 @@ module ActiveRecord #:nodoc:
|
|
113
113
|
def structure_dump_indexes(table_name) #:nodoc:
|
114
114
|
indexes(table_name).map do |options|
|
115
115
|
column_names = options[:columns]
|
116
|
-
options = {:
|
117
|
-
index_name
|
116
|
+
options = { name: options[:name], unique: options[:unique] }
|
117
|
+
index_name = index_name(table_name, column: column_names)
|
118
118
|
if Hash === options # legacy support, since this param was a string
|
119
119
|
index_type = options[:unique] ? "UNIQUE" : ""
|
120
120
|
index_name = options[:name] || index_name
|
@@ -164,22 +164,11 @@ module ActiveRecord #:nodoc:
|
|
164
164
|
end
|
165
165
|
|
166
166
|
def foreign_key_definition(to_table, options = {}) #:nodoc:
|
167
|
-
|
167
|
+
column_sql = quote_column_name(options[:column] || "#{to_table.to_s.singularize}_id")
|
168
|
+
references = options[:references] ? options[:references].first : nil
|
169
|
+
references_sql = quote_column_name(options[:primary_key] || references || "id")
|
168
170
|
|
169
|
-
|
170
|
-
# composite foreign key
|
171
|
-
columns_sql = columns.map {|c| quote_column_name(c)}.join(',')
|
172
|
-
references = options[:references] || columns
|
173
|
-
references_sql = references.map {|c| quote_column_name(c)}.join(',')
|
174
|
-
else
|
175
|
-
columns_sql = quote_column_name(columns.first || "#{to_table.to_s.singularize}_id")
|
176
|
-
references = options[:references] ? options[:references].first : nil
|
177
|
-
references_sql = quote_column_name(options[:primary_key] || references || "id")
|
178
|
-
end
|
179
|
-
|
180
|
-
table_name = to_table
|
181
|
-
|
182
|
-
sql = "FOREIGN KEY (#{columns_sql}) REFERENCES #{quote_table_name(table_name)}(#{references_sql})"
|
171
|
+
sql = "FOREIGN KEY (#{column_sql}) REFERENCES #{quote_table_name(to_table)}(#{references_sql})"
|
183
172
|
|
184
173
|
case options[:dependent]
|
185
174
|
when :nullify
|
@@ -199,17 +188,17 @@ module ActiveRecord #:nodoc:
|
|
199
188
|
AND name NOT LIKE 'BIN$%'
|
200
189
|
AND owner = SYS_CONTEXT('userenv', 'current_schema') ORDER BY type").each do |source|
|
201
190
|
ddl = "CREATE OR REPLACE \n"
|
202
|
-
select_all(
|
191
|
+
select_all("
|
203
192
|
SELECT text
|
204
193
|
FROM all_source
|
205
194
|
WHERE name = '#{source['name']}'
|
206
195
|
AND type = '#{source['type']}'
|
207
196
|
AND owner = SYS_CONTEXT('userenv', 'current_schema')
|
208
197
|
ORDER BY line
|
209
|
-
|
210
|
-
ddl << row[
|
198
|
+
").each do |row|
|
199
|
+
ddl << row["text"]
|
211
200
|
end
|
212
|
-
ddl << ";" unless ddl.strip[-1,1] ==
|
201
|
+
ddl << ";" unless ddl.strip[-1, 1] == ";"
|
213
202
|
structure << ddl
|
214
203
|
end
|
215
204
|
|
@@ -251,7 +240,7 @@ module ActiveRecord #:nodoc:
|
|
251
240
|
end)
|
252
241
|
end
|
253
242
|
|
254
|
-
def full_drop(preserve_tables=false) #:nodoc:
|
243
|
+
def full_drop(preserve_tables = false) #:nodoc:
|
255
244
|
s = preserve_tables ? [] : [structure_drop]
|
256
245
|
s << temp_table_drop if preserve_tables
|
257
246
|
s << drop_sql_for_feature("view")
|
@@ -264,30 +253,6 @@ module ActiveRecord #:nodoc:
|
|
264
253
|
s.join
|
265
254
|
end
|
266
255
|
|
267
|
-
def add_column_options!(sql, options) #:nodoc:
|
268
|
-
type = options[:type] || ((column = options[:column]) && column.type)
|
269
|
-
type = type && type.to_sym
|
270
|
-
# handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
|
271
|
-
if options_include_default?(options)
|
272
|
-
if type == :text
|
273
|
-
sql << " DEFAULT #{quote(options[:default])}"
|
274
|
-
else
|
275
|
-
# from abstract adapter
|
276
|
-
sql << " DEFAULT #{quote(options[:default], options[:column])}"
|
277
|
-
end
|
278
|
-
end
|
279
|
-
# must explicitly add NULL or NOT NULL to allow change_column to work on migrations
|
280
|
-
if options[:null] == false
|
281
|
-
sql << " NOT NULL"
|
282
|
-
elsif options[:null] == true
|
283
|
-
sql << " NULL" unless type == :primary_key
|
284
|
-
end
|
285
|
-
# add AS expression for virtual columns
|
286
|
-
if options[:as].present?
|
287
|
-
sql << " AS (#{options[:as]})"
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
256
|
def execute_structure_dump(string)
|
292
257
|
string.split(STATEMENT_TOKEN).each do |ddl|
|
293
258
|
execute(ddl) unless ddl.blank?
|
@@ -296,44 +261,44 @@ module ActiveRecord #:nodoc:
|
|
296
261
|
|
297
262
|
private
|
298
263
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
264
|
+
# virtual columns are an 11g feature. This returns [] if feature is not
|
265
|
+
# present or none are found.
|
266
|
+
# return [{'column_name' => 'FOOS', 'data_default' => '...'}, ...]
|
267
|
+
def virtual_columns_for(table)
|
268
|
+
begin
|
269
|
+
select_all <<-SQL
|
305
270
|
SELECT column_name, data_default
|
306
271
|
FROM all_tab_cols
|
307
272
|
WHERE virtual_column = 'YES'
|
308
273
|
AND owner = SYS_CONTEXT('userenv', 'session_user')
|
309
274
|
AND table_name = '#{table.upcase}'
|
310
275
|
SQL
|
311
|
-
|
312
|
-
|
313
|
-
|
276
|
+
# feature not supported previous to 11g
|
277
|
+
rescue ActiveRecord::StatementInvalid => _e
|
278
|
+
[]
|
279
|
+
end
|
314
280
|
end
|
315
|
-
end
|
316
281
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
282
|
+
def drop_sql_for_feature(type)
|
283
|
+
short_type = type == "materialized view" ? "mview" : type
|
284
|
+
join_with_statement_token(
|
285
|
+
select_values("SELECT #{short_type}_name FROM all_#{short_type.tableize} where owner = SYS_CONTEXT('userenv', 'session_user')").map do |name|
|
286
|
+
"DROP #{type.upcase} \"#{name}\""
|
287
|
+
end)
|
288
|
+
end
|
324
289
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
290
|
+
def drop_sql_for_object(type)
|
291
|
+
join_with_statement_token(
|
292
|
+
select_values("SELECT object_name FROM all_objects WHERE object_type = '#{type.upcase}' and owner = SYS_CONTEXT('userenv', 'session_user')").map do |name|
|
293
|
+
"DROP #{type.upcase} \"#{name}\""
|
294
|
+
end)
|
295
|
+
end
|
331
296
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
297
|
+
def join_with_statement_token(array)
|
298
|
+
string = array.join(STATEMENT_TOKEN)
|
299
|
+
string << STATEMENT_TOKEN unless string.blank?
|
300
|
+
string
|
301
|
+
end
|
337
302
|
end
|
338
303
|
end
|
339
304
|
end
|