activerecord-oracle_enhanced-adapter 6.1.4 → 7.0.1
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/History.md +78 -0
- data/README.md +12 -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 +19 -22
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +14 -8
- 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 +37 -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 +123 -98
- 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/custom_spec.rb +88 -0
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +2 -2
- metadata +22 -6
@@ -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
|
@@ -664,8 +665,8 @@ module ActiveRecord
|
|
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 }
|