ruby-plsql 0.5.3 → 0.8.0

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