pmacs-activerecord-oracle_enhanced-adapter 1.4.2.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +52 -0
  3. data/History.md +284 -0
  4. data/License.txt +20 -0
  5. data/README.md +403 -0
  6. data/RUNNING_TESTS.md +45 -0
  7. data/Rakefile +59 -0
  8. data/VERSION +1 -0
  9. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced.rake +105 -0
  11. data/lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb +41 -0
  12. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1408 -0
  13. data/lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb +118 -0
  14. data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +141 -0
  15. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +135 -0
  16. data/lib/active_record/connection_adapters/oracle_enhanced_context_index.rb +359 -0
  17. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +25 -0
  18. data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
  19. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +44 -0
  20. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +565 -0
  21. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +491 -0
  22. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +260 -0
  23. data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +231 -0
  24. data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +257 -0
  25. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb +397 -0
  26. data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +265 -0
  27. data/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb +294 -0
  28. data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +17 -0
  29. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -0
  30. data/lib/pmacs-activerecord-oracle_enhanced-adapter.rb +25 -0
  31. data/pmacs-activerecord-oracle_enhanced-adapter.gemspec +131 -0
  32. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +778 -0
  33. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +332 -0
  34. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +427 -0
  35. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +19 -0
  36. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +113 -0
  37. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +1376 -0
  38. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +69 -0
  39. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +141 -0
  40. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +25 -0
  41. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +378 -0
  42. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +438 -0
  43. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +1280 -0
  44. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +339 -0
  45. data/spec/spec_helper.rb +187 -0
  46. metadata +302 -0
@@ -0,0 +1,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,131 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "pmacs-activerecord-oracle_enhanced-adapter"
8
+ s.version = "1.4.2.rc1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Charles Treatman", "Raimonds Simanovskis"]
12
+ s.date = "2013-02-22"
13
+ s.description = "Oracle \"enhanced\" ActiveRecord adapter contains useful additional methods for working with new and legacy Oracle databases.\nThis adapter is superset of original ActiveRecord Oracle adapter.\n"
14
+ s.email = "charles.treatman@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".rspec",
20
+ "Gemfile",
21
+ "History.md",
22
+ "License.txt",
23
+ "README.md",
24
+ "RUNNING_TESTS.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/active_record/connection_adapters/emulation/oracle_adapter.rb",
28
+ "lib/active_record/connection_adapters/oracle_enhanced.rake",
29
+ "lib/active_record/connection_adapters/oracle_enhanced_activerecord_patches.rb",
30
+ "lib/active_record/connection_adapters/oracle_enhanced_adapter.rb",
31
+ "lib/active_record/connection_adapters/oracle_enhanced_base_ext.rb",
32
+ "lib/active_record/connection_adapters/oracle_enhanced_column.rb",
33
+ "lib/active_record/connection_adapters/oracle_enhanced_connection.rb",
34
+ "lib/active_record/connection_adapters/oracle_enhanced_context_index.rb",
35
+ "lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb",
36
+ "lib/active_record/connection_adapters/oracle_enhanced_cpk.rb",
37
+ "lib/active_record/connection_adapters/oracle_enhanced_dirty.rb",
38
+ "lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb",
39
+ "lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb",
40
+ "lib/active_record/connection_adapters/oracle_enhanced_procedures.rb",
41
+ "lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb",
42
+ "lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb",
43
+ "lib/active_record/connection_adapters/oracle_enhanced_schema_statements.rb",
44
+ "lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb",
45
+ "lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb",
46
+ "lib/active_record/connection_adapters/oracle_enhanced_tasks.rb",
47
+ "lib/active_record/connection_adapters/oracle_enhanced_version.rb",
48
+ "lib/pmacs-activerecord-oracle_enhanced-adapter.rb",
49
+ "pmacs-activerecord-oracle_enhanced-adapter.gemspec",
50
+ "spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb",
51
+ "spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb",
52
+ "spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb",
53
+ "spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb",
54
+ "spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb",
55
+ "spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb",
56
+ "spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb",
57
+ "spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb",
58
+ "spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb",
59
+ "spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb",
60
+ "spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb",
61
+ "spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb",
62
+ "spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb",
63
+ "spec/spec_helper.rb"
64
+ ]
65
+ s.homepage = "http://github.com/pmacs/oracle-enhanced"
66
+ s.require_paths = ["lib"]
67
+ s.rubygems_version = "1.8.21"
68
+ s.summary = "Oracle enhanced adapter for ActiveRecord"
69
+ s.test_files = [
70
+ "spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb",
71
+ "spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb",
72
+ "spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb",
73
+ "spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb",
74
+ "spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb",
75
+ "spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb",
76
+ "spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb",
77
+ "spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb",
78
+ "spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb",
79
+ "spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb",
80
+ "spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb",
81
+ "spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb",
82
+ "spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb",
83
+ "spec/spec_helper.rb"
84
+ ]
85
+
86
+ if s.respond_to? :specification_version then
87
+ s.specification_version = 3
88
+
89
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
90
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
91
+ s.add_development_dependency(%q<rspec>, ["~> 2.4"])
92
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
93
+ s.add_development_dependency(%q<activerecord>, [">= 0"])
94
+ s.add_development_dependency(%q<activemodel>, [">= 0"])
95
+ s.add_development_dependency(%q<activesupport>, [">= 0"])
96
+ s.add_development_dependency(%q<actionpack>, [">= 0"])
97
+ s.add_development_dependency(%q<railties>, [">= 0"])
98
+ s.add_development_dependency(%q<arel>, [">= 0"])
99
+ s.add_development_dependency(%q<journey>, [">= 0"])
100
+ s.add_development_dependency(%q<ruby-plsql>, [">= 0.4.4"])
101
+ s.add_development_dependency(%q<ruby-oci8>, [">= 2.0.4"])
102
+ else
103
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
104
+ s.add_dependency(%q<rspec>, ["~> 2.4"])
105
+ s.add_dependency(%q<rdoc>, [">= 0"])
106
+ s.add_dependency(%q<activerecord>, [">= 0"])
107
+ s.add_dependency(%q<activemodel>, [">= 0"])
108
+ s.add_dependency(%q<activesupport>, [">= 0"])
109
+ s.add_dependency(%q<actionpack>, [">= 0"])
110
+ s.add_dependency(%q<railties>, [">= 0"])
111
+ s.add_dependency(%q<arel>, [">= 0"])
112
+ s.add_dependency(%q<journey>, [">= 0"])
113
+ s.add_dependency(%q<ruby-plsql>, [">= 0.4.4"])
114
+ s.add_dependency(%q<ruby-oci8>, [">= 2.0.4"])
115
+ end
116
+ else
117
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
118
+ s.add_dependency(%q<rspec>, ["~> 2.4"])
119
+ s.add_dependency(%q<rdoc>, [">= 0"])
120
+ s.add_dependency(%q<activerecord>, [">= 0"])
121
+ s.add_dependency(%q<activemodel>, [">= 0"])
122
+ s.add_dependency(%q<activesupport>, [">= 0"])
123
+ s.add_dependency(%q<actionpack>, [">= 0"])
124
+ s.add_dependency(%q<railties>, [">= 0"])
125
+ s.add_dependency(%q<arel>, [">= 0"])
126
+ s.add_dependency(%q<journey>, [">= 0"])
127
+ s.add_dependency(%q<ruby-plsql>, [">= 0.4.4"])
128
+ s.add_dependency(%q<ruby-oci8>, [">= 2.0.4"])
129
+ end
130
+ end
131
+
@@ -0,0 +1,778 @@
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
+ if self.respond_to?(:table_name=)
213
+ self.table_name = "test_employees"
214
+ else
215
+ set_table_name "test_employees"
216
+ end
217
+ end
218
+ end
219
+
220
+ after(:all) do
221
+ @conn = ActiveRecord::Base.connection
222
+ Object.send(:remove_const, "TestEmployee")
223
+ Object.send(:remove_const, "TestEmployee2")
224
+ @conn.execute "DROP TABLE test_employees"
225
+ @conn.execute "DROP TABLE test_employees_without_pk"
226
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = nil
227
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
228
+ end
229
+
230
+ before(:each) do
231
+ set_logger
232
+ @conn = ActiveRecord::Base.connection
233
+ @conn.clear_columns_cache
234
+ end
235
+
236
+ after(:each) do
237
+ clear_logger
238
+ end
239
+
240
+ describe "without column caching" do
241
+
242
+ before(:each) do
243
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = false
244
+ end
245
+
246
+ it 'should identify virtual columns as such' do
247
+ pending "Not supported in this database version" unless @oracle11g
248
+ te = TestEmployee.connection.columns('test_employees').detect(&:virtual?)
249
+ te.name.should == 'full_name'
250
+ end
251
+
252
+ it "should get columns from database at first time" do
253
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
254
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
255
+ end
256
+
257
+ it "should get columns from database at second time" do
258
+ TestEmployee.connection.columns('test_employees')
259
+ @logger.clear(:debug)
260
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
261
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
262
+ end
263
+
264
+ it "should get primary key from database at first time" do
265
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
266
+ @logger.logged(:debug).last.should =~ /select .* from all_constraints/im
267
+ end
268
+
269
+ it "should get primary key from database at first time" do
270
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
271
+ @logger.clear(:debug)
272
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
273
+ @logger.logged(:debug).last.should =~ /select .* from all_constraints/im
274
+ end
275
+
276
+ it "should have correct sql types when 2 models are using the same table and AR query cache is enabled" do
277
+ @conn.cache do
278
+ TestEmployee.columns.map(&:sql_type).should == @column_sql_types
279
+ TestEmployee2.columns.map(&:sql_type).should == @column_sql_types
280
+ end
281
+ end
282
+
283
+ end
284
+
285
+ describe "with column caching" do
286
+
287
+ before(:each) do
288
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.cache_columns = true
289
+ end
290
+
291
+ it "should get columns from database at first time" do
292
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
293
+ @logger.logged(:debug).last.should =~ /select .* from all_tab_cols/im
294
+ end
295
+
296
+ it "should get columns from cache at second time" do
297
+ TestEmployee.connection.columns('test_employees')
298
+ @logger.clear(:debug)
299
+ TestEmployee.connection.columns('test_employees').map(&:name).should == @column_names
300
+ @logger.logged(:debug).last.should be_blank
301
+ end
302
+
303
+ it "should get primary key from database at first time" do
304
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
305
+ @logger.logged(:debug).last.should =~ /select .* from all_constraints/im
306
+ end
307
+
308
+ it "should get primary key from cache at first time" do
309
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
310
+ @logger.clear(:debug)
311
+ TestEmployee.connection.pk_and_sequence_for('test_employees').should == ['id', nil]
312
+ @logger.logged(:debug).last.should be_blank
313
+ end
314
+
315
+ it "should store primary key as nil in cache at first time for table without primary key" do
316
+ TestEmployee.connection.pk_and_sequence_for('test_employees_without_pk').should == nil
317
+ @logger.clear(:debug)
318
+ TestEmployee.connection.pk_and_sequence_for('test_employees_without_pk').should == nil
319
+ @logger.logged(:debug).last.should be_blank
320
+ end
321
+
322
+ end
323
+
324
+ end
325
+
326
+ describe "without composite_primary_keys" do
327
+
328
+ before(:all) do
329
+ @conn = ActiveRecord::Base.connection
330
+ @conn.execute "DROP TABLE test_employees" rescue nil
331
+ @conn.execute <<-SQL
332
+ CREATE TABLE test_employees (
333
+ employee_id NUMBER PRIMARY KEY,
334
+ name VARCHAR2(50)
335
+ )
336
+ SQL
337
+ Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
338
+ class ::TestEmployee < ActiveRecord::Base
339
+ if self.respond_to?(:primary_key=)
340
+ self.primary_key = :employee_id
341
+ else
342
+ set_primary_key :employee_id
343
+ end
344
+ end
345
+ end
346
+
347
+ after(:all) do
348
+ Object.send(:remove_const, "TestEmployee")
349
+ @conn.execute "DROP TABLE test_employees"
350
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
351
+ end
352
+
353
+ it "should tell ActiveRecord that count distinct is supported" do
354
+ ActiveRecord::Base.connection.supports_count_distinct?.should be_true
355
+ end
356
+
357
+ it "should execute correct SQL COUNT DISTINCT statement" do
358
+ lambda { TestEmployee.count(:employee_id, :distinct => true) }.should_not raise_error
359
+ end
360
+
361
+ end
362
+
363
+
364
+ describe "reserved words column quoting" do
365
+
366
+ before(:all) do
367
+ schema_define do
368
+ create_table :test_reserved_words do |t|
369
+ t.string :varchar2
370
+ t.integer :integer
371
+ t.text :comment
372
+ end
373
+ end
374
+ class ::TestReservedWord < ActiveRecord::Base; end
375
+ end
376
+
377
+ after(:all) do
378
+ schema_define do
379
+ drop_table :test_reserved_words
380
+ end
381
+ Object.send(:remove_const, "TestReservedWord")
382
+ ActiveRecord::Base.table_name_prefix = nil
383
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
384
+ end
385
+
386
+ before(:each) do
387
+ set_logger
388
+ end
389
+
390
+ after(:each) do
391
+ clear_logger
392
+ end
393
+
394
+ it "should create table" do
395
+ [:varchar2, :integer, :comment].each do |attr|
396
+ TestReservedWord.columns_hash[attr.to_s].name.should == attr.to_s
397
+ end
398
+ end
399
+
400
+ it "should create record" do
401
+ attrs = {
402
+ :varchar2 => 'dummy',
403
+ :integer => 1,
404
+ :comment => 'dummy'
405
+ }
406
+ record = TestReservedWord.create!(attrs)
407
+ record.reload
408
+ attrs.each do |k, v|
409
+ record.send(k).should == v
410
+ end
411
+ end
412
+
413
+ it "should remove double quotes in column quoting" do
414
+ ActiveRecord::Base.connection.quote_column_name('aaa "bbb" ccc').should == '"aaa bbb ccc"'
415
+ end
416
+
417
+ end
418
+
419
+ describe "valid table names" do
420
+ before(:all) do
421
+ @adapter = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
422
+ end
423
+
424
+ it "should be valid with letters and digits" do
425
+ @adapter.valid_table_name?("abc_123").should be_true
426
+ end
427
+
428
+ it "should be valid with schema name" do
429
+ @adapter.valid_table_name?("abc_123.def_456").should be_true
430
+ end
431
+
432
+ it "should be valid with $ in name" do
433
+ @adapter.valid_table_name?("sys.v$session").should be_true
434
+ end
435
+
436
+ it "should be valid with upcase schema name" do
437
+ @adapter.valid_table_name?("ABC_123.DEF_456").should be_true
438
+ end
439
+
440
+ it "should be valid with irregular schema name and database links" do
441
+ @adapter.valid_table_name?('abc$#_123.abc$#_123@abc$#@._123').should be_true
442
+ end
443
+
444
+ it "should not be valid with two dots in name" do
445
+ @adapter.valid_table_name?("abc_123.def_456.ghi_789").should be_false
446
+ end
447
+
448
+ it "should not be valid with invalid characters" do
449
+ @adapter.valid_table_name?("warehouse-things").should be_false
450
+ end
451
+
452
+ it "should not be valid with for camel-case" do
453
+ @adapter.valid_table_name?("Abc").should be_false
454
+ @adapter.valid_table_name?("aBc").should be_false
455
+ @adapter.valid_table_name?("abC").should be_false
456
+ end
457
+
458
+ it "should not be valid for names > 30 characters" do
459
+ @adapter.valid_table_name?("a" * 31).should be_false
460
+ end
461
+
462
+ it "should not be valid for schema names > 30 characters" do
463
+ @adapter.valid_table_name?(("a" * 31) + ".validname").should be_false
464
+ end
465
+
466
+ it "should not be valid for database links > 128 characters" do
467
+ @adapter.valid_table_name?("name@" + "a" * 129).should be_false
468
+ end
469
+
470
+ it "should not be valid for names that do not begin with alphabetic characters" do
471
+ @adapter.valid_table_name?("1abc").should be_false
472
+ @adapter.valid_table_name?("_abc").should be_false
473
+ @adapter.valid_table_name?("abc.1xyz").should be_false
474
+ @adapter.valid_table_name?("abc._xyz").should be_false
475
+ end
476
+ end
477
+
478
+ describe "table quoting" do
479
+
480
+ def create_warehouse_things_table
481
+ ActiveRecord::Schema.define do
482
+ suppress_messages do
483
+ create_table "warehouse-things" do |t|
484
+ t.string :name
485
+ t.integer :foo
486
+ end
487
+ end
488
+ end
489
+ end
490
+
491
+ def create_camel_case_table
492
+ ActiveRecord::Schema.define do
493
+ suppress_messages do
494
+ create_table "CamelCase" do |t|
495
+ t.string :name
496
+ t.integer :foo
497
+ end
498
+ end
499
+ end
500
+ end
501
+
502
+ before(:all) do
503
+ @conn = ActiveRecord::Base.connection
504
+ end
505
+
506
+ after(:each) do
507
+ ActiveRecord::Schema.define do
508
+ suppress_messages do
509
+ drop_table "warehouse-things" rescue nil
510
+ drop_table "CamelCase" rescue nil
511
+ end
512
+ end
513
+ Object.send(:remove_const, "WarehouseThing") rescue nil
514
+ Object.send(:remove_const, "CamelCase") rescue nil
515
+ end
516
+
517
+ it "should allow creation of a table with non alphanumeric characters" do
518
+ create_warehouse_things_table
519
+ class ::WarehouseThing < ActiveRecord::Base
520
+ if self.respond_to?(:table_name=)
521
+ self.table_name = "warehouse-things"
522
+ else
523
+ set_table_name "warehouse-things"
524
+ end
525
+ end
526
+
527
+ wh = WarehouseThing.create!(:name => "Foo", :foo => 2)
528
+ wh.id.should_not be_nil
529
+
530
+ @conn.tables.should include("warehouse-things")
531
+ end
532
+
533
+ it "should allow creation of a table with CamelCase name" do
534
+ create_camel_case_table
535
+ class ::CamelCase < ActiveRecord::Base
536
+ if self.respond_to?(:table_name=)
537
+ self.table_name = "CamelCase"
538
+ else
539
+ set_table_name "CamelCase"
540
+ end
541
+ end
542
+
543
+ cc = CamelCase.create!(:name => "Foo", :foo => 2)
544
+ cc.id.should_not be_nil
545
+
546
+ @conn.tables.should include("CamelCase")
547
+ end
548
+
549
+ end
550
+
551
+ describe "access table over database link" do
552
+ before(:all) do
553
+ @conn = ActiveRecord::Base.connection
554
+ @db_link = "db_link"
555
+ @sys_conn = ActiveRecord::Base.oracle_enhanced_connection(SYSTEM_CONNECTION_PARAMS)
556
+ @sys_conn.drop_table :test_posts rescue nil
557
+ @sys_conn.create_table :test_posts do |t|
558
+ t.string :title
559
+ # cannot update LOBs over database link
560
+ t.string :body
561
+ t.timestamps
562
+ end
563
+ @db_link_username = SYSTEM_CONNECTION_PARAMS[:username]
564
+ @db_link_password = SYSTEM_CONNECTION_PARAMS[:password]
565
+ @db_link_database = SYSTEM_CONNECTION_PARAMS[:database]
566
+ @conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
567
+ @conn.execute "CREATE DATABASE LINK #{@db_link} CONNECT TO #{@db_link_username} IDENTIFIED BY \"#{@db_link_password}\" USING '#{@db_link_database}'"
568
+ @conn.execute "CREATE OR REPLACE SYNONYM test_posts FOR test_posts@#{@db_link}"
569
+ @conn.execute "CREATE OR REPLACE SYNONYM test_posts_seq FOR test_posts_seq@#{@db_link}"
570
+ class ::TestPost < ActiveRecord::Base
571
+ end
572
+ if TestPost.respond_to?(:table_name=)
573
+ TestPost.table_name = "test_posts"
574
+ else
575
+ TestPost.set_table_name "test_posts"
576
+ end
577
+ end
578
+
579
+ after(:all) do
580
+ @conn.execute "DROP SYNONYM test_posts"
581
+ @conn.execute "DROP SYNONYM test_posts_seq"
582
+ @conn.execute "DROP DATABASE LINK #{@db_link}" rescue nil
583
+ @sys_conn.drop_table :test_posts rescue nil
584
+ Object.send(:remove_const, "TestPost") rescue nil
585
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
586
+ end
587
+
588
+ it "should verify database link" do
589
+ @conn.select_value("select * from dual@#{@db_link}") == 'X'
590
+ end
591
+
592
+ it "should get column names" do
593
+ TestPost.column_names.should == ["id", "title", "body", "created_at", "updated_at"]
594
+ end
595
+
596
+ it "should create record" do
597
+ p = TestPost.create(:title => "Title", :body => "Body")
598
+ p.id.should_not be_nil
599
+ TestPost.find(p.id).should_not be_nil
600
+ end
601
+
602
+ end
603
+
604
+ describe "session information" do
605
+ before(:all) do
606
+ @conn = ActiveRecord::Base.connection
607
+ end
608
+
609
+ it "should get current database name" do
610
+ # get database name if using //host:port/database connection string
611
+ database_name = CONNECTION_PARAMS[:database].split('/').last
612
+ @conn.current_database.upcase.should == database_name.upcase
613
+ end
614
+
615
+ it "should get current database session user" do
616
+ @conn.current_user.upcase.should == CONNECTION_PARAMS[:username].upcase
617
+ end
618
+ end
619
+
620
+ describe "temporary tables" do
621
+ before(:all) do
622
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:table] = 'UNUSED'
623
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces[:clob] = 'UNUSED'
624
+ @conn = ActiveRecord::Base.connection
625
+ end
626
+ after(:all) do
627
+ ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces={}
628
+ end
629
+
630
+ after(:each) do
631
+ @conn.drop_table :foos rescue nil
632
+ end
633
+ it "should create ok" do
634
+ @conn.create_table :foos, :temporary => true, :id => false do |t|
635
+ t.integer :id
636
+ t.text :bar
637
+ end
638
+ end
639
+ it "should show up as temporary" do
640
+ @conn.create_table :foos, :temporary => true, :id => false do |t|
641
+ t.integer :id
642
+ end
643
+ @conn.temporary_table?("foos").should be_true
644
+ end
645
+ end
646
+
647
+ describe "eager loading" do
648
+ before(:all) do
649
+ schema_define do
650
+ create_table :test_posts do |t|
651
+ t.string :title
652
+ end
653
+ create_table :test_comments do |t|
654
+ t.integer :test_post_id
655
+ t.string :description
656
+ end
657
+ add_index :test_comments, :test_post_id
658
+ end
659
+ class ::TestPost < ActiveRecord::Base
660
+ has_many :test_comments
661
+ end
662
+ class ::TestComment < ActiveRecord::Base
663
+ belongs_to :test_post
664
+ end
665
+ @ids = (1..1010).to_a
666
+ TestPost.transaction do
667
+ @ids.each do |id|
668
+ TestPost.create!(:id => id, :title => "Title #{id}")
669
+ TestComment.create!(:test_post_id => id, :description => "Description #{id}")
670
+ end
671
+ end
672
+ end
673
+
674
+ after(:all) do
675
+ schema_define do
676
+ drop_table :test_comments
677
+ drop_table :test_posts
678
+ end
679
+ Object.send(:remove_const, "TestPost")
680
+ Object.send(:remove_const, "TestComment")
681
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
682
+ end
683
+
684
+ it "should load included association with more than 1000 records" do
685
+ posts = TestPost.includes(:test_comments).all
686
+ posts.size.should == @ids.size
687
+ end
688
+
689
+ end if ENV['RAILS_GEM_VERSION'] >= '3.1'
690
+
691
+ describe "with statement pool" do
692
+ before(:all) do
693
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS.merge(:statement_limit => 3))
694
+ @conn = ActiveRecord::Base.connection
695
+ schema_define do
696
+ drop_table :test_posts rescue nil
697
+ create_table :test_posts
698
+ end
699
+ class ::TestPost < ActiveRecord::Base
700
+ end
701
+ @statements = @conn.instance_variable_get(:@statements)
702
+ end
703
+
704
+ before(:each) do
705
+ @conn.clear_cache!
706
+ end
707
+
708
+ after(:all) do
709
+ schema_define do
710
+ drop_table :test_posts
711
+ end
712
+ Object.send(:remove_const, "TestPost")
713
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
714
+ end
715
+
716
+ it "should clear older cursors when statement limit is reached" do
717
+ pk = TestPost.columns.find { |c| c.primary }
718
+ sub = @conn.substitute_at(pk, 0)
719
+ binds = [[pk, 1]]
720
+
721
+ lambda {
722
+ 4.times do |i|
723
+ @conn.exec_query("SELECT * FROM test_posts WHERE #{i}=#{i} AND id = #{sub}", "SQL", binds)
724
+ end
725
+ }.should change(@statements, :length).by(+3)
726
+ end
727
+
728
+ it "should cache UPDATE statements with bind variables" do
729
+ lambda {
730
+ pk = TestPost.columns.find { |c| c.primary }
731
+ sub = @conn.substitute_at(pk, 0)
732
+ binds = [[pk, 1]]
733
+ @conn.exec_update("UPDATE test_posts SET id = #{sub}", "SQL", binds)
734
+ }.should change(@statements, :length).by(+1)
735
+ end
736
+
737
+ it "should not cache UPDATE statements without bind variables" do
738
+ lambda {
739
+ binds = []
740
+ @conn.exec_update("UPDATE test_posts SET id = 1", "SQL", binds)
741
+ }.should_not change(@statements, :length)
742
+ end
743
+ end if ENV['RAILS_GEM_VERSION'] >= '3.1'
744
+
745
+ describe "explain" do
746
+ before(:all) do
747
+ @conn = ActiveRecord::Base.connection
748
+ schema_define do
749
+ drop_table :test_posts rescue nil
750
+ create_table :test_posts
751
+ end
752
+ class ::TestPost < ActiveRecord::Base
753
+ end
754
+ end
755
+
756
+ after(:all) do
757
+ schema_define do
758
+ drop_table :test_posts
759
+ end
760
+ Object.send(:remove_const, "TestPost")
761
+ ActiveRecord::Base.clear_cache! if ActiveRecord::Base.respond_to?(:"clear_cache!")
762
+ end
763
+
764
+ it "should explain query" do
765
+ explain = TestPost.where(:id => 1).explain
766
+ explain.should include("Cost")
767
+ explain.should include("INDEX UNIQUE SCAN")
768
+ end
769
+
770
+ it "should explain query with binds" do
771
+ pk = TestPost.columns.find { |c| c.primary }
772
+ sub = @conn.substitute_at(pk, 0)
773
+ explain = TestPost.where(TestPost.arel_table[pk.name].eq(sub)).bind([pk, 1]).explain
774
+ explain.should include("Cost")
775
+ explain.should include("INDEX UNIQUE SCAN")
776
+ end
777
+ end if ENV['RAILS_GEM_VERSION'] >= '3.2'
778
+ end