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
@@ -0,0 +1,345 @@
|
|
1
|
+
module PLSQL
|
2
|
+
class ProcedureCall #:nodoc:
|
3
|
+
|
4
|
+
def initialize(procedure, args = [])
|
5
|
+
@procedure = procedure
|
6
|
+
@overload = get_overload_from_arguments_list(args)
|
7
|
+
construct_sql(args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def exec
|
11
|
+
@cursor = @procedure.schema.connection.parse(@sql)
|
12
|
+
|
13
|
+
@bind_values.each do |arg, value|
|
14
|
+
@cursor.bind_param(":#{arg}", value, @bind_metadata[arg])
|
15
|
+
end
|
16
|
+
|
17
|
+
@return_vars.each do |var|
|
18
|
+
@cursor.bind_param(":#{var}", nil, @return_vars_metadata[var])
|
19
|
+
end
|
20
|
+
|
21
|
+
@cursor.exec
|
22
|
+
|
23
|
+
if block_given?
|
24
|
+
yield get_return_value
|
25
|
+
nil
|
26
|
+
else
|
27
|
+
get_return_value
|
28
|
+
end
|
29
|
+
ensure
|
30
|
+
@cursor.close if @cursor
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def get_overload_from_arguments_list(args)
|
36
|
+
# find which overloaded definition to use
|
37
|
+
# if definition is overloaded then match by number of arguments
|
38
|
+
if @procedure.overloaded?
|
39
|
+
# named arguments
|
40
|
+
if args.size == 1 && args[0].is_a?(Hash)
|
41
|
+
number_of_args = args[0].keys.size
|
42
|
+
overload = overload_argument_list.keys.detect do |ov|
|
43
|
+
overload_argument_list[ov].size == number_of_args &&
|
44
|
+
overload_arguments[ov].keys.sort_by{|k| k.to_s} == args[0].keys.sort_by{|k| k.to_s}
|
45
|
+
end
|
46
|
+
# sequential arguments
|
47
|
+
# TODO: should try to implement matching by types of arguments
|
48
|
+
else
|
49
|
+
number_of_args = args.size
|
50
|
+
overload = overload_argument_list.keys.detect do |ov|
|
51
|
+
overload_argument_list[ov].size == number_of_args
|
52
|
+
end
|
53
|
+
end
|
54
|
+
raise ArgumentError, "Wrong number of arguments passed to overloaded PL/SQL procedure" unless overload
|
55
|
+
overload
|
56
|
+
else
|
57
|
+
0
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def construct_sql(args)
|
62
|
+
@declare_sql = "DECLARE\n"
|
63
|
+
@assignment_sql = "BEGIN\n"
|
64
|
+
@call_sql = ""
|
65
|
+
@return_sql = ""
|
66
|
+
@return_vars = []
|
67
|
+
@return_vars_metadata = {}
|
68
|
+
|
69
|
+
# construct procedure call if procedure name is available
|
70
|
+
# otherwise will get surrounding call_sql from @procedure (used for table statements)
|
71
|
+
if procedure_name
|
72
|
+
@call_sql << add_return if return_metadata
|
73
|
+
@call_sql << "#{schema_name}." if schema_name
|
74
|
+
@call_sql << "#{package_name}." if package_name
|
75
|
+
@call_sql << "#{procedure_name}("
|
76
|
+
end
|
77
|
+
|
78
|
+
@bind_values = {}
|
79
|
+
@bind_metadata = {}
|
80
|
+
|
81
|
+
# Named arguments
|
82
|
+
if args.size == 1 && args[0].is_a?(Hash) &&
|
83
|
+
# do not use named arguments if procedure has just one PL/SQL record or object type argument -
|
84
|
+
# in that case passed Hash should be used as value for this PL/SQL record argument
|
85
|
+
# (which will be processed in sequential arguments bracnh)
|
86
|
+
!(argument_list.size == 1 &&
|
87
|
+
['PL/SQL RECORD','OBJECT'].include?(arguments[(only_argument=argument_list[0])][:data_type]) &&
|
88
|
+
args[0].keys != [only_argument])
|
89
|
+
# Add missing output arguments with nil value
|
90
|
+
arguments.each do |arg, metadata|
|
91
|
+
if !args[0].has_key?(arg) && metadata[:in_out] == 'OUT'
|
92
|
+
args[0][arg] = nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
# Add passed parameters to procedure call with parameter names
|
96
|
+
@call_sql << args[0].map do |arg, value|
|
97
|
+
"#{arg} => " << add_argument(arg, value)
|
98
|
+
end.join(', ')
|
99
|
+
|
100
|
+
# Sequential arguments
|
101
|
+
else
|
102
|
+
argument_count = argument_list.size
|
103
|
+
raise ArgumentError, "Too many arguments passed to PL/SQL procedure" if args.size > argument_count
|
104
|
+
# Add missing output arguments with nil value
|
105
|
+
if args.size < argument_count &&
|
106
|
+
(args.size...argument_count).all?{|i| arguments[argument_list[i]][:in_out] == 'OUT'}
|
107
|
+
args += [nil] * (argument_count - args.size)
|
108
|
+
end
|
109
|
+
# Add passed parameters to procedure call in sequence
|
110
|
+
@call_sql << (0...args.size).map do |i|
|
111
|
+
arg = argument_list[i]
|
112
|
+
value = args[i]
|
113
|
+
add_argument(arg, value)
|
114
|
+
end.join(', ')
|
115
|
+
end
|
116
|
+
|
117
|
+
# finish procedure call construction if procedure name is available
|
118
|
+
# otherwise will get surrounding call_sql from @procedure (used for table statements)
|
119
|
+
if procedure_name
|
120
|
+
@call_sql << ");\n"
|
121
|
+
else
|
122
|
+
@call_sql = @procedure.call_sql(@call_sql)
|
123
|
+
end
|
124
|
+
add_out_vars
|
125
|
+
@sql = "" << @declare_sql << @assignment_sql << @call_sql << @return_sql << "END;\n"
|
126
|
+
# puts "DEBUG: sql = #{@sql.gsub "\n", "<br/>\n"}"
|
127
|
+
end
|
128
|
+
|
129
|
+
def add_argument(argument, value)
|
130
|
+
argument_metadata = arguments[argument]
|
131
|
+
raise ArgumentError, "Wrong argument #{argument.inspect} passed to PL/SQL procedure" unless argument_metadata
|
132
|
+
case argument_metadata[:data_type]
|
133
|
+
when 'PL/SQL RECORD'
|
134
|
+
@declare_sql << record_declaration_sql(argument, argument_metadata)
|
135
|
+
record_assignment_sql, record_bind_values, record_bind_metadata =
|
136
|
+
record_assignment_sql_values_metadata(argument, argument_metadata, value)
|
137
|
+
@assignment_sql << record_assignment_sql
|
138
|
+
@bind_values.merge!(record_bind_values)
|
139
|
+
@bind_metadata.merge!(record_bind_metadata)
|
140
|
+
"l_#{argument}"
|
141
|
+
when 'PL/SQL BOOLEAN'
|
142
|
+
@declare_sql << "l_#{argument} BOOLEAN;\n"
|
143
|
+
@assignment_sql << "l_#{argument} := (:#{argument} = 1);\n"
|
144
|
+
@bind_values[argument] = value.nil? ? nil : (value ? 1 : 0)
|
145
|
+
@bind_metadata[argument] = argument_metadata.merge(:data_type => "NUMBER", :data_precision => 1)
|
146
|
+
"l_#{argument}"
|
147
|
+
else
|
148
|
+
@bind_values[argument] = value
|
149
|
+
@bind_metadata[argument] = argument_metadata
|
150
|
+
":#{argument}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def record_declaration_sql(argument, argument_metadata)
|
155
|
+
fields_metadata = argument_metadata[:fields]
|
156
|
+
sql = "TYPE t_#{argument} IS RECORD (\n"
|
157
|
+
fields_sorted_by_position = fields_metadata.keys.sort_by{|k| fields_metadata[k][:position]}
|
158
|
+
sql << fields_sorted_by_position.map do |field|
|
159
|
+
metadata = fields_metadata[field]
|
160
|
+
"#{field} #{type_to_sql(metadata)}"
|
161
|
+
end.join(",\n")
|
162
|
+
sql << ");\n"
|
163
|
+
sql << "l_#{argument} t_#{argument};\n"
|
164
|
+
end
|
165
|
+
|
166
|
+
def record_assignment_sql_values_metadata(argument, argument_metadata, record_value)
|
167
|
+
sql = ""
|
168
|
+
bind_values = {}
|
169
|
+
bind_metadata = {}
|
170
|
+
(record_value||{}).each do |key, value|
|
171
|
+
field = key.is_a?(Symbol) ? key : key.to_s.downcase.to_sym
|
172
|
+
metadata = argument_metadata[:fields][field]
|
173
|
+
raise ArgumentError, "Wrong field name #{key.inspect} passed to PL/SQL record argument #{argument.inspect}" unless metadata
|
174
|
+
bind_variable = :"#{argument}_f#{metadata[:position]}"
|
175
|
+
sql << "l_#{argument}.#{field} := :#{bind_variable};\n"
|
176
|
+
bind_values[bind_variable] = value
|
177
|
+
bind_metadata[bind_variable] = metadata
|
178
|
+
end
|
179
|
+
[sql, bind_values, bind_metadata]
|
180
|
+
end
|
181
|
+
|
182
|
+
def add_return
|
183
|
+
case return_metadata[:data_type]
|
184
|
+
when 'PL/SQL RECORD'
|
185
|
+
@declare_sql << record_declaration_sql('return', return_metadata)
|
186
|
+
return_metadata[:fields].each do |field, metadata|
|
187
|
+
bind_variable = :"return_f#{metadata[:position]}"
|
188
|
+
@return_vars << bind_variable
|
189
|
+
@return_vars_metadata[bind_variable] = metadata
|
190
|
+
@return_sql << ":#{bind_variable} := l_return.#{field};\n"
|
191
|
+
end
|
192
|
+
"l_return := "
|
193
|
+
when 'PL/SQL BOOLEAN'
|
194
|
+
@declare_sql << "l_return BOOLEAN;\n"
|
195
|
+
@declare_sql << "x_return NUMBER(1);\n"
|
196
|
+
@return_vars << :return
|
197
|
+
@return_vars_metadata[:return] = return_metadata.merge(:data_type => "NUMBER", :data_precision => 1)
|
198
|
+
@return_sql << "IF l_return IS NULL THEN\nx_return := NULL;\nELSIF l_return THEN\nx_return := 1;\nELSE\nx_return := 0;\nEND IF;\n" <<
|
199
|
+
":return := x_return;\n"
|
200
|
+
"l_return := "
|
201
|
+
else
|
202
|
+
@return_vars << :return
|
203
|
+
@return_vars_metadata[:return] = return_metadata
|
204
|
+
':return := '
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def add_out_vars
|
209
|
+
out_list.each do |argument|
|
210
|
+
argument_metadata = arguments[argument]
|
211
|
+
case argument_metadata[:data_type]
|
212
|
+
when 'PL/SQL RECORD'
|
213
|
+
argument_metadata[:fields].each do |field, metadata|
|
214
|
+
bind_variable = :"#{argument}_o#{metadata[:position]}"
|
215
|
+
@return_vars << bind_variable
|
216
|
+
@return_vars_metadata[bind_variable] = metadata
|
217
|
+
@return_sql << ":#{bind_variable} := l_#{argument}.#{field};\n"
|
218
|
+
end
|
219
|
+
when 'PL/SQL BOOLEAN'
|
220
|
+
@declare_sql << "x_#{argument} NUMBER(1);\n"
|
221
|
+
bind_variable = :"o_#{argument}"
|
222
|
+
@return_vars << bind_variable
|
223
|
+
@return_vars_metadata[bind_variable] = argument_metadata.merge(:data_type => "NUMBER", :data_precision => 1)
|
224
|
+
@return_sql << "IF l_#{argument} IS NULL THEN\nx_#{argument} := NULL;\n" <<
|
225
|
+
"ELSIF l_#{argument} THEN\nx_#{argument} := 1;\nELSE\nx_#{argument} := 0;\nEND IF;\n" <<
|
226
|
+
":#{bind_variable} := x_#{argument};\n"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def type_to_sql(metadata)
|
232
|
+
case metadata[:data_type]
|
233
|
+
when 'NUMBER'
|
234
|
+
precision, scale = metadata[:data_precision], metadata[:data_scale]
|
235
|
+
"NUMBER#{precision ? "(#{precision}#{scale ? ",#{scale}": ""})" : ""}"
|
236
|
+
when 'VARCHAR2', 'CHAR', 'NVARCHAR2', 'NCHAR'
|
237
|
+
length = metadata[:data_length]
|
238
|
+
if length && (char_used = metadata[:char_used])
|
239
|
+
length = "#{length} #{char_used == 'C' ? 'CHAR' : 'BYTE'}"
|
240
|
+
end
|
241
|
+
"#{metadata[:data_type]}#{length ? "(#{length})": ""}"
|
242
|
+
when 'TABLE', 'VARRAY', 'OBJECT'
|
243
|
+
metadata[:sql_type_name]
|
244
|
+
else
|
245
|
+
metadata[:data_type]
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def get_return_value
|
250
|
+
# if function with output parameters
|
251
|
+
if return_metadata && out_list.size > 0
|
252
|
+
result = [function_return_value, {}]
|
253
|
+
out_list.each do |k|
|
254
|
+
result[1][k] = out_var_value(k)
|
255
|
+
end
|
256
|
+
# if function without output parameters
|
257
|
+
elsif return_metadata
|
258
|
+
result = function_return_value
|
259
|
+
# if procedure with output parameters
|
260
|
+
elsif out_list.size > 0
|
261
|
+
result = {}
|
262
|
+
out_list.each do |k|
|
263
|
+
result[k] = out_var_value(k)
|
264
|
+
end
|
265
|
+
# if procedure without output parameters
|
266
|
+
else
|
267
|
+
result = nil
|
268
|
+
end
|
269
|
+
result
|
270
|
+
end
|
271
|
+
|
272
|
+
def function_return_value
|
273
|
+
case return_metadata[:data_type]
|
274
|
+
when 'PL/SQL RECORD'
|
275
|
+
return_value = {}
|
276
|
+
return_metadata[:fields].each do |field, metadata|
|
277
|
+
bind_variable = :"return_f#{metadata[:position]}"
|
278
|
+
return_value[field] = @cursor[":#{bind_variable}"]
|
279
|
+
end
|
280
|
+
return_value
|
281
|
+
when 'PL/SQL BOOLEAN'
|
282
|
+
numeric_value = @cursor[':return']
|
283
|
+
numeric_value.nil? ? nil : numeric_value == 1
|
284
|
+
else
|
285
|
+
@cursor[':return']
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def out_var_value(argument)
|
290
|
+
argument_metadata = arguments[argument]
|
291
|
+
case argument_metadata[:data_type]
|
292
|
+
when 'PL/SQL RECORD'
|
293
|
+
return_value = {}
|
294
|
+
argument_metadata[:fields].each do |field, metadata|
|
295
|
+
bind_variable = :"#{argument}_o#{metadata[:position]}"
|
296
|
+
return_value[field] = @cursor[":#{bind_variable}"]
|
297
|
+
end
|
298
|
+
return_value
|
299
|
+
when 'PL/SQL BOOLEAN'
|
300
|
+
numeric_value = @cursor[":o_#{argument}"]
|
301
|
+
numeric_value.nil? ? nil : numeric_value == 1
|
302
|
+
else
|
303
|
+
@cursor[":#{argument}"]
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def overload_argument_list
|
308
|
+
@overload_argument_list ||= @procedure.argument_list
|
309
|
+
end
|
310
|
+
|
311
|
+
def overload_arguments
|
312
|
+
@overload_arguments ||= @procedure.arguments
|
313
|
+
end
|
314
|
+
|
315
|
+
def argument_list
|
316
|
+
@argument_list ||= overload_argument_list[@overload]
|
317
|
+
end
|
318
|
+
|
319
|
+
def arguments
|
320
|
+
@arguments ||= overload_arguments[@overload]
|
321
|
+
end
|
322
|
+
|
323
|
+
def return_metadata
|
324
|
+
@return_metadata ||= @procedure.return[@overload]
|
325
|
+
end
|
326
|
+
|
327
|
+
def out_list
|
328
|
+
@out_list ||= @procedure.out_list[@overload]
|
329
|
+
end
|
330
|
+
|
331
|
+
def schema_name
|
332
|
+
@schema_name ||= @procedure.schema_name
|
333
|
+
end
|
334
|
+
|
335
|
+
def package_name
|
336
|
+
@package_name ||= @procedure.package
|
337
|
+
end
|
338
|
+
|
339
|
+
def procedure_name
|
340
|
+
@procedure_name ||= @procedure.procedure
|
341
|
+
end
|
342
|
+
|
343
|
+
end
|
344
|
+
|
345
|
+
end
|
data/lib/plsql/schema.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
module PLSQL
|
2
2
|
class Schema
|
3
|
+
include SQLStatements
|
4
|
+
|
3
5
|
@@schemas = {}
|
4
6
|
|
5
7
|
class <<self
|
6
|
-
def find_or_new(connection_alias)
|
8
|
+
def find_or_new(connection_alias) #:nodoc:
|
7
9
|
connection_alias ||= :default
|
8
10
|
if @@schemas[connection_alias]
|
9
11
|
@@schemas[connection_alias]
|
@@ -14,21 +16,32 @@ module PLSQL
|
|
14
16
|
|
15
17
|
end
|
16
18
|
|
17
|
-
def initialize(raw_conn = nil, schema = nil, first = true)
|
19
|
+
def initialize(raw_conn = nil, schema = nil, first = true) #:nodoc:
|
18
20
|
self.connection = raw_conn
|
19
21
|
@schema_name = schema ? schema.to_s.upcase : nil
|
20
22
|
@first = first
|
21
23
|
end
|
22
24
|
|
25
|
+
# Returns connection wrapper object (this is not raw OCI8 or JDBC connection!)
|
23
26
|
def connection
|
24
27
|
@connection
|
25
28
|
end
|
26
29
|
|
27
|
-
def raw_connection=(raw_conn)
|
30
|
+
def raw_connection=(raw_conn) #:nodoc:
|
28
31
|
@connection = raw_conn ? Connection.create(raw_conn) : nil
|
29
32
|
reset_instance_variables
|
30
33
|
end
|
31
34
|
|
35
|
+
# Set connection to OCI8 or JDBC connection:
|
36
|
+
#
|
37
|
+
# plsql.connection = OCI8.new(database_user, database_password, DATABASE_NAME)
|
38
|
+
#
|
39
|
+
# or
|
40
|
+
#
|
41
|
+
# plsql.connection = java.sql.DriverManager.getConnection(
|
42
|
+
# "jdbc:oracle:thin:@#{DATABASE_HOST}:#{DATABASE_PORT}:#{DATABASE_NAME}",
|
43
|
+
# database_user, database_password)
|
44
|
+
#
|
32
45
|
def connection=(conn)
|
33
46
|
if conn.is_a?(::PLSQL::Connection)
|
34
47
|
@connection = conn
|
@@ -38,39 +51,31 @@ module PLSQL
|
|
38
51
|
end
|
39
52
|
end
|
40
53
|
|
54
|
+
# Set connection to current ActiveRecord connection (use in initializer file):
|
55
|
+
#
|
56
|
+
# plsql.activerecord_class = ActiveRecord::Base
|
57
|
+
#
|
41
58
|
def activerecord_class=(ar_class)
|
42
59
|
@connection = ar_class ? Connection.create(nil, ar_class) : nil
|
43
60
|
reset_instance_variables
|
44
61
|
end
|
45
|
-
|
62
|
+
|
63
|
+
# Disconnect from Oracle
|
46
64
|
def logoff
|
47
|
-
connection.logoff
|
65
|
+
@connection.logoff
|
48
66
|
self.connection = nil
|
49
67
|
end
|
50
68
|
|
69
|
+
# Current Oracle schema name
|
51
70
|
def schema_name
|
52
71
|
return nil unless connection
|
53
72
|
@schema_name ||= select_first("SELECT SYS_CONTEXT('userenv','session_user') FROM dual")[0]
|
54
73
|
end
|
55
74
|
|
56
|
-
def select_first(sql, *bindvars)
|
57
|
-
# cursor = connection.exec(sql, *bindvars)
|
58
|
-
# result = cursor.fetch
|
59
|
-
# cursor.close
|
60
|
-
# result
|
61
|
-
connection.select_first(sql, *bindvars)
|
62
|
-
end
|
63
|
-
|
64
|
-
def commit
|
65
|
-
connection.commit
|
66
|
-
end
|
67
|
-
|
68
|
-
def rollback
|
69
|
-
connection.rollback
|
70
|
-
end
|
71
|
-
|
72
75
|
# Set to :local or :utc
|
73
76
|
@@default_timezone = nil
|
77
|
+
|
78
|
+
# Default timezone to which database values will be converted - :utc or :local
|
74
79
|
def default_timezone
|
75
80
|
@@default_timezone ||
|
76
81
|
# Use ActiveRecord class default_timezone when ActiveRecord connection is used
|
@@ -78,7 +83,8 @@ module PLSQL
|
|
78
83
|
# default to local timezone
|
79
84
|
:local
|
80
85
|
end
|
81
|
-
|
86
|
+
|
87
|
+
# Set default timezone to which database values will be converted - :utc or :local
|
82
88
|
def default_timezone=(value)
|
83
89
|
if [:local, :utc].include?(value)
|
84
90
|
@@default_timezone = value
|
@@ -89,7 +95,7 @@ module PLSQL
|
|
89
95
|
|
90
96
|
# Same implementation as for ActiveRecord
|
91
97
|
# 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
|
92
|
-
def local_timezone_offset
|
98
|
+
def local_timezone_offset #:nodoc:
|
93
99
|
::Time.local(2007).utc_offset.to_r / 86400
|
94
100
|
end
|
95
101
|
|
@@ -97,32 +103,35 @@ module PLSQL
|
|
97
103
|
|
98
104
|
def reset_instance_variables
|
99
105
|
if @connection
|
100
|
-
@
|
101
|
-
@packages = {}
|
102
|
-
@schemas = {}
|
106
|
+
@schema_objects = {}
|
103
107
|
else
|
104
|
-
@
|
105
|
-
@packages = nil
|
106
|
-
@schemas = nil
|
108
|
+
@schema_objects = nil
|
107
109
|
end
|
110
|
+
@schema_name = nil
|
108
111
|
@@default_timezone = nil
|
109
112
|
end
|
110
113
|
|
111
|
-
def method_missing(method, *args)
|
114
|
+
def method_missing(method, *args, &block)
|
112
115
|
raise ArgumentError, "No PL/SQL connection" unless connection
|
113
|
-
|
114
|
-
|
116
|
+
# look in cache at first
|
117
|
+
if schema_object = @schema_objects[method]
|
118
|
+
if schema_object.is_a?(Procedure)
|
119
|
+
schema_object.exec(*args, &block)
|
120
|
+
else
|
121
|
+
schema_object
|
122
|
+
end
|
123
|
+
# search in database
|
115
124
|
elsif procedure = Procedure.find(self, method)
|
116
|
-
@
|
117
|
-
procedure.exec(*args)
|
118
|
-
elsif package = @packages[method]
|
119
|
-
package
|
125
|
+
@schema_objects[method] = procedure
|
126
|
+
procedure.exec(*args, &block)
|
120
127
|
elsif package = Package.find(self, method)
|
121
|
-
@
|
122
|
-
elsif
|
123
|
-
|
128
|
+
@schema_objects[method] = package
|
129
|
+
elsif table = Table.find(self, method)
|
130
|
+
@schema_objects[method] = table
|
131
|
+
elsif sequence = Sequence.find(self, method)
|
132
|
+
@schema_objects[method] = sequence
|
124
133
|
elsif schema = find_other_schema(method)
|
125
|
-
@
|
134
|
+
@schema_objects[method] = schema
|
126
135
|
else
|
127
136
|
raise ArgumentError, "No PL/SQL procedure found"
|
128
137
|
end
|
@@ -141,6 +150,15 @@ module PLSQL
|
|
141
150
|
end
|
142
151
|
|
143
152
|
module Kernel
|
153
|
+
# Returns current schema object. You can now chain either database object (packages, procedures, tables, sequences)
|
154
|
+
# in current schema or specify different schema name. Examples:
|
155
|
+
#
|
156
|
+
# plsql.test_function('some parameter')
|
157
|
+
# plsql.test_package.test_function('some parameter')
|
158
|
+
# plsql.other_schema.test_package.test_function('some parameter')
|
159
|
+
# plsql.table_name.all
|
160
|
+
# plsql.other_schema.table_name.all
|
161
|
+
#
|
144
162
|
def plsql(connection_alias = nil)
|
145
163
|
PLSQL::Schema.find_or_new(connection_alias)
|
146
164
|
end
|