activerecord-oracle_enhanced-adapter 1.6.9 → 1.7.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/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'
|