ruby-plsql 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,15 +26,12 @@ module PLSQL
26
26
 
27
27
  def connection=(raw_conn)
28
28
  @connection = raw_conn ? Connection.create(raw_conn) : nil
29
- if @connection
30
- @procedures = {}
31
- @packages = {}
32
- @schemas = {}
33
- else
34
- @procedures = nil
35
- @packages = nil
36
- @schemas = nil
37
- end
29
+ reset_instance_variables
30
+ end
31
+
32
+ def activerecord_class=(ar_class)
33
+ @connection = ar_class ? Connection.create(nil, ar_class) : nil
34
+ reset_instance_variables
38
35
  end
39
36
 
40
37
  def logoff
@@ -63,7 +60,44 @@ module PLSQL
63
60
  connection.rollback
64
61
  end
65
62
 
63
+ # Set to :local or :utc
64
+ @@default_timezone = nil
65
+ def default_timezone
66
+ @@default_timezone ||
67
+ # Use ActiveRecord class default_timezone when ActiveRecord connection is used
68
+ (@connection && (ar_class = @connection.activerecord_class) && ar_class.default_timezone) ||
69
+ # default to local timezone
70
+ :local
71
+ end
72
+
73
+ def default_timezone=(value)
74
+ if [:local, :utc].include?(value)
75
+ @@default_timezone = value
76
+ else
77
+ raise ArgumentError, "default timezone should be :local or :utc"
78
+ end
79
+ end
80
+
81
+ # Same implementation as for ActiveRecord
82
+ # DateTimes aren't aware of DST rules, so use a consistent non-DST offset when creating a DateTime with an offset in the local zone
83
+ def local_timezone_offset
84
+ ::Time.local(2007).utc_offset.to_r / 86400
85
+ end
86
+
66
87
  private
88
+
89
+ def reset_instance_variables
90
+ if @connection
91
+ @procedures = {}
92
+ @packages = {}
93
+ @schemas = {}
94
+ else
95
+ @procedures = nil
96
+ @packages = nil
97
+ @schemas = nil
98
+ end
99
+ @@default_timezone = nil
100
+ end
67
101
 
68
102
  def method_missing(method, *args)
69
103
  raise ArgumentError, "No PL/SQL connection" unless connection
@@ -6,7 +6,6 @@ end
6
6
  unless defined?(JRUBY_VERSION)
7
7
  begin
8
8
  require "oci8"
9
- require "oradate_patch"
10
9
  rescue LoadError
11
10
  puts <<-EOS
12
11
  To use ruby_plsql you must install ruby-oci8 library.
@@ -25,12 +24,12 @@ else
25
24
  else
26
25
  require ojdbc_jar
27
26
  end
28
- import java.sql.Statement
29
- import java.sql.Connection
30
- import java.sql.SQLException
31
- import java.sql.Types
32
- import java.sql.DriverManager
33
- DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
27
+ # import java.sql.Statement
28
+ # import java.sql.Connection
29
+ # import java.sql.SQLException
30
+ # import java.sql.Types
31
+ # import java.sql.DriverManager
32
+ java.sql.DriverManager.registerDriver Java::oracle.jdbc.driver.OracleDriver.new
34
33
  rescue LoadError
35
34
  puts <<-EOS
36
35
  To use ruby_plsql you must have Oracle JDBC driver installed.
@@ -1,9 +1,3 @@
1
1
  module RubyPlsql #:nodoc:
2
- module VERSION #:nodoc:
3
- MAJOR = 0
4
- MINOR = 2
5
- TINY = 4
6
-
7
- STRING = [MAJOR, MINOR, TINY].join('.')
8
- end
2
+ VERSION = '0.3.0'
9
3
  end
@@ -0,0 +1,336 @@
1
+ # encoding: utf-8
2
+
3
+ require File.dirname(__FILE__) + '/../spec_helper'
4
+
5
+ describe "Connection" do
6
+
7
+ before(:all) do
8
+ @raw_conn = get_connection
9
+ end
10
+
11
+ after(:all) do
12
+ unless defined?(JRUBY_VERSION)
13
+ @raw_conn.logoff rescue nil
14
+ else
15
+ @raw_conn.close rescue nil
16
+ end
17
+ end
18
+
19
+ before(:each) do
20
+ @conn = PLSQL::Connection.create( @raw_conn )
21
+ end
22
+
23
+ it "should create connection" do
24
+ @conn.raw_connection.should == @raw_conn
25
+ end
26
+
27
+ unless defined?(JRUBY_VERSION)
28
+ it "should be oci connection" do
29
+ @conn.should be_oci
30
+ @conn.raw_driver.should == :oci
31
+ end
32
+ else
33
+ it "should be jdbc connection" do
34
+ @conn.should be_jdbc
35
+ @conn.raw_driver.should == :jdbc
36
+ end
37
+ end
38
+
39
+ it "should logoff connection" do
40
+ @conn.logoff.should be_true
41
+ end
42
+
43
+ # Ruby 1.8 and 1.9
44
+ if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
45
+ describe "OCI data type conversions" do
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]
49
+ end
50
+
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]
54
+ end
55
+
56
+ it "should translate PL/SQL NUMBER to Ruby OraNumber" do
57
+ @conn.plsql_to_ruby_data_type("NUMBER", 15).should == [OraNumber, nil]
58
+ end
59
+
60
+ it "should translate PL/SQL DATE to Ruby DateTime" do
61
+ @conn.plsql_to_ruby_data_type("DATE", nil).should == [DateTime, nil]
62
+ end
63
+
64
+ it "should translate PL/SQL TIMESTAMP to Ruby Time" do
65
+ @conn.plsql_to_ruby_data_type("TIMESTAMP", nil).should == [Time, nil]
66
+ end
67
+
68
+ it "should not translate Ruby Fixnum when OraNumber type specified" do
69
+ @conn.ruby_value_to_ora_value(100, OraNumber).should eql(100)
70
+ end
71
+
72
+ it "should translate Ruby Bignum value to OraNumber when OraNumber type specified" do
73
+ ora_number = @conn.ruby_value_to_ora_value(12345678901234567890, OraNumber)
74
+ ora_number.class.should == OraNumber
75
+ ora_number.to_s.should == "12345678901234567890"
76
+ # OraNumber has more numeric comparison methods in ruby-oci8 2.0
77
+ ora_number.should == OraNumber.new("12345678901234567890") if OCI8::VERSION >= '2.0.0'
78
+ end
79
+
80
+ it "should translate Ruby String value to OCI8::CLOB when OCI8::CLOB type specified" do
81
+ large_text = "x" * 100_000
82
+ ora_value = @conn.ruby_value_to_ora_value(large_text, OCI8::CLOB)
83
+ ora_value.class.should == OCI8::CLOB
84
+ ora_value.size.should == 100_000
85
+ ora_value.rewind
86
+ ora_value.read.should == large_text
87
+ end
88
+
89
+ it "should translate Oracle OraNumber integer value to Fixnum" do
90
+ @conn.ora_value_to_ruby_value(OraNumber.new(100)).should eql(100)
91
+ end
92
+
93
+ it "should translate Oracle OraNumber float value to BigDecimal" do
94
+ @conn.ora_value_to_ruby_value(OraNumber.new(100.11)).should eql(BigDecimal("100.11"))
95
+ end
96
+
97
+ # ruby-oci8 2.0 returns DATE as Time or DateTime
98
+ if OCI8::VERSION < '2.0.0'
99
+ it "should translate Oracle OraDate value to Time" do
100
+ now = OraDate.now
101
+ @conn.ora_value_to_ruby_value(now).should eql(now.to_time)
102
+ end
103
+ end
104
+
105
+ it "should translate Oracle CLOB value to String" do
106
+ large_text = "x" * 100_000
107
+ clob = OCI8::CLOB.new(@raw_conn, large_text)
108
+ @conn.ora_value_to_ruby_value(clob).should == large_text
109
+ end
110
+
111
+ end
112
+
113
+ elsif RUBY_ENGINE == 'jruby'
114
+
115
+ describe "JDBC data type conversions" do
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]
119
+ end
120
+
121
+ it "should translate PL/SQL NUMBER to Ruby BigDecimal" do
122
+ @conn.plsql_to_ruby_data_type("NUMBER", 15).should == [BigDecimal, nil]
123
+ end
124
+
125
+ it "should translate PL/SQL DATE to Ruby DateTime" do
126
+ @conn.plsql_to_ruby_data_type("DATE", nil).should == [Time, nil]
127
+ end
128
+
129
+ it "should translate PL/SQL TIMESTAMP to Ruby Time" do
130
+ @conn.plsql_to_ruby_data_type("TIMESTAMP", nil).should == [Time, nil]
131
+ end
132
+
133
+ it "should not translate Ruby Fixnum when BigDecimal type specified" do
134
+ @conn.ruby_value_to_ora_value(100, BigDecimal).should eql(100)
135
+ end
136
+
137
+ it "should translate Ruby Bignum value to BigDecimal when BigDecimal type specified" do
138
+ big_decimal = @conn.ruby_value_to_ora_value(12345678901234567890, BigDecimal)
139
+ big_decimal.class.should == BigDecimal
140
+ big_decimal.should == BigDecimal("12345678901234567890")
141
+ end
142
+
143
+ # it "should translate Ruby OraDate value to DateTime when DateTime type specified" do
144
+ # now = OraDate.now
145
+ # @conn.ruby_value_to_ora_value(now, DateTime).should eql(now.to_datetime)
146
+ # end
147
+
148
+ it "should translate Ruby String value to Java::OracleSql::CLOB when Java::OracleSql::CLOB type specified" do
149
+ large_text = "x" * 100_000
150
+ ora_value = @conn.ruby_value_to_ora_value(large_text, Java::OracleSql::CLOB)
151
+ ora_value.class.should == Java::OracleSql::CLOB
152
+ ora_value.length.should == 100_000
153
+ ora_value.getSubString(1, ora_value.length) == large_text
154
+ ora_value.freeTemporary
155
+ end
156
+
157
+ it "should translate Ruby nil value to empty Java::OracleSql::CLOB when Java::OracleSql::CLOB type specified" do
158
+ ora_value = @conn.ruby_value_to_ora_value(nil, Java::OracleSql::CLOB)
159
+ ora_value.class.should == Java::OracleSql::CLOB
160
+ ora_value.isEmptyLob.should be_true
161
+ end
162
+
163
+ it "should translate Oracle BigDecimal integer value to Fixnum" do
164
+ @conn.ora_value_to_ruby_value(BigDecimal("100")).should eql(100)
165
+ end
166
+
167
+ it "should translate Oracle BigDecimal float value to BigDecimal" do
168
+ @conn.ora_value_to_ruby_value(BigDecimal("100.11")).should eql(BigDecimal("100.11"))
169
+ end
170
+
171
+ # it "should translate Oracle OraDate value to Time" do
172
+ # now = OraDate.now
173
+ # @conn.ora_value_to_ruby_value(now).should eql(now.to_time)
174
+ # end
175
+
176
+ it "should translate Oracle CLOB value to String" do
177
+ large_text = "āčē" * 100_000
178
+ clob = @conn.ruby_value_to_ora_value(large_text, Java::OracleSql::CLOB)
179
+ @conn.ora_value_to_ruby_value(clob).should == large_text
180
+ clob.freeTemporary
181
+ end
182
+
183
+ it "should translate empty Oracle CLOB value to nil" do
184
+ clob = @conn.ruby_value_to_ora_value(nil, Java::OracleSql::CLOB)
185
+ @conn.ora_value_to_ruby_value(clob).should be_nil
186
+ end
187
+
188
+ end
189
+
190
+ end
191
+
192
+ describe "SQL statements" do
193
+
194
+ it "should execute SQL statement and return first result" do
195
+ @now = Time.local(2008,05,31,23,22,11)
196
+ @conn.select_first("SELECT 'abc',123,123.456,
197
+ TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')
198
+ FROM dual").should == ["abc",123,123.456,@now]
199
+ end
200
+
201
+ it "should execute SQL statement with bind parameters and return first result" do
202
+ @today = Date.parse("2008-05-31")
203
+ @now = Time.local(2008,05,31,23,22,11)
204
+ @conn.select_first("SELECT :1,:2,:3,:4,:5 FROM dual",
205
+ 'abc',123,123.456,@now,@today).should == ["abc",123,123.456,@now,Time.parse(@today.to_s)]
206
+ end
207
+
208
+ it "should execute SQL statement with NULL values and return first result" do
209
+ @now = Time.local(2008,05,31,23,22,11)
210
+ @conn.select_first("SELECT NULL,123,123.456,
211
+ TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')
212
+ FROM dual").should == [nil,123,123.456,@now]
213
+ end
214
+
215
+ if defined?(JRUBY_VERSION)
216
+
217
+ it "should execute SQL statement with NULL values as bind parameters and return first result" do
218
+ @today = Date.parse("2008-05-31")
219
+ @now = Time.local(2008,05,31,23,22,11)
220
+ @conn.select_first("SELECT :1,:2,:3,:4,:5 FROM dual",
221
+ nil,123,123.456,@now,@today).should == [nil,123,123.456,@now,Time.parse(@today.to_s)]
222
+ end
223
+
224
+ end
225
+
226
+ it "should execute SQL statement and return all results" do
227
+ @now = Time.local(2008,05,31,23,22,11)
228
+ @conn.select_all("SELECT 'abc',123,123.456,
229
+ TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')
230
+ FROM dual
231
+ UNION ALL SELECT 'abc',123,123.456,
232
+ TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')
233
+ FROM dual").should == [["abc",123,123.456,@now],["abc",123,123.456,@now]]
234
+ end
235
+
236
+ it "should execute SQL statement with bind parameters and return all results" do
237
+ @now = Time.local(2008,05,31,23,22,11)
238
+ @conn.select_all("SELECT :1,:2,:3,:4 FROM dual UNION ALL SELECT :1,:2,:3,:4 FROM dual",
239
+ 'abc',123,123.456,@now,'abc',123,123.456,@now).should == [["abc",123,123.456,@now],["abc",123,123.456,@now]]
240
+ end
241
+
242
+ it "should execute SQL statement and yield all results in block" do
243
+ @now = Time.local(2008,05,31,23,22,11)
244
+ @conn.select_all("SELECT 'abc',123,123.456,
245
+ TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')
246
+ FROM dual
247
+ UNION ALL SELECT 'abc',123,123.456,
248
+ TO_DATE('#{@now.strftime("%Y-%m-%d %H:%M:%S")}','YYYY-MM-DD HH24:MI:SS')
249
+ FROM dual") do |r|
250
+ r.should == ["abc",123,123.456,@now]
251
+ end.should == 2
252
+ end
253
+
254
+ it "should execute SQL statement with bind parameters and yield all results in block" do
255
+ @now = Time.local(2008,05,31,23,22,11)
256
+ @conn.select_all("SELECT :1,:2,:3,:4 FROM dual UNION ALL SELECT :1,:2,:3,:4 FROM dual",
257
+ 'abc',123,123.456,@now,'abc',123,123.456,@now) do |r|
258
+ r.should == ["abc",123,123.456,@now]
259
+ end.should == 2
260
+ end
261
+
262
+ end
263
+
264
+ describe "PL/SQL procedures" do
265
+ before(:each) do
266
+ @random = rand(1000)
267
+ @now = Time.local(2008,05,31,23,22,11)
268
+ sql = <<-EOS
269
+ CREATE OR REPLACE FUNCTION test_add_random (p_number NUMBER, p_varchar IN OUT VARCHAR2, p_date IN OUT DATE)
270
+ RETURN NUMBER
271
+ IS
272
+ BEGIN
273
+ RETURN p_number + #{@random};
274
+ END test_add_random;
275
+ EOS
276
+ @conn.exec(sql).should be_true
277
+ end
278
+
279
+ # it "should execute PL/SQL procedure definition" do
280
+ # @conn.select_first("SELECT test_add_random(1) FROM dual").should == [@random + 1]
281
+ # end
282
+
283
+ it "should parse PL/SQL procedure call and bind parameters and exec and get bind parameter value" do
284
+ sql = <<-EOS
285
+ BEGIN
286
+ :result := test_add_random (:p_number, :p_varchar, :p_date);
287
+ END;
288
+ EOS
289
+ cursor = @conn.parse(sql)
290
+ cursor.bind_param(":result",nil,Fixnum,nil,'OUT')
291
+ cursor.bind_param(":p_number",100,Fixnum,3)
292
+ cursor.bind_param(":p_varchar","abc",String,100,'IN/OUT')
293
+ cursor.bind_param(":p_date",@now,Time,100,'IN/OUT')
294
+ cursor.exec
295
+ cursor[":result"].should == @random + 100
296
+ cursor[":p_varchar"].should == "abc"
297
+ cursor[":p_date"].should == @now
298
+ cursor.close.should be_nil
299
+ end
300
+
301
+ end
302
+
303
+ describe "commit and rollback" do
304
+ before(:each) do
305
+ sql = "CREATE TABLE test_commit (dummy VARCHAR2(100))"
306
+ @conn.exec(sql).should be_true
307
+ @conn.autocommit = false
308
+ @conn.should_not be_autocommit
309
+ end
310
+ after(:each) do
311
+ sql = "DROP TABLE test_commit"
312
+ @conn.exec(sql).should be_true
313
+ end
314
+
315
+ it "should do commit" do
316
+ @conn.exec("INSERT INTO test_commit VALUES ('test')")
317
+ @conn.commit
318
+ @conn.select_first("SELECT COUNT(*) FROM test_commit")[0].should == 1
319
+ end
320
+
321
+ it "should do rollback" do
322
+ @conn.exec("INSERT INTO test_commit VALUES ('test')")
323
+ @conn.rollback
324
+ @conn.select_first("SELECT COUNT(*) FROM test_commit")[0].should == 0
325
+ end
326
+
327
+ it "should do commit and rollback should not undo commited transaction" do
328
+ @conn.exec("INSERT INTO test_commit VALUES ('test')")
329
+ @conn.commit
330
+ @conn.rollback
331
+ @conn.select_first("SELECT COUNT(*) FROM test_commit")[0].should == 1
332
+ end
333
+
334
+ end
335
+
336
+ end
@@ -46,3 +46,61 @@ describe "Package" do
46
46
  end
47
47
 
48
48
  end
49
+
50
+ describe "Synonym to package" do
51
+
52
+ before(:all) do
53
+ plsql.connection = get_connection
54
+ plsql.connection.exec <<-EOS
55
+ CREATE OR REPLACE PACKAGE hr.test_package IS
56
+ FUNCTION test_procedure ( p_string VARCHAR2 )
57
+ RETURN VARCHAR2;
58
+ END;
59
+ EOS
60
+ plsql.connection.exec <<-EOS
61
+ CREATE OR REPLACE PACKAGE BODY hr.test_package IS
62
+ FUNCTION test_procedure ( p_string VARCHAR2 )
63
+ RETURN VARCHAR2
64
+ IS
65
+ BEGIN
66
+ RETURN UPPER(p_string);
67
+ END test_procedure;
68
+ END;
69
+ EOS
70
+ plsql.connection.exec "CREATE SYNONYM test_pkg_synonym FOR hr.test_package"
71
+ end
72
+
73
+ after(:all) do
74
+ plsql.connection.exec "DROP SYNONYM test_pkg_synonym" rescue nil
75
+ plsql.logoff
76
+ end
77
+
78
+ it "should find synonym to package" do
79
+ PLSQL::Package.find(plsql, :test_pkg_synonym).should_not be_nil
80
+ end
81
+
82
+ it "should execute package function using synonym and return correct value" do
83
+ plsql.test_pkg_synonym.test_procedure('xxx').should == 'XXX'
84
+ end
85
+
86
+ end
87
+
88
+ describe "Public synonym to package" do
89
+
90
+ before(:all) do
91
+ plsql.connection = get_connection
92
+ end
93
+
94
+ after(:all) do
95
+ plsql.logoff
96
+ end
97
+
98
+ it "should find public synonym to package" do
99
+ PLSQL::Package.find(plsql, :utl_encode).should_not be_nil
100
+ end
101
+
102
+ it "should execute package function using public synonym and return correct value" do
103
+ plsql.utl_encode.base64_encode('abc').should == '4372773D'
104
+ end
105
+
106
+ end