ruby-plsql 0.2.4 → 0.3.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.
@@ -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