rsim-activerecord-oracle_enhanced-adapter 1.2.0.2 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|