ruby-plsql 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|