activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|