activerecord-oracle_enhanced-adapter 1.4.3 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
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