ruby-plsql 0.1.2 → 0.1.3
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 +9 -0
- data/lib/plsql/procedure.rb +64 -20
- data/lib/ruby_plsql/version.rb +1 -1
- data/spec/plsql/procedure_spec.rb +115 -3
- data/website/index.html +1 -1
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.1.3 2008-04-15
|
2
|
+
|
3
|
+
* Improvements
|
4
|
+
* Support for overloaded procedure definitions (named parameter calls compared by number of arguments and by argument names,
|
5
|
+
sequential parameters compared by number of arguments)
|
6
|
+
* Bug fixes
|
7
|
+
* Fixed BigDecimal support for procedure parameters (all number types except from Fixnum are converted to Float)
|
8
|
+
* Fixed Date parameters support (always will convert to DateTime)
|
9
|
+
|
1
10
|
== 0.1.2 2008-04-02
|
2
11
|
|
3
12
|
* Improvements
|
data/lib/plsql/procedure.rb
CHANGED
@@ -30,9 +30,12 @@ module PLSQL
|
|
30
30
|
@procedure = procedure.to_s.upcase
|
31
31
|
@package = package
|
32
32
|
@arguments = {}
|
33
|
-
@
|
33
|
+
@argument_list = {}
|
34
|
+
@out_list = {}
|
35
|
+
@return = {}
|
36
|
+
@overloaded = false
|
34
37
|
num_rows = @schema.connection.exec("
|
35
|
-
SELECT a.argument_name, a.position, a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale
|
38
|
+
SELECT a.argument_name, a.position, a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale, a.overload
|
36
39
|
FROM all_arguments a, all_objects o
|
37
40
|
WHERE o.owner = :owner
|
38
41
|
AND o.object_name = :object_name
|
@@ -42,9 +45,17 @@ module PLSQL
|
|
42
45
|
AND NVL(a.package_name,'nil') = :package
|
43
46
|
", @schema.schema_name, @package ? @package : @procedure, @procedure, @package ? @package : 'nil'
|
44
47
|
) do |r|
|
45
|
-
|
48
|
+
|
49
|
+
argument_name, position, data_type, in_out, data_length, data_precision, data_scale, overload = r
|
50
|
+
|
51
|
+
@overloaded ||= !overload.nil?
|
52
|
+
# if not overloaded then store arguments at key 0
|
53
|
+
overload ||= 0
|
54
|
+
@arguments[overload] ||= {}
|
55
|
+
@return[overload] ||= nil
|
56
|
+
|
46
57
|
if argument_name
|
47
|
-
@arguments[argument_name.downcase.to_sym] = {
|
58
|
+
@arguments[overload][argument_name.downcase.to_sym] = {
|
48
59
|
:position => position,
|
49
60
|
:data_type => data_type,
|
50
61
|
:in_out => in_out,
|
@@ -53,7 +64,7 @@ module PLSQL
|
|
53
64
|
:data_scale => data_scale
|
54
65
|
}
|
55
66
|
else
|
56
|
-
@return = {
|
67
|
+
@return[overload] = {
|
57
68
|
:data_type => data_type,
|
58
69
|
:in_out => in_out,
|
59
70
|
:data_length => data_length,
|
@@ -62,34 +73,65 @@ module PLSQL
|
|
62
73
|
}
|
63
74
|
end
|
64
75
|
end
|
65
|
-
@
|
66
|
-
@
|
76
|
+
@overloads = @arguments.keys.sort
|
77
|
+
@overloads.each do |overload|
|
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] == 'OUT'}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def overloaded?
|
84
|
+
@overloaded
|
67
85
|
end
|
68
86
|
|
69
87
|
def exec(*args)
|
88
|
+
# find which overloaded definition to use
|
89
|
+
# if definition is overloaded then match by number of arguments
|
90
|
+
if @overloaded
|
91
|
+
# named arguments
|
92
|
+
if args.size == 1 && args[0].is_a?(Hash)
|
93
|
+
number_of_args = args[0].keys.size
|
94
|
+
overload = @argument_list.keys.detect do |ov|
|
95
|
+
@argument_list[ov].size == number_of_args &&
|
96
|
+
@arguments[ov].keys.sort_by{|k| k.to_s} == args[0].keys.sort_by{|k| k.to_s}
|
97
|
+
end
|
98
|
+
# sequential arguments
|
99
|
+
# TODO: should try to implement matching by types of arguments
|
100
|
+
else
|
101
|
+
number_of_args = args.size
|
102
|
+
overload = @argument_list.keys.detect do |ov|
|
103
|
+
@argument_list[ov].size == number_of_args
|
104
|
+
end
|
105
|
+
end
|
106
|
+
raise ArgumentError, "Wrong number of arguments passed to overloaded PL/SQL procedure" unless overload
|
107
|
+
else
|
108
|
+
overload = 0
|
109
|
+
end
|
110
|
+
|
70
111
|
sql = "BEGIN\n"
|
71
|
-
sql << ":return := " if @return
|
112
|
+
sql << ":return := " if @return[overload]
|
72
113
|
sql << "#{@schema.schema_name}." if @schema
|
73
114
|
sql << "#{@package}." if @package
|
74
115
|
sql << "#{@procedure}("
|
116
|
+
|
75
117
|
# Named arguments
|
76
118
|
args_list = []
|
77
119
|
args_hash = {}
|
78
120
|
if args.size == 1 and args[0].is_a?(Hash)
|
79
121
|
sql << args[0].map do |k,v|
|
80
|
-
raise ArgumentError, "Wrong argument passed to PL/SQL procedure" unless @arguments[k]
|
122
|
+
raise ArgumentError, "Wrong argument passed to PL/SQL procedure" unless @arguments[overload][k]
|
81
123
|
args_list << k
|
82
124
|
args_hash[k] = v
|
83
125
|
"#{k.to_s} => :#{k.to_s}"
|
84
126
|
end.join(', ')
|
85
|
-
# Sequential arguments
|
127
|
+
# Sequential arguments
|
86
128
|
else
|
87
|
-
raise ArgumentError, "Too many arguments passed to PL/SQL procedure" if args.size > @argument_list.size
|
129
|
+
raise ArgumentError, "Too many arguments passed to PL/SQL procedure" if args.size > @argument_list[overload].size
|
88
130
|
# Add missing arguments with nil value
|
89
|
-
args = args + [nil]*(@argument_list.size-args.size) if args.size < @argument_list.size
|
131
|
+
args = args + [nil]*(@argument_list[overload].size-args.size) if args.size < @argument_list[overload].size
|
90
132
|
i = 0
|
91
133
|
sql << args.map do |v|
|
92
|
-
k = @argument_list[i]
|
134
|
+
k = @argument_list[overload][i]
|
93
135
|
i += 1
|
94
136
|
args_list << k
|
95
137
|
args_hash[k] = v
|
@@ -102,24 +144,24 @@ module PLSQL
|
|
102
144
|
cursor = @schema.connection.parse(sql)
|
103
145
|
|
104
146
|
args_list.each do |k|
|
105
|
-
data_type, data_length = plsql_to_ruby_data_type(@arguments[k])
|
147
|
+
data_type, data_length = plsql_to_ruby_data_type(@arguments[overload][k])
|
106
148
|
cursor.bind_param(":#{k.to_s}", ruby_value_to_ora_value(args_hash[k], data_type), data_type, data_length)
|
107
149
|
end
|
108
150
|
|
109
|
-
if @return
|
110
|
-
data_type, data_length = plsql_to_ruby_data_type(@return)
|
151
|
+
if @return[overload]
|
152
|
+
data_type, data_length = plsql_to_ruby_data_type(@return[overload])
|
111
153
|
cursor.bind_param(":return", nil, data_type, data_length)
|
112
154
|
end
|
113
155
|
|
114
156
|
cursor.exec
|
115
157
|
|
116
158
|
# if function
|
117
|
-
if @return
|
159
|
+
if @return[overload]
|
118
160
|
result = ora_value_to_ruby_value(cursor[':return'])
|
119
161
|
# if procedure with output parameters
|
120
|
-
elsif @out_list.size > 0
|
162
|
+
elsif @out_list[overload].size > 0
|
121
163
|
result = {}
|
122
|
-
@out_list.each do |k|
|
164
|
+
@out_list[overload].each do |k|
|
123
165
|
result[k] = ora_value_to_ruby_value(cursor[":#{k}"])
|
124
166
|
end
|
125
167
|
# if procedure without output parameters
|
@@ -151,7 +193,9 @@ module PLSQL
|
|
151
193
|
|
152
194
|
def ruby_value_to_ora_value(val, type)
|
153
195
|
if type == OraNumber
|
154
|
-
val.is_a?(
|
196
|
+
val.is_a?(Fixnum) ? val : val.to_f
|
197
|
+
elsif type == DateTime
|
198
|
+
val ? val.to_datetime : nil
|
155
199
|
else
|
156
200
|
val
|
157
201
|
end
|
data/lib/ruby_plsql/version.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
|
3
|
+
require "rubygems"
|
4
|
+
require "activerecord"
|
5
|
+
|
3
6
|
describe "Procedure with string parameters" do
|
4
7
|
|
5
8
|
before(:all) do
|
@@ -80,6 +83,12 @@ describe "Procedure with numeric parameters" do
|
|
80
83
|
plsql.test_sum(123.123,456.456).should == 579.579
|
81
84
|
end
|
82
85
|
|
86
|
+
it "should process BigDecimal parameters" do
|
87
|
+
plsql.test_sum(:p_num1 => BigDecimal.new("123.123"), :p_num2 => BigDecimal.new("456.456")).should == 579.579
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
|
83
92
|
end
|
84
93
|
|
85
94
|
describe "Procedure with date parameters" do
|
@@ -101,16 +110,30 @@ describe "Procedure with date parameters" do
|
|
101
110
|
plsql.logoff
|
102
111
|
end
|
103
112
|
|
104
|
-
it "should process
|
113
|
+
it "should process DateTime parameters" do
|
105
114
|
now = DateTime.new(2008,8,12,14,28,0)
|
106
115
|
plsql.test_date(now).should == now + 1
|
107
116
|
end
|
108
117
|
|
109
|
-
it "should process old
|
118
|
+
it "should process old DateTime parameters" do
|
110
119
|
now = DateTime.new(1900,1,1,12,0,0)
|
111
120
|
plsql.test_date(now).should == now + 1
|
112
121
|
end
|
113
122
|
|
123
|
+
it "should process Date parameters" do
|
124
|
+
now = Date.new(2008,8,12)
|
125
|
+
plsql.test_date(now).should == now + 1
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should process old Date parameters" do
|
129
|
+
now = Date.new(1900,1,1)
|
130
|
+
plsql.test_date(now).should == now + 1
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should process nil date parameters" do
|
134
|
+
plsql.test_date(nil).should be_nil
|
135
|
+
end
|
136
|
+
|
114
137
|
end
|
115
138
|
|
116
139
|
describe "Procedure with timestamp parameters" do
|
@@ -173,4 +196,93 @@ describe "Procedure with output parameters" do
|
|
173
196
|
plsql.test_copy.should == { :p_to => nil, :p_to_double => nil }
|
174
197
|
end
|
175
198
|
|
176
|
-
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "Package with procedures with same name but different argument lists" do
|
202
|
+
before(:all) do
|
203
|
+
plsql.connection = conn = OCI8.new("hr","hr","xe")
|
204
|
+
plsql.connection.exec <<-EOS
|
205
|
+
CREATE OR REPLACE PACKAGE test_package2 IS
|
206
|
+
FUNCTION test_procedure ( p_string VARCHAR2 )
|
207
|
+
RETURN VARCHAR2;
|
208
|
+
PROCEDURE test_procedure ( p_string VARCHAR2, p_result OUT VARCHAR2 )
|
209
|
+
;
|
210
|
+
PROCEDURE test_procedure ( p_number NUMBER, p_result OUT VARCHAR2 )
|
211
|
+
;
|
212
|
+
FUNCTION test_procedure2 ( p_string VARCHAR2 )
|
213
|
+
RETURN VARCHAR2;
|
214
|
+
END;
|
215
|
+
EOS
|
216
|
+
plsql.connection.exec <<-EOS
|
217
|
+
CREATE OR REPLACE PACKAGE BODY test_package2 IS
|
218
|
+
FUNCTION test_procedure ( p_string VARCHAR2 )
|
219
|
+
RETURN VARCHAR2
|
220
|
+
IS
|
221
|
+
BEGIN
|
222
|
+
RETURN UPPER(p_string);
|
223
|
+
END test_procedure;
|
224
|
+
PROCEDURE test_procedure ( p_string VARCHAR2, p_result OUT VARCHAR2 )
|
225
|
+
IS
|
226
|
+
BEGIN
|
227
|
+
p_result := UPPER(p_string);
|
228
|
+
END test_procedure;
|
229
|
+
PROCEDURE test_procedure ( p_number NUMBER, p_result OUT VARCHAR2 )
|
230
|
+
IS
|
231
|
+
BEGIN
|
232
|
+
p_result := LOWER(TO_CHAR(p_number));
|
233
|
+
END test_procedure;
|
234
|
+
FUNCTION test_procedure2 ( p_string VARCHAR2 )
|
235
|
+
RETURN VARCHAR2
|
236
|
+
IS
|
237
|
+
BEGIN
|
238
|
+
RETURN UPPER(p_string);
|
239
|
+
END test_procedure2;
|
240
|
+
END;
|
241
|
+
EOS
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
after(:all) do
|
246
|
+
plsql.logoff
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should find existing package" do
|
250
|
+
PLSQL::Package.find(plsql, :test_package2).should_not be_nil
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should identify overloaded procedure definition" do
|
254
|
+
@procedure = PLSQL::Procedure.find(plsql, :test_procedure, "TEST_PACKAGE2")
|
255
|
+
@procedure.should_not be_nil
|
256
|
+
@procedure.should be_overloaded
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should identify non-overloaded procedure definition" do
|
260
|
+
@procedure = PLSQL::Procedure.find(plsql, :test_procedure2, "TEST_PACKAGE2")
|
261
|
+
@procedure.should_not be_nil
|
262
|
+
@procedure.should_not be_overloaded
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should execute correct procedures based on number of arguments and return correct value" do
|
266
|
+
plsql.test_package2.test_procedure('xxx').should == 'XXX'
|
267
|
+
plsql.test_package2.test_procedure('xxx', nil).should == {:p_result => 'XXX'}
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should execute correct procedures based on number of named arguments and return correct value" do
|
271
|
+
plsql.test_package2.test_procedure(:p_string => 'xxx').should == 'XXX'
|
272
|
+
plsql.test_package2.test_procedure(:p_string => 'xxx', :p_result => nil).should == {:p_result => 'XXX'}
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should raise exception if procedure cannot be found based on number of arguments" do
|
276
|
+
lambda { plsql.test_package2.test_procedure() }.should raise_error(ArgumentError)
|
277
|
+
end
|
278
|
+
|
279
|
+
# TODO: should try to implement matching by types of arguments
|
280
|
+
# it "should find procedure based on types of arguments" do
|
281
|
+
# plsql.test_package2.test_procedure(111, nil).should == {:p_result => '111'}
|
282
|
+
# end
|
283
|
+
|
284
|
+
it "should find procedure based on names of named arguments" do
|
285
|
+
plsql.test_package2.test_procedure(:p_number => 111, :p_result => nil).should == {:p_result => '111'}
|
286
|
+
end
|
287
|
+
|
288
|
+
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.1.
|
36
|
+
<a href="http://rubyforge.org/projects/ruby-plsql" class="numbers">0.1.3</a>
|
37
37
|
</div>
|
38
38
|
<h1>→ ‘ruby-plsql’</h1>
|
39
39
|
|
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.1.
|
4
|
+
version: 0.1.3
|
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: 2008-04-
|
12
|
+
date: 2008-04-16 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|