activerecord-oracle_enhanced-adapter-with-schema 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +52 -0
  3. data/History.md +301 -0
  4. data/License.txt +20 -0
  5. data/README.md +123 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +59 -0
  8. data/VERSION +1 -0
  9. data/activerecord-oracle_enhanced-adapter-with-schema.gemspec +130 -0
  10. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1399 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +121 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +146 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +119 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +359 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +46 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +565 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +494 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +227 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +260 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +428 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +258 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +294 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  30. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  31. data/lib/activerecord-oracle_enhanced-adapter-with-schema.rb +25 -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 +1388 -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 +440 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1385 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +339 -0
  45. data/spec/spec_helper.rb +189 -0
  46. metadata +260 -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,1388 @@
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
+
1056
+ it "should keep unchanged serialized data when other columns changed" do
1057
+ @employee = Test2Employee.create!(
1058
+ :first_name => "First",
1059
+ :last_name => "Last",
1060
+ :comments => "initial serialized data"
1061
+ )
1062
+ @employee.first_name = "Steve"
1063
+ @employee.save
1064
+ @employee.reload
1065
+ @employee.comments.should == "initial serialized data"
1066
+ end
1067
+ end
1068
+
1069
+ describe "OracleEnhancedAdapter handling of BLOB columns" do
1070
+ before(:all) do
1071
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
1072
+ @conn = ActiveRecord::Base.connection
1073
+ @conn.execute <<-SQL
1074
+ CREATE TABLE test_employees (
1075
+ employee_id NUMBER(6,0) PRIMARY KEY,
1076
+ first_name VARCHAR2(20),
1077
+ last_name VARCHAR2(25),
1078
+ binary_data BLOB
1079
+ )
1080
+ SQL
1081
+ @conn.execute <<-SQL
1082
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
1083
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
1084
+ SQL
1085
+ @binary_data = "\0\1\2\3\4\5\6\7\8\9"*10000
1086
+ @binary_data2 = "\1\2\3\4\5\6\7\8\9\0"*10000
1087
+ end
1088
+
1089
+ after(:all) do
1090
+ @conn.execute "DROP TABLE test_employees"
1091
+ @conn.execute "DROP SEQUENCE test_employees_seq"
1092
+ end
1093
+
1094
+ before(:each) do
1095
+ class ::TestEmployee < ActiveRecord::Base
1096
+ if self.respond_to?(:primary_key=)
1097
+ self.primary_key = "employee_id"
1098
+ else
1099
+ set_primary_key "employee_id"
1100
+ end
1101
+ end
1102
+ end
1103
+
1104
+ after(:each) do
1105
+ Object.send(:remove_const, "TestEmployee")
1106
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
1107
+ end
1108
+
1109
+ it "should create record with BLOB data" do
1110
+ @employee = TestEmployee.create!(
1111
+ :first_name => "First",
1112
+ :last_name => "Last",
1113
+ :binary_data => @binary_data
1114
+ )
1115
+ @employee.reload
1116
+ @employee.binary_data.should == @binary_data
1117
+ end
1118
+
1119
+ it "should update record with BLOB data" do
1120
+ @employee = TestEmployee.create!(
1121
+ :first_name => "First",
1122
+ :last_name => "Last"
1123
+ )
1124
+ @employee.reload
1125
+ @employee.binary_data.should be_nil
1126
+ @employee.binary_data = @binary_data
1127
+ @employee.save!
1128
+ @employee.reload
1129
+ @employee.binary_data.should == @binary_data
1130
+ end
1131
+
1132
+ it "should update record with zero-length BLOB data" do
1133
+ @employee = TestEmployee.create!(
1134
+ :first_name => "First",
1135
+ :last_name => "Last"
1136
+ )
1137
+ @employee.reload
1138
+ @employee.binary_data.should be_nil
1139
+ @employee.binary_data = ''
1140
+ @employee.save!
1141
+ @employee.reload
1142
+ @employee.binary_data.should == ''
1143
+ end
1144
+
1145
+ it "should update record that has existing BLOB data with different BLOB data" do
1146
+ @employee = TestEmployee.create!(
1147
+ :first_name => "First",
1148
+ :last_name => "Last",
1149
+ :binary_data => @binary_data
1150
+ )
1151
+ @employee.reload
1152
+ @employee.binary_data = @binary_data2
1153
+ @employee.save!
1154
+ @employee.reload
1155
+ @employee.binary_data.should == @binary_data2
1156
+ end
1157
+
1158
+ it "should update record that has existing BLOB data with nil" do
1159
+ @employee = TestEmployee.create!(
1160
+ :first_name => "First",
1161
+ :last_name => "Last",
1162
+ :binary_data => @binary_data
1163
+ )
1164
+ @employee.reload
1165
+ @employee.binary_data = nil
1166
+ @employee.save!
1167
+ @employee.reload
1168
+ @employee.binary_data.should be_nil
1169
+ end
1170
+
1171
+ it "should update record that has existing BLOB data with zero-length BLOB data" do
1172
+ @employee = TestEmployee.create!(
1173
+ :first_name => "First",
1174
+ :last_name => "Last",
1175
+ :binary_data => @binary_data
1176
+ )
1177
+ @employee.reload
1178
+ @employee.binary_data = ''
1179
+ @employee.save!
1180
+ @employee.reload
1181
+ @employee.binary_data.should == ''
1182
+ end
1183
+
1184
+ it "should update record that has zero-length BLOB data with non-empty BLOB data" do
1185
+ @employee = TestEmployee.create!(
1186
+ :first_name => "First",
1187
+ :last_name => "Last",
1188
+ :binary_data => ''
1189
+ )
1190
+ @employee.reload
1191
+ @employee.binary_data.should == ''
1192
+ @employee.binary_data = @binary_data
1193
+ @employee.save!
1194
+ @employee.reload
1195
+ @employee.binary_data.should == @binary_data
1196
+ end
1197
+ end
1198
+
1199
+ describe "OracleEnhancedAdapter handling of RAW columns" do
1200
+ before(:all) do
1201
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
1202
+ @conn = ActiveRecord::Base.connection
1203
+ @conn.execute <<-SQL
1204
+ CREATE TABLE test_employees (
1205
+ employee_id NUMBER(6,0) PRIMARY KEY,
1206
+ first_name VARCHAR2(20),
1207
+ last_name VARCHAR2(25),
1208
+ binary_data RAW(1024)
1209
+ )
1210
+ SQL
1211
+ @conn.execute <<-SQL
1212
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
1213
+ INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
1214
+ SQL
1215
+ @binary_data = "\0\1\2\3\4\5\6\7\8\9"*100
1216
+ @binary_data2 = "\1\2\3\4\5\6\7\8\9\0"*100
1217
+ end
1218
+
1219
+ after(:all) do
1220
+ @conn.execute "DROP TABLE test_employees"
1221
+ @conn.execute "DROP SEQUENCE test_employees_seq"
1222
+ end
1223
+
1224
+ before(:each) do
1225
+ class ::TestEmployee < ActiveRecord::Base
1226
+ if self.respond_to?(:primary_key=)
1227
+ self.primary_key = "employee_id"
1228
+ else
1229
+ set_primary_key "employee_id"
1230
+ end
1231
+ end
1232
+ end
1233
+
1234
+ after(:each) do
1235
+ Object.send(:remove_const, "TestEmployee")
1236
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
1237
+ end
1238
+
1239
+ it "should create record with RAW data" do
1240
+ @employee = TestEmployee.create!(
1241
+ :first_name => "First",
1242
+ :last_name => "Last",
1243
+ :binary_data => @binary_data
1244
+ )
1245
+ @employee.reload
1246
+ @employee.binary_data.should == @binary_data
1247
+ end
1248
+
1249
+ it "should update record with RAW data" do
1250
+ @employee = TestEmployee.create!(
1251
+ :first_name => "First",
1252
+ :last_name => "Last"
1253
+ )
1254
+ @employee.reload
1255
+ @employee.binary_data.should be_nil
1256
+ @employee.binary_data = @binary_data
1257
+ @employee.save!
1258
+ @employee.reload
1259
+ @employee.binary_data.should == @binary_data
1260
+ end
1261
+
1262
+ it "should update record with zero-length RAW data" do
1263
+ @employee = TestEmployee.create!(
1264
+ :first_name => "First",
1265
+ :last_name => "Last"
1266
+ )
1267
+ @employee.reload
1268
+ @employee.binary_data.should be_nil
1269
+ @employee.binary_data = ''
1270
+ @employee.save!
1271
+ @employee.reload
1272
+ @employee.binary_data.should.nil?
1273
+ end
1274
+
1275
+ it "should update record that has existing RAW data with different RAW data" do
1276
+ @employee = TestEmployee.create!(
1277
+ :first_name => "First",
1278
+ :last_name => "Last",
1279
+ :binary_data => @binary_data
1280
+ )
1281
+ @employee.reload
1282
+ @employee.binary_data = @binary_data2
1283
+ @employee.save!
1284
+ @employee.reload
1285
+ @employee.binary_data.should == @binary_data2
1286
+ end
1287
+
1288
+ it "should update record that has existing RAW data with nil" do
1289
+ @employee = TestEmployee.create!(
1290
+ :first_name => "First",
1291
+ :last_name => "Last",
1292
+ :binary_data => @binary_data
1293
+ )
1294
+ @employee.reload
1295
+ @employee.binary_data = nil
1296
+ @employee.save!
1297
+ @employee.reload
1298
+ @employee.binary_data.should be_nil
1299
+ end
1300
+
1301
+ it "should update record that has existing RAW data with zero-length RAW data" do
1302
+ @employee = TestEmployee.create!(
1303
+ :first_name => "First",
1304
+ :last_name => "Last",
1305
+ :binary_data => @binary_data
1306
+ )
1307
+ @employee.reload
1308
+ @employee.binary_data = ''
1309
+ @employee.save!
1310
+ @employee.reload
1311
+ @employee.binary_data.should.nil?
1312
+ end
1313
+
1314
+ it "should update record that has zero-length BLOB data with non-empty RAW data" do
1315
+ @employee = TestEmployee.create!(
1316
+ :first_name => "First",
1317
+ :last_name => "Last",
1318
+ :binary_data => ''
1319
+ )
1320
+ @employee.reload
1321
+ @employee.binary_data = @binary_data
1322
+ @employee.save!
1323
+ @employee.reload
1324
+ @employee.binary_data.should == @binary_data
1325
+ end
1326
+ end
1327
+
1328
+
1329
+ describe "OracleEnhancedAdapter quoting of NCHAR and NVARCHAR2 columns" do
1330
+ before(:all) do
1331
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
1332
+ @conn = ActiveRecord::Base.connection
1333
+ @conn.execute <<-SQL
1334
+ CREATE TABLE test_items (
1335
+ id NUMBER(6,0) PRIMARY KEY,
1336
+ nchar_column NCHAR(20),
1337
+ nvarchar2_column NVARCHAR2(20),
1338
+ char_column CHAR(20),
1339
+ varchar2_column VARCHAR2(20)
1340
+ )
1341
+ SQL
1342
+ @conn.execute "CREATE SEQUENCE test_items_seq"
1343
+ end
1344
+
1345
+ after(:all) do
1346
+ @conn.execute "DROP TABLE test_items"
1347
+ @conn.execute "DROP SEQUENCE test_items_seq"
1348
+ end
1349
+
1350
+ before(:each) do
1351
+ class ::TestItem < ActiveRecord::Base
1352
+ end
1353
+ end
1354
+
1355
+ after(:each) do
1356
+ Object.send(:remove_const, "TestItem")
1357
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
1358
+ end
1359
+
1360
+ it "should set nchar instance variable" do
1361
+ columns = @conn.columns('test_items')
1362
+ %w(nchar_column nvarchar2_column char_column varchar2_column).each do |col|
1363
+ column = columns.detect{|c| c.name == col}
1364
+ column.type.should == :string
1365
+ column.nchar.should == (col[0,1] == 'n' ? true : nil)
1366
+ end
1367
+ end
1368
+
1369
+ it "should quote with N prefix" do
1370
+ columns = @conn.columns('test_items')
1371
+ %w(nchar_column nvarchar2_column char_column varchar2_column).each do |col|
1372
+ column = columns.detect{|c| c.name == col}
1373
+ @conn.quote('abc', column).should == (column.nchar ? "N'abc'" : "'abc'")
1374
+ @conn.quote(nil, column).should == 'NULL'
1375
+ end
1376
+ end
1377
+
1378
+ it "should create record" do
1379
+ nchar_data = 'āčē'
1380
+ item = TestItem.create(
1381
+ :nchar_column => nchar_data,
1382
+ :nvarchar2_column => nchar_data
1383
+ ).reload
1384
+ item.nchar_column.should == nchar_data + ' '*17
1385
+ item.nvarchar2_column.should == nchar_data
1386
+ end
1387
+
1388
+ end