ruby-plsql 0.1.6 → 0.2.0
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 +10 -0
- data/Manifest.txt +2 -0
- data/lib/oradate_patch.rb +10 -0
- data/lib/plsql/connection.rb +440 -0
- data/lib/plsql/procedure.rb +8 -39
- data/lib/plsql/schema.rb +10 -9
- data/lib/ruby_plsql.rb +36 -9
- data/lib/ruby_plsql/version.rb +2 -2
- data/spec/plsql/package_spec.rb +1 -1
- data/spec/plsql/procedure_spec.rb +41 -18
- data/spec/plsql/schema_spec.rb +12 -9
- data/spec/spec_helper.rb +8 -0
- data/website/index.html +7 -5
- data/website/index.txt +5 -3
- metadata +3 -1
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 0.2.0 2008-06-26
|
2
|
+
|
3
|
+
* New features
|
4
|
+
* Added JRuby and Oracle JDBC driver support with the same functionality as in case of MRI and ruby-oci8 driver
|
5
|
+
* All database driver specifics are extracted in separate Connection class with OCIConnection and JDBCConnection subclasses
|
6
|
+
* Improvements
|
7
|
+
* PL/SQL functions/procedures with DATE return values and output parameters returns Time values by default (previously DateTime values
|
8
|
+
were returned by default). If value is too old then DateTime value is returned. From Ruby Time, DateTime and Date values can be
|
9
|
+
passed as arguments to DATE parameters.
|
10
|
+
|
1
11
|
== 0.1.6 2008-06-16
|
2
12
|
|
3
13
|
* Improvements
|
data/Manifest.txt
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
class OraDate
|
2
|
+
if defined? DateTime # ruby 1.8.0 or upper
|
3
|
+
# RSI: create DateTime in local timezone
|
4
|
+
def to_datetime
|
5
|
+
DateTime.parse(Time.local(year, month, day, hour, minute, second).iso8601)
|
6
|
+
rescue
|
7
|
+
DateTime.new(year, month, day, hour, minute, second)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,440 @@
|
|
1
|
+
module PLSQL
|
2
|
+
class Connection
|
3
|
+
attr_reader :raw_connection
|
4
|
+
attr_reader :raw_driver
|
5
|
+
|
6
|
+
def initialize(raw_drv, raw_conn)
|
7
|
+
@raw_driver = raw_drv
|
8
|
+
@raw_connection = raw_conn
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create(raw_conn)
|
12
|
+
if !raw_conn.respond_to?(:java_class) && defined?(OCI8)
|
13
|
+
OCIConnection.new(:oci, raw_conn)
|
14
|
+
elsif raw_conn.respond_to?(:java_class) && raw_conn.java_class.to_s =~ /jdbc/
|
15
|
+
JDBCConnection.new(:jdbc, raw_conn)
|
16
|
+
else
|
17
|
+
raise ArgumentError, "Unknown raw driver"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def oci?
|
22
|
+
@raw_driver == :oci
|
23
|
+
end
|
24
|
+
|
25
|
+
def jdbc?
|
26
|
+
@raw_driver == :jdbc
|
27
|
+
end
|
28
|
+
|
29
|
+
def logoff
|
30
|
+
raise NoMethodError, "Not implemented for this raw driver"
|
31
|
+
end
|
32
|
+
|
33
|
+
def select_first(sql, *bindvars)
|
34
|
+
raise NoMethodError, "Not implemented for this raw driver"
|
35
|
+
end
|
36
|
+
|
37
|
+
def select_all(sql, *bindvars, &block)
|
38
|
+
raise NoMethodError, "Not implemented for this raw driver"
|
39
|
+
end
|
40
|
+
|
41
|
+
def exec(sql, *bindvars)
|
42
|
+
raise NoMethodError, "Not implemented for this raw driver"
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse(sql)
|
46
|
+
raise NoMethodError, "Not implemented for this raw driver"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class OCIConnection < Connection
|
52
|
+
|
53
|
+
def logoff
|
54
|
+
raw_connection.logoff
|
55
|
+
end
|
56
|
+
|
57
|
+
def select_first(sql, *bindvars)
|
58
|
+
cursor = raw_connection.exec(sql, *bindvars)
|
59
|
+
result = cursor.fetch
|
60
|
+
if result
|
61
|
+
result.map { |val| ora_value_to_ruby_value(val) }
|
62
|
+
else
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
ensure
|
66
|
+
cursor.close rescue nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def select_all(sql, *bindvars, &block)
|
70
|
+
cursor = raw_connection.exec(sql, *bindvars)
|
71
|
+
results = []
|
72
|
+
row_count = 0
|
73
|
+
while row = cursor.fetch
|
74
|
+
row_with_typecast = row.map {|val| ora_value_to_ruby_value(val) }
|
75
|
+
if block_given?
|
76
|
+
yield(row_with_typecast)
|
77
|
+
row_count += 1
|
78
|
+
else
|
79
|
+
results << row_with_typecast
|
80
|
+
end
|
81
|
+
end
|
82
|
+
block_given? ? row_count : results
|
83
|
+
ensure
|
84
|
+
cursor.close rescue nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def exec(sql, *bindvars)
|
88
|
+
raw_connection.exec(sql, *bindvars)
|
89
|
+
end
|
90
|
+
|
91
|
+
class Cursor
|
92
|
+
attr_accessor :raw_cursor
|
93
|
+
|
94
|
+
def initialize(raw_cur)
|
95
|
+
@raw_cursor = raw_cur
|
96
|
+
end
|
97
|
+
|
98
|
+
def bind_param(key, value, type=nil, length=nil, in_out='IN')
|
99
|
+
raw_cursor.bind_param(key, value, type, length)
|
100
|
+
end
|
101
|
+
|
102
|
+
def exec(*bindvars)
|
103
|
+
raw_cursor.exec(*bindvars)
|
104
|
+
end
|
105
|
+
|
106
|
+
def [](key)
|
107
|
+
raw_cursor[key]
|
108
|
+
end
|
109
|
+
|
110
|
+
def close
|
111
|
+
raw_cursor.close
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def parse(sql)
|
116
|
+
Cursor.new(raw_connection.parse(sql))
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
def plsql_to_ruby_data_type(data_type, data_length)
|
121
|
+
case data_type
|
122
|
+
when "VARCHAR2"
|
123
|
+
[String, data_length || 4000]
|
124
|
+
when "NUMBER"
|
125
|
+
[OraNumber, nil]
|
126
|
+
when "DATE"
|
127
|
+
[DateTime, nil]
|
128
|
+
when "TIMESTAMP"
|
129
|
+
[Time, nil]
|
130
|
+
# CLOB
|
131
|
+
# BLOB
|
132
|
+
else
|
133
|
+
[String, 4000]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def ruby_value_to_ora_value(val, type)
|
138
|
+
if type == OraNumber
|
139
|
+
val.nil? || val.is_a?(Fixnum) ? val : val.to_f
|
140
|
+
elsif type == DateTime
|
141
|
+
val ? val.to_datetime : nil
|
142
|
+
else
|
143
|
+
val
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def ora_value_to_ruby_value(val)
|
148
|
+
case val
|
149
|
+
when Float, OraNumber
|
150
|
+
ora_number_to_ruby_number(val)
|
151
|
+
when DateTime, OraDate
|
152
|
+
ora_date_to_ruby_date(val)
|
153
|
+
else
|
154
|
+
val
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
def ora_number_to_ruby_number(num)
|
162
|
+
num.to_i == num.to_f ? num.to_i : num.to_f
|
163
|
+
end
|
164
|
+
|
165
|
+
def ora_date_to_ruby_date(val)
|
166
|
+
case val
|
167
|
+
when DateTime
|
168
|
+
Time.parse(val.strftime("%c")) rescue val
|
169
|
+
when OraDate
|
170
|
+
val.to_time rescue val.to_datetime
|
171
|
+
else
|
172
|
+
val
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
|
180
|
+
class JDBCConnection < Connection
|
181
|
+
def logoff
|
182
|
+
raw_connection.close
|
183
|
+
true
|
184
|
+
rescue
|
185
|
+
false
|
186
|
+
end
|
187
|
+
|
188
|
+
def select_first(sql, *bindvars)
|
189
|
+
stmt = prepare_statement(sql, *bindvars)
|
190
|
+
rset = stmt.executeQuery
|
191
|
+
metadata = rset.getMetaData
|
192
|
+
column_count = metadata.getColumnCount
|
193
|
+
if rset.next
|
194
|
+
(1..column_count).map do |i|
|
195
|
+
get_ruby_value_from_result_set(rset,i,metadata.getColumnTypeName(i))
|
196
|
+
end
|
197
|
+
else
|
198
|
+
nil
|
199
|
+
end
|
200
|
+
ensure
|
201
|
+
rset.close rescue nil
|
202
|
+
stmt.close rescue nil
|
203
|
+
end
|
204
|
+
|
205
|
+
def select_all(sql, *bindvars, &block)
|
206
|
+
stmt = prepare_statement(sql, *bindvars)
|
207
|
+
results = []
|
208
|
+
row_count = 0
|
209
|
+
rset = stmt.executeQuery
|
210
|
+
metadata = rset.getMetaData
|
211
|
+
column_count = metadata.getColumnCount
|
212
|
+
while rset.next
|
213
|
+
row_with_typecast = (1..column_count).map do |i|
|
214
|
+
get_ruby_value_from_result_set(rset,i,metadata.getColumnTypeName(i))
|
215
|
+
end
|
216
|
+
if block_given?
|
217
|
+
yield(row_with_typecast)
|
218
|
+
row_count += 1
|
219
|
+
else
|
220
|
+
results << row_with_typecast
|
221
|
+
end
|
222
|
+
end
|
223
|
+
block_given? ? row_count : results
|
224
|
+
ensure
|
225
|
+
rset.close rescue nil
|
226
|
+
stmt.close rescue nil
|
227
|
+
end
|
228
|
+
|
229
|
+
def exec(sql, *bindvars)
|
230
|
+
cs = prepare_call(sql, *bindvars)
|
231
|
+
cs.execute
|
232
|
+
true
|
233
|
+
ensure
|
234
|
+
cs.close rescue nil
|
235
|
+
end
|
236
|
+
|
237
|
+
class Cursor
|
238
|
+
|
239
|
+
def initialize(sql, conn)
|
240
|
+
@sql = sql
|
241
|
+
@connection = conn
|
242
|
+
@params = sql.scan(/\:\w+/)
|
243
|
+
@out_types = {}
|
244
|
+
@out_index = {}
|
245
|
+
@statement = @connection.prepare_call(sql)
|
246
|
+
end
|
247
|
+
|
248
|
+
def bind_param(key, value, type=nil, length=nil, in_out='IN')
|
249
|
+
@connection.set_bind_variable(@statement, key, value, type, length)
|
250
|
+
if in_out =~ /OUT/
|
251
|
+
@out_types[key] = type || value.class
|
252
|
+
@out_index[key] = bind_param_index(key)
|
253
|
+
@statement.registerOutParameter(@out_index[key],@connection.get_java_sql_type(value,type))
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def exec
|
258
|
+
@statement.execute
|
259
|
+
end
|
260
|
+
|
261
|
+
def [](key)
|
262
|
+
@connection.get_bind_variable(@statement, @out_index[key], @out_types[key])
|
263
|
+
end
|
264
|
+
|
265
|
+
def close
|
266
|
+
@statement.close
|
267
|
+
end
|
268
|
+
|
269
|
+
private
|
270
|
+
|
271
|
+
def bind_param_index(key)
|
272
|
+
return key if key.kind_of? Integer
|
273
|
+
key = ":#{key.to_s}" unless key.to_s =~ /^:/
|
274
|
+
@params.index(key)+1
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def parse(sql)
|
279
|
+
Cursor.new(sql, self)
|
280
|
+
end
|
281
|
+
|
282
|
+
def prepare_statement(sql, *bindvars)
|
283
|
+
stmt = raw_connection.prepareStatement(sql)
|
284
|
+
bindvars.each_with_index do |bv, i|
|
285
|
+
set_bind_variable(stmt, i+1, bv)
|
286
|
+
end
|
287
|
+
stmt
|
288
|
+
end
|
289
|
+
|
290
|
+
def prepare_call(sql, *bindvars)
|
291
|
+
stmt = raw_connection.prepareCall(sql)
|
292
|
+
bindvars.each_with_index do |bv, i|
|
293
|
+
set_bind_variable(stmt, i+1, bv)
|
294
|
+
end
|
295
|
+
stmt
|
296
|
+
end
|
297
|
+
|
298
|
+
def get_java_sql_type(value, type)
|
299
|
+
case type ? type.to_s : value.class.to_s
|
300
|
+
when 'Fixnum', 'Bignum', 'Integer'
|
301
|
+
java.sql.Types::INTEGER
|
302
|
+
when 'Float'
|
303
|
+
java.sql.Types::FLOAT
|
304
|
+
when 'BigDecimal'
|
305
|
+
java.sql.Types::NUMERIC
|
306
|
+
when 'String'
|
307
|
+
java.sql.Types::VARCHAR
|
308
|
+
when 'Date'
|
309
|
+
java.sql.Types::DATE
|
310
|
+
when 'Time'
|
311
|
+
java.sql.Types::DATE
|
312
|
+
when 'DateTime'
|
313
|
+
java.sql.Types::DATE
|
314
|
+
else
|
315
|
+
java.sql.Types::VARCHAR
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
def set_bind_variable(stmt, i, value, type=nil, length=nil)
|
320
|
+
key = i.kind_of?(Integer) ? nil : i.to_s.gsub(':','')
|
321
|
+
case !value.nil? && type ? type.to_s : value.class.to_s
|
322
|
+
when 'Fixnum', 'Bignum', 'Integer'
|
323
|
+
stmt.send("setInt#{key && "AtName"}", key || i, value)
|
324
|
+
when 'Float'
|
325
|
+
stmt.send("setFloat#{key && "AtName"}", key || i, value)
|
326
|
+
when 'BigDecimal'
|
327
|
+
stmt.send("setBigDecimal#{key && "AtName"}", key || i, java.math.BigDecimal.new(value.to_s))
|
328
|
+
when 'String'
|
329
|
+
stmt.send("setString#{key && "AtName"}", key || i, value)
|
330
|
+
when 'Date'
|
331
|
+
stmt.send("setDate#{key && "AtName"}", key || i, java.sql.Date.new(Time.parse(value.to_s).to_i*1000))
|
332
|
+
when 'Time'
|
333
|
+
stmt.send("setTime#{key && "AtName"}", key || i, java.sql.Time.new(value.to_i*1000))
|
334
|
+
when 'DateTime'
|
335
|
+
stmt.send("setTime#{key && "AtName"}", key || i, java.sql.Time.new(Time.parse(value.strftime("%c")).to_i*1000))
|
336
|
+
when 'NilClass'
|
337
|
+
stmt.send("setNull#{key && "AtName"}", key || i, get_java_sql_type(value, type))
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def get_bind_variable(stmt, i, type)
|
342
|
+
case type.to_s
|
343
|
+
when 'Fixnum', 'Bignum', 'Integer'
|
344
|
+
stmt.getInt(i)
|
345
|
+
when 'Float'
|
346
|
+
stmt.getFloat(i)
|
347
|
+
when 'BigDecimal'
|
348
|
+
bd = stmt.getBigDecimal(i)
|
349
|
+
bd && BigDecimal.new(bd.to_s)
|
350
|
+
when 'String'
|
351
|
+
stmt.getString(i)
|
352
|
+
when 'Date','Time','DateTime'
|
353
|
+
ts = stmt.getTimestamp(i)
|
354
|
+
# ts && Time.parse(Time.at(ts.getTime/1000).iso8601)
|
355
|
+
ts && Time.local(1900+ts.year, ts.month+1, ts.date, ts.hours, ts.minutes, ts.seconds)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def get_ruby_value_from_result_set(rset, i, type_name)
|
360
|
+
case type_name
|
361
|
+
when "CHAR", "VARCHAR2"
|
362
|
+
rset.getString(i)
|
363
|
+
when "NUMBER"
|
364
|
+
d = rset.getBigDecimal(i)
|
365
|
+
if d.nil?
|
366
|
+
nil
|
367
|
+
elsif d.scale == 0
|
368
|
+
d.longValue
|
369
|
+
else
|
370
|
+
d.doubleValue
|
371
|
+
end
|
372
|
+
when "DATE", "TIMESTAMP"
|
373
|
+
Time.at(rset.getTimestamp(i).getTime/1000)
|
374
|
+
else
|
375
|
+
nil
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def plsql_to_ruby_data_type(data_type, data_length)
|
380
|
+
case data_type
|
381
|
+
when "VARCHAR2"
|
382
|
+
[String, data_length || 4000]
|
383
|
+
when "NUMBER"
|
384
|
+
[BigDecimal, nil]
|
385
|
+
when "DATE"
|
386
|
+
[Time, nil]
|
387
|
+
when "TIMESTAMP"
|
388
|
+
[Time, nil]
|
389
|
+
# CLOB
|
390
|
+
# BLOB
|
391
|
+
else
|
392
|
+
[String, 4000]
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def ruby_value_to_ora_value(val, type)
|
397
|
+
if type == BigDecimal
|
398
|
+
val.nil? || val.is_a?(Fixnum) ? val : val.to_f
|
399
|
+
elsif type == Time
|
400
|
+
date_to_time(val)
|
401
|
+
else
|
402
|
+
val
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def ora_value_to_ruby_value(val)
|
407
|
+
case val
|
408
|
+
when Float, BigDecimal
|
409
|
+
ora_number_to_ruby_number(val)
|
410
|
+
# when OraDate
|
411
|
+
# ora_date_to_ruby_date(val)
|
412
|
+
else
|
413
|
+
val
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
private
|
418
|
+
|
419
|
+
def ora_number_to_ruby_number(num)
|
420
|
+
num.to_i == num.to_f ? num.to_i : num.to_f
|
421
|
+
end
|
422
|
+
|
423
|
+
# def ora_date_to_ruby_date(val)
|
424
|
+
# val.to_time
|
425
|
+
# end
|
426
|
+
|
427
|
+
def date_to_time(val)
|
428
|
+
case val
|
429
|
+
when Time
|
430
|
+
val
|
431
|
+
when DateTime
|
432
|
+
Time.parse(val.strftime("%c"))
|
433
|
+
when Date
|
434
|
+
Time.parse(val.strftime("%c"))
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
end
|
439
|
+
|
440
|
+
end
|
data/lib/plsql/procedure.rb
CHANGED
@@ -34,7 +34,7 @@ module PLSQL
|
|
34
34
|
@out_list = {}
|
35
35
|
@return = {}
|
36
36
|
@overloaded = false
|
37
|
-
num_rows = @schema.connection.
|
37
|
+
num_rows = @schema.connection.select_all("
|
38
38
|
SELECT a.argument_name, a.position, a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale, a.overload
|
39
39
|
FROM all_arguments a, all_objects o
|
40
40
|
WHERE o.owner = :owner
|
@@ -76,7 +76,7 @@ module PLSQL
|
|
76
76
|
@overloads = @arguments.keys.sort
|
77
77
|
@overloads.each do |overload|
|
78
78
|
@argument_list[overload] = @arguments[overload].keys.sort {|k1, k2| @arguments[overload][k1][:position] <=> @arguments[overload][k2][:position]}
|
79
|
-
@out_list[overload] = @argument_list[overload].select {|k| @arguments[overload][k][:in_out]
|
79
|
+
@out_list[overload] = @argument_list[overload].select {|k| @arguments[overload][k][:in_out] =~ /OUT/}
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -145,12 +145,13 @@ module PLSQL
|
|
145
145
|
|
146
146
|
args_list.each do |k|
|
147
147
|
data_type, data_length = plsql_to_ruby_data_type(@arguments[overload][k])
|
148
|
-
cursor.bind_param(":#{k.to_s}", ruby_value_to_ora_value(args_hash[k], data_type),
|
148
|
+
cursor.bind_param(":#{k.to_s}", ruby_value_to_ora_value(args_hash[k], data_type),
|
149
|
+
data_type, data_length, @arguments[overload][k][:in_out])
|
149
150
|
end
|
150
151
|
|
151
152
|
if @return[overload]
|
152
153
|
data_type, data_length = plsql_to_ruby_data_type(@return[overload])
|
153
|
-
cursor.bind_param(":return", nil, data_type, data_length)
|
154
|
+
cursor.bind_param(":return", nil, data_type, data_length, 'OUT')
|
154
155
|
end
|
155
156
|
|
156
157
|
cursor.exec
|
@@ -181,47 +182,15 @@ module PLSQL
|
|
181
182
|
private
|
182
183
|
|
183
184
|
def plsql_to_ruby_data_type(argument)
|
184
|
-
|
185
|
-
when "VARCHAR2"
|
186
|
-
[String, argument[:data_length] ? argument[:data_length] : 4000]
|
187
|
-
when "NUMBER"
|
188
|
-
[OraNumber, nil]
|
189
|
-
when "DATE"
|
190
|
-
[DateTime, nil]
|
191
|
-
when "TIMESTAMP"
|
192
|
-
[Time, nil]
|
193
|
-
# CLOB
|
194
|
-
# BLOB
|
195
|
-
else
|
196
|
-
[String, 4000]
|
197
|
-
end
|
185
|
+
@schema.connection.plsql_to_ruby_data_type(argument[:data_type],argument[:data_length])
|
198
186
|
end
|
199
187
|
|
200
188
|
def ruby_value_to_ora_value(val, type)
|
201
|
-
|
202
|
-
val.nil? || val.is_a?(Fixnum) ? val : val.to_f
|
203
|
-
elsif type == DateTime
|
204
|
-
val ? val.to_datetime : nil
|
205
|
-
else
|
206
|
-
val
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def ora_number_to_ruby_number(num)
|
211
|
-
if num.to_i == num.to_f
|
212
|
-
num.to_i
|
213
|
-
else
|
214
|
-
num.to_f
|
215
|
-
end
|
189
|
+
@schema.connection.ruby_value_to_ora_value(val, type)
|
216
190
|
end
|
217
191
|
|
218
192
|
def ora_value_to_ruby_value(val)
|
219
|
-
|
220
|
-
when OraNumber
|
221
|
-
ora_number_to_ruby_number(val)
|
222
|
-
else
|
223
|
-
val
|
224
|
-
end
|
193
|
+
@schema.connection.ora_value_to_ruby_value(val)
|
225
194
|
end
|
226
195
|
|
227
196
|
end
|
data/lib/plsql/schema.rb
CHANGED
@@ -14,8 +14,8 @@ module PLSQL
|
|
14
14
|
|
15
15
|
end
|
16
16
|
|
17
|
-
def initialize(
|
18
|
-
self.connection =
|
17
|
+
def initialize(raw_conn = nil, schema = nil, first = true)
|
18
|
+
self.connection = raw_conn
|
19
19
|
@schema_name = schema ? schema.to_s.upcase : nil
|
20
20
|
@first = first
|
21
21
|
end
|
@@ -24,8 +24,8 @@ module PLSQL
|
|
24
24
|
@connection
|
25
25
|
end
|
26
26
|
|
27
|
-
def connection=(
|
28
|
-
@connection =
|
27
|
+
def connection=(raw_conn)
|
28
|
+
@connection = raw_conn ? Connection.create(raw_conn) : nil
|
29
29
|
if @connection
|
30
30
|
@procedures = {}
|
31
31
|
@packages = {}
|
@@ -48,10 +48,11 @@ module PLSQL
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def select_first(sql, *bindvars)
|
51
|
-
cursor = connection.exec(sql, *bindvars)
|
52
|
-
result = cursor.fetch
|
53
|
-
cursor.close
|
54
|
-
result
|
51
|
+
# cursor = connection.exec(sql, *bindvars)
|
52
|
+
# result = cursor.fetch
|
53
|
+
# cursor.close
|
54
|
+
# result
|
55
|
+
connection.select_first(sql, *bindvars)
|
55
56
|
end
|
56
57
|
|
57
58
|
def commit
|
@@ -87,7 +88,7 @@ module PLSQL
|
|
87
88
|
def find_other_schema(name)
|
88
89
|
return nil unless @first && connection
|
89
90
|
if select_first("SELECT username FROM all_users WHERE username = :username", name.to_s.upcase)
|
90
|
-
Schema.new(connection, name, false)
|
91
|
+
Schema.new(connection.raw_connection, name, false)
|
91
92
|
else
|
92
93
|
nil
|
93
94
|
end
|
data/lib/ruby_plsql.rb
CHANGED
@@ -3,14 +3,41 @@ $:.unshift File.dirname(__FILE__)
|
|
3
3
|
module RubyPlsql #:nodoc:
|
4
4
|
end
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
unless defined?(JRUBY_VERSION)
|
7
|
+
begin
|
8
|
+
require "oci8"
|
9
|
+
require "oradate_patch"
|
10
|
+
rescue LoadError
|
11
|
+
puts <<-EOS
|
12
|
+
To use ruby_plsql you must install ruby-oci8 library.
|
13
|
+
EOS
|
14
|
+
end
|
15
|
+
else
|
16
|
+
begin
|
17
|
+
require "java"
|
18
|
+
ojdbc_jar = "ojdbc14.jar"
|
19
|
+
if ojdbc_jar_path = ENV["PATH"].split(":").find{|d| File.exists?(File.join(d,ojdbc_jar))}
|
20
|
+
require File.join(ojdbc_jar_path,ojdbc_jar)
|
21
|
+
else
|
22
|
+
require ojdbc_jar
|
23
|
+
end
|
24
|
+
import java.sql.Statement
|
25
|
+
import java.sql.Connection
|
26
|
+
import java.sql.SQLException
|
27
|
+
import java.sql.Types
|
28
|
+
import java.sql.DriverManager
|
29
|
+
DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
|
30
|
+
rescue LoadError
|
31
|
+
puts <<-EOS
|
32
|
+
To use ruby_plsql you must have Oracle JDBC driver installed.
|
33
|
+
EOS
|
11
34
|
end
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
35
|
+
end
|
36
|
+
|
37
|
+
require "time"
|
38
|
+
require "date"
|
39
|
+
require "bigdecimal"
|
40
|
+
|
41
|
+
%w(connection schema procedure package).each do |file|
|
42
|
+
require File.dirname(__FILE__) + "/plsql/#{file}"
|
16
43
|
end
|
data/lib/ruby_plsql/version.rb
CHANGED
data/spec/plsql/package_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/../spec_helper'
|
|
2
2
|
|
3
3
|
describe "Package" do
|
4
4
|
before(:all) do
|
5
|
-
plsql.connection =
|
5
|
+
plsql.connection = get_connection
|
6
6
|
plsql.connection.exec <<-EOS
|
7
7
|
CREATE OR REPLACE PACKAGE test_package IS
|
8
8
|
FUNCTION test_procedure ( p_string VARCHAR2 )
|
@@ -6,7 +6,7 @@ require "activerecord"
|
|
6
6
|
describe "Function with string parameters" do
|
7
7
|
|
8
8
|
before(:all) do
|
9
|
-
plsql.connection =
|
9
|
+
plsql.connection = get_connection
|
10
10
|
plsql.connection.exec <<-EOS
|
11
11
|
CREATE OR REPLACE FUNCTION test_uppercase
|
12
12
|
( p_string VARCHAR2 )
|
@@ -59,7 +59,7 @@ end
|
|
59
59
|
describe "Function with numeric parameters" do
|
60
60
|
|
61
61
|
before(:all) do
|
62
|
-
plsql.connection =
|
62
|
+
plsql.connection = get_connection
|
63
63
|
plsql.connection.exec <<-EOS
|
64
64
|
CREATE OR REPLACE FUNCTION test_sum
|
65
65
|
( p_num1 NUMBER, p_num2 NUMBER )
|
@@ -100,7 +100,7 @@ end
|
|
100
100
|
describe "Function with date parameters" do
|
101
101
|
|
102
102
|
before(:all) do
|
103
|
-
plsql.connection =
|
103
|
+
plsql.connection = get_connection
|
104
104
|
plsql.connection.exec <<-EOS
|
105
105
|
CREATE OR REPLACE FUNCTION test_date
|
106
106
|
( p_date DATE )
|
@@ -116,26 +116,49 @@ describe "Function with date parameters" do
|
|
116
116
|
plsql.logoff
|
117
117
|
end
|
118
118
|
|
119
|
-
it "should process
|
120
|
-
now =
|
121
|
-
plsql.test_date(now).should == now +
|
119
|
+
it "should process Time parameters" do
|
120
|
+
now = Time.local(2008,8,12,14,28,0)
|
121
|
+
plsql.test_date(now).should == now + 60*60*24
|
122
122
|
end
|
123
123
|
|
124
|
+
it "should process DateTime parameters" do
|
125
|
+
now = DateTime.parse(Time.local(2008,8,12,14,28,0).iso8601)
|
126
|
+
result = plsql.test_date(now)
|
127
|
+
result.class.should == Time
|
128
|
+
result.should == Time.parse((now + 1).strftime("%c"))
|
129
|
+
end
|
130
|
+
|
124
131
|
it "should process old DateTime parameters" do
|
125
|
-
now = DateTime.new(
|
126
|
-
plsql.test_date(now)
|
132
|
+
now = DateTime.new(1901,1,1,12,0,0)
|
133
|
+
result = plsql.test_date(now)
|
134
|
+
unless defined?(JRUBY_VERSION)
|
135
|
+
result.class.should == DateTime
|
136
|
+
result.should == now + 1
|
137
|
+
else
|
138
|
+
result.class.should == Time
|
139
|
+
result.should == Time.parse((now + 1).strftime("%c"))
|
140
|
+
end
|
127
141
|
end
|
128
142
|
|
129
143
|
it "should process Date parameters" do
|
130
144
|
now = Date.new(2008,8,12)
|
131
|
-
plsql.test_date(now)
|
145
|
+
result = plsql.test_date(now)
|
146
|
+
result.class.should == Time
|
147
|
+
result.should == Time.parse((now + 1).strftime("%c"))
|
132
148
|
end
|
133
|
-
|
149
|
+
|
134
150
|
it "should process old Date parameters" do
|
135
|
-
now = Date.new(
|
136
|
-
plsql.test_date(now)
|
151
|
+
now = Date.new(1901,1,1)
|
152
|
+
result = plsql.test_date(now)
|
153
|
+
unless defined?(JRUBY_VERSION)
|
154
|
+
# result.class.should == DateTime
|
155
|
+
result.should == now + 1
|
156
|
+
else
|
157
|
+
result.class.should == Time
|
158
|
+
result.should == Time.parse((now + 1).strftime("%c"))
|
159
|
+
end
|
137
160
|
end
|
138
|
-
|
161
|
+
|
139
162
|
it "should process nil date parameter as NULL" do
|
140
163
|
plsql.test_date(nil).should be_nil
|
141
164
|
end
|
@@ -145,7 +168,7 @@ end
|
|
145
168
|
describe "Function with timestamp parameters" do
|
146
169
|
|
147
170
|
before(:all) do
|
148
|
-
plsql.connection =
|
171
|
+
plsql.connection = get_connection
|
149
172
|
plsql.connection.exec <<-EOS
|
150
173
|
CREATE OR REPLACE FUNCTION test_timestamp
|
151
174
|
( p_time TIMESTAMP )
|
@@ -170,7 +193,7 @@ end
|
|
170
193
|
|
171
194
|
describe "Procedure with output parameters" do
|
172
195
|
before(:all) do
|
173
|
-
plsql.connection =
|
196
|
+
plsql.connection = get_connection
|
174
197
|
plsql.connection.exec <<-EOS
|
175
198
|
CREATE OR REPLACE PROCEDURE test_copy
|
176
199
|
( p_from VARCHAR2, p_to OUT VARCHAR2, p_to_double OUT VARCHAR2 )
|
@@ -206,7 +229,7 @@ end
|
|
206
229
|
|
207
230
|
describe "Package with procedures with same name but different argument lists" do
|
208
231
|
before(:all) do
|
209
|
-
plsql.connection =
|
232
|
+
plsql.connection = get_connection
|
210
233
|
plsql.connection.exec <<-EOS
|
211
234
|
CREATE OR REPLACE PACKAGE test_package2 IS
|
212
235
|
FUNCTION test_procedure ( p_string VARCHAR2 )
|
@@ -295,7 +318,7 @@ end
|
|
295
318
|
|
296
319
|
describe "Function with output parameters" do
|
297
320
|
before(:all) do
|
298
|
-
plsql.connection =
|
321
|
+
plsql.connection = get_connection
|
299
322
|
plsql.connection.exec <<-EOS
|
300
323
|
CREATE OR REPLACE FUNCTION test_copy_function
|
301
324
|
( p_from VARCHAR2, p_to OUT VARCHAR2, p_to_double OUT VARCHAR2 )
|
@@ -334,7 +357,7 @@ end
|
|
334
357
|
|
335
358
|
describe "Function without parameters" do
|
336
359
|
before(:all) do
|
337
|
-
plsql.connection =
|
360
|
+
plsql.connection = get_connection
|
338
361
|
plsql.connection.exec <<-EOS
|
339
362
|
CREATE OR REPLACE FUNCTION test_no_params
|
340
363
|
RETURN VARCHAR2
|
data/spec/plsql/schema_spec.rb
CHANGED
@@ -8,24 +8,28 @@ describe "Schema" do
|
|
8
8
|
|
9
9
|
end
|
10
10
|
|
11
|
-
describe "
|
11
|
+
describe "Schema connection" do
|
12
12
|
|
13
13
|
before(:each) do
|
14
|
-
@conn =
|
14
|
+
@conn = get_connection
|
15
15
|
end
|
16
16
|
|
17
17
|
after(:each) do
|
18
|
-
|
18
|
+
unless defined? JRUBY_VERSION
|
19
|
+
@conn.logoff
|
20
|
+
else
|
21
|
+
@conn.close
|
22
|
+
end
|
19
23
|
end
|
20
24
|
|
21
25
|
it "should connect to test database" do
|
22
26
|
plsql.connection = @conn
|
23
|
-
plsql.connection.should == @conn
|
27
|
+
plsql.connection.raw_connection.should == @conn
|
24
28
|
end
|
25
29
|
|
26
30
|
it "should connect to test database using connection alias" do
|
27
31
|
plsql(:hr).connection = @conn
|
28
|
-
plsql(:hr).connection.should == @conn
|
32
|
+
plsql(:hr).connection.raw_connection.should == @conn
|
29
33
|
end
|
30
34
|
|
31
35
|
it "should return schema name" do
|
@@ -41,12 +45,11 @@ end
|
|
41
45
|
|
42
46
|
describe "Named Schema" do
|
43
47
|
before(:all) do
|
44
|
-
@conn =
|
45
|
-
plsql.connection = @conn
|
48
|
+
plsql.connection = @conn = get_connection
|
46
49
|
end
|
47
50
|
|
48
51
|
after(:all) do
|
49
|
-
|
52
|
+
plsql.connection.logoff
|
50
53
|
end
|
51
54
|
|
52
55
|
it "should find existing schema" do
|
@@ -54,7 +57,7 @@ describe "Named Schema" do
|
|
54
57
|
end
|
55
58
|
|
56
59
|
it "should have the same connection as default schema" do
|
57
|
-
plsql.hr.connection.should == @conn
|
60
|
+
plsql.hr.connection.raw_connection.should == @conn
|
58
61
|
end
|
59
62
|
|
60
63
|
it "should return schema name" do
|
data/spec/spec_helper.rb
CHANGED
@@ -7,3 +7,11 @@ rescue LoadError
|
|
7
7
|
end
|
8
8
|
|
9
9
|
require File.expand_path(File.dirname(__FILE__) + "/../lib/ruby_plsql")
|
10
|
+
|
11
|
+
def get_connection
|
12
|
+
unless defined?(JRUBY_VERSION)
|
13
|
+
OCI8.new("hr","hr","xe")
|
14
|
+
else
|
15
|
+
DriverManager.getConnection("jdbc:oracle:thin:@ubuntu710:1521:XE","hr","hr")
|
16
|
+
end
|
17
|
+
end
|
data/website/index.html
CHANGED
@@ -33,7 +33,7 @@
|
|
33
33
|
<h1>Ruby API for PL/SQL</h1>
|
34
34
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/ruby-plsql"; return false'>
|
35
35
|
<p>Get Version</p>
|
36
|
-
<a href="http://rubyforge.org/projects/ruby-plsql" class="numbers">0.
|
36
|
+
<a href="http://rubyforge.org/projects/ruby-plsql" class="numbers">0.2.0</a>
|
37
37
|
</div>
|
38
38
|
<h1>→ ‘ruby-plsql’</h1>
|
39
39
|
|
@@ -41,7 +41,9 @@
|
|
41
41
|
<h2>What</h2>
|
42
42
|
|
43
43
|
|
44
|
-
<p>ruby-plsql gem provides simple Ruby <span class="caps">API</span> for calling Oracle PL/SQL procedures.
|
44
|
+
<p>ruby-plsql gem provides simple Ruby <span class="caps">API</span> for calling Oracle PL/SQL procedures.
|
45
|
+
ruby-plsql support both <span class="caps">MRI</span> and JRuby runtime environments.
|
46
|
+
This gem requires ruby-oci8 library (if <span class="caps">MRI</span> is used) or Oracle <span class="caps">JDBC</span> driver (ojdbc14.jar) (if JRuby is used) for connection to Oracle database.</p>
|
45
47
|
|
46
48
|
|
47
49
|
<h2>Installing</h2>
|
@@ -88,10 +90,10 @@
|
|
88
90
|
<h2>How to submit patches</h2>
|
89
91
|
|
90
92
|
|
91
|
-
<p>Submit bugs and patches to <a href="http://
|
93
|
+
<p>Submit bugs and patches to <a href="http://rsim.lighthouseapp.com/projects/11470-ruby-plsql">Lighthouse</a></p>
|
92
94
|
|
93
95
|
|
94
|
-
<p>
|
96
|
+
<p>Source code is located at <a href="http://github.com/rsim/ruby-plsql">GitHub</a></p>
|
95
97
|
|
96
98
|
|
97
99
|
<h2>License</h2>
|
@@ -99,7 +101,7 @@
|
|
99
101
|
|
100
102
|
<p>This code is free to use under the terms of the <span class="caps">MIT</span> license.</p>
|
101
103
|
<p class="coda">
|
102
|
-
<a href="http://blog.rayapps.com">Raimonds Simanovskis</a>,
|
104
|
+
<a href="http://blog.rayapps.com">Raimonds Simanovskis</a>, 26th June 2008<br>
|
103
105
|
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
104
106
|
</p>
|
105
107
|
</div>
|
data/website/index.txt
CHANGED
@@ -5,7 +5,9 @@ h1. → 'ruby-plsql'
|
|
5
5
|
|
6
6
|
h2. What
|
7
7
|
|
8
|
-
ruby-plsql gem provides simple Ruby API for calling Oracle PL/SQL procedures.
|
8
|
+
ruby-plsql gem provides simple Ruby API for calling Oracle PL/SQL procedures.
|
9
|
+
ruby-plsql support both MRI and JRuby runtime environments.
|
10
|
+
This gem requires ruby-oci8 library (if MRI is used) or Oracle JDBC driver (ojdbc14.jar) (if JRuby is used) for connection to Oracle database.
|
9
11
|
|
10
12
|
h2. Installing
|
11
13
|
|
@@ -41,9 +43,9 @@ Submit your feedback as comments "here.":http://blog.rayapps.com/2008/03/15/ruby
|
|
41
43
|
|
42
44
|
h2. How to submit patches
|
43
45
|
|
44
|
-
Submit bugs and patches to "
|
46
|
+
Submit bugs and patches to "Lighthouse":http://rsim.lighthouseapp.com/projects/11470-ruby-plsql
|
45
47
|
|
46
|
-
|
48
|
+
Source code is located at "GitHub":http://github.com/rsim/ruby-plsql
|
47
49
|
|
48
50
|
h2. License
|
49
51
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-plsql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raimonds Simanovskis
|
@@ -34,6 +34,8 @@ files:
|
|
34
34
|
- Rakefile
|
35
35
|
- config/hoe.rb
|
36
36
|
- config/requirements.rb
|
37
|
+
- lib/oradate_patch.rb
|
38
|
+
- lib/plsql/connection.rb
|
37
39
|
- lib/plsql/package.rb
|
38
40
|
- lib/plsql/procedure.rb
|
39
41
|
- lib/plsql/schema.rb
|