ruby-plsql 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +19 -0
- data/License.txt +1 -1
- data/README.rdoc +9 -4
- data/VERSION +1 -1
- data/lib/plsql/connection.rb +24 -9
- data/lib/plsql/helpers.rb +9 -0
- data/lib/plsql/jdbc_connection.rb +38 -9
- data/lib/plsql/oci8_patches.rb +25 -0
- data/lib/plsql/oci_connection.rb +46 -12
- data/lib/plsql/package.rb +25 -12
- data/lib/plsql/procedure.rb +23 -29
- data/lib/plsql/procedure_call.rb +53 -4
- data/lib/plsql/schema.rb +114 -45
- data/lib/plsql/sequence.rb +1 -1
- data/lib/plsql/sql_statements.rb +7 -2
- data/lib/plsql/table.rb +80 -25
- data/lib/plsql/type.rb +87 -0
- data/lib/plsql/variable.rb +146 -0
- data/lib/plsql/version.rb +1 -1
- data/lib/plsql/view.rb +41 -0
- data/lib/ruby_plsql.rb +1 -1
- data/spec/plsql/connection_spec.rb +112 -50
- data/spec/plsql/package_spec.rb +19 -10
- data/spec/plsql/procedure_spec.rb +159 -126
- data/spec/plsql/schema_spec.rb +109 -1
- data/spec/plsql/sql_statements_spec.rb +14 -32
- data/spec/plsql/table_spec.rb +75 -9
- data/spec/plsql/type_spec.rb +133 -0
- data/spec/plsql/variable_spec.rb +458 -0
- data/spec/plsql/version_spec.rb +8 -0
- data/spec/plsql/view_spec.rb +259 -0
- data/spec/spec_helper.rb +1 -1
- metadata +15 -2
data/History.txt
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
== 0.4.1 2010-01-04
|
2
|
+
|
3
|
+
* New features
|
4
|
+
* Call procedures from SYS.STANDARD without schema and package prefix
|
5
|
+
* DBMS_OUTPUT logging to specified IO stream (e.g. plsql.dbms_output_stream = STDOUT)
|
6
|
+
* Support table operations also on views
|
7
|
+
* Specify plsql.connection.prefetch_rows= to reduce network round trips when selecting large number of rows
|
8
|
+
* Support for PLS_INTEGER and BINARY_INTEGER parameters and return values
|
9
|
+
* Access to package variables (basic types, object types, %TYPE and %ROWTYPE)
|
10
|
+
* Table insert_values method
|
11
|
+
* Insert partial list of table column values (and use default values for missing columns)
|
12
|
+
* Improvements
|
13
|
+
* Improved performance of table and synonyms metadata select
|
14
|
+
* Check required ruby-oci8 version
|
15
|
+
* Bug fixes
|
16
|
+
* limit object types when selecting from all_objects to avoid getting irrelevant records with the same name
|
17
|
+
* select where condition :column => nil is transformed to "column IS NULL"
|
18
|
+
* TIMESTAMP fractional seconds patch for ruby-oci8 2.0.3
|
19
|
+
|
1
20
|
== 0.4.0 2009-11-23
|
2
21
|
|
3
22
|
* New features
|
data/License.txt
CHANGED
data/README.rdoc
CHANGED
@@ -6,9 +6,9 @@ Ruby API for calling Oracle PL/SQL procedures.
|
|
6
6
|
|
7
7
|
ruby-plsql gem provides simple Ruby API for calling Oracle PL/SQL procedures. It could be used both for accessing Oracle PL/SQL API procedures in legacy applications as well as it could be used to create PL/SQL unit tests using Ruby testing libraries.
|
8
8
|
|
9
|
-
NUMBER, VARCHAR2, DATE, TIMESTAMP, CLOB, BLOB, BOOLEAN, PL/SQL RECORD, TABLE, VARRAY, OBJECT and CURSOR types are supported for input and output parameters and return values of PL/SQL procedures and functions.
|
9
|
+
NUMBER, BINARY_INTEGER, PLS_INTEGER, VARCHAR2, NVARCHAR2, CHAR, NCHAR, DATE, TIMESTAMP, CLOB, BLOB, BOOLEAN, PL/SQL RECORD, TABLE, VARRAY, OBJECT and CURSOR types are supported for input and output parameters and return values of PL/SQL procedures and functions.
|
10
10
|
|
11
|
-
ruby-plsql
|
11
|
+
ruby-plsql supports both Ruby 1.8 MRI, Ruby 1.9.1 YARV and JRuby 1.3/1.4 runtime environments.
|
12
12
|
|
13
13
|
== USAGE
|
14
14
|
|
@@ -36,7 +36,7 @@ ruby-plsql support both Ruby 1.8 MRI, Ruby 1.9.1 YARV and JRuby 1.3/1.4 runtime
|
|
36
36
|
|
37
37
|
# Nested objects or arrays are also supported
|
38
38
|
p_employee = { :employee_id => 1, :first_name => 'First', :last_name => 'Last', :hire_date => Time.local(2000,01,31),
|
39
|
-
:address => {:street => 'Street', :city => 'City', :country => 'Country},
|
39
|
+
:address => {:street => 'Street', :city => 'City', :country => 'Country'},
|
40
40
|
:phones => [{:type => 'mobile', :phone_number => '123456'}, {:type => 'fixed', :phone_number => '654321'}]}
|
41
41
|
plsql.test_store_employee(p_employee)
|
42
42
|
|
@@ -67,6 +67,11 @@ ruby-plsql also provides simple API for select/insert/update/delete table operat
|
|
67
67
|
employees = [employee1, employee2, ... ] # array of many Hashes
|
68
68
|
plsql.employees.insert employees
|
69
69
|
|
70
|
+
# insert many records as list of values
|
71
|
+
plsql.employees.insert_values [:employee_id, :first_name, :last_name],
|
72
|
+
[1, 'First 1', 'Last 1'],
|
73
|
+
[2, 'First 2', 'Last 2']
|
74
|
+
|
70
75
|
# select one record
|
71
76
|
plsql.employees.first # SELECT * FROM employees
|
72
77
|
# fetch first row => {:employee_id => ..., :first_name => '...', ...}
|
@@ -131,7 +136,7 @@ In addition install either ruby-oci8 (for MRI/YARV) or copy Oracle JDBC driver t
|
|
131
136
|
|
132
137
|
(The MIT License)
|
133
138
|
|
134
|
-
Copyright (c)
|
139
|
+
Copyright (c) 2008-2010 Raimonds Simanovskis
|
135
140
|
|
136
141
|
Permission is hereby granted, free of charge, to any person obtaining
|
137
142
|
a copy of this software and associated documentation files (the
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.1
|
data/lib/plsql/connection.rb
CHANGED
@@ -65,22 +65,28 @@ module PLSQL
|
|
65
65
|
raise NoMethodError, "Not implemented for this raw driver"
|
66
66
|
end
|
67
67
|
|
68
|
+
# Set number of rows to be prefetched. This can reduce the number of network round trips when fetching many rows.
|
69
|
+
# The default value is one. (If ActiveRecord oracle_enhanced connection is used then default is 100)
|
70
|
+
def prefetch_rows=(value)
|
71
|
+
raise NoMethodError, "Not implemented for this raw driver"
|
72
|
+
end
|
73
|
+
|
68
74
|
def select_first(sql, *bindvars) #:nodoc:
|
69
|
-
cursor = cursor_from_query(
|
75
|
+
cursor = cursor_from_query(sql, bindvars, :prefetch_rows => 1)
|
70
76
|
cursor.fetch
|
71
77
|
ensure
|
72
78
|
cursor.close rescue nil
|
73
79
|
end
|
74
80
|
|
75
81
|
def select_hash_first(sql, *bindvars) #:nodoc:
|
76
|
-
cursor = cursor_from_query(
|
82
|
+
cursor = cursor_from_query(sql, bindvars, :prefetch_rows => 1)
|
77
83
|
cursor.fetch_hash
|
78
84
|
ensure
|
79
85
|
cursor.close rescue nil
|
80
86
|
end
|
81
87
|
|
82
88
|
def select_all(sql, *bindvars, &block) #:nodoc:
|
83
|
-
cursor = cursor_from_query(
|
89
|
+
cursor = cursor_from_query(sql, bindvars)
|
84
90
|
results = []
|
85
91
|
row_count = 0
|
86
92
|
while row = cursor.fetch
|
@@ -97,7 +103,7 @@ module PLSQL
|
|
97
103
|
end
|
98
104
|
|
99
105
|
def select_hash_all(sql, *bindvars, &block) #:nodoc:
|
100
|
-
cursor = cursor_from_query(
|
106
|
+
cursor = cursor_from_query(sql, bindvars)
|
101
107
|
results = []
|
102
108
|
row_count = 0
|
103
109
|
while row = cursor.fetch_hash
|
@@ -121,10 +127,6 @@ module PLSQL
|
|
121
127
|
raise NoMethodError, "Not implemented for this raw driver"
|
122
128
|
end
|
123
129
|
|
124
|
-
def arrays_to_hash(keys, values) #:nodoc:
|
125
|
-
(0...keys.size).inject({}) { |hash, i| hash[keys[i]] = values[i]; hash }
|
126
|
-
end
|
127
|
-
|
128
130
|
module CursorCommon
|
129
131
|
# Fetch all rows from cursor, each row as array of values
|
130
132
|
def fetch_all
|
@@ -146,10 +148,23 @@ module PLSQL
|
|
146
148
|
|
147
149
|
# Fetch row from cursor as hash {:column => value, ...}
|
148
150
|
def fetch_hash
|
149
|
-
(row = fetch) &&
|
151
|
+
(row = fetch) && ArrayHelpers::to_hash(fields, row)
|
150
152
|
end
|
151
153
|
end
|
152
154
|
|
155
|
+
# all_synonyms view is quite slow therefore
|
156
|
+
# this implementation is overriden in OCI connection with faster native OCI method
|
157
|
+
def describe_synonym(schema_name, synonym_name) #:nodoc:
|
158
|
+
select_first(
|
159
|
+
"SELECT table_owner, table_name FROM all_synonyms WHERE owner = :owner AND synonym_name = :synonym_name",
|
160
|
+
schema_name.to_s.upcase, synonym_name.to_s.upcase)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns array with major and minor version of database (e.g. [10, 2])
|
164
|
+
def database_version
|
165
|
+
raise NoMethodError, "Not implemented for this raw driver"
|
166
|
+
end
|
167
|
+
|
153
168
|
end
|
154
169
|
|
155
170
|
end
|
@@ -54,6 +54,10 @@ module PLSQL
|
|
54
54
|
raw_connection.setAutoCommit(value)
|
55
55
|
end
|
56
56
|
|
57
|
+
def prefetch_rows=(value)
|
58
|
+
raw_connection.setDefaultRowPrefetch(value)
|
59
|
+
end
|
60
|
+
|
57
61
|
def exec(sql, *bindvars)
|
58
62
|
cs = prepare_call(sql, *bindvars)
|
59
63
|
cs.execute
|
@@ -127,8 +131,11 @@ module PLSQL
|
|
127
131
|
end
|
128
132
|
end
|
129
133
|
|
130
|
-
def self.new_from_query(conn, sql,
|
134
|
+
def self.new_from_query(conn, sql, bindvars=[], options={})
|
131
135
|
stmt = conn.prepare_statement(sql, *bindvars)
|
136
|
+
if prefetch_rows = options[:prefetch_rows]
|
137
|
+
stmt.setRowPrefetch(prefetch_rows)
|
138
|
+
end
|
132
139
|
cursor = Cursor.new(conn, stmt.executeQuery)
|
133
140
|
cursor.statement = stmt
|
134
141
|
cursor
|
@@ -164,8 +171,8 @@ module PLSQL
|
|
164
171
|
CallableStatement.new(self, sql)
|
165
172
|
end
|
166
173
|
|
167
|
-
def cursor_from_query(sql,
|
168
|
-
Cursor.new_from_query(sql,
|
174
|
+
def cursor_from_query(sql, bindvars=[], options={})
|
175
|
+
Cursor.new_from_query(self, sql, bindvars, options)
|
169
176
|
end
|
170
177
|
|
171
178
|
def prepare_statement(sql, *bindvars)
|
@@ -194,7 +201,7 @@ module PLSQL
|
|
194
201
|
Java::OracleSql::CLOB => Java::oracle.jdbc.OracleTypes::CLOB,
|
195
202
|
Java::OracleSql::BLOB => Java::oracle.jdbc.OracleTypes::BLOB,
|
196
203
|
Date => java.sql.Types::DATE,
|
197
|
-
Time => java.sql.Types::
|
204
|
+
Time => java.sql.Types::TIMESTAMP,
|
198
205
|
DateTime => java.sql.Types::DATE,
|
199
206
|
Java::OracleSql::ARRAY => Java::oracle.jdbc.OracleTypes::ARRAY,
|
200
207
|
Array => Java::oracle.jdbc.OracleTypes::ARRAY,
|
@@ -207,6 +214,7 @@ module PLSQL
|
|
207
214
|
java.sql.Types::CHAR => String,
|
208
215
|
java.sql.Types::VARCHAR => String,
|
209
216
|
java.sql.Types::NUMERIC => BigDecimal,
|
217
|
+
java.sql.Types::INTEGER => Fixnum,
|
210
218
|
java.sql.Types::DATE => Time,
|
211
219
|
java.sql.Types::TIMESTAMP => Time,
|
212
220
|
Java::oracle.jdbc.OracleTypes::TIMESTAMPTZ => Time,
|
@@ -238,8 +246,10 @@ module PLSQL
|
|
238
246
|
stmt.send("setClob#{key && "AtName"}", key || i, value)
|
239
247
|
when :'Java::OracleSql::BLOB'
|
240
248
|
stmt.send("setBlob#{key && "AtName"}", key || i, value)
|
241
|
-
when :Date, :
|
249
|
+
when :Date, :DateTime, :'Java::OracleSql::DATE'
|
242
250
|
stmt.send("setDATE#{key && "AtName"}", key || i, value)
|
251
|
+
when :Time, :'Java::JavaSql::Timestamp'
|
252
|
+
stmt.send("setTimestamp#{key && "AtName"}", key || i, value)
|
243
253
|
when :NilClass
|
244
254
|
if ['TABLE', 'VARRAY', 'OBJECT'].include?(metadata[:data_type])
|
245
255
|
stmt.send("setNull#{key && "AtName"}", key || i, get_java_sql_type(value, type),
|
@@ -280,8 +290,10 @@ module PLSQL
|
|
280
290
|
stmt.getClob(i)
|
281
291
|
when :'Java::OracleSql::BLOB'
|
282
292
|
stmt.getBlob(i)
|
283
|
-
when :Date, :
|
293
|
+
when :Date, :DateTime
|
284
294
|
stmt.getDATE(i)
|
295
|
+
when :Time
|
296
|
+
stmt.getTimestamp(i)
|
285
297
|
when :'Java::OracleSql::ARRAY'
|
286
298
|
stmt.getArray(i)
|
287
299
|
when :'Java::OracleSql::STRUCT'
|
@@ -312,8 +324,10 @@ module PLSQL
|
|
312
324
|
[Java::OracleSql::BLOB, nil]
|
313
325
|
when "NUMBER"
|
314
326
|
[BigDecimal, nil]
|
327
|
+
when "PLS_INTEGER", "BINARY_INTEGER"
|
328
|
+
[Fixnum, nil]
|
315
329
|
when "DATE"
|
316
|
-
[
|
330
|
+
[DateTime, nil]
|
317
331
|
when "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE"
|
318
332
|
[Time, nil]
|
319
333
|
when "TABLE", "VARRAY"
|
@@ -341,7 +355,7 @@ module PLSQL
|
|
341
355
|
else
|
342
356
|
java_bigdecimal(value)
|
343
357
|
end
|
344
|
-
when :
|
358
|
+
when :Date, :DateTime
|
345
359
|
case value
|
346
360
|
when DateTime
|
347
361
|
java_date(Time.send(plsql.default_timezone, value.year, value.month, value.day, value.hour, value.min, value.sec))
|
@@ -350,6 +364,8 @@ module PLSQL
|
|
350
364
|
else
|
351
365
|
java_date(value)
|
352
366
|
end
|
367
|
+
when :Time
|
368
|
+
java_timestamp(value)
|
353
369
|
when :'Java::OracleSql::CLOB'
|
354
370
|
if value
|
355
371
|
clob = Java::OracleSql::CLOB.createTemporary(raw_connection, false, Java::OracleSql::CLOB::DURATION_SESSION)
|
@@ -431,6 +447,11 @@ module PLSQL
|
|
431
447
|
t = value.timeValue
|
432
448
|
Time.send(plsql.default_timezone, d.year + 1900, d.month + 1, d.date, t.hours, t.minutes, t.seconds)
|
433
449
|
end
|
450
|
+
when Java::JavaSql::Timestamp
|
451
|
+
if value
|
452
|
+
Time.send(plsql.default_timezone, value.year + 1900, value.month + 1, value.date, value.hours, value.minutes, value.seconds,
|
453
|
+
value.nanos / 1000)
|
454
|
+
end
|
434
455
|
when Java::OracleSql::CLOB
|
435
456
|
if value.isEmptyLob
|
436
457
|
nil
|
@@ -450,7 +471,7 @@ module PLSQL
|
|
450
471
|
struct_metadata = descriptor.getMetaData
|
451
472
|
field_names = (1..descriptor.getLength).map {|i| struct_metadata.getColumnName(i).downcase.to_sym}
|
452
473
|
field_values = value.getAttributes.map{|e| ora_value_to_ruby_value(e)}
|
453
|
-
|
474
|
+
ArrayHelpers::to_hash(field_names, field_values)
|
454
475
|
when Java::java.sql.ResultSet
|
455
476
|
Cursor.new(self, value)
|
456
477
|
else
|
@@ -458,12 +479,20 @@ module PLSQL
|
|
458
479
|
end
|
459
480
|
end
|
460
481
|
|
482
|
+
def database_version
|
483
|
+
@database_version ||= (md = raw_connection.getMetaData) && [md.getDatabaseMajorVersion, md.getDatabaseMinorVersion]
|
484
|
+
end
|
485
|
+
|
461
486
|
private
|
462
487
|
|
463
488
|
def java_date(value)
|
464
489
|
value && Java::oracle.sql.DATE.new(value.strftime("%Y-%m-%d %H:%M:%S"))
|
465
490
|
end
|
466
491
|
|
492
|
+
def java_timestamp(value)
|
493
|
+
value && Java::java.sql.Timestamp.new(value.year-1900, value.month-1, value.day, value.hour, value.min, value.sec, value.usec * 1000)
|
494
|
+
end
|
495
|
+
|
467
496
|
def java_bigdecimal(value)
|
468
497
|
value && java.math.BigDecimal.new(value.to_s)
|
469
498
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# apply TIMESTAMP fractional seconds patch to ruby-oci8 2.0.3
|
2
|
+
# see http://rubyforge.org/forum/forum.php?thread_id=46576&forum_id=1078
|
3
|
+
if OCI8::VERSION == "2.0.3" &&
|
4
|
+
!OCI8::BindType::Util.method_defined?(:datetime_to_array_without_timestamp_patch)
|
5
|
+
|
6
|
+
OCI8::BindType::Util.module_eval do
|
7
|
+
alias :datetime_to_array_without_timestamp_patch :datetime_to_array
|
8
|
+
def datetime_to_array(val, full)
|
9
|
+
result = datetime_to_array_without_timestamp_patch(val, full)
|
10
|
+
if result && result[6] == 0
|
11
|
+
if val.respond_to? :nsec
|
12
|
+
fsec = val.nsec
|
13
|
+
elsif val.respond_to? :usec
|
14
|
+
fsec = val.usec * 1000
|
15
|
+
else
|
16
|
+
fsec = 0
|
17
|
+
end
|
18
|
+
result[6] = fsec
|
19
|
+
end
|
20
|
+
result
|
21
|
+
end
|
22
|
+
private :datetime_to_array_without_timestamp_patch, :datetime_to_array
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/plsql/oci_connection.rb
CHANGED
@@ -2,10 +2,16 @@ begin
|
|
2
2
|
require "oci8"
|
3
3
|
rescue LoadError
|
4
4
|
# OCI8 driver is unavailable.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
raise LoadError, "ERROR: ruby-plsql could not load ruby-oci8 library. Please install ruby-oci8 gem."
|
6
|
+
end
|
7
|
+
|
8
|
+
require "plsql/oci8_patches"
|
9
|
+
|
10
|
+
# check ruby-oci8 version
|
11
|
+
required_oci8_version = [2, 0, 3]
|
12
|
+
oci8_version_ints = OCI8::VERSION.scan(/\d+/).map{|s| s.to_i}
|
13
|
+
if (oci8_version_ints <=> required_oci8_version) < 0
|
14
|
+
raise LoadError, "ERROR: ruby-oci8 version #{OCI8::VERSION} is too old. Please install ruby-oci8 version #{required_oci8_version.join('.')} or later."
|
9
15
|
end
|
10
16
|
|
11
17
|
module PLSQL
|
@@ -31,6 +37,10 @@ module PLSQL
|
|
31
37
|
raw_connection.autocommit = value
|
32
38
|
end
|
33
39
|
|
40
|
+
def prefetch_rows=(value)
|
41
|
+
raw_connection.prefetch_rows = value
|
42
|
+
end
|
43
|
+
|
34
44
|
def exec(sql, *bindvars)
|
35
45
|
raw_connection.exec(sql, *bindvars)
|
36
46
|
true
|
@@ -54,8 +64,17 @@ module PLSQL
|
|
54
64
|
self.new(conn, raw_cursor)
|
55
65
|
end
|
56
66
|
|
57
|
-
def self.new_from_query(conn, sql,
|
58
|
-
|
67
|
+
def self.new_from_query(conn, sql, bindvars=[], options={})
|
68
|
+
cursor = new_from_parse(conn, sql)
|
69
|
+
if prefetch_rows = options[:prefetch_rows]
|
70
|
+
cursor.prefetch_rows = prefetch_rows
|
71
|
+
end
|
72
|
+
cursor.exec(*bindvars)
|
73
|
+
cursor
|
74
|
+
end
|
75
|
+
|
76
|
+
def prefetch_rows=(value)
|
77
|
+
@raw_cursor.prefetch_rows = value
|
59
78
|
end
|
60
79
|
|
61
80
|
def bind_param(arg, value, metadata)
|
@@ -99,24 +118,24 @@ module PLSQL
|
|
99
118
|
Cursor.new_from_parse(self, sql)
|
100
119
|
end
|
101
120
|
|
102
|
-
def cursor_from_query(sql,
|
103
|
-
Cursor.new_from_query(sql,
|
121
|
+
def cursor_from_query(sql, bindvars=[], options={})
|
122
|
+
Cursor.new_from_query(self, sql, bindvars, options)
|
104
123
|
end
|
105
124
|
|
106
125
|
def plsql_to_ruby_data_type(metadata)
|
107
126
|
data_type, data_length = metadata[:data_type], metadata[:data_length]
|
108
127
|
case data_type
|
109
|
-
when "VARCHAR2"
|
128
|
+
when "VARCHAR2", "CHAR", "NVARCHAR2", "NCHAR"
|
110
129
|
[String, data_length || 32767]
|
111
|
-
when "CLOB"
|
130
|
+
when "CLOB", "NCLOB"
|
112
131
|
[OCI8::CLOB, nil]
|
113
132
|
when "BLOB"
|
114
133
|
[OCI8::BLOB, nil]
|
115
|
-
when "NUMBER"
|
134
|
+
when "NUMBER", "PLS_INTEGER", "BINARY_INTEGER"
|
116
135
|
[OraNumber, nil]
|
117
136
|
when "DATE"
|
118
137
|
[DateTime, nil]
|
119
|
-
when "TIMESTAMP"
|
138
|
+
when "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE"
|
120
139
|
[Time, nil]
|
121
140
|
when "TABLE", "VARRAY", "OBJECT"
|
122
141
|
# create Ruby class for collection
|
@@ -240,6 +259,21 @@ module PLSQL
|
|
240
259
|
end
|
241
260
|
end
|
242
261
|
|
262
|
+
def describe_synonym(schema_name, synonym_name)
|
263
|
+
if schema_name == 'PUBLIC'
|
264
|
+
full_name = synonym_name.to_s
|
265
|
+
else
|
266
|
+
full_name = "#{schema_name}.#{synonym_name}"
|
267
|
+
end
|
268
|
+
metadata = raw_connection.describe_synonym(full_name)
|
269
|
+
[metadata.schema_name, metadata.name]
|
270
|
+
rescue OCIError
|
271
|
+
nil
|
272
|
+
end
|
273
|
+
|
274
|
+
def database_version
|
275
|
+
@database_version ||= (version = raw_connection.oracle_server_version) && [version.major, version.minor]
|
276
|
+
end
|
243
277
|
|
244
278
|
private
|
245
279
|
|
data/lib/plsql/package.rb
CHANGED
@@ -2,16 +2,16 @@ module PLSQL
|
|
2
2
|
|
3
3
|
module PackageClassMethods #:nodoc:
|
4
4
|
def find(schema, package)
|
5
|
-
if schema.select_first(
|
6
|
-
SELECT object_name FROM all_objects
|
5
|
+
if schema.select_first(
|
6
|
+
"SELECT object_name FROM all_objects
|
7
7
|
WHERE owner = :owner
|
8
8
|
AND object_name = :package
|
9
9
|
AND object_type = 'PACKAGE'",
|
10
10
|
schema.schema_name, package.to_s.upcase)
|
11
11
|
new(schema, package)
|
12
12
|
# search for synonym
|
13
|
-
elsif (row = schema.select_first(
|
14
|
-
SELECT o.owner, o.object_name
|
13
|
+
elsif (row = schema.select_first(
|
14
|
+
"SELECT o.owner, o.object_name
|
15
15
|
FROM all_synonyms s, all_objects o
|
16
16
|
WHERE s.owner IN (:owner, 'PUBLIC')
|
17
17
|
AND s.synonym_name = :synonym_name
|
@@ -34,22 +34,35 @@ module PLSQL
|
|
34
34
|
@schema = schema
|
35
35
|
@override_schema_name = override_schema_name
|
36
36
|
@package = package.to_s.upcase
|
37
|
-
@
|
37
|
+
@package_objects = {}
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def method_missing(method, *args, &block)
|
43
|
-
if
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
if assignment = (method.to_s[-1,1] == '=')
|
44
|
+
method = method.to_s.chop.to_sym
|
45
|
+
end
|
46
|
+
object = (@package_objects[method] ||=
|
47
|
+
Procedure.find(@schema, method, @package, @override_schema_name) ||
|
48
|
+
Variable.find(@schema, method, @package, @override_schema_name))
|
49
|
+
case object
|
50
|
+
when Procedure
|
51
|
+
raise ArgumentError, "Cannot assign value to package procedure '#{method.to_s.upcase}'" if assignment
|
52
|
+
object.exec(*args, &block)
|
53
|
+
when Variable
|
54
|
+
if assignment
|
55
|
+
raise ArgumentError, "Just one value can be assigned to package variable '#{method.to_s.upcase}'" unless args.size == 1 && block == nil
|
56
|
+
object.value = args[0]
|
57
|
+
else
|
58
|
+
raise ArgumentError, "Cannot pass arguments when getting package variable '#{method.to_s.upcase}' value" unless args.size == 0 && block == nil
|
59
|
+
object.value
|
60
|
+
end
|
48
61
|
else
|
49
|
-
raise ArgumentError, "No PL/SQL procedure found"
|
62
|
+
raise ArgumentError, "No PL/SQL procedure or variable '#{method.to_s.upcase}' found"
|
50
63
|
end
|
51
64
|
end
|
52
|
-
|
65
|
+
|
53
66
|
end
|
54
67
|
|
55
68
|
end
|