ruby-plsql 0.5.3 → 0.8.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.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.github/stale.yml +37 -0
  3. data/.github/workflows/rubocop.yml +37 -0
  4. data/.github/workflows/test.yml +69 -0
  5. data/.rubocop.yml +147 -0
  6. data/.travis.yml +88 -0
  7. data/.travis/oracle/download.sh +15 -0
  8. data/.travis/oracle/install.sh +32 -0
  9. data/.travis/setup_accounts.sh +9 -0
  10. data/Gemfile +17 -9
  11. data/History.txt +76 -0
  12. data/README.md +29 -6
  13. data/Rakefile +31 -26
  14. data/VERSION +1 -1
  15. data/Vagrantfile +4 -4
  16. data/ci/network/admin/tnsnames.ora +7 -0
  17. data/ci/setup_accounts.sh +9 -0
  18. data/gemfiles/Gemfile.activerecord-5.0 +21 -0
  19. data/gemfiles/Gemfile.activerecord-5.1 +21 -0
  20. data/gemfiles/Gemfile.activerecord-5.2 +21 -0
  21. data/gemfiles/Gemfile.activerecord-6.0 +21 -0
  22. data/gemfiles/Gemfile.activerecord-6.1 +21 -0
  23. data/gemfiles/Gemfile.activerecord-main +21 -0
  24. data/lib/plsql/connection.rb +19 -22
  25. data/lib/plsql/helpers.rb +1 -3
  26. data/lib/plsql/jdbc_connection.rb +70 -68
  27. data/lib/plsql/oci8_patches.rb +2 -2
  28. data/lib/plsql/oci_connection.rb +62 -77
  29. data/lib/plsql/package.rb +61 -46
  30. data/lib/plsql/procedure.rb +358 -78
  31. data/lib/plsql/procedure_call.rb +508 -463
  32. data/lib/plsql/schema.rb +96 -101
  33. data/lib/plsql/sequence.rb +10 -13
  34. data/lib/plsql/sql_statements.rb +9 -11
  35. data/lib/plsql/table.rb +60 -63
  36. data/lib/plsql/type.rb +71 -76
  37. data/lib/plsql/variable.rb +90 -94
  38. data/lib/plsql/version.rb +1 -1
  39. data/lib/plsql/view.rb +16 -19
  40. data/ruby-plsql.gemspec +55 -35
  41. data/spec/plsql/connection_spec.rb +72 -66
  42. data/spec/plsql/package_spec.rb +63 -14
  43. data/spec/plsql/procedure_spec.rb +603 -261
  44. data/spec/plsql/schema_spec.rb +47 -23
  45. data/spec/plsql/sequence_spec.rb +2 -2
  46. data/spec/plsql/sql_statements_spec.rb +6 -6
  47. data/spec/plsql/table_spec.rb +84 -79
  48. data/spec/plsql/type_spec.rb +24 -30
  49. data/spec/plsql/variable_spec.rb +80 -88
  50. data/spec/plsql/version_spec.rb +4 -4
  51. data/spec/plsql/view_spec.rb +42 -42
  52. data/spec/spec_helper.rb +38 -35
  53. data/spec/support/create_arunit_user.sql +2 -0
  54. data/spec/support/custom_config.rb.sample +14 -0
  55. data/spec/support/test_db.rb +12 -13
  56. data/spec/support/unlock_and_setup_hr_user.sql +2 -0
  57. metadata +111 -34
@@ -1,12 +1,16 @@
1
1
  module PLSQL
2
2
  class ProcedureCall #:nodoc:
3
-
4
3
  def initialize(procedure, args = [], options = {})
5
4
  @procedure = procedure
6
5
  @schema = @procedure.schema
7
6
  @dbms_output_stream = @schema.dbms_output_stream
8
7
  @skip_self = options[:skip_self]
9
8
  @self = options[:self]
9
+
10
+ if args.size == 1 && args[0].is_a?(Hash) && args[0].keys.all? { |k| k.is_a?(Symbol) }
11
+ args[0] = args[0].map { |k, v| [k.downcase, v] }.to_h
12
+ end
13
+
10
14
  @overload = get_overload_from_arguments_list(args)
11
15
  @procedure.ensure_tmp_tables_created(@overload) if @procedure.respond_to?(:ensure_tmp_tables_created)
12
16
  construct_sql(args)
@@ -39,543 +43,584 @@ module PLSQL
39
43
 
40
44
  private
41
45
 
42
- def get_overload_from_arguments_list(args)
43
- # if not overloaded then overload index 0 is used
44
- return 0 unless @procedure.overloaded?
45
- # If named arguments are used then
46
- # there should be just one Hash argument with symbol keys
47
- if args.size == 1 && args[0].is_a?(Hash) && args[0].keys.all?{|k| k.is_a?(Symbol)}
48
- args_keys = args[0].keys
49
- # implicit SELF argument for object instance procedures
50
- args_keys << :self if @self && !args_keys.include?(:self)
51
- number_of_args = args_keys.size
52
- matching_overloads = [] # overloads with exact or smaller number of matching named arguments
53
- overload_argument_list.keys.each do |ov|
54
- # assume that missing arguments have default value
55
- missing_arguments_count = overload_argument_list[ov].size - number_of_args
56
- if missing_arguments_count >= 0 &&
57
- args_keys.all?{|k| overload_argument_list[ov].include?(k)}
58
- matching_overloads << [ov, missing_arguments_count]
46
+ def get_overload_from_arguments_list(args)
47
+ # if not overloaded then overload index 0 is used
48
+ return 0 unless @procedure.overloaded?
49
+ # If named arguments are used then
50
+ # there should be just one Hash argument with symbol keys
51
+ if args.size == 1 && args[0].is_a?(Hash) && args[0].keys.all? { |k| k.is_a?(Symbol) }
52
+ args_keys = args[0].keys
53
+ # implicit SELF argument for object instance procedures
54
+ args_keys << :self if @self && !args_keys.include?(:self)
55
+ number_of_args = args_keys.size
56
+ matching_overloads = [] # overloads with exact or smaller number of matching named arguments
57
+ overload_argument_list.keys.each do |ov|
58
+ # assume that missing arguments have default value
59
+ missing_arguments_count = overload_argument_list[ov].size - number_of_args
60
+ if missing_arguments_count >= 0 &&
61
+ args_keys.all? { |k| overload_argument_list[ov].include?(k) }
62
+ matching_overloads << [ov, missing_arguments_count]
63
+ end
59
64
  end
60
- end
61
- # pick first matching overload with smallest missing arguments count
62
- # (hoping that missing arguments will be defaulted - cannot find default value from all_arguments)
63
- overload = matching_overloads.sort_by{|ov, score| score}[0][0]
64
- # otherwise try matching by sequential arguments count and types
65
- else
66
- number_of_args = args.size
67
- matching_types = []
68
- # if implicit SELF argument for object instance procedures should be passed
69
- # then it should be added as first argument to find matches
70
- if @self
71
- number_of_args += 1
72
- matching_types << ['OBJECT']
73
- end
74
- args.each do |arg|
75
- matching_types << matching_oracle_types_for_ruby_value(arg)
76
- end
77
- exact_overloads = [] # overloads with exact number of matching arguments
78
- smaller_overloads = [] # overloads with smaller number of matching arguments
79
- # overload = overload_argument_list.keys.detect do |ov|
80
- # overload_argument_list[ov].size == number_of_args
81
- # end
82
- overload_argument_list.keys.each do |ov|
83
- score = 0 # lower score is better match
84
- ov_arg_list_size = overload_argument_list[ov].size
85
- if (number_of_args <= ov_arg_list_size &&
86
- (0..(number_of_args-1)).all? do |i|
87
- ov_arg = overload_argument_list[ov][i]
88
- matching_types[i] == :all || # either value matches any type
89
- (ind = matching_types[i].index(overload_arguments[ov][ov_arg][:data_type])) &&
90
- (score += ind) # or add index of matched type
91
- end)
92
- if number_of_args == ov_arg_list_size
93
- exact_overloads << [ov, score]
94
- else
95
- smaller_overloads << [ov, score]
65
+ # pick first matching overload with smallest missing arguments count
66
+ # (hoping that missing arguments will be defaulted - cannot find default value from all_arguments)
67
+ overload = matching_overloads.sort_by { |ov, score| score }[0][0]
68
+ # otherwise try matching by sequential arguments count and types
69
+ else
70
+ number_of_args = args.size
71
+ matching_types = []
72
+ # if implicit SELF argument for object instance procedures should be passed
73
+ # then it should be added as first argument to find matches
74
+ if @self
75
+ number_of_args += 1
76
+ matching_types << ["OBJECT"]
77
+ end
78
+ args.each do |arg|
79
+ matching_types << matching_oracle_types_for_ruby_value(arg)
80
+ end
81
+ exact_overloads = [] # overloads with exact number of matching arguments
82
+ smaller_overloads = [] # overloads with smaller number of matching arguments
83
+ # overload = overload_argument_list.keys.detect do |ov|
84
+ # overload_argument_list[ov].size == number_of_args
85
+ # end
86
+ overload_argument_list.keys.each do |ov|
87
+ score = 0 # lower score is better match
88
+ ov_arg_list_size = overload_argument_list[ov].size
89
+ if (number_of_args <= ov_arg_list_size &&
90
+ (0..(number_of_args - 1)).all? do |i|
91
+ ov_arg = overload_argument_list[ov][i]
92
+ matching_types[i] == :all || # either value matches any type
93
+ (ind = matching_types[i].index(overload_arguments[ov][ov_arg][:data_type])) &&
94
+ (score += ind) # or add index of matched type
95
+ end)
96
+ if number_of_args == ov_arg_list_size
97
+ exact_overloads << [ov, score]
98
+ else
99
+ smaller_overloads << [ov, score]
100
+ end
96
101
  end
97
102
  end
103
+ # pick either first exact matching overload of first matching with smaller argument count
104
+ # (hoping that missing arguments will be defaulted - cannot find default value from all_arguments)
105
+ overload = if !exact_overloads.empty?
106
+ exact_overloads.sort_by { |ov, score| score }[0][0]
107
+ elsif !smaller_overloads.empty?
108
+ smaller_overloads.sort_by { |ov, score| score }[0][0]
109
+ end
98
110
  end
99
- # pick either first exact matching overload of first matching with smaller argument count
100
- # (hoping that missing arguments will be defaulted - cannot find default value from all_arguments)
101
- overload = if !exact_overloads.empty?
102
- exact_overloads.sort_by{|ov, score| score}[0][0]
103
- elsif !smaller_overloads.empty?
104
- smaller_overloads.sort_by{|ov, score| score}[0][0]
105
- end
111
+ raise ArgumentError, "Wrong number or types of arguments passed to overloaded PL/SQL procedure" unless overload
112
+ overload
106
113
  end
107
- raise ArgumentError, "Wrong number or types of arguments passed to overloaded PL/SQL procedure" unless overload
108
- overload
109
- end
110
114
 
111
- MATCHING_TYPES = {
112
- :integer => ['NUMBER', 'PLS_INTEGER', 'BINARY_INTEGER'],
113
- :decimal => ['NUMBER', 'BINARY_FLOAT', 'BINARY_DOUBLE'],
114
- :string => ['VARCHAR2', 'NVARCHAR2', 'CHAR', 'NCHAR', 'CLOB', 'BLOB'],
115
- :date => ['DATE'],
116
- :time => ['DATE', 'TIMESTAMP', 'TIMESTAMP WITH TIME ZONE', 'TIMESTAMP WITH LOCAL TIME ZONE'],
117
- :boolean => ['PL/SQL BOOLEAN'],
118
- :hash => ['PL/SQL RECORD', 'OBJECT', 'PL/SQL TABLE'],
119
- :array => ['TABLE', 'VARRAY'],
120
- :cursor => ['REF CURSOR']
121
- }
122
- def matching_oracle_types_for_ruby_value(value)
123
- case value
124
- when NilClass
125
- :all
126
- when Fixnum, Bignum
127
- MATCHING_TYPES[:integer]
128
- when BigDecimal, Float
129
- MATCHING_TYPES[:decimal]
130
- when String
131
- MATCHING_TYPES[:string]
132
- when Date
133
- MATCHING_TYPES[:date]
134
- when Time
135
- MATCHING_TYPES[:time]
136
- when TrueClass, FalseClass
137
- MATCHING_TYPES[:boolean]
138
- when Hash
139
- MATCHING_TYPES[:hash]
140
- when Array
141
- MATCHING_TYPES[:array]
142
- when CursorCommon
143
- MATCHING_TYPES[:cursor]
115
+ MATCHING_TYPES = {
116
+ integer: ["NUMBER", "NATURAL", "NATURALN", "POSITIVE", "POSITIVEN", "SIGNTYPE", "SIMPLE_INTEGER", "PLS_INTEGER", "BINARY_INTEGER"],
117
+ decimal: ["NUMBER", "BINARY_FLOAT", "BINARY_DOUBLE"],
118
+ string: ["VARCHAR", "VARCHAR2", "NVARCHAR2", "CHAR", "NCHAR", "CLOB", "BLOB", "XMLTYPE"],
119
+ date: ["DATE"],
120
+ time: ["DATE", "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE"],
121
+ boolean: ["PL/SQL BOOLEAN"],
122
+ hash: ["PL/SQL RECORD", "OBJECT", "PL/SQL TABLE"],
123
+ array: ["TABLE", "VARRAY"],
124
+ cursor: ["REF CURSOR"]
125
+ }
126
+ def matching_oracle_types_for_ruby_value(value)
127
+ case value
128
+ when NilClass
129
+ :all
130
+ when Integer
131
+ MATCHING_TYPES[:integer]
132
+ when BigDecimal, Float
133
+ MATCHING_TYPES[:decimal]
134
+ when String
135
+ MATCHING_TYPES[:string]
136
+ when Date
137
+ MATCHING_TYPES[:date]
138
+ when Time
139
+ MATCHING_TYPES[:time]
140
+ when TrueClass, FalseClass
141
+ MATCHING_TYPES[:boolean]
142
+ when Hash
143
+ MATCHING_TYPES[:hash]
144
+ when Array
145
+ MATCHING_TYPES[:array]
146
+ when CursorCommon
147
+ MATCHING_TYPES[:cursor]
148
+ end
144
149
  end
145
- end
146
150
 
147
- def construct_sql(args)
148
- @declare_sql = ""
149
- @assignment_sql = ""
150
- @call_sql = ""
151
- @return_sql = ""
152
- @return_vars = []
153
- @return_vars_metadata = {}
154
-
155
- @call_sql << add_return if return_metadata
156
- # construct procedure call if procedure name is available
157
- # otherwise will get surrounding call_sql from @procedure (used for table statements)
158
- if procedure_name
159
- @call_sql << "#{schema_name}." if schema_name
160
- @call_sql << "#{package_name}." if package_name
161
- @call_sql << "#{procedure_name}("
162
- end
163
-
164
- @bind_values = {}
165
- @bind_metadata = {}
166
-
167
- # Named arguments
168
- # there should be just one Hash argument with symbol keys
169
- if args.size == 1 && args[0].is_a?(Hash) && args[0].keys.all?{|k| k.is_a?(Symbol)} &&
170
- # do not use named arguments if procedure has just one PL/SQL record PL/SQL table or object type argument -
171
- # in that case passed Hash should be used as value for this PL/SQL record argument
172
- # (which will be processed in sequential arguments bracnh)
173
- !(argument_list.size == 1 &&
174
- ['PL/SQL RECORD','PL/SQL TABLE','OBJECT'].include?(arguments[(only_argument=argument_list[0])][:data_type]) &&
175
- args[0].keys != [only_argument])
176
- # Add missing output arguments with nil value
177
- arguments.each do |arg, metadata|
178
- if !args[0].has_key?(arg) && metadata[:in_out] == 'OUT'
179
- args[0][arg] = nil
151
+ def construct_sql(args)
152
+ @declare_sql = ""
153
+ @assignment_sql = ""
154
+ @call_sql = ""
155
+ @return_sql = ""
156
+ @return_vars = []
157
+ @return_vars_metadata = {}
158
+
159
+ @call_sql << add_return if return_metadata
160
+ # construct procedure call if procedure name is available
161
+ # otherwise will get surrounding call_sql from @procedure (used for table statements)
162
+ if procedure_name
163
+ @call_sql << "#{schema_name}." if schema_name
164
+ @call_sql << "#{package_name}." if package_name
165
+ @call_sql << "#{procedure_name}("
166
+ end
167
+
168
+ @bind_values = {}
169
+ @bind_metadata = {}
170
+
171
+ # Named arguments
172
+ # there should be just one Hash argument with symbol keys
173
+ if args.size == 1 && args[0].is_a?(Hash) && args[0].keys.all? { |k| k.is_a?(Symbol) } &&
174
+ # do not use named arguments if procedure has just one PL/SQL record PL/SQL table or object type argument -
175
+ # in that case passed Hash should be used as value for this PL/SQL record argument
176
+ # (which will be processed in sequential arguments bracnh)
177
+ !(argument_list.size == 1 &&
178
+ ["PL/SQL RECORD", "PL/SQL TABLE", "OBJECT"].include?(arguments[(only_argument = argument_list[0])][:data_type]) &&
179
+ args[0].keys != [only_argument])
180
+ # Add missing output arguments with nil value
181
+ arguments.each do |arg, metadata|
182
+ if !args[0].has_key?(arg) && metadata[:in_out] == "OUT"
183
+ args[0][arg] = nil
184
+ end
180
185
  end
186
+ # Add SELF argument if provided
187
+ args[0][:self] = @self if @self
188
+ # Add passed parameters to procedure call with parameter names
189
+ @call_sql << args[0].map do |arg, value|
190
+ "#{arg} => " << add_argument(arg, value)
191
+ end.join(", ")
192
+
193
+ # Sequential arguments
194
+ else
195
+ # add SELF as first argument if provided
196
+ args.unshift(@self) if @self
197
+ argument_count = argument_list.size
198
+ raise ArgumentError, "Too many arguments passed to PL/SQL procedure" if args.size > argument_count
199
+ # Add missing output arguments with nil value
200
+ if args.size < argument_count &&
201
+ (args.size...argument_count).all? { |i| arguments[argument_list[i]][:in_out] == "OUT" }
202
+ args += [nil] * (argument_count - args.size)
203
+ end
204
+ # Add passed parameters to procedure call in sequence
205
+ @call_sql << (0...args.size).map do |i|
206
+ arg = argument_list[i]
207
+ value = args[i]
208
+ add_argument(arg, value)
209
+ end.join(", ")
181
210
  end
182
- # Add SELF argument if provided
183
- args[0][:self] = @self if @self
184
- # Add passed parameters to procedure call with parameter names
185
- @call_sql << args[0].map do |arg, value|
186
- "#{arg} => " << add_argument(arg, value)
187
- end.join(', ')
188
-
189
- # Sequential arguments
190
- else
191
- # add SELF as first argument if provided
192
- args.unshift(@self) if @self
193
- argument_count = argument_list.size
194
- raise ArgumentError, "Too many arguments passed to PL/SQL procedure" if args.size > argument_count
195
- # Add missing output arguments with nil value
196
- if args.size < argument_count &&
197
- (args.size...argument_count).all?{|i| arguments[argument_list[i]][:in_out] == 'OUT'}
198
- args += [nil] * (argument_count - args.size)
211
+
212
+ # finish procedure call construction if procedure name is available
213
+ # otherwise will get surrounding call_sql from @procedure (used for table statements)
214
+ if procedure_name
215
+ @call_sql << ");\n"
216
+ else
217
+ @call_sql = @procedure.call_sql(@call_sql)
199
218
  end
200
- # Add passed parameters to procedure call in sequence
201
- @call_sql << (0...args.size).map do |i|
202
- arg = argument_list[i]
203
- value = args[i]
204
- add_argument(arg, value)
205
- end.join(', ')
206
- end
207
-
208
- # finish procedure call construction if procedure name is available
209
- # otherwise will get surrounding call_sql from @procedure (used for table statements)
210
- if procedure_name
211
- @call_sql << ");\n"
212
- else
213
- @call_sql = @procedure.call_sql(@call_sql)
214
- end
215
- add_out_variables
219
+ add_out_variables
216
220
 
217
- @sql = @declare_sql.empty? ? "" : "DECLARE\n" << @declare_sql
218
- @sql << "BEGIN\n" << @assignment_sql << dbms_output_enable_sql << @call_sql << @return_sql << "END;\n"
219
- end
221
+ @sql = @declare_sql.empty? ? "" : "DECLARE\n" << @declare_sql
222
+ @sql << "BEGIN\n" << @assignment_sql << dbms_output_enable_sql << @call_sql << @return_sql << "END;\n"
223
+ end
220
224
 
221
- def add_argument(argument, value, argument_metadata=nil)
222
- argument_metadata ||= arguments[argument]
223
- raise ArgumentError, "Wrong argument #{argument.inspect} passed to PL/SQL procedure" unless argument_metadata
224
- case argument_metadata[:data_type]
225
- when 'PL/SQL RECORD'
226
- add_record_declaration(argument, argument_metadata)
227
- record_assignment_sql, record_bind_values, record_bind_metadata =
228
- record_assignment_sql_values_metadata(argument, argument_metadata, value)
229
- @assignment_sql << record_assignment_sql
230
- @bind_values.merge!(record_bind_values)
231
- @bind_metadata.merge!(record_bind_metadata)
232
- "l_#{argument}"
233
- when 'PL/SQL BOOLEAN'
234
- @declare_sql << "l_#{argument} BOOLEAN;\n"
235
- @assignment_sql << "l_#{argument} := (:#{argument} = 1);\n"
236
- @bind_values[argument] = value.nil? ? nil : (value ? 1 : 0)
237
- @bind_metadata[argument] = argument_metadata.merge(:data_type => "NUMBER", :data_precision => 1)
238
- "l_#{argument}"
239
- else
240
- # TABLE or PL/SQL TABLE type defined inside package
241
- if argument_metadata[:tmp_table_name]
242
- add_table_declaration_and_assignment(argument, argument_metadata)
243
- insert_values_into_tmp_table(argument, argument_metadata, value)
225
+ def add_argument(argument, value, argument_metadata = nil)
226
+ argument_metadata ||= arguments[argument]
227
+ raise ArgumentError, "Wrong argument #{argument.inspect} passed to PL/SQL procedure" unless argument_metadata
228
+ case argument_metadata[:data_type]
229
+ when "PL/SQL RECORD"
230
+ add_record_declaration(argument, argument_metadata)
231
+ record_assignment_sql, record_bind_values, record_bind_metadata =
232
+ record_assignment_sql_values_metadata(argument, argument_metadata, value)
233
+ @assignment_sql << record_assignment_sql
234
+ @bind_values.merge!(record_bind_values)
235
+ @bind_metadata.merge!(record_bind_metadata)
236
+ "l_#{argument}"
237
+ when "PL/SQL BOOLEAN"
238
+ @declare_sql << "l_#{argument} BOOLEAN;\n"
239
+ @assignment_sql << "l_#{argument} := (:#{argument} = 1);\n"
240
+ @bind_values[argument] = value.nil? ? nil : (value ? 1 : 0)
241
+ @bind_metadata[argument] = argument_metadata.merge(data_type: "NUMBER", data_precision: 1)
244
242
  "l_#{argument}"
243
+ when "UNDEFINED"
244
+ if argument_metadata[:type_name] == "XMLTYPE"
245
+ @declare_sql << "l_#{argument} XMLTYPE;\n"
246
+ @assignment_sql << "l_#{argument} := XMLTYPE(:#{argument});\n" if not value.nil?
247
+ @bind_values[argument] = value if not value.nil?
248
+ @bind_metadata[argument] = argument_metadata.merge(data_type: "CLOB")
249
+ "l_#{argument}"
250
+ end
245
251
  else
246
- @bind_values[argument] = value
247
- @bind_metadata[argument] = argument_metadata
248
- ":#{argument}"
252
+ # TABLE or PL/SQL TABLE type defined inside package
253
+ if argument_metadata[:tmp_table_name]
254
+ add_table_declaration_and_assignment(argument, argument_metadata)
255
+ insert_values_into_tmp_table(argument, argument_metadata, value)
256
+ "l_#{argument}"
257
+ else
258
+ @bind_values[argument] = value
259
+ @bind_metadata[argument] = argument_metadata
260
+ ":#{argument}"
261
+ end
249
262
  end
250
263
  end
251
- end
252
264
 
253
- def add_table_declaration_and_assignment(argument, argument_metadata)
254
- is_index_by_table = argument_metadata[:data_type] == 'PL/SQL TABLE'
255
- @declare_sql << "l_#{argument} #{argument_metadata[:sql_type_name]}#{is_index_by_table ? nil : " := #{argument_metadata[:sql_type_name]}()"};\n"
256
- @assignment_sql << "FOR r_#{argument} IN c_#{argument} LOOP\n"
257
- @assignment_sql << "l_#{argument}.EXTEND;\n" unless is_index_by_table
258
- case argument_metadata[:element][:data_type]
259
- when 'PL/SQL RECORD'
260
- fields = record_fields_sorted_by_position(argument_metadata[:element][:fields])
261
- fields_string = is_index_by_table ? "*" : fields.join(', ')
262
- @declare_sql << "CURSOR c_#{argument} IS SELECT #{fields_string} FROM #{argument_metadata[:tmp_table_name]} ORDER BY i__;\n"
263
- if is_index_by_table
264
- fields.each do |field|
265
- @assignment_sql << "l_#{argument}(r_#{argument}.i__).#{field} := r_#{argument}.#{field};\n"
265
+ def add_table_declaration_and_assignment(argument, argument_metadata)
266
+ is_index_by_table = argument_metadata[:data_type] == "PL/SQL TABLE"
267
+ @declare_sql << "l_#{argument} #{argument_metadata[:sql_type_name]}#{is_index_by_table ? nil : " := #{argument_metadata[:sql_type_name]}()"};\n"
268
+ @assignment_sql << "FOR r_#{argument} IN c_#{argument} LOOP\n"
269
+ @assignment_sql << "l_#{argument}.EXTEND;\n" unless is_index_by_table
270
+ case argument_metadata[:element][:data_type]
271
+ when "PL/SQL RECORD"
272
+ fields = record_fields_sorted_by_position(argument_metadata[:element][:fields])
273
+ fields_string = is_index_by_table ? "*" : fields.join(", ")
274
+ @declare_sql << "CURSOR c_#{argument} IS SELECT #{fields_string} FROM #{argument_metadata[:tmp_table_name]} ORDER BY i__;\n"
275
+ if is_index_by_table
276
+ fields.each do |field|
277
+ @assignment_sql << "l_#{argument}(r_#{argument}.i__).#{field} := r_#{argument}.#{field};\n"
278
+ end
279
+ else
280
+ @assignment_sql << "l_#{argument}(l_#{argument}.COUNT) := r_#{argument};\n"
266
281
  end
267
282
  else
268
- @assignment_sql << "l_#{argument}(l_#{argument}.COUNT) := r_#{argument};\n"
283
+ @declare_sql << "CURSOR c_#{argument} IS SELECT * FROM #{argument_metadata[:tmp_table_name]} ORDER BY i__;\n"
284
+ @assignment_sql << "l_#{argument}(r_#{argument}.i__) := r_#{argument}.element;\n"
269
285
  end
270
- else
271
- @declare_sql << "CURSOR c_#{argument} IS SELECT * FROM #{argument_metadata[:tmp_table_name]} ORDER BY i__;\n"
272
- @assignment_sql << "l_#{argument}(r_#{argument}.i__) := r_#{argument}.element;\n"
286
+ @assignment_sql << "END LOOP;\n"
287
+ @assignment_sql << "DELETE FROM #{argument_metadata[:tmp_table_name]};\n"
273
288
  end
274
- @assignment_sql << "END LOOP;\n"
275
- @assignment_sql << "DELETE FROM #{argument_metadata[:tmp_table_name]};\n"
276
- end
277
289
 
278
- def insert_values_into_tmp_table(argument, argument_metadata, values)
279
- return unless values && !values.empty?
280
- is_index_by_table = argument_metadata[:data_type] == 'PL/SQL TABLE'
281
- if is_index_by_table
282
- raise ArgumentError, "Hash value should be passed for #{argument.inspect} argument" unless values.is_a?(Hash)
283
- else
284
- raise ArgumentError, "Array value should be passed for #{argument.inspect} argument" unless values.is_a?(Array)
285
- end
286
- tmp_table = @schema.root_schema.send(argument_metadata[:tmp_table_name])
287
- # insert values without autocommit
288
- old_autocommit = @schema.connection.autocommit?
289
- @schema.connection.autocommit = false if old_autocommit
290
- tmp_table.delete
291
- case argument_metadata[:element][:data_type]
292
- when 'PL/SQL RECORD'
293
- values_with_index = []
290
+ def insert_values_into_tmp_table(argument, argument_metadata, values)
291
+ return unless values && !values.empty?
292
+ is_index_by_table = argument_metadata[:data_type] == "PL/SQL TABLE"
294
293
  if is_index_by_table
295
- values.each{|i,v| values_with_index << v.merge(:i__ => i)}
294
+ raise ArgumentError, "Hash value should be passed for #{argument.inspect} argument" unless values.is_a?(Hash)
296
295
  else
297
- values.each_with_index{|v,i| values_with_index << v.merge(:i__ => i+1)}
296
+ raise ArgumentError, "Array value should be passed for #{argument.inspect} argument" unless values.is_a?(Array)
298
297
  end
299
- tmp_table.insert values_with_index
300
- else
301
- values_with_index = []
302
- if is_index_by_table
303
- values.each{|i,v| values_with_index << [v, i]}
298
+ tmp_table = @schema.root_schema.send(argument_metadata[:tmp_table_name])
299
+ # insert values without autocommit
300
+ old_autocommit = @schema.connection.autocommit?
301
+ @schema.connection.autocommit = false if old_autocommit
302
+ tmp_table.delete
303
+ case argument_metadata[:element][:data_type]
304
+ when "PL/SQL RECORD"
305
+ values_with_index = []
306
+ if is_index_by_table
307
+ values.each { |i, v| values_with_index << v.merge(i__: i) }
308
+ else
309
+ values.each_with_index { |v, i| values_with_index << v.merge(i__: i + 1) }
310
+ end
311
+ tmp_table.insert values_with_index
304
312
  else
305
- values.each_with_index{|v,i| values_with_index << [v, i+1]}
313
+ values_with_index = []
314
+ if is_index_by_table
315
+ values.each { |i, v| values_with_index << [v, i] }
316
+ else
317
+ values.each_with_index { |v, i| values_with_index << [v, i + 1] }
318
+ end
319
+ tmp_table.insert_values [:element, :i__], *values_with_index
306
320
  end
307
- tmp_table.insert_values [:element, :i__], *values_with_index
321
+ @schema.connection.autocommit = true if old_autocommit
308
322
  end
309
- @schema.connection.autocommit = true if old_autocommit
310
- end
311
323
 
312
- def add_record_declaration(argument, argument_metadata)
313
- @declare_sql << if argument_metadata[:type_subname]
314
- "l_#{argument} #{argument_metadata[:sql_type_name]};\n"
315
- else
316
- fields_metadata = argument_metadata[:fields]
317
- sql = "TYPE t_#{argument} IS RECORD (\n"
318
- sql << record_fields_sorted_by_position(fields_metadata).map do |field|
319
- metadata = fields_metadata[field]
320
- "#{field} #{type_to_sql(metadata)}"
321
- end.join(",\n")
322
- sql << ");\n"
323
- sql << "l_#{argument} t_#{argument};\n"
324
+ def add_record_declaration(argument, argument_metadata)
325
+ @declare_sql << if argument_metadata[:type_subname]
326
+ "l_#{argument} #{argument_metadata[:sql_type_name]};\n"
327
+ else
328
+ fields_metadata = argument_metadata[:fields]
329
+ sql = "TYPE t_#{argument} IS RECORD (\n"
330
+ sql << record_fields_sorted_by_position(fields_metadata).map do |field|
331
+ metadata = fields_metadata[field]
332
+ "#{field} #{type_to_sql(metadata)}"
333
+ end.join(",\n")
334
+ sql << ");\n"
335
+ sql << "l_#{argument} t_#{argument};\n"
336
+ end
324
337
  end
325
- end
326
338
 
327
- def record_fields_sorted_by_position(fields_metadata)
328
- fields_metadata.keys.sort_by{|k| fields_metadata[k][:position]}
329
- end
339
+ def record_fields_sorted_by_position(fields_metadata)
340
+ fields_metadata.keys.sort_by { |k| fields_metadata[k][:position] }
341
+ end
330
342
 
331
- def record_assignment_sql_values_metadata(argument, argument_metadata, record_value)
332
- sql = ""
333
- bind_values = {}
334
- bind_metadata = {}
335
- (record_value||{}).each do |key, value|
336
- field = key.is_a?(Symbol) ? key : key.to_s.downcase.to_sym
337
- metadata = argument_metadata[:fields][field]
338
- raise ArgumentError, "Wrong field name #{key.inspect} passed to PL/SQL record argument #{argument.inspect}" unless metadata
339
- bind_variable = :"#{argument}_f#{metadata[:position]}"
340
- sql << "l_#{argument}.#{field} := :#{bind_variable};\n"
341
- bind_values[bind_variable] = value
342
- bind_metadata[bind_variable] = metadata
343
- end
344
- [sql, bind_values, bind_metadata]
345
- end
343
+ def record_assignment_sql_values_metadata(argument, argument_metadata, record_value)
344
+ sql = ""
345
+ bind_values = {}
346
+ bind_metadata = {}
347
+ (record_value || {}).each do |key, value|
348
+ field = key.is_a?(Symbol) ? key : key.to_s.downcase.to_sym
349
+ metadata = argument_metadata[:fields][field]
350
+ raise ArgumentError, "Wrong field name #{key.inspect} passed to PL/SQL record argument #{argument.inspect}" unless metadata
351
+ bind_variable = :"#{argument}_f#{metadata[:position]}"
352
+ case metadata[:data_type]
353
+ when "PL/SQL BOOLEAN"
354
+ sql << "l_#{argument}.#{field} := (:#{bind_variable} = 1);\n"
355
+ bind_values[bind_variable] = value.nil? ? nil : (value ? 1 : 0)
356
+ bind_metadata[bind_variable] = metadata.merge(data_type: "NUMBER", data_precision: 1)
357
+ else
358
+ sql << "l_#{argument}.#{field} := :#{bind_variable};\n"
359
+ bind_values[bind_variable] = value
360
+ bind_metadata[bind_variable] = metadata
361
+ end
362
+ end
363
+ [sql, bind_values, bind_metadata]
364
+ end
346
365
 
347
- def add_return
348
- add_return_variable(:return, return_metadata, true)
349
- end
366
+ def add_return
367
+ add_return_variable(:return, return_metadata, true)
368
+ end
350
369
 
351
- def add_out_variables
352
- out_list.each do |argument|
353
- add_return_variable(argument, arguments[argument])
370
+ def add_out_variables
371
+ out_list.each do |argument|
372
+ add_return_variable(argument, arguments[argument])
373
+ end
354
374
  end
355
- end
356
375
 
357
- def add_return_variable(argument, argument_metadata, is_return_value=false)
358
- case argument_metadata[:data_type]
359
- when 'PL/SQL RECORD'
360
- add_record_declaration(argument, argument_metadata) if is_return_value
361
- argument_metadata[:fields].each do |field, metadata|
376
+ def add_return_variable(argument, argument_metadata, is_return_value = false)
377
+ case argument_metadata[:data_type]
378
+ when "PL/SQL RECORD"
379
+ add_record_declaration(argument, argument_metadata) if is_return_value
380
+ argument_metadata[:fields].each do |field, metadata|
381
+ # should use different output bind variable as JDBC does not support
382
+ # if output bind variable appears in several places
383
+ bind_variable = :"#{argument}_o#{metadata[:position]}"
384
+ case metadata[:data_type]
385
+ when "PL/SQL BOOLEAN"
386
+ @return_vars << bind_variable
387
+ @return_vars_metadata[bind_variable] = metadata.merge(data_type: "NUMBER", data_precision: 1)
388
+ arg_field = "l_#{argument}.#{field}"
389
+ @return_sql << ":#{bind_variable} := " << "CASE WHEN #{arg_field} = true THEN 1 " <<
390
+ "WHEN #{arg_field} = false THEN 0 ELSE NULL END;\n"
391
+ else
392
+ @return_vars << bind_variable
393
+ @return_vars_metadata[bind_variable] = metadata
394
+ @return_sql << ":#{bind_variable} := l_#{argument}.#{field};\n"
395
+ end
396
+ end
397
+ "l_#{argument} := " if is_return_value
398
+ when "UNDEFINED"
399
+ if argument_metadata[:type_name] == "XMLTYPE"
400
+ @declare_sql << "l_#{argument} XMLTYPE;\n" if is_return_value
401
+ bind_variable = :"o_#{argument}"
402
+ @return_vars << bind_variable
403
+ @return_vars_metadata[bind_variable] = argument_metadata.merge(data_type: "CLOB")
404
+ @return_sql << ":#{bind_variable} := CASE WHEN l_#{argument} IS NOT NULL THEN l_#{argument}.getclobval() END;\n"
405
+ "l_#{argument} := " if is_return_value
406
+ end
407
+ when "PL/SQL BOOLEAN"
408
+ @declare_sql << "l_#{argument} BOOLEAN;\n" if is_return_value
409
+ @declare_sql << "o_#{argument} NUMBER(1);\n"
362
410
  # should use different output bind variable as JDBC does not support
363
411
  # if output bind variable appears in several places
364
- bind_variable = :"#{argument}_o#{metadata[:position]}"
412
+ bind_variable = :"o_#{argument}"
365
413
  @return_vars << bind_variable
366
- @return_vars_metadata[bind_variable] = metadata
367
- @return_sql << ":#{bind_variable} := l_#{argument}.#{field};\n"
368
- end
369
- "l_#{argument} := " if is_return_value
370
- when 'PL/SQL BOOLEAN'
371
- @declare_sql << "l_#{argument} BOOLEAN;\n" if is_return_value
372
- @declare_sql << "o_#{argument} NUMBER(1);\n"
373
- # should use different output bind variable as JDBC does not support
374
- # if output bind variable appears in several places
375
- bind_variable = :"o_#{argument}"
376
- @return_vars << bind_variable
377
- @return_vars_metadata[bind_variable] = argument_metadata.merge(:data_type => "NUMBER", :data_precision => 1)
378
- @return_sql << "IF l_#{argument} IS NULL THEN\no_#{argument} := NULL;\n" <<
379
- "ELSIF l_#{argument} THEN\no_#{argument} := 1;\nELSE\no_#{argument} := 0;\nEND IF;\n" <<
380
- ":#{bind_variable} := o_#{argument};\n"
381
- "l_#{argument} := " if is_return_value
382
- else
383
- if argument_metadata[:tmp_table_name]
384
- add_return_table(argument, argument_metadata, is_return_value)
385
- elsif is_return_value
386
- @return_vars << argument
387
- @return_vars_metadata[argument] = argument_metadata
388
- ":#{argument} := "
414
+ @return_vars_metadata[bind_variable] = argument_metadata.merge(data_type: "NUMBER", data_precision: 1)
415
+ @return_sql << "IF l_#{argument} IS NULL THEN\no_#{argument} := NULL;\n" <<
416
+ "ELSIF l_#{argument} THEN\no_#{argument} := 1;\nELSE\no_#{argument} := 0;\nEND IF;\n" <<
417
+ ":#{bind_variable} := o_#{argument};\n"
418
+ "l_#{argument} := " if is_return_value
419
+ else
420
+ if argument_metadata[:tmp_table_name]
421
+ add_return_table(argument, argument_metadata, is_return_value)
422
+ elsif is_return_value
423
+ @return_vars << argument
424
+ @return_vars_metadata[argument] = argument_metadata
425
+ ":#{argument} := "
426
+ end
389
427
  end
390
428
  end
391
- end
392
429
 
393
- def add_return_table(argument, argument_metadata, is_return_value=false)
394
- is_index_by_table = argument_metadata[:data_type] == 'PL/SQL TABLE'
395
- declare_i__
396
- @declare_sql << "l_return #{return_metadata[:sql_type_name]};\n" if is_return_value
397
- @return_vars << argument
398
- @return_vars_metadata[argument] = argument_metadata.merge(:data_type => "REF CURSOR")
399
- @return_sql << if is_index_by_table
400
- "i__ := l_#{argument}.FIRST;\nLOOP\nEXIT WHEN i__ IS NULL;\n"
401
- else
402
- "IF l_#{argument}.COUNT > 0 THEN\nFOR i__ IN l_#{argument}.FIRST..l_#{argument}.LAST LOOP\n"
403
- end
404
- case argument_metadata[:element][:data_type]
405
- when 'PL/SQL RECORD'
406
- field_names = record_fields_sorted_by_position(argument_metadata[:element][:fields])
407
- values_string = field_names.map{|f| "l_#{argument}(i__).#{f}"}.join(', ')
408
- @return_sql << "INSERT INTO #{argument_metadata[:tmp_table_name]} VALUES (#{values_string}, i__);\n"
409
- return_fields_string = is_index_by_table ? '*' : field_names.join(', ')
410
- else
411
- @return_sql << "INSERT INTO #{argument_metadata[:tmp_table_name]} VALUES (l_#{argument}(i__), i__);\n"
412
- return_fields_string = '*'
413
- end
414
- @return_sql << "i__ := l_#{argument}.NEXT(i__);\n" if is_index_by_table
415
- @return_sql << "END LOOP;\n"
416
- @return_sql << "END IF;\n" unless is_index_by_table
417
- @return_sql << "OPEN :#{argument} FOR SELECT #{return_fields_string} FROM #{argument_metadata[:tmp_table_name]} ORDER BY i__;\n"
418
- @return_sql << "DELETE FROM #{argument_metadata[:tmp_table_name]};\n"
419
- "l_#{argument} := " if is_return_value
420
- end
430
+ def add_return_table(argument, argument_metadata, is_return_value = false)
431
+ is_index_by_table = argument_metadata[:data_type] == "PL/SQL TABLE"
432
+ declare_i__
433
+ @declare_sql << "l_return #{return_metadata[:sql_type_name]};\n" if is_return_value
434
+ @return_vars << argument
435
+ @return_vars_metadata[argument] = argument_metadata.merge(data_type: "REF CURSOR")
436
+ @return_sql << if is_index_by_table
437
+ "i__ := l_#{argument}.FIRST;\nLOOP\nEXIT WHEN i__ IS NULL;\n"
438
+ else
439
+ "IF l_#{argument}.COUNT > 0 THEN\nFOR i__ IN l_#{argument}.FIRST..l_#{argument}.LAST LOOP\n"
440
+ end
441
+ case argument_metadata[:element][:data_type]
442
+ when "PL/SQL RECORD"
443
+ field_names = record_fields_sorted_by_position(argument_metadata[:element][:fields])
444
+ values_string = field_names.map { |f| "l_#{argument}(i__).#{f}" }.join(", ")
445
+ @return_sql << "INSERT INTO #{argument_metadata[:tmp_table_name]} VALUES (#{values_string}, i__);\n"
446
+ return_fields_string = is_index_by_table ? "*" : field_names.join(", ")
447
+ else
448
+ @return_sql << "INSERT INTO #{argument_metadata[:tmp_table_name]} VALUES (l_#{argument}(i__), i__);\n"
449
+ return_fields_string = "*"
450
+ end
451
+ @return_sql << "i__ := l_#{argument}.NEXT(i__);\n" if is_index_by_table
452
+ @return_sql << "END LOOP;\n"
453
+ @return_sql << "END IF;\n" unless is_index_by_table
454
+ @return_sql << "OPEN :#{argument} FOR SELECT #{return_fields_string} FROM #{argument_metadata[:tmp_table_name]} ORDER BY i__;\n"
455
+ @return_sql << "DELETE FROM #{argument_metadata[:tmp_table_name]};\n"
456
+ "l_#{argument} := " if is_return_value
457
+ end
421
458
 
422
- # declare once temp variable i__ that is used as itertor
423
- def declare_i__
424
- unless @declared_i__
425
- @declare_sql << "i__ PLS_INTEGER;\n"
426
- @declared_i__ = true
459
+ # declare once temp variable i__ that is used as itertor
460
+ def declare_i__
461
+ unless @declared_i__
462
+ @declare_sql << "i__ PLS_INTEGER;\n"
463
+ @declared_i__ = true
464
+ end
427
465
  end
428
- end
429
466
 
430
- def type_to_sql(metadata)
431
- ProcedureCommon.type_to_sql(metadata)
432
- end
467
+ def type_to_sql(metadata)
468
+ ProcedureCommon.type_to_sql(metadata)
469
+ end
433
470
 
434
- def get_return_value
435
- # if function with output parameters
436
- if return_metadata && out_list.size > 0
437
- result = [function_return_value, {}]
438
- out_list.each do |k|
439
- result[1][k] = out_variable_value(k)
440
- end
441
- result
442
- # if function without output parameters
443
- elsif return_metadata
444
- function_return_value
445
- # if procedure with output parameters
446
- elsif out_list.size > 0
447
- result = {}
448
- out_list.each do |k|
449
- result[k] = out_variable_value(k)
471
+ def get_return_value
472
+ # if function with output parameters
473
+ if return_metadata && out_list.size > 0
474
+ result = [function_return_value, {}]
475
+ out_list.each do |k|
476
+ result[1][k] = out_variable_value(k)
477
+ end
478
+ result
479
+ # if function without output parameters
480
+ elsif return_metadata
481
+ function_return_value
482
+ # if procedure with output parameters
483
+ elsif out_list.size > 0
484
+ result = {}
485
+ out_list.each do |k|
486
+ result[k] = out_variable_value(k)
487
+ end
488
+ result
489
+ # if procedure without output parameters
490
+ else
491
+ nil
450
492
  end
451
- result
452
- # if procedure without output parameters
453
- else
454
- nil
455
493
  end
456
- end
457
494
 
458
- def function_return_value
459
- return_variable_value(:return, return_metadata)
460
- end
495
+ def function_return_value
496
+ return_variable_value(:return, return_metadata)
497
+ end
461
498
 
462
- def out_variable_value(argument)
463
- return_variable_value(argument, arguments[argument])
464
- end
499
+ def out_variable_value(argument)
500
+ return_variable_value(argument, arguments[argument])
501
+ end
465
502
 
466
- def return_variable_value(argument, argument_metadata)
467
- case argument_metadata[:data_type]
468
- when 'PL/SQL RECORD'
469
- return_value = {}
470
- argument_metadata[:fields].each do |field, metadata|
471
- return_value[field] = @cursor[":#{argument}_o#{metadata[:position]}"]
472
- end
473
- return_value
474
- when 'PL/SQL BOOLEAN'
475
- numeric_value = @cursor[":o_#{argument}"]
476
- numeric_value.nil? ? nil : numeric_value == 1
477
- else
478
- if argument_metadata[:tmp_table_name]
479
- is_index_by_table = argument_metadata[:data_type] == 'PL/SQL TABLE'
480
- case argument_metadata[:element][:data_type]
481
- when 'PL/SQL RECORD'
482
- if is_index_by_table
483
- Hash[*@cursor[":#{argument}"].fetch_hash_all.map{|row| [row.delete(:i__), row]}.flatten]
503
+ def return_variable_value(argument, argument_metadata)
504
+ case argument_metadata[:data_type]
505
+ when "PL/SQL RECORD"
506
+ return_value = {}
507
+ argument_metadata[:fields].each do |field, metadata|
508
+ field_value = @cursor[":#{argument}_o#{metadata[:position]}"]
509
+ case metadata[:data_type]
510
+ when "PL/SQL BOOLEAN"
511
+ return_value[field] = field_value.nil? ? nil : field_value == 1
484
512
  else
485
- @cursor[":#{argument}"].fetch_hash_all
513
+ return_value[field] = field_value
486
514
  end
487
- else
488
- if is_index_by_table
489
- Hash[*@cursor[":#{argument}"].fetch_all.map{|row| [row[1], row[0]]}.flatten]
515
+ end
516
+ return_value
517
+ when "PL/SQL BOOLEAN"
518
+ numeric_value = @cursor[":o_#{argument}"]
519
+ numeric_value.nil? ? nil : numeric_value == 1
520
+ when "UNDEFINED"
521
+ if argument_metadata[:type_name] == "XMLTYPE"
522
+ @cursor[":o_#{argument}"]
523
+ end
524
+ else
525
+ if argument_metadata[:tmp_table_name]
526
+ is_index_by_table = argument_metadata[:data_type] == "PL/SQL TABLE"
527
+ case argument_metadata[:element][:data_type]
528
+ when "PL/SQL RECORD"
529
+ if is_index_by_table
530
+ Hash[*@cursor[":#{argument}"].fetch_hash_all.map { |row| [row.delete(:i__), row] }.flatten]
531
+ else
532
+ @cursor[":#{argument}"].fetch_hash_all
533
+ end
490
534
  else
491
- @cursor[":#{argument}"].fetch_all.map{|row| row[0]}
535
+ if is_index_by_table
536
+ Hash[*@cursor[":#{argument}"].fetch_all.map { |row| [row[1], row[0]] }.flatten]
537
+ else
538
+ @cursor[":#{argument}"].fetch_all.map { |row| row[0] }
539
+ end
492
540
  end
541
+ else
542
+ @cursor[":#{argument}"]
493
543
  end
494
- else
495
- @cursor[":#{argument}"]
496
544
  end
497
545
  end
498
- end
499
546
 
500
- def overload_argument_list
501
- @overload_argument_list ||=
502
- @skip_self ? @procedure.argument_list_without_self : @procedure.argument_list
503
- end
547
+ def overload_argument_list
548
+ @overload_argument_list ||=
549
+ @skip_self ? @procedure.argument_list_without_self : @procedure.argument_list
550
+ end
504
551
 
505
- def overload_arguments
506
- @overload_arguments ||=
507
- @skip_self ? @procedure.arguments_without_self : @procedure.arguments
508
- end
552
+ def overload_arguments
553
+ @overload_arguments ||=
554
+ @skip_self ? @procedure.arguments_without_self : @procedure.arguments
555
+ end
509
556
 
510
- def argument_list
511
- @argument_list ||= overload_argument_list[@overload]
512
- end
557
+ def argument_list
558
+ @argument_list ||= overload_argument_list[@overload]
559
+ end
513
560
 
514
- def arguments
515
- @arguments ||= overload_arguments[@overload]
516
- end
561
+ def arguments
562
+ @arguments ||= overload_arguments[@overload]
563
+ end
517
564
 
518
- def return_metadata
519
- @return_metadata ||= @procedure.return[@overload]
520
- end
565
+ def return_metadata
566
+ @return_metadata ||= @procedure.return[@overload]
567
+ end
521
568
 
522
- def out_list
523
- @out_list ||=
524
- @skip_self ? @procedure.out_list_without_self[@overload] : @procedure.out_list[@overload]
525
- end
569
+ def out_list
570
+ @out_list ||=
571
+ @skip_self ? @procedure.out_list_without_self[@overload] : @procedure.out_list[@overload]
572
+ end
526
573
 
527
- def schema_name
528
- @schema_name ||= @procedure.schema_name
529
- end
574
+ def schema_name
575
+ @schema_name ||= @procedure.schema_name
576
+ end
530
577
 
531
- def package_name
532
- @package_name ||= @procedure.package
533
- end
578
+ def package_name
579
+ @package_name ||= @procedure.package
580
+ end
534
581
 
535
- def procedure_name
536
- @procedure_name ||= @procedure.procedure
537
- end
582
+ def procedure_name
583
+ @procedure_name ||= @procedure.procedure
584
+ end
538
585
 
539
- def dbms_output_enable_sql
540
- @dbms_output_stream ? "DBMS_OUTPUT.ENABLE(#{@schema.dbms_output_buffer_size});\n" : ""
541
- end
586
+ def dbms_output_enable_sql
587
+ @dbms_output_stream ? "DBMS_OUTPUT.ENABLE(#{@schema.dbms_output_buffer_size});\n" : ""
588
+ end
542
589
 
543
- def dbms_output_lines
544
- lines = []
545
- if @dbms_output_stream
546
- if (@schema.connection.database_version <=> [10, 2, 0, 0]) >= 0
547
- cursor = @schema.connection.parse("BEGIN DBMS_OUTPUT.GET_LINES(:dbms_output_lines, :dbms_output_numlines); END;\n")
548
- cursor.bind_param(':dbms_output_lines', nil,
549
- :data_type => 'TABLE',
550
- :data_length => nil,
551
- :sql_type_name => "SYS.DBMSOUTPUT_LINESARRAY",
552
- :in_out => 'OUT')
553
- cursor.bind_param(':dbms_output_numlines', Schema::DBMS_OUTPUT_MAX_LINES, :data_type => 'NUMBER', :in_out => 'IN/OUT')
554
- cursor.exec
555
- lines = cursor[':dbms_output_lines']
556
- cursor.close
557
- else
558
- cursor = @schema.connection.parse("BEGIN sys.dbms_output.get_line(:line, :status); END;")
559
- while true do
560
- cursor.bind_param(':line', nil, :data_type => 'VARCHAR2', :in_out => 'OUT')
561
- cursor.bind_param(':status', nil, :data_type => 'NUMBER', :in_out => 'OUT')
590
+ def dbms_output_lines
591
+ lines = []
592
+ if @dbms_output_stream
593
+ if (@schema.connection.database_version <=> [10, 2, 0, 0]) >= 0
594
+ cursor = @schema.connection.parse("BEGIN DBMS_OUTPUT.GET_LINES(:dbms_output_lines, :dbms_output_numlines); END;\n")
595
+ cursor.bind_param(":dbms_output_lines", nil,
596
+ data_type: "TABLE",
597
+ data_length: nil,
598
+ sql_type_name: "SYS.DBMSOUTPUT_LINESARRAY",
599
+ in_out: "OUT")
600
+ cursor.bind_param(":dbms_output_numlines", Schema::DBMS_OUTPUT_MAX_LINES, data_type: "NUMBER", in_out: "IN/OUT")
562
601
  cursor.exec
563
- break unless cursor[':status'] == 0
564
- lines << cursor[':line']
602
+ lines = cursor[":dbms_output_lines"]
603
+ cursor.close
604
+ else
605
+ cursor = @schema.connection.parse("BEGIN sys.dbms_output.get_line(:line, :status); END;")
606
+ while true do
607
+ cursor.bind_param(":line", nil, data_type: "VARCHAR2", in_out: "OUT")
608
+ cursor.bind_param(":status", nil, data_type: "NUMBER", in_out: "OUT")
609
+ cursor.exec
610
+ break unless cursor[":status"] == 0
611
+ lines << cursor[":line"]
612
+ end
613
+ cursor.close
565
614
  end
566
- cursor.close
567
615
  end
616
+ lines
568
617
  end
569
- lines
570
- end
571
618
 
572
- def dbms_output_log
573
- dbms_output_lines.each do |line|
574
- @dbms_output_stream.puts "DBMS_OUTPUT: #{line}" if line
619
+ def dbms_output_log
620
+ dbms_output_lines.each do |line|
621
+ @dbms_output_stream.puts "DBMS_OUTPUT: #{line}" if line
622
+ end
623
+ @dbms_output_stream.flush if @dbms_output_stream
575
624
  end
576
- @dbms_output_stream.flush if @dbms_output_stream
577
- end
578
-
579
625
  end
580
-
581
626
  end