rwc9u-activerecord-oracle_enhanced-adapter 1.1.9.5 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (22) hide show
  1. data/History.txt +11 -0
  2. data/Manifest.txt +6 -0
  3. data/README.txt +6 -2
  4. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +757 -909
  5. data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +71 -0
  6. data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +64 -0
  7. data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +2 -2
  8. data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +352 -0
  9. data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +346 -0
  10. data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +2 -1
  11. data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +2 -2
  12. data/oracle-enhanced.gemspec +32 -8
  13. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +111 -93
  14. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +170 -0
  15. data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +40 -0
  16. data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +11 -6
  17. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +148 -53
  18. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +13 -5
  19. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +12 -6
  20. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +10 -6
  21. data/spec/spec_helper.rb +51 -6
  22. metadata +13 -6
@@ -0,0 +1,346 @@
1
+ require 'delegate'
2
+
3
+ begin
4
+ require 'oci8' unless self.class.const_defined? :OCI8
5
+
6
+ # RSI: added mapping for TIMESTAMP / WITH TIME ZONE / LOCAL TIME ZONE types
7
+ # currently Ruby-OCI8 does not support fractional seconds for timestamps
8
+ OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP] = OCI8::BindType::OraDate
9
+ OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_TZ] = OCI8::BindType::OraDate
10
+ OCI8::BindType::Mapping[OCI8::SQLT_TIMESTAMP_LTZ] = OCI8::BindType::OraDate
11
+ rescue LoadError
12
+ # OCI8 driver is unavailable.
13
+ error_message = "ERROR: ActiveRecord oracle_enhanced adapter could not load ruby-oci8 library. "+
14
+ "Please install ruby-oci8 library or gem."
15
+ if defined?(RAILS_DEFAULT_LOGGER)
16
+ RAILS_DEFAULT_LOGGER.error error_message
17
+ else
18
+ STDERR.puts error_message
19
+ end
20
+ raise LoadError
21
+ end
22
+
23
+ module ActiveRecord
24
+ module ConnectionAdapters
25
+
26
+ # OCI database interface for MRI
27
+ class OracleEnhancedOCIConnection < OracleEnhancedConnection
28
+
29
+ def initialize(config)
30
+ @raw_connection = OCI8EnhancedAutoRecover.new(config, OracleEnhancedOCIFactory)
31
+ end
32
+
33
+ def auto_retry
34
+ @raw_connection.auto_retry if @raw_connection
35
+ end
36
+
37
+ def auto_retry=(value)
38
+ @raw_connection.auto_retry = value if @raw_connection
39
+ end
40
+
41
+ def logoff
42
+ @raw_connection.logoff
43
+ @raw_connection.active = false
44
+ end
45
+
46
+ def commit
47
+ @raw_connection.commit
48
+ end
49
+
50
+ def rollback
51
+ @raw_connection.rollback
52
+ end
53
+
54
+ def autocommit?
55
+ @raw_connection.autocommit?
56
+ end
57
+
58
+ def autocommit=(value)
59
+ @raw_connection.autocommit = value
60
+ end
61
+
62
+ # Checks connection, returns true if active. Note that ping actively
63
+ # checks the connection, while #active? simply returns the last
64
+ # known state.
65
+ def ping
66
+ @raw_connection.ping
67
+ rescue OCIException => e
68
+ raise OracleEnhancedConnectionException, e.message
69
+ end
70
+
71
+ def active?
72
+ @raw_connection.active?
73
+ end
74
+
75
+ def reset!
76
+ @raw_connection.reset!
77
+ rescue OCIException => e
78
+ raise OracleEnhancedConnectionException, e.message
79
+ end
80
+
81
+ def exec(sql, *bindvars, &block)
82
+ @raw_connection.exec(sql, *bindvars, &block)
83
+ end
84
+
85
+ def select(sql, name = nil, return_column_names = false)
86
+ cursor = @raw_connection.exec(sql)
87
+ cols = cursor.get_col_names.map { |x| oracle_downcase(x) }
88
+ rows = []
89
+
90
+ while row = cursor.fetch
91
+ hash = Hash.new
92
+
93
+ cols.each_with_index do |col, i|
94
+ hash[col] =
95
+ case row[i]
96
+ when OCI8::LOB
97
+ if name == 'Writable Large Object'
98
+ row[i]
99
+ else
100
+ data = row[i].read
101
+ # In Ruby 1.9.1 always change encoding to ASCII-8BIT for binaries
102
+ data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding) && row[i].is_a?(OCI8::BLOB)
103
+ data
104
+ end
105
+ # ruby-oci8 1.0 returns OraDate
106
+ when OraDate
107
+ d = row[i]
108
+ # RSI: added emulate_dates_by_column_name functionality
109
+ # if emulate_dates_by_column_name && self.class.is_date_column?(col)
110
+ # d.to_date
111
+ # elsif
112
+ if OracleEnhancedAdapter.emulate_dates && (d.hour == 0 && d.minute == 0 && d.second == 0)
113
+ d.to_date
114
+ else
115
+ # code from Time.time_with_datetime_fallback
116
+ begin
117
+ Time.send(Base.default_timezone, d.year, d.month, d.day, d.hour, d.minute, d.second)
118
+ rescue
119
+ offset = Base.default_timezone.to_sym == :local ? ::DateTime.local_offset : 0
120
+ ::DateTime.civil(d.year, d.month, d.day, d.hour, d.minute, d.second, offset)
121
+ end
122
+ end
123
+ # ruby-oci8 2.0 returns Time or DateTime
124
+ when Time, DateTime
125
+ d = row[i]
126
+ if OracleEnhancedAdapter.emulate_dates && (d.hour == 0 && d.min == 0 && d.sec == 0)
127
+ d.to_date
128
+ else
129
+ # recreate Time or DateTime using Base.default_timezone
130
+ begin
131
+ Time.send(Base.default_timezone, d.year, d.month, d.day, d.hour, d.min, d.sec)
132
+ rescue
133
+ offset = Base.default_timezone.to_sym == :local ? ::DateTime.local_offset : 0
134
+ ::DateTime.civil(d.year, d.month, d.day, d.hour, d.min, d.sec, offset)
135
+ end
136
+ end
137
+ # RSI: added emulate_integers_by_column_name functionality
138
+ when Float
139
+ n = row[i]
140
+ if OracleEnhancedAdapter.emulate_integers_by_column_name && OracleEnhancedAdapter.is_integer_column?(col)
141
+ n.to_i
142
+ else
143
+ n
144
+ end
145
+ # ruby-oci8 2.0 returns OraNumber - convert it to Integer or BigDecimal
146
+ when OraNumber
147
+ n = row[i]
148
+ n == (n_to_i = n.to_i) ? n_to_i : BigDecimal.new(n.to_s)
149
+ else row[i]
150
+ end unless col == 'raw_rnum_'
151
+ end
152
+
153
+ rows << hash
154
+ end
155
+
156
+ return_column_names ? [rows, cols] : rows
157
+ ensure
158
+ cursor.close if cursor
159
+ end
160
+
161
+ def write_lob(lob, value, is_binary = false)
162
+ lob.write value
163
+ end
164
+
165
+ def describe(name)
166
+ quoted_name = OracleEnhancedAdapter.valid_table_name?(name) ? name : "\"#{name}\""
167
+ @raw_connection.describe(quoted_name)
168
+ rescue OCIException => e
169
+ raise OracleEnhancedConnectionException, e.message
170
+ end
171
+
172
+ end
173
+
174
+ # The OracleEnhancedOCIFactory factors out the code necessary to connect and
175
+ # configure an Oracle/OCI connection.
176
+ class OracleEnhancedOCIFactory #:nodoc:
177
+ def self.new_connection(config)
178
+ username, password, database = config[:username].to_s, config[:password].to_s, config[:database].to_s
179
+ privilege = config[:privilege] && config[:privilege].to_sym
180
+ async = config[:allow_concurrency]
181
+ prefetch_rows = config[:prefetch_rows] || 100
182
+ cursor_sharing = config[:cursor_sharing] || 'similar'
183
+
184
+ conn = OCI8.new username, password, database, privilege
185
+ conn.exec %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
186
+ conn.exec %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'} rescue nil
187
+ conn.autocommit = true
188
+ conn.non_blocking = true if async
189
+ conn.prefetch_rows = prefetch_rows
190
+ conn.exec "alter session set cursor_sharing = #{cursor_sharing}" rescue nil
191
+ conn
192
+ end
193
+ end
194
+
195
+
196
+ end
197
+ end
198
+
199
+
200
+
201
+ class OCI8 #:nodoc:
202
+
203
+ class Cursor #:nodoc:
204
+ if method_defined? :define_a_column
205
+ # This OCI8 patch is required with the ruby-oci8 1.0.x or lower.
206
+ # Set OCI8::BindType::Mapping[] to change the column type
207
+ # when using ruby-oci8 2.0.
208
+
209
+ alias :enhanced_define_a_column_pre_ar :define_a_column
210
+ def define_a_column(i)
211
+ case do_ocicall(@ctx) { @parms[i - 1].attrGet(OCI_ATTR_DATA_TYPE) }
212
+ when 8; @stmt.defineByPos(i, String, 65535) # Read LONG values
213
+ when 187; @stmt.defineByPos(i, OraDate) # Read TIMESTAMP values
214
+ when 108
215
+ if @parms[i - 1].attrGet(OCI_ATTR_TYPE_NAME) == 'XMLTYPE'
216
+ @stmt.defineByPos(i, String, 65535)
217
+ else
218
+ raise 'unsupported datatype'
219
+ end
220
+ else enhanced_define_a_column_pre_ar i
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ if OCI8.public_method_defined?(:describe_table)
227
+ # ruby-oci8 2.0 or upper
228
+
229
+ def describe(name)
230
+ info = describe_table(name.to_s)
231
+ raise %Q{"DESC #{name}" failed} if info.nil?
232
+ [info.obj_schema, info.obj_name]
233
+ end
234
+ else
235
+ # ruby-oci8 1.0.x or lower
236
+
237
+ # missing constant from oci8 < 0.1.14
238
+ OCI_PTYPE_UNK = 0 unless defined?(OCI_PTYPE_UNK)
239
+
240
+ # Uses the describeAny OCI call to find the target owner and table_name
241
+ # indicated by +name+, parsing through synonynms as necessary. Returns
242
+ # an array of [owner, table_name].
243
+ def describe(name)
244
+ @desc ||= @@env.alloc(OCIDescribe)
245
+ @desc.attrSet(OCI_ATTR_DESC_PUBLIC, -1) if VERSION >= '0.1.14'
246
+ do_ocicall(@ctx) { @desc.describeAny(@svc, name.to_s, OCI_PTYPE_UNK) } rescue raise %Q{"DESC #{name}" failed; does it exist?}
247
+ info = @desc.attrGet(OCI_ATTR_PARAM)
248
+
249
+ case info.attrGet(OCI_ATTR_PTYPE)
250
+ when OCI_PTYPE_TABLE, OCI_PTYPE_VIEW
251
+ owner = info.attrGet(OCI_ATTR_OBJ_SCHEMA)
252
+ table_name = info.attrGet(OCI_ATTR_OBJ_NAME)
253
+ [owner, table_name]
254
+ when OCI_PTYPE_SYN
255
+ schema = info.attrGet(OCI_ATTR_SCHEMA_NAME)
256
+ name = info.attrGet(OCI_ATTR_NAME)
257
+ describe(schema + '.' + name)
258
+ else raise %Q{"DESC #{name}" failed; not a table or view.}
259
+ end
260
+ end
261
+ end
262
+
263
+ end
264
+
265
+ # The OCI8AutoRecover class enhances the OCI8 driver with auto-recover and
266
+ # reset functionality. If a call to #exec fails, and autocommit is turned on
267
+ # (ie., we're not in the middle of a longer transaction), it will
268
+ # automatically reconnect and try again. If autocommit is turned off,
269
+ # this would be dangerous (as the earlier part of the implied transaction
270
+ # may have failed silently if the connection died) -- so instead the
271
+ # connection is marked as dead, to be reconnected on it's next use.
272
+ class OCI8EnhancedAutoRecover < DelegateClass(OCI8) #:nodoc:
273
+ attr_accessor :active
274
+ alias :active? :active
275
+
276
+ cattr_accessor :auto_retry
277
+ class << self
278
+ alias :auto_retry? :auto_retry
279
+ end
280
+ @@auto_retry = false
281
+
282
+ def initialize(config, factory)
283
+ @active = true
284
+ @config = config
285
+ @factory = factory
286
+ @connection = @factory.new_connection @config
287
+ super @connection
288
+ end
289
+
290
+ # Checks connection, returns true if active. Note that ping actively
291
+ # checks the connection, while #active? simply returns the last
292
+ # known state.
293
+ def ping
294
+ @connection.exec("select 1 from dual") { |r| nil }
295
+ @active = true
296
+ rescue
297
+ @active = false
298
+ raise
299
+ end
300
+
301
+ # Resets connection, by logging off and creating a new connection.
302
+ def reset!
303
+ logoff rescue nil
304
+ begin
305
+ @connection = @factory.new_connection @config
306
+ __setobj__ @connection
307
+ @active = true
308
+ rescue
309
+ @active = false
310
+ raise
311
+ end
312
+ end
313
+
314
+ # ORA-00028: your session has been killed
315
+ # ORA-01012: not logged on
316
+ # ORA-03113: end-of-file on communication channel
317
+ # ORA-03114: not connected to ORACLE
318
+ # ORA-03135: connection lost contact
319
+ LOST_CONNECTION_ERROR_CODES = [ 28, 1012, 3113, 3114, 3135 ]
320
+
321
+ # Adds auto-recovery functionality.
322
+ #
323
+ # See: http://www.jiubao.org/ruby-oci8/api.en.html#label-11
324
+ def exec(sql, *bindvars, &block)
325
+ should_retry = self.class.auto_retry? && autocommit?
326
+
327
+ begin
328
+ @connection.exec(sql, *bindvars, &block)
329
+ rescue OCIException => e
330
+ raise unless LOST_CONNECTION_ERROR_CODES.include?(e.code)
331
+ @active = false
332
+ raise unless should_retry
333
+ should_retry = false
334
+ reset! rescue nil
335
+ retry
336
+ end
337
+ end
338
+
339
+ # RSI: otherwise not working in Ruby 1.9.1
340
+ if RUBY_VERSION =~ /^1\.9/
341
+ def describe(name)
342
+ @connection.describe(name)
343
+ end
344
+ end
345
+
346
+ end
@@ -40,7 +40,8 @@ module ActiveRecord #:nodoc:
40
40
  base.instance_eval do
41
41
  alias_method_chain :create, :custom_method
42
42
  # insert after dirty checking in Rails 2.1
43
- if private_instance_methods.include?('update_without_dirty')
43
+ # in Ruby 1.9 methods names are returned as symbols
44
+ if private_instance_methods.include?('update_without_dirty') || private_instance_methods.include?(:update_without_dirty)
44
45
  alias_method :update_without_custom_method, :update_without_dirty
45
46
  alias_method :update_without_dirty, :update_with_custom_method
46
47
  else
@@ -2,8 +2,8 @@ module ActiveRecord #:nodoc:
2
2
  module ConnectionAdapters #:nodoc:
3
3
  module OracleEnhancedVersion #:nodoc:
4
4
  MAJOR = 1
5
- MINOR = 1
6
- TINY = 9
5
+ MINOR = 2
6
+ TINY = 0
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
9
9
  end
@@ -1,16 +1,40 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{activerecord-oracle_enhanced-adapter}
5
- s.version = "1.1.9.5"
5
+ s.version = "1.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["Raimonds Simanovskis (patched by Rob Christie"]
9
- s.date = %q{2009-01-21}
10
- s.description = %q{Oracle enhanced adapter for Active Record. Additional patches to support ActiveRecord unit tests}
11
- s.email = ["robchristie@gmail.com"]
8
+ s.authors = ["Raimonds Simanovskis"]
9
+ s.date = %q{2009-03-22}
10
+ s.description = %q{Oracle enhanced adapter for ActiveRecord}
11
+ s.email = ["raimonds.simanovskis@gmail.com"]
12
12
  s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.txt"]
13
- s.files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "lib/active_record/connection_adapters/emulation/oracle_adapter.rb", "lib/active_record/connection_adapters/oracle_enhanced.rake", "lib/active_record/connection_adapters/oracle_enhanced_adapter.rb", "lib/active_record/connection_adapters/oracle_enhanced_cpk.rb", "lib/active_record/connection_adapters/oracle_enhanced_dirty.rb", "lib/active_record/connection_adapters/oracle_enhanced_procedures.rb", "lib/active_record/connection_adapters/oracle_enhanced_reserved_words.rb", "lib/active_record/connection_adapters/oracle_enhanced_tasks.rb", "lib/active_record/connection_adapters/oracle_enhanced_version.rb", "oracle-enhanced.gemspec", "spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb", "spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb", "spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb", "spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb", "spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb", "spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb", "spec/spec.opts", "spec/spec_helper.rb"]
13
+ s.files = ["History.txt", "License.txt", "Manifest.txt", "README.txt",
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"]
14
38
  s.has_rdoc = true
15
39
  s.homepage = %q{http://oracle-enhanced.rubyforge.org}
16
40
  s.post_install_message = %q{}
@@ -18,7 +42,7 @@ Gem::Specification.new do |s|
18
42
  s.require_paths = ["lib"]
19
43
  s.rubyforge_project = %q{oracle-enhanced}
20
44
  s.rubygems_version = %q{1.3.1}
21
- s.summary = %q{Oracle enhanced adapter for Active Record}
45
+ s.summary = %q{Oracle enhanced adapter for ActiveRecord}
22
46
 
23
47
  if s.respond_to? :specification_version then
24
48
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -3,61 +3,75 @@ require File.dirname(__FILE__) + '/../../spec_helper.rb'
3
3
  describe "OracleEnhancedAdapter establish connection" do
4
4
 
5
5
  it "should connect to database" do
6
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
7
- :database => "xe",
8
- :username => "hr",
9
- :password => "hr")
6
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
10
7
  ActiveRecord::Base.connection.should_not be_nil
11
8
  ActiveRecord::Base.connection.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
12
9
  end
13
10
 
14
11
  it "should connect to database as SYSDBA" do
15
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
16
- :database => "xe",
17
- :username => "sys",
18
- :password => "manager",
19
- :privilege => :SYSDBA)
12
+ ActiveRecord::Base.establish_connection(SYS_CONNECTION_PARAMS)
20
13
  ActiveRecord::Base.connection.should_not be_nil
21
14
  ActiveRecord::Base.connection.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
22
15
  end
23
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
+
24
34
  end
25
35
 
26
36
  describe "OracleEnhancedAdapter schema dump" do
27
37
 
28
38
  before(:all) do
29
- @old_conn = ActiveRecord::Base.oracle_connection(
30
- :database => "xe",
31
- :username => "hr",
32
- :password => "hr")
33
- @old_conn.class.should == ActiveRecord::ConnectionAdapters::OracleAdapter
34
- @new_conn = ActiveRecord::Base.oracle_enhanced_connection(
35
- :database => "xe",
36
- :username => "hr",
37
- :password => "hr")
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)
38
48
  @new_conn.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
39
49
  end
40
50
 
41
- it "should return the same tables list as original oracle adapter" do
42
- @new_conn.tables.should == @old_conn.tables
43
- end
51
+ unless defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION =~ /^1\.9/
52
+ it "should return the same tables list as original oracle adapter" do
53
+ @new_conn.tables.sort.should == @old_conn.tables.sort
54
+ end
44
55
 
45
- it "should return the same index list as original oracle adapter" do
46
- @new_conn.indexes('employees').should == @old_conn.indexes('employees')
47
- end
56
+ it "should return the same index list as original oracle adapter" do
57
+ @new_conn.indexes('employees').sort_by(&:name).should == @old_conn.indexes('employees').sort_by(&:name)
58
+ end
48
59
 
49
- it "should return the same pk_and_sequence_for as original oracle adapter" do
50
- @new_conn.tables.each do |t|
51
- @new_conn.pk_and_sequence_for(t).should == @old_conn.pk_and_sequence_for(t)
60
+ it "should return the same pk_and_sequence_for as original oracle adapter" do
61
+ if @old_conn.respond_to?(:pk_and_sequence_for)
62
+ @new_conn.tables.each do |t|
63
+ @new_conn.pk_and_sequence_for(t).should == @old_conn.pk_and_sequence_for(t)
64
+ end
65
+ end
52
66
  end
53
- end
54
67
 
55
- it "should return the same structure dump as original oracle adapter" do
56
- @new_conn.structure_dump.should == @old_conn.structure_dump
57
- end
68
+ it "should return the same structure dump as original oracle adapter" do
69
+ @new_conn.structure_dump.should == @old_conn.structure_dump
70
+ end
58
71
 
59
- it "should return the same structure drop as original oracle adapter" do
60
- @new_conn.structure_drop.should == @old_conn.structure_drop
72
+ it "should return the same structure drop as original oracle adapter" do
73
+ @new_conn.structure_drop.should == @old_conn.structure_drop
74
+ end
61
75
  end
62
76
 
63
77
  it "should return the character size of nvarchar fields" do
@@ -75,10 +89,7 @@ end
75
89
 
76
90
  describe "OracleEnhancedAdapter database stucture dump extentions" do
77
91
  before(:all) do
78
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
79
- :database => "xe",
80
- :username => "hr",
81
- :password => "hr")
92
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
82
93
  @conn = ActiveRecord::Base.connection
83
94
  @conn.execute <<-SQL
84
95
  CREATE TABLE nvarchartable (
@@ -100,10 +111,7 @@ end
100
111
 
101
112
  describe "OracleEnhancedAdapter database session store" do
102
113
  before(:all) do
103
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
104
- :database => "xe",
105
- :username => "hr",
106
- :password => "hr")
114
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
107
115
  @conn = ActiveRecord::Base.connection
108
116
  @conn.execute <<-SQL
109
117
  CREATE TABLE sessions (
@@ -119,6 +127,11 @@ describe "OracleEnhancedAdapter database session store" do
119
127
  CREATE SEQUENCE sessions_seq MINVALUE 1 MAXVALUE 999999999999999999999999999
120
128
  INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
121
129
  SQL
130
+ if ENV['RAILS_GEM_VERSION'] >= '2.3'
131
+ @session_class = ActiveRecord::SessionStore::Session
132
+ else
133
+ @session_class = CGI::Session::ActiveRecordStore::Session
134
+ end
122
135
  end
123
136
 
124
137
  after(:all) do
@@ -131,29 +144,29 @@ describe "OracleEnhancedAdapter database session store" do
131
144
  end
132
145
 
133
146
  it "should save session data" do
134
- @session = CGI::Session::ActiveRecordStore::Session.new :session_id => "111111", :data => "something" #, :updated_at => Time.now
147
+ @session = @session_class.new :session_id => "111111", :data => "something" #, :updated_at => Time.now
135
148
  @session.save!
136
- @session = CGI::Session::ActiveRecordStore::Session.find_by_session_id("111111")
149
+ @session = @session_class.find_by_session_id("111111")
137
150
  @session.data.should == "something"
138
151
  end
139
152
 
140
153
  it "should change session data when partial updates enabled" do
141
- return pending("Not in this ActiveRecord version") unless CGI::Session::ActiveRecordStore::Session.respond_to?(:partial_updates=)
142
- CGI::Session::ActiveRecordStore::Session.partial_updates = true
143
- @session = CGI::Session::ActiveRecordStore::Session.new :session_id => "222222", :data => "something" #, :updated_at => Time.now
154
+ return pending("Not in this ActiveRecord version") unless @session_class.respond_to?(:partial_updates=)
155
+ @session_class.partial_updates = true
156
+ @session = @session_class.new :session_id => "222222", :data => "something" #, :updated_at => Time.now
144
157
  @session.save!
145
- @session = CGI::Session::ActiveRecordStore::Session.find_by_session_id("222222")
158
+ @session = @session_class.find_by_session_id("222222")
146
159
  @session.data = "other thing"
147
160
  @session.save!
148
161
  # second save should call again blob writing callback
149
162
  @session.save!
150
- @session = CGI::Session::ActiveRecordStore::Session.find_by_session_id("222222")
163
+ @session = @session_class.find_by_session_id("222222")
151
164
  @session.data.should == "other thing"
152
165
  end
153
166
 
154
167
  it "should have one enhanced_write_lobs callback" do
155
- return pending("Not in this ActiveRecord version") unless CGI::Session::ActiveRecordStore::Session.respond_to?(:after_save_callback_chain)
156
- CGI::Session::ActiveRecordStore::Session.after_save_callback_chain.select{|cb| cb.method == :enhanced_write_lobs}.should have(1).record
168
+ return pending("Not in this ActiveRecord version") unless @session_class.respond_to?(:after_save_callback_chain)
169
+ @session_class.after_save_callback_chain.select{|cb| cb.method == :enhanced_write_lobs}.should have(1).record
157
170
  end
158
171
 
159
172
  it "should not set sessions table session_id column type as integer if emulate_integers_by_column_name is true" do
@@ -167,10 +180,7 @@ end
167
180
 
168
181
  describe "OracleEnhancedAdapter ignore specified table columns" do
169
182
  before(:all) do
170
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
171
- :database => "xe",
172
- :username => "hr",
173
- :password => "hr")
183
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
174
184
  @conn = ActiveRecord::Base.connection
175
185
  @conn.execute <<-SQL
176
186
  CREATE TABLE test_employees (
@@ -204,14 +214,14 @@ describe "OracleEnhancedAdapter ignore specified table columns" do
204
214
  end
205
215
 
206
216
  it "should ignore specified table columns" do
207
- class TestEmployee < ActiveRecord::Base
217
+ class ::TestEmployee < ActiveRecord::Base
208
218
  ignore_table_columns :phone_number, :hire_date
209
219
  end
210
220
  TestEmployee.connection.columns('test_employees').select{|c| ['phone_number','hire_date'].include?(c.name) }.should be_empty
211
221
  end
212
222
 
213
223
  it "should ignore specified table columns specified in several lines" do
214
- class TestEmployee < ActiveRecord::Base
224
+ class ::TestEmployee < ActiveRecord::Base
215
225
  ignore_table_columns :phone_number
216
226
  ignore_table_columns :hire_date
217
227
  end
@@ -219,7 +229,7 @@ describe "OracleEnhancedAdapter ignore specified table columns" do
219
229
  end
220
230
 
221
231
  it "should not ignore unspecified table columns" do
222
- class TestEmployee < ActiveRecord::Base
232
+ class ::TestEmployee < ActiveRecord::Base
223
233
  ignore_table_columns :phone_number, :hire_date
224
234
  end
225
235
  TestEmployee.connection.columns('test_employees').select{|c| c.name == 'email' }.should_not be_empty
@@ -231,10 +241,7 @@ end
231
241
  describe "OracleEnhancedAdapter table and sequence creation with non-default primary key" do
232
242
 
233
243
  before(:all) do
234
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
235
- :database => "xe",
236
- :username => "hr",
237
- :password => "hr")
244
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
238
245
  ActiveRecord::Schema.define do
239
246
  suppress_messages do
240
247
  create_table :keyboards, :force => true, :id => false do |t|
@@ -246,10 +253,10 @@ describe "OracleEnhancedAdapter table and sequence creation with non-default pri
246
253
  end
247
254
  end
248
255
  end
249
- class Keyboard < ActiveRecord::Base
256
+ class ::Keyboard < ActiveRecord::Base
250
257
  set_primary_key :key_number
251
258
  end
252
- class IdKeyboard < ActiveRecord::Base
259
+ class ::IdKeyboard < ActiveRecord::Base
253
260
  end
254
261
  end
255
262
 
@@ -276,12 +283,9 @@ end
276
283
  describe "OracleEnhancedAdapter without composite_primary_keys" do
277
284
 
278
285
  before(:all) do
279
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
280
- :database => "xe",
281
- :username => "hr",
282
- :password => "hr")
286
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
283
287
  Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
284
- class Employee < ActiveRecord::Base
288
+ class ::Employee < ActiveRecord::Base
285
289
  set_primary_key :employee_id
286
290
  end
287
291
  end
@@ -299,10 +303,7 @@ end
299
303
  describe "OracleEnhancedAdapter sequence creation parameters" do
300
304
 
301
305
  before(:all) do
302
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
303
- :database => "xe",
304
- :username => "hr",
305
- :password => "hr")
306
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
306
307
  end
307
308
 
308
309
  def create_test_employees_table(sequence_start_value = nil)
@@ -341,7 +342,7 @@ describe "OracleEnhancedAdapter sequence creation parameters" do
341
342
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value.should == 10000
342
343
 
343
344
  create_test_employees_table
344
- class TestEmployee < ActiveRecord::Base; end
345
+ class ::TestEmployee < ActiveRecord::Base; end
345
346
 
346
347
  employee = TestEmployee.create!
347
348
  employee.id.should == 10000
@@ -351,7 +352,7 @@ describe "OracleEnhancedAdapter sequence creation parameters" do
351
352
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = 1
352
353
 
353
354
  create_test_employees_table
354
- class TestEmployee < ActiveRecord::Base; end
355
+ class ::TestEmployee < ActiveRecord::Base; end
355
356
 
356
357
  employee = TestEmployee.create!
357
358
  employee.id.should == 1
@@ -359,7 +360,7 @@ describe "OracleEnhancedAdapter sequence creation parameters" do
359
360
 
360
361
  it "should use sequence start value from table definition" do
361
362
  create_test_employees_table(10)
362
- class TestEmployee < ActiveRecord::Base; end
363
+ class ::TestEmployee < ActiveRecord::Base; end
363
364
 
364
365
  employee = TestEmployee.create!
365
366
  employee.id.should == 10
@@ -367,7 +368,7 @@ describe "OracleEnhancedAdapter sequence creation parameters" do
367
368
 
368
369
  it "should use sequence start value and other options from table definition" do
369
370
  create_test_employees_table("100 NOCACHE INCREMENT BY 10")
370
- class TestEmployee < ActiveRecord::Base; end
371
+ class ::TestEmployee < ActiveRecord::Base; end
371
372
 
372
373
  employee = TestEmployee.create!
373
374
  employee.id.should == 100
@@ -380,10 +381,7 @@ end
380
381
  describe "OracleEnhancedAdapter table and column comments" do
381
382
 
382
383
  before(:all) do
383
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
384
- :database => "xe",
385
- :username => "hr",
386
- :password => "hr")
384
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
387
385
  @conn = ActiveRecord::Base.connection
388
386
  end
389
387
 
@@ -411,7 +409,7 @@ describe "OracleEnhancedAdapter table and column comments" do
411
409
  it "should create table with table comment" do
412
410
  table_comment = "Test Employees"
413
411
  create_test_employees_table(table_comment)
414
- class TestEmployee < ActiveRecord::Base; end
412
+ class ::TestEmployee < ActiveRecord::Base; end
415
413
 
416
414
  @conn.table_comment("test_employees").should == table_comment
417
415
  TestEmployee.table_comment.should == table_comment
@@ -420,7 +418,7 @@ describe "OracleEnhancedAdapter table and column comments" do
420
418
  it "should create table with columns comment" do
421
419
  column_comments = {:first_name => "Given Name", :last_name => "Surname"}
422
420
  create_test_employees_table(nil, column_comments)
423
- class TestEmployee < ActiveRecord::Base; end
421
+ class ::TestEmployee < ActiveRecord::Base; end
424
422
 
425
423
  [:first_name, :last_name].each do |attr|
426
424
  @conn.column_comment("test_employees", attr.to_s).should == column_comments[attr]
@@ -435,7 +433,7 @@ describe "OracleEnhancedAdapter table and column comments" do
435
433
  table_comment = "Test Employees"
436
434
  column_comments = {:first_name => "Given Name", :last_name => "Surname"}
437
435
  create_test_employees_table(table_comment, column_comments)
438
- class TestEmployee < ActiveRecord::Base; end
436
+ class ::TestEmployee < ActiveRecord::Base; end
439
437
 
440
438
  @conn.table_comment(TestEmployee.table_name).should == table_comment
441
439
  TestEmployee.table_comment.should == table_comment
@@ -452,10 +450,7 @@ end
452
450
  describe "OracleEnhancedAdapter column quoting" do
453
451
 
454
452
  before(:all) do
455
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
456
- :database => "xe",
457
- :username => "hr",
458
- :password => "hr")
453
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
459
454
  @conn = ActiveRecord::Base.connection
460
455
  end
461
456
 
@@ -482,7 +477,7 @@ describe "OracleEnhancedAdapter column quoting" do
482
477
 
483
478
  it "should allow creation of a table with oracle reserved words as column names" do
484
479
  create_test_reserved_words_table
485
- class TestReservedWord < ActiveRecord::Base; end
480
+ class ::TestReservedWord < ActiveRecord::Base; end
486
481
 
487
482
  [:varchar2, :integer].each do |attr|
488
483
  TestReservedWord.columns_hash[attr.to_s].name.should == attr.to_s
@@ -491,13 +486,36 @@ describe "OracleEnhancedAdapter column quoting" do
491
486
 
492
487
  end
493
488
 
489
+ describe "OracleEnhancedAdapter valid table names" do
490
+ before(:all) do
491
+ @adapter = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
492
+ end
493
+ it "should be valid with letters and digits" do
494
+ @adapter.valid_table_name?("abc_123").should be_true
495
+ end
496
+
497
+ it "should be valid with schema name" do
498
+ @adapter.valid_table_name?("abc_123.def_456").should be_true
499
+ end
500
+
501
+ it "should be valid with $ in name" do
502
+ @adapter.valid_table_name?("sys.v$session").should be_true
503
+ end
504
+
505
+ it "should not be valid with two dots in name" do
506
+ @adapter.valid_table_name?("abc_123.def_456.ghi_789").should be_false
507
+ end
508
+
509
+ it "should not be valid with invalid characters" do
510
+ @adapter.valid_table_name?("warehouse-things").should be_false
511
+ end
512
+
513
+ end
514
+
494
515
  describe "OracleEnhancedAdapter table quoting" do
495
516
 
496
517
  before(:all) do
497
- ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
498
- :database => "xe",
499
- :username => "hr",
500
- :password => "hr")
518
+ ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
501
519
  @conn = ActiveRecord::Base.connection
502
520
  end
503
521
 
@@ -524,7 +542,7 @@ describe "OracleEnhancedAdapter table quoting" do
524
542
 
525
543
  it "should allow creation of a table with non alphanumeric characters" do
526
544
  create_warehouse_things_table
527
- class WarehouseThing < ActiveRecord::Base
545
+ class ::WarehouseThing < ActiveRecord::Base
528
546
  set_table_name "warehouse-things"
529
547
  end
530
548