ctreatma-activerecord-oracle_enhanced-adapter 1.4.1.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 (47) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +51 -0
  3. data/History.md +269 -0
  4. data/License.txt +20 -0
  5. data/README.md +378 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +46 -0
  8. data/VERSION +1 -0
  9. data/activerecord-oracle_enhanced-adapter.gemspec +130 -0
  10. data/ctreatma-activerecord-oracle_enhanced-adapter.gemspec +129 -0
  11. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1390 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +106 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +136 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +119 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +328 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +553 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +492 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +213 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +252 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +373 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +265 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +290 -0
  30. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  31. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  32. data/lib/activerecord-oracle_enhanced-adapter.rb +25 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +749 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +310 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +426 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1330 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +121 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +374 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +380 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1112 -0
  45. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +323 -0
  46. data/spec/spec_helper.rb +185 -0
  47. metadata +287 -0
@@ -0,0 +1,17 @@
1
+ # Used just for Rails 2.x
2
+ # In Rails 3.x rake tasks are loaded using railtie
3
+ if ActiveRecord::VERSION::MAJOR == 2
4
+
5
+ if defined?(Rake.application) && Rake.application &&
6
+ ActiveRecord::Base.configurations[defined?(Rails.env) ? Rails.env : RAILS_ENV]['adapter'] == 'oracle_enhanced'
7
+ oracle_enhanced_rakefile = File.dirname(__FILE__) + "/oracle_enhanced.rake"
8
+ if Rake.application.lookup("environment")
9
+ # rails tasks already defined; load the override tasks now
10
+ load oracle_enhanced_rakefile
11
+ else
12
+ # rails tasks not loaded yet; load as an import
13
+ Rake.application.add_import(oracle_enhanced_rakefile)
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1 @@
1
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter::VERSION = File.read(File.dirname(__FILE__)+'/../../../VERSION').chomp
@@ -0,0 +1,25 @@
1
+ # define railtie which will be executed in Rails 3
2
+ if defined?(::Rails::Railtie)
3
+
4
+ module ActiveRecord
5
+ module ConnectionAdapters
6
+ class OracleEnhancedRailtie < ::Rails::Railtie
7
+ rake_tasks do
8
+ load 'active_record/connection_adapters/oracle_enhanced.rake'
9
+ end
10
+
11
+ ActiveSupport.on_load(:active_record) do
12
+ require 'active_record/connection_adapters/oracle_enhanced_adapter'
13
+
14
+ # Cache column descriptions between requests in test and production environments
15
+ if Rails.env.test? || Rails.env.production?
16
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = true
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,749 @@
1
+ require 'spec_helper'
2
+
3
+ describe "OracleEnhancedAdapter establish connection" do
4
+
5
+ it "should connect to database" do
6
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
7
+ ActiveRecord::Base.connection.should_not be_nil
8
+ ActiveRecord::Base.connection.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
9
+ end
10
+
11
+ it "should connect to database as SYSDBA" do
12
+ ActiveRecord::Base.establish_connection(SYS_CONNECTION_PARAMS)
13
+ ActiveRecord::Base.connection.should_not be_nil
14
+ ActiveRecord::Base.connection.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
15
+ end
16
+
17
+ it "should be active after connection to database" do
18
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
19
+ ActiveRecord::Base.connection.should be_active
20
+ end
21
+
22
+ it "should not be active after disconnection to database" do
23
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
24
+ ActiveRecord::Base.connection.disconnect!
25
+ ActiveRecord::Base.connection.should_not be_active
26
+ end
27
+
28
+ it "should be active after reconnection to database" do
29
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
30
+ ActiveRecord::Base.connection.reconnect!
31
+ ActiveRecord::Base.connection.should be_active
32
+ end
33
+
34
+ end
35
+
36
+ describe "OracleEnhancedAdapter" do
37
+ include LoggerSpecHelper
38
+ include SchemaSpecHelper
39
+
40
+ before(:all) do
41
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
42
+ end
43
+
44
+ describe "database session store" do
45
+ before(:all) do
46
+ @conn.execute "DROP TABLE sessions" rescue nil
47
+ @conn.execute "DROP SEQUENCE sessions_seq" rescue nil
48
+ @conn = ActiveRecord::Base.connection
49
+ @conn.execute <<-SQL
50
+ CREATE TABLE sessions (
51
+ id NUMBER(38,0) NOT NULL,
52
+ session_id VARCHAR2(255) DEFAULT NULL,
53
+ data CLOB DEFAULT NULL,
54
+ created_at DATE DEFAULT NULL,
55
+ updated_at DATE DEFAULT NULL,
56
+ PRIMARY KEY (ID)
57
+ )
58
+ SQL
59
+ @conn.execute <<-SQL
60
+ CREATE SEQUENCE sessions_seq MINVALUE 1 MAXVALUE 999999999999999999999999999
61
+ INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
62
+ SQL
63
+ if ENV['RAILS_GEM_VERSION'] >= '2.3'
64
+ @session_class = ActiveRecord::SessionStore::Session
65
+ else
66
+ @session_class = CGI::Session::ActiveRecordStore::Session
67
+ end
68
+ end
69
+
70
+ after(:all) do
71
+ @conn.execute "DROP TABLE sessions"
72
+ @conn.execute "DROP SEQUENCE sessions_seq"
73
+ end
74
+
75
+ it "should create sessions table" do
76
+ ActiveRecord::Base.connection.tables.grep("sessions").should_not be_empty
77
+ end
78
+
79
+ it "should save session data" do
80
+ @session = @session_class.new :session_id => "111111", :data => "something" #, :updated_at => Time.now
81
+ @session.save!
82
+ @session = @session_class.find_by_session_id("111111")
83
+ @session.data.should == "something"
84
+ end
85
+
86
+ it "should change session data when partial updates enabled" do
87
+ return pending("Not in this ActiveRecord version") unless @session_class.respond_to?(:partial_updates=)
88
+ @session_class.partial_updates = true
89
+ @session = @session_class.new :session_id => "222222", :data => "something" #, :updated_at => Time.now
90
+ @session.save!
91
+ @session = @session_class.find_by_session_id("222222")
92
+ @session.data = "other thing"
93
+ @session.save!
94
+ # second save should call again blob writing callback
95
+ @session.save!
96
+ @session = @session_class.find_by_session_id("222222")
97
+ @session.data.should == "other thing"
98
+ end
99
+
100
+ it "should have one enhanced_write_lobs callback" do
101
+ return pending("Not in this ActiveRecord version") unless @session_class.respond_to?(:after_save_callback_chain)
102
+ @session_class.after_save_callback_chain.select{|cb| cb.method == :enhanced_write_lobs}.should have(1).record
103
+ end
104
+
105
+ it "should not set sessions table session_id column type as integer if emulate_integers_by_column_name is true" do
106
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
107
+ columns = @conn.columns('sessions')
108
+ column = columns.detect{|c| c.name == "session_id"}
109
+ column.type.should == :string
110
+ end
111
+
112
+ end
113
+
114
+ describe "ignore specified table columns" do
115
+ before(:all) do
116
+ @conn = ActiveRecord::Base.connection
117
+ @conn.execute "DROP TABLE test_employees" rescue nil
118
+ @conn.execute <<-SQL
119
+ CREATE TABLE test_employees (
120
+ id NUMBER PRIMARY KEY,
121
+ first_name VARCHAR2(20),
122
+ last_name VARCHAR2(25),
123
+ email VARCHAR2(25),
124
+ phone_number VARCHAR2(20),
125
+ hire_date DATE,
126
+ job_id NUMBER,
127
+ salary NUMBER,
128
+ commission_pct NUMBER(2,2),
129
+ manager_id NUMBER(6),
130
+ department_id NUMBER(4,0),
131
+ created_at DATE
132
+ )
133
+ SQL
134
+ @conn.execute "DROP SEQUENCE test_employees_seq" rescue nil
135
+ @conn.execute <<-SQL
136
+ CREATE SEQUENCE test_employees_seq MINVALUE 1
137
+ INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE
138
+ SQL
139
+ end
140
+
141
+ after(:all) do
142
+ @conn.execute "DROP TABLE test_employees"
143
+ @conn.execute "DROP SEQUENCE test_employees_seq"
144
+ end
145
+
146
+ after(:each) do
147
+ Object.send(:remove_const, "TestEmployee")
148
+ ActiveRecord::Base.connection.clear_ignored_table_columns
149
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
150
+ end
151
+
152
+ it "should ignore specified table columns" do
153
+ class ::TestEmployee < ActiveRecord::Base
154
+ ignore_table_columns :phone_number, :hire_date
155
+ end
156
+ TestEmployee.connection.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
157
+ end
158
+
159
+ it "should ignore specified table columns specified in several lines" do
160
+ class ::TestEmployee < ActiveRecord::Base
161
+ ignore_table_columns :phone_number
162
+ ignore_table_columns :hire_date
163
+ end
164
+ TestEmployee.connection.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
165
+ end
166
+
167
+ it "should not ignore unspecified table columns" do
168
+ class ::TestEmployee < ActiveRecord::Base
169
+ ignore_table_columns :phone_number, :hire_date
170
+ end
171
+ TestEmployee.connection.columns('test_employees').select{|c| c.name == 'email' }.should_not be_empty
172
+ end
173
+
174
+ it "should ignore specified table columns in other connection" do
175
+ class ::TestEmployee < ActiveRecord::Base
176
+ ignore_table_columns :phone_number, :hire_date
177
+ end
178
+ # establish other connection
179
+ other_conn = ActiveRecord::Base.oracle_enhanced_connection(CONNECTION_PARAMS)
180
+ other_conn.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
181
+ end
182
+
183
+ end
184
+
185
+ describe "cache table columns" do
186
+ before(:all) do
187
+ @conn = ActiveRecord::Base.connection
188
+ @conn.execute "DROP TABLE test_employees" rescue nil
189
+ @oracle11g = !! @conn.select_value("SELECT * FROM v$version WHERE banner LIKE 'Oracle%11g%'")
190
+ @conn.execute <<-SQL
191
+ CREATE TABLE test_employees (
192
+ id NUMBER PRIMARY KEY,
193
+ first_name VARCHAR2(20),
194
+ last_name VARCHAR2(25),
195
+ #{ @oracle11g ? "full_name AS (first_name || ' ' || last_name)," : "full_name VARCHAR2(46),"}
196
+ hire_date DATE
197
+ )
198
+ SQL
199
+ @conn.execute <<-SQL
200
+ CREATE TABLE test_employees_without_pk (
201
+ first_name VARCHAR2(20),
202
+ last_name VARCHAR2(25),
203
+ hire_date DATE
204
+ )
205
+ SQL
206
+ @column_names = ['id', 'first_name', 'last_name', 'full_name', 'hire_date']
207
+ @column_sql_types = ["NUMBER", "VARCHAR2(20)", "VARCHAR2(25)", "VARCHAR2(46)", "DATE"]
208
+ class ::TestEmployee < ActiveRecord::Base
209
+ end
210
+ # Another class using the same table
211
+ class ::TestEmployee2 < ActiveRecord::Base
212
+ set_table_name "test_employees"
213
+ end
214
+ end
215
+
216
+ after(:all) do
217
+ @conn = ActiveRecord::Base.connection
218
+ Object.send(:remove_const, "TestEmployee")
219
+ Object.send(:remove_const, "TestEmployee2")
220
+ @conn.execute "DROP TABLE test_employees"
221
+ @conn.execute "DROP TABLE test_employees_without_pk"
222
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = nil
223
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
224
+ end
225
+
226
+ before(:each) do
227
+ set_logger
228
+ @conn = ActiveRecord::Base.connection
229
+ @conn.clear_columns_cache
230
+ end
231
+
232
+ after(:each) do
233
+ clear_logger
234
+ end
235
+
236
+ describe "without column caching" do
237
+
238
+ before(:each) do
239
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = false
240
+ end
241
+
242
+ it 'should identify virtual columns as such' do
243
+ pending "Not supported in this database version" unless @oracle11g
244
+ te = TestEmployee.connection.columns('test_employees').detect(&:virtual?)
245
+ te.name.should == 'full_name'
246
+ end
247
+
248
+ it "should get columns from database at first time" do
249
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
250
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
251
+ end
252
+
253
+ it "should get columns from database at second time" do
254
+ TestEmployee.connection.columns('test_employees')
255
+ @logger.clear(:debug)
256
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
257
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
258
+ end
259
+
260
+ it "should get primary key from database at first time" do
261
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
262
+ @logger.logged(:debug).last.should =~ /select .* from all_constraints/im
263
+ end
264
+
265
+ it "should get primary key from database at first time" do
266
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
267
+ @logger.clear(:debug)
268
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
269
+ @logger.logged(:debug).last.should =~ /select .* from all_constraints/im
270
+ end
271
+
272
+ it "should have correct sql types when 2 models are using the same table and AR query cache is enabled" do
273
+ @conn.cache do
274
+ TestEmployee.columns.map(&:sql_type).should == @column_sql_types
275
+ TestEmployee2.columns.map(&:sql_type).should == @column_sql_types
276
+ end
277
+ end
278
+
279
+ end
280
+
281
+ describe "with column caching" do
282
+
283
+ before(:each) do
284
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = true
285
+ end
286
+
287
+ it "should get columns from database at first time" do
288
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
289
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
290
+ end
291
+
292
+ it "should get columns from cache at second time" do
293
+ TestEmployee.connection.columns('test_employees')
294
+ @logger.clear(:debug)
295
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
296
+ @logger.logged(:debug).last.should be_blank
297
+ end
298
+
299
+ it "should get primary key from database at first time" do
300
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
301
+ @logger.logged(:debug).last.should =~ /select .* from all_constraints/im
302
+ end
303
+
304
+ it "should get primary key from cache at first time" do
305
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
306
+ @logger.clear(:debug)
307
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
308
+ @logger.logged(:debug).last.should be_blank
309
+ end
310
+
311
+ it "should store primary key as nil in cache at first time for table without primary key" do
312
+ TestEmployee.connection.pk_and_sequence_for('test_employees_without_pk').should == nil
313
+ @logger.clear(:debug)
314
+ TestEmployee.connection.pk_and_sequence_for('test_employees_without_pk').should == nil
315
+ @logger.logged(:debug).last.should be_blank
316
+ end
317
+
318
+ end
319
+
320
+ end
321
+
322
+ describe "without composite_primary_keys" do
323
+
324
+ before(:all) do
325
+ @conn = ActiveRecord::Base.connection
326
+ @conn.execute "DROP TABLE test_employees" rescue nil
327
+ @conn.execute <<-SQL
328
+ CREATE TABLE test_employees (
329
+ employee_id NUMBER PRIMARY KEY,
330
+ name VARCHAR2(50)
331
+ )
332
+ SQL
333
+ Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
334
+ class ::TestEmployee < ActiveRecord::Base
335
+ set_primary_key :employee_id
336
+ end
337
+ end
338
+
339
+ after(:all) do
340
+ Object.send(:remove_const, "TestEmployee")
341
+ @conn.execute "DROP TABLE test_employees"
342
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
343
+ end
344
+
345
+ it "should tell ActiveRecord that count distinct is supported" do
346
+ ActiveRecord::Base.connection.supports_count_distinct?.should be_true
347
+ end
348
+
349
+ it "should execute correct SQL COUNT DISTINCT statement" do
350
+ lambda { TestEmployee.count(:employee_id, :distinct => true) }.should_not raise_error
351
+ end
352
+
353
+ end
354
+
355
+
356
+ describe "reserved words column quoting" do
357
+
358
+ before(:all) do
359
+ schema_define do
360
+ create_table :test_reserved_words do |t|
361
+ t.string :varchar2
362
+ t.integer :integer
363
+ t.text :comment
364
+ end
365
+ end
366
+ class ::TestReservedWord < ActiveRecord::Base; end
367
+ end
368
+
369
+ after(:all) do
370
+ schema_define do
371
+ drop_table :test_reserved_words
372
+ end
373
+ Object.send(:remove_const, "TestReservedWord")
374
+ ActiveRecord::Base.table_name_prefix = nil
375
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
376
+ end
377
+
378
+ before(:each) do
379
+ set_logger
380
+ end
381
+
382
+ after(:each) do
383
+ clear_logger
384
+ end
385
+
386
+ it "should create table" do
387
+ [:varchar2, :integer, :comment].each do |attr|
388
+ TestReservedWord.columns_hash[attr.to_s].name.should == attr.to_s
389
+ end
390
+ end
391
+
392
+ it "should create record" do
393
+ attrs = {
394
+ :varchar2 => 'dummy',
395
+ :integer => 1,
396
+ :comment => 'dummy'
397
+ }
398
+ record = TestReservedWord.create!(attrs)
399
+ record.reload
400
+ attrs.each do |k, v|
401
+ record.send(k).should == v
402
+ end
403
+ end
404
+
405
+ it "should remove double quotes in column quoting" do
406
+ ActiveRecord::Base.connection.quote_column_name('aaa "bbb" ccc').should == '"aaa bbb ccc"'
407
+ end
408
+
409
+ end
410
+
411
+ describe "valid table names" do
412
+ before(:all) do
413
+ @adapter = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
414
+ end
415
+
416
+ it "should be valid with letters and digits" do
417
+ @adapter.valid_table_name?("abc_123").should be_true
418
+ end
419
+
420
+ it "should be valid with schema name" do
421
+ @adapter.valid_table_name?("abc_123.def_456").should be_true
422
+ end
423
+
424
+ it "should be valid with $ in name" do
425
+ @adapter.valid_table_name?("sys.v$session").should be_true
426
+ end
427
+
428
+ it "should be valid with upcase schema name" do
429
+ @adapter.valid_table_name?("ABC_123.DEF_456").should be_true
430
+ end
431
+
432
+ it "should be valid with irregular schema name and database links" do
433
+ @adapter.valid_table_name?('abc$#_123.abc$#_123@abc$#@._123').should be_true
434
+ end
435
+
436
+ it "should not be valid with two dots in name" do
437
+ @adapter.valid_table_name?("abc_123.def_456.ghi_789").should be_false
438
+ end
439
+
440
+ it "should not be valid with invalid characters" do
441
+ @adapter.valid_table_name?("warehouse-things").should be_false
442
+ end
443
+
444
+ it "should not be valid with for camel-case" do
445
+ @adapter.valid_table_name?("Abc").should be_false
446
+ @adapter.valid_table_name?("aBc").should be_false
447
+ @adapter.valid_table_name?("abC").should be_false
448
+ end
449
+
450
+ it "should not be valid for names > 30 characters" do
451
+ @adapter.valid_table_name?("a" * 31).should be_false
452
+ end
453
+
454
+ it "should not be valid for schema names > 30 characters" do
455
+ @adapter.valid_table_name?(("a" * 31) + ".validname").should be_false
456
+ end
457
+
458
+ it "should not be valid for database links > 128 characters" do
459
+ @adapter.valid_table_name?("name@" + "a" * 129).should be_false
460
+ end
461
+
462
+ it "should not be valid for names that do not begin with alphabetic characters" do
463
+ @adapter.valid_table_name?("1abc").should be_false
464
+ @adapter.valid_table_name?("_abc").should be_false
465
+ @adapter.valid_table_name?("abc.1xyz").should be_false
466
+ @adapter.valid_table_name?("abc._xyz").should be_false
467
+ end
468
+ end
469
+
470
+ describe "table quoting" do
471
+
472
+ def create_warehouse_things_table
473
+ ActiveRecord::Schema.define do
474
+ suppress_messages do
475
+ create_table "warehouse-things" do |t|
476
+ t.string :name
477
+ t.integer :foo
478
+ end
479
+ end
480
+ end
481
+ end
482
+
483
+ def create_camel_case_table
484
+ ActiveRecord::Schema.define do
485
+ suppress_messages do
486
+ create_table "CamelCase" do |t|
487
+ t.string :name
488
+ t.integer :foo
489
+ end
490
+ end
491
+ end
492
+ end
493
+
494
+ before(:all) do
495
+ @conn = ActiveRecord::Base.connection
496
+ end
497
+
498
+ after(:each) do
499
+ ActiveRecord::Schema.define do
500
+ suppress_messages do
501
+ drop_table "warehouse-things" rescue nil
502
+ drop_table "CamelCase" rescue nil
503
+ end
504
+ end
505
+ Object.send(:remove_const, "WarehouseThing") rescue nil
506
+ Object.send(:remove_const, "CamelCase") rescue nil
507
+ end
508
+
509
+ it "should allow creation of a table with non alphanumeric characters" do
510
+ create_warehouse_things_table
511
+ class ::WarehouseThing < ActiveRecord::Base
512
+ set_table_name "warehouse-things"
513
+ end
514
+
515
+ wh = WarehouseThing.create!(:name => "Foo", :foo => 2)
516
+ wh.id.should_not be_nil
517
+
518
+ @conn.tables.should include("warehouse-things")
519
+ end
520
+
521
+ it "should allow creation of a table with CamelCase name" do
522
+ create_camel_case_table
523
+ class ::CamelCase < ActiveRecord::Base
524
+ set_table_name "CamelCase"
525
+ end
526
+
527
+ cc = CamelCase.create!(:name => "Foo", :foo => 2)
528
+ cc.id.should_not be_nil
529
+
530
+ @conn.tables.should include("CamelCase")
531
+ end
532
+
533
+ end
534
+
535
+ describe "access table over database link" do
536
+ before(:all) do
537
+ @conn = ActiveRecord::Base.connection
538
+ @db_link = "db_link"
539
+ @sys_conn = ActiveRecord::Base.oracle_enhanced_connection(SYSTEM_CONNECTION_PARAMS)
540
+ @sys_conn.drop_table :test_posts rescue nil
541
+ @sys_conn.create_table :test_posts do |t|
542
+ t.string :title
543
+ # cannot update LOBs over database link
544
+ t.string :body
545
+ t.timestamps
546
+ end
547
+ @db_link_username = SYSTEM_CONNECTION_PARAMS[:username]
548
+ @db_link_password = SYSTEM_CONNECTION_PARAMS[:password]
549
+ @db_link_database = SYSTEM_CONNECTION_PARAMS[:database]
550
+ @conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
551
+ @conn.execute "CREATE DATABASE LINK #{@db_link} CONNECT TO #{@db_link_username} IDENTIFIED BY \"#{@db_link_password}\" USING '#{@db_link_database}'"
552
+ @conn.execute "CREATE OR REPLACE SYNONYM test_posts FOR test_posts@#{@db_link}"
553
+ @conn.execute "CREATE OR REPLACE SYNONYM test_posts_seq FOR test_posts_seq@#{@db_link}"
554
+ class ::TestPost < ActiveRecord::Base
555
+ end
556
+ TestPost.set_table_name "test_posts"
557
+ end
558
+
559
+ after(:all) do
560
+ @conn.execute "DROP SYNONYM test_posts"
561
+ @conn.execute "DROP SYNONYM test_posts_seq"
562
+ @conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
563
+ @sys_conn.drop_table :test_posts rescue nil
564
+ Object.send(:remove_const, "TestPost") rescue nil
565
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
566
+ end
567
+
568
+ it "should verify database link" do
569
+ @conn.select_value("select * from dual@#{@db_link}") == 'X'
570
+ end
571
+
572
+ it "should get column names" do
573
+ TestPost.column_names.should == ["id", "title", "body", "created_at", "updated_at"]
574
+ end
575
+
576
+ it "should create record" do
577
+ p = TestPost.create(:title => "Title", :body => "Body")
578
+ p.id.should_not be_nil
579
+ TestPost.find(p.id).should_not be_nil
580
+ end
581
+
582
+ end
583
+
584
+ describe "session information" do
585
+ before(:all) do
586
+ @conn = ActiveRecord::Base.connection
587
+ end
588
+
589
+ it "should get current database name" do
590
+ # get database name if using //host:port/database connection string
591
+ database_name = CONNECTION_PARAMS[:database].split('/').last
592
+ @conn.current_database.upcase.should == database_name.upcase
593
+ end
594
+
595
+ it "should get current database session user" do
596
+ @conn.current_user.upcase.should == CONNECTION_PARAMS[:username].upcase
597
+ end
598
+ end
599
+
600
+ describe "temporary tables" do
601
+ before(:all) do
602
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:table] = 'UNUSED'
603
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = 'UNUSED'
604
+ @conn = ActiveRecord::Base.connection
605
+ end
606
+ after(:all) do
607
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces={}
608
+ end
609
+
610
+ after(:each) do
611
+ @conn.drop_table :foos rescue nil
612
+ end
613
+ it "should create ok" do
614
+ @conn.create_table :foos, :temporary => true, :id => false do |t|
615
+ t.integer :id
616
+ t.text :bar
617
+ end
618
+ end
619
+ it "should show up as temporary" do
620
+ @conn.create_table :foos, :temporary => true, :id => false do |t|
621
+ t.integer :id
622
+ end
623
+ @conn.temporary_table?("foos").should be_true
624
+ end
625
+ end
626
+
627
+ describe "eager loading" do
628
+ before(:all) do
629
+ schema_define do
630
+ create_table :test_posts do |t|
631
+ t.string :title
632
+ end
633
+ create_table :test_comments do |t|
634
+ t.integer :test_post_id
635
+ t.string :description
636
+ end
637
+ add_index :test_comments, :test_post_id
638
+ end
639
+ class ::TestPost < ActiveRecord::Base
640
+ has_many :test_comments
641
+ end
642
+ class ::TestComment < ActiveRecord::Base
643
+ belongs_to :test_post
644
+ end
645
+ @ids = (1..1010).to_a
646
+ TestPost.transaction do
647
+ @ids.each do |id|
648
+ TestPost.create!(:id => id, :title => "Title #{id}")
649
+ TestComment.create!(:test_post_id => id, :description => "Description #{id}")
650
+ end
651
+ end
652
+ end
653
+
654
+ after(:all) do
655
+ schema_define do
656
+ drop_table :test_comments
657
+ drop_table :test_posts
658
+ end
659
+ Object.send(:remove_const, "TestPost")
660
+ Object.send(:remove_const, "TestComment")
661
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
662
+ end
663
+
664
+ it "should load included association with more than 1000 records" do
665
+ posts = TestPost.includes(:test_comments).all
666
+ posts.size.should == @ids.size
667
+ end
668
+
669
+ end if ENV['RAILS_GEM_VERSION'] >= '3.1'
670
+
671
+ describe "with statement pool" do
672
+ before(:all) do
673
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS.merge(:statement_limit => 3))
674
+ @conn = ActiveRecord::Base.connection
675
+ schema_define do
676
+ drop_table :test_posts rescue nil
677
+ create_table :test_posts
678
+ end
679
+ class ::TestPost < ActiveRecord::Base
680
+ end
681
+ @statements = @conn.instance_variable_get(:@statements)
682
+ end
683
+
684
+ before(:each) do
685
+ @conn.clear_cache!
686
+ end
687
+
688
+ after(:all) do
689
+ schema_define do
690
+ drop_table :test_posts
691
+ end
692
+ Object.send(:remove_const, "TestPost")
693
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
694
+ end
695
+
696
+ it "should clear older cursors when statement limit is reached" do
697
+ pk = TestPost.columns.find { |c| c.primary }
698
+ sub = @conn.substitute_at(pk, 0)
699
+ binds = [[pk, 1]]
700
+
701
+ lambda {
702
+ 4.times do |i|
703
+ @conn.exec_query("SELECT * FROM test_posts WHERE #{i}=#{i} AND id = #{sub}", "SQL", binds)
704
+ end
705
+ }.should change(@statements, :length).by(+3)
706
+ end
707
+
708
+ it "should cache UPDATE statements with bind variables" do
709
+ lambda {
710
+ pk = TestPost.columns.find { |c| c.primary }
711
+ sub = @conn.substitute_at(pk, 0)
712
+ binds = [[pk, 1]]
713
+ @conn.exec_update("UPDATE test_posts SET id = #{sub}", "SQL", binds)
714
+ }.should change(@statements, :length).by(+1)
715
+ end
716
+
717
+ it "should not cache UPDATE statements without bind variables" do
718
+ lambda {
719
+ binds = []
720
+ @conn.exec_update("UPDATE test_posts SET id = 1", "SQL", binds)
721
+ }.should_not change(@statements, :length)
722
+ end
723
+ end if ENV['RAILS_GEM_VERSION'] >= '3.1'
724
+
725
+ describe "explain" do
726
+ before(:all) do
727
+ schema_define do
728
+ drop_table :test_posts rescue nil
729
+ create_table :test_posts
730
+ end
731
+ class ::TestPost < ActiveRecord::Base
732
+ end
733
+ end
734
+
735
+ after(:all) do
736
+ schema_define do
737
+ drop_table :test_posts
738
+ end
739
+ Object.send(:remove_const, "TestPost")
740
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
741
+ end
742
+
743
+ it "should explain query" do
744
+ explain = TestPost.where(:id => 1).explain
745
+ explain.should include("Cost")
746
+ explain.should include("INDEX UNIQUE SCAN")
747
+ end
748
+ end if ENV['RAILS_GEM_VERSION'] >= '3.2'
749
+ end