activerecord-oracle_enhanced-adapter 6.1.6 → 7.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +53 -2
- data/README.md +1 -1
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +22 -13
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +16 -17
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +12 -6
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +4 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +18 -18
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +6 -6
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +16 -16
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +6 -6
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +35 -27
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +30 -29
- data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +124 -99
- data/lib/arel/visitors/oracle.rb +6 -2
- data/lib/arel/visitors/oracle12.rb +4 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +18 -1
- data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +5 -5
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +3 -3
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +5 -5
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +10 -10
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +34 -7
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +5 -5
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +2 -2
- metadata +5 -5
@@ -63,9 +63,9 @@ require "active_record/type/oracle_enhanced/timestampltz"
|
|
63
63
|
require "active_record/type/oracle_enhanced/character_string"
|
64
64
|
|
65
65
|
module ActiveRecord
|
66
|
-
module ConnectionHandling
|
66
|
+
module ConnectionHandling # :nodoc:
|
67
67
|
# Establishes a connection to the database that's used by all Active Record objects.
|
68
|
-
def oracle_enhanced_connection(config)
|
68
|
+
def oracle_enhanced_connection(config) # :nodoc:
|
69
69
|
if config[:emulate_oracle_adapter] == true
|
70
70
|
# allows the enhanced adapter to look like the OracleAdapter. Useful to pick up
|
71
71
|
# conditionals in the rails activerecord test suite
|
@@ -79,7 +79,7 @@ module ActiveRecord
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
module ConnectionAdapters
|
82
|
+
module ConnectionAdapters # :nodoc:
|
83
83
|
# Oracle enhanced adapter will work with both
|
84
84
|
# CRuby ruby-oci8 gem (which provides interface to Oracle OCI client)
|
85
85
|
# or with JRuby and Oracle JDBC driver.
|
@@ -120,6 +120,7 @@ module ActiveRecord
|
|
120
120
|
# * <tt>:schema</tt> - database schema which holds schema objects.
|
121
121
|
# * <tt>:tcp_keepalive</tt> - TCP keepalive is enabled for OCI client, defaults to true
|
122
122
|
# * <tt>:tcp_keepalive_time</tt> - TCP keepalive time for OCI client, defaults to 600
|
123
|
+
# * <tt>:jdbc_statement_cache_size</tt> - number of cached SQL cursors to keep open, disabled per default (for unpooled JDBC only)
|
123
124
|
#
|
124
125
|
# Optionals NLS parameters:
|
125
126
|
#
|
@@ -248,7 +249,7 @@ module ActiveRecord
|
|
248
249
|
|
249
250
|
ADAPTER_NAME = "OracleEnhanced"
|
250
251
|
|
251
|
-
def adapter_name
|
252
|
+
def adapter_name # :nodoc:
|
252
253
|
ADAPTER_NAME
|
253
254
|
end
|
254
255
|
|
@@ -272,11 +273,11 @@ module ActiveRecord
|
|
272
273
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
273
274
|
end
|
274
275
|
|
275
|
-
def supports_savepoints?
|
276
|
+
def supports_savepoints? # :nodoc:
|
276
277
|
true
|
277
278
|
end
|
278
279
|
|
279
|
-
def supports_transaction_isolation?
|
280
|
+
def supports_transaction_isolation? # :nodoc:
|
280
281
|
true
|
281
282
|
end
|
282
283
|
|
@@ -359,7 +360,7 @@ module ActiveRecord
|
|
359
360
|
end
|
360
361
|
end
|
361
362
|
|
362
|
-
|
363
|
+
# :stopdoc:
|
363
364
|
DEFAULT_NLS_PARAMETERS = {
|
364
365
|
nls_calendar: nil,
|
365
366
|
nls_comp: nil,
|
@@ -378,13 +379,13 @@ module ActiveRecord
|
|
378
379
|
nls_time_tz_format: nil
|
379
380
|
}
|
380
381
|
|
381
|
-
|
382
|
+
# :stopdoc:
|
382
383
|
FIXED_NLS_PARAMETERS = {
|
383
384
|
nls_date_format: "YYYY-MM-DD HH24:MI:SS",
|
384
385
|
nls_timestamp_format: "YYYY-MM-DD HH24:MI:SS:FF6"
|
385
386
|
}
|
386
387
|
|
387
|
-
|
388
|
+
# :stopdoc:
|
388
389
|
NATIVE_DATABASE_TYPES = {
|
389
390
|
primary_key: "NUMBER(38) NOT NULL PRIMARY KEY",
|
390
391
|
string: { name: "VARCHAR2", limit: 255 },
|
@@ -408,9 +409,9 @@ module ActiveRecord
|
|
408
409
|
NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS = NATIVE_DATABASE_TYPES.dup.merge(
|
409
410
|
boolean: { name: "VARCHAR2", limit: 1 }
|
410
411
|
)
|
411
|
-
|
412
|
+
# :startdoc:
|
412
413
|
|
413
|
-
def native_database_types
|
414
|
+
def native_database_types # :nodoc:
|
414
415
|
emulate_booleans_from_strings ? NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS : NATIVE_DATABASE_TYPES
|
415
416
|
end
|
416
417
|
|
@@ -420,10 +421,10 @@ module ActiveRecord
|
|
420
421
|
# If SQL statement fails due to lost connection then reconnect
|
421
422
|
# and retry SQL statement if autocommit mode is enabled.
|
422
423
|
# By default this functionality is disabled.
|
423
|
-
attr_reader :auto_retry
|
424
|
+
attr_reader :auto_retry # :nodoc:
|
424
425
|
@auto_retry = false
|
425
426
|
|
426
|
-
def auto_retry=(value)
|
427
|
+
def auto_retry=(value) # :nodoc:
|
427
428
|
@auto_retry = value
|
428
429
|
@connection.auto_retry = value if @connection
|
429
430
|
end
|
@@ -434,7 +435,7 @@ module ActiveRecord
|
|
434
435
|
end
|
435
436
|
|
436
437
|
# Returns true if the connection is active.
|
437
|
-
def active?
|
438
|
+
def active? # :nodoc:
|
438
439
|
# Pings the connection to check if it's still good. Note that an
|
439
440
|
# #active? method is also available, but that simply returns the
|
440
441
|
# last known state, which isn't good enough if the connection has
|
@@ -445,7 +446,7 @@ module ActiveRecord
|
|
445
446
|
end
|
446
447
|
|
447
448
|
# Reconnects to the database.
|
448
|
-
def reconnect!
|
449
|
+
def reconnect! # :nodoc:
|
449
450
|
super
|
450
451
|
@connection.reset!
|
451
452
|
rescue OracleEnhanced::ConnectionException => e
|
@@ -458,7 +459,7 @@ module ActiveRecord
|
|
458
459
|
end
|
459
460
|
|
460
461
|
# Disconnects from the database.
|
461
|
-
def disconnect!
|
462
|
+
def disconnect! # :nodoc:
|
462
463
|
super
|
463
464
|
@connection.logoff rescue nil
|
464
465
|
end
|
@@ -491,12 +492,12 @@ module ActiveRecord
|
|
491
492
|
do_not_prefetch = @do_not_prefetch_primary_key[table_name]
|
492
493
|
if do_not_prefetch.nil?
|
493
494
|
owner, desc_table_name = @connection.describe(table_name)
|
494
|
-
@do_not_prefetch_primary_key
|
495
|
+
@do_not_prefetch_primary_key[table_name] = do_not_prefetch = !has_primary_key?(table_name, owner, desc_table_name)
|
495
496
|
end
|
496
497
|
!do_not_prefetch
|
497
498
|
end
|
498
499
|
|
499
|
-
def reset_pk_sequence!(table_name, primary_key = nil, sequence_name = nil)
|
500
|
+
def reset_pk_sequence!(table_name, primary_key = nil, sequence_name = nil) # :nodoc:
|
500
501
|
return nil unless data_source_exists?(table_name)
|
501
502
|
unless primary_key && sequence_name
|
502
503
|
# *Note*: Only primary key is implemented - sequence will be nil.
|
@@ -561,7 +562,7 @@ module ActiveRecord
|
|
561
562
|
def column_definitions(table_name)
|
562
563
|
(owner, desc_table_name) = @connection.describe(table_name)
|
563
564
|
|
564
|
-
select_all(<<~SQL.squish, "SCHEMA")
|
565
|
+
select_all(<<~SQL.squish, "SCHEMA", [bind_string("owner", owner), bind_string("table_name", desc_table_name)])
|
565
566
|
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cols.column_name AS name, cols.data_type AS sql_type,
|
566
567
|
cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
|
567
568
|
cols.data_type_owner AS sql_type_owner,
|
@@ -574,8 +575,8 @@ module ActiveRecord
|
|
574
575
|
DECODE(data_type, 'NUMBER', data_scale, NULL) AS scale,
|
575
576
|
comments.comments as column_comment
|
576
577
|
FROM all_tab_cols cols, all_col_comments comments
|
577
|
-
WHERE cols.owner =
|
578
|
-
AND cols.table_name =
|
578
|
+
WHERE cols.owner = :owner
|
579
|
+
AND cols.table_name = :table_name
|
579
580
|
AND cols.hidden_column = 'NO'
|
580
581
|
AND cols.owner = comments.owner
|
581
582
|
AND cols.table_name = comments.table_name
|
@@ -590,22 +591,22 @@ module ActiveRecord
|
|
590
591
|
|
591
592
|
# Find a table's primary key and sequence.
|
592
593
|
# *Note*: Only primary key is implemented - sequence will be nil.
|
593
|
-
def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil)
|
594
|
+
def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil) # :nodoc:
|
594
595
|
(owner, desc_table_name) = @connection.describe(table_name)
|
595
596
|
|
596
|
-
seqs =
|
597
|
+
seqs = select_values_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("owner", owner), bind_string("sequence_name", default_sequence_name(desc_table_name))])
|
597
598
|
select /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ us.sequence_name
|
598
599
|
from all_sequences us
|
599
|
-
where us.sequence_owner =
|
600
|
-
and us.sequence_name = upper(
|
600
|
+
where us.sequence_owner = :owner
|
601
|
+
and us.sequence_name = upper(:sequence_name)
|
601
602
|
SQL
|
602
603
|
|
603
604
|
# changed back from user_constraints to all_constraints for consistency
|
604
|
-
pks =
|
605
|
+
pks = select_values_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("owner", owner), bind_string("table_name", desc_table_name)])
|
605
606
|
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
|
606
607
|
FROM all_constraints c, all_cons_columns cc
|
607
|
-
WHERE c.owner =
|
608
|
-
AND c.table_name =
|
608
|
+
WHERE c.owner = :owner
|
609
|
+
AND c.table_name = :table_name
|
609
610
|
AND c.constraint_type = 'P'
|
610
611
|
AND cc.owner = c.owner
|
611
612
|
AND cc.constraint_name = c.constraint_name
|
@@ -628,14 +629,14 @@ module ActiveRecord
|
|
628
629
|
pk_and_sequence && pk_and_sequence.first
|
629
630
|
end
|
630
631
|
|
631
|
-
def has_primary_key?(table_name, owner = nil, desc_table_name = nil)
|
632
|
+
def has_primary_key?(table_name, owner = nil, desc_table_name = nil) # :nodoc:
|
632
633
|
!pk_and_sequence_for(table_name, owner, desc_table_name).nil?
|
633
634
|
end
|
634
635
|
|
635
636
|
def primary_keys(table_name) # :nodoc:
|
636
637
|
(_owner, desc_table_name) = @connection.describe(table_name)
|
637
638
|
|
638
|
-
pks =
|
639
|
+
pks = select_values_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("table_name", desc_table_name)])
|
639
640
|
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */ cc.column_name
|
640
641
|
FROM all_constraints c, all_cons_columns cc
|
641
642
|
WHERE c.owner = SYS_CONTEXT('userenv', 'current_schema')
|
@@ -648,7 +649,7 @@ module ActiveRecord
|
|
648
649
|
pks.map { |pk| oracle_downcase(pk) }
|
649
650
|
end
|
650
651
|
|
651
|
-
def columns_for_distinct(columns, orders)
|
652
|
+
def columns_for_distinct(columns, orders) # :nodoc:
|
652
653
|
# construct a valid columns name for DISTINCT clause,
|
653
654
|
# ie. one that includes the ORDER BY columns, using FIRST_VALUE such that
|
654
655
|
# the inclusion of these columns doesn't invalidate the DISTINCT
|
@@ -661,11 +662,11 @@ module ActiveRecord
|
|
661
662
|
}.reject(&:blank?).map.with_index { |column, i|
|
662
663
|
"FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns} ORDER BY #{column}) AS alias_#{i}__"
|
663
664
|
}
|
664
|
-
|
665
|
+
[super, *order_columns].join(", ")
|
665
666
|
end
|
666
667
|
|
667
|
-
def temporary_table?(table_name)
|
668
|
-
|
668
|
+
def temporary_table?(table_name) # :nodoc:
|
669
|
+
select_value_forcing_binds(<<~SQL.squish, "SCHEMA", [bind_string("table_name", table_name.upcase)]) == "Y"
|
669
670
|
SELECT /*+ OPTIMIZER_FEATURES_ENABLE('11.2.0.2') */
|
670
671
|
temporary FROM all_tables WHERE table_name = :table_name and owner = SYS_CONTEXT('userenv', 'current_schema')
|
671
672
|
SQL
|
@@ -689,82 +690,106 @@ module ActiveRecord
|
|
689
690
|
end
|
690
691
|
end
|
691
692
|
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
693
|
+
class << self
|
694
|
+
private
|
695
|
+
def initialize_type_map(m)
|
696
|
+
super
|
697
|
+
# oracle
|
698
|
+
register_class_with_precision m, %r(WITH TIME ZONE)i, Type::OracleEnhanced::TimestampTz
|
699
|
+
register_class_with_precision m, %r(WITH LOCAL TIME ZONE)i, Type::OracleEnhanced::TimestampLtz
|
700
|
+
register_class_with_limit m, %r(raw)i, Type::OracleEnhanced::Raw
|
701
|
+
register_class_with_limit m, %r{^(char)}i, Type::OracleEnhanced::CharacterString
|
702
|
+
register_class_with_limit m, %r{^(nchar)}i, Type::OracleEnhanced::String
|
703
|
+
register_class_with_limit m, %r(varchar)i, Type::OracleEnhanced::String
|
704
|
+
register_class_with_limit m, %r(clob)i, Type::OracleEnhanced::Text
|
705
|
+
register_class_with_limit m, %r(nclob)i, Type::OracleEnhanced::NationalCharacterText
|
706
|
+
|
707
|
+
m.register_type "NCHAR", Type::OracleEnhanced::NationalCharacterString.new
|
708
|
+
m.alias_type %r(NVARCHAR2)i, "NCHAR"
|
709
|
+
|
710
|
+
m.register_type(%r(NUMBER)i) do |sql_type|
|
711
|
+
scale = extract_scale(sql_type)
|
712
|
+
precision = extract_precision(sql_type)
|
713
|
+
limit = extract_limit(sql_type)
|
714
|
+
if scale == 0
|
715
|
+
Type::OracleEnhanced::Integer.new(precision: precision, limit: limit)
|
716
|
+
else
|
717
|
+
Type::Decimal.new(precision: precision, scale: scale)
|
718
|
+
end
|
716
719
|
end
|
717
|
-
end
|
718
720
|
|
719
|
-
|
720
|
-
|
721
|
+
if OracleEnhancedAdapter.emulate_booleans
|
722
|
+
m.register_type %r(^NUMBER\(1\))i, Type::Boolean.new
|
723
|
+
end
|
721
724
|
end
|
722
|
-
|
725
|
+
end
|
723
726
|
|
724
|
-
|
725
|
-
case default
|
726
|
-
when String
|
727
|
-
default.gsub("''", "'")
|
728
|
-
else
|
729
|
-
default
|
730
|
-
end
|
731
|
-
end
|
727
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
732
728
|
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
729
|
+
def type_map
|
730
|
+
TYPE_MAP
|
731
|
+
end
|
732
|
+
|
733
|
+
def extract_value_from_default(default)
|
734
|
+
case default
|
735
|
+
when String
|
736
|
+
default.gsub("''", "'")
|
737
|
+
else
|
738
|
+
default
|
740
739
|
end
|
740
|
+
end
|
741
741
|
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
when 900, 904, 942, 955, 1418, 2289, 2449, 17008
|
749
|
-
ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
|
750
|
-
when 1400
|
751
|
-
ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
|
752
|
-
when 2291, 2292
|
753
|
-
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
754
|
-
when 12899
|
755
|
-
ValueTooLong.new(message, sql: sql, binds: binds)
|
756
|
-
else
|
757
|
-
super
|
758
|
-
end
|
742
|
+
def extract_limit(sql_type) # :nodoc:
|
743
|
+
case sql_type
|
744
|
+
when /^bigint/i
|
745
|
+
19
|
746
|
+
when /\((.*)\)/
|
747
|
+
$1.to_i
|
759
748
|
end
|
749
|
+
end
|
760
750
|
|
761
|
-
|
762
|
-
|
763
|
-
|
751
|
+
def translate_exception(exception, message:, sql:, binds:) # :nodoc:
|
752
|
+
case @connection.error_code(exception)
|
753
|
+
when 1
|
754
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
755
|
+
when 60
|
756
|
+
Deadlocked.new(message)
|
757
|
+
when 900, 904, 942, 955, 1418, 2289, 2449, 17008
|
758
|
+
ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds)
|
759
|
+
when 1400
|
760
|
+
ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
|
761
|
+
when 2291, 2292
|
762
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
763
|
+
when 12899
|
764
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
765
|
+
else
|
766
|
+
super
|
764
767
|
end
|
768
|
+
end
|
769
|
+
|
770
|
+
# create bind object for type String
|
771
|
+
def bind_string(name, value)
|
772
|
+
ActiveRecord::Relation::QueryAttribute.new(name, value, Type::OracleEnhanced::String.new)
|
773
|
+
end
|
774
|
+
|
775
|
+
# call select_values using binds even if surrounding SQL preparation/execution is done + # with conn.unprepared_statement (like AR.to_sql)
|
776
|
+
def select_values_forcing_binds(arel, name, binds)
|
777
|
+
# remove possible force of unprepared SQL during dictionary access
|
778
|
+
unprepared_statement_forced = prepared_statements_disabled_cache.include?(object_id)
|
779
|
+
prepared_statements_disabled_cache.delete(object_id) if unprepared_statement_forced
|
780
|
+
|
781
|
+
select_values(arel, name, binds)
|
782
|
+
ensure
|
783
|
+
# Restore unprepared_statement setting for surrounding SQL
|
784
|
+
prepared_statements_disabled_cache.add(object_id) if unprepared_statement_forced
|
785
|
+
end
|
786
|
+
|
787
|
+
def select_value_forcing_binds(arel, name, binds)
|
788
|
+
single_value_from_rows(select_values_forcing_binds(arel, name, binds))
|
789
|
+
end
|
765
790
|
|
766
|
-
|
767
|
-
|
791
|
+
ActiveRecord::Type.register(:boolean, Type::OracleEnhanced::Boolean, adapter: :oracle_enhanced)
|
792
|
+
ActiveRecord::Type.register(:json, Type::OracleEnhanced::Json, adapter: :oracle_enhanced)
|
768
793
|
end
|
769
794
|
end
|
770
795
|
end
|
data/lib/arel/visitors/oracle.rb
CHANGED
@@ -28,7 +28,7 @@ module Arel # :nodoc: all
|
|
28
28
|
|
29
29
|
collector = super(o, collector)
|
30
30
|
|
31
|
-
if offset.expr.is_a?
|
31
|
+
if offset.expr.type.is_a? ActiveModel::Type::Value
|
32
32
|
collector << ") raw_sql_ WHERE rownum <= ("
|
33
33
|
collector = visit offset.expr, collector
|
34
34
|
collector << " + "
|
@@ -38,7 +38,7 @@ module Arel # :nodoc: all
|
|
38
38
|
return collector
|
39
39
|
else
|
40
40
|
collector << ") raw_sql_
|
41
|
-
WHERE rownum <= #{offset.expr.
|
41
|
+
WHERE rownum <= #{offset.expr.value_before_type_cast + limit.value_before_type_cast}
|
42
42
|
)
|
43
43
|
WHERE "
|
44
44
|
return visit(offset, collector)
|
@@ -192,6 +192,10 @@ module Arel # :nodoc: all
|
|
192
192
|
array
|
193
193
|
end
|
194
194
|
|
195
|
+
def visit_ActiveModel_Attribute(o, collector)
|
196
|
+
collector.add_bind(o) { |i| ":a#{i}" }
|
197
|
+
end
|
198
|
+
|
195
199
|
def visit_Arel_Nodes_BindParam(o, collector)
|
196
200
|
collector.add_bind(o.value) { |i| ":a#{i}" }
|
197
201
|
end
|
@@ -99,6 +99,10 @@ module Arel # :nodoc: all
|
|
99
99
|
super
|
100
100
|
end
|
101
101
|
|
102
|
+
def visit_ActiveModel_Attribute(o, collector)
|
103
|
+
collector.add_bind(o) { |i| ":a#{i}" }
|
104
|
+
end
|
105
|
+
|
102
106
|
def visit_Arel_Nodes_BindParam(o, collector)
|
103
107
|
collector.add_bind(o.value) { |i| ":a#{i}" }
|
104
108
|
end
|
@@ -41,6 +41,23 @@ describe "OracleEnhancedAdapter establish connection" do
|
|
41
41
|
expect(ActiveRecord::Base.connection.select_value("select value from v$parameter where name = 'cursor_sharing'")).to eq("EXACT")
|
42
42
|
end
|
43
43
|
|
44
|
+
it "should not use JDBC statement caching" do
|
45
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
46
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS)
|
47
|
+
expect(ActiveRecord::Base.connection.raw_connection.getImplicitCachingEnabled).to eq(false)
|
48
|
+
expect(ActiveRecord::Base.connection.raw_connection.getStatementCacheSize).to eq(-1)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should use JDBC statement caching" do
|
53
|
+
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
54
|
+
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(jdbc_statement_cache_size: 100))
|
55
|
+
expect(ActiveRecord::Base.connection.raw_connection.getImplicitCachingEnabled).to eq(true)
|
56
|
+
expect(ActiveRecord::Base.connection.raw_connection.getStatementCacheSize).to eq(100)
|
57
|
+
# else: don't raise error if OCI connection has parameter "jdbc_statement_cache_size", still ignore it
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
44
61
|
it "should connect to database using service_name" do
|
45
62
|
ActiveRecord::Base.establish_connection(SERVICE_NAME_CONNECTION_PARAMS)
|
46
63
|
expect(ActiveRecord::Base.connection).not_to be_nil
|
@@ -215,7 +232,7 @@ describe "OracleEnhancedConnection" do
|
|
215
232
|
end
|
216
233
|
|
217
234
|
it "should respect default_timezone = :utc than time_zone setting" do
|
218
|
-
# it expects that ActiveRecord
|
235
|
+
# it expects that ActiveRecord.default_timezone = :utc
|
219
236
|
ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_WITH_TIMEZONE_PARAMS)
|
220
237
|
post = Post.create!
|
221
238
|
created_at = post.created_at
|
@@ -326,7 +326,7 @@ describe "OracleEnhancedAdapter context index" do
|
|
326
326
|
it "should dump definition of single column index" do
|
327
327
|
@conn.add_context_index :posts, :title
|
328
328
|
output = dump_table_schema "posts"
|
329
|
-
expect(output).to match(/add_context_index "posts", \["title"\], name:
|
329
|
+
expect(output).to match(/add_context_index "posts", \["title"\], name: "index_posts_on_title"$/)
|
330
330
|
@conn.remove_context_index :posts, :title
|
331
331
|
end
|
332
332
|
|
@@ -375,7 +375,7 @@ describe "OracleEnhancedAdapter context index" do
|
|
375
375
|
sub_query = "SELECT comments.author AS comment_author, comments.body AS comment_body\nFROM comments\nWHERE comments.post_id = :id"
|
376
376
|
@conn.add_context_index :posts, [:title, :body, sub_query], options
|
377
377
|
output = dump_table_schema "posts"
|
378
|
-
expect(output).to match(/add_context_index "posts", \[:title, :body, "#{sub_query.
|
378
|
+
expect(output).to match(/add_context_index "posts", \[:title, :body, "#{sub_query.tr("\n", ' ')}"\], #{options.inspect[1..-2]}$/)
|
379
379
|
@conn.remove_context_index :posts, name: "post_and_comments_index"
|
380
380
|
end
|
381
381
|
end
|
@@ -210,8 +210,8 @@ describe "OracleEnhancedAdapter custom methods for create, update and destroy" d
|
|
210
210
|
expect(@employee.first_name).to eq("First")
|
211
211
|
end
|
212
212
|
|
213
|
-
it "should not update record if nothing is changed and partial
|
214
|
-
TestEmployee.
|
213
|
+
it "should not update record if nothing is changed and partial updates are enabled" do
|
214
|
+
TestEmployee.partial_updates = true
|
215
215
|
@employee = TestEmployee.create(
|
216
216
|
first_name: "First",
|
217
217
|
last_name: "Last",
|
@@ -223,8 +223,8 @@ describe "OracleEnhancedAdapter custom methods for create, update and destroy" d
|
|
223
223
|
expect(@employee.version).to eq(1)
|
224
224
|
end
|
225
225
|
|
226
|
-
it "should update record if nothing is changed and partial
|
227
|
-
TestEmployee.
|
226
|
+
it "should update record if nothing is changed and partial updates are disabled" do
|
227
|
+
TestEmployee.partial_updates = false
|
228
228
|
@employee = TestEmployee.create(
|
229
229
|
first_name: "First",
|
230
230
|
last_name: "Last",
|
@@ -316,7 +316,7 @@ describe "OracleEnhancedAdapter custom methods for create, update and destroy" d
|
|
316
316
|
end
|
317
317
|
|
318
318
|
it "should log update record" do
|
319
|
-
(TestEmployee.
|
319
|
+
(TestEmployee.partial_updates = false) rescue nil
|
320
320
|
@employee = TestEmployee.create(
|
321
321
|
first_name: "First",
|
322
322
|
last_name: "Last",
|
@@ -71,7 +71,7 @@ describe "OracleEnhancedAdapter schema dump" do
|
|
71
71
|
|
72
72
|
it "should be able to dump default values using special characters" do
|
73
73
|
output = dump_table_schema "test_defaults"
|
74
|
-
expect(output).to match(/t.string
|
74
|
+
expect(output).to match(/t.string "special_c", default: "\\n"/)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
@@ -104,7 +104,7 @@ describe "OracleEnhancedAdapter schema dump" do
|
|
104
104
|
|
105
105
|
it "should be able to dump ntext columns" do
|
106
106
|
output = dump_table_schema "test_ntexts"
|
107
|
-
expect(output).to match(/t.ntext
|
107
|
+
expect(output).to match(/t.ntext "ntext_column"/)
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
@@ -370,7 +370,7 @@ describe "OracleEnhancedAdapter schema dump" do
|
|
370
370
|
expect(output).to match(/t\.virtual "full_name",(\s*)type: :string,(\s*)limit: 512,(\s*)as: "\\"FIRST_NAME\\"\|\|', '\|\|\\"LAST_NAME\\""/)
|
371
371
|
expect(output).to match(/t\.virtual "short_name",(\s*)type: :string,(\s*)limit: 300,(\s*)as:(.*)/)
|
372
372
|
expect(output).to match(/t\.virtual "full_name_length",(\s*)type: :integer,(\s*)precision: 38,(\s*)as:(.*)/)
|
373
|
-
expect(output).to match(/t\.virtual "name_ratio",(\s*)as:(.*)
|
373
|
+
expect(output).to match(/t\.virtual "name_ratio",(\s*)as:(.*)"$/) # no :type
|
374
374
|
expect(output).to match(/t\.virtual "abbrev_name",(\s*)type: :string,(\s*)limit: 100,(\s*)as:(.*)/)
|
375
375
|
expect(output).to match(/t\.virtual "field_with_leading_space",(\s*)type: :string,(\s*)limit: 300,(\s*)as: "' '\|\|\\"FIRST_NAME\\"\|\|' '"/)
|
376
376
|
end
|
@@ -333,7 +333,7 @@ describe "OracleEnhancedAdapter schema definition" do
|
|
333
333
|
("index_test_employees_on_first_name_and_middle_name_and_last_name"))
|
334
334
|
else
|
335
335
|
expect(@conn.index_name("test_employees", column: ["first_name", "middle_name", "last_name"])).to eq(
|
336
|
-
"i" + Digest::SHA1.hexdigest("index_test_employees_on_first_name_and_middle_name_and_last_name")[0, 29]
|
336
|
+
"i" + OpenSSL::Digest::SHA1.hexdigest("index_test_employees_on_first_name_and_middle_name_and_last_name")[0, 29]
|
337
337
|
)
|
338
338
|
end
|
339
339
|
end
|
@@ -455,7 +455,7 @@ end
|
|
455
455
|
end
|
456
456
|
|
457
457
|
it "should add foreign key" do
|
458
|
-
fk_name = "fk_rails_#{Digest::SHA256.hexdigest("test_comments_test_post_id_fk").first(10)}"
|
458
|
+
fk_name = "fk_rails_#{OpenSSL::Digest::SHA256.hexdigest("test_comments_test_post_id_fk").first(10)}"
|
459
459
|
|
460
460
|
schema_define do
|
461
461
|
add_foreign_key :test_comments, :test_posts
|
@@ -475,7 +475,7 @@ end
|
|
475
475
|
end
|
476
476
|
|
477
477
|
it "should add foreign key with column" do
|
478
|
-
fk_name = "fk_rails_#{Digest::SHA256.hexdigest("test_comments_post_id_fk").first(10)}"
|
478
|
+
fk_name = "fk_rails_#{OpenSSL::Digest::SHA256.hexdigest("test_comments_post_id_fk").first(10)}"
|
479
479
|
|
480
480
|
schema_define do
|
481
481
|
add_foreign_key :test_comments, :test_posts, column: "post_id"
|
@@ -1122,13 +1122,13 @@ end
|
|
1122
1122
|
|
1123
1123
|
before(:each) do
|
1124
1124
|
@conn.instance_variable_set :@would_execute_sql, @would_execute_sql = +""
|
1125
|
-
class
|
1125
|
+
class << @conn
|
1126
1126
|
def execute(sql, name = nil); @would_execute_sql << sql << ";\n"; end
|
1127
1127
|
end
|
1128
1128
|
end
|
1129
1129
|
|
1130
1130
|
after(:each) do
|
1131
|
-
class
|
1131
|
+
class << @conn
|
1132
1132
|
remove_method :execute
|
1133
1133
|
end
|
1134
1134
|
@conn.instance_eval { remove_instance_variable :@would_execute_sql }
|