ruby-plsql 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -30,9 +30,12 @@ module PLSQL
30
30
  @procedure = procedure.to_s.upcase
31
31
  @package = package
32
32
  @arguments = {}
33
- @return = nil
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
- argument_name, position, data_type, in_out, data_length, data_precision, data_scale = r
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
- @argument_list = @arguments.keys.sort {|k1, k2| @arguments[k1][:position] <=> @arguments[k2][:position]}
66
- @out_list = @argument_list.select {|k| @arguments[k][:in_out] == 'OUT'}
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?(Bignum) ? val.to_f : val
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
@@ -2,7 +2,7 @@ module RubyPlsql #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -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 date parameters" do
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 date parameters" do
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.2</a>
36
+ <a href="http://rubyforge.org/projects/ruby-plsql" class="numbers">0.1.3</a>
37
37
  </div>
38
38
  <h1>&#x2192; &#8216;ruby-plsql&#8217;</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.2
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-02 00:00:00 +03:00
12
+ date: 2008-04-16 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies: []
15
15