activerecord-oracle_enhanced-adapter 1.6.9 → 1.7.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +10 -11
- data/History.md +126 -14
- data/README.md +9 -6
- data/RUNNING_TESTS.md +1 -1
- data/Rakefile +1 -16
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +15 -52
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +8 -22
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +53 -45
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +6 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +23 -62
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +46 -56
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +35 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +34 -21
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +36 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +174 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +17 -8
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +17 -11
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +160 -178
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +42 -94
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +50 -54
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +15 -11
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +197 -301
- data/lib/active_record/oracle_enhanced/type/integer.rb +3 -2
- data/lib/active_record/oracle_enhanced/type/national_character_string.rb +25 -0
- data/lib/active_record/oracle_enhanced/type/raw.rb +14 -2
- data/lib/active_record/oracle_enhanced/type/string.rb +28 -0
- data/lib/active_record/oracle_enhanced/type/text.rb +32 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +12 -17
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +113 -135
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +51 -59
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +40 -41
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +6 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +281 -233
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +7 -7
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +10 -10
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +22 -22
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +36 -37
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +86 -46
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +194 -294
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +53 -39
- data/spec/spec_helper.rb +0 -6
- metadata +42 -143
- data/.travis.yml +0 -39
- data/.travis/oracle/download.sh +0 -14
- data/.travis/oracle/install.sh +0 -31
- data/.travis/setup_accounts.sh +0 -9
- data/lib/active_record/connection_adapters/oracle_enhanced/dirty.rb +0 -40
- data/lib/active_record/oracle_enhanced/type/timestamp.rb +0 -11
- data/spec/spec_config.yaml.template +0 -11
- data/spec/support/alter_system_user_password.sql +0 -2
- data/spec/support/create_oracle_enhanced_users.sql +0 -31
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
# oracle_enhanced_adapter.rb -- ActiveRecord adapter for Oracle 8i, 9i, 10g, 11g
|
3
2
|
#
|
4
3
|
# Authors or original oracle_adapter: Graham Jenkins, Michael Schoen
|
@@ -33,15 +32,14 @@ require 'active_record/connection_adapters/abstract_adapter'
|
|
33
32
|
require 'active_record/connection_adapters/oracle_enhanced/connection'
|
34
33
|
require 'active_record/connection_adapters/oracle_enhanced/database_statements'
|
35
34
|
require 'active_record/connection_adapters/oracle_enhanced/schema_statements'
|
35
|
+
require 'active_record/connection_adapters/oracle_enhanced/schema_statements_ext'
|
36
36
|
require 'active_record/connection_adapters/oracle_enhanced/column_dumper'
|
37
37
|
require 'active_record/connection_adapters/oracle_enhanced/context_index'
|
38
|
-
|
39
38
|
require 'active_record/connection_adapters/oracle_enhanced/column'
|
39
|
+
require 'active_record/connection_adapters/oracle_enhanced/quoting'
|
40
40
|
|
41
41
|
require 'digest/sha1'
|
42
42
|
|
43
|
-
require 'arel/visitors/bind_visitor'
|
44
|
-
|
45
43
|
ActiveRecord::Base.class_eval do
|
46
44
|
class_attribute :custom_create_method, :custom_update_method, :custom_delete_method
|
47
45
|
end
|
@@ -60,21 +58,30 @@ module ActiveRecord
|
|
60
58
|
#
|
61
59
|
# set_date_columns :created_on, :updated_on
|
62
60
|
def self.set_date_columns(*args)
|
63
|
-
|
61
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
62
|
+
'set_date_columns` has been deprecated. Please use Rails attribute API.
|
63
|
+
MSG
|
64
|
+
# connection.set_type_for_columns(table_name,:date,*args)
|
64
65
|
end
|
65
66
|
|
66
67
|
# Specify which table columns should be typecasted to Time (or DateTime), e.g.:
|
67
68
|
#
|
68
69
|
# set_datetime_columns :created_date, :updated_date
|
69
70
|
def self.set_datetime_columns(*args)
|
70
|
-
|
71
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
72
|
+
'set_datetime_columns` has been deprecated. Please use Rails attribute API.
|
73
|
+
MSG
|
74
|
+
# connection.set_type_for_columns(table_name,:datetime,*args)
|
71
75
|
end
|
72
76
|
|
73
77
|
# Specify which table columns should be typecasted to boolean values +true+ or +false+, e.g.:
|
74
78
|
#
|
75
79
|
# set_boolean_columns :is_valid, :is_completed
|
76
80
|
def self.set_boolean_columns(*args)
|
77
|
-
|
81
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
82
|
+
'set_boolean_columns` has been deprecated. Please use Rails attribute API.
|
83
|
+
MSG
|
84
|
+
# connection.set_type_for_columns(table_name,:boolean,*args)
|
78
85
|
end
|
79
86
|
|
80
87
|
# Specify which table columns should be typecasted to integer values.
|
@@ -83,7 +90,10 @@ module ActiveRecord
|
|
83
90
|
#
|
84
91
|
# set_integer_columns :version_number, :object_identifier
|
85
92
|
def self.set_integer_columns(*args)
|
86
|
-
|
93
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
94
|
+
'set_integer_columns` has been deprecated. Please use Rails attribute API.
|
95
|
+
MSG
|
96
|
+
# connection.set_type_for_columns(table_name,:integer,*args)
|
87
97
|
end
|
88
98
|
|
89
99
|
# Specify which table columns should be typecasted to string values.
|
@@ -91,11 +101,15 @@ module ActiveRecord
|
|
91
101
|
#
|
92
102
|
# set_string_columns :active_flag
|
93
103
|
def self.set_string_columns(*args)
|
94
|
-
|
104
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
105
|
+
'set_string_columns` has been deprecated. Please use Rails attribute API.
|
106
|
+
MSG
|
107
|
+
# connection.set_type_for_columns(table_name,:string,*args)
|
95
108
|
end
|
96
109
|
|
97
110
|
# Get table comment from schema definition.
|
98
111
|
def self.table_comment
|
112
|
+
#TODO: may be deprecated
|
99
113
|
connection.table_comment(self.table_name)
|
100
114
|
end
|
101
115
|
|
@@ -225,8 +239,10 @@ module ActiveRecord
|
|
225
239
|
# TODO: Use relative
|
226
240
|
include ActiveRecord::ConnectionAdapters::OracleEnhanced::DatabaseStatements
|
227
241
|
include ActiveRecord::ConnectionAdapters::OracleEnhanced::SchemaStatements
|
242
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhanced::SchemaStatementsExt
|
228
243
|
include ActiveRecord::ConnectionAdapters::OracleEnhanced::ColumnDumper
|
229
244
|
include ActiveRecord::ConnectionAdapters::OracleEnhanced::ContextIndex
|
245
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhanced::Quoting
|
230
246
|
|
231
247
|
def schema_creation
|
232
248
|
OracleEnhanced::SchemaCreation.new self
|
@@ -389,19 +405,11 @@ module ActiveRecord
|
|
389
405
|
end
|
390
406
|
end
|
391
407
|
|
392
|
-
def initialize(connection, logger, config)
|
393
|
-
super(connection, logger)
|
408
|
+
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
409
|
+
super(connection, logger, config)
|
394
410
|
@quoted_column_names, @quoted_table_names = {}, {}
|
395
|
-
@config = config
|
396
411
|
@statements = StatementPool.new(connection, config.fetch(:statement_limit) { 250 })
|
397
412
|
@enable_dbms_output = false
|
398
|
-
@visitor = Arel::Visitors::Oracle.new self
|
399
|
-
|
400
|
-
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
401
|
-
@prepared_statements = true
|
402
|
-
else
|
403
|
-
@prepared_statements = false
|
404
|
-
end
|
405
413
|
end
|
406
414
|
|
407
415
|
ADAPTER_NAME = 'OracleEnhanced'.freeze
|
@@ -410,6 +418,14 @@ module ActiveRecord
|
|
410
418
|
ADAPTER_NAME
|
411
419
|
end
|
412
420
|
|
421
|
+
def arel_visitor # :nodoc:
|
422
|
+
if supports_fetch_first_n_rows_and_offset?
|
423
|
+
Arel::Visitors::Oracle12.new(self)
|
424
|
+
else
|
425
|
+
Arel::Visitors::Oracle.new(self)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
413
429
|
def supports_migrations? #:nodoc:
|
414
430
|
true
|
415
431
|
end
|
@@ -434,6 +450,24 @@ module ActiveRecord
|
|
434
450
|
true
|
435
451
|
end
|
436
452
|
|
453
|
+
def supports_fetch_first_n_rows_and_offset?
|
454
|
+
if @connection.database_version == [12,1]
|
455
|
+
true
|
456
|
+
else
|
457
|
+
false
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
def supports_datetime_with_precision?
|
462
|
+
#TODO: Needs to consider to return false to keep old behaviour
|
463
|
+
#to map :datetime as DATE
|
464
|
+
@connection.database_version.first >= 9
|
465
|
+
end
|
466
|
+
|
467
|
+
def supports_comments?
|
468
|
+
true
|
469
|
+
end
|
470
|
+
|
437
471
|
#:stopdoc:
|
438
472
|
DEFAULT_NLS_PARAMETERS = {
|
439
473
|
:nls_calendar => nil,
|
@@ -463,11 +497,12 @@ module ActiveRecord
|
|
463
497
|
:integer => { :name => "NUMBER", :limit => 38 },
|
464
498
|
:float => { :name => "BINARY_FLOAT" },
|
465
499
|
:decimal => { :name => "DECIMAL" },
|
466
|
-
:
|
500
|
+
#TODO: Needs to consider to support :datetime as DATE
|
501
|
+
:datetime => { :name => "TIMESTAMP" },
|
467
502
|
# changed to native TIMESTAMP type
|
468
503
|
# :timestamp => { :name => "DATE" },
|
469
504
|
:timestamp => { :name => "TIMESTAMP" },
|
470
|
-
:time => { :name => "
|
505
|
+
:time => { :name => "TIMESTAMP" },
|
471
506
|
:date => { :name => "DATE" },
|
472
507
|
:binary => { :name => "BLOB" },
|
473
508
|
:boolean => { :name => "NUMBER", :limit => 1 },
|
@@ -528,178 +563,6 @@ module ActiveRecord
|
|
528
563
|
end
|
529
564
|
alias ids_in_list_limit in_clause_length
|
530
565
|
|
531
|
-
# QUOTING ==================================================
|
532
|
-
#
|
533
|
-
# see: abstract/quoting.rb
|
534
|
-
|
535
|
-
def quote_column_name(name) #:nodoc:
|
536
|
-
name = name.to_s
|
537
|
-
@quoted_column_names[name] ||= begin
|
538
|
-
# if only valid lowercase column characters in name
|
539
|
-
if name =~ /\A[a-z][a-z_0-9\$#]*\Z/
|
540
|
-
"\"#{name.upcase}\""
|
541
|
-
else
|
542
|
-
# remove double quotes which cannot be used inside quoted identifier
|
543
|
-
"\"#{name.gsub('"', '')}\""
|
544
|
-
end
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
# This method is used in add_index to identify either column name (which is quoted)
|
549
|
-
# or function based index (in which case function expression is not quoted)
|
550
|
-
def quote_column_name_or_expression(name) #:nodoc:
|
551
|
-
name = name.to_s
|
552
|
-
case name
|
553
|
-
# if only valid lowercase column characters in name
|
554
|
-
when /^[a-z][a-z_0-9\$#]*$/
|
555
|
-
"\"#{name.upcase}\""
|
556
|
-
when /^[a-z][a-z_0-9\$#\-]*$/i
|
557
|
-
"\"#{name}\""
|
558
|
-
# if other characters present then assume that it is expression
|
559
|
-
# which should not be quoted
|
560
|
-
else
|
561
|
-
name
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
# Used only for quoting database links as the naming rules for links
|
566
|
-
# differ from the rules for column names. Specifically, link names may
|
567
|
-
# include periods.
|
568
|
-
def quote_database_link(name)
|
569
|
-
case name
|
570
|
-
when NONQUOTED_DATABASE_LINK
|
571
|
-
%Q("#{name.upcase}")
|
572
|
-
else
|
573
|
-
name
|
574
|
-
end
|
575
|
-
end
|
576
|
-
|
577
|
-
# Names must be from 1 to 30 bytes long with these exceptions:
|
578
|
-
# * Names of databases are limited to 8 bytes.
|
579
|
-
# * Names of database links can be as long as 128 bytes.
|
580
|
-
#
|
581
|
-
# Nonquoted identifiers cannot be Oracle Database reserved words
|
582
|
-
#
|
583
|
-
# Nonquoted identifiers must begin with an alphabetic character from
|
584
|
-
# your database character set
|
585
|
-
#
|
586
|
-
# Nonquoted identifiers can contain only alphanumeric characters from
|
587
|
-
# your database character set and the underscore (_), dollar sign ($),
|
588
|
-
# and pound sign (#). Database links can also contain periods (.) and
|
589
|
-
# "at" signs (@). Oracle strongly discourages you from using $ and # in
|
590
|
-
# nonquoted identifiers.
|
591
|
-
NONQUOTED_OBJECT_NAME = /[A-Za-z][A-z0-9$#]{0,29}/
|
592
|
-
NONQUOTED_DATABASE_LINK = /[A-Za-z][A-z0-9$#\.@]{0,127}/
|
593
|
-
VALID_TABLE_NAME = /\A(?:#{NONQUOTED_OBJECT_NAME}\.)?#{NONQUOTED_OBJECT_NAME}(?:@#{NONQUOTED_DATABASE_LINK})?\Z/
|
594
|
-
|
595
|
-
# unescaped table name should start with letter and
|
596
|
-
# contain letters, digits, _, $ or #
|
597
|
-
# can be prefixed with schema name
|
598
|
-
# CamelCase table names should be quoted
|
599
|
-
def self.valid_table_name?(name) #:nodoc:
|
600
|
-
name = name.to_s
|
601
|
-
name =~ VALID_TABLE_NAME && !(name =~ /[A-Z]/ && name =~ /[a-z]/) ? true : false
|
602
|
-
end
|
603
|
-
|
604
|
-
def quote_table_name(name) #:nodoc:
|
605
|
-
name, link = name.to_s.split('@')
|
606
|
-
@quoted_table_names[name] ||= [name.split('.').map{|n| quote_column_name(n)}.join('.'), quote_database_link(link)].compact.join('@')
|
607
|
-
end
|
608
|
-
|
609
|
-
def quote_string(s) #:nodoc:
|
610
|
-
s.gsub(/'/, "''")
|
611
|
-
end
|
612
|
-
|
613
|
-
def quote(value, column = nil) #:nodoc:
|
614
|
-
if value && column
|
615
|
-
case column.type
|
616
|
-
when :text, :binary
|
617
|
-
%Q{empty_#{ type_to_sql(column.type.to_sym).downcase rescue 'blob' }()}
|
618
|
-
# NLS_DATE_FORMAT independent TIMESTAMP support
|
619
|
-
when :timestamp
|
620
|
-
quote_timestamp_with_to_timestamp(value)
|
621
|
-
# NLS_DATE_FORMAT independent DATE support
|
622
|
-
when :date, :time, :datetime
|
623
|
-
quote_date_with_to_date(value)
|
624
|
-
when :raw
|
625
|
-
quote_raw(value)
|
626
|
-
when :string
|
627
|
-
# NCHAR and NVARCHAR2 literals should be quoted with N'...'.
|
628
|
-
# Read directly instance variable as otherwise migrations with table column default values are failing
|
629
|
-
# as migrations pass ColumnDefinition object to this method.
|
630
|
-
# Check if instance variable is defined to avoid warnings about accessing undefined instance variable.
|
631
|
-
column.instance_variable_defined?('@nchar') && column.instance_variable_get('@nchar') ? 'N' << super : super
|
632
|
-
else
|
633
|
-
super
|
634
|
-
end
|
635
|
-
elsif value.acts_like?(:date)
|
636
|
-
quote_date_with_to_date(value)
|
637
|
-
elsif value.acts_like?(:time)
|
638
|
-
value.to_i == value.to_f ? quote_date_with_to_date(value) : quote_timestamp_with_to_timestamp(value)
|
639
|
-
else
|
640
|
-
super
|
641
|
-
end
|
642
|
-
end
|
643
|
-
|
644
|
-
def quoted_true #:nodoc:
|
645
|
-
return "'#{self.class.boolean_to_string(true)}'" if emulate_booleans_from_strings
|
646
|
-
"1"
|
647
|
-
end
|
648
|
-
|
649
|
-
def quoted_false #:nodoc:
|
650
|
-
return "'#{self.class.boolean_to_string(false)}'" if emulate_booleans_from_strings
|
651
|
-
"0"
|
652
|
-
end
|
653
|
-
|
654
|
-
def quote_date_with_to_date(value) #:nodoc:
|
655
|
-
# should support that composite_primary_keys gem will pass date as string
|
656
|
-
value = quoted_date(value) if value.acts_like?(:date) || value.acts_like?(:time)
|
657
|
-
"TO_DATE('#{value}','YYYY-MM-DD HH24:MI:SS')"
|
658
|
-
end
|
659
|
-
|
660
|
-
# Encode a string or byte array as string of hex codes
|
661
|
-
def self.encode_raw(value)
|
662
|
-
# When given a string, convert to a byte array.
|
663
|
-
value = value.unpack('C*') if value.is_a?(String)
|
664
|
-
value.map { |x| "%02X" % x }.join
|
665
|
-
end
|
666
|
-
|
667
|
-
# quote encoded raw value
|
668
|
-
def quote_raw(value) #:nodoc:
|
669
|
-
"'#{self.class.encode_raw(value)}'"
|
670
|
-
end
|
671
|
-
|
672
|
-
def quote_timestamp_with_to_timestamp(value) #:nodoc:
|
673
|
-
# add up to 9 digits of fractional seconds to inserted time
|
674
|
-
value = "#{quoted_date(value)}:#{("%.6f"%value.to_f).split('.')[1]}" if value.acts_like?(:time)
|
675
|
-
"TO_TIMESTAMP('#{value}','YYYY-MM-DD HH24:MI:SS:FF6')"
|
676
|
-
end
|
677
|
-
|
678
|
-
# Cast a +value+ to a type that the database understands.
|
679
|
-
def type_cast(value, column)
|
680
|
-
if column && column.cast_type.is_a?(Type::Serialized)
|
681
|
-
super
|
682
|
-
else
|
683
|
-
case value
|
684
|
-
when true, false
|
685
|
-
if emulate_booleans_from_strings || column && column.type == :string
|
686
|
-
self.class.boolean_to_string(value)
|
687
|
-
else
|
688
|
-
value ? 1 : 0
|
689
|
-
end
|
690
|
-
when Date, Time
|
691
|
-
if value.acts_like?(:time)
|
692
|
-
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
693
|
-
value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
|
694
|
-
else
|
695
|
-
value
|
696
|
-
end
|
697
|
-
else
|
698
|
-
super
|
699
|
-
end
|
700
|
-
end
|
701
|
-
end
|
702
|
-
|
703
566
|
# CONNECTION MANAGEMENT ====================================
|
704
567
|
#
|
705
568
|
|
@@ -785,7 +648,7 @@ module ActiveRecord
|
|
785
648
|
end
|
786
649
|
|
787
650
|
def reset_pk_sequence!(table_name, primary_key = nil, sequence_name = nil) #:nodoc:
|
788
|
-
return nil unless
|
651
|
+
return nil unless data_source_exists?(table_name)
|
789
652
|
unless primary_key and sequence_name
|
790
653
|
# *Note*: Only primary key is implemented - sequence will be nil.
|
791
654
|
primary_key, sequence_name = pk_and_sequence_for(table_name)
|
@@ -825,8 +688,10 @@ module ActiveRecord
|
|
825
688
|
columns.each do |col|
|
826
689
|
value = attributes[col.name]
|
827
690
|
# changed sequence of next two lines - should check if value is nil before converting to yaml
|
828
|
-
next if value.
|
829
|
-
|
691
|
+
next if value.nil? || (value == '')
|
692
|
+
if klass.attribute_types[col.name].is_a? ActiveRecord::Type::Serialized
|
693
|
+
value = klass.attribute_types[col.name].serialize(value)
|
694
|
+
end
|
830
695
|
uncached do
|
831
696
|
sql = is_with_cpk ? "SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)} WHERE #{klass.composite_where_clause(id)} FOR UPDATE" :
|
832
697
|
"SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)} WHERE #{quote_column_name(klass.primary_key)} = #{id} FOR UPDATE"
|
@@ -860,19 +725,51 @@ module ActiveRecord
|
|
860
725
|
end
|
861
726
|
|
862
727
|
def tables(name = nil) #:nodoc:
|
728
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
729
|
+
#tables currently returns both tables and views.
|
730
|
+
This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
|
731
|
+
Use #data_sources instead.
|
732
|
+
MSG
|
733
|
+
|
734
|
+
if name
|
735
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
736
|
+
Passing arguments to #tables is deprecated without replacement.
|
737
|
+
MSG
|
738
|
+
end
|
739
|
+
|
740
|
+
data_sources
|
741
|
+
end
|
742
|
+
|
743
|
+
|
744
|
+
def data_sources
|
863
745
|
select_values(
|
864
746
|
"SELECT DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name) FROM all_tables WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'",
|
865
|
-
|
747
|
+
'SCHEMA')
|
866
748
|
end
|
867
749
|
|
868
|
-
# Will return true if database object exists (to be able to use also views and synonyms for ActiveRecord models)
|
869
750
|
def table_exists?(table_name)
|
751
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
752
|
+
#table_exists? currently checks both tables and views.
|
753
|
+
This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
|
754
|
+
Use #data_source_exists? instead.
|
755
|
+
MSG
|
756
|
+
|
757
|
+
data_source_exists?(table_name)
|
758
|
+
end
|
759
|
+
|
760
|
+
# Will return true if database object exists (to be able to use also views and synonyms for ActiveRecord models)
|
761
|
+
# Needs to consider how to support synonyms in Rails 5.1
|
762
|
+
def data_source_exists?(table_name)
|
870
763
|
(_owner, table_name, _db_link) = @connection.describe(table_name)
|
871
764
|
true
|
872
765
|
rescue
|
873
766
|
false
|
874
767
|
end
|
875
768
|
|
769
|
+
def views # :nodoc:
|
770
|
+
select_values("SELECT LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'session_user')")
|
771
|
+
end
|
772
|
+
|
876
773
|
def materialized_views #:nodoc:
|
877
774
|
select_values("SELECT LOWER(mview_name) FROM all_mviews WHERE owner = SYS_CONTEXT('userenv', 'current_schema')")
|
878
775
|
end
|
@@ -925,10 +822,19 @@ module ActiveRecord
|
|
925
822
|
statement_parameters = $1
|
926
823
|
end
|
927
824
|
end
|
928
|
-
all_schema_indexes << OracleEnhanced::IndexDefinition.new(
|
929
|
-
row['
|
930
|
-
row['
|
931
|
-
row['
|
825
|
+
all_schema_indexes << OracleEnhanced::IndexDefinition.new(
|
826
|
+
row['table_name'],
|
827
|
+
row['index_name'],
|
828
|
+
row['uniqueness'] == "UNIQUE",
|
829
|
+
[],
|
830
|
+
nil,
|
831
|
+
nil,
|
832
|
+
nil,
|
833
|
+
row['index_type'] == 'DOMAIN' ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
|
834
|
+
nil,
|
835
|
+
row['parameters'],
|
836
|
+
statement_parameters,
|
837
|
+
row['tablespace_name'] == default_tablespace_name ? nil : row['tablespace_name'])
|
932
838
|
current_index = row['index_name']
|
933
839
|
end
|
934
840
|
|
@@ -953,6 +859,10 @@ module ActiveRecord
|
|
953
859
|
|
954
860
|
# set ignored columns for table
|
955
861
|
def ignore_table_columns(table_name, *args) #:nodoc:
|
862
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
863
|
+
`ignore_table_columns` will be deprecated in next version of Oracle enhanced adapter
|
864
|
+
since Rails 5 introduces `ignored_columns`. Use `ignored_columns` instead of `ignore_table_columns`.
|
865
|
+
MSG
|
956
866
|
@@ignore_table_columns ||= {}
|
957
867
|
@@ignore_table_columns[table_name] ||= []
|
958
868
|
@@ignore_table_columns[table_name] += args.map{|a| a.to_s.downcase}
|
@@ -1036,19 +946,25 @@ module ActiveRecord
|
|
1036
946
|
@@do_not_prefetch_primary_key[table_name] = nil
|
1037
947
|
|
1038
948
|
table_cols = <<-SQL.strip.gsub(/\s+/, ' ')
|
1039
|
-
SELECT column_name AS name, data_type AS sql_type,
|
1040
|
-
|
949
|
+
SELECT cols.column_name AS name, cols.data_type AS sql_type,
|
950
|
+
cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
|
951
|
+
cols.data_type_owner AS sql_type_owner,
|
952
|
+
DECODE(cols.data_type, 'NUMBER', data_precision,
|
1041
953
|
'FLOAT', data_precision,
|
1042
954
|
'VARCHAR2', DECODE(char_used, 'C', char_length, data_length),
|
1043
955
|
'RAW', DECODE(char_used, 'C', char_length, data_length),
|
1044
956
|
'CHAR', DECODE(char_used, 'C', char_length, data_length),
|
1045
957
|
NULL) AS limit,
|
1046
|
-
DECODE(data_type, 'NUMBER', data_scale, NULL) AS scale
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
AND
|
1051
|
-
|
958
|
+
DECODE(data_type, 'NUMBER', data_scale, NULL) AS scale,
|
959
|
+
comments.comments as column_comment
|
960
|
+
FROM all_tab_cols#{db_link} cols, all_col_comments#{db_link} comments
|
961
|
+
WHERE cols.owner = '#{owner}'
|
962
|
+
AND cols.table_name = '#{desc_table_name}'
|
963
|
+
AND cols.hidden_column = 'NO'
|
964
|
+
AND cols.owner = comments.owner
|
965
|
+
AND cols.table_name = comments.table_name
|
966
|
+
AND cols.column_name = comments.column_name
|
967
|
+
ORDER BY cols.column_id
|
1052
968
|
SQL
|
1053
969
|
|
1054
970
|
# added deletion of ignored columns
|
@@ -1078,55 +994,21 @@ module ActiveRecord
|
|
1078
994
|
row['data_default'] = false if (row['data_default'] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings)
|
1079
995
|
end
|
1080
996
|
|
1081
|
-
|
1082
|
-
case row['sql_type']
|
1083
|
-
when /decimal|numeric|number/i
|
1084
|
-
if get_type_for_column(table_name, oracle_downcase(row['name'])) == :integer
|
1085
|
-
cast_type = ActiveRecord::OracleEnhanced::Type::Integer.new
|
1086
|
-
elsif OracleEnhancedAdapter.emulate_booleans && row['sql_type'].upcase == "NUMBER(1)"
|
1087
|
-
cast_type = Type::Boolean.new
|
1088
|
-
elsif OracleEnhancedAdapter.emulate_integers_by_column_name && OracleEnhancedAdapter.is_integer_column?(row['name'], table_name)
|
1089
|
-
cast_type = ActiveRecord::OracleEnhanced::Type::Integer.new
|
1090
|
-
else
|
1091
|
-
cast_type = lookup_cast_type(row['sql_type'])
|
1092
|
-
end
|
1093
|
-
when /char/i
|
1094
|
-
if get_type_for_column(table_name, oracle_downcase(row['name'])) == :string
|
1095
|
-
cast_type = Type::String.new
|
1096
|
-
elsif get_type_for_column(table_name, oracle_downcase(row['name'])) == :boolean
|
1097
|
-
cast_type = Type::Boolean.new
|
1098
|
-
elsif OracleEnhancedAdapter.emulate_booleans_from_strings && OracleEnhancedAdapter.is_boolean_column?(row['name'], row['sql_type'], table_name)
|
1099
|
-
cast_type = Type::Boolean.new
|
1100
|
-
else
|
1101
|
-
cast_type = lookup_cast_type(row['sql_type'])
|
1102
|
-
end
|
1103
|
-
when /date/i
|
1104
|
-
if get_type_for_column(table_name, oracle_downcase(row['name'])) == :date
|
1105
|
-
cast_type = Type::Date.new
|
1106
|
-
elsif get_type_for_column(table_name, oracle_downcase(row['name'])) == :datetime
|
1107
|
-
cast_type = Type::DateTime.new
|
1108
|
-
elsif OracleEnhancedAdapter.emulate_dates_by_column_name && OracleEnhancedAdapter.is_date_column?(row['name'], table_name)
|
1109
|
-
cast_type = Type::Date.new
|
1110
|
-
else
|
1111
|
-
cast_type = lookup_cast_type(row['sql_type'])
|
1112
|
-
end
|
1113
|
-
else
|
1114
|
-
cast_type = lookup_cast_type(row['sql_type'])
|
1115
|
-
end
|
1116
|
-
|
997
|
+
type_metadata = fetch_type_metadata(row['sql_type'])
|
1117
998
|
new_column(oracle_downcase(row['name']),
|
1118
999
|
row['data_default'],
|
1119
|
-
|
1120
|
-
row['sql_type'],
|
1000
|
+
type_metadata,
|
1121
1001
|
row['nullable'] == 'Y',
|
1122
1002
|
table_name,
|
1123
1003
|
is_virtual,
|
1124
|
-
false
|
1004
|
+
false,
|
1005
|
+
row['column_comment']
|
1006
|
+
)
|
1125
1007
|
end
|
1126
1008
|
end
|
1127
1009
|
|
1128
|
-
def new_column(name, default,
|
1129
|
-
OracleEnhancedColumn.new(name, default,
|
1010
|
+
def new_column(name, default, sql_type_metadata = nil, null = true, table_name = nil, virtual = false, returning_id = false,comment = nil) # :nodoc:
|
1011
|
+
OracleEnhancedColumn.new(name, default, sql_type_metadata, null, table_name, virtual, returning_id, comment)
|
1130
1012
|
end
|
1131
1013
|
|
1132
1014
|
# used just in tests to clear column cache
|
@@ -1187,6 +1069,12 @@ module ActiveRecord
|
|
1187
1069
|
AND cc.constraint_name = c.constraint_name
|
1188
1070
|
SQL
|
1189
1071
|
|
1072
|
+
warn <<-WARNING.strip_heredoc if pks.count > 1
|
1073
|
+
WARNING: Rails does not support composite primary key.
|
1074
|
+
|
1075
|
+
#{table_name} has composite primary key. Composite primary key is ignored.
|
1076
|
+
WARNING
|
1077
|
+
|
1190
1078
|
# only support single column keys
|
1191
1079
|
pks.size == 1 ? [oracle_downcase(pks.first),
|
1192
1080
|
oracle_downcase(seqs.first)] : nil
|
@@ -1202,31 +1090,20 @@ module ActiveRecord
|
|
1202
1090
|
!pk_and_sequence_for(table_name, owner, desc_table_name, db_link).nil?
|
1203
1091
|
end
|
1204
1092
|
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
super
|
1220
|
-
else
|
1221
|
-
order_columns = orders.map { |c|
|
1222
|
-
c = c.to_sql unless c.is_a?(String)
|
1223
|
-
# remove any ASC/DESC modifiers
|
1224
|
-
c.gsub(/\s+(ASC|DESC)\s*?/i, '')
|
1225
|
-
}.reject(&:blank?).map.with_index { |c,i|
|
1226
|
-
"FIRST_VALUE(#{c}) OVER (PARTITION BY #{columns} ORDER BY #{c}) AS alias_#{i}__"
|
1227
|
-
}
|
1228
|
-
[super].concat(order_columns).join(', ')
|
1229
|
-
end
|
1093
|
+
def primary_keys(table_name) # :nodoc:
|
1094
|
+
(owner, desc_table_name, db_link) = @connection.describe(table_name) unless owner
|
1095
|
+
|
1096
|
+
pks = select_values(<<-SQL.strip_heredoc, 'Primary Keys')
|
1097
|
+
SELECT cc.column_name
|
1098
|
+
FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc
|
1099
|
+
WHERE c.owner = '#{owner}'
|
1100
|
+
AND c.table_name = '#{desc_table_name}'
|
1101
|
+
AND c.constraint_type = 'P'
|
1102
|
+
AND cc.owner = c.owner
|
1103
|
+
AND cc.constraint_name = c.constraint_name
|
1104
|
+
order by cc.position
|
1105
|
+
SQL
|
1106
|
+
pks.map {|pk| oracle_downcase(pk)}
|
1230
1107
|
end
|
1231
1108
|
|
1232
1109
|
def columns_for_distinct(columns, orders) #:nodoc:
|
@@ -1246,24 +1123,37 @@ module ActiveRecord
|
|
1246
1123
|
end
|
1247
1124
|
|
1248
1125
|
def temporary_table?(table_name) #:nodoc:
|
1249
|
-
select_value("SELECT temporary FROM
|
1126
|
+
select_value("SELECT temporary FROM all_tables WHERE table_name = '#{table_name.upcase}' and owner = SYS_CONTEXT('userenv', 'session_user')") == 'Y'
|
1250
1127
|
end
|
1251
1128
|
|
1252
1129
|
# construct additional wrapper subquery if select.offset is used to avoid generation of invalid subquery
|
1253
1130
|
# ... IN ( SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM ( ... ) raw_sql_ ) WHERE raw_rnum_ > ... )
|
1254
|
-
def join_to_update(update, select) #:nodoc:
|
1255
|
-
if
|
1256
|
-
|
1257
|
-
|
1131
|
+
def join_to_update(update, select, key) #:nodoc:
|
1132
|
+
#TODO: Need to validate if we can remove join_to_update from Oracle enhanced adapter after testing
|
1133
|
+
# older version of Oracle 11gR2
|
1134
|
+
super
|
1135
|
+
end
|
1258
1136
|
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1137
|
+
def valid_type?(type)
|
1138
|
+
!native_database_types[type].nil?
|
1139
|
+
end
|
1262
1140
|
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1141
|
+
def combine_bind_parameters(
|
1142
|
+
from_clause: [],
|
1143
|
+
join_clause: [],
|
1144
|
+
where_clause: [],
|
1145
|
+
having_clause: [],
|
1146
|
+
limit: nil,
|
1147
|
+
offset: nil
|
1148
|
+
) # :nodoc:
|
1149
|
+
result = from_clause + join_clause + where_clause + having_clause
|
1150
|
+
if offset
|
1151
|
+
result << offset
|
1152
|
+
end
|
1153
|
+
if limit
|
1154
|
+
result << limit
|
1266
1155
|
end
|
1156
|
+
result
|
1267
1157
|
end
|
1268
1158
|
|
1269
1159
|
protected
|
@@ -1271,9 +1161,12 @@ module ActiveRecord
|
|
1271
1161
|
def initialize_type_map(m)
|
1272
1162
|
super
|
1273
1163
|
# oracle
|
1274
|
-
register_class_with_limit m, %r(date)i, Type::DateTime
|
1275
1164
|
register_class_with_limit m, %r(raw)i, ActiveRecord::OracleEnhanced::Type::Raw
|
1276
|
-
register_class_with_limit m, %r(
|
1165
|
+
register_class_with_limit m, %r(char)i, ActiveRecord::OracleEnhanced::Type::String
|
1166
|
+
register_class_with_limit m, %r(clob)i, ActiveRecord::OracleEnhanced::Type::Text
|
1167
|
+
|
1168
|
+
m.register_type 'NCHAR', ActiveRecord::OracleEnhanced::Type::NationalCharacterString.new
|
1169
|
+
m.alias_type %r(NVARCHAR2)i, 'NCHAR'
|
1277
1170
|
|
1278
1171
|
m.register_type(%r(NUMBER)i) do |sql_type|
|
1279
1172
|
scale = extract_scale(sql_type)
|
@@ -1285,6 +1178,8 @@ module ActiveRecord
|
|
1285
1178
|
Type::Decimal.new(precision: precision, scale: scale)
|
1286
1179
|
end
|
1287
1180
|
end
|
1181
|
+
|
1182
|
+
m.register_type %r(^NUMBER\(1\))i, Type::Boolean.new if OracleEnhancedAdapter.emulate_booleans
|
1288
1183
|
end
|
1289
1184
|
|
1290
1185
|
def extract_limit(sql_type) #:nodoc:
|
@@ -1299,9 +1194,11 @@ module ActiveRecord
|
|
1299
1194
|
def translate_exception(exception, message) #:nodoc:
|
1300
1195
|
case @connection.error_code(exception)
|
1301
1196
|
when 1
|
1302
|
-
RecordNotUnique.new(message
|
1197
|
+
RecordNotUnique.new(message)
|
1303
1198
|
when 2291
|
1304
|
-
InvalidForeignKey.new(message
|
1199
|
+
InvalidForeignKey.new(message)
|
1200
|
+
when 12899
|
1201
|
+
ValueTooLong.new(message)
|
1305
1202
|
else
|
1306
1203
|
super
|
1307
1204
|
end
|
@@ -1309,10 +1206,6 @@ module ActiveRecord
|
|
1309
1206
|
|
1310
1207
|
private
|
1311
1208
|
|
1312
|
-
def select(sql, name = nil, binds = [])
|
1313
|
-
exec_query(sql, name, binds)
|
1314
|
-
end
|
1315
|
-
|
1316
1209
|
def oracle_downcase(column_name)
|
1317
1210
|
@connection.oracle_downcase(column_name)
|
1318
1211
|
end
|
@@ -1390,9 +1283,6 @@ require 'active_record/connection_adapters/oracle_enhanced/context_index'
|
|
1390
1283
|
# Load additional methods for composite_primary_keys support
|
1391
1284
|
require 'active_record/connection_adapters/oracle_enhanced/cpk'
|
1392
1285
|
|
1393
|
-
# Load patch for dirty tracking methods
|
1394
|
-
require 'active_record/connection_adapters/oracle_enhanced/dirty'
|
1395
|
-
|
1396
1286
|
# Patches and enhancements for schema dumper
|
1397
1287
|
require 'active_record/connection_adapters/oracle_enhanced/schema_dumper'
|
1398
1288
|
|
@@ -1417,8 +1307,14 @@ require 'active_record/connection_adapters/oracle_enhanced/database_statements'
|
|
1417
1307
|
# Add Type:Raw
|
1418
1308
|
require 'active_record/oracle_enhanced/type/raw'
|
1419
1309
|
|
1420
|
-
# Add Type:Timestamp
|
1421
|
-
require 'active_record/oracle_enhanced/type/timestamp'
|
1422
|
-
|
1423
1310
|
# Add OracleEnhanced::Type::Integer
|
1424
1311
|
require 'active_record/oracle_enhanced/type/integer'
|
1312
|
+
|
1313
|
+
# Add OracleEnhanced::Type::String
|
1314
|
+
require 'active_record/oracle_enhanced/type/string'
|
1315
|
+
|
1316
|
+
# Add OracleEnhanced::Type::NationalCharacterString
|
1317
|
+
require 'active_record/oracle_enhanced/type/national_character_string'
|
1318
|
+
|
1319
|
+
# Add OracleEnhanced::Type::Text
|
1320
|
+
require 'active_record/oracle_enhanced/type/text'
|