ruby-plsql 0.3.1 → 0.4.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/.gitignore +10 -0
- data/History.txt +7 -0
- data/README.rdoc +97 -29
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/lib/plsql/connection.rb +85 -11
- data/lib/plsql/jdbc_connection.rb +317 -165
- data/lib/plsql/oci_connection.rb +158 -78
- data/lib/plsql/package.rb +5 -5
- data/lib/plsql/procedure.rb +69 -134
- data/lib/plsql/procedure_call.rb +345 -0
- data/lib/plsql/schema.rb +58 -40
- data/lib/plsql/sequence.rb +49 -0
- data/lib/plsql/sql_statements.rb +61 -0
- data/lib/plsql/table.rb +285 -0
- data/lib/plsql/version.rb +3 -0
- data/lib/ruby-plsql.rb +1 -0
- data/lib/ruby_plsql.rb +7 -40
- data/spec/plsql/connection_spec.rb +40 -24
- data/spec/plsql/procedure_spec.rb +1145 -453
- data/spec/plsql/schema_spec.rb +9 -2
- data/spec/plsql/sequence_spec.rb +67 -0
- data/spec/plsql/sql_statements_spec.rb +109 -0
- data/spec/plsql/table_spec.rb +269 -0
- data/spec/spec_helper.rb +20 -10
- metadata +35 -34
- data/lib/ruby_plsql/version.rb +0 -3
@@ -44,25 +44,25 @@ describe "Connection" do
|
|
44
44
|
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
|
45
45
|
describe "OCI data type conversions" do
|
46
46
|
it "should translate PL/SQL VARCHAR2 to Ruby String" do
|
47
|
-
@conn.plsql_to_ruby_data_type("VARCHAR2", 100).should == [String, 100]
|
48
|
-
@conn.plsql_to_ruby_data_type("VARCHAR2", nil).should == [String, 32767]
|
47
|
+
@conn.plsql_to_ruby_data_type(:data_type => "VARCHAR2", :data_length => 100).should == [String, 100]
|
48
|
+
@conn.plsql_to_ruby_data_type(:data_type => "VARCHAR2", :data_length => nil).should == [String, 32767]
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should translate PL/SQL CLOB to Ruby String" do
|
52
|
-
@conn.plsql_to_ruby_data_type("CLOB", 100_000).should == [OCI8::CLOB, nil]
|
53
|
-
@conn.plsql_to_ruby_data_type("CLOB", nil).should == [OCI8::CLOB, nil]
|
52
|
+
@conn.plsql_to_ruby_data_type(:data_type => "CLOB", :data_length => 100_000).should == [OCI8::CLOB, nil]
|
53
|
+
@conn.plsql_to_ruby_data_type(:data_type => "CLOB", :data_length => nil).should == [OCI8::CLOB, nil]
|
54
54
|
end
|
55
55
|
|
56
56
|
it "should translate PL/SQL NUMBER to Ruby OraNumber" do
|
57
|
-
@conn.plsql_to_ruby_data_type("NUMBER", 15).should == [OraNumber, nil]
|
57
|
+
@conn.plsql_to_ruby_data_type(:data_type => "NUMBER", :data_length => 15).should == [OraNumber, nil]
|
58
58
|
end
|
59
59
|
|
60
60
|
it "should translate PL/SQL DATE to Ruby DateTime" do
|
61
|
-
@conn.plsql_to_ruby_data_type("DATE", nil).should == [DateTime, nil]
|
61
|
+
@conn.plsql_to_ruby_data_type(:data_type => "DATE", :data_length => nil).should == [DateTime, nil]
|
62
62
|
end
|
63
63
|
|
64
64
|
it "should translate PL/SQL TIMESTAMP to Ruby Time" do
|
65
|
-
@conn.plsql_to_ruby_data_type("TIMESTAMP", nil).should == [Time, nil]
|
65
|
+
@conn.plsql_to_ruby_data_type(:data_type => "TIMESTAMP", :data_length => nil).should == [Time, nil]
|
66
66
|
end
|
67
67
|
|
68
68
|
it "should not translate Ruby Fixnum when OraNumber type specified" do
|
@@ -114,30 +114,29 @@ describe "Connection" do
|
|
114
114
|
|
115
115
|
describe "JDBC data type conversions" do
|
116
116
|
it "should translate PL/SQL VARCHAR2 to Ruby String" do
|
117
|
-
@conn.plsql_to_ruby_data_type("VARCHAR2", 100).should == [String, 100]
|
118
|
-
@conn.plsql_to_ruby_data_type("VARCHAR2", nil).should == [String, 32767]
|
117
|
+
@conn.plsql_to_ruby_data_type(:data_type => "VARCHAR2", :data_length => 100).should == [String, 100]
|
118
|
+
@conn.plsql_to_ruby_data_type(:data_type => "VARCHAR2", :data_length => nil).should == [String, 32767]
|
119
119
|
end
|
120
120
|
|
121
121
|
it "should translate PL/SQL NUMBER to Ruby BigDecimal" do
|
122
|
-
@conn.plsql_to_ruby_data_type("NUMBER", 15).should == [BigDecimal, nil]
|
122
|
+
@conn.plsql_to_ruby_data_type(:data_type => "NUMBER", :data_length => 15).should == [BigDecimal, nil]
|
123
123
|
end
|
124
124
|
|
125
125
|
it "should translate PL/SQL DATE to Ruby DateTime" do
|
126
|
-
@conn.plsql_to_ruby_data_type("DATE", nil).should == [Time, nil]
|
126
|
+
@conn.plsql_to_ruby_data_type(:data_type => "DATE", :data_length => nil).should == [Time, nil]
|
127
127
|
end
|
128
128
|
|
129
129
|
it "should translate PL/SQL TIMESTAMP to Ruby Time" do
|
130
|
-
@conn.plsql_to_ruby_data_type("TIMESTAMP", nil).should == [Time, nil]
|
130
|
+
@conn.plsql_to_ruby_data_type(:data_type => "TIMESTAMP", :data_length => nil).should == [Time, nil]
|
131
131
|
end
|
132
132
|
|
133
133
|
it "should not translate Ruby Fixnum when BigDecimal type specified" do
|
134
|
-
@conn.ruby_value_to_ora_value(100, BigDecimal).should
|
134
|
+
@conn.ruby_value_to_ora_value(100, BigDecimal).should == java.math.BigDecimal.new(100)
|
135
135
|
end
|
136
136
|
|
137
137
|
it "should translate Ruby Bignum value to BigDecimal when BigDecimal type specified" do
|
138
138
|
big_decimal = @conn.ruby_value_to_ora_value(12345678901234567890, BigDecimal)
|
139
|
-
big_decimal.
|
140
|
-
big_decimal.should == BigDecimal("12345678901234567890")
|
139
|
+
big_decimal.should == java.math.BigDecimal.new("12345678901234567890")
|
141
140
|
end
|
142
141
|
|
143
142
|
# it "should translate Ruby OraDate value to DateTime when DateTime type specified" do
|
@@ -189,7 +188,7 @@ describe "Connection" do
|
|
189
188
|
|
190
189
|
end
|
191
190
|
|
192
|
-
describe "SQL statements" do
|
191
|
+
describe "SQL SELECT statements" do
|
193
192
|
|
194
193
|
it "should execute SQL statement and return first result" do
|
195
194
|
@now = Time.local(2008,05,31,23,22,11)
|
@@ -198,6 +197,13 @@ describe "Connection" do
|
|
198
197
|
FROM dual").should == ["abc",123,123.456,@now]
|
199
198
|
end
|
200
199
|
|
200
|
+
it "should execute SQL statement and return first result as hash" do
|
201
|
+
@now = Time.local(2008,05,31,23,22,11)
|
202
|
+
@conn.select_hash_first("SELECT 'abc' a, 123 b, 123.456 c,
|
203
|
+
TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}', 'YYYY-MM-DD HH24:MI:SS') d
|
204
|
+
FROM dual").should == {:a => "abc", :b => 123, :c => 123.456, :d => @now}
|
205
|
+
end
|
206
|
+
|
201
207
|
it "should execute SQL statement with bind parameters and return first result" do
|
202
208
|
@today = Date.parse("2008-05-31")
|
203
209
|
@now = Time.local(2008,05,31,23,22,11)
|
@@ -232,7 +238,17 @@ describe "Connection" do
|
|
232
238
|
TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')
|
233
239
|
FROM dual").should == [["abc",123,123.456,@now],["abc",123,123.456,@now]]
|
234
240
|
end
|
235
|
-
|
241
|
+
|
242
|
+
it "should execute SQL statement and return all results as hash" do
|
243
|
+
@now = Time.local(2008,05,31,23,22,11)
|
244
|
+
@conn.select_hash_all("SELECT 'abc' a, 123 b, 123.456 c,
|
245
|
+
TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS') d
|
246
|
+
FROM dual
|
247
|
+
UNION ALL SELECT 'def' a, 123 b, 123.456 c,
|
248
|
+
TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS') d
|
249
|
+
FROM dual").should == [{:a=>"abc",:b=>123,:c=>123.456,:d=>@now},{:a=>"def",:b=>123,:c=>123.456,:d=>@now}]
|
250
|
+
end
|
251
|
+
|
236
252
|
it "should execute SQL statement with bind parameters and return all results" do
|
237
253
|
@now = Time.local(2008,05,31,23,22,11)
|
238
254
|
@conn.select_all("SELECT :1,:2,:3,:4 FROM dual UNION ALL SELECT :1,:2,:3,:4 FROM dual",
|
@@ -276,9 +292,9 @@ describe "Connection" do
|
|
276
292
|
@conn.exec(sql).should be_true
|
277
293
|
end
|
278
294
|
|
279
|
-
|
280
|
-
|
281
|
-
|
295
|
+
after(:each) do
|
296
|
+
@conn.exec "DROP FUNCTION test_add_random"
|
297
|
+
end
|
282
298
|
|
283
299
|
it "should parse PL/SQL procedure call and bind parameters and exec and get bind parameter value" do
|
284
300
|
sql = <<-EOS
|
@@ -287,10 +303,10 @@ describe "Connection" do
|
|
287
303
|
END;
|
288
304
|
EOS
|
289
305
|
cursor = @conn.parse(sql)
|
290
|
-
cursor.bind_param(":result",nil,
|
291
|
-
cursor.bind_param(":p_number",100,
|
292
|
-
cursor.bind_param(":p_varchar","abc",
|
293
|
-
cursor.bind_param(":p_date"
|
306
|
+
cursor.bind_param(":result", nil, :data_type => 'NUMBER', :in_out => 'OUT')
|
307
|
+
cursor.bind_param(":p_number", 100, :data_type => 'NUMBER', :in_out => 'IN')
|
308
|
+
cursor.bind_param(":p_varchar", "abc", :data_type => 'VARCHAR2', :in_out => 'IN/OUT')
|
309
|
+
cursor.bind_param(":p_date", @now, :data_type => 'DATE', :in_out => 'IN/OUT')
|
294
310
|
cursor.exec
|
295
311
|
cursor[":result"].should == @random + 100
|
296
312
|
cursor[":p_varchar"].should == "abc"
|
@@ -2,586 +2,1278 @@
|
|
2
2
|
|
3
3
|
require File.dirname(__FILE__) + '/../spec_helper'
|
4
4
|
|
5
|
-
|
6
|
-
# require "activerecord"
|
7
|
-
|
8
|
-
describe "Function with string parameters" do
|
9
|
-
|
5
|
+
describe "Parameter type mapping /" do
|
10
6
|
before(:all) do
|
11
7
|
plsql.connection = get_connection
|
12
|
-
plsql.connection.exec <<-EOS
|
13
|
-
CREATE OR REPLACE FUNCTION test_uppercase
|
14
|
-
( p_string VARCHAR2 )
|
15
|
-
RETURN VARCHAR2
|
16
|
-
IS
|
17
|
-
BEGIN
|
18
|
-
RETURN UPPER(p_string);
|
19
|
-
END test_uppercase;
|
20
|
-
EOS
|
21
8
|
end
|
22
|
-
|
9
|
+
|
23
10
|
after(:all) do
|
24
11
|
plsql.logoff
|
25
12
|
end
|
13
|
+
|
14
|
+
describe "Function with string parameters" do
|
26
15
|
|
27
|
-
|
28
|
-
|
29
|
-
|
16
|
+
before(:all) do
|
17
|
+
plsql.connection.exec <<-EOS
|
18
|
+
CREATE OR REPLACE FUNCTION test_uppercase
|
19
|
+
( p_string VARCHAR2 )
|
20
|
+
RETURN VARCHAR2
|
21
|
+
IS
|
22
|
+
BEGIN
|
23
|
+
RETURN UPPER(p_string);
|
24
|
+
END test_uppercase;
|
25
|
+
EOS
|
26
|
+
end
|
27
|
+
|
28
|
+
after(:all) do
|
29
|
+
plsql.connection.exec "DROP FUNCTION test_uppercase"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should find existing procedure" do
|
33
|
+
PLSQL::Procedure.find(plsql, :test_uppercase).should_not be_nil
|
34
|
+
end
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
|
36
|
+
it "should not find nonexisting procedure" do
|
37
|
+
PLSQL::Procedure.find(plsql, :qwerty123456).should be_nil
|
38
|
+
end
|
34
39
|
|
35
|
-
|
36
|
-
|
37
|
-
|
40
|
+
it "should execute function and return correct value" do
|
41
|
+
plsql.test_uppercase('xxx').should == 'XXX'
|
42
|
+
end
|
38
43
|
|
39
|
-
|
40
|
-
|
41
|
-
|
44
|
+
it "should execute function with named parameters and return correct value" do
|
45
|
+
plsql.test_uppercase(:p_string => 'xxx').should == 'XXX'
|
46
|
+
end
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
48
|
+
it "should raise error if wrong number of arguments is passed" do
|
49
|
+
lambda { plsql.test_uppercase('xxx','yyy') }.should raise_error(ArgumentError)
|
50
|
+
end
|
46
51
|
|
47
|
-
|
48
|
-
|
49
|
-
|
52
|
+
it "should raise error if wrong named argument is passed" do
|
53
|
+
lambda { plsql.test_uppercase(:p_string2 => 'xxx') }.should raise_error(ArgumentError)
|
54
|
+
end
|
50
55
|
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
it "should execute function with schema name specified" do
|
57
|
+
plsql.hr.test_uppercase('xxx').should == 'XXX'
|
58
|
+
end
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
it "should process nil parameter as NULL" do
|
61
|
+
plsql.test_uppercase(nil).should be_nil
|
62
|
+
end
|
58
63
|
|
59
|
-
end
|
64
|
+
end
|
60
65
|
|
61
|
-
describe "Function with numeric parameters" do
|
66
|
+
describe "Function with numeric parameters" do
|
62
67
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
68
|
+
before(:all) do
|
69
|
+
plsql.connection.exec <<-SQL
|
70
|
+
CREATE OR REPLACE FUNCTION test_sum
|
71
|
+
( p_num1 NUMBER, p_num2 NUMBER )
|
72
|
+
RETURN NUMBER
|
73
|
+
IS
|
74
|
+
BEGIN
|
75
|
+
RETURN p_num1 + p_num2;
|
76
|
+
END test_sum;
|
77
|
+
SQL
|
78
|
+
plsql.connection.exec <<-SQL
|
79
|
+
CREATE OR REPLACE FUNCTION test_number_1
|
80
|
+
( p_num NUMBER )
|
81
|
+
RETURN VARCHAR2
|
82
|
+
IS
|
83
|
+
BEGIN
|
84
|
+
IF p_num = 1 THEN
|
85
|
+
RETURN 'Y';
|
86
|
+
ELSIF p_num = 0 THEN
|
87
|
+
RETURN 'N';
|
88
|
+
ELSIF p_num IS NULL THEN
|
89
|
+
RETURN NULL;
|
90
|
+
ELSE
|
91
|
+
RETURN 'UNKNOWN';
|
92
|
+
END IF;
|
93
|
+
END test_number_1;
|
94
|
+
SQL
|
95
|
+
end
|
75
96
|
|
76
|
-
|
77
|
-
|
78
|
-
|
97
|
+
after(:all) do
|
98
|
+
plsql.connection.exec "DROP FUNCTION test_sum"
|
99
|
+
plsql.connection.exec "DROP FUNCTION test_number_1"
|
100
|
+
end
|
79
101
|
|
80
|
-
|
81
|
-
|
82
|
-
|
102
|
+
it "should process integer parameters" do
|
103
|
+
plsql.test_sum(123,456).should == 579
|
104
|
+
end
|
83
105
|
|
84
|
-
|
85
|
-
|
86
|
-
|
106
|
+
it "should process big integer parameters" do
|
107
|
+
plsql.test_sum(123123123123,456456456456).should == 579579579579
|
108
|
+
end
|
87
109
|
|
88
|
-
|
89
|
-
|
90
|
-
|
110
|
+
it "should process float parameters and return BigDecimal" do
|
111
|
+
plsql.test_sum(123.123,456.456).should == BigDecimal("579.579")
|
112
|
+
end
|
91
113
|
|
92
|
-
|
93
|
-
|
94
|
-
|
114
|
+
it "should process BigDecimal parameters and return BigDecimal" do
|
115
|
+
plsql.test_sum(:p_num1 => BigDecimal("123.123"), :p_num2 => BigDecimal("456.456")).should == BigDecimal("579.579")
|
116
|
+
end
|
95
117
|
|
96
|
-
|
97
|
-
|
98
|
-
|
118
|
+
it "should process nil parameter as NULL" do
|
119
|
+
plsql.test_sum(123,nil).should be_nil
|
120
|
+
end
|
99
121
|
|
100
|
-
|
122
|
+
it "should convert true value to 1 for NUMBER parameter" do
|
123
|
+
plsql.test_number_1(true).should == 'Y'
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should convert false value to 0 for NUMBER parameter" do
|
127
|
+
plsql.test_number_1(false).should == 'N'
|
128
|
+
end
|
101
129
|
|
102
|
-
describe "Function with date parameters" do
|
103
|
-
|
104
|
-
before(:all) do
|
105
|
-
plsql.connection = get_connection
|
106
|
-
plsql.connection.exec <<-EOS
|
107
|
-
CREATE OR REPLACE FUNCTION test_date
|
108
|
-
( p_date DATE )
|
109
|
-
RETURN DATE
|
110
|
-
IS
|
111
|
-
BEGIN
|
112
|
-
RETURN p_date + 1;
|
113
|
-
END test_date;
|
114
|
-
EOS
|
115
130
|
end
|
131
|
+
|
132
|
+
describe "Function with date parameters" do
|
116
133
|
|
117
|
-
|
118
|
-
|
119
|
-
|
134
|
+
before(:all) do
|
135
|
+
plsql.connection.exec <<-EOS
|
136
|
+
CREATE OR REPLACE FUNCTION test_date
|
137
|
+
( p_date DATE )
|
138
|
+
RETURN DATE
|
139
|
+
IS
|
140
|
+
BEGIN
|
141
|
+
RETURN p_date + 1;
|
142
|
+
END test_date;
|
143
|
+
EOS
|
144
|
+
end
|
145
|
+
|
146
|
+
before(:each) do
|
147
|
+
plsql.default_timezone = :local
|
148
|
+
end
|
120
149
|
|
121
|
-
|
122
|
-
|
123
|
-
|
150
|
+
after(:all) do
|
151
|
+
plsql.connection.exec "DROP FUNCTION test_date"
|
152
|
+
end
|
124
153
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
154
|
+
it "should process Time parameters" do
|
155
|
+
now = Time.local(2008,8,12,14,28,0)
|
156
|
+
plsql.test_date(now).should == now + 60*60*24
|
157
|
+
end
|
129
158
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
159
|
+
it "should process UTC Time parameters" do
|
160
|
+
plsql.default_timezone = :utc
|
161
|
+
now = Time.utc(2008,8,12,14,28,0)
|
162
|
+
plsql.test_date(now).should == now + 60*60*24
|
163
|
+
end
|
135
164
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
165
|
+
it "should process DateTime parameters" do
|
166
|
+
now = DateTime.parse(Time.local(2008,8,12,14,28,0).iso8601)
|
167
|
+
result = plsql.test_date(now)
|
168
|
+
result.class.should == Time
|
169
|
+
result.should == Time.parse((now + 1).strftime("%c"))
|
170
|
+
end
|
142
171
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
unless defined?(JRUBY_VERSION)
|
147
|
-
result.class.should == DateTime
|
148
|
-
result.should == now + 1
|
149
|
-
else
|
172
|
+
it "should process old DateTime parameters" do
|
173
|
+
now = DateTime.civil(1901,1,1,12,0,0,plsql.local_timezone_offset)
|
174
|
+
result = plsql.test_date(now)
|
150
175
|
result.class.should == Time
|
151
176
|
result.should == Time.parse((now + 1).strftime("%c"))
|
152
177
|
end
|
153
|
-
end
|
154
178
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
179
|
+
it "should process Date parameters" do
|
180
|
+
now = Date.new(2008,8,12)
|
181
|
+
result = plsql.test_date(now)
|
182
|
+
result.class.should == Time
|
183
|
+
result.should == Time.parse((now + 1).strftime("%c"))
|
184
|
+
end
|
161
185
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
unless defined?(JRUBY_VERSION)
|
166
|
-
result.class.should == DateTime
|
167
|
-
result.strftime("%c").should == (now + 1).strftime("%c")
|
168
|
-
else
|
186
|
+
it "should process old Date parameters" do
|
187
|
+
now = Date.new(1901,1,1)
|
188
|
+
result = plsql.test_date(now)
|
169
189
|
result.class.should == Time
|
170
190
|
result.should == Time.parse((now + 1).strftime("%c"))
|
171
191
|
end
|
192
|
+
|
193
|
+
it "should process nil date parameter as NULL" do
|
194
|
+
plsql.test_date(nil).should be_nil
|
195
|
+
end
|
196
|
+
|
172
197
|
end
|
198
|
+
|
199
|
+
describe "Function with timestamp parameters" do
|
173
200
|
|
174
|
-
|
175
|
-
|
201
|
+
before(:all) do
|
202
|
+
plsql.connection.exec <<-EOS
|
203
|
+
CREATE OR REPLACE FUNCTION test_timestamp
|
204
|
+
( p_time TIMESTAMP )
|
205
|
+
RETURN TIMESTAMP
|
206
|
+
IS
|
207
|
+
BEGIN
|
208
|
+
RETURN p_time + NUMTODSINTERVAL(1, 'DAY');
|
209
|
+
END test_timestamp;
|
210
|
+
EOS
|
211
|
+
end
|
212
|
+
|
213
|
+
after(:all) do
|
214
|
+
plsql.connection.exec "DROP FUNCTION test_timestamp"
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should process timestamp parameters" do
|
218
|
+
# now = Time.now
|
219
|
+
now = Time.local(2008,8,12,14,28,0)
|
220
|
+
plsql.test_timestamp(now).should == now + 60*60*24
|
221
|
+
end
|
222
|
+
|
176
223
|
end
|
177
224
|
|
178
|
-
|
225
|
+
describe "Procedure with output parameters" do
|
226
|
+
before(:all) do
|
227
|
+
plsql.connection.exec <<-EOS
|
228
|
+
CREATE OR REPLACE PROCEDURE test_copy
|
229
|
+
( p_from VARCHAR2, p_to OUT VARCHAR2, p_to_double OUT VARCHAR2 )
|
230
|
+
IS
|
231
|
+
BEGIN
|
232
|
+
p_to := p_from;
|
233
|
+
p_to_double := p_from || p_from;
|
234
|
+
END test_copy;
|
235
|
+
EOS
|
236
|
+
end
|
237
|
+
|
238
|
+
after(:all) do
|
239
|
+
plsql.connection.exec "DROP PROCEDURE test_copy"
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should return hash with output parameters" do
|
243
|
+
plsql.test_copy("abc", nil, nil).should == { :p_to => "abc", :p_to_double => "abcabc" }
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should return hash with output parameters when called with named parameters" do
|
247
|
+
plsql.test_copy(:p_from => "abc", :p_to => nil, :p_to_double => nil).should == { :p_to => "abc", :p_to_double => "abcabc" }
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should substitute output parameters with nil if they are not specified" do
|
251
|
+
plsql.test_copy("abc").should == { :p_to => "abc", :p_to_double => "abcabc" }
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should substitute named output parameters with nil if they are not specified" do
|
255
|
+
plsql.test_copy(:p_from => "abc").should == { :p_to => "abc", :p_to_double => "abcabc" }
|
256
|
+
end
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
describe "Package with procedures with same name but different argument lists" do
|
261
|
+
before(:all) do
|
262
|
+
plsql.connection.exec <<-EOS
|
263
|
+
CREATE OR REPLACE PACKAGE test_package2 IS
|
264
|
+
FUNCTION test_procedure ( p_string VARCHAR2 )
|
265
|
+
RETURN VARCHAR2;
|
266
|
+
PROCEDURE test_procedure ( p_string VARCHAR2, p_result OUT VARCHAR2 )
|
267
|
+
;
|
268
|
+
PROCEDURE test_procedure ( p_number NUMBER, p_result OUT VARCHAR2 )
|
269
|
+
;
|
270
|
+
FUNCTION test_procedure2 ( p_string VARCHAR2 )
|
271
|
+
RETURN VARCHAR2;
|
272
|
+
END;
|
273
|
+
EOS
|
274
|
+
plsql.connection.exec <<-EOS
|
275
|
+
CREATE OR REPLACE PACKAGE BODY test_package2 IS
|
276
|
+
FUNCTION test_procedure ( p_string VARCHAR2 )
|
277
|
+
RETURN VARCHAR2
|
278
|
+
IS
|
279
|
+
BEGIN
|
280
|
+
RETURN UPPER(p_string);
|
281
|
+
END test_procedure;
|
282
|
+
PROCEDURE test_procedure ( p_string VARCHAR2, p_result OUT VARCHAR2 )
|
283
|
+
IS
|
284
|
+
BEGIN
|
285
|
+
p_result := UPPER(p_string);
|
286
|
+
END test_procedure;
|
287
|
+
PROCEDURE test_procedure ( p_number NUMBER, p_result OUT VARCHAR2 )
|
288
|
+
IS
|
289
|
+
BEGIN
|
290
|
+
p_result := LOWER(TO_CHAR(p_number));
|
291
|
+
END test_procedure;
|
292
|
+
FUNCTION test_procedure2 ( p_string VARCHAR2 )
|
293
|
+
RETURN VARCHAR2
|
294
|
+
IS
|
295
|
+
BEGIN
|
296
|
+
RETURN UPPER(p_string);
|
297
|
+
END test_procedure2;
|
298
|
+
END;
|
299
|
+
EOS
|
179
300
|
|
180
|
-
|
301
|
+
end
|
181
302
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
303
|
+
after(:all) do
|
304
|
+
plsql.connection.exec "DROP PACKAGE test_package2"
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should find existing package" do
|
308
|
+
PLSQL::Package.find(plsql, :test_package2).should_not be_nil
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should identify overloaded procedure definition" do
|
312
|
+
@procedure = PLSQL::Procedure.find(plsql, :test_procedure, "TEST_PACKAGE2")
|
313
|
+
@procedure.should_not be_nil
|
314
|
+
@procedure.should be_overloaded
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should identify non-overloaded procedure definition" do
|
318
|
+
@procedure = PLSQL::Procedure.find(plsql, :test_procedure2, "TEST_PACKAGE2")
|
319
|
+
@procedure.should_not be_nil
|
320
|
+
@procedure.should_not be_overloaded
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should execute correct procedures based on number of arguments and return correct value" do
|
324
|
+
plsql.test_package2.test_procedure('xxx').should == 'XXX'
|
325
|
+
plsql.test_package2.test_procedure('xxx', nil).should == {:p_result => 'XXX'}
|
326
|
+
end
|
327
|
+
|
328
|
+
it "should execute correct procedures based on number of named arguments and return correct value" do
|
329
|
+
plsql.test_package2.test_procedure(:p_string => 'xxx').should == 'XXX'
|
330
|
+
plsql.test_package2.test_procedure(:p_string => 'xxx', :p_result => nil).should == {:p_result => 'XXX'}
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should raise exception if procedure cannot be found based on number of arguments" do
|
334
|
+
lambda { plsql.test_package2.test_procedure() }.should raise_error(ArgumentError)
|
335
|
+
end
|
336
|
+
|
337
|
+
# TODO: should try to implement matching by types of arguments
|
338
|
+
# it "should find procedure based on types of arguments" do
|
339
|
+
# plsql.test_package2.test_procedure(111, nil).should == {:p_result => '111'}
|
340
|
+
# end
|
341
|
+
|
342
|
+
it "should find procedure based on names of named arguments" do
|
343
|
+
plsql.test_package2.test_procedure(:p_number => 111, :p_result => nil).should == {:p_result => '111'}
|
344
|
+
end
|
345
|
+
|
193
346
|
end
|
347
|
+
|
348
|
+
describe "Function with output parameters" do
|
349
|
+
before(:all) do
|
350
|
+
plsql.connection.exec <<-EOS
|
351
|
+
CREATE OR REPLACE FUNCTION test_copy_function
|
352
|
+
( p_from VARCHAR2, p_to OUT VARCHAR2, p_to_double OUT VARCHAR2 )
|
353
|
+
RETURN NUMBER
|
354
|
+
IS
|
355
|
+
BEGIN
|
356
|
+
p_to := p_from;
|
357
|
+
p_to_double := p_from || p_from;
|
358
|
+
RETURN LENGTH(p_from);
|
359
|
+
END test_copy_function;
|
360
|
+
EOS
|
361
|
+
end
|
194
362
|
|
195
|
-
|
196
|
-
|
363
|
+
after(:all) do
|
364
|
+
plsql.connection.exec "DROP FUNCTION test_copy_function"
|
365
|
+
end
|
366
|
+
|
367
|
+
it "should return array with return value and hash of output parameters" do
|
368
|
+
plsql.test_copy_function("abc", nil, nil).should == [3, { :p_to => "abc", :p_to_double => "abcabc" }]
|
369
|
+
end
|
370
|
+
|
371
|
+
it "should return array with return value and hash of output parameters when called with named parameters" do
|
372
|
+
plsql.test_copy_function(:p_from => "abc", :p_to => nil, :p_to_double => nil).should ==
|
373
|
+
[3, { :p_to => "abc", :p_to_double => "abcabc" }]
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should substitute output parameters with nil if they are not specified" do
|
377
|
+
plsql.test_copy_function("abc").should == [3, { :p_to => "abc", :p_to_double => "abcabc" }]
|
378
|
+
end
|
379
|
+
|
197
380
|
end
|
381
|
+
|
382
|
+
describe "Function or procedure without parameters" do
|
383
|
+
before(:all) do
|
384
|
+
plsql.connection.exec <<-EOS
|
385
|
+
CREATE OR REPLACE FUNCTION test_no_params
|
386
|
+
RETURN VARCHAR2
|
387
|
+
IS
|
388
|
+
BEGIN
|
389
|
+
RETURN 'dummy';
|
390
|
+
END test_no_params;
|
391
|
+
EOS
|
392
|
+
plsql.connection.exec <<-EOS
|
393
|
+
CREATE OR REPLACE PROCEDURE test_proc_no_params
|
394
|
+
IS
|
395
|
+
BEGIN
|
396
|
+
NULL;
|
397
|
+
END test_proc_no_params;
|
398
|
+
EOS
|
399
|
+
end
|
198
400
|
|
199
|
-
|
200
|
-
|
201
|
-
|
401
|
+
after(:all) do
|
402
|
+
plsql.connection.exec "DROP FUNCTION test_no_params"
|
403
|
+
plsql.connection.exec "DROP PROCEDURE test_proc_no_params"
|
404
|
+
end
|
405
|
+
|
406
|
+
it "should find function" do
|
407
|
+
PLSQL::Procedure.find(plsql, :test_no_params).should_not be_nil
|
408
|
+
end
|
409
|
+
|
410
|
+
it "should return function value" do
|
411
|
+
plsql.test_no_params.should == "dummy"
|
412
|
+
end
|
413
|
+
|
414
|
+
it "should find procedure" do
|
415
|
+
PLSQL::Procedure.find(plsql, :test_proc_no_params).should_not be_nil
|
416
|
+
end
|
417
|
+
|
418
|
+
it "should execute procedure" do
|
419
|
+
plsql.test_proc_no_params.should be_nil
|
420
|
+
end
|
421
|
+
|
202
422
|
end
|
203
423
|
|
204
|
-
|
424
|
+
describe "Function with CLOB parameter and return value" do
|
425
|
+
|
426
|
+
before(:all) do
|
427
|
+
plsql.connection.exec <<-EOS
|
428
|
+
CREATE OR REPLACE FUNCTION test_clob
|
429
|
+
( p_clob CLOB )
|
430
|
+
RETURN CLOB
|
431
|
+
IS
|
432
|
+
BEGIN
|
433
|
+
RETURN p_clob;
|
434
|
+
END test_clob;
|
435
|
+
EOS
|
436
|
+
end
|
437
|
+
|
438
|
+
after(:all) do
|
439
|
+
plsql.connection.exec "DROP FUNCTION test_clob"
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should find existing procedure" do
|
443
|
+
PLSQL::Procedure.find(plsql, :test_clob).should_not be_nil
|
444
|
+
end
|
445
|
+
|
446
|
+
it "should execute function and return correct value" do
|
447
|
+
large_text = 'ābčdēfghij' * 10_000
|
448
|
+
plsql.test_clob(large_text).should == large_text
|
449
|
+
end
|
450
|
+
|
451
|
+
unless defined?(JRUBY_VERSION)
|
452
|
+
|
453
|
+
it "should execute function with empty string and return nil (oci8 cannot pass empty CLOB parameter)" do
|
454
|
+
text = ''
|
455
|
+
plsql.test_clob(text).should be_nil
|
456
|
+
end
|
457
|
+
|
458
|
+
else
|
459
|
+
|
460
|
+
it "should execute function with empty string and return empty string" do
|
461
|
+
text = ''
|
462
|
+
plsql.test_clob(text).should == text
|
463
|
+
end
|
464
|
+
|
465
|
+
end
|
466
|
+
|
467
|
+
it "should execute function with nil and return nil" do
|
468
|
+
plsql.test_clob(nil).should be_nil
|
469
|
+
end
|
205
470
|
|
206
|
-
describe "Procedure with output parameters" do
|
207
|
-
before(:all) do
|
208
|
-
plsql.connection = get_connection
|
209
|
-
plsql.connection.exec <<-EOS
|
210
|
-
CREATE OR REPLACE PROCEDURE test_copy
|
211
|
-
( p_from VARCHAR2, p_to OUT VARCHAR2, p_to_double OUT VARCHAR2 )
|
212
|
-
IS
|
213
|
-
BEGIN
|
214
|
-
p_to := p_from;
|
215
|
-
p_to_double := p_from || p_from;
|
216
|
-
END test_copy;
|
217
|
-
EOS
|
218
471
|
end
|
472
|
+
|
473
|
+
describe "Procedrue with CLOB parameter and return value" do
|
219
474
|
|
220
|
-
|
221
|
-
|
475
|
+
before(:all) do
|
476
|
+
plsql.connection.exec <<-EOS
|
477
|
+
CREATE OR REPLACE PROCEDURE test_clob_proc
|
478
|
+
( p_clob CLOB,
|
479
|
+
p_return OUT CLOB)
|
480
|
+
IS
|
481
|
+
BEGIN
|
482
|
+
p_return := p_clob;
|
483
|
+
END test_clob_proc;
|
484
|
+
EOS
|
485
|
+
end
|
486
|
+
|
487
|
+
after(:all) do
|
488
|
+
plsql.connection.exec "DROP PROCEDURE test_clob_proc"
|
489
|
+
end
|
490
|
+
|
491
|
+
it "should find existing procedure" do
|
492
|
+
PLSQL::Procedure.find(plsql, :test_clob_proc).should_not be_nil
|
493
|
+
end
|
494
|
+
|
495
|
+
it "should execute function and return correct value" do
|
496
|
+
large_text = 'ābčdēfghij' * 10_000
|
497
|
+
plsql.test_clob_proc(large_text)[:p_return].should == large_text
|
498
|
+
end
|
222
499
|
end
|
500
|
+
|
501
|
+
describe "Procedrue with BLOB parameter and return value" do
|
502
|
+
|
503
|
+
before(:all) do
|
504
|
+
plsql.connection.exec <<-EOS
|
505
|
+
CREATE OR REPLACE PROCEDURE test_blob_proc
|
506
|
+
( p_blob BLOB,
|
507
|
+
p_return OUT BLOB)
|
508
|
+
IS
|
509
|
+
BEGIN
|
510
|
+
p_return := p_blob;
|
511
|
+
END test_blob_proc;
|
512
|
+
EOS
|
513
|
+
end
|
223
514
|
|
224
|
-
|
225
|
-
|
515
|
+
after(:all) do
|
516
|
+
plsql.connection.exec "DROP PROCEDURE test_blob_proc"
|
517
|
+
end
|
518
|
+
|
519
|
+
it "should find existing procedure" do
|
520
|
+
PLSQL::Procedure.find(plsql, :test_blob_proc).should_not be_nil
|
521
|
+
end
|
522
|
+
|
523
|
+
it "should execute function and return correct value" do
|
524
|
+
large_binary = '\000\001\002\003\004\005\006\007\010\011' * 10_000
|
525
|
+
plsql.test_blob_proc(large_binary)[:p_return].should == large_binary
|
526
|
+
end
|
226
527
|
end
|
227
528
|
|
228
|
-
|
229
|
-
|
529
|
+
describe "Function with record parameter" do
|
530
|
+
|
531
|
+
before(:all) do
|
532
|
+
plsql.connection.exec "DROP TABLE test_employees" rescue nil
|
533
|
+
plsql.connection.exec <<-SQL
|
534
|
+
CREATE TABLE test_employees (
|
535
|
+
employee_id NUMBER(15),
|
536
|
+
first_name VARCHAR2(50),
|
537
|
+
last_name VARCHAR2(50),
|
538
|
+
hire_date DATE
|
539
|
+
)
|
540
|
+
SQL
|
541
|
+
plsql.connection.exec <<-SQL
|
542
|
+
CREATE OR REPLACE FUNCTION test_full_name (p_employee test_employees%ROWTYPE)
|
543
|
+
RETURN VARCHAR2
|
544
|
+
IS
|
545
|
+
BEGIN
|
546
|
+
RETURN p_employee.first_name || ' ' || p_employee.last_name;
|
547
|
+
END test_full_name;
|
548
|
+
SQL
|
549
|
+
plsql.connection.exec <<-SQL
|
550
|
+
CREATE OR REPLACE FUNCTION test_employee_record (p_employee test_employees%ROWTYPE)
|
551
|
+
RETURN test_employees%ROWTYPE
|
552
|
+
IS
|
553
|
+
BEGIN
|
554
|
+
RETURN p_employee;
|
555
|
+
END test_employee_record;
|
556
|
+
SQL
|
557
|
+
plsql.connection.exec <<-SQL
|
558
|
+
CREATE OR REPLACE FUNCTION test_employee_record2 (p_employee test_employees%ROWTYPE, x_employee OUT test_employees%ROWTYPE)
|
559
|
+
RETURN test_employees%ROWTYPE
|
560
|
+
IS
|
561
|
+
BEGIN
|
562
|
+
x_employee.employee_id := p_employee.employee_id;
|
563
|
+
x_employee.first_name := p_employee.first_name;
|
564
|
+
x_employee.last_name := p_employee.last_name;
|
565
|
+
x_employee.hire_date := p_employee.hire_date;
|
566
|
+
RETURN p_employee;
|
567
|
+
END test_employee_record2;
|
568
|
+
SQL
|
569
|
+
@p_employee = {
|
570
|
+
:employee_id => 1,
|
571
|
+
:first_name => 'First',
|
572
|
+
:last_name => 'Last',
|
573
|
+
:hire_date => Time.local(2000,01,31)
|
574
|
+
}
|
575
|
+
@p_employee2 = {
|
576
|
+
'employee_id' => 1,
|
577
|
+
'FIRST_NAME' => 'Second',
|
578
|
+
'last_name' => 'Last',
|
579
|
+
'hire_date' => Time.local(2000,01,31)
|
580
|
+
}
|
581
|
+
end
|
582
|
+
|
583
|
+
after(:all) do
|
584
|
+
plsql.connection.exec "DROP FUNCTION test_full_name"
|
585
|
+
plsql.connection.exec "DROP FUNCTION test_employee_record"
|
586
|
+
plsql.connection.exec "DROP FUNCTION test_employee_record2"
|
587
|
+
plsql.connection.exec "DROP TABLE test_employees"
|
588
|
+
end
|
589
|
+
|
590
|
+
it "should find existing function" do
|
591
|
+
PLSQL::Procedure.find(plsql, :test_full_name).should_not be_nil
|
592
|
+
end
|
593
|
+
|
594
|
+
it "should execute function with named parameter and return correct value" do
|
595
|
+
plsql.test_full_name(:p_employee => @p_employee).should == 'First Last'
|
596
|
+
end
|
597
|
+
|
598
|
+
it "should execute function with sequential parameter and return correct value" do
|
599
|
+
plsql.test_full_name(@p_employee).should == 'First Last'
|
600
|
+
end
|
601
|
+
|
602
|
+
it "should execute function with Hash parameter using strings as keys" do
|
603
|
+
plsql.test_full_name(@p_employee2).should == 'Second Last'
|
604
|
+
end
|
605
|
+
|
606
|
+
it "should raise error if wrong field name is passed for record parameter" do
|
607
|
+
lambda do
|
608
|
+
plsql.test_full_name(@p_employee.merge :xxx => 'xxx').should == 'Second Last'
|
609
|
+
end.should raise_error(ArgumentError)
|
610
|
+
end
|
611
|
+
|
612
|
+
it "should return record return value" do
|
613
|
+
plsql.test_employee_record(@p_employee).should == @p_employee
|
614
|
+
end
|
615
|
+
|
616
|
+
it "should return record return value and output record parameter value" do
|
617
|
+
plsql.test_employee_record2(@p_employee, nil).should == [@p_employee, {:x_employee => @p_employee}]
|
618
|
+
end
|
619
|
+
|
230
620
|
end
|
231
621
|
|
232
|
-
|
233
|
-
|
622
|
+
describe "Function with boolean parameters" do
|
623
|
+
|
624
|
+
before(:all) do
|
625
|
+
plsql.connection.exec <<-SQL
|
626
|
+
CREATE OR REPLACE FUNCTION test_boolean
|
627
|
+
( p_boolean BOOLEAN )
|
628
|
+
RETURN BOOLEAN
|
629
|
+
IS
|
630
|
+
BEGIN
|
631
|
+
RETURN p_boolean;
|
632
|
+
END test_boolean;
|
633
|
+
SQL
|
634
|
+
plsql.connection.exec <<-SQL
|
635
|
+
CREATE OR REPLACE PROCEDURE test_boolean2
|
636
|
+
( p_boolean BOOLEAN, x_boolean OUT BOOLEAN )
|
637
|
+
IS
|
638
|
+
BEGIN
|
639
|
+
x_boolean := p_boolean;
|
640
|
+
END test_boolean2;
|
641
|
+
SQL
|
642
|
+
end
|
643
|
+
|
644
|
+
after(:all) do
|
645
|
+
plsql.connection.exec "DROP FUNCTION test_boolean"
|
646
|
+
plsql.connection.exec "DROP PROCEDURE test_boolean2"
|
647
|
+
end
|
648
|
+
|
649
|
+
it "should accept true value and return true value" do
|
650
|
+
plsql.test_boolean(true).should == true
|
651
|
+
end
|
652
|
+
|
653
|
+
it "should accept false value and return false value" do
|
654
|
+
plsql.test_boolean(false).should == false
|
655
|
+
end
|
656
|
+
|
657
|
+
it "should accept nil value and return nil value" do
|
658
|
+
plsql.test_boolean(nil).should be_nil
|
659
|
+
end
|
660
|
+
|
661
|
+
it "should accept true value and assign true value to output parameter" do
|
662
|
+
plsql.test_boolean2(true, nil).should == {:x_boolean => true}
|
663
|
+
end
|
664
|
+
|
665
|
+
it "should accept false value and assign false value to output parameter" do
|
666
|
+
plsql.test_boolean2(false, nil).should == {:x_boolean => false}
|
667
|
+
end
|
668
|
+
|
669
|
+
it "should accept nil value and assign nil value to output parameter" do
|
670
|
+
plsql.test_boolean2(nil, nil).should == {:x_boolean => nil}
|
671
|
+
end
|
672
|
+
|
234
673
|
end
|
235
674
|
|
236
|
-
|
237
|
-
|
675
|
+
describe "Function with object type parameter" do
|
676
|
+
|
677
|
+
before(:all) do
|
678
|
+
plsql.connection.exec "DROP TYPE t_employee" rescue nil
|
679
|
+
plsql.connection.exec "DROP TYPE t_phones" rescue nil
|
680
|
+
plsql.connection.exec <<-SQL
|
681
|
+
CREATE OR REPLACE TYPE t_address AS OBJECT (
|
682
|
+
street VARCHAR2(50),
|
683
|
+
city VARCHAR2(50),
|
684
|
+
country VARCHAR2(50)
|
685
|
+
)
|
686
|
+
SQL
|
687
|
+
plsql.connection.exec <<-SQL
|
688
|
+
CREATE OR REPLACE TYPE t_phone AS OBJECT (
|
689
|
+
type VARCHAR2(10),
|
690
|
+
phone_number VARCHAR2(50)
|
691
|
+
)
|
692
|
+
SQL
|
693
|
+
plsql.connection.exec <<-SQL
|
694
|
+
CREATE OR REPLACE TYPE t_phones AS TABLE OF T_PHONE
|
695
|
+
SQL
|
696
|
+
plsql.connection.exec <<-SQL
|
697
|
+
CREATE OR REPLACE TYPE t_employee AS OBJECT (
|
698
|
+
employee_id NUMBER(15),
|
699
|
+
first_name VARCHAR2(50),
|
700
|
+
last_name VARCHAR2(50),
|
701
|
+
hire_date DATE,
|
702
|
+
address t_address,
|
703
|
+
phones t_phones
|
704
|
+
)
|
705
|
+
SQL
|
706
|
+
plsql.connection.exec <<-SQL
|
707
|
+
CREATE OR REPLACE FUNCTION test_full_name (p_employee t_employee)
|
708
|
+
RETURN VARCHAR2
|
709
|
+
IS
|
710
|
+
BEGIN
|
711
|
+
RETURN p_employee.first_name || ' ' || p_employee.last_name;
|
712
|
+
END;
|
713
|
+
SQL
|
714
|
+
plsql.connection.exec <<-SQL
|
715
|
+
CREATE OR REPLACE FUNCTION test_employee_object (p_employee t_employee)
|
716
|
+
RETURN t_employee
|
717
|
+
IS
|
718
|
+
BEGIN
|
719
|
+
RETURN p_employee;
|
720
|
+
END;
|
721
|
+
SQL
|
722
|
+
plsql.connection.exec <<-SQL
|
723
|
+
CREATE OR REPLACE FUNCTION test_employee_object2 (p_employee t_employee, x_employee OUT t_employee)
|
724
|
+
RETURN t_employee
|
725
|
+
IS
|
726
|
+
BEGIN
|
727
|
+
x_employee := p_employee;
|
728
|
+
RETURN p_employee;
|
729
|
+
END;
|
730
|
+
SQL
|
731
|
+
@p_employee = {
|
732
|
+
:employee_id => 1,
|
733
|
+
:first_name => 'First',
|
734
|
+
:last_name => 'Last',
|
735
|
+
:hire_date => Time.local(2000,01,31),
|
736
|
+
:address => {:street => 'Main street 1', :city => 'Riga', :country => 'Latvia'},
|
737
|
+
:phones => [{:type => 'mobile', :phone_number => '123456'}, {:type => 'home', :phone_number => '654321'}]
|
738
|
+
}
|
739
|
+
end
|
740
|
+
|
741
|
+
after(:all) do
|
742
|
+
plsql.connection.exec "DROP FUNCTION test_full_name"
|
743
|
+
plsql.connection.exec "DROP FUNCTION test_employee_object"
|
744
|
+
plsql.connection.exec "DROP FUNCTION test_employee_object2"
|
745
|
+
plsql.connection.exec "DROP TYPE t_employee"
|
746
|
+
plsql.connection.exec "DROP TYPE t_address"
|
747
|
+
plsql.connection.exec "DROP TYPE t_phones"
|
748
|
+
plsql.connection.exec "DROP TYPE t_phone"
|
749
|
+
end
|
750
|
+
|
751
|
+
it "should find existing function" do
|
752
|
+
PLSQL::Procedure.find(plsql, :test_full_name).should_not be_nil
|
753
|
+
end
|
754
|
+
|
755
|
+
it "should execute function with named parameter and return correct value" do
|
756
|
+
plsql.test_full_name(:p_employee => @p_employee).should == 'First Last'
|
757
|
+
end
|
758
|
+
|
759
|
+
it "should execute function with sequential parameter and return correct value" do
|
760
|
+
plsql.test_full_name(@p_employee).should == 'First Last'
|
761
|
+
end
|
762
|
+
|
763
|
+
it "should raise error if wrong field name is passed for record parameter" do
|
764
|
+
lambda do
|
765
|
+
plsql.test_full_name(@p_employee.merge :xxx => 'xxx')
|
766
|
+
end.should raise_error(ArgumentError)
|
767
|
+
end
|
768
|
+
|
769
|
+
it "should return object type return value" do
|
770
|
+
plsql.test_employee_object(@p_employee).should == @p_employee
|
771
|
+
end
|
772
|
+
|
773
|
+
it "should return object type return value and output object type parameter value" do
|
774
|
+
plsql.test_employee_object2(@p_employee, nil).should == [@p_employee, {:x_employee => @p_employee}]
|
775
|
+
end
|
776
|
+
|
238
777
|
end
|
239
778
|
|
240
|
-
end
|
241
779
|
|
242
|
-
describe "
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
;
|
253
|
-
FUNCTION test_procedure2 ( p_string VARCHAR2 )
|
254
|
-
RETURN VARCHAR2;
|
255
|
-
END;
|
256
|
-
EOS
|
257
|
-
plsql.connection.exec <<-EOS
|
258
|
-
CREATE OR REPLACE PACKAGE BODY test_package2 IS
|
259
|
-
FUNCTION test_procedure ( p_string VARCHAR2 )
|
260
|
-
RETURN VARCHAR2
|
780
|
+
describe "Function with table parameter" do
|
781
|
+
|
782
|
+
before(:all) do
|
783
|
+
# Array of numbers
|
784
|
+
plsql.connection.exec <<-SQL
|
785
|
+
CREATE OR REPLACE TYPE t_numbers AS TABLE OF NUMBER(15)
|
786
|
+
SQL
|
787
|
+
plsql.connection.exec <<-SQL
|
788
|
+
CREATE OR REPLACE FUNCTION test_sum (p_numbers IN t_numbers)
|
789
|
+
RETURN NUMBER
|
261
790
|
IS
|
791
|
+
l_sum NUMBER(15) := 0;
|
262
792
|
BEGIN
|
263
|
-
|
264
|
-
|
265
|
-
|
793
|
+
IF p_numbers.COUNT > 0 THEN
|
794
|
+
FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
|
795
|
+
IF p_numbers.EXISTS(i) THEN
|
796
|
+
l_sum := l_sum + p_numbers(i);
|
797
|
+
END IF;
|
798
|
+
END LOOP;
|
799
|
+
RETURN l_sum;
|
800
|
+
ELSE
|
801
|
+
RETURN NULL;
|
802
|
+
END IF;
|
803
|
+
END;
|
804
|
+
SQL
|
805
|
+
|
806
|
+
plsql.connection.exec <<-SQL
|
807
|
+
CREATE OR REPLACE FUNCTION test_increment(p_numbers IN t_numbers, p_increment_by IN NUMBER DEFAULT 1)
|
808
|
+
RETURN t_numbers
|
266
809
|
IS
|
810
|
+
l_numbers t_numbers := t_numbers();
|
267
811
|
BEGIN
|
268
|
-
|
269
|
-
|
270
|
-
|
812
|
+
FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
|
813
|
+
IF p_numbers.EXISTS(i) THEN
|
814
|
+
l_numbers.EXTEND;
|
815
|
+
l_numbers(i) := p_numbers(i) + p_increment_by;
|
816
|
+
END IF;
|
817
|
+
END LOOP;
|
818
|
+
RETURN l_numbers;
|
819
|
+
END;
|
820
|
+
SQL
|
821
|
+
|
822
|
+
# Array of strings
|
823
|
+
plsql.connection.exec <<-SQL
|
824
|
+
CREATE OR REPLACE TYPE t_strings AS TABLE OF VARCHAR2(4000)
|
825
|
+
SQL
|
826
|
+
plsql.connection.exec <<-SQL
|
827
|
+
CREATE OR REPLACE FUNCTION test_copy_strings(p_strings IN t_strings, x_strings OUT t_strings)
|
828
|
+
RETURN t_strings
|
271
829
|
IS
|
272
830
|
BEGIN
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
831
|
+
x_strings := t_strings();
|
832
|
+
FOR i IN p_strings.FIRST..p_strings.LAST LOOP
|
833
|
+
IF p_strings.EXISTS(i) THEN
|
834
|
+
x_strings.EXTEND;
|
835
|
+
x_strings(i) := p_strings(i);
|
836
|
+
END IF;
|
837
|
+
END LOOP;
|
838
|
+
RETURN x_strings;
|
839
|
+
END;
|
840
|
+
SQL
|
841
|
+
|
842
|
+
# Wrong type definition inside package
|
843
|
+
plsql.connection.exec <<-SQL
|
844
|
+
CREATE OR REPLACE PACKAGE test_collections IS
|
845
|
+
TYPE t_numbers IS TABLE OF NUMBER(15);
|
846
|
+
FUNCTION test_sum (p_numbers IN t_numbers)
|
847
|
+
RETURN NUMBER;
|
848
|
+
END;
|
849
|
+
SQL
|
850
|
+
plsql.connection.exec <<-SQL
|
851
|
+
CREATE OR REPLACE PACKAGE BODY test_collections IS
|
852
|
+
FUNCTION test_sum (p_numbers IN t_numbers)
|
853
|
+
RETURN NUMBER
|
854
|
+
IS
|
855
|
+
l_sum NUMBER(15) := 0;
|
856
|
+
BEGIN
|
857
|
+
IF p_numbers.COUNT > 0 THEN
|
858
|
+
FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
|
859
|
+
IF p_numbers.EXISTS(i) THEN
|
860
|
+
l_sum := l_sum + p_numbers(i);
|
861
|
+
END IF;
|
862
|
+
END LOOP;
|
863
|
+
RETURN l_sum;
|
864
|
+
ELSE
|
865
|
+
RETURN NULL;
|
866
|
+
END IF;
|
867
|
+
END;
|
868
|
+
END;
|
869
|
+
SQL
|
870
|
+
|
871
|
+
# Array of objects
|
872
|
+
plsql.connection.exec <<-SQL
|
873
|
+
CREATE OR REPLACE TYPE t_phone AS OBJECT (
|
874
|
+
type VARCHAR2(10),
|
875
|
+
phone_number VARCHAR2(50)
|
876
|
+
)
|
877
|
+
SQL
|
878
|
+
plsql.connection.exec <<-SQL
|
879
|
+
CREATE OR REPLACE TYPE t_phones AS TABLE OF T_PHONE
|
880
|
+
SQL
|
881
|
+
plsql.connection.exec <<-SQL
|
882
|
+
CREATE OR REPLACE FUNCTION test_copy_objects(p_phones IN t_phones, x_phones OUT t_phones)
|
883
|
+
RETURN t_phones
|
277
884
|
IS
|
278
885
|
BEGIN
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
886
|
+
x_phones := p_phones;
|
887
|
+
RETURN x_phones;
|
888
|
+
END;
|
889
|
+
SQL
|
890
|
+
end
|
283
891
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
892
|
+
after(:all) do
|
893
|
+
plsql.connection.exec "DROP FUNCTION test_sum"
|
894
|
+
plsql.connection.exec "DROP FUNCTION test_increment"
|
895
|
+
plsql.connection.exec "DROP FUNCTION test_copy_strings"
|
896
|
+
plsql.connection.exec "DROP PACKAGE test_collections"
|
897
|
+
plsql.connection.exec "DROP FUNCTION test_copy_objects"
|
898
|
+
plsql.connection.exec "DROP TYPE t_numbers"
|
899
|
+
plsql.connection.exec "DROP TYPE t_strings"
|
900
|
+
plsql.connection.exec "DROP TYPE t_phones"
|
901
|
+
plsql.connection.exec "DROP TYPE t_phone"
|
902
|
+
end
|
293
903
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
@procedure.should be_overloaded
|
298
|
-
end
|
904
|
+
it "should find existing function" do
|
905
|
+
PLSQL::Procedure.find(plsql, :test_sum).should_not be_nil
|
906
|
+
end
|
299
907
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
@procedure.should_not be_overloaded
|
304
|
-
end
|
908
|
+
it "should execute function with number array parameter" do
|
909
|
+
plsql.test_sum([1,2,3,4]).should == 10
|
910
|
+
end
|
305
911
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
end
|
912
|
+
it "should return number array return value" do
|
913
|
+
plsql.test_increment([1,2,3,4], 1).should == [2,3,4,5]
|
914
|
+
end
|
310
915
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
916
|
+
it "should execute function with string array and return string array output parameter" do
|
917
|
+
strings = ['1','2','3','4']
|
918
|
+
plsql.test_copy_strings(strings).should == [strings, {:x_strings => strings}]
|
919
|
+
end
|
315
920
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
# it "should find procedure based on types of arguments" do
|
322
|
-
# plsql.test_package2.test_procedure(111, nil).should == {:p_result => '111'}
|
323
|
-
# end
|
921
|
+
it "should raise error if parameter type is defined inside package" do
|
922
|
+
lambda do
|
923
|
+
plsql.test_collections.test_sum([1,2,3,4])
|
924
|
+
end.should raise_error(ArgumentError)
|
925
|
+
end
|
324
926
|
|
325
|
-
|
326
|
-
|
327
|
-
|
927
|
+
it "should execute function with object array and return object array output parameter" do
|
928
|
+
phones = [{:type => 'mobile', :phone_number => '123456'}, {:type => 'home', :phone_number => '654321'}]
|
929
|
+
plsql.test_copy_objects(phones).should == [phones, {:x_phones => phones}]
|
930
|
+
end
|
328
931
|
|
329
|
-
|
932
|
+
it "should execute function with empty object array" do
|
933
|
+
phones = []
|
934
|
+
plsql.test_copy_objects(phones).should == [phones, {:x_phones => phones}]
|
935
|
+
end
|
330
936
|
|
331
|
-
describe "Function with output parameters" do
|
332
|
-
before(:all) do
|
333
|
-
plsql.connection = get_connection
|
334
|
-
plsql.connection.exec <<-EOS
|
335
|
-
CREATE OR REPLACE FUNCTION test_copy_function
|
336
|
-
( p_from VARCHAR2, p_to OUT VARCHAR2, p_to_double OUT VARCHAR2 )
|
337
|
-
RETURN NUMBER
|
338
|
-
IS
|
339
|
-
BEGIN
|
340
|
-
p_to := p_from;
|
341
|
-
p_to_double := p_from || p_from;
|
342
|
-
RETURN LENGTH(p_from);
|
343
|
-
END test_copy_function;
|
344
|
-
EOS
|
345
|
-
end
|
346
|
-
|
347
|
-
after(:all) do
|
348
|
-
plsql.logoff
|
349
|
-
end
|
350
|
-
|
351
|
-
it "should return array with return value and hash of output parameters" do
|
352
|
-
plsql.test_copy_function("abc", nil, nil).should == [3, { :p_to => "abc", :p_to_double => "abcabc" }]
|
353
937
|
end
|
354
938
|
|
355
|
-
|
356
|
-
plsql.test_copy_function(:p_from => "abc", :p_to => nil, :p_to_double => nil).should ==
|
357
|
-
[3, { :p_to => "abc", :p_to_double => "abcabc" }]
|
358
|
-
end
|
939
|
+
describe "Function with VARRAY parameter" do
|
359
940
|
|
360
|
-
|
361
|
-
|
362
|
-
|
941
|
+
before(:all) do
|
942
|
+
# Array of numbers
|
943
|
+
plsql.connection.exec <<-SQL
|
944
|
+
CREATE OR REPLACE TYPE t_numbers_array AS VARRAY(100) OF NUMBER(15)
|
945
|
+
SQL
|
946
|
+
plsql.connection.exec <<-SQL
|
947
|
+
CREATE OR REPLACE FUNCTION test_sum (p_numbers IN t_numbers_array)
|
948
|
+
RETURN NUMBER
|
949
|
+
IS
|
950
|
+
l_sum NUMBER(15) := 0;
|
951
|
+
BEGIN
|
952
|
+
IF p_numbers.COUNT > 0 THEN
|
953
|
+
FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
|
954
|
+
l_sum := l_sum + p_numbers(i);
|
955
|
+
END LOOP;
|
956
|
+
RETURN l_sum;
|
957
|
+
ELSE
|
958
|
+
RETURN NULL;
|
959
|
+
END IF;
|
960
|
+
END;
|
961
|
+
SQL
|
962
|
+
|
963
|
+
plsql.connection.exec <<-SQL
|
964
|
+
CREATE OR REPLACE FUNCTION test_increment(p_numbers IN t_numbers_array, p_increment_by IN NUMBER DEFAULT 1)
|
965
|
+
RETURN t_numbers_array
|
966
|
+
IS
|
967
|
+
l_numbers t_numbers_array := t_numbers_array();
|
968
|
+
BEGIN
|
969
|
+
FOR i IN p_numbers.FIRST..p_numbers.LAST LOOP
|
970
|
+
l_numbers.EXTEND;
|
971
|
+
l_numbers(i) := p_numbers(i) + p_increment_by;
|
972
|
+
END LOOP;
|
973
|
+
RETURN l_numbers;
|
974
|
+
END;
|
975
|
+
SQL
|
976
|
+
|
977
|
+
# Array of strings
|
978
|
+
plsql.connection.exec <<-SQL
|
979
|
+
CREATE OR REPLACE TYPE t_strings_array AS VARRAY(100) OF VARCHAR2(4000)
|
980
|
+
SQL
|
981
|
+
plsql.connection.exec <<-SQL
|
982
|
+
CREATE OR REPLACE FUNCTION test_copy_strings(p_strings IN t_strings_array, x_strings OUT t_strings_array)
|
983
|
+
RETURN t_strings_array
|
984
|
+
IS
|
985
|
+
BEGIN
|
986
|
+
x_strings := t_strings_array();
|
987
|
+
FOR i IN p_strings.FIRST..p_strings.LAST LOOP
|
988
|
+
x_strings.EXTEND;
|
989
|
+
x_strings(i) := p_strings(i);
|
990
|
+
END LOOP;
|
991
|
+
RETURN x_strings;
|
992
|
+
END;
|
993
|
+
SQL
|
994
|
+
|
995
|
+
# Array of objects
|
996
|
+
plsql.connection.exec "DROP TYPE t_phones_array" rescue nil
|
997
|
+
plsql.connection.exec <<-SQL
|
998
|
+
CREATE OR REPLACE TYPE t_phone AS OBJECT (
|
999
|
+
type VARCHAR2(10),
|
1000
|
+
phone_number VARCHAR2(50)
|
1001
|
+
)
|
1002
|
+
SQL
|
1003
|
+
plsql.connection.exec <<-SQL
|
1004
|
+
CREATE OR REPLACE TYPE t_phones_array AS ARRAY(100) OF T_PHONE
|
1005
|
+
SQL
|
1006
|
+
plsql.connection.exec <<-SQL
|
1007
|
+
CREATE OR REPLACE FUNCTION test_copy_objects(p_phones IN t_phones_array, x_phones OUT t_phones_array)
|
1008
|
+
RETURN t_phones_array
|
1009
|
+
IS
|
1010
|
+
BEGIN
|
1011
|
+
x_phones := p_phones;
|
1012
|
+
RETURN x_phones;
|
1013
|
+
END;
|
1014
|
+
SQL
|
1015
|
+
end
|
363
1016
|
|
364
|
-
|
365
|
-
|
366
|
-
|
1017
|
+
after(:all) do
|
1018
|
+
plsql.connection.exec "DROP FUNCTION test_sum"
|
1019
|
+
plsql.connection.exec "DROP FUNCTION test_increment"
|
1020
|
+
plsql.connection.exec "DROP FUNCTION test_copy_strings"
|
1021
|
+
plsql.connection.exec "DROP FUNCTION test_copy_objects"
|
1022
|
+
plsql.connection.exec "DROP TYPE t_numbers_array"
|
1023
|
+
plsql.connection.exec "DROP TYPE t_strings_array"
|
1024
|
+
plsql.connection.exec "DROP TYPE t_phones_array"
|
1025
|
+
plsql.connection.exec "DROP TYPE t_phone"
|
1026
|
+
end
|
367
1027
|
|
368
|
-
|
1028
|
+
it "should find existing function" do
|
1029
|
+
PLSQL::Procedure.find(plsql, :test_sum).should_not be_nil
|
1030
|
+
end
|
369
1031
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
plsql.connection.exec <<-EOS
|
374
|
-
CREATE OR REPLACE FUNCTION test_no_params
|
375
|
-
RETURN VARCHAR2
|
376
|
-
IS
|
377
|
-
BEGIN
|
378
|
-
RETURN 'dummy';
|
379
|
-
END test_no_params;
|
380
|
-
EOS
|
381
|
-
plsql.connection.exec <<-EOS
|
382
|
-
CREATE OR REPLACE PROCEDURE test_proc_no_params
|
383
|
-
IS
|
384
|
-
BEGIN
|
385
|
-
NULL;
|
386
|
-
END test_proc_no_params;
|
387
|
-
EOS
|
388
|
-
end
|
389
|
-
|
390
|
-
after(:all) do
|
391
|
-
plsql.logoff
|
392
|
-
end
|
1032
|
+
it "should execute function with number array parameter" do
|
1033
|
+
plsql.test_sum([1,2,3,4]).should == 10
|
1034
|
+
end
|
393
1035
|
|
394
|
-
|
395
|
-
|
396
|
-
|
1036
|
+
it "should return number array return value" do
|
1037
|
+
plsql.test_increment([1,2,3,4], 1).should == [2,3,4,5]
|
1038
|
+
end
|
397
1039
|
|
398
|
-
|
399
|
-
|
400
|
-
|
1040
|
+
it "should execute function with string array and return string array output parameter" do
|
1041
|
+
strings = ['1','2','3','4']
|
1042
|
+
plsql.test_copy_strings(strings).should == [strings, {:x_strings => strings}]
|
1043
|
+
end
|
401
1044
|
|
402
|
-
|
403
|
-
|
404
|
-
|
1045
|
+
it "should execute function with object array and return object array output parameter" do
|
1046
|
+
phones = [{:type => 'mobile', :phone_number => '123456'}, {:type => 'home', :phone_number => '654321'}]
|
1047
|
+
plsql.test_copy_objects(phones).should == [phones, {:x_phones => phones}]
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
it "should execute function with empty object array" do
|
1051
|
+
phones = []
|
1052
|
+
plsql.test_copy_objects(phones).should == [phones, {:x_phones => phones}]
|
1053
|
+
end
|
405
1054
|
|
406
|
-
it "should execute procedure" do
|
407
|
-
plsql.test_proc_no_params.should be_nil
|
408
1055
|
end
|
409
1056
|
|
410
|
-
|
1057
|
+
describe "Function with cursor return value or parameter" do
|
411
1058
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
1059
|
+
before(:all) do
|
1060
|
+
plsql.connection.exec "DROP TABLE test_employees" rescue nil
|
1061
|
+
plsql.connection.exec <<-SQL
|
1062
|
+
CREATE TABLE test_employees (
|
1063
|
+
employee_id NUMBER(15),
|
1064
|
+
first_name VARCHAR2(50),
|
1065
|
+
last_name VARCHAR2(50),
|
1066
|
+
hire_date DATE
|
1067
|
+
)
|
1068
|
+
SQL
|
1069
|
+
plsql.connection.exec <<-SQL
|
1070
|
+
CREATE OR REPLACE PROCEDURE test_insert_employee(p_employee test_employees%ROWTYPE)
|
1071
|
+
IS
|
1072
|
+
BEGIN
|
1073
|
+
INSERT INTO test_employees
|
1074
|
+
VALUES p_employee;
|
1075
|
+
END;
|
1076
|
+
SQL
|
1077
|
+
plsql.connection.exec <<-SQL
|
1078
|
+
CREATE OR REPLACE FUNCTION test_cursor
|
1079
|
+
RETURN SYS_REFCURSOR
|
1080
|
+
IS
|
1081
|
+
l_cursor SYS_REFCURSOR;
|
1082
|
+
BEGIN
|
1083
|
+
OPEN l_cursor FOR
|
1084
|
+
SELECT * FROM test_employees ORDER BY employee_id;
|
1085
|
+
RETURN l_cursor;
|
1086
|
+
END;
|
1087
|
+
SQL
|
1088
|
+
plsql.connection.exec <<-SQL
|
1089
|
+
CREATE OR REPLACE PROCEDURE test_cursor_out(x_cursor OUT SYS_REFCURSOR)
|
1090
|
+
IS
|
1091
|
+
BEGIN
|
1092
|
+
OPEN x_cursor FOR
|
1093
|
+
SELECT * FROM test_employees ORDER BY employee_id;
|
1094
|
+
END;
|
1095
|
+
SQL
|
1096
|
+
plsql.connection.exec <<-SQL
|
1097
|
+
CREATE OR REPLACE FUNCTION test_cursor_fetch(p_cursor SYS_REFCURSOR)
|
1098
|
+
RETURN test_employees%ROWTYPE
|
1099
|
+
IS
|
1100
|
+
l_record test_employees%ROWTYPE;
|
1101
|
+
BEGIN
|
1102
|
+
FETCH p_cursor INTO l_record;
|
1103
|
+
RETURN l_record;
|
1104
|
+
END;
|
1105
|
+
SQL
|
1106
|
+
@fields = [:employee_id, :first_name, :last_name, :hire_date]
|
1107
|
+
@employees = (1..10).map do |i|
|
1108
|
+
{
|
1109
|
+
:employee_id => i,
|
1110
|
+
:first_name => "First #{i}",
|
1111
|
+
:last_name => "Last #{i}",
|
1112
|
+
:hire_date => Time.local(2000,01,i)
|
1113
|
+
}
|
1114
|
+
end
|
1115
|
+
@employees.each do |e|
|
1116
|
+
plsql.test_insert_employee(e)
|
1117
|
+
end
|
1118
|
+
plsql.connection.commit
|
1119
|
+
end
|
434
1120
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
1121
|
+
after(:all) do
|
1122
|
+
plsql.connection.exec "DROP FUNCTION test_cursor"
|
1123
|
+
plsql.connection.exec "DROP PROCEDURE test_cursor_out"
|
1124
|
+
plsql.connection.exec "DROP PROCEDURE test_insert_employee"
|
1125
|
+
plsql.connection.exec "DROP FUNCTION test_cursor_fetch"
|
1126
|
+
plsql.connection.exec "DROP TABLE test_employees"
|
1127
|
+
end
|
439
1128
|
|
440
|
-
|
1129
|
+
it "should find existing function" do
|
1130
|
+
PLSQL::Procedure.find(plsql, :test_cursor).should_not be_nil
|
1131
|
+
end
|
441
1132
|
|
442
|
-
it "should
|
443
|
-
|
444
|
-
|
1133
|
+
it "should return cursor and fetch first row" do
|
1134
|
+
plsql.test_cursor do |cursor|
|
1135
|
+
cursor.fetch.should == @fields.map{|f| @employees[0][f]}
|
1136
|
+
end.should be_nil
|
445
1137
|
end
|
446
|
-
|
447
|
-
else
|
448
1138
|
|
449
|
-
it "should
|
450
|
-
|
451
|
-
plsql.
|
1139
|
+
it "should close all returned cursors after block is executed" do
|
1140
|
+
cursor2 = nil
|
1141
|
+
plsql.test_cursor do |cursor|
|
1142
|
+
cursor2 = cursor
|
1143
|
+
end.should be_nil
|
1144
|
+
lambda { cursor2.fetch }.should raise_error
|
452
1145
|
end
|
453
|
-
|
454
|
-
end
|
455
1146
|
|
456
|
-
|
457
|
-
|
458
|
-
|
1147
|
+
it "should not raise error if cursor is closed inside block" do
|
1148
|
+
lambda do
|
1149
|
+
plsql.test_cursor do |cursor|
|
1150
|
+
cursor.close
|
1151
|
+
end
|
1152
|
+
end.should_not raise_error
|
1153
|
+
end
|
459
1154
|
|
460
|
-
|
1155
|
+
it "should fetch hash from returned cursor" do
|
1156
|
+
plsql.test_cursor do |cursor|
|
1157
|
+
cursor.fetch_hash.should == @employees[0]
|
1158
|
+
end
|
1159
|
+
end
|
461
1160
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
1161
|
+
it "should fetch all rows from returned cursor" do
|
1162
|
+
plsql.test_cursor do |cursor|
|
1163
|
+
cursor.fetch_all.should == @employees.map{|e| @fields.map{|f| e[f]}}
|
1164
|
+
end
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
it "should fetch all rows as hash from returned cursor" do
|
1168
|
+
plsql.test_cursor do |cursor|
|
1169
|
+
cursor.fetch_hash_all.should == @employees
|
1170
|
+
end
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
it "should get field names from returned cursor" do
|
1174
|
+
plsql.test_cursor do |cursor|
|
1175
|
+
cursor.fields.should == @fields
|
1176
|
+
end
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
it "should return output parameter with cursor and fetch first row" do
|
1180
|
+
plsql.test_cursor_out do |result|
|
1181
|
+
result[:x_cursor].fetch.should == @fields.map{|f| @employees[0][f]}
|
1182
|
+
end.should be_nil
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
it "should return output parameter with cursor and fetch all rows as hash" do
|
1186
|
+
plsql.test_cursor_out do |result|
|
1187
|
+
result[:x_cursor].fetch_hash_all.should == @employees
|
1188
|
+
end.should be_nil
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
it "should execute function with cursor parameter and return record" do
|
1192
|
+
pending "not possible from JDBC" if defined?(JRUBY_VERSION)
|
1193
|
+
plsql.test_cursor do |cursor|
|
1194
|
+
plsql.test_cursor_fetch(cursor).should == @employees[0]
|
1195
|
+
end
|
1196
|
+
end
|
484
1197
|
|
485
|
-
it "should execute function and return correct value" do
|
486
|
-
large_text = 'ābčdēfghij' * 10_000
|
487
|
-
plsql.test_clob_proc(large_text)[:p_return].should == large_text
|
488
1198
|
end
|
489
1199
|
end
|
490
1200
|
|
491
|
-
describe "
|
492
|
-
|
1201
|
+
describe "Synonyms /" do
|
1202
|
+
|
493
1203
|
before(:all) do
|
494
1204
|
plsql.connection = get_connection
|
495
|
-
plsql.connection.exec <<-EOS
|
496
|
-
CREATE OR REPLACE PROCEDURE test_blob_proc
|
497
|
-
( p_blob BLOB,
|
498
|
-
p_return OUT BLOB)
|
499
|
-
IS
|
500
|
-
BEGIN
|
501
|
-
p_return := p_blob;
|
502
|
-
END test_blob_proc;
|
503
|
-
EOS
|
504
1205
|
end
|
505
|
-
|
1206
|
+
|
506
1207
|
after(:all) do
|
507
1208
|
plsql.logoff
|
508
1209
|
end
|
509
|
-
|
510
|
-
it "should find existing procedure" do
|
511
|
-
PLSQL::Procedure.find(plsql, :test_blob_proc).should_not be_nil
|
512
|
-
end
|
513
1210
|
|
514
|
-
|
515
|
-
large_binary = '\000\001\002\003\004\005\006\007\010\011' * 10_000
|
516
|
-
plsql.test_blob_proc(large_binary)[:p_return].should == large_binary
|
517
|
-
end
|
518
|
-
end
|
519
|
-
|
520
|
-
describe "Synonym to function" do
|
1211
|
+
describe "Local synonym to function" do
|
521
1212
|
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
end
|
1213
|
+
before(:all) do
|
1214
|
+
plsql.connection.exec <<-EOS
|
1215
|
+
CREATE OR REPLACE FUNCTION hr.test_uppercase
|
1216
|
+
( p_string VARCHAR2 )
|
1217
|
+
RETURN VARCHAR2
|
1218
|
+
IS
|
1219
|
+
BEGIN
|
1220
|
+
RETURN UPPER(p_string);
|
1221
|
+
END test_uppercase;
|
1222
|
+
EOS
|
1223
|
+
plsql.connection.exec "CREATE SYNONYM test_synonym FOR hr.test_uppercase"
|
1224
|
+
end
|
535
1225
|
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
1226
|
+
after(:all) do
|
1227
|
+
plsql.connection.exec "DROP SYNONYM test_synonym"
|
1228
|
+
plsql.connection.exec "DROP FUNCTION hr.test_uppercase"
|
1229
|
+
end
|
540
1230
|
|
541
|
-
|
542
|
-
|
543
|
-
|
1231
|
+
it "should find synonym to function" do
|
1232
|
+
PLSQL::Procedure.find(plsql, :test_synonym).should_not be_nil
|
1233
|
+
end
|
544
1234
|
|
545
|
-
|
546
|
-
|
547
|
-
|
1235
|
+
it "should execute function using synonym and return correct value" do
|
1236
|
+
plsql.test_synonym('xxx').should == 'XXX'
|
1237
|
+
end
|
548
1238
|
|
549
|
-
end
|
1239
|
+
end
|
550
1240
|
|
551
|
-
describe "Public synonym to function" do
|
1241
|
+
describe "Public synonym to function" do
|
552
1242
|
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
end
|
1243
|
+
before(:all) do
|
1244
|
+
plsql.connection.exec <<-EOS
|
1245
|
+
CREATE OR REPLACE FUNCTION hr.test_ora_login_user
|
1246
|
+
RETURN VARCHAR2
|
1247
|
+
IS
|
1248
|
+
BEGIN
|
1249
|
+
RETURN 'XXX';
|
1250
|
+
END test_ora_login_user;
|
1251
|
+
EOS
|
1252
|
+
end
|
564
1253
|
|
565
|
-
|
566
|
-
|
567
|
-
|
1254
|
+
after(:all) do
|
1255
|
+
plsql.connection.exec "DROP FUNCTION hr.test_ora_login_user"
|
1256
|
+
end
|
568
1257
|
|
569
|
-
|
570
|
-
|
571
|
-
|
1258
|
+
it "should find public synonym to function" do
|
1259
|
+
PLSQL::Procedure.find(plsql, :ora_login_user).should_not be_nil
|
1260
|
+
end
|
572
1261
|
|
573
|
-
|
574
|
-
|
575
|
-
|
1262
|
+
it "should execute function using public synonym and return correct value" do
|
1263
|
+
plsql.ora_login_user.should == 'HR'
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
it "should find private synonym before public synonym" do
|
1267
|
+
# should reconnect to force clearing of procedure cache
|
1268
|
+
plsql.connection = get_connection
|
1269
|
+
plsql.connection.exec "DROP SYNONYM ora_login_user" rescue nil
|
1270
|
+
plsql.connection.exec "CREATE SYNONYM ora_login_user FOR hr.test_ora_login_user"
|
1271
|
+
plsql.ora_login_user.should == 'XXX'
|
1272
|
+
plsql.connection.exec "DROP SYNONYM ora_login_user"
|
1273
|
+
plsql.connection = get_connection
|
1274
|
+
plsql.ora_login_user.should == 'HR'
|
1275
|
+
end
|
576
1276
|
|
577
|
-
it "should find private synonym before public synonym" do
|
578
|
-
# should reconnect to force clearing of procedure cache
|
579
|
-
plsql.connection = get_connection
|
580
|
-
plsql.connection.exec "CREATE SYNONYM ora_login_user FOR hr.test_ora_login_user"
|
581
|
-
plsql.ora_login_user.should == 'XXX'
|
582
|
-
plsql.connection.exec "DROP SYNONYM ora_login_user"
|
583
|
-
plsql.connection = get_connection
|
584
|
-
plsql.ora_login_user.should == 'HR'
|
585
1277
|
end
|
586
1278
|
|
587
1279
|
end
|