activerecord-oracle_enhanced-adapter 1.4.3 → 5.2.0

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.
Files changed (100) hide show
  1. checksums.yaml +5 -5
  2. data/History.md +1162 -2
  3. data/README.md +567 -155
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +3 -1
  6. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +19 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +132 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +345 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +52 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +280 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +64 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +59 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +538 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +46 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +435 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +196 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +164 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +79 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +194 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +709 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +28 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +353 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +33 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +3 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +385 -1083
  29. data/lib/active_record/type/oracle_enhanced/boolean.rb +20 -0
  30. data/lib/active_record/type/oracle_enhanced/integer.rb +15 -0
  31. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  32. data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
  33. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  34. data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
  35. data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
  36. data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
  37. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  38. data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
  39. data/lib/activerecord-oracle_enhanced-adapter.rb +5 -13
  40. data/spec/active_record/connection_adapters/{oracle_enhanced_emulate_oracle_adapter_spec.rb → emulation/oracle_adapter_spec.rb} +5 -4
  41. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +469 -0
  42. data/spec/active_record/connection_adapters/{oracle_enhanced_context_index_spec.rb → oracle_enhanced/context_index_spec.rb} +140 -128
  43. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +112 -0
  44. data/spec/active_record/connection_adapters/{oracle_enhanced_dbms_output_spec.rb → oracle_enhanced/dbms_output_spec.rb} +13 -13
  45. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +365 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +196 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1433 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +478 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +385 -550
  51. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +92 -1249
  52. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  53. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +208 -0
  54. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +139 -0
  55. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  56. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +91 -0
  57. data/spec/active_record/oracle_enhanced/type/json_spec.rb +57 -0
  58. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  59. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  60. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +122 -0
  61. data/spec/active_record/oracle_enhanced/type/text_spec.rb +229 -0
  62. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +75 -0
  63. data/spec/spec_config.yaml.template +11 -0
  64. data/spec/spec_helper.rb +100 -93
  65. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  66. data/spec/support/alter_system_user_password.sql +2 -0
  67. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  68. metadata +105 -152
  69. data/.rspec +0 -2
  70. data/Gemfile +0 -52
  71. data/RUNNING_TESTS.md +0 -45
  72. data/Rakefile +0 -59
  73. data/activerecord-oracle_enhanced-adapter.gemspec +0 -130
  74. data/lib/active_record/connection_adapters/oracle_enhanced.rake +0 -105
  75. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +0 -41
  76. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +0 -121
  77. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +0 -151
  78. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +0 -119
  79. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +0 -359
  80. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +0 -25
  81. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +0 -21
  82. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +0 -46
  83. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +0 -572
  84. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +0 -497
  85. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +0 -260
  86. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +0 -227
  87. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +0 -260
  88. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +0 -428
  89. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +0 -258
  90. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +0 -294
  91. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +0 -17
  92. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +0 -1
  93. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +0 -334
  94. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +0 -19
  95. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +0 -113
  96. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +0 -141
  97. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +0 -378
  98. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +0 -440
  99. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +0 -1400
  100. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +0 -339
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class Boolean < ActiveModel::Type::Boolean # :nodoc:
7
+ private
8
+
9
+ def cast_value(value)
10
+ # Kind of adding 'n' and 'N' to `FALSE_VALUES`
11
+ if ["n", "N"].include?(value)
12
+ false
13
+ else
14
+ super
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class Integer < ActiveModel::Type::Integer # :nodoc:
7
+ private
8
+
9
+ def max_value
10
+ ("9" * 38).to_i
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class Json < ActiveRecord::Type::Json
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class NationalCharacterString < ActiveRecord::Type::OracleEnhanced::String # :nodoc:
9
+ def serialize(value)
10
+ return unless value
11
+ Data.new(super)
12
+ end
13
+
14
+ class Data # :nodoc:
15
+ def initialize(value)
16
+ @value = value
17
+ end
18
+
19
+ def to_s
20
+ @value
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class NationalCharacterText < ActiveRecord::Type::Text # :nodoc:
9
+ def type
10
+ :ntext
11
+ end
12
+
13
+ def changed_in_place?(raw_old_value, new_value)
14
+ # TODO: Needs to find a way not to cast here.
15
+ raw_old_value = cast(raw_old_value)
16
+ super
17
+ end
18
+
19
+ def serialize(value)
20
+ return unless value
21
+ Data.new(super)
22
+ end
23
+
24
+ class Data # :nodoc:
25
+ def initialize(value)
26
+ @value = value
27
+ end
28
+
29
+ def to_s
30
+ @value
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class Raw < ActiveModel::Type::String # :nodoc:
9
+ def type
10
+ :raw
11
+ end
12
+
13
+ def serialize(value)
14
+ # Encode a string or byte array as string of hex codes
15
+ if value.nil?
16
+ super
17
+ else
18
+ value = value.unpack("C*")
19
+ value.map { |x| "%02X" % x }.join
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class String < ActiveModel::Type::String # :nodoc:
9
+ def changed?(old_value, new_value, _new_value_before_type_cast)
10
+ if old_value.nil?
11
+ new_value = nil if new_value == ""
12
+ old_value != new_value
13
+ else
14
+ super
15
+ end
16
+ end
17
+
18
+ def changed_in_place?(raw_old_value, new_value)
19
+ if raw_old_value.nil?
20
+ new_value = nil if new_value == ""
21
+ raw_old_value != new_value
22
+ else
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/type/string"
4
+
5
+ module ActiveRecord
6
+ module Type
7
+ module OracleEnhanced
8
+ class Text < ActiveRecord::Type::Text # :nodoc:
9
+ def changed_in_place?(raw_old_value, new_value)
10
+ # TODO: Needs to find a way not to cast here.
11
+ raw_old_value = cast(raw_old_value)
12
+ super
13
+ end
14
+
15
+ def serialize(value)
16
+ return unless value
17
+ Data.new(super)
18
+ end
19
+
20
+ class Data # :nodoc:
21
+ def initialize(value)
22
+ @value = value
23
+ end
24
+
25
+ def to_s
26
+ @value
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class TimestampLtz < ActiveRecord::Type::DateTime
7
+ def type
8
+ :timestampltz
9
+ end
10
+
11
+ class Data < DelegateClass(::Time) # :nodoc:
12
+ end
13
+
14
+ def serialize(value)
15
+ case value = super
16
+ when ::Time
17
+ Data.new(value)
18
+ else
19
+ value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ module OracleEnhanced
6
+ class TimestampTz < ActiveRecord::Type::DateTime
7
+ def type
8
+ :timestamptz
9
+ end
10
+
11
+ class Data < DelegateClass(::Time) # :nodoc:
12
+ end
13
+
14
+ def serialize(value)
15
+ case value = super
16
+ when ::Time
17
+ Data.new(value)
18
+ else
19
+ value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,25 +1,17 @@
1
- # define railtie which will be executed in Rails 3
2
- if defined?(::Rails::Railtie)
1
+ # frozen_string_literal: true
3
2
 
3
+ if defined?(Rails)
4
4
  module ActiveRecord
5
5
  module ConnectionAdapters
6
6
  class OracleEnhancedRailtie < ::Rails::Railtie
7
7
  rake_tasks do
8
- load 'active_record/connection_adapters/oracle_enhanced.rake'
8
+ load "active_record/connection_adapters/oracle_enhanced/database_tasks.rb"
9
9
  end
10
10
 
11
11
  ActiveSupport.on_load(:active_record) do
12
- require 'active_record/connection_adapters/oracle_enhanced_adapter'
13
-
14
- # Cache column descriptions between requests in test and production environments
15
- if Rails.env.test? || Rails.env.production?
16
- ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = true
17
- end
18
-
12
+ require "active_record/connection_adapters/oracle_enhanced_adapter"
19
13
  end
20
-
21
14
  end
22
15
  end
23
16
  end
24
-
25
- end
17
+ end
@@ -1,8 +1,9 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
3
  describe "OracleEnhancedAdapter emulate OracleAdapter" do
4
4
 
5
5
  before(:all) do
6
+ @old_oracle_adapter = nil
6
7
  if defined?(ActiveRecord::ConnectionAdapters::OracleAdapter)
7
8
  @old_oracle_adapter = ActiveRecord::ConnectionAdapters::OracleAdapter
8
9
  ActiveRecord::ConnectionAdapters.send(:remove_const, :OracleAdapter)
@@ -10,9 +11,9 @@ describe "OracleEnhancedAdapter emulate OracleAdapter" do
10
11
  end
11
12
 
12
13
  it "should be an OracleAdapter" do
13
- @conn = ActiveRecord::Base.establish_connection(CONNECTION_PARAMS.merge(:emulate_oracle_adapter => true))
14
- ActiveRecord::Base.connection.should_not be_nil
15
- ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::OracleAdapter).should be_true
14
+ @conn = ActiveRecord::Base.establish_connection(CONNECTION_PARAMS.merge(emulate_oracle_adapter: true))
15
+ expect(ActiveRecord::Base.connection).not_to be_nil
16
+ expect(ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::OracleAdapter)).to be_truthy
16
17
  end
17
18
 
18
19
  after(:all) do
@@ -0,0 +1,469 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe "OracleEnhancedAdapter establish connection" do
4
+
5
+ it "should connect to database" do
6
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
7
+ expect(ActiveRecord::Base.connection).not_to be_nil
8
+ expect(ActiveRecord::Base.connection.class).to eq(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter)
9
+ end
10
+
11
+ it "should connect to database as SYSDBA" do
12
+ ActiveRecord::Base.establish_connection(SYS_CONNECTION_PARAMS)
13
+ expect(ActiveRecord::Base.connection).not_to be_nil
14
+ expect(ActiveRecord::Base.connection.class).to eq(ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter)
15
+ end
16
+
17
+ it "should be active after connection to database" do
18
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
19
+ expect(ActiveRecord::Base.connection).to be_active
20
+ end
21
+
22
+ it "should not be active after disconnection to database" do
23
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
24
+ ActiveRecord::Base.connection.disconnect!
25
+ expect(ActiveRecord::Base.connection).not_to be_active
26
+ end
27
+
28
+ it "should be active after reconnection to database" do
29
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
30
+ ActiveRecord::Base.connection.reconnect!
31
+ expect(ActiveRecord::Base.connection).to be_active
32
+ end
33
+
34
+ it "should use database default cursor_sharing parameter value exact by default" do
35
+ # Use `SYSTEM_CONNECTION_PARAMS` to query v$parameter
36
+ ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS)
37
+ expect(ActiveRecord::Base.connection.select_value("select value from v$parameter where name = 'cursor_sharing'")).to eq("EXACT")
38
+ end
39
+
40
+ it "should use modified cursor_sharing value force" do
41
+ ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(cursor_sharing: :force))
42
+ expect(ActiveRecord::Base.connection.select_value("select value from v$parameter where name = 'cursor_sharing'")).to eq("FORCE")
43
+ end
44
+ end
45
+
46
+ describe "OracleEnhancedConnection" do
47
+
48
+ describe "create connection" do
49
+ before(:all) do
50
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
51
+ end
52
+
53
+ before(:each) do
54
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS) unless @conn.active?
55
+ end
56
+
57
+ it "should create new connection" do
58
+ expect(@conn).to be_active
59
+ end
60
+
61
+ it "should ping active connection" do
62
+ expect(@conn.ping).to be_truthy
63
+ end
64
+
65
+ it "should not ping inactive connection" do
66
+ @conn.logoff
67
+ expect { @conn.ping }.to raise_error(ActiveRecord::ConnectionAdapters::OracleEnhanced::ConnectionException)
68
+ end
69
+
70
+ it "should reset active connection" do
71
+ @conn.reset!
72
+ expect(@conn).to be_active
73
+ end
74
+
75
+ it "should be in autocommit mode after connection" do
76
+ expect(@conn).to be_autocommit
77
+ end
78
+
79
+ end
80
+
81
+ describe "create connection with schema option" do
82
+
83
+ it "should create new connection" do
84
+ ActiveRecord::Base.establish_connection(CONNECTION_WITH_SCHEMA_PARAMS)
85
+ expect(ActiveRecord::Base.connection).to be_active
86
+ end
87
+
88
+ it "should swith to specified schema" do
89
+ ActiveRecord::Base.establish_connection(CONNECTION_WITH_SCHEMA_PARAMS)
90
+ expect(ActiveRecord::Base.connection.current_schema).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:schema].upcase)
91
+ end
92
+
93
+ it "should swith to specified schema after reset" do
94
+ ActiveRecord::Base.connection.reset!
95
+ expect(ActiveRecord::Base.connection.current_schema).to eq(CONNECTION_WITH_SCHEMA_PARAMS[:schema].upcase)
96
+ end
97
+
98
+ end
99
+
100
+ describe "create connection with NLS parameters" do
101
+ after do
102
+ ENV["NLS_DATE_FORMAT"] = nil
103
+ end
104
+
105
+ it "should use NLS_DATE_FORMAT environment variable" do
106
+ ENV["NLS_DATE_FORMAT"] = "YYYY-MM-DD"
107
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
108
+ expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD" }])
109
+ end
110
+
111
+ it "should use configuration value and ignore NLS_DATE_FORMAT environment variable" do
112
+ ENV["NLS_DATE_FORMAT"] = "YYYY-MM-DD"
113
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS.merge(nls_date_format: "YYYY-MM-DD HH24:MI"))
114
+ expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => "YYYY-MM-DD HH24:MI" }])
115
+ end
116
+
117
+ it "should use default value when NLS_DATE_FORMAT environment variable is not set" do
118
+ ENV["NLS_DATE_FORMAT"] = nil
119
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
120
+ default = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::DEFAULT_NLS_PARAMETERS[:nls_date_format]
121
+ expect(@conn.select("select SYS_CONTEXT('userenv', 'NLS_DATE_FORMAT') as value from dual")).to eq([{ "value" => default }])
122
+ end
123
+ end
124
+
125
+ describe "with non-string parameters" do
126
+ before(:all) do
127
+ params = CONNECTION_PARAMS.dup
128
+ params[:username] = params[:username].to_sym
129
+ params[:password] = params[:password].to_sym
130
+ params[:database] = params[:database].to_sym
131
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
132
+ end
133
+
134
+ it "should create new connection" do
135
+ expect(@conn).to be_active
136
+ end
137
+ end
138
+
139
+ describe "with slash-prefixed database name (service name)" do
140
+ before(:all) do
141
+ params = CONNECTION_PARAMS.dup
142
+ params[:database] = "/#{params[:database]}" unless params[:database].match(/^\//)
143
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
144
+ end
145
+
146
+ it "should create new connection" do
147
+ expect(@conn).to be_active
148
+ end
149
+ end
150
+
151
+ describe "default_timezone" do
152
+ include SchemaSpecHelper
153
+
154
+ before(:all) do
155
+ ActiveRecord::Base.establish_connection(CONNECTION_WITH_TIMEZONE_PARAMS)
156
+ schema_define do
157
+ create_table :posts, force: true do |t|
158
+ t.timestamps null: false
159
+ end
160
+ end
161
+ class ::Post < ActiveRecord::Base
162
+ end
163
+ end
164
+
165
+ after(:all) do
166
+ Object.send(:remove_const, "Post")
167
+ ActiveRecord::Base.clear_cache!
168
+ end
169
+
170
+ it "should respect default_timezone = :utc than time_zone setting" do
171
+ # it expects that ActiveRecord::Base.default_timezone = :utc
172
+ ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_WITH_TIMEZONE_PARAMS)
173
+ post = Post.create!
174
+ created_at = post.created_at
175
+ expect(post).to eq(Post.find_by!(created_at: created_at))
176
+ end
177
+
178
+ end
179
+
180
+ describe 'with host="connection-string"' do
181
+ let(:username) { CONNECTION_PARAMS[:username] }
182
+ let(:password) { CONNECTION_PARAMS[:password] }
183
+ let(:connection_string) { "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=#{DATABASE_HOST})(PORT=#{DATABASE_PORT})))(CONNECT_DATA=(SERVICE_NAME=#{DATABASE_NAME})))" }
184
+ let(:params) { { username: username, password: password, host: "connection-string", database: connection_string } }
185
+
186
+ it "uses the database param as the connection string" do
187
+ if ORACLE_ENHANCED_CONNECTION == :jdbc
188
+ expect(java.sql.DriverManager).to receive(:getConnection).with("jdbc:oracle:thin:@#{connection_string}", anything).and_call_original
189
+ else
190
+ expect(OCI8).to receive(:new).with(username, password, connection_string, nil).and_call_original
191
+ end
192
+ conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
193
+ expect(conn).to be_active
194
+ end
195
+ end
196
+
197
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
198
+
199
+ describe "create JDBC connection" do
200
+
201
+ it "should create new connection using :url" do
202
+ params = CONNECTION_PARAMS.dup
203
+ params[:url] = "jdbc:oracle:thin:@#{DATABASE_HOST && "//#{DATABASE_HOST}#{DATABASE_PORT && ":#{DATABASE_PORT}"}/"}#{DATABASE_NAME}"
204
+
205
+ params[:host] = nil
206
+ params[:database] = nil
207
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
208
+ expect(@conn).to be_active
209
+ end
210
+
211
+ it "should create new connection using :url and tnsnames alias" do
212
+ params = CONNECTION_PARAMS.dup
213
+ params[:url] = "jdbc:oracle:thin:@#{DATABASE_NAME}"
214
+ params[:host] = nil
215
+ params[:database] = nil
216
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
217
+ expect(@conn).to be_active
218
+ end
219
+
220
+ it "should create new connection using just tnsnames alias" do
221
+ params = CONNECTION_PARAMS.dup
222
+ params[:host] = nil
223
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
224
+ expect(@conn).to be_active
225
+ end
226
+
227
+ it "should create a new connection using JNDI" do
228
+
229
+ begin
230
+ import "oracle.jdbc.driver.OracleDriver"
231
+ import "org.apache.commons.pool.impl.GenericObjectPool"
232
+ import "org.apache.commons.dbcp.PoolingDataSource"
233
+ import "org.apache.commons.dbcp.PoolableConnectionFactory"
234
+ import "org.apache.commons.dbcp.DriverManagerConnectionFactory"
235
+ rescue NameError => e
236
+ return skip e.message
237
+ end
238
+
239
+ class InitialContextMock
240
+ def initialize
241
+ connection_pool = GenericObjectPool.new(nil)
242
+ uri = "jdbc:oracle:thin:@#{DATABASE_HOST && "#{DATABASE_HOST}:"}#{DATABASE_PORT && "#{DATABASE_PORT}:"}#{DATABASE_NAME}"
243
+ connection_factory = DriverManagerConnectionFactory.new(uri, DATABASE_USER, DATABASE_PASSWORD)
244
+ PoolableConnectionFactory.new(connection_factory, connection_pool, nil, nil, false, true)
245
+ @data_source = PoolingDataSource.new(connection_pool)
246
+ @data_source.access_to_underlying_connection_allowed = true
247
+ end
248
+ def lookup(path)
249
+ if (path == "java:/comp/env")
250
+ self
251
+ else
252
+ @data_source
253
+ end
254
+ end
255
+ end
256
+
257
+ allow(javax.naming.InitialContext).to receive(:new).and_return(InitialContextMock.new)
258
+
259
+ params = {}
260
+ params[:jndi] = "java:comp/env/jdbc/test"
261
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
262
+ expect(@conn).to be_active
263
+ end
264
+
265
+ end
266
+
267
+ it "should fall back to directly instantiating OracleDriver" do
268
+ params = CONNECTION_PARAMS.dup
269
+ params[:url] = "jdbc:oracle:thin:@#{DATABASE_HOST && "//#{DATABASE_HOST}#{DATABASE_PORT && ":#{DATABASE_PORT}"}/"}#{DATABASE_NAME}"
270
+ params[:host] = nil
271
+ params[:database] = nil
272
+ allow(java.sql.DriverManager).to receive(:getConnection).and_raise("no suitable driver found")
273
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(params)
274
+ expect(@conn).to be_active
275
+ end
276
+
277
+ end
278
+
279
+ describe "SQL execution" do
280
+ before(:all) do
281
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
282
+ end
283
+
284
+ it "should execute SQL statement" do
285
+ expect(@conn.exec("SELECT * FROM dual")).not_to be_nil
286
+ end
287
+
288
+ it "should execute SQL select" do
289
+ expect(@conn.select("SELECT * FROM dual")).to eq([{ "dummy" => "X" }])
290
+ end
291
+
292
+ it "should execute SQL select and return also columns" do
293
+ expect(@conn.select("SELECT * FROM dual", nil, true)).to eq([ [{ "dummy" => "X" }], ["dummy"] ])
294
+ end
295
+
296
+ end
297
+
298
+ describe "SQL with bind parameters" do
299
+ before(:all) do
300
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
301
+ end
302
+
303
+ it "should execute SQL statement with bind parameter" do
304
+ cursor = @conn.prepare("SELECT * FROM dual WHERE :1 = 1")
305
+ cursor.bind_param(1, 1)
306
+ cursor.exec
307
+ expect(cursor.get_col_names).to eq(["DUMMY"])
308
+ expect(cursor.fetch).to eq(["X"])
309
+ cursor.close
310
+ end
311
+
312
+ it "should execute prepared statement with different bind parameters" do
313
+ cursor = @conn.prepare("SELECT * FROM dual WHERE :1 = 1")
314
+ cursor.bind_param(1, 1)
315
+ cursor.exec
316
+ expect(cursor.fetch).to eq(["X"])
317
+ cursor.bind_param(1, 0)
318
+ cursor.exec
319
+ expect(cursor.fetch).to be_nil
320
+ cursor.close
321
+ end
322
+ end
323
+
324
+ describe "SQL with bind parameters when NLS_NUMERIC_CHARACTERS is set to ', '" do
325
+ before(:all) do
326
+ ENV["NLS_NUMERIC_CHARACTERS"] = ", "
327
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
328
+ @conn.exec "CREATE TABLE test_employees (age NUMBER(10,2))"
329
+ end
330
+
331
+ after(:all) do
332
+ ENV["NLS_NUMERIC_CHARACTERS"] = nil
333
+ @conn.exec "DROP TABLE test_employees" rescue nil
334
+ end
335
+
336
+ it "should execute prepared statement with decimal bind parameter " do
337
+ cursor = @conn.prepare("INSERT INTO test_employees VALUES(:1)")
338
+ type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "NUMBER", type: :decimal, limit: 10, precision: nil, scale: 2)
339
+ column = ActiveRecord::ConnectionAdapters::OracleEnhanced::Column.new("age", nil, type_metadata, false, "test_employees", nil)
340
+ expect(column.type).to eq(:decimal)
341
+ # Here 1.5 expects that this value has been type casted already
342
+ # it should use bind_params in the long term.
343
+ cursor.bind_param(1, 1.5)
344
+ cursor.exec
345
+ cursor.close
346
+ cursor = @conn.prepare("SELECT age FROM test_employees")
347
+ cursor.exec
348
+ expect(cursor.fetch).to eq([1.5])
349
+ cursor.close
350
+ end
351
+ end
352
+
353
+ describe "auto reconnection" do
354
+ before(:all) do
355
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
356
+ @conn = ActiveRecord::Base.connection.instance_variable_get("@connection")
357
+ @sys_conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(SYS_CONNECTION_PARAMS)
358
+ end
359
+
360
+ before(:each) do
361
+ ActiveRecord::Base.connection.reconnect! unless @conn.active?
362
+ end
363
+
364
+ def kill_current_session
365
+ audsid = @conn.select("SELECT userenv('sessionid') audsid FROM dual").first["audsid"]
366
+ sid_serial = @sys_conn.select("SELECT s.sid||','||s.serial# sid_serial
367
+ FROM v$session s
368
+ WHERE audsid = '#{audsid}'").first["sid_serial"]
369
+ @sys_conn.exec "ALTER SYSTEM KILL SESSION '#{sid_serial}' IMMEDIATE"
370
+ end
371
+
372
+ it "should reconnect and execute SQL statement if connection is lost and auto retry is enabled" do
373
+ # @conn.auto_retry = true
374
+ ActiveRecord::Base.connection.auto_retry = true
375
+ kill_current_session
376
+ expect(@conn.exec("SELECT * FROM dual")).not_to be_nil
377
+ end
378
+
379
+ it "should not reconnect and execute SQL statement if connection is lost and auto retry is disabled" do
380
+ # @conn.auto_retry = false
381
+ ActiveRecord::Base.connection.auto_retry = false
382
+ kill_current_session
383
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
384
+ expect { @conn.exec("SELECT * FROM dual") }.to raise_error(NativeException)
385
+ else
386
+ expect { @conn.exec("SELECT * FROM dual") }.to raise_error(OCIError)
387
+ end
388
+ end
389
+
390
+ it "should reconnect and execute SQL select if connection is lost and auto retry is enabled" do
391
+ # @conn.auto_retry = true
392
+ ActiveRecord::Base.connection.auto_retry = true
393
+ kill_current_session
394
+ expect(@conn.select("SELECT * FROM dual")).to eq([{ "dummy" => "X" }])
395
+ end
396
+
397
+ it "should not reconnect and execute SQL select if connection is lost and auto retry is disabled" do
398
+ # @conn.auto_retry = false
399
+ ActiveRecord::Base.connection.auto_retry = false
400
+ kill_current_session
401
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
402
+ expect { @conn.select("SELECT * FROM dual") }.to raise_error(NativeException)
403
+ else
404
+ expect { @conn.select("SELECT * FROM dual") }.to raise_error(OCIError)
405
+ end
406
+ end
407
+
408
+ end
409
+
410
+ describe "describe table" do
411
+ before(:all) do
412
+ @conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
413
+ @owner = CONNECTION_PARAMS[:username].upcase
414
+ end
415
+
416
+ it "should describe existing table" do
417
+ @conn.exec "CREATE TABLE test_employees (first_name VARCHAR2(20))" rescue nil
418
+ expect(@conn.describe("test_employees")).to eq([@owner, "TEST_EMPLOYEES"])
419
+ @conn.exec "DROP TABLE test_employees" rescue nil
420
+ end
421
+
422
+ it "should not describe non-existing table" do
423
+ expect { @conn.describe("test_xxx") }.to raise_error(ActiveRecord::ConnectionAdapters::OracleEnhanced::ConnectionException)
424
+ end
425
+
426
+ it "should describe table in other schema" do
427
+ expect(@conn.describe("sys.dual")).to eq(["SYS", "DUAL"])
428
+ end
429
+
430
+ it "should describe table in other schema if the schema and table are in different cases" do
431
+ expect(@conn.describe("SYS.dual")).to eq(["SYS", "DUAL"])
432
+ end
433
+
434
+ it "should describe existing view" do
435
+ @conn.exec "CREATE TABLE test_employees (first_name VARCHAR2(20))" rescue nil
436
+ @conn.exec "CREATE VIEW test_employees_v AS SELECT * FROM test_employees" rescue nil
437
+ expect(@conn.describe("test_employees_v")).to eq([@owner, "TEST_EMPLOYEES_V"])
438
+ @conn.exec "DROP VIEW test_employees_v" rescue nil
439
+ @conn.exec "DROP TABLE test_employees" rescue nil
440
+ end
441
+
442
+ it "should describe view in other schema" do
443
+ expect(@conn.describe("sys.v_$version")).to eq(["SYS", "V_$VERSION"])
444
+ end
445
+
446
+ it "should describe existing private synonym" do
447
+ @conn.exec "CREATE SYNONYM test_dual FOR sys.dual" rescue nil
448
+ expect(@conn.describe("test_dual")).to eq(["SYS", "DUAL"])
449
+ @conn.exec "DROP SYNONYM test_dual" rescue nil
450
+ end
451
+
452
+ it "should describe existing public synonym" do
453
+ expect(@conn.describe("all_tables")).to eq(["SYS", "ALL_TABLES"])
454
+ end
455
+
456
+ if defined?(OCI8)
457
+ context "OCI8 adapter" do
458
+
459
+ it "should not fallback to SELECT-based logic when querying non-existent table information" do
460
+ expect(@conn).not_to receive(:select_one)
461
+ @conn.describe("non_existent") rescue ActiveRecord::ConnectionAdapters::OracleEnhanced::ConnectionException
462
+ end
463
+
464
+ end
465
+ end
466
+
467
+ end
468
+
469
+ end