pmacs-activerecord-oracle_enhanced-adapter 1.4.2.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +52 -0
  3. data/History.md +284 -0
  4. data/License.txt +20 -0
  5. data/README.md +403 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +59 -0
  8. data/VERSION +1 -0
  9. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1408 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +118 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +141 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +135 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +359 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +44 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +565 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +491 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +231 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +257 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +397 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +265 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +294 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  30. data/lib/pmacs-activerecord-oracle_enhanced-adapter.rb +25 -0
  31. data/pmacs-activerecord-oracle_enhanced-adapter.gemspec +131 -0
  32. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +778 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +332 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +427 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1376 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +141 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +378 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +438 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1280 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +339 -0
  45. data/spec/spec_helper.rb +187 -0
  46. metadata +302 -0
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe "OracleEnhancedAdapter to_d method" do
5
+ it "BigDecimal#to_d returns the same decimal number" do
6
+ d = BigDecimal.new("12345678901234567890.0123456789")
7
+ d.to_d.should == d
8
+ end
9
+
10
+ it "Bignum#to_d translates large integer to decimal" do
11
+ n = 12345678901234567890
12
+ n.to_d.should == BigDecimal.new(n.to_s)
13
+ end
14
+
15
+ it "Fixnum#to_d translates small integer to decimal" do
16
+ n = 123456
17
+ n.to_d.should == BigDecimal.new(n.to_s)
18
+ end
19
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+
3
+ unless defined?(NO_COMPOSITE_PRIMARY_KEYS)
4
+
5
+ describe "OracleEnhancedAdapter composite_primary_keys support" do
6
+ include SchemaSpecHelper
7
+
8
+ before(:all) do
9
+ if defined?(::ActiveRecord::ConnectionAdapters::OracleAdapter)
10
+ @old_oracle_adapter = ::ActiveRecord::ConnectionAdapters::OracleAdapter
11
+ ::ActiveRecord::ConnectionAdapters.send(:remove_const, :OracleAdapter)
12
+ end
13
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
14
+ if $cpk_oracle_adapter
15
+ ::ActiveRecord::ConnectionAdapters::OracleAdapter = $cpk_oracle_adapter
16
+ $cpk_oracle_adapter = nil
17
+ end
18
+ require 'composite_primary_keys'
19
+ end
20
+
21
+ after(:all) do
22
+ # Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
23
+ if defined?(::ActiveRecord::ConnectionAdapters::OracleAdapter)
24
+ $cpk_oracle_adapter = ::ActiveRecord::ConnectionAdapters::OracleAdapter
25
+ ::ActiveRecord::ConnectionAdapters.send(:remove_const, :OracleAdapter)
26
+ end
27
+ if @old_oracle_adapter
28
+ ::ActiveRecord::ConnectionAdapters::OracleAdapter = @old_oracle_adapter
29
+ @old_oracle_adapter = nil
30
+ end
31
+ end
32
+
33
+ describe "do not use count distinct" do
34
+ before(:all) do
35
+ schema_define do
36
+ create_table :job_history, :primary_key => [:employee_id, :start_date], :force => true do |t|
37
+ t.integer :employee_id
38
+ t.date :start_date
39
+ end
40
+ end
41
+ class ::JobHistory < ActiveRecord::Base
42
+ set_table_name "job_history"
43
+ set_primary_keys :employee_id, :start_date
44
+ end
45
+ end
46
+
47
+ after(:all) do
48
+ Object.send(:remove_const, 'JobHistory') if defined?(JobHistory)
49
+ schema_define do
50
+ drop_table :job_history
51
+ end
52
+ end
53
+
54
+ it "should tell ActiveRecord that count distinct is not supported" do
55
+ ActiveRecord::Base.connection.supports_count_distinct?.should be_false
56
+ end
57
+
58
+ it "should execute correct SQL COUNT DISTINCT statement on table with composite primary keys" do
59
+ lambda { JobHistory.count(:distinct => true) }.should_not raise_error
60
+ end
61
+ end
62
+
63
+ describe "table with LOB" do
64
+ before(:all) do
65
+ schema_define do
66
+ create_table :cpk_write_lobs_test, :primary_key => [:type_category, :date_value], :force => true do |t|
67
+ t.string :type_category, :limit => 15, :null => false
68
+ t.date :date_value, :null => false
69
+ t.text :results, :null => false
70
+ t.timestamps
71
+ end
72
+ create_table :non_cpk_write_lobs_test, :force => true do |t|
73
+ t.date :date_value, :null => false
74
+ t.text :results, :null => false
75
+ t.timestamps
76
+ end
77
+ end
78
+ class ::CpkWriteLobsTest < ActiveRecord::Base
79
+ set_table_name 'cpk_write_lobs_test'
80
+ set_primary_keys :type_category, :date_value
81
+ end
82
+ class ::NonCpkWriteLobsTest < ActiveRecord::Base
83
+ set_table_name 'non_cpk_write_lobs_test'
84
+ end
85
+ end
86
+
87
+ after(:all) do
88
+ schema_define do
89
+ drop_table :cpk_write_lobs_test
90
+ drop_table :non_cpk_write_lobs_test
91
+ end
92
+ Object.send(:remove_const, "CpkWriteLobsTest")
93
+ Object.send(:remove_const, "NonCpkWriteLobsTest")
94
+ end
95
+
96
+ it "should create new record in table with CPK and LOB" do
97
+ lambda {
98
+ CpkWriteLobsTest.create(:type_category => 'AAA', :date_value => Date.today, :results => 'DATA '*10)
99
+ }.should_not raise_error
100
+ end
101
+
102
+ it "should create new record in table without CPK and with LOB" do
103
+ lambda {
104
+ NonCpkWriteLobsTest.create(:date_value => Date.today, :results => 'DATA '*10)
105
+ }.should_not raise_error
106
+ end
107
+ end
108
+
109
+ # Other testing was done based on composite_primary_keys tests
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,1376 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe "OracleEnhancedAdapter date type detection based on column names" do
5
+ before(:all) do
6
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
7
+ @conn = ActiveRecord::Base.connection
8
+ @conn.execute "DROP TABLE test_employees" rescue nil
9
+ @conn.execute "DROP SEQUENCE test_employees_seq" rescue nil
10
+ @conn.execute <<-SQL
11
+ CREATE TABLE test_employees (
12
+ employee_id NUMBER(6,0) PRIMARY KEY,
13
+ first_name VARCHAR2(20),
14
+ last_name VARCHAR2(25),
15
+ email VARCHAR2(25),
16
+ phone_number VARCHAR2(20),
17
+ hire_date DATE,
18
+ job_id NUMBER(6,0),
19
+ salary NUMBER(8,2),
20
+ commission_pct NUMBER(2,2),
21
+ manager_id NUMBER(6,0),
22
+ department_id NUMBER(4,0),
23
+ created_at DATE,
24
+ updated_at DATE
25
+ )
26
+ SQL
27
+ @conn.execute <<-SQL
28
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
29
+ INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
30
+ SQL
31
+ end
32
+
33
+ after(:all) do
34
+ @conn.execute "DROP TABLE test_employees"
35
+ @conn.execute "DROP SEQUENCE test_employees_seq"
36
+ end
37
+
38
+ it "should set DATE column type as datetime if emulate_dates_by_column_name is false" do
39
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
40
+ columns = @conn.columns('test_employees')
41
+ column = columns.detect{|c| c.name == "hire_date"}
42
+ column.type.should == :datetime
43
+ end
44
+
45
+ it "should set DATE column type as date if column name contains '_date_' and emulate_dates_by_column_name is true" do
46
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
47
+ columns = @conn.columns('test_employees')
48
+ column = columns.detect{|c| c.name == "hire_date"}
49
+ column.type.should == :date
50
+ end
51
+
52
+ it "should set DATE column type as datetime if column name does not contain '_date_' and emulate_dates_by_column_name is true" do
53
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
54
+ columns = @conn.columns('test_employees')
55
+ column = columns.detect{|c| c.name == "created_at"}
56
+ column.type.should == :datetime
57
+ end
58
+
59
+ it "should set DATE column type as datetime if column name contains 'date' as part of other word and emulate_dates_by_column_name is true" do
60
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
61
+ columns = @conn.columns('test_employees')
62
+ column = columns.detect{|c| c.name == "updated_at"}
63
+ column.type.should == :datetime
64
+ end
65
+
66
+ it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
67
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
68
+ columns = @conn.columns('test_employees')
69
+ column = columns.detect{|c| c.name == "hire_date"}
70
+ column.type_cast(Time.now).class.should == Time
71
+ end
72
+
73
+ it "should return Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
74
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
75
+ columns = @conn.columns('test_employees')
76
+ column = columns.detect{|c| c.name == "hire_date"}
77
+ column.type_cast(Time.now).class.should == Date
78
+ end
79
+
80
+ it "should typecast DateTime value to Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
81
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
82
+ columns = @conn.columns('test_employees')
83
+ column = columns.detect{|c| c.name == "hire_date"}
84
+ column.type_cast(DateTime.new(1900,1,1)).class.should == Date
85
+ end
86
+
87
+ describe "/ DATE values from ActiveRecord model" do
88
+ before(:each) do
89
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
90
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = false
91
+ class ::TestEmployee < ActiveRecord::Base
92
+ if self.respond_to?(:primary_key=)
93
+ self.primary_key = "employee_id"
94
+ else
95
+ set_primary_key "employee_id"
96
+ end
97
+ end
98
+ end
99
+
100
+ def create_test_employee(params={})
101
+ @today = params[:today] || Date.new(2008,8,19)
102
+ @now = params[:now] || Time.local(2008,8,19,17,03,59)
103
+ @employee = TestEmployee.create(
104
+ :first_name => "First",
105
+ :last_name => "Last",
106
+ :hire_date => @today,
107
+ :created_at => @now
108
+ )
109
+ @employee.reload
110
+ end
111
+
112
+ after(:each) do
113
+ # @employee.destroy if @employee
114
+ Object.send(:remove_const, "TestEmployee")
115
+ @conn.clear_types_for_columns
116
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
117
+ end
118
+
119
+ it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
120
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
121
+ create_test_employee
122
+ @employee.hire_date.class.should == Time
123
+ end
124
+
125
+ it "should return Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
126
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
127
+ create_test_employee
128
+ @employee.hire_date.class.should == Date
129
+ end
130
+
131
+ it "should return Date value from DATE column with old date value if column name contains 'date' and emulate_dates_by_column_name is true" do
132
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
133
+ create_test_employee(:today => Date.new(1900,1,1))
134
+ @employee.hire_date.class.should == Date
135
+ end
136
+
137
+ it "should return Time value from DATE column if column name does not contain 'date' and emulate_dates_by_column_name is true" do
138
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
139
+ create_test_employee
140
+ @employee.created_at.class.should == Time
141
+ end
142
+
143
+ it "should return Date value from DATE column if emulate_dates_by_column_name is false but column is defined as date" do
144
+ class ::TestEmployee < ActiveRecord::Base
145
+ set_date_columns :hire_date
146
+ end
147
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
148
+ create_test_employee
149
+ @employee.hire_date.class.should == Date
150
+ end
151
+
152
+ it "should return Date value from DATE column with old date value if emulate_dates_by_column_name is false but column is defined as date" do
153
+ class ::TestEmployee < ActiveRecord::Base
154
+ set_date_columns :hire_date
155
+ end
156
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
157
+ create_test_employee(:today => Date.new(1900,1,1))
158
+ @employee.hire_date.class.should == Date
159
+ end
160
+
161
+ it "should see set_date_columns values in different connection" do
162
+ class ::TestEmployee < ActiveRecord::Base
163
+ set_date_columns :hire_date
164
+ end
165
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
166
+ # establish other connection
167
+ other_conn = ActiveRecord::Base.oracle_enhanced_connection(CONNECTION_PARAMS)
168
+ other_conn.get_type_for_column('test_employees', 'hire_date').should == :date
169
+ end
170
+
171
+ it "should return Time value from DATE column if emulate_dates_by_column_name is true but column is defined as datetime" do
172
+ class ::TestEmployee < ActiveRecord::Base
173
+ set_datetime_columns :hire_date
174
+ end
175
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
176
+ create_test_employee
177
+ @employee.hire_date.class.should == Time
178
+ # change to current time with hours, minutes and seconds
179
+ @employee.hire_date = @now
180
+ @employee.save!
181
+ @employee.reload
182
+ @employee.hire_date.class.should == Time
183
+ @employee.hire_date.should == @now
184
+ end
185
+
186
+ it "should guess Date or Time value if emulate_dates is true" do
187
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = true
188
+ create_test_employee
189
+ @employee.hire_date.class.should == Date
190
+ @employee.created_at.class.should == Time
191
+ end
192
+
193
+ end
194
+
195
+ end
196
+
197
+ describe "OracleEnhancedAdapter integer type detection based on column names" do
198
+ before(:all) do
199
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
200
+ @conn = ActiveRecord::Base.connection
201
+ @conn.execute "DROP TABLE test2_employees" rescue nil
202
+ @conn.execute <<-SQL
203
+ CREATE TABLE test2_employees (
204
+ id NUMBER PRIMARY KEY,
205
+ first_name VARCHAR2(20),
206
+ last_name VARCHAR2(25),
207
+ email VARCHAR2(25),
208
+ phone_number VARCHAR2(20),
209
+ hire_date DATE,
210
+ job_id NUMBER,
211
+ salary NUMBER,
212
+ commission_pct NUMBER(2,2),
213
+ manager_id NUMBER(6),
214
+ is_manager NUMBER(1),
215
+ department_id NUMBER(4,0),
216
+ created_at DATE
217
+ )
218
+ SQL
219
+ @conn.execute "DROP SEQUENCE test2_employees_seq" rescue nil
220
+ @conn.execute <<-SQL
221
+ CREATE SEQUENCE test2_employees_seq MINVALUE 1
222
+ INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
223
+ SQL
224
+ end
225
+
226
+ after(:all) do
227
+ @conn.execute "DROP TABLE test2_employees"
228
+ @conn.execute "DROP SEQUENCE test2_employees_seq"
229
+ end
230
+
231
+ it "should set NUMBER column type as decimal if emulate_integers_by_column_name is false" do
232
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
233
+ columns = @conn.columns('test2_employees')
234
+ column = columns.detect{|c| c.name == "job_id"}
235
+ column.type.should == :decimal
236
+ end
237
+
238
+ it "should set NUMBER column type as integer if emulate_integers_by_column_name is true" do
239
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
240
+ columns = @conn.columns('test2_employees')
241
+ column = columns.detect{|c| c.name == "job_id"}
242
+ column.type.should == :integer
243
+ column = columns.detect{|c| c.name == "id"}
244
+ column.type.should == :integer
245
+ end
246
+
247
+ it "should set NUMBER column type as decimal if column name does not contain 'id' and emulate_integers_by_column_name is true" do
248
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
249
+ columns = @conn.columns('test2_employees')
250
+ column = columns.detect{|c| c.name == "salary"}
251
+ column.type.should == :decimal
252
+ end
253
+
254
+ it "should return BigDecimal value from NUMBER column if emulate_integers_by_column_name is false" do
255
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
256
+ columns = @conn.columns('test2_employees')
257
+ column = columns.detect{|c| c.name == "job_id"}
258
+ column.type_cast(1.0).class.should == BigDecimal
259
+ end
260
+
261
+ it "should return Fixnum value from NUMBER column if column name contains 'id' and emulate_integers_by_column_name is true" do
262
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
263
+ columns = @conn.columns('test2_employees')
264
+ column = columns.detect{|c| c.name == "job_id"}
265
+ column.type_cast(1.0).class.should == Fixnum
266
+ end
267
+
268
+ describe "/ NUMBER values from ActiveRecord model" do
269
+ before(:each) do
270
+ class ::Test2Employee < ActiveRecord::Base
271
+ end
272
+ end
273
+
274
+ after(:each) do
275
+ Object.send(:remove_const, "Test2Employee")
276
+ @conn.clear_types_for_columns
277
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = true
278
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
279
+ end
280
+
281
+ def create_employee2
282
+ @employee2 = Test2Employee.create(
283
+ :first_name => "First",
284
+ :last_name => "Last",
285
+ :job_id => 1,
286
+ :is_manager => 1,
287
+ :salary => 1000
288
+ )
289
+ @employee2.reload
290
+ end
291
+
292
+ it "should return BigDecimal value from NUMBER column if emulate_integers_by_column_name is false" do
293
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
294
+ create_employee2
295
+ @employee2.job_id.class.should == BigDecimal
296
+ end
297
+
298
+ it "should return Fixnum value from NUMBER column if column name contains 'id' and emulate_integers_by_column_name is true" do
299
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
300
+ create_employee2
301
+ @employee2.job_id.class.should == Fixnum
302
+ end
303
+
304
+ it "should return Fixnum value from NUMBER column with integer value using _before_type_cast method" do
305
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
306
+ create_employee2
307
+ @employee2.job_id_before_type_cast.class.should == Fixnum
308
+ end
309
+
310
+ it "should return BigDecimal value from NUMBER column if column name does not contain 'id' and emulate_integers_by_column_name is true" do
311
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
312
+ create_employee2
313
+ @employee2.salary.class.should == BigDecimal
314
+ end
315
+
316
+ it "should return Fixnum value from NUMBER column if column specified in set_integer_columns" do
317
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
318
+ Test2Employee.set_integer_columns :job_id
319
+ create_employee2
320
+ @employee2.job_id.class.should == Fixnum
321
+ end
322
+
323
+ it "should return Boolean value from NUMBER(1) column if emulate booleans is used" do
324
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = true
325
+ create_employee2
326
+ @employee2.is_manager.class.should == TrueClass
327
+ end
328
+
329
+ it "should return Fixnum value from NUMBER(1) column if emulate booleans is not used" do
330
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = false
331
+ create_employee2
332
+ @employee2.is_manager.class.should == Fixnum
333
+ end
334
+
335
+ it "should return Fixnum value from NUMBER(1) column if column specified in set_integer_columns" do
336
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = true
337
+ Test2Employee.set_integer_columns :is_manager
338
+ create_employee2
339
+ @employee2.is_manager.class.should == Fixnum
340
+ end
341
+
342
+ end
343
+
344
+ end
345
+
346
+ describe "OracleEnhancedAdapter boolean type detection based on string column types and names" do
347
+ before(:all) do
348
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
349
+ @conn = ActiveRecord::Base.connection
350
+ @conn.execute <<-SQL
351
+ CREATE TABLE test3_employees (
352
+ id NUMBER PRIMARY KEY,
353
+ first_name VARCHAR2(20),
354
+ last_name VARCHAR2(25),
355
+ email VARCHAR2(25),
356
+ phone_number VARCHAR2(20),
357
+ hire_date DATE,
358
+ job_id NUMBER,
359
+ salary NUMBER,
360
+ commission_pct NUMBER(2,2),
361
+ manager_id NUMBER(6),
362
+ department_id NUMBER(4,0),
363
+ created_at DATE,
364
+ has_email CHAR(1),
365
+ has_phone VARCHAR2(1) DEFAULT 'Y',
366
+ active_flag VARCHAR2(2),
367
+ manager_yn VARCHAR2(3) DEFAULT 'N',
368
+ test_boolean VARCHAR2(3)
369
+ )
370
+ SQL
371
+ @conn.execute <<-SQL
372
+ CREATE SEQUENCE test3_employees_seq MINVALUE 1
373
+ INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
374
+ SQL
375
+ end
376
+
377
+ after(:all) do
378
+ @conn.execute "DROP TABLE test3_employees"
379
+ @conn.execute "DROP SEQUENCE test3_employees_seq"
380
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
381
+ end
382
+
383
+ it "should set CHAR/VARCHAR2 column type as string if emulate_booleans_from_strings is false" do
384
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
385
+ columns = @conn.columns('test3_employees')
386
+ %w(has_email has_phone active_flag manager_yn).each do |col|
387
+ column = columns.detect{|c| c.name == col}
388
+ column.type.should == :string
389
+ end
390
+ end
391
+
392
+ it "should set CHAR/VARCHAR2 column type as boolean if emulate_booleans_from_strings is true" do
393
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
394
+ columns = @conn.columns('test3_employees')
395
+ %w(has_email has_phone active_flag manager_yn).each do |col|
396
+ column = columns.detect{|c| c.name == col}
397
+ column.type.should == :boolean
398
+ end
399
+ end
400
+
401
+ it "should set VARCHAR2 column type as string if column name does not contain 'flag' or 'yn' and emulate_booleans_from_strings is true" do
402
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
403
+ columns = @conn.columns('test3_employees')
404
+ %w(phone_number email).each do |col|
405
+ column = columns.detect{|c| c.name == col}
406
+ column.type.should == :string
407
+ end
408
+ end
409
+
410
+ it "should return string value from VARCHAR2 boolean column if emulate_booleans_from_strings is false" do
411
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
412
+ columns = @conn.columns('test3_employees')
413
+ %w(has_email has_phone active_flag manager_yn).each do |col|
414
+ column = columns.detect{|c| c.name == col}
415
+ column.type_cast("Y").class.should == String
416
+ end
417
+ end
418
+
419
+ it "should return boolean value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
420
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
421
+ columns = @conn.columns('test3_employees')
422
+ %w(has_email has_phone active_flag manager_yn).each do |col|
423
+ column = columns.detect{|c| c.name == col}
424
+ column.type_cast("Y").class.should == TrueClass
425
+ column.type_cast("N").class.should == FalseClass
426
+ end
427
+ end
428
+
429
+ it "should translate boolean type to VARCHAR2(1) if emulate_booleans_from_strings is true" do
430
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
431
+ ActiveRecord::Base.connection.type_to_sql(
432
+ :boolean, nil, nil, nil).should == "VARCHAR2(1)"
433
+ end
434
+
435
+ it "should translate boolean type to NUMBER(1) if emulate_booleans_from_strings is false" do
436
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
437
+ ActiveRecord::Base.connection.type_to_sql(
438
+ :boolean, nil, nil, nil).should == "NUMBER(1)"
439
+ end
440
+
441
+ it "should get default value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
442
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
443
+ columns = @conn.columns('test3_employees')
444
+ columns.detect{|c| c.name == 'has_phone'}.default.should be_true
445
+ columns.detect{|c| c.name == 'manager_yn'}.default.should be_false
446
+ end
447
+
448
+ describe "/ VARCHAR2 boolean values from ActiveRecord model" do
449
+ before(:each) do
450
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
451
+ class ::Test3Employee < ActiveRecord::Base
452
+ end
453
+ end
454
+
455
+ after(:each) do
456
+ Object.send(:remove_const, "Test3Employee")
457
+ @conn.clear_types_for_columns
458
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
459
+ end
460
+
461
+ def create_employee3(params={})
462
+ @employee3 = Test3Employee.create(
463
+ {
464
+ :first_name => "First",
465
+ :last_name => "Last",
466
+ :has_email => true,
467
+ :has_phone => false,
468
+ :active_flag => true,
469
+ :manager_yn => false
470
+ }.merge(params)
471
+ )
472
+ @employee3.reload
473
+ end
474
+
475
+ it "should return String value from VARCHAR2 boolean column if emulate_booleans_from_strings is false" do
476
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
477
+ create_employee3
478
+ %w(has_email has_phone active_flag manager_yn).each do |col|
479
+ @employee3.send(col.to_sym).class.should == String
480
+ end
481
+ end
482
+
483
+ it "should return boolean value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
484
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
485
+ create_employee3
486
+ %w(has_email active_flag).each do |col|
487
+ @employee3.send(col.to_sym).class.should == TrueClass
488
+ @employee3.send((col+"_before_type_cast").to_sym).should == "Y"
489
+ end
490
+ %w(has_phone manager_yn).each do |col|
491
+ @employee3.send(col.to_sym).class.should == FalseClass
492
+ @employee3.send((col+"_before_type_cast").to_sym).should == "N"
493
+ end
494
+ end
495
+
496
+ it "should return string value from VARCHAR2 column if it is not boolean column and emulate_booleans_from_strings is true" do
497
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
498
+ create_employee3
499
+ @employee3.first_name.class.should == String
500
+ end
501
+
502
+ it "should return boolean value from VARCHAR2 boolean column if column specified in set_boolean_columns" do
503
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
504
+ Test3Employee.set_boolean_columns :test_boolean
505
+ create_employee3(:test_boolean => true)
506
+ @employee3.test_boolean.class.should == TrueClass
507
+ @employee3.test_boolean_before_type_cast.should == "Y"
508
+ create_employee3(:test_boolean => false)
509
+ @employee3.test_boolean.class.should == FalseClass
510
+ @employee3.test_boolean_before_type_cast.should == "N"
511
+ create_employee3(:test_boolean => nil)
512
+ @employee3.test_boolean.class.should == NilClass
513
+ @employee3.test_boolean_before_type_cast.should == nil
514
+ create_employee3(:test_boolean => "")
515
+ @employee3.test_boolean.class.should == NilClass
516
+ @employee3.test_boolean_before_type_cast.should == nil
517
+ end
518
+
519
+ it "should return string value from VARCHAR2 column with boolean column name but is specified in set_string_columns" do
520
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
521
+ Test3Employee.set_string_columns :active_flag
522
+ create_employee3
523
+ @employee3.active_flag.class.should == String
524
+ end
525
+
526
+ end
527
+
528
+ end
529
+
530
+ describe "OracleEnhancedAdapter timestamp with timezone support" do
531
+ before(:all) do
532
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
533
+ @conn = ActiveRecord::Base.connection
534
+ @conn.execute <<-SQL
535
+ CREATE TABLE test_employees (
536
+ employee_id NUMBER(6,0) PRIMARY KEY,
537
+ first_name VARCHAR2(20),
538
+ last_name VARCHAR2(25),
539
+ email VARCHAR2(25),
540
+ phone_number VARCHAR2(20),
541
+ hire_date DATE,
542
+ job_id NUMBER(6,0),
543
+ salary NUMBER(8,2),
544
+ commission_pct NUMBER(2,2),
545
+ manager_id NUMBER(6,0),
546
+ department_id NUMBER(4,0),
547
+ created_at TIMESTAMP,
548
+ created_at_tz TIMESTAMP WITH TIME ZONE,
549
+ created_at_ltz TIMESTAMP WITH LOCAL TIME ZONE
550
+ )
551
+ SQL
552
+ @conn.execute <<-SQL
553
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
554
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
555
+ SQL
556
+ end
557
+
558
+ after(:all) do
559
+ @conn.execute "DROP TABLE test_employees"
560
+ @conn.execute "DROP SEQUENCE test_employees_seq"
561
+ end
562
+
563
+ it "should set TIMESTAMP columns type as datetime" do
564
+ columns = @conn.columns('test_employees')
565
+ ts_columns = columns.select{|c| c.name =~ /created_at/}
566
+ ts_columns.each {|c| c.type.should == :timestamp}
567
+ end
568
+
569
+ describe "/ TIMESTAMP WITH TIME ZONE values from ActiveRecord model" do
570
+ before(:all) do
571
+ class ::TestEmployee < ActiveRecord::Base
572
+ if self.respond_to?(:primary_key=)
573
+ self.primary_key = "employee_id"
574
+ else
575
+ set_primary_key "employee_id"
576
+ end
577
+ end
578
+ end
579
+
580
+ after(:all) do
581
+ Object.send(:remove_const, "TestEmployee")
582
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
583
+ end
584
+
585
+ it "should return Time value from TIMESTAMP columns" do
586
+ @now = Time.local(2008,5,26,23,11,11,0)
587
+ @employee = TestEmployee.create(
588
+ :created_at => @now,
589
+ :created_at_tz => @now,
590
+ :created_at_ltz => @now
591
+ )
592
+ @employee.reload
593
+ [:created_at, :created_at_tz, :created_at_ltz].each do |c|
594
+ @employee.send(c).class.should == Time
595
+ @employee.send(c).to_f.should == @now.to_f
596
+ end
597
+ end
598
+
599
+ it "should return Time value with fractional seconds from TIMESTAMP columns" do
600
+ @now = Time.local(2008,5,26,23,11,11,10)
601
+ @employee = TestEmployee.create(
602
+ :created_at => @now,
603
+ :created_at_tz => @now,
604
+ :created_at_ltz => @now
605
+ )
606
+ @employee.reload
607
+ [:created_at, :created_at_tz, :created_at_ltz].each do |c|
608
+ @employee.send(c).class.should == Time
609
+ @employee.send(c).to_f.should == @now.to_f
610
+ end
611
+ end
612
+
613
+ end
614
+
615
+ end
616
+
617
+
618
+ describe "OracleEnhancedAdapter date and timestamp with different NLS date formats" do
619
+ before(:all) do
620
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
621
+ @conn = ActiveRecord::Base.connection
622
+ @conn.execute <<-SQL
623
+ CREATE TABLE test_employees (
624
+ employee_id NUMBER(6,0) PRIMARY KEY,
625
+ first_name VARCHAR2(20),
626
+ last_name VARCHAR2(25),
627
+ email VARCHAR2(25),
628
+ phone_number VARCHAR2(20),
629
+ hire_date DATE,
630
+ job_id NUMBER(6,0),
631
+ salary NUMBER(8,2),
632
+ commission_pct NUMBER(2,2),
633
+ manager_id NUMBER(6,0),
634
+ department_id NUMBER(4,0),
635
+ created_at DATE,
636
+ created_at_ts TIMESTAMP
637
+ )
638
+ SQL
639
+ @conn.execute <<-SQL
640
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
641
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
642
+ SQL
643
+ # @conn.execute %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
644
+ @conn.execute %q{alter session set nls_date_format = 'DD-MON-YYYY HH24:MI:SS'}
645
+ # @conn.execute %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'}
646
+ @conn.execute %q{alter session set nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS'}
647
+ end
648
+
649
+ after(:all) do
650
+ @conn.execute "DROP TABLE test_employees"
651
+ @conn.execute "DROP SEQUENCE test_employees_seq"
652
+ end
653
+
654
+ before(:each) do
655
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = false
656
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
657
+ class ::TestEmployee < ActiveRecord::Base
658
+ if self.respond_to?(:primary_key=)
659
+ self.primary_key = "employee_id"
660
+ else
661
+ set_primary_key "employee_id"
662
+ end
663
+ end
664
+ @today = Date.new(2008,6,28)
665
+ @now = Time.local(2008,6,28,13,34,33)
666
+ end
667
+
668
+ after(:each) do
669
+ Object.send(:remove_const, "TestEmployee")
670
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
671
+ end
672
+
673
+ def create_test_employee
674
+ @employee = TestEmployee.create(
675
+ :first_name => "First",
676
+ :last_name => "Last",
677
+ :hire_date => @today,
678
+ :created_at => @now,
679
+ :created_at_ts => @now
680
+ )
681
+ @employee.reload
682
+ end
683
+
684
+ it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
685
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
686
+ create_test_employee
687
+ @employee.hire_date.class.should == Time
688
+ @employee.hire_date.should == @today.to_time
689
+ end
690
+
691
+ it "should return Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
692
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
693
+ create_test_employee
694
+ @employee.hire_date.class.should == Date
695
+ @employee.hire_date.should == @today
696
+ end
697
+
698
+ it "should return Time value from DATE column if column name does not contain 'date' and emulate_dates_by_column_name is true" do
699
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
700
+ create_test_employee
701
+ @employee.created_at.class.should == Time
702
+ @employee.created_at.should == @now
703
+ end
704
+
705
+ it "should return Time value from TIMESTAMP columns" do
706
+ create_test_employee
707
+ @employee.created_at_ts.class.should == Time
708
+ @employee.created_at_ts.should == @now
709
+ end
710
+
711
+ it "should quote Date values with TO_DATE" do
712
+ @conn.quote(@today).should == "TO_DATE('#{@today.year}-#{"%02d" % @today.month}-#{"%02d" % @today.day}','YYYY-MM-DD HH24:MI:SS')"
713
+ end
714
+
715
+ it "should quote Time values with TO_DATE" do
716
+ @conn.quote(@now).should == "TO_DATE('#{@now.year}-#{"%02d" % @now.month}-#{"%02d" % @now.day} "+
717
+ "#{"%02d" % @now.hour}:#{"%02d" % @now.min}:#{"%02d" % @now.sec}','YYYY-MM-DD HH24:MI:SS')"
718
+ end
719
+
720
+ it "should quote Time values with TO_TIMESTAMP" do
721
+ @ts = @now + 0.1
722
+ @conn.quote(@ts).should == "TO_TIMESTAMP('#{@ts.year}-#{"%02d" % @ts.month}-#{"%02d" % @ts.day} "+
723
+ "#{"%02d" % @ts.hour}:#{"%02d" % @ts.min}:#{"%02d" % @ts.sec}:100000','YYYY-MM-DD HH24:MI:SS:FF6')"
724
+ end
725
+
726
+ end
727
+
728
+ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
729
+ before(:all) do
730
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
731
+ @conn = ActiveRecord::Base.connection
732
+ @conn.execute <<-SQL
733
+ CREATE TABLE test_employees (
734
+ employee_id NUMBER(6,0) PRIMARY KEY,
735
+ first_name VARCHAR2(20),
736
+ last_name VARCHAR2(25),
737
+ hire_date DATE,
738
+ last_login_at DATE,
739
+ last_login_at_ts TIMESTAMP
740
+ )
741
+ SQL
742
+ @conn.execute <<-SQL
743
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
744
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
745
+ SQL
746
+ class ::TestEmployee < ActiveRecord::Base
747
+ if self.respond_to?(:primary_key=)
748
+ self.primary_key = "employee_id"
749
+ else
750
+ set_primary_key "employee_id"
751
+ end
752
+ end
753
+ @today = Date.new(2008,6,28)
754
+ @today_iso = "2008-06-28"
755
+ @today_nls = "28.06.2008"
756
+ @nls_date_format = "%d.%m.%Y"
757
+ @now = Time.local(2008,6,28,13,34,33)
758
+ @now_iso = "2008-06-28 13:34:33"
759
+ @now_nls = "28.06.2008 13:34:33"
760
+ @nls_time_format = "%d.%m.%Y %H:%M:%S"
761
+ @now_nls_with_tz = "28.06.2008 13:34:33+05:00"
762
+ @nls_with_tz_time_format = "%d.%m.%Y %H:%M:%S%Z"
763
+ @now_with_tz = Time.parse @now_nls_with_tz
764
+ end
765
+
766
+ after(:all) do
767
+ Object.send(:remove_const, "TestEmployee")
768
+ @conn.execute "DROP TABLE test_employees"
769
+ @conn.execute "DROP SEQUENCE test_employees_seq"
770
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
771
+ end
772
+
773
+ before(:each) do
774
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
775
+ end
776
+
777
+ it "should assign ISO string to date column" do
778
+ @employee = TestEmployee.create(
779
+ :first_name => "First",
780
+ :last_name => "Last",
781
+ :hire_date => @today_iso
782
+ )
783
+ @employee.hire_date.should == @today
784
+ @employee.reload
785
+ @employee.hire_date.should == @today
786
+ end
787
+
788
+ it "should assign NLS string to date column" do
789
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = @nls_date_format
790
+ @employee = TestEmployee.create(
791
+ :first_name => "First",
792
+ :last_name => "Last",
793
+ :hire_date => @today_nls
794
+ )
795
+ @employee.hire_date.should == @today
796
+ @employee.reload
797
+ @employee.hire_date.should == @today
798
+ end
799
+
800
+ it "should assign ISO time string to date column" do
801
+ @employee = TestEmployee.create(
802
+ :first_name => "First",
803
+ :last_name => "Last",
804
+ :hire_date => @now_iso
805
+ )
806
+ @employee.hire_date.should == @today
807
+ @employee.reload
808
+ @employee.hire_date.should == @today
809
+ end
810
+
811
+ it "should assign NLS time string to date column" do
812
+ # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = @nls_date_format
813
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_time_format
814
+ @employee = TestEmployee.create(
815
+ :first_name => "First",
816
+ :last_name => "Last",
817
+ :hire_date => @now_nls
818
+ )
819
+ @employee.hire_date.should == @today
820
+ @employee.reload
821
+ @employee.hire_date.should == @today
822
+ end
823
+
824
+ it "should assign ISO time string to datetime column" do
825
+ @employee = TestEmployee.create(
826
+ :first_name => "First",
827
+ :last_name => "Last",
828
+ :last_login_at => @now_iso
829
+ )
830
+ @employee.last_login_at.should == @now
831
+ @employee.reload
832
+ @employee.last_login_at.should == @now
833
+ end
834
+
835
+ it "should assign NLS time string to datetime column" do
836
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_time_format
837
+ @employee = TestEmployee.create(
838
+ :first_name => "First",
839
+ :last_name => "Last",
840
+ :last_login_at => @now_nls
841
+ )
842
+ @employee.last_login_at.should == @now
843
+ @employee.reload
844
+ @employee.last_login_at.should == @now
845
+ end
846
+
847
+ it "should assign NLS time string with time zone to datetime column" do
848
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_with_tz_time_format
849
+ @employee = TestEmployee.create(
850
+ :first_name => "First",
851
+ :last_name => "Last",
852
+ :last_login_at => @now_nls_with_tz
853
+ )
854
+ @employee.last_login_at.should == @now_with_tz
855
+ @employee.reload
856
+ @employee.last_login_at.should == @now_with_tz
857
+ end
858
+
859
+ it "should assign ISO date string to datetime column" do
860
+ @employee = TestEmployee.create(
861
+ :first_name => "First",
862
+ :last_name => "Last",
863
+ :last_login_at => @today_iso
864
+ )
865
+ @employee.last_login_at.should == @today.to_time
866
+ @employee.reload
867
+ @employee.last_login_at.should == @today.to_time
868
+ end
869
+
870
+ it "should assign NLS date string to datetime column" do
871
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = @nls_date_format
872
+ # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_time_format
873
+ @employee = TestEmployee.create(
874
+ :first_name => "First",
875
+ :last_name => "Last",
876
+ :last_login_at => @today_nls
877
+ )
878
+ @employee.last_login_at.should == @today.to_time
879
+ @employee.reload
880
+ @employee.last_login_at.should == @today.to_time
881
+ end
882
+
883
+ end
884
+
885
+ describe "OracleEnhancedAdapter handling of CLOB columns" do
886
+ before(:all) do
887
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
888
+ @conn = ActiveRecord::Base.connection
889
+ @conn.execute <<-SQL
890
+ CREATE TABLE test_employees (
891
+ id NUMBER(6,0) PRIMARY KEY,
892
+ first_name VARCHAR2(20),
893
+ last_name VARCHAR2(25),
894
+ comments CLOB
895
+ )
896
+ SQL
897
+ @conn.execute <<-SQL
898
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
899
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
900
+ SQL
901
+ @conn.execute <<-SQL
902
+ CREATE TABLE test2_employees (
903
+ id NUMBER(6,0) PRIMARY KEY,
904
+ first_name VARCHAR2(20),
905
+ last_name VARCHAR2(25),
906
+ comments CLOB
907
+ )
908
+ SQL
909
+ @conn.execute <<-SQL
910
+ CREATE SEQUENCE test2_employees_seq MINVALUE 1
911
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
912
+ SQL
913
+ @char_data = (0..127).to_a.pack("C*") * 800
914
+ @char_data2 = ((1..127).to_a.pack("C*") + "\0") * 800
915
+
916
+ class ::TestEmployee < ActiveRecord::Base; end
917
+ class ::Test2Employee < ActiveRecord::Base
918
+ serialize :comments
919
+ end
920
+ class ::TestEmployeeReadOnlyClob < ActiveRecord::Base
921
+ set_table_name :test_employees
922
+ attr_readonly :comments
923
+ end
924
+ end
925
+
926
+ after(:all) do
927
+ @conn.execute "DROP TABLE test_employees"
928
+ @conn.execute "DROP SEQUENCE test_employees_seq"
929
+ @conn.execute "DROP TABLE test2_employees"
930
+ @conn.execute "DROP SEQUENCE test2_employees_seq"
931
+ Object.send(:remove_const, "TestEmployee")
932
+ Object.send(:remove_const, "Test2Employee")
933
+ Object.send(:remove_const, "TestEmployeeReadOnlyClob")
934
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
935
+ end
936
+
937
+ it "should create record without CLOB data when attribute is serialized" do
938
+ @employee = Test2Employee.create!(
939
+ :first_name => "First",
940
+ :last_name => "Last"
941
+ )
942
+ @employee.should be_valid
943
+ end
944
+
945
+ it "should accept Symbol value for CLOB column" do
946
+ @employee = TestEmployee.create!(
947
+ :comments => :test_comment
948
+ )
949
+ @employee.should be_valid
950
+ end
951
+
952
+ it "should respect attr_readonly setting for CLOB column" do
953
+ @employee = TestEmployeeReadOnlyClob.create!(
954
+ :first_name => "First",
955
+ :comments => "initial"
956
+ )
957
+ @employee.should be_valid
958
+ @employee.reload
959
+ @employee.comments.should == 'initial'
960
+ @employee.comments = "changed"
961
+ @employee.save.should == true
962
+ @employee.reload
963
+ @employee.comments.should == 'initial'
964
+ end
965
+
966
+
967
+ it "should create record with CLOB data" do
968
+ @employee = TestEmployee.create!(
969
+ :first_name => "First",
970
+ :last_name => "Last",
971
+ :comments => @char_data
972
+ )
973
+ @employee.reload
974
+ @employee.comments.should == @char_data
975
+ end
976
+
977
+ it "should update record with CLOB data" do
978
+ @employee = TestEmployee.create!(
979
+ :first_name => "First",
980
+ :last_name => "Last"
981
+ )
982
+ @employee.reload
983
+ @employee.comments.should be_nil
984
+ @employee.comments = @char_data
985
+ @employee.save!
986
+ @employee.reload
987
+ @employee.comments.should == @char_data
988
+ end
989
+
990
+ it "should update record with zero-length CLOB data" do
991
+ @employee = TestEmployee.create!(
992
+ :first_name => "First",
993
+ :last_name => "Last"
994
+ )
995
+ @employee.reload
996
+ @employee.comments.should be_nil
997
+ @employee.comments = ''
998
+ @employee.save!
999
+ @employee.reload
1000
+ @employee.comments.should == ''
1001
+ end
1002
+
1003
+ it "should update record that has existing CLOB data with different CLOB data" do
1004
+ @employee = TestEmployee.create!(
1005
+ :first_name => "First",
1006
+ :last_name => "Last",
1007
+ :comments => @char_data
1008
+ )
1009
+ @employee.reload
1010
+ @employee.comments = @char_data2
1011
+ @employee.save!
1012
+ @employee.reload
1013
+ @employee.comments.should == @char_data2
1014
+ end
1015
+
1016
+ it "should update record that has existing CLOB data with nil" do
1017
+ @employee = TestEmployee.create!(
1018
+ :first_name => "First",
1019
+ :last_name => "Last",
1020
+ :comments => @char_data
1021
+ )
1022
+ @employee.reload
1023
+ @employee.comments = nil
1024
+ @employee.save!
1025
+ @employee.reload
1026
+ @employee.comments.should be_nil
1027
+ end
1028
+
1029
+ it "should update record that has existing CLOB data with zero-length CLOB data" do
1030
+ @employee = TestEmployee.create!(
1031
+ :first_name => "First",
1032
+ :last_name => "Last",
1033
+ :comments => @char_data
1034
+ )
1035
+ @employee.reload
1036
+ @employee.comments = ''
1037
+ @employee.save!
1038
+ @employee.reload
1039
+ @employee.comments.should == ''
1040
+ end
1041
+
1042
+ it "should update record that has zero-length CLOB data with non-empty CLOB data" do
1043
+ @employee = TestEmployee.create!(
1044
+ :first_name => "First",
1045
+ :last_name => "Last",
1046
+ :comments => ''
1047
+ )
1048
+ @employee.reload
1049
+ @employee.comments.should == ''
1050
+ @employee.comments = @char_data
1051
+ @employee.save!
1052
+ @employee.reload
1053
+ @employee.comments.should == @char_data
1054
+ end
1055
+ end
1056
+
1057
+ describe "OracleEnhancedAdapter handling of BLOB columns" do
1058
+ before(:all) do
1059
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
1060
+ @conn = ActiveRecord::Base.connection
1061
+ @conn.execute <<-SQL
1062
+ CREATE TABLE test_employees (
1063
+ employee_id NUMBER(6,0) PRIMARY KEY,
1064
+ first_name VARCHAR2(20),
1065
+ last_name VARCHAR2(25),
1066
+ binary_data BLOB
1067
+ )
1068
+ SQL
1069
+ @conn.execute <<-SQL
1070
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
1071
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
1072
+ SQL
1073
+ @binary_data = "\0\1\2\3\4\5\6\7\8\9"*10000
1074
+ @binary_data2 = "\1\2\3\4\5\6\7\8\9\0"*10000
1075
+ end
1076
+
1077
+ after(:all) do
1078
+ @conn.execute "DROP TABLE test_employees"
1079
+ @conn.execute "DROP SEQUENCE test_employees_seq"
1080
+ end
1081
+
1082
+ before(:each) do
1083
+ class ::TestEmployee < ActiveRecord::Base
1084
+ if self.respond_to?(:primary_key=)
1085
+ self.primary_key = "employee_id"
1086
+ else
1087
+ set_primary_key "employee_id"
1088
+ end
1089
+ end
1090
+ end
1091
+
1092
+ after(:each) do
1093
+ Object.send(:remove_const, "TestEmployee")
1094
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
1095
+ end
1096
+
1097
+ it "should create record with BLOB data" do
1098
+ @employee = TestEmployee.create!(
1099
+ :first_name => "First",
1100
+ :last_name => "Last",
1101
+ :binary_data => @binary_data
1102
+ )
1103
+ @employee.reload
1104
+ @employee.binary_data.should == @binary_data
1105
+ end
1106
+
1107
+ it "should update record with BLOB data" do
1108
+ @employee = TestEmployee.create!(
1109
+ :first_name => "First",
1110
+ :last_name => "Last"
1111
+ )
1112
+ @employee.reload
1113
+ @employee.binary_data.should be_nil
1114
+ @employee.binary_data = @binary_data
1115
+ @employee.save!
1116
+ @employee.reload
1117
+ @employee.binary_data.should == @binary_data
1118
+ end
1119
+
1120
+ it "should update record with zero-length BLOB data" do
1121
+ @employee = TestEmployee.create!(
1122
+ :first_name => "First",
1123
+ :last_name => "Last"
1124
+ )
1125
+ @employee.reload
1126
+ @employee.binary_data.should be_nil
1127
+ @employee.binary_data = ''
1128
+ @employee.save!
1129
+ @employee.reload
1130
+ @employee.binary_data.should == ''
1131
+ end
1132
+
1133
+ it "should update record that has existing BLOB data with different BLOB data" do
1134
+ @employee = TestEmployee.create!(
1135
+ :first_name => "First",
1136
+ :last_name => "Last",
1137
+ :binary_data => @binary_data
1138
+ )
1139
+ @employee.reload
1140
+ @employee.binary_data = @binary_data2
1141
+ @employee.save!
1142
+ @employee.reload
1143
+ @employee.binary_data.should == @binary_data2
1144
+ end
1145
+
1146
+ it "should update record that has existing BLOB data with nil" do
1147
+ @employee = TestEmployee.create!(
1148
+ :first_name => "First",
1149
+ :last_name => "Last",
1150
+ :binary_data => @binary_data
1151
+ )
1152
+ @employee.reload
1153
+ @employee.binary_data = nil
1154
+ @employee.save!
1155
+ @employee.reload
1156
+ @employee.binary_data.should be_nil
1157
+ end
1158
+
1159
+ it "should update record that has existing BLOB data with zero-length BLOB data" do
1160
+ @employee = TestEmployee.create!(
1161
+ :first_name => "First",
1162
+ :last_name => "Last",
1163
+ :binary_data => @binary_data
1164
+ )
1165
+ @employee.reload
1166
+ @employee.binary_data = ''
1167
+ @employee.save!
1168
+ @employee.reload
1169
+ @employee.binary_data.should == ''
1170
+ end
1171
+
1172
+ it "should update record that has zero-length BLOB data with non-empty BLOB data" do
1173
+ @employee = TestEmployee.create!(
1174
+ :first_name => "First",
1175
+ :last_name => "Last",
1176
+ :binary_data => ''
1177
+ )
1178
+ @employee.reload
1179
+ @employee.binary_data.should == ''
1180
+ @employee.binary_data = @binary_data
1181
+ @employee.save!
1182
+ @employee.reload
1183
+ @employee.binary_data.should == @binary_data
1184
+ end
1185
+ end
1186
+
1187
+ describe "OracleEnhancedAdapter handling of RAW columns" do
1188
+ before(:all) do
1189
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
1190
+ @conn = ActiveRecord::Base.connection
1191
+ @conn.execute <<-SQL
1192
+ CREATE TABLE test_employees (
1193
+ employee_id NUMBER(6,0) PRIMARY KEY,
1194
+ first_name VARCHAR2(20),
1195
+ last_name VARCHAR2(25),
1196
+ binary_data RAW(1024)
1197
+ )
1198
+ SQL
1199
+ @conn.execute <<-SQL
1200
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
1201
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
1202
+ SQL
1203
+ @binary_data = "\0\1\2\3\4\5\6\7\8\9"*100
1204
+ @binary_data2 = "\1\2\3\4\5\6\7\8\9\0"*100
1205
+ end
1206
+
1207
+ after(:all) do
1208
+ @conn.execute "DROP TABLE test_employees"
1209
+ @conn.execute "DROP SEQUENCE test_employees_seq"
1210
+ end
1211
+
1212
+ before(:each) do
1213
+ class ::TestEmployee < ActiveRecord::Base
1214
+ if self.respond_to?(:primary_key=)
1215
+ self.primary_key = "employee_id"
1216
+ else
1217
+ set_primary_key "employee_id"
1218
+ end
1219
+ end
1220
+ end
1221
+
1222
+ after(:each) do
1223
+ Object.send(:remove_const, "TestEmployee")
1224
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
1225
+ end
1226
+
1227
+ it "should create record with RAW data" do
1228
+ @employee = TestEmployee.create!(
1229
+ :first_name => "First",
1230
+ :last_name => "Last",
1231
+ :binary_data => @binary_data
1232
+ )
1233
+ @employee.reload
1234
+ @employee.binary_data.should == @binary_data
1235
+ end
1236
+
1237
+ it "should update record with RAW data" do
1238
+ @employee = TestEmployee.create!(
1239
+ :first_name => "First",
1240
+ :last_name => "Last"
1241
+ )
1242
+ @employee.reload
1243
+ @employee.binary_data.should be_nil
1244
+ @employee.binary_data = @binary_data
1245
+ @employee.save!
1246
+ @employee.reload
1247
+ @employee.binary_data.should == @binary_data
1248
+ end
1249
+
1250
+ it "should update record with zero-length RAW data" do
1251
+ @employee = TestEmployee.create!(
1252
+ :first_name => "First",
1253
+ :last_name => "Last"
1254
+ )
1255
+ @employee.reload
1256
+ @employee.binary_data.should be_nil
1257
+ @employee.binary_data = ''
1258
+ @employee.save!
1259
+ @employee.reload
1260
+ @employee.binary_data.should.nil?
1261
+ end
1262
+
1263
+ it "should update record that has existing RAW data with different RAW data" do
1264
+ @employee = TestEmployee.create!(
1265
+ :first_name => "First",
1266
+ :last_name => "Last",
1267
+ :binary_data => @binary_data
1268
+ )
1269
+ @employee.reload
1270
+ @employee.binary_data = @binary_data2
1271
+ @employee.save!
1272
+ @employee.reload
1273
+ @employee.binary_data.should == @binary_data2
1274
+ end
1275
+
1276
+ it "should update record that has existing RAW data with nil" do
1277
+ @employee = TestEmployee.create!(
1278
+ :first_name => "First",
1279
+ :last_name => "Last",
1280
+ :binary_data => @binary_data
1281
+ )
1282
+ @employee.reload
1283
+ @employee.binary_data = nil
1284
+ @employee.save!
1285
+ @employee.reload
1286
+ @employee.binary_data.should be_nil
1287
+ end
1288
+
1289
+ it "should update record that has existing RAW data with zero-length RAW data" do
1290
+ @employee = TestEmployee.create!(
1291
+ :first_name => "First",
1292
+ :last_name => "Last",
1293
+ :binary_data => @binary_data
1294
+ )
1295
+ @employee.reload
1296
+ @employee.binary_data = ''
1297
+ @employee.save!
1298
+ @employee.reload
1299
+ @employee.binary_data.should.nil?
1300
+ end
1301
+
1302
+ it "should update record that has zero-length BLOB data with non-empty RAW data" do
1303
+ @employee = TestEmployee.create!(
1304
+ :first_name => "First",
1305
+ :last_name => "Last",
1306
+ :binary_data => ''
1307
+ )
1308
+ @employee.reload
1309
+ @employee.binary_data = @binary_data
1310
+ @employee.save!
1311
+ @employee.reload
1312
+ @employee.binary_data.should == @binary_data
1313
+ end
1314
+ end
1315
+
1316
+
1317
+ describe "OracleEnhancedAdapter quoting of NCHAR and NVARCHAR2 columns" do
1318
+ before(:all) do
1319
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
1320
+ @conn = ActiveRecord::Base.connection
1321
+ @conn.execute <<-SQL
1322
+ CREATE TABLE test_items (
1323
+ id NUMBER(6,0) PRIMARY KEY,
1324
+ nchar_column NCHAR(20),
1325
+ nvarchar2_column NVARCHAR2(20),
1326
+ char_column CHAR(20),
1327
+ varchar2_column VARCHAR2(20)
1328
+ )
1329
+ SQL
1330
+ @conn.execute "CREATE SEQUENCE test_items_seq"
1331
+ end
1332
+
1333
+ after(:all) do
1334
+ @conn.execute "DROP TABLE test_items"
1335
+ @conn.execute "DROP SEQUENCE test_items_seq"
1336
+ end
1337
+
1338
+ before(:each) do
1339
+ class ::TestItem < ActiveRecord::Base
1340
+ end
1341
+ end
1342
+
1343
+ after(:each) do
1344
+ Object.send(:remove_const, "TestItem")
1345
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
1346
+ end
1347
+
1348
+ it "should set nchar instance variable" do
1349
+ columns = @conn.columns('test_items')
1350
+ %w(nchar_column nvarchar2_column char_column varchar2_column).each do |col|
1351
+ column = columns.detect{|c| c.name == col}
1352
+ column.type.should == :string
1353
+ column.nchar.should == (col[0,1] == 'n' ? true : nil)
1354
+ end
1355
+ end
1356
+
1357
+ it "should quote with N prefix" do
1358
+ columns = @conn.columns('test_items')
1359
+ %w(nchar_column nvarchar2_column char_column varchar2_column).each do |col|
1360
+ column = columns.detect{|c| c.name == col}
1361
+ @conn.quote('abc', column).should == (column.nchar ? "N'abc'" : "'abc'")
1362
+ @conn.quote(nil, column).should == 'NULL'
1363
+ end
1364
+ end
1365
+
1366
+ it "should create record" do
1367
+ nchar_data = 'āčē'
1368
+ item = TestItem.create(
1369
+ :nchar_column => nchar_data,
1370
+ :nvarchar2_column => nchar_data
1371
+ ).reload
1372
+ item.nchar_column.should == nchar_data + ' '*17
1373
+ item.nvarchar2_column.should == nchar_data
1374
+ end
1375
+
1376
+ end