ctreatma-activerecord-oracle_enhanced-adapter 1.4.1.1

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