rsim-activerecord-oracle_enhanced-adapter 1.2.0.2 → 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 +7 -1
- data/Manifest.txt +1 -1
- data/{README.txt → README.rdoc} +11 -0
- data/lib/active_record/connection_adapters/oracle_enhanced.rake +6 -4
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +54 -26
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +57 -68
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +40 -35
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +15 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -1
- data/oracle-enhanced.gemspec +4 -4
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +82 -16
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +64 -0
- metadata +4 -4
data/History.txt
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
-
==
|
1
|
+
== 1.2.1 2009-06-07
|
2
2
|
|
3
|
+
* Enhancements
|
4
|
+
* caching of table indexes query which makes schema dump much faster
|
3
5
|
* Bug fixes:
|
4
6
|
* return Date (and not DateTime) values for :date column value before year 1970
|
7
|
+
* fixed after_create/update/destroy callbacks with plsql custom methods
|
8
|
+
* fixed creation of large integers in JRuby
|
9
|
+
* Made test tasks respect RAILS_ENV
|
10
|
+
* fixed support for composite primary keys for tables with LOBs
|
5
11
|
|
6
12
|
== 1.2.0 2009-03-22
|
7
13
|
|
data/Manifest.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
@@ -29,6 +29,17 @@ Bugs and enhancement requests can be reported at http://rsim.lighthouseapp.com/p
|
|
29
29
|
|
30
30
|
* sudo gem install activerecord-oracle_enhanced-adapter
|
31
31
|
|
32
|
+
== CONTRIBUTORS:
|
33
|
+
|
34
|
+
* Raimonds Simanovskis
|
35
|
+
* Jorge Dias
|
36
|
+
* James Wylder
|
37
|
+
* Rob Christie
|
38
|
+
* Nate Wieger
|
39
|
+
* Edgars Beigarts
|
40
|
+
* Lachlan Laycock
|
41
|
+
* toddwf
|
42
|
+
|
32
43
|
== LICENSE:
|
33
44
|
|
34
45
|
(The MIT License)
|
@@ -24,17 +24,19 @@ namespace :db do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
namespace :test do
|
27
|
-
redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
|
27
|
+
redefine_task :clone_structure => [ :rails_env, "db:structure:dump", "db:test:purge" ] do
|
28
|
+
env = RAILS_ENV ||= 'test'
|
28
29
|
abcs = ActiveRecord::Base.configurations
|
29
|
-
ActiveRecord::Base.establish_connection(
|
30
|
+
ActiveRecord::Base.establish_connection(env.to_sym)
|
30
31
|
IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split("\n\n").each do |ddl|
|
31
32
|
ActiveRecord::Base.connection.execute(ddl.chop)
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
|
-
redefine_task :purge => :environment do
|
36
|
+
redefine_task :purge => [:rails_env, :environment] do
|
37
|
+
env = RAILS_ENV ||= 'test'
|
36
38
|
abcs = ActiveRecord::Base.configurations
|
37
|
-
ActiveRecord::Base.establish_connection(
|
39
|
+
ActiveRecord::Base.establish_connection(env.to_sym)
|
38
40
|
ActiveRecord::Base.connection.structure_drop.split("\n\n").each do |ddl|
|
39
41
|
ActiveRecord::Base.connection.execute(ddl.chop)
|
40
42
|
end
|
@@ -518,15 +518,26 @@ module ActiveRecord
|
|
518
518
|
|
519
519
|
# Writes LOB values from attributes, as indicated by the LOB columns of klass.
|
520
520
|
def write_lobs(table_name, klass, attributes)
|
521
|
-
|
521
|
+
# is class with composite primary key>
|
522
|
+
is_with_cpk = klass.respond_to?(:composite?) && klass.composite?
|
523
|
+
if is_with_cpk
|
524
|
+
id = klass.primary_key.map {|pk| attributes[pk.to_s] }
|
525
|
+
else
|
526
|
+
id = quote(attributes[klass.primary_key])
|
527
|
+
end
|
522
528
|
klass.columns.select { |col| col.sql_type =~ /LOB$/i }.each do |col|
|
523
529
|
value = attributes[col.name]
|
524
530
|
# RSI: changed sequence of next two lines - should check if value is nil before converting to yaml
|
525
531
|
next if value.nil? || (value == '')
|
526
532
|
value = value.to_yaml if col.text? && klass.serialized_attributes[col.name]
|
527
533
|
uncached do
|
528
|
-
|
534
|
+
if is_with_cpk
|
535
|
+
lob = select_one("SELECT #{col.name} FROM #{table_name} WHERE #{klass.composite_where_clause(id)} FOR UPDATE",
|
536
|
+
'Writable Large Object')[col.name]
|
537
|
+
else
|
538
|
+
lob = select_one("SELECT #{col.name} FROM #{table_name} WHERE #{klass.primary_key} = #{id} FOR UPDATE",
|
529
539
|
'Writable Large Object')[col.name]
|
540
|
+
end
|
530
541
|
@connection.write_lob(lob, value, col.type == :binary)
|
531
542
|
end
|
532
543
|
end
|
@@ -562,33 +573,42 @@ module ActiveRecord
|
|
562
573
|
select_all("select decode(table_name,upper(table_name),lower(table_name),table_name) name from all_tables where owner = sys_context('userenv','session_user')").map {|t| t['name']}
|
563
574
|
end
|
564
575
|
|
565
|
-
|
566
|
-
(owner, table_name) = @connection.describe(table_name)
|
567
|
-
result = select_all(<<-SQL, name)
|
568
|
-
SELECT lower(i.index_name) as index_name, i.uniqueness, lower(c.column_name) as column_name
|
569
|
-
FROM all_indexes i, all_ind_columns c
|
570
|
-
WHERE i.table_name = '#{table_name}'
|
571
|
-
AND i.owner = '#{owner}'
|
572
|
-
AND i.table_owner = '#{owner}'
|
573
|
-
AND c.index_name = i.index_name
|
574
|
-
AND c.index_owner = i.owner
|
575
|
-
AND NOT EXISTS (SELECT uc.index_name FROM all_constraints uc WHERE uc.index_name = i.index_name AND uc.owner = i.owner AND uc.constraint_type = 'P')
|
576
|
-
ORDER BY i.index_name, c.column_position
|
577
|
-
SQL
|
578
|
-
|
579
|
-
current_index = nil
|
580
|
-
indexes = []
|
576
|
+
cattr_accessor :all_schema_indexes
|
581
577
|
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
578
|
+
# This method selects all indexes at once, and caches them in a class variable.
|
579
|
+
# Subsequent index calls get them from the variable, without going to the DB.
|
580
|
+
def indexes(table_name, name = nil)
|
581
|
+
(owner, table_name) = @connection.describe(table_name)
|
582
|
+
unless all_schema_indexes
|
583
|
+
result = select_all(<<-SQL)
|
584
|
+
SELECT lower(i.table_name) as table_name, lower(i.index_name) as index_name, i.uniqueness, lower(c.column_name) as column_name
|
585
|
+
FROM all_indexes i, all_ind_columns c
|
586
|
+
WHERE i.owner = '#{owner}'
|
587
|
+
AND i.table_owner = '#{owner}'
|
588
|
+
AND c.index_name = i.index_name
|
589
|
+
AND c.index_owner = i.owner
|
590
|
+
AND NOT EXISTS (SELECT uc.index_name FROM all_constraints uc WHERE uc.index_name = i.index_name AND uc.owner = i.owner AND uc.constraint_type = 'P')
|
591
|
+
ORDER BY i.index_name, c.column_position
|
592
|
+
SQL
|
593
|
+
|
594
|
+
current_index = nil
|
595
|
+
self.all_schema_indexes = []
|
596
|
+
|
597
|
+
result.each do |row|
|
598
|
+
# have to keep track of indexes because above query returns dups
|
599
|
+
# there is probably a better query we could figure out
|
600
|
+
if current_index != row['index_name']
|
601
|
+
self.all_schema_indexes << ::ActiveRecord::ConnectionAdapters::IndexDefinition.new(row['table_name'], row['index_name'], row['uniqueness'] == "UNIQUE", [])
|
602
|
+
current_index = row['index_name']
|
603
|
+
end
|
604
|
+
|
605
|
+
self.all_schema_indexes.last.columns << row['column_name']
|
586
606
|
end
|
587
|
-
|
588
|
-
indexes.last.columns << row['column_name']
|
589
607
|
end
|
590
|
-
|
591
|
-
indexes
|
608
|
+
|
609
|
+
# Return the indexes just for the requested table, since AR is structured that way
|
610
|
+
table_name = table_name.downcase
|
611
|
+
all_schema_indexes.select{|i| i.table == table_name}
|
592
612
|
end
|
593
613
|
|
594
614
|
# RSI: set ignored columns for table
|
@@ -726,7 +746,15 @@ module ActiveRecord
|
|
726
746
|
execute "DROP SEQUENCE #{seq_name}" rescue nil
|
727
747
|
end
|
728
748
|
|
749
|
+
# clear cached indexes when adding new index
|
750
|
+
def add_index(table_name, column_name, options = {})
|
751
|
+
self.all_schema_indexes = nil
|
752
|
+
super
|
753
|
+
end
|
754
|
+
|
755
|
+
# clear cached indexes when removing index
|
729
756
|
def remove_index(table_name, options = {}) #:nodoc:
|
757
|
+
self.all_schema_indexes = nil
|
730
758
|
execute "DROP INDEX #{index_name(table_name, options)}"
|
731
759
|
end
|
732
760
|
|
@@ -72,6 +72,9 @@ module ActiveRecord
|
|
72
72
|
# Set session time zone to current time zone
|
73
73
|
@raw_connection.setSessionTimeZone(java.util.TimeZone.default.getID)
|
74
74
|
|
75
|
+
# Set default number of rows to prefetch
|
76
|
+
# @raw_connection.setDefaultRowPrefetch(prefetch_rows) if prefetch_rows
|
77
|
+
|
75
78
|
# default schema owner
|
76
79
|
@owner = username.upcase
|
77
80
|
|
@@ -156,7 +159,7 @@ module ActiveRecord
|
|
156
159
|
end
|
157
160
|
|
158
161
|
def exec_no_retry(sql)
|
159
|
-
cs =
|
162
|
+
cs = @raw_connection.prepareCall(sql)
|
160
163
|
case sql
|
161
164
|
when /\A\s*UPDATE/i, /\A\s*INSERT/i, /\A\s*DELETE/i
|
162
165
|
cs.executeUpdate
|
@@ -175,59 +178,35 @@ module ActiveRecord
|
|
175
178
|
end
|
176
179
|
|
177
180
|
def select_no_retry(sql, name = nil, return_column_names = false)
|
178
|
-
stmt =
|
181
|
+
stmt = @raw_connection.prepareStatement(sql)
|
179
182
|
rset = stmt.executeQuery
|
183
|
+
|
184
|
+
# Reuse the same hash for all rows
|
185
|
+
column_hash = {}
|
186
|
+
|
180
187
|
metadata = rset.getMetaData
|
181
188
|
column_count = metadata.getColumnCount
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
189
|
+
|
190
|
+
cols_types_index = (1..column_count).map do |i|
|
191
|
+
col_name = oracle_downcase(metadata.getColumnName(i))
|
192
|
+
next if col_name == 'raw_rnum_'
|
193
|
+
column_hash[col_name] = nil
|
194
|
+
[col_name, metadata.getColumnTypeName(i).to_sym, i]
|
187
195
|
end
|
196
|
+
cols_types_index.delete(nil)
|
188
197
|
|
189
198
|
rows = []
|
190
|
-
|
199
|
+
get_lob_value = !(name == 'Writable Large Object')
|
200
|
+
|
191
201
|
while rset.next
|
192
|
-
hash =
|
193
|
-
|
194
|
-
|
195
|
-
i = i0 + 1
|
196
|
-
hash[col] =
|
197
|
-
case column_type = col_types[i0]
|
198
|
-
when /CLOB/
|
199
|
-
name == 'Writable Large Object' ? rset.getClob(i) : get_ruby_value_from_result_set(rset, i, column_type)
|
200
|
-
when /BLOB/
|
201
|
-
name == 'Writable Large Object' ? rset.getBlob(i) : get_ruby_value_from_result_set(rset, i, column_type)
|
202
|
-
when 'DATE'
|
203
|
-
t = get_ruby_value_from_result_set(rset, i, column_type)
|
204
|
-
# RSI: added emulate_dates_by_column_name functionality
|
205
|
-
# if emulate_dates_by_column_name && self.class.is_date_column?(col)
|
206
|
-
# d.to_date
|
207
|
-
# elsif
|
208
|
-
if t && OracleEnhancedAdapter.emulate_dates && (t.hour == 0 && t.min == 0 && t.sec == 0)
|
209
|
-
t.to_date
|
210
|
-
else
|
211
|
-
# JRuby Time supports time before year 1900 therefore now need to fall back to DateTime
|
212
|
-
t
|
213
|
-
end
|
214
|
-
# RSI: added emulate_integers_by_column_name functionality
|
215
|
-
when "NUMBER"
|
216
|
-
n = get_ruby_value_from_result_set(rset, i, column_type)
|
217
|
-
if n && n.is_a?(Float) && OracleEnhancedAdapter.emulate_integers_by_column_name && OracleEnhancedAdapter.is_integer_column?(col)
|
218
|
-
n.to_i
|
219
|
-
else
|
220
|
-
n
|
221
|
-
end
|
222
|
-
else
|
223
|
-
get_ruby_value_from_result_set(rset, i, column_type)
|
224
|
-
end unless col == 'raw_rnum_'
|
202
|
+
hash = column_hash.dup
|
203
|
+
cols_types_index.each do |col, column_type, i|
|
204
|
+
hash[col] = get_ruby_value_from_result_set(rset, i, column_type, get_lob_value)
|
225
205
|
end
|
226
|
-
|
227
206
|
rows << hash
|
228
207
|
end
|
229
208
|
|
230
|
-
return_column_names ? [rows,
|
209
|
+
return_column_names ? [rows, cols_types_index.map(&:first)] : rows
|
231
210
|
ensure
|
232
211
|
rset.close rescue nil
|
233
212
|
stmt.close rescue nil
|
@@ -284,50 +263,62 @@ module ActiveRecord
|
|
284
263
|
|
285
264
|
private
|
286
265
|
|
287
|
-
def prepare_statement(sql)
|
288
|
-
|
289
|
-
end
|
266
|
+
# def prepare_statement(sql)
|
267
|
+
# @raw_connection.prepareStatement(sql)
|
268
|
+
# end
|
290
269
|
|
291
|
-
def prepare_call(sql, *bindvars)
|
292
|
-
|
293
|
-
end
|
270
|
+
# def prepare_call(sql, *bindvars)
|
271
|
+
# @raw_connection.prepareCall(sql)
|
272
|
+
# end
|
294
273
|
|
295
|
-
def get_ruby_value_from_result_set(rset, i, type_name)
|
274
|
+
def get_ruby_value_from_result_set(rset, i, type_name, get_lob_value = true)
|
296
275
|
case type_name
|
297
|
-
when
|
298
|
-
rset.
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
276
|
+
when :NUMBER
|
277
|
+
# d = rset.getBigDecimal(i)
|
278
|
+
# if d.nil?
|
279
|
+
# nil
|
280
|
+
# elsif d.scale == 0
|
281
|
+
# d.toBigInteger+0
|
282
|
+
# else
|
283
|
+
# # Is there better way how to convert Java BigDecimal to Ruby BigDecimal?
|
284
|
+
# d.toString.to_d
|
285
|
+
# end
|
286
|
+
d = rset.getNUMBER(i)
|
305
287
|
if d.nil?
|
306
288
|
nil
|
307
|
-
elsif d.
|
308
|
-
d.
|
289
|
+
elsif d.isInt
|
290
|
+
Integer(d.stringValue)
|
309
291
|
else
|
310
|
-
|
311
|
-
d.toString.to_d
|
292
|
+
BigDecimal.new(d.stringValue)
|
312
293
|
end
|
313
|
-
when
|
294
|
+
when :VARCHAR2, :CHAR, :LONG
|
295
|
+
rset.getString(i)
|
296
|
+
when :DATE
|
314
297
|
if dt = rset.getDATE(i)
|
315
298
|
d = dt.dateValue
|
316
299
|
t = dt.timeValue
|
317
|
-
|
300
|
+
if OracleEnhancedAdapter.emulate_dates && t.hours == 0 && t.minutes == 0 && t.seconds == 0
|
301
|
+
Date.new(d.year + 1900, d.month + 1, d.date)
|
302
|
+
else
|
303
|
+
Time.send(Base.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
|
304
|
+
end
|
318
305
|
else
|
319
306
|
nil
|
320
307
|
end
|
321
|
-
when
|
308
|
+
when :TIMESTAMP, :TIMESTAMPTZ, :TIMESTAMPLTZ
|
322
309
|
ts = rset.getTimestamp(i)
|
323
310
|
ts && Time.send(Base.default_timezone, ts.year + 1900, ts.month + 1, ts.date, ts.hours, ts.minutes, ts.seconds,
|
324
311
|
ts.nanos / 1000)
|
312
|
+
when :CLOB
|
313
|
+
get_lob_value ? lob_to_ruby_value(rset.getClob(i)) : rset.getClob(i)
|
314
|
+
when :BLOB
|
315
|
+
get_lob_value ? lob_to_ruby_value(rset.getBlob(i)) : rset.getBlob(i)
|
325
316
|
else
|
326
317
|
nil
|
327
318
|
end
|
328
319
|
end
|
329
320
|
|
330
|
-
def
|
321
|
+
def lob_to_ruby_value(val)
|
331
322
|
case val
|
332
323
|
when ::Java::OracleSql::CLOB
|
333
324
|
if val.isEmptyLob
|
@@ -341,8 +332,6 @@ module ActiveRecord
|
|
341
332
|
else
|
342
333
|
String.from_java_bytes(val.getBytes(1, val.length))
|
343
334
|
end
|
344
|
-
else
|
345
|
-
val
|
346
335
|
end
|
347
336
|
end
|
348
337
|
|
@@ -84,70 +84,75 @@ module ActiveRecord
|
|
84
84
|
|
85
85
|
def select(sql, name = nil, return_column_names = false)
|
86
86
|
cursor = @raw_connection.exec(sql)
|
87
|
-
cols =
|
87
|
+
cols = []
|
88
|
+
# Ignore raw_rnum_ which is used to simulate LIMIT and OFFSET
|
89
|
+
cursor.get_col_names.each do |col_name|
|
90
|
+
col_name = oracle_downcase(col_name)
|
91
|
+
cols << col_name unless col_name == 'raw_rnum_'
|
92
|
+
end
|
93
|
+
# Reuse the same hash for all rows
|
94
|
+
column_hash = {}
|
95
|
+
cols.each {|c| column_hash[c] = nil}
|
88
96
|
rows = []
|
97
|
+
get_lob_value = !(name == 'Writable Large Object')
|
89
98
|
|
90
99
|
while row = cursor.fetch
|
91
|
-
hash =
|
100
|
+
hash = column_hash.dup
|
92
101
|
|
93
102
|
cols.each_with_index do |col, i|
|
94
103
|
hash[col] =
|
95
|
-
case row[i]
|
104
|
+
case v = row[i]
|
105
|
+
# RSI: added emulate_integers_by_column_name functionality
|
106
|
+
when Float
|
107
|
+
# if OracleEnhancedAdapter.emulate_integers_by_column_name && OracleEnhancedAdapter.is_integer_column?(col)
|
108
|
+
# v.to_i
|
109
|
+
# else
|
110
|
+
# v
|
111
|
+
# end
|
112
|
+
v == (v_to_i = v.to_i) ? v_to_i : v
|
113
|
+
# ruby-oci8 2.0 returns OraNumber - convert it to Integer or BigDecimal
|
114
|
+
when OraNumber
|
115
|
+
v == (v_to_i = v.to_i) ? v_to_i : BigDecimal.new(v.to_s)
|
116
|
+
when String
|
117
|
+
v
|
96
118
|
when OCI8::LOB
|
97
|
-
if
|
98
|
-
|
99
|
-
else
|
100
|
-
data = row[i].read
|
119
|
+
if get_lob_value
|
120
|
+
data = v.read
|
101
121
|
# 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) &&
|
122
|
+
data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding) && v.is_a?(OCI8::BLOB)
|
103
123
|
data
|
124
|
+
else
|
125
|
+
v
|
104
126
|
end
|
105
127
|
# ruby-oci8 1.0 returns OraDate
|
106
128
|
when OraDate
|
107
|
-
d = row[i]
|
108
129
|
# RSI: added emulate_dates_by_column_name functionality
|
109
|
-
|
110
|
-
|
111
|
-
# elsif
|
112
|
-
if OracleEnhancedAdapter.emulate_dates && (d.hour == 0 && d.minute == 0 && d.second == 0)
|
113
|
-
d.to_date
|
130
|
+
if OracleEnhancedAdapter.emulate_dates && (v.hour == 0 && v.minute == 0 && v.second == 0)
|
131
|
+
v.to_date
|
114
132
|
else
|
115
133
|
# code from Time.time_with_datetime_fallback
|
116
134
|
begin
|
117
|
-
Time.send(Base.default_timezone,
|
135
|
+
Time.send(Base.default_timezone, v.year, v.month, v.day, v.hour, v.minute, v.second)
|
118
136
|
rescue
|
119
137
|
offset = Base.default_timezone.to_sym == :local ? ::DateTime.local_offset : 0
|
120
|
-
::DateTime.civil(
|
138
|
+
::DateTime.civil(v.year, v.month, v.day, v.hour, v.minute, v.second, offset)
|
121
139
|
end
|
122
140
|
end
|
123
141
|
# ruby-oci8 2.0 returns Time or DateTime
|
124
142
|
when Time, DateTime
|
125
|
-
|
126
|
-
|
127
|
-
d.to_date
|
143
|
+
if OracleEnhancedAdapter.emulate_dates && (v.hour == 0 && v.min == 0 && v.sec == 0)
|
144
|
+
v.to_date
|
128
145
|
else
|
129
146
|
# recreate Time or DateTime using Base.default_timezone
|
130
147
|
begin
|
131
|
-
Time.send(Base.default_timezone,
|
148
|
+
Time.send(Base.default_timezone, v.year, v.month, v.day, v.hour, v.min, v.sec)
|
132
149
|
rescue
|
133
150
|
offset = Base.default_timezone.to_sym == :local ? ::DateTime.local_offset : 0
|
134
|
-
::DateTime.civil(
|
151
|
+
::DateTime.civil(v.year, v.month, v.day, v.hour, v.min, v.sec, offset)
|
135
152
|
end
|
136
153
|
end
|
137
|
-
|
138
|
-
|
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_'
|
154
|
+
else v
|
155
|
+
end
|
151
156
|
end
|
152
157
|
|
153
158
|
rows << hash
|
@@ -38,17 +38,30 @@ module ActiveRecord #:nodoc:
|
|
38
38
|
module InstanceMethods
|
39
39
|
def self.included(base)
|
40
40
|
base.instance_eval do
|
41
|
-
|
41
|
+
if private_instance_methods.include?('create_without_callbacks') || private_instance_methods.include?(:create_without_callbacks)
|
42
|
+
alias_method :create_without_custom_method, :create_without_callbacks
|
43
|
+
alias_method :create_without_callbacks, :create_with_custom_method
|
44
|
+
else
|
45
|
+
alias_method_chain :create, :custom_method
|
46
|
+
end
|
42
47
|
# insert after dirty checking in Rails 2.1
|
43
48
|
# in Ruby 1.9 methods names are returned as symbols
|
44
49
|
if private_instance_methods.include?('update_without_dirty') || private_instance_methods.include?(:update_without_dirty)
|
45
50
|
alias_method :update_without_custom_method, :update_without_dirty
|
46
51
|
alias_method :update_without_dirty, :update_with_custom_method
|
52
|
+
elsif private_instance_methods.include?('update_without_callbacks') || private_instance_methods.include?(:update_without_callbacks)
|
53
|
+
alias_method :update_without_custom_method, :update_without_callbacks
|
54
|
+
alias_method :update_without_callbacks, :update_with_custom_method
|
47
55
|
else
|
48
56
|
alias_method_chain :update, :custom_method
|
49
57
|
end
|
50
58
|
private :create, :update
|
51
|
-
|
59
|
+
if public_instance_methods.include?('destroy_without_callbacks') || public_instance_methods.include?(:destroy_without_callbacks)
|
60
|
+
alias_method :destroy_without_custom_method, :destroy_without_callbacks
|
61
|
+
alias_method :destroy_without_callbacks, :destroy_with_custom_method
|
62
|
+
else
|
63
|
+
alias_method_chain :destroy, :custom_method
|
64
|
+
end
|
52
65
|
public :destroy
|
53
66
|
end
|
54
67
|
end
|
data/oracle-enhanced.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{activerecord-oracle_enhanced-adapter}
|
5
|
-
s.version = "1.2.
|
5
|
+
s.version = "1.2.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Raimonds Simanovskis"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-06-07}
|
10
10
|
s.description = %q{Oracle enhanced adapter for ActiveRecord}
|
11
11
|
s.email = ["raimonds.simanovskis@gmail.com"]
|
12
|
-
s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.
|
13
|
-
s.files = ["History.txt", "License.txt", "Manifest.txt", "README.
|
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
14
|
"lib/active_record/connection_adapters/emulation/oracle_adapter.rb",
|
15
15
|
"lib/active_record/connection_adapters/oracle_enhanced.rake",
|
16
16
|
"lib/active_record/connection_adapters/oracle_enhanced_adapter.rb",
|
@@ -3,35 +3,101 @@ require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
|
3
3
|
describe "OracleEnhancedAdapter composite_primary_keys support" do
|
4
4
|
|
5
5
|
before(:all) do
|
6
|
-
if defined?(ActiveRecord::ConnectionAdapters::OracleAdapter)
|
7
|
-
@old_oracle_adapter = ActiveRecord::ConnectionAdapters::OracleAdapter
|
8
|
-
ActiveRecord::ConnectionAdapters.send(:remove_const, :OracleAdapter)
|
6
|
+
if defined?(::ActiveRecord::ConnectionAdapters::OracleAdapter)
|
7
|
+
@old_oracle_adapter = ::ActiveRecord::ConnectionAdapters::OracleAdapter
|
8
|
+
::ActiveRecord::ConnectionAdapters.send(:remove_const, :OracleAdapter)
|
9
9
|
end
|
10
10
|
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
set_primary_keys :employee_id, :start_date
|
11
|
+
if $cpk_oracle_adapter
|
12
|
+
::ActiveRecord::ConnectionAdapters::OracleAdapter = $cpk_oracle_adapter
|
13
|
+
$cpk_oracle_adapter = nil
|
15
14
|
end
|
15
|
+
require 'composite_primary_keys'
|
16
16
|
end
|
17
17
|
|
18
18
|
after(:all) do
|
19
|
-
Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
|
20
|
-
|
19
|
+
# Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
|
20
|
+
if defined?(::ActiveRecord::ConnectionAdapters::OracleAdapter)
|
21
|
+
$cpk_oracle_adapter = ::ActiveRecord::ConnectionAdapters::OracleAdapter
|
22
|
+
::ActiveRecord::ConnectionAdapters.send(:remove_const, :OracleAdapter)
|
23
|
+
end
|
21
24
|
if @old_oracle_adapter
|
22
|
-
ActiveRecord::ConnectionAdapters
|
23
|
-
|
25
|
+
::ActiveRecord::ConnectionAdapters::OracleAdapter = @old_oracle_adapter
|
26
|
+
@old_oracle_adapter = nil
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
describe "do not use count distinct" do
|
31
|
+
before(:all) do
|
32
|
+
class ::JobHistory < ActiveRecord::Base
|
33
|
+
set_table_name "job_history"
|
34
|
+
set_primary_keys :employee_id, :start_date
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
after(:all) do
|
39
|
+
Object.send(:remove_const, 'JobHistory') if defined?(JobHistory)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should tell ActiveRecord that count distinct is not supported" do
|
43
|
+
ActiveRecord::Base.connection.supports_count_distinct?.should be_false
|
44
|
+
end
|
30
45
|
|
31
|
-
|
32
|
-
|
46
|
+
it "should execute correct SQL COUNT DISTINCT statement on table with composite primary keys" do
|
47
|
+
lambda { JobHistory.count(:distinct => true) }.should_not raise_error
|
48
|
+
end
|
33
49
|
end
|
34
50
|
|
51
|
+
describe "table with LOB" do
|
52
|
+
before(:all) do
|
53
|
+
ActiveRecord::Schema.define do
|
54
|
+
suppress_messages do
|
55
|
+
create_table :cpk_write_lobs_test, :primary_key => [:type_category, :date_value], :force => true do |t|
|
56
|
+
t.string :type_category, :limit => 15, :null => false
|
57
|
+
t.date :date_value, :null => false
|
58
|
+
t.text :results, :null => false
|
59
|
+
t.timestamps
|
60
|
+
end
|
61
|
+
create_table :non_cpk_write_lobs_test, :force => true do |t|
|
62
|
+
t.date :date_value, :null => false
|
63
|
+
t.text :results, :null => false
|
64
|
+
t.timestamps
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
class ::CpkWriteLobsTest < ActiveRecord::Base
|
69
|
+
set_table_name 'cpk_write_lobs_test'
|
70
|
+
set_primary_keys :type_category, :date_value
|
71
|
+
end
|
72
|
+
class ::NonCpkWriteLobsTest < ActiveRecord::Base
|
73
|
+
set_table_name 'non_cpk_write_lobs_test'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
after(:all) do
|
78
|
+
ActiveRecord::Schema.define do
|
79
|
+
suppress_messages do
|
80
|
+
drop_table :cpk_write_lobs_test
|
81
|
+
drop_table :non_cpk_write_lobs_test
|
82
|
+
end
|
83
|
+
end
|
84
|
+
Object.send(:remove_const, "CpkWriteLobsTest")
|
85
|
+
Object.send(:remove_const, "NonCpkWriteLobsTest")
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should create new record in table with CPK and LOB" do
|
89
|
+
lambda {
|
90
|
+
CpkWriteLobsTest.create(:type_category => 'AAA', :date_value => Date.today, :results => 'DATA '*10)
|
91
|
+
}.should_not raise_error
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should create new record in table without CPK and with LOB" do
|
95
|
+
lambda {
|
96
|
+
NonCpkWriteLobsTest.create(:date_value => Date.today, :results => 'DATA '*10)
|
97
|
+
}.should_not raise_error
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
35
101
|
# Other testing was done based on composite_primary_keys tests
|
36
102
|
|
37
103
|
end
|
@@ -159,6 +159,26 @@ describe "OracleEnhancedAdapter custom methods for create, update and destroy" d
|
|
159
159
|
@employee.update_time.should_not be_nil
|
160
160
|
end
|
161
161
|
|
162
|
+
it "should rollback record when exception is raised in after_create callback" do
|
163
|
+
@employee = TestEmployee.new(
|
164
|
+
:first_name => "First",
|
165
|
+
:last_name => "Last",
|
166
|
+
:hire_date => @today
|
167
|
+
)
|
168
|
+
TestEmployee.class_eval { def after_create() raise "Make the transaction rollback" end }
|
169
|
+
begin
|
170
|
+
employees_count = TestEmployee.count
|
171
|
+
@employee.save
|
172
|
+
fail "Did not raise exception"
|
173
|
+
rescue => e
|
174
|
+
e.message.should == "Make the transaction rollback"
|
175
|
+
@employee.id.should == nil
|
176
|
+
TestEmployee.count.should == employees_count
|
177
|
+
ensure
|
178
|
+
TestEmployee.class_eval { remove_method :after_create }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
162
182
|
it "should update record" do
|
163
183
|
@employee = TestEmployee.create(
|
164
184
|
:first_name => "First",
|
@@ -173,6 +193,29 @@ describe "OracleEnhancedAdapter custom methods for create, update and destroy" d
|
|
173
193
|
@employee.description.should == "Second Last"
|
174
194
|
end
|
175
195
|
|
196
|
+
it "should rollback record when exception is raised in after_update callback" do
|
197
|
+
TestEmployee.class_eval { def after_update() raise "Make the transaction rollback" end }
|
198
|
+
begin
|
199
|
+
@employee = TestEmployee.create(
|
200
|
+
:first_name => "First",
|
201
|
+
:last_name => "Last",
|
202
|
+
:hire_date => @today,
|
203
|
+
:description => "description"
|
204
|
+
)
|
205
|
+
empl_id = @employee.id
|
206
|
+
@employee.reload
|
207
|
+
@employee.first_name = "Second"
|
208
|
+
@employee.save!
|
209
|
+
fail "Did not raise exception"
|
210
|
+
rescue => e
|
211
|
+
e.message.should == "Make the transaction rollback"
|
212
|
+
@employee.reload
|
213
|
+
@employee.first_name.should == "First"
|
214
|
+
ensure
|
215
|
+
TestEmployee.class_eval { remove_method :after_update }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
176
219
|
it "should not update record if nothing is changed and partial updates are enabled" do
|
177
220
|
return pending("Not in this ActiveRecord version") unless TestEmployee.respond_to?(:partial_updates=)
|
178
221
|
TestEmployee.partial_updates = true
|
@@ -214,6 +257,27 @@ describe "OracleEnhancedAdapter custom methods for create, update and destroy" d
|
|
214
257
|
TestEmployee.find_by_employee_id(empl_id).should be_nil
|
215
258
|
end
|
216
259
|
|
260
|
+
it "should rollback record when exception is raised in after_desotry callback" do
|
261
|
+
TestEmployee.class_eval { def after_destroy() raise "Make the transaction rollback" end }
|
262
|
+
@employee = TestEmployee.create(
|
263
|
+
:first_name => "First",
|
264
|
+
:last_name => "Last",
|
265
|
+
:hire_date => @today
|
266
|
+
)
|
267
|
+
@employee.reload
|
268
|
+
empl_id = @employee.id
|
269
|
+
begin
|
270
|
+
@employee.destroy
|
271
|
+
fail "Did not raise exception"
|
272
|
+
rescue => e
|
273
|
+
e.message.should == "Make the transaction rollback"
|
274
|
+
@employee.id.should == empl_id
|
275
|
+
TestEmployee.find_by_employee_id(empl_id).should_not be_nil
|
276
|
+
ensure
|
277
|
+
TestEmployee.class_eval { remove_method :after_destroy }
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
217
281
|
it "should log create record" do
|
218
282
|
log_to @buffer
|
219
283
|
# reestablish plsql.connection as log_to might reset existing connection
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsim-activerecord-oracle_enhanced-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raimonds Simanovskis
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -33,12 +33,12 @@ extra_rdoc_files:
|
|
33
33
|
- History.txt
|
34
34
|
- License.txt
|
35
35
|
- Manifest.txt
|
36
|
-
- README.
|
36
|
+
- README.rdoc
|
37
37
|
files:
|
38
38
|
- History.txt
|
39
39
|
- License.txt
|
40
40
|
- Manifest.txt
|
41
|
-
- README.
|
41
|
+
- README.rdoc
|
42
42
|
- lib/active_record/connection_adapters/emulation/oracle_adapter.rb
|
43
43
|
- lib/active_record/connection_adapters/oracle_enhanced.rake
|
44
44
|
- lib/active_record/connection_adapters/oracle_enhanced_adapter.rb
|