activerecord-oracle_enhanced-adapter 8.1.0-java

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 (78) hide show
  1. checksums.yaml +7 -0
  2. data/History.md +1971 -0
  3. data/License.txt +20 -0
  4. data/README.md +947 -0
  5. data/VERSION +1 -0
  6. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +7 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +24 -0
  8. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +137 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +359 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_limits.rb +47 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +325 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +63 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +71 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +629 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +38 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +57 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +465 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +44 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +195 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +186 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +95 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +99 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +197 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +739 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +394 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced/type_metadata.rb +34 -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 +886 -0
  29. data/lib/active_record/type/oracle_enhanced/boolean.rb +19 -0
  30. data/lib/active_record/type/oracle_enhanced/character_string.rb +36 -0
  31. data/lib/active_record/type/oracle_enhanced/integer.rb +14 -0
  32. data/lib/active_record/type/oracle_enhanced/json.rb +10 -0
  33. data/lib/active_record/type/oracle_enhanced/national_character_string.rb +26 -0
  34. data/lib/active_record/type/oracle_enhanced/national_character_text.rb +36 -0
  35. data/lib/active_record/type/oracle_enhanced/raw.rb +25 -0
  36. data/lib/active_record/type/oracle_enhanced/string.rb +29 -0
  37. data/lib/active_record/type/oracle_enhanced/text.rb +32 -0
  38. data/lib/active_record/type/oracle_enhanced/timestampltz.rb +25 -0
  39. data/lib/active_record/type/oracle_enhanced/timestamptz.rb +25 -0
  40. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  41. data/lib/arel/visitors/oracle.rb +216 -0
  42. data/lib/arel/visitors/oracle12.rb +121 -0
  43. data/lib/arel/visitors/oracle_common.rb +51 -0
  44. data/spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb +24 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +40 -0
  46. data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
  47. data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +589 -0
  48. data/spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb +431 -0
  49. data/spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb +122 -0
  50. data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
  51. data/spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb +69 -0
  52. data/spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb +362 -0
  53. data/spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb +181 -0
  54. data/spec/active_record/connection_adapters/oracle_enhanced/schema_dumper_spec.rb +492 -0
  55. data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +1318 -0
  56. data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +485 -0
  57. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +815 -0
  58. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +230 -0
  59. data/spec/active_record/oracle_enhanced/type/binary_spec.rb +119 -0
  60. data/spec/active_record/oracle_enhanced/type/boolean_spec.rb +206 -0
  61. data/spec/active_record/oracle_enhanced/type/character_string_spec.rb +67 -0
  62. data/spec/active_record/oracle_enhanced/type/custom_spec.rb +90 -0
  63. data/spec/active_record/oracle_enhanced/type/decimal_spec.rb +56 -0
  64. data/spec/active_record/oracle_enhanced/type/dirty_spec.rb +141 -0
  65. data/spec/active_record/oracle_enhanced/type/float_spec.rb +48 -0
  66. data/spec/active_record/oracle_enhanced/type/integer_spec.rb +101 -0
  67. data/spec/active_record/oracle_enhanced/type/json_spec.rb +56 -0
  68. data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +55 -0
  69. data/spec/active_record/oracle_enhanced/type/national_character_text_spec.rb +230 -0
  70. data/spec/active_record/oracle_enhanced/type/raw_spec.rb +137 -0
  71. data/spec/active_record/oracle_enhanced/type/text_spec.rb +295 -0
  72. data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +107 -0
  73. data/spec/spec_config.yaml.template +11 -0
  74. data/spec/spec_helper.rb +225 -0
  75. data/spec/support/alter_system_set_open_cursors.sql +1 -0
  76. data/spec/support/alter_system_user_password.sql +2 -0
  77. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  78. metadata +181 -0
@@ -0,0 +1,230 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe "OracleEnhancedAdapter date and datetime type detection based on attribute settings" do
4
+ before(:all) do
5
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
6
+ @conn = ActiveRecord::Base.connection
7
+ @conn.execute "DROP TABLE test_employees" rescue nil
8
+ @conn.execute "DROP SEQUENCE test_employees_seq" rescue nil
9
+ @conn.execute <<~SQL
10
+ CREATE TABLE test_employees (
11
+ employee_id NUMBER(6,0) PRIMARY KEY,
12
+ first_name VARCHAR2(20),
13
+ last_name VARCHAR2(25),
14
+ email VARCHAR2(25),
15
+ phone_number VARCHAR2(20),
16
+ hire_date DATE,
17
+ job_id NUMBER(6,0),
18
+ salary NUMBER(8,2),
19
+ commission_pct NUMBER(2,2),
20
+ manager_id NUMBER(6,0),
21
+ department_id NUMBER(4,0),
22
+ created_at DATE,
23
+ updated_at DATE
24
+ )
25
+ SQL
26
+ @conn.execute <<~SQL
27
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
28
+ INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
29
+ SQL
30
+ end
31
+
32
+ after(:all) do
33
+ @conn.execute "DROP TABLE test_employees"
34
+ @conn.execute "DROP SEQUENCE test_employees_seq"
35
+ end
36
+
37
+ describe "/ DATE values from ActiveRecord model" do
38
+ before(:each) do
39
+ class ::TestEmployee < ActiveRecord::Base
40
+ self.primary_key = "employee_id"
41
+ end
42
+ end
43
+
44
+ def create_test_employee(params = {})
45
+ @today = params[:today] || Date.new(2008, 8, 19)
46
+ @now = params[:now] || Time.local(2008, 8, 19, 17, 03, 59)
47
+ @employee = TestEmployee.create(
48
+ first_name: "First",
49
+ last_name: "Last",
50
+ hire_date: @today,
51
+ created_at: @now
52
+ )
53
+ @employee.reload
54
+ end
55
+
56
+ after(:each) do
57
+ Object.send(:remove_const, "TestEmployee")
58
+ ActiveRecord::Base.clear_cache!
59
+ end
60
+
61
+ it "should return Date value from DATE column by default" do
62
+ create_test_employee
63
+ expect(@employee.hire_date.class).to eq(Date)
64
+ end
65
+
66
+ it "should return Date value from DATE column with old date value by default" do
67
+ create_test_employee(today: Date.new(1900, 1, 1))
68
+ expect(@employee.hire_date.class).to eq(Date)
69
+ end
70
+
71
+ it "should return Time value from DATE column if attribute is set to :datetime" do
72
+ class ::TestEmployee < ActiveRecord::Base
73
+ attribute :hire_date, :datetime
74
+ end
75
+ create_test_employee
76
+ expect(@employee.hire_date.class).to eq(Time)
77
+ # change to current time with hours, minutes and seconds
78
+ @employee.hire_date = @now
79
+ @employee.save!
80
+ @employee.reload
81
+ expect(@employee.hire_date.class).to eq(Time)
82
+ expect(@employee.hire_date).to eq(@now)
83
+ end
84
+ end
85
+ end
86
+
87
+ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
88
+ include SchemaSpecHelper
89
+
90
+ before(:all) do
91
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
92
+ @conn = ActiveRecord::Base.connection
93
+ schema_define do
94
+ create_table :test_employees, force: true do |t|
95
+ t.string :first_name, limit: 20
96
+ t.string :last_name, limit: 25
97
+ t.date :hire_date
98
+ t.date :last_login_at
99
+ t.datetime :last_login_at_ts
100
+ end
101
+ end
102
+ class ::TestEmployee < ActiveRecord::Base
103
+ attribute :last_login_at, :datetime
104
+ end
105
+ @today = Date.new(2008, 6, 28)
106
+ @today_iso = "2008-06-28"
107
+ @today_nls = "28.06.2008"
108
+ @nls_date_format = "%d.%m.%Y"
109
+ @now = Time.local(2008, 6, 28, 13, 34, 33)
110
+ @now_iso = "2008-06-28 13:34:33"
111
+ @now_nls = "28.06.2008 13:34:33"
112
+ @nls_time_format = "%d.%m.%Y %H:%M:%S"
113
+ @now_nls_with_tz = "28.06.2008 13:34:33+05:00"
114
+ @nls_with_tz_time_format = "%d.%m.%Y %H:%M:%S%Z"
115
+ @now_with_tz = Time.parse @now_nls_with_tz
116
+ end
117
+
118
+ after(:all) do
119
+ Object.send(:remove_const, "TestEmployee")
120
+ @conn.drop_table :test_employees, if_exists: true
121
+ ActiveRecord::Base.clear_cache!
122
+ end
123
+
124
+ after(:each) do
125
+ ActiveRecord.default_timezone = :utc
126
+ end
127
+
128
+ it "should assign ISO string to date column" do
129
+ @employee = TestEmployee.create(
130
+ first_name: "First",
131
+ last_name: "Last",
132
+ hire_date: @today_iso
133
+ )
134
+ expect(@employee.hire_date).to eq(@today)
135
+ @employee.reload
136
+ expect(@employee.hire_date).to eq(@today)
137
+ end
138
+
139
+ it "should assign NLS string to date column" do
140
+ @employee = TestEmployee.create(
141
+ first_name: "First",
142
+ last_name: "Last",
143
+ hire_date: @today_nls
144
+ )
145
+ expect(@employee.hire_date).to eq(@today)
146
+ @employee.reload
147
+ expect(@employee.hire_date).to eq(@today)
148
+ end
149
+
150
+ it "should assign ISO time string to date column" do
151
+ @employee = TestEmployee.create(
152
+ first_name: "First",
153
+ last_name: "Last",
154
+ hire_date: @now_iso
155
+ )
156
+ expect(@employee.hire_date).to eq(@today)
157
+ @employee.reload
158
+ expect(@employee.hire_date).to eq(@today)
159
+ end
160
+
161
+ it "should assign NLS time string to date column" do
162
+ @employee = TestEmployee.create(
163
+ first_name: "First",
164
+ last_name: "Last",
165
+ hire_date: @now_nls
166
+ )
167
+ expect(@employee.hire_date).to eq(@today)
168
+ @employee.reload
169
+ expect(@employee.hire_date).to eq(@today)
170
+ end
171
+
172
+ it "should assign ISO time string to datetime column" do
173
+ ActiveRecord.default_timezone = :local
174
+ @employee = TestEmployee.create(
175
+ first_name: "First",
176
+ last_name: "Last",
177
+ last_login_at: @now_iso
178
+ )
179
+ expect(@employee.last_login_at).to eq(@now)
180
+ @employee.reload
181
+ expect(@employee.last_login_at).to eq(@now)
182
+ end
183
+
184
+ it "should assign NLS time string to datetime column" do
185
+ ActiveRecord.default_timezone = :local
186
+ @employee = TestEmployee.create(
187
+ first_name: "First",
188
+ last_name: "Last",
189
+ last_login_at: @now_nls
190
+ )
191
+ expect(@employee.last_login_at).to eq(@now)
192
+ @employee.reload
193
+ expect(@employee.last_login_at).to eq(@now)
194
+ end
195
+
196
+ it "should assign NLS time string with time zone to datetime column" do
197
+ @employee = TestEmployee.create(
198
+ first_name: "First",
199
+ last_name: "Last",
200
+ last_login_at: @now_nls_with_tz
201
+ )
202
+ expect(@employee.last_login_at).to eq(@now_with_tz)
203
+ @employee.reload
204
+ expect(@employee.last_login_at).to eq(@now_with_tz)
205
+ end
206
+
207
+ it "should assign ISO date string to datetime column" do
208
+ ActiveRecord.default_timezone = :local
209
+ @employee = TestEmployee.create(
210
+ first_name: "First",
211
+ last_name: "Last",
212
+ last_login_at: @today_iso
213
+ )
214
+ expect(@employee.last_login_at).to eq(@today.to_time)
215
+ @employee.reload
216
+ expect(@employee.last_login_at).to eq(@today.to_time)
217
+ end
218
+
219
+ it "should assign NLS date string to datetime column" do
220
+ ActiveRecord.default_timezone = :local
221
+ @employee = TestEmployee.create(
222
+ first_name: "First",
223
+ last_name: "Last",
224
+ last_login_at: @today_nls
225
+ )
226
+ expect(@employee.last_login_at).to eq(@today.to_time)
227
+ @employee.reload
228
+ expect(@employee.last_login_at).to eq(@today.to_time)
229
+ end
230
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe "OracleEnhancedAdapter handling of BLOB columns" do
4
+ include SchemaSpecHelper
5
+
6
+ before(:all) do
7
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
8
+ @conn = ActiveRecord::Base.connection
9
+ schema_define do
10
+ create_table :test_employees, force: true do |t|
11
+ t.string :first_name, limit: 20
12
+ t.string :last_name, limit: 25
13
+ t.binary :binary_data
14
+ end
15
+ end
16
+ class ::TestEmployee < ActiveRecord::Base
17
+ end
18
+ @binary_data = "\0\1\2\3\4\5\6\7\8\9" * 10000
19
+ @binary_data2 = "\1\2\3\4\5\6\7\8\9\0" * 10000
20
+ end
21
+
22
+ after(:all) do
23
+ @conn.drop_table :test_employees, if_exists: true
24
+ Object.send(:remove_const, "TestEmployee")
25
+ end
26
+
27
+ after(:each) do
28
+ ActiveRecord::Base.clear_cache!
29
+ end
30
+
31
+ it "should create record with BLOB data" do
32
+ @employee = TestEmployee.create!(
33
+ first_name: "First",
34
+ last_name: "Last",
35
+ binary_data: @binary_data
36
+ )
37
+ @employee.reload
38
+ expect(@employee.binary_data).to eq(@binary_data)
39
+ end
40
+
41
+ it "should update record with BLOB data" do
42
+ @employee = TestEmployee.create!(
43
+ first_name: "First",
44
+ last_name: "Last"
45
+ )
46
+ @employee.reload
47
+ expect(@employee.binary_data).to be_nil
48
+ @employee.binary_data = @binary_data
49
+ @employee.save!
50
+ @employee.reload
51
+ expect(@employee.binary_data).to eq(@binary_data)
52
+ end
53
+
54
+ it "should update record with zero-length BLOB data" do
55
+ @employee = TestEmployee.create!(
56
+ first_name: "First",
57
+ last_name: "Last"
58
+ )
59
+ @employee.reload
60
+ expect(@employee.binary_data).to be_nil
61
+ @employee.binary_data = ""
62
+ @employee.save!
63
+ @employee.reload
64
+ expect(@employee.binary_data).to eq("")
65
+ end
66
+
67
+ it "should update record that has existing BLOB data with different BLOB data" do
68
+ @employee = TestEmployee.create!(
69
+ first_name: "First",
70
+ last_name: "Last",
71
+ binary_data: @binary_data
72
+ )
73
+ @employee.reload
74
+ @employee.binary_data = @binary_data2
75
+ @employee.save!
76
+ @employee.reload
77
+ expect(@employee.binary_data).to eq(@binary_data2)
78
+ end
79
+
80
+ it "should update record that has existing BLOB data with nil" do
81
+ @employee = TestEmployee.create!(
82
+ first_name: "First",
83
+ last_name: "Last",
84
+ binary_data: @binary_data
85
+ )
86
+ @employee.reload
87
+ @employee.binary_data = nil
88
+ @employee.save!
89
+ @employee.reload
90
+ expect(@employee.binary_data).to be_nil
91
+ end
92
+
93
+ it "should update record that has existing BLOB data with zero-length BLOB data" do
94
+ @employee = TestEmployee.create!(
95
+ first_name: "First",
96
+ last_name: "Last",
97
+ binary_data: @binary_data
98
+ )
99
+ @employee.reload
100
+ @employee.binary_data = ""
101
+ @employee.save!
102
+ @employee.reload
103
+ expect(@employee.binary_data).to eq("")
104
+ end
105
+
106
+ it "should update record that has zero-length BLOB data with non-empty BLOB data" do
107
+ @employee = TestEmployee.create!(
108
+ first_name: "First",
109
+ last_name: "Last",
110
+ binary_data: ""
111
+ )
112
+ @employee.reload
113
+ expect(@employee.binary_data).to eq("")
114
+ @employee.binary_data = @binary_data
115
+ @employee.save!
116
+ @employee.reload
117
+ expect(@employee.binary_data).to eq(@binary_data)
118
+ end
119
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe "OracleEnhancedAdapter boolean type detection based on string column types and names" do
4
+ before(:all) do
5
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
6
+ @conn = ActiveRecord::Base.connection
7
+ @conn.execute <<~SQL
8
+ CREATE TABLE test3_employees (
9
+ id NUMBER PRIMARY KEY,
10
+ first_name VARCHAR2(20),
11
+ last_name VARCHAR2(25),
12
+ email VARCHAR2(25),
13
+ phone_number VARCHAR2(20),
14
+ hire_date DATE,
15
+ job_id NUMBER,
16
+ salary NUMBER,
17
+ commission_pct NUMBER(2,2),
18
+ manager_id NUMBER(6),
19
+ department_id NUMBER(4,0),
20
+ created_at DATE,
21
+ has_email CHAR(1),
22
+ has_phone VARCHAR2(1) DEFAULT 'Y',
23
+ active_flag VARCHAR2(2),
24
+ manager_yn VARCHAR2(3) DEFAULT 'N',
25
+ test_boolean VARCHAR2(3)
26
+ )
27
+ SQL
28
+ @conn.execute <<~SQL
29
+ CREATE SEQUENCE test3_employees_seq MINVALUE 1
30
+ INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
31
+ SQL
32
+ end
33
+
34
+ after(:all) do
35
+ @conn.execute "DROP TABLE test3_employees"
36
+ @conn.execute "DROP SEQUENCE test3_employees_seq"
37
+ end
38
+
39
+ before(:each) do
40
+ class ::Test3Employee < ActiveRecord::Base
41
+ end
42
+ end
43
+
44
+ after(:each) do
45
+ Object.send(:remove_const, "Test3Employee")
46
+ ActiveRecord::Base.clear_cache!
47
+ end
48
+
49
+ describe "default values in new records" do
50
+ context "when emulate_booleans_from_strings is false" do
51
+ before do
52
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
53
+ end
54
+
55
+ it "are Y or N" do
56
+ subject = Test3Employee.new
57
+ expect(subject.has_phone).to eq("Y")
58
+ expect(subject.manager_yn).to eq("N")
59
+ end
60
+ end
61
+
62
+ context "when emulate_booleans_from_strings is true" do
63
+ before do
64
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
65
+ end
66
+
67
+ it "are True or False" do
68
+ class ::Test3Employee < ActiveRecord::Base
69
+ attribute :has_phone, :boolean
70
+ attribute :manager_yn, :boolean, default: false
71
+ end
72
+ subject = Test3Employee.new
73
+ expect(subject.has_phone).to be_a(TrueClass)
74
+ expect(subject.manager_yn).to be_a(FalseClass)
75
+ end
76
+ end
77
+ end
78
+
79
+ it "should translate boolean type to NUMBER(1) if emulate_booleans_from_strings is false" do
80
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
81
+ sql_type = ActiveRecord::Base.connection.type_to_sql(:boolean)
82
+ expect(sql_type).to eq("NUMBER(1)")
83
+ end
84
+
85
+ describe "/ VARCHAR2 boolean values from ActiveRecord model" do
86
+ before(:each) do
87
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
88
+ end
89
+
90
+ after(:each) do
91
+ ActiveRecord::Base.clear_cache!
92
+ end
93
+
94
+ def create_employee3(params = {})
95
+ @employee3 = Test3Employee.create(
96
+ {
97
+ first_name: "First",
98
+ last_name: "Last",
99
+ has_email: true,
100
+ has_phone: false,
101
+ active_flag: true,
102
+ manager_yn: false
103
+ }.merge(params)
104
+ )
105
+ @employee3.reload
106
+ end
107
+
108
+ it "should return String value from VARCHAR2 boolean column if emulate_booleans_from_strings is false" do
109
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
110
+ create_employee3
111
+ %w(has_email has_phone active_flag manager_yn).each do |col|
112
+ expect(@employee3.send(col.to_sym).class).to eq(String)
113
+ end
114
+ end
115
+
116
+ it "should return boolean value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
117
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
118
+ class ::Test3Employee < ActiveRecord::Base
119
+ attribute :has_email, :boolean
120
+ attribute :active_flag, :boolean
121
+ attribute :has_phone, :boolean, default: false
122
+ attribute :manager_yn, :boolean, default: false
123
+ end
124
+ create_employee3
125
+ %w(has_email active_flag).each do |col|
126
+ expect(@employee3.send(col.to_sym).class).to eq(TrueClass)
127
+ expect(@employee3.send((col + "_before_type_cast").to_sym)).to eq("Y")
128
+ end
129
+ %w(has_phone manager_yn).each do |col|
130
+ expect(@employee3.send(col.to_sym).class).to eq(FalseClass)
131
+ expect(@employee3.send((col + "_before_type_cast").to_sym)).to eq("N")
132
+ end
133
+ end
134
+
135
+ it "should return string value from VARCHAR2 column if it is not boolean column and emulate_booleans_from_strings is true" do
136
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
137
+ create_employee3
138
+ expect(@employee3.first_name.class).to eq(String)
139
+ end
140
+
141
+ it "should return boolean value from VARCHAR2 boolean column if attribute is set to :boolean" do
142
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
143
+ class ::Test3Employee < ActiveRecord::Base
144
+ attribute :test_boolean, :boolean
145
+ end
146
+ create_employee3(test_boolean: true)
147
+ expect(@employee3.test_boolean.class).to eq(TrueClass)
148
+ expect(@employee3.test_boolean_before_type_cast).to eq("Y")
149
+ create_employee3(test_boolean: false)
150
+ expect(@employee3.test_boolean.class).to eq(FalseClass)
151
+ expect(@employee3.test_boolean_before_type_cast).to eq("N")
152
+ create_employee3(test_boolean: nil)
153
+ expect(@employee3.test_boolean.class).to eq(NilClass)
154
+ expect(@employee3.test_boolean_before_type_cast).to be_nil
155
+ create_employee3(test_boolean: "")
156
+ expect(@employee3.test_boolean.class).to eq(NilClass)
157
+ expect(@employee3.test_boolean_before_type_cast).to be_nil
158
+ end
159
+
160
+ it "should return string value from VARCHAR2 column with boolean column name but attribute is set to :string" do
161
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
162
+ class ::Test3Employee < ActiveRecord::Base
163
+ attribute :active_flag, :string
164
+ end
165
+ create_employee3
166
+ expect(@employee3.active_flag.class).to eq(String)
167
+ end
168
+ end
169
+ end
170
+
171
+ describe "OracleEnhancedAdapter boolean support when emulate_booleans_from_strings = true" do
172
+ include SchemaSpecHelper
173
+
174
+ before(:all) do
175
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
176
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
177
+ schema_define do
178
+ create_table :posts, force: true do |t|
179
+ t.string :name, null: false
180
+ t.boolean :is_default, default: false
181
+ end
182
+ end
183
+ end
184
+
185
+ after(:all) do
186
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
187
+ end
188
+
189
+ before(:each) do
190
+ class ::Post < ActiveRecord::Base
191
+ attribute :is_default, :boolean
192
+ end
193
+ end
194
+
195
+ after(:each) do
196
+ Object.send(:remove_const, "Post")
197
+ ActiveRecord::Base.clear_cache!
198
+ end
199
+
200
+ it "boolean should not change after reload" do
201
+ post = Post.create(name: "Test 1", is_default: false)
202
+ expect(post.is_default).to be false
203
+ post.reload
204
+ expect(post.is_default).to be false
205
+ end
206
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe "OracleEnhancedAdapter processing CHAR column" do
4
+ before(:all) do
5
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
6
+ @conn = ActiveRecord::Base.connection
7
+ @conn.execute <<~SQL
8
+ CREATE TABLE test_items (
9
+ id NUMBER(6,0) PRIMARY KEY,
10
+ padded CHAR(10)
11
+ )
12
+ SQL
13
+ @conn.execute "CREATE SEQUENCE test_items_seq"
14
+ end
15
+
16
+ after(:all) do
17
+ @conn.execute "DROP TABLE test_items"
18
+ @conn.execute "DROP SEQUENCE test_items_seq"
19
+ end
20
+
21
+ before(:each) do
22
+ class ::TestItem < ActiveRecord::Base
23
+ end
24
+ end
25
+
26
+ after(:each) do
27
+ TestItem.delete_all
28
+ Object.send(:remove_const, "TestItem")
29
+ ActiveRecord::Base.clear_cache!
30
+ end
31
+
32
+ it "should create and find record" do
33
+ str = "ABC"
34
+ TestItem.create!
35
+ item = TestItem.first
36
+ item.padded = str
37
+ item.save
38
+
39
+ expect(TestItem.where(padded: item.padded).count).to eq(1)
40
+
41
+ item_reloaded = TestItem.first
42
+ expect(item_reloaded.padded).to eq(str)
43
+ end
44
+
45
+ it "should support case sensitive matching" do
46
+ TestItem.create!(
47
+ padded: "First",
48
+ )
49
+ TestItem.create!(
50
+ padded: "first",
51
+ )
52
+
53
+ expect(TestItem.where(TestItem.arel_table[:padded].matches("first%", "\\", true))).to have_attributes(count: 1)
54
+ end
55
+
56
+ it "should support case insensitive matching" do
57
+ TestItem.create!(
58
+ padded: "First",
59
+ )
60
+ TestItem.create!(
61
+ padded: "first",
62
+ )
63
+
64
+ expect(TestItem.where(TestItem.arel_table[:padded].matches("first%", "\\", false))).to have_attributes(count: 2)
65
+ expect(TestItem.where(TestItem.arel_table[:padded].matches("first%"))).to have_attributes(count: 2)
66
+ end
67
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+
5
+ describe "OracleEnhancedAdapter custom types handling" do
6
+ include SchemaSpecHelper
7
+
8
+ before(:all) do
9
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
10
+ schema_define do
11
+ create_table :test_employees, force: true do |t|
12
+ t.string :first_name, limit: 20
13
+ t.string :last_name, limit: 25
14
+ t.text :signature
15
+ end
16
+ end
17
+
18
+ class TestEmployee < ActiveRecord::Base
19
+ class AttributeSignature < ActiveRecord::Type::Text
20
+ def cast(value)
21
+ case value
22
+ when Signature
23
+ value
24
+ when nil
25
+ nil
26
+ else
27
+ Signature.new(Base64.decode64 value)
28
+ end
29
+ end
30
+
31
+ def serialize(value)
32
+ Base64.encode64 value.raw
33
+ end
34
+
35
+ def changed_in_place?(raw_old_value, new_value)
36
+ new_value != cast(raw_old_value)
37
+ end
38
+ end
39
+
40
+ class Signature
41
+ attr_reader :raw
42
+
43
+ def initialize(raw_value)
44
+ @raw = raw_value
45
+ end
46
+
47
+ def to_s
48
+ "Signature nice string #{raw[0..5]}"
49
+ end
50
+
51
+ def ==(object)
52
+ raw == object&.raw
53
+ end
54
+ alias eql? ==
55
+ end
56
+
57
+ attribute :signature, AttributeSignature.new
58
+ end
59
+ end
60
+
61
+ after(:all) do
62
+ schema_define do
63
+ drop_table :test_employees
64
+ end
65
+ Object.send(:remove_const, "TestEmployee")
66
+ ActiveRecord::Base.clear_cache!
67
+ end
68
+
69
+ it "should serialize LOBs when creating a record" do
70
+ raw_signature = "peter'ssignature"
71
+ signature = TestEmployee::Signature.new(raw_signature)
72
+ @employee = TestEmployee.create!(first_name: "Peter", last_name: "Doe", signature: signature)
73
+ @employee.reload
74
+ expect(@employee.signature).to eql(signature)
75
+ expect(@employee.signature).to_not be(signature)
76
+ expect(TestEmployee.first.read_attribute_before_type_cast(:signature)).to eq(Base64.encode64 raw_signature)
77
+ end
78
+
79
+ it "should serialize LOBs when updating a record" do
80
+ raw_signature = "peter'ssignature"
81
+ signature = TestEmployee::Signature.new(raw_signature)
82
+ @employee = TestEmployee.create!(first_name: "Peter", last_name: "Doe", signature: TestEmployee::Signature.new("old signature"))
83
+ @employee.signature = signature
84
+ @employee.save!
85
+ @employee.reload
86
+ expect(@employee.signature).to eql(signature)
87
+ expect(@employee.signature).to_not be(signature)
88
+ expect(TestEmployee.first.read_attribute_before_type_cast(:signature)).to eq(Base64.encode64 raw_signature)
89
+ end
90
+ end