plukevdh-activerecord-oracle_enhanced-adapter 1.2.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.
- data/History.txt +111 -0
- data/License.txt +20 -0
- data/Manifest.txt +26 -0
- data/README.rdoc +68 -0
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +5 -0
- data/lib/active_record/connection_adapters/oracle_enhanced.rake +48 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +1200 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +71 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +64 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +21 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +358 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +368 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +150 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_reserved_words.rb +126 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +11 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +7 -0
- data/oracle-enhanced.gemspec +59 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +659 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +170 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +40 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +103 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +951 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +93 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +27 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +340 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +94 -0
- metadata +94 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
module ActiveRecord #:nodoc:
|
2
|
+
module ConnectionAdapters #:nodoc:
|
3
|
+
module OracleEnhancedReservedWords #:nodoc:
|
4
|
+
|
5
|
+
RESERVED_WORDS = {
|
6
|
+
"ACCESS" => true,
|
7
|
+
"ADD" => true,
|
8
|
+
"ALL" => true,
|
9
|
+
"ALTER" => true,
|
10
|
+
"AND" => true,
|
11
|
+
"ANY" => true,
|
12
|
+
"AS" => true,
|
13
|
+
"ASC" => true,
|
14
|
+
"AUDIT" => true,
|
15
|
+
"BETWEEN" => true,
|
16
|
+
"BY" => true,
|
17
|
+
"CHAR" => true,
|
18
|
+
"CHECK" => true,
|
19
|
+
"CLUSTER" => true,
|
20
|
+
"COLUMN" => true,
|
21
|
+
"COMMENT" => true,
|
22
|
+
"COMPRESS" => true,
|
23
|
+
"CONNECT" => true,
|
24
|
+
"CREATE" => true,
|
25
|
+
"CURRENT" => true,
|
26
|
+
"DATE" => true,
|
27
|
+
"DECIMAL" => true,
|
28
|
+
"DEFAULT" => true,
|
29
|
+
"DELETE" => true,
|
30
|
+
"DESC" => true,
|
31
|
+
"DISTINCT" => true,
|
32
|
+
"DROP" => true,
|
33
|
+
"ELSE" => true,
|
34
|
+
"EXCLUSIVE" => true,
|
35
|
+
"EXISTS" => true,
|
36
|
+
"FILE" => true,
|
37
|
+
"FLOAT" => true,
|
38
|
+
"FOR" => true,
|
39
|
+
"FROM" => true,
|
40
|
+
"GRANT" => true,
|
41
|
+
"GROUP" => true,
|
42
|
+
"HAVING" => true,
|
43
|
+
"IDENTIFIED" => true,
|
44
|
+
"IMMEDIATE" => true,
|
45
|
+
"IN" => true,
|
46
|
+
"INCREMENT" => true,
|
47
|
+
"INDEX" => true,
|
48
|
+
"INITIAL" => true,
|
49
|
+
"INSERT" => true,
|
50
|
+
"INTEGER" => true,
|
51
|
+
"INTERSECT" => true,
|
52
|
+
"INTO" => true,
|
53
|
+
"IS" => true,
|
54
|
+
"LEVEL" => true,
|
55
|
+
"LIKE" => true,
|
56
|
+
"LOCK" => true,
|
57
|
+
"LONG" => true,
|
58
|
+
"MAXEXTENTS" => true,
|
59
|
+
"MINUS" => true,
|
60
|
+
"MLSLABEL" => true,
|
61
|
+
"MODE" => true,
|
62
|
+
"MODIFY" => true,
|
63
|
+
"NOAUDIT" => true,
|
64
|
+
"NOCOMPRESS" => true,
|
65
|
+
"NOT" => true,
|
66
|
+
"NOWAIT" => true,
|
67
|
+
"NULL" => true,
|
68
|
+
"NUMBER" => true,
|
69
|
+
"OF" => true,
|
70
|
+
"OFFLINE" => true,
|
71
|
+
"ON" => true,
|
72
|
+
"ONLINE" => true,
|
73
|
+
"OPTION" => true,
|
74
|
+
"OR" => true,
|
75
|
+
"ORDER" => true,
|
76
|
+
"PCTFREE" => true,
|
77
|
+
"PRIOR" => true,
|
78
|
+
"PRIVILEGES" => true,
|
79
|
+
"PUBLIC" => true,
|
80
|
+
"RAW" => true,
|
81
|
+
"RENAME" => true,
|
82
|
+
"RESOURCE" => true,
|
83
|
+
"REVOKE" => true,
|
84
|
+
"ROW" => true,
|
85
|
+
"ROWID" => true,
|
86
|
+
"ROWNUM" => true,
|
87
|
+
"ROWS" => true,
|
88
|
+
"SELECT" => true,
|
89
|
+
"SESSION" => true,
|
90
|
+
"SET" => true,
|
91
|
+
"SHARE" => true,
|
92
|
+
"SIZE" => true,
|
93
|
+
"SMALLINT" => true,
|
94
|
+
"START" => true,
|
95
|
+
"SUCCESSFUL" => true,
|
96
|
+
"SYNONYM" => true,
|
97
|
+
"SYSDATE" => true,
|
98
|
+
"TABLE" => true,
|
99
|
+
"THEN" => true,
|
100
|
+
"TO" => true,
|
101
|
+
"TRIGGER" => true,
|
102
|
+
"UID" => true,
|
103
|
+
"UNION" => true,
|
104
|
+
"UNIQUE" => true,
|
105
|
+
"UPDATE" => true,
|
106
|
+
"USER" => true,
|
107
|
+
"VALIDATE" => true,
|
108
|
+
"VALUES" => true,
|
109
|
+
"VARCHAR" => true,
|
110
|
+
"VARCHAR2" => true,
|
111
|
+
"VIEW" => true,
|
112
|
+
"WHENEVER" => true,
|
113
|
+
"WHERE" => true,
|
114
|
+
"WITH" => true
|
115
|
+
}
|
116
|
+
|
117
|
+
def quote_oracle_reserved_words(name)
|
118
|
+
RESERVED_WORDS[name.to_s.upcase].nil? ? name : "\"#{name}\""
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
|
125
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhancedReservedWords
|
126
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# implementation idea taken from JDBC adapter
|
2
|
+
if defined?(Rake.application) && Rake.application && ActiveRecord::Base.configurations[RAILS_ENV]['adapter'] == 'oracle_enhanced'
|
3
|
+
oracle_enhanced_rakefile = File.dirname(__FILE__) + "/oracle_enhanced.rake"
|
4
|
+
if Rake.application.lookup("environment")
|
5
|
+
# rails tasks already defined; load the override tasks now
|
6
|
+
load oracle_enhanced_rakefile
|
7
|
+
else
|
8
|
+
# rails tasks not loaded yet; load as an import
|
9
|
+
Rake.application.add_import(oracle_enhanced_rakefile)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{activerecord-oracle_enhanced-adapter}
|
5
|
+
s.version = "1.2.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Raimonds Simanovskis"]
|
9
|
+
s.date = %q{2009-09-04}
|
10
|
+
s.description = %q{Oracle enhanced adapter for ActiveRecord}
|
11
|
+
s.email = ["raimonds.simanovskis@gmail.com"]
|
12
|
+
s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.rdoc"]
|
13
|
+
s.files = ["History.txt", "License.txt", "Manifest.txt", "README.rdoc",
|
14
|
+
"lib/active_record/connection_adapters/emulation/oracle_adapter.rb",
|
15
|
+
"lib/active_record/connection_adapters/oracle_enhanced.rake",
|
16
|
+
"lib/active_record/connection_adapters/oracle_enhanced_adapter.rb",
|
17
|
+
"lib/active_record/connection_adapters/oracle_enhanced_connection.rb",
|
18
|
+
"lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb",
|
19
|
+
"lib/active_record/connection_adapters/oracle_enhanced_cpk.rb",
|
20
|
+
"lib/active_record/connection_adapters/oracle_enhanced_dirty.rb",
|
21
|
+
"lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb",
|
22
|
+
"lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb",
|
23
|
+
"lib/active_record/connection_adapters/oracle_enhanced_procedures.rb",
|
24
|
+
"lib/active_record/connection_adapters/oracle_enhanced_reserved_words.rb",
|
25
|
+
"lib/active_record/connection_adapters/oracle_enhanced_tasks.rb",
|
26
|
+
"lib/active_record/connection_adapters/oracle_enhanced_version.rb",
|
27
|
+
"oracle-enhanced.gemspec",
|
28
|
+
"spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb",
|
29
|
+
"spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb",
|
30
|
+
"spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb",
|
31
|
+
"spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb",
|
32
|
+
"spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb",
|
33
|
+
"spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb",
|
34
|
+
"spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb",
|
35
|
+
"spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb",
|
36
|
+
"spec/spec.opts",
|
37
|
+
"spec/spec_helper.rb"]
|
38
|
+
s.has_rdoc = true
|
39
|
+
s.homepage = %q{http://oracle-enhanced.rubyforge.org}
|
40
|
+
s.post_install_message = %q{}
|
41
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubyforge_project = %q{oracle-enhanced}
|
44
|
+
s.rubygems_version = %q{1.3.1}
|
45
|
+
s.summary = %q{Oracle enhanced adapter for ActiveRecord}
|
46
|
+
|
47
|
+
if s.respond_to? :specification_version then
|
48
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
49
|
+
s.specification_version = 2
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
55
|
+
end
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,659 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
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 schema dump" do
|
37
|
+
|
38
|
+
before(:all) do
|
39
|
+
if !defined?(RUBY_ENGINE)
|
40
|
+
@old_conn = ActiveRecord::Base.oracle_connection(CONNECTION_PARAMS)
|
41
|
+
@old_conn.class.should == ActiveRecord::ConnectionAdapters::OracleAdapter
|
42
|
+
elsif RUBY_ENGINE == 'jruby'
|
43
|
+
@old_conn = ActiveRecord::Base.jdbc_connection(JDBC_CONNECTION_PARAMS)
|
44
|
+
@old_conn.class.should == ActiveRecord::ConnectionAdapters::JdbcAdapter
|
45
|
+
end
|
46
|
+
|
47
|
+
@new_conn = ActiveRecord::Base.oracle_enhanced_connection(CONNECTION_PARAMS)
|
48
|
+
@new_conn.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
|
49
|
+
end
|
50
|
+
|
51
|
+
after(:all) do
|
52
|
+
# Workaround for undefining callback that was defined by JDBC adapter
|
53
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
54
|
+
ActiveRecord::Base.class_eval do
|
55
|
+
def after_save_with_oracle_lob
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
unless defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION =~ /^1\.9/
|
63
|
+
it "should return the same tables list as original oracle adapter" do
|
64
|
+
@new_conn.tables.sort.should == @old_conn.tables.sort
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return the same index list as original oracle adapter" do
|
68
|
+
@new_conn.indexes('employees').sort_by(&:name).should == @old_conn.indexes('employees').sort_by(&:name)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return the same pk_and_sequence_for as original oracle adapter" do
|
72
|
+
if @old_conn.respond_to?(:pk_and_sequence_for)
|
73
|
+
@new_conn.tables.each do |t|
|
74
|
+
@new_conn.pk_and_sequence_for(t).should == @old_conn.pk_and_sequence_for(t)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should return the same structure dump as original oracle adapter" do
|
80
|
+
@new_conn.structure_dump.split(";\n\n").sort.should == @old_conn.structure_dump.split(";\n\n").sort
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return the same structure drop as original oracle adapter" do
|
84
|
+
@new_conn.structure_drop.split(";\n\n").sort.should == @old_conn.structure_drop.split(";\n\n").sort
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return the character size of nvarchar fields" do
|
89
|
+
@new_conn.execute <<-SQL
|
90
|
+
CREATE TABLE nvarchartable (
|
91
|
+
session_id NVARCHAR2(255) DEFAULT NULL
|
92
|
+
)
|
93
|
+
SQL
|
94
|
+
if /.*session_id nvarchar2\((\d+)\).*/ =~ @new_conn.structure_dump
|
95
|
+
"#$1".should == "255"
|
96
|
+
end
|
97
|
+
@new_conn.execute "DROP TABLE nvarchartable"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "OracleEnhancedAdapter database stucture dump extentions" do
|
102
|
+
before(:all) do
|
103
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
104
|
+
@conn = ActiveRecord::Base.connection
|
105
|
+
@conn.execute <<-SQL
|
106
|
+
CREATE TABLE nvarchartable (
|
107
|
+
unq_nvarchar NVARCHAR2(255) DEFAULT NULL
|
108
|
+
)
|
109
|
+
SQL
|
110
|
+
end
|
111
|
+
|
112
|
+
after(:all) do
|
113
|
+
@conn.execute "DROP TABLE nvarchartable"
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should return the character size of nvarchar fields" do
|
117
|
+
if /.*unq_nvarchar nvarchar2\((\d+)\).*/ =~ @conn.structure_dump
|
118
|
+
"#$1".should == "255"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "OracleEnhancedAdapter database session store" do
|
124
|
+
before(:all) do
|
125
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
126
|
+
@conn = ActiveRecord::Base.connection
|
127
|
+
@conn.execute <<-SQL
|
128
|
+
CREATE TABLE sessions (
|
129
|
+
id NUMBER(38,0) NOT NULL,
|
130
|
+
session_id VARCHAR2(255) DEFAULT NULL,
|
131
|
+
data CLOB DEFAULT NULL,
|
132
|
+
created_at DATE DEFAULT NULL,
|
133
|
+
updated_at DATE DEFAULT NULL,
|
134
|
+
PRIMARY KEY (ID)
|
135
|
+
)
|
136
|
+
SQL
|
137
|
+
@conn.execute <<-SQL
|
138
|
+
CREATE SEQUENCE sessions_seq MINVALUE 1 MAXVALUE 999999999999999999999999999
|
139
|
+
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
140
|
+
SQL
|
141
|
+
if ENV['RAILS_GEM_VERSION'] >= '2.3'
|
142
|
+
@session_class = ActiveRecord::SessionStore::Session
|
143
|
+
else
|
144
|
+
@session_class = CGI::Session::ActiveRecordStore::Session
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
after(:all) do
|
149
|
+
@conn.execute "DROP TABLE sessions"
|
150
|
+
@conn.execute "DROP SEQUENCE sessions_seq"
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should create sessions table" do
|
154
|
+
ActiveRecord::Base.connection.tables.grep("sessions").should_not be_empty
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should save session data" do
|
158
|
+
@session = @session_class.new :session_id => "111111", :data => "something" #, :updated_at => Time.now
|
159
|
+
@session.save!
|
160
|
+
@session = @session_class.find_by_session_id("111111")
|
161
|
+
@session.data.should == "something"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should change session data when partial updates enabled" do
|
165
|
+
return pending("Not in this ActiveRecord version") unless @session_class.respond_to?(:partial_updates=)
|
166
|
+
@session_class.partial_updates = true
|
167
|
+
@session = @session_class.new :session_id => "222222", :data => "something" #, :updated_at => Time.now
|
168
|
+
@session.save!
|
169
|
+
@session = @session_class.find_by_session_id("222222")
|
170
|
+
@session.data = "other thing"
|
171
|
+
@session.save!
|
172
|
+
# second save should call again blob writing callback
|
173
|
+
@session.save!
|
174
|
+
@session = @session_class.find_by_session_id("222222")
|
175
|
+
@session.data.should == "other thing"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should have one enhanced_write_lobs callback" do
|
179
|
+
return pending("Not in this ActiveRecord version") unless @session_class.respond_to?(:after_save_callback_chain)
|
180
|
+
@session_class.after_save_callback_chain.select{|cb| cb.method == :enhanced_write_lobs}.should have(1).record
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should not set sessions table session_id column type as integer if emulate_integers_by_column_name is true" do
|
184
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
185
|
+
columns = @conn.columns('sessions')
|
186
|
+
column = columns.detect{|c| c.name == "session_id"}
|
187
|
+
column.type.should == :string
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "OracleEnhancedAdapter ignore specified table columns" do
|
193
|
+
before(:all) do
|
194
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
195
|
+
@conn = ActiveRecord::Base.connection
|
196
|
+
@conn.execute <<-SQL
|
197
|
+
CREATE TABLE test_employees (
|
198
|
+
id NUMBER,
|
199
|
+
first_name VARCHAR2(20),
|
200
|
+
last_name VARCHAR2(25),
|
201
|
+
email VARCHAR2(25),
|
202
|
+
phone_number VARCHAR2(20),
|
203
|
+
hire_date DATE,
|
204
|
+
job_id NUMBER,
|
205
|
+
salary NUMBER,
|
206
|
+
commission_pct NUMBER(2,2),
|
207
|
+
manager_id NUMBER(6),
|
208
|
+
department_id NUMBER(4,0),
|
209
|
+
created_at DATE
|
210
|
+
)
|
211
|
+
SQL
|
212
|
+
@conn.execute <<-SQL
|
213
|
+
CREATE SEQUENCE test_employees_seq MINVALUE 1
|
214
|
+
INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE
|
215
|
+
SQL
|
216
|
+
end
|
217
|
+
|
218
|
+
after(:all) do
|
219
|
+
@conn.execute "DROP TABLE test_employees"
|
220
|
+
@conn.execute "DROP SEQUENCE test_employees_seq"
|
221
|
+
end
|
222
|
+
|
223
|
+
after(:each) do
|
224
|
+
Object.send(:remove_const, "TestEmployee")
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should ignore specified table columns" do
|
228
|
+
class ::TestEmployee < ActiveRecord::Base
|
229
|
+
ignore_table_columns :phone_number, :hire_date
|
230
|
+
end
|
231
|
+
TestEmployee.connection.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should ignore specified table columns specified in several lines" do
|
235
|
+
class ::TestEmployee < ActiveRecord::Base
|
236
|
+
ignore_table_columns :phone_number
|
237
|
+
ignore_table_columns :hire_date
|
238
|
+
end
|
239
|
+
TestEmployee.connection.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should not ignore unspecified table columns" do
|
243
|
+
class ::TestEmployee < ActiveRecord::Base
|
244
|
+
ignore_table_columns :phone_number, :hire_date
|
245
|
+
end
|
246
|
+
TestEmployee.connection.columns('test_employees').select{|c| c.name == 'email' }.should_not be_empty
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
describe "OracleEnhancedAdapter table and sequence creation with non-default primary key" do
|
253
|
+
|
254
|
+
before(:all) do
|
255
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
256
|
+
ActiveRecord::Schema.define do
|
257
|
+
suppress_messages do
|
258
|
+
create_table :keyboards, :force => true, :id => false do |t|
|
259
|
+
t.primary_key :key_number
|
260
|
+
t.string :name
|
261
|
+
end
|
262
|
+
create_table :id_keyboards, :force => true do |t|
|
263
|
+
t.string :name
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
class ::Keyboard < ActiveRecord::Base
|
268
|
+
set_primary_key :key_number
|
269
|
+
end
|
270
|
+
class ::IdKeyboard < ActiveRecord::Base
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
after(:all) do
|
275
|
+
ActiveRecord::Schema.define do
|
276
|
+
suppress_messages do
|
277
|
+
drop_table :keyboards
|
278
|
+
drop_table :id_keyboards
|
279
|
+
end
|
280
|
+
end
|
281
|
+
Object.send(:remove_const, "Keyboard")
|
282
|
+
Object.send(:remove_const, "IdKeyboard")
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should create sequence for non-default primary key" do
|
286
|
+
ActiveRecord::Base.connection.next_sequence_value(Keyboard.sequence_name).should_not be_nil
|
287
|
+
end
|
288
|
+
|
289
|
+
it "should create sequence for default primary key" do
|
290
|
+
ActiveRecord::Base.connection.next_sequence_value(IdKeyboard.sequence_name).should_not be_nil
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
describe "OracleEnhancedAdapter without composite_primary_keys" do
|
295
|
+
|
296
|
+
before(:all) do
|
297
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
298
|
+
Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
|
299
|
+
class ::Employee < ActiveRecord::Base
|
300
|
+
set_primary_key :employee_id
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should tell ActiveRecord that count distinct is supported" do
|
305
|
+
ActiveRecord::Base.connection.supports_count_distinct?.should be_true
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should execute correct SQL COUNT DISTINCT statement" do
|
309
|
+
lambda { Employee.count(:employee_id, :distinct => true) }.should_not raise_error
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
describe "OracleEnhancedAdapter sequence creation parameters" do
|
315
|
+
|
316
|
+
before(:all) do
|
317
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
318
|
+
end
|
319
|
+
|
320
|
+
def create_test_employees_table(sequence_start_value = nil)
|
321
|
+
ActiveRecord::Schema.define do
|
322
|
+
suppress_messages do
|
323
|
+
create_table :test_employees, sequence_start_value ? {:sequence_start_value => sequence_start_value} : {} do |t|
|
324
|
+
t.string :first_name
|
325
|
+
t.string :last_name
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def save_default_sequence_start_value
|
332
|
+
@saved_sequence_start_value = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value
|
333
|
+
end
|
334
|
+
|
335
|
+
def restore_default_sequence_start_value
|
336
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = @saved_sequence_start_value
|
337
|
+
end
|
338
|
+
|
339
|
+
before(:each) do
|
340
|
+
save_default_sequence_start_value
|
341
|
+
end
|
342
|
+
after(:each) do
|
343
|
+
restore_default_sequence_start_value
|
344
|
+
ActiveRecord::Schema.define do
|
345
|
+
suppress_messages do
|
346
|
+
drop_table :test_employees
|
347
|
+
end
|
348
|
+
end
|
349
|
+
Object.send(:remove_const, "TestEmployee")
|
350
|
+
end
|
351
|
+
|
352
|
+
it "should use default sequence start value 10000" do
|
353
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value.should == 10000
|
354
|
+
|
355
|
+
create_test_employees_table
|
356
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
357
|
+
|
358
|
+
employee = TestEmployee.create!
|
359
|
+
employee.id.should == 10000
|
360
|
+
end
|
361
|
+
|
362
|
+
it "should use specified default sequence start value" do
|
363
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = 1
|
364
|
+
|
365
|
+
create_test_employees_table
|
366
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
367
|
+
|
368
|
+
employee = TestEmployee.create!
|
369
|
+
employee.id.should == 1
|
370
|
+
end
|
371
|
+
|
372
|
+
it "should use sequence start value from table definition" do
|
373
|
+
create_test_employees_table(10)
|
374
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
375
|
+
|
376
|
+
employee = TestEmployee.create!
|
377
|
+
employee.id.should == 10
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should use sequence start value and other options from table definition" do
|
381
|
+
create_test_employees_table("100 NOCACHE INCREMENT BY 10")
|
382
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
383
|
+
|
384
|
+
employee = TestEmployee.create!
|
385
|
+
employee.id.should == 100
|
386
|
+
employee = TestEmployee.create!
|
387
|
+
employee.id.should == 110
|
388
|
+
end
|
389
|
+
|
390
|
+
end
|
391
|
+
|
392
|
+
describe "OracleEnhancedAdapter table and column comments" do
|
393
|
+
|
394
|
+
before(:all) do
|
395
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
396
|
+
@conn = ActiveRecord::Base.connection
|
397
|
+
end
|
398
|
+
|
399
|
+
def create_test_employees_table(table_comment=nil, column_comments={})
|
400
|
+
ActiveRecord::Schema.define do
|
401
|
+
suppress_messages do
|
402
|
+
create_table :test_employees, :comment => table_comment do |t|
|
403
|
+
t.string :first_name, :comment => column_comments[:first_name]
|
404
|
+
t.string :last_name, :comment => column_comments[:last_name]
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
after(:each) do
|
411
|
+
ActiveRecord::Schema.define do
|
412
|
+
suppress_messages do
|
413
|
+
drop_table :test_employees
|
414
|
+
end
|
415
|
+
end
|
416
|
+
Object.send(:remove_const, "TestEmployee")
|
417
|
+
ActiveRecord::Base.table_name_prefix = nil
|
418
|
+
end
|
419
|
+
|
420
|
+
it "should create table with table comment" do
|
421
|
+
table_comment = "Test Employees"
|
422
|
+
create_test_employees_table(table_comment)
|
423
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
424
|
+
|
425
|
+
@conn.table_comment("test_employees").should == table_comment
|
426
|
+
TestEmployee.table_comment.should == table_comment
|
427
|
+
end
|
428
|
+
|
429
|
+
it "should create table with columns comment" do
|
430
|
+
column_comments = {:first_name => "Given Name", :last_name => "Surname"}
|
431
|
+
create_test_employees_table(nil, column_comments)
|
432
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
433
|
+
|
434
|
+
[:first_name, :last_name].each do |attr|
|
435
|
+
@conn.column_comment("test_employees", attr.to_s).should == column_comments[attr]
|
436
|
+
end
|
437
|
+
[:first_name, :last_name].each do |attr|
|
438
|
+
TestEmployee.columns_hash[attr.to_s].comment.should == column_comments[attr]
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should create table with table and columns comment and custom table name prefix" do
|
443
|
+
ActiveRecord::Base.table_name_prefix = "xxx_"
|
444
|
+
table_comment = "Test Employees"
|
445
|
+
column_comments = {:first_name => "Given Name", :last_name => "Surname"}
|
446
|
+
create_test_employees_table(table_comment, column_comments)
|
447
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
448
|
+
|
449
|
+
@conn.table_comment(TestEmployee.table_name).should == table_comment
|
450
|
+
TestEmployee.table_comment.should == table_comment
|
451
|
+
[:first_name, :last_name].each do |attr|
|
452
|
+
@conn.column_comment(TestEmployee.table_name, attr.to_s).should == column_comments[attr]
|
453
|
+
end
|
454
|
+
[:first_name, :last_name].each do |attr|
|
455
|
+
TestEmployee.columns_hash[attr.to_s].comment.should == column_comments[attr]
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
end
|
460
|
+
|
461
|
+
describe "OracleEnhancedAdapter column quoting" do
|
462
|
+
|
463
|
+
before(:all) do
|
464
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
465
|
+
@conn = ActiveRecord::Base.connection
|
466
|
+
end
|
467
|
+
|
468
|
+
def create_test_reserved_words_table
|
469
|
+
ActiveRecord::Schema.define do
|
470
|
+
suppress_messages do
|
471
|
+
create_table :test_reserved_words do |t|
|
472
|
+
t.string :varchar2
|
473
|
+
t.integer :integer
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
after(:each) do
|
480
|
+
ActiveRecord::Schema.define do
|
481
|
+
suppress_messages do
|
482
|
+
drop_table :test_reserved_words
|
483
|
+
end
|
484
|
+
end
|
485
|
+
Object.send(:remove_const, "TestReservedWord")
|
486
|
+
ActiveRecord::Base.table_name_prefix = nil
|
487
|
+
end
|
488
|
+
|
489
|
+
it "should allow creation of a table with oracle reserved words as column names" do
|
490
|
+
create_test_reserved_words_table
|
491
|
+
class ::TestReservedWord < ActiveRecord::Base; end
|
492
|
+
|
493
|
+
[:varchar2, :integer].each do |attr|
|
494
|
+
TestReservedWord.columns_hash[attr.to_s].name.should == attr.to_s
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
end
|
499
|
+
|
500
|
+
describe "OracleEnhancedAdapter valid table names" do
|
501
|
+
before(:all) do
|
502
|
+
@adapter = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
|
503
|
+
end
|
504
|
+
it "should be valid with letters and digits" do
|
505
|
+
@adapter.valid_table_name?("abc_123").should be_true
|
506
|
+
end
|
507
|
+
|
508
|
+
it "should be valid with schema name" do
|
509
|
+
@adapter.valid_table_name?("abc_123.def_456").should be_true
|
510
|
+
end
|
511
|
+
|
512
|
+
it "should be valid with $ in name" do
|
513
|
+
@adapter.valid_table_name?("sys.v$session").should be_true
|
514
|
+
end
|
515
|
+
|
516
|
+
it "should not be valid with two dots in name" do
|
517
|
+
@adapter.valid_table_name?("abc_123.def_456.ghi_789").should be_false
|
518
|
+
end
|
519
|
+
|
520
|
+
it "should not be valid with invalid characters" do
|
521
|
+
@adapter.valid_table_name?("warehouse-things").should be_false
|
522
|
+
end
|
523
|
+
|
524
|
+
end
|
525
|
+
|
526
|
+
describe "OracleEnhancedAdapter table quoting" do
|
527
|
+
|
528
|
+
before(:all) do
|
529
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
530
|
+
@conn = ActiveRecord::Base.connection
|
531
|
+
end
|
532
|
+
|
533
|
+
def create_warehouse_things_table
|
534
|
+
ActiveRecord::Schema.define do
|
535
|
+
suppress_messages do
|
536
|
+
create_table "warehouse-things" do |t|
|
537
|
+
t.string :name
|
538
|
+
t.integer :foo
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
|
544
|
+
def create_camel_case_table
|
545
|
+
ActiveRecord::Schema.define do
|
546
|
+
suppress_messages do
|
547
|
+
create_table "CamelCase" do |t|
|
548
|
+
t.string :name
|
549
|
+
t.integer :foo
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
after(:each) do
|
556
|
+
ActiveRecord::Schema.define do
|
557
|
+
suppress_messages do
|
558
|
+
drop_table "warehouse-things" rescue nil
|
559
|
+
drop_table "CamelCase" rescue nil
|
560
|
+
end
|
561
|
+
end
|
562
|
+
Object.send(:remove_const, "WarehouseThing") rescue nil
|
563
|
+
Object.send(:remove_const, "CamelCase") rescue nil
|
564
|
+
end
|
565
|
+
|
566
|
+
it "should allow creation of a table with non alphanumeric characters" do
|
567
|
+
create_warehouse_things_table
|
568
|
+
class ::WarehouseThing < ActiveRecord::Base
|
569
|
+
set_table_name "warehouse-things"
|
570
|
+
end
|
571
|
+
|
572
|
+
wh = WarehouseThing.create!(:name => "Foo", :foo => 2)
|
573
|
+
wh.id.should_not be_nil
|
574
|
+
|
575
|
+
@conn.tables.should include("warehouse-things")
|
576
|
+
end
|
577
|
+
|
578
|
+
it "should allow creation of a table with CamelCase name" do
|
579
|
+
create_camel_case_table
|
580
|
+
class ::CamelCase < ActiveRecord::Base
|
581
|
+
set_table_name "CamelCase"
|
582
|
+
end
|
583
|
+
|
584
|
+
cc = CamelCase.create!(:name => "Foo", :foo => 2)
|
585
|
+
cc.id.should_not be_nil
|
586
|
+
|
587
|
+
@conn.tables.should include("CamelCase")
|
588
|
+
end
|
589
|
+
|
590
|
+
end
|
591
|
+
|
592
|
+
describe "OracleEnhancedAdapter create triggers" do
|
593
|
+
|
594
|
+
before(:all) do
|
595
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
596
|
+
@conn = ActiveRecord::Base.connection
|
597
|
+
ActiveRecord::Schema.define do
|
598
|
+
suppress_messages do
|
599
|
+
create_table :test_employees do |t|
|
600
|
+
t.string :first_name
|
601
|
+
t.string :last_name
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|
605
|
+
class ::TestEmployee < ActiveRecord::Base; end
|
606
|
+
end
|
607
|
+
|
608
|
+
after(:all) do
|
609
|
+
ActiveRecord::Schema.define do
|
610
|
+
suppress_messages do
|
611
|
+
drop_table :test_employees
|
612
|
+
end
|
613
|
+
end
|
614
|
+
Object.send(:remove_const, "TestEmployee")
|
615
|
+
end
|
616
|
+
|
617
|
+
it "should create table trigger with :new reference" do
|
618
|
+
lambda do
|
619
|
+
@conn.execute <<-SQL
|
620
|
+
CREATE OR REPLACE TRIGGER test_employees_pkt
|
621
|
+
BEFORE INSERT ON test_employees FOR EACH ROW
|
622
|
+
BEGIN
|
623
|
+
IF inserting THEN
|
624
|
+
IF :new.id IS NULL THEN
|
625
|
+
SELECT test_employees_seq.NEXTVAL INTO :new.id FROM dual;
|
626
|
+
END IF;
|
627
|
+
END IF;
|
628
|
+
END;
|
629
|
+
SQL
|
630
|
+
end.should_not raise_error
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
describe "OracleEnhancedAdapter add index" do
|
635
|
+
|
636
|
+
before(:all) do
|
637
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
638
|
+
@conn = ActiveRecord::Base.connection
|
639
|
+
end
|
640
|
+
|
641
|
+
it "should return default index name if it is not larger than 30 characters" do
|
642
|
+
@conn.index_name("employees", :column => "first_name").should == "index_employees_on_first_name"
|
643
|
+
end
|
644
|
+
|
645
|
+
it "should return shortened index name by removing 'index', 'on' and 'and' keywords" do
|
646
|
+
@conn.index_name("employees", :column => ["first_name", "email"]).should == "i_employees_first_name_email"
|
647
|
+
end
|
648
|
+
|
649
|
+
it "should return shortened index name by shortening table and column names" do
|
650
|
+
@conn.index_name("employees", :column => ["first_name", "last_name"]).should == "i_emp_fir_nam_las_nam"
|
651
|
+
end
|
652
|
+
|
653
|
+
it "should raise error if too large index name cannot be shortened" do
|
654
|
+
lambda do
|
655
|
+
@conn.index_name("test_employees", :column => ["first_name", "middle_name", "last_name"])
|
656
|
+
end.should raise_error(ArgumentError)
|
657
|
+
end
|
658
|
+
|
659
|
+
end
|