ruby-plsql 0.7.1 → 0.9.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +26 -0
  3. data/README.md +1 -1
  4. data/VERSION +1 -1
  5. data/lib/plsql/connection.rb +16 -16
  6. data/lib/plsql/helpers.rb +3 -3
  7. data/lib/plsql/jdbc_connection.rb +3 -5
  8. data/lib/plsql/oci_connection.rb +8 -4
  9. data/lib/plsql/package.rb +3 -3
  10. data/lib/plsql/procedure.rb +306 -11
  11. data/lib/plsql/procedure_call.rb +20 -15
  12. data/lib/plsql/schema.rb +13 -9
  13. data/lib/plsql/sequence.rb +2 -2
  14. data/lib/plsql/table.rb +7 -6
  15. data/lib/plsql/type.rb +7 -7
  16. data/lib/plsql/variable.rb +4 -4
  17. data/lib/plsql/version.rb +1 -1
  18. data/lib/plsql/view.rb +2 -2
  19. metadata +13 -91
  20. data/.codeclimate.yml +0 -30
  21. data/.github/stale.yml +0 -37
  22. data/.rubocop.yml +0 -153
  23. data/.travis/oracle/download.sh +0 -15
  24. data/.travis/oracle/install.sh +0 -32
  25. data/.travis/setup_accounts.sh +0 -9
  26. data/.travis.yml +0 -49
  27. data/Gemfile +0 -21
  28. data/Rakefile +0 -53
  29. data/Vagrantfile +0 -38
  30. data/gemfiles/Gemfile.activerecord-5.0 +0 -21
  31. data/gemfiles/Gemfile.activerecord-5.1 +0 -21
  32. data/gemfiles/Gemfile.activerecord-5.2 +0 -21
  33. data/ruby-plsql.gemspec +0 -114
  34. data/spec/plsql/connection_spec.rb +0 -505
  35. data/spec/plsql/package_spec.rb +0 -172
  36. data/spec/plsql/procedure_spec.rb +0 -2360
  37. data/spec/plsql/schema_spec.rb +0 -356
  38. data/spec/plsql/sequence_spec.rb +0 -67
  39. data/spec/plsql/sql_statements_spec.rb +0 -91
  40. data/spec/plsql/table_spec.rb +0 -371
  41. data/spec/plsql/type_spec.rb +0 -299
  42. data/spec/plsql/variable_spec.rb +0 -497
  43. data/spec/plsql/version_spec.rb +0 -8
  44. data/spec/plsql/view_spec.rb +0 -264
  45. data/spec/spec.opts +0 -6
  46. data/spec/spec_helper.rb +0 -121
  47. data/spec/support/create_arunit_user.sql +0 -2
  48. data/spec/support/custom_config.rb.sample +0 -14
  49. data/spec/support/file_check_script.sh +0 -9
  50. data/spec/support/test_db.rb +0 -149
  51. data/spec/support/unlock_and_setup_hr_user.sql +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 561e2fcdfa5b528f42ebe473058e1d1c68a47876e3142ebce4c78df2f9583f16
4
- data.tar.gz: 76bc35318e85ca4fc0f08bde88ce9dab706a94130138cac61872105b79c66ba1
3
+ metadata.gz: e240a454b5016fb465baaff47830601ea5f06f9a0f4ed7f2e032e2e8027c8841
4
+ data.tar.gz: 8209b0f8b037838e7be37578a396b8652855540abd6a0c2cbf226adfaf7a598e
5
5
  SHA512:
6
- metadata.gz: 8e15cd8d687a56e1a60846a9cd7943e3d6b2969195b5e4876aa3aba1a4fc6a13f10090c028936bf57527ddcf351f5f6b7bec4f44f55592fd40199d1364c74cea
7
- data.tar.gz: da24e51d1ac39afcdf49025c721c30a503fb84b77f946be96e58466c06fc56236c51ba0fb132f0dbf8582cbd21f20927eb26cb185bf1bd61ac2d6e69da1e17b8
6
+ metadata.gz: af3ba3c7a782369e6e4f94afe467194f155fc961dc80e946ebbbaec07f48244169d33f1c0c387d6710752b7590f70c9cc5fb84bc21f8687b8c520d32ed09f557
7
+ data.tar.gz: 2fe1c1fa55a48cc547a3f34f371aba37147c4d3c8efc2c34d104b42b8e250251f6d233d65c6fedba42855774ccf559d6aed4164f341823b5c6fbbbb605acb047
data/History.txt CHANGED
@@ -1,3 +1,29 @@
1
+ This file is no longer being updated. For the latest updates and release information, please see: https://github.com/rsim/ruby-plsql/releases
2
+
3
+ == 0.8.0 2021-08-10
4
+ * Improvements and fixes
5
+ * Support Rails 6.1 [#193]
6
+ * Support Rails 6.0 [#178]
7
+ * Support Oracle Database 18c or higher [#196]
8
+ * case-insensitive table names and proc params [#185]
9
+ * Use OCI driver type for RUBY_ENGINE TruffleRuby [#190]
10
+ * Replace NativeException with Java::JavaSql::SQLException [#192]
11
+ * Fixnum and Bignum are deprecated in Ruby 2.4 [#191]
12
+
13
+ * CI
14
+ * Run CI with GitHub Actions [#198]
15
+ * CI against Rails 6.1 [#193]
16
+ * CI against Rails 6.0 [#178]
17
+ * CI against Ruby 3.0.2, 2.7.4 and 2.6.8 [#197]
18
+ * Exclude jruby-head with Rails main [#194]
19
+ * Exclude jruby-head with Rails main [#194]
20
+ * Bump RuboCop version to 0.81.0 [#186]
21
+ * Run RuboCop using GitHub Actions [#180, #182]
22
+ * Remove .codeclimate.yml [#181]
23
+ * Fallback to bundler 1.7.13 [#171]
24
+ * Terminate CI against Ruby 2.2.x [#172]
25
+ * Use Ubuntu Xenial at Travis CI [#176]
26
+
1
27
  == 0.7.1 2018-09-03
2
28
  * Fix
3
29
  * Address incorrect versions in Gemfile
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/rsim/ruby-plsql.svg?branch=master)](https://travis-ci.org/rsim/ruby-plsql)
1
+ [![Build Status](https://travis-ci.com/rsim/ruby-plsql.svg?branch=master)](https://travis-ci.com/rsim/ruby-plsql)
2
2
 
3
3
  ruby-plsql
4
4
  ==========
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.1
1
+ 0.9.0
@@ -3,13 +3,13 @@ module PLSQL
3
3
  attr_reader :raw_driver
4
4
  attr_reader :activerecord_class
5
5
 
6
- def initialize(raw_conn, ar_class = nil) #:nodoc:
6
+ def initialize(raw_conn, ar_class = nil) # :nodoc:
7
7
  @raw_driver = self.class.driver_type
8
8
  @raw_connection = raw_conn
9
9
  @activerecord_class = ar_class
10
10
  end
11
11
 
12
- def self.create(raw_conn, ar_class = nil) #:nodoc:
12
+ def self.create(raw_conn, ar_class = nil) # :nodoc:
13
13
  if ar_class && !(defined?(::ActiveRecord) && ar_class.ancestors.include?(::ActiveRecord::Base))
14
14
  raise ArgumentError, "Wrong ActiveRecord class"
15
15
  end
@@ -23,7 +23,7 @@ module PLSQL
23
23
  end
24
24
  end
25
25
 
26
- def self.create_new(params) #:nodoc:
26
+ def self.create_new(params) # :nodoc:
27
27
  conn = case driver_type
28
28
  when :oci
29
29
  OCIConnection.create_raw(params)
@@ -36,9 +36,9 @@ module PLSQL
36
36
  conn
37
37
  end
38
38
 
39
- def self.driver_type #:nodoc:
40
- # MRI 1.8.6 or YARV 1.9.1
41
- @driver_type ||= if (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby") && defined?(OCI8)
39
+ def self.driver_type # :nodoc:
40
+ # MRI 1.8.6 or YARV 1.9.1 or TruffleRuby
41
+ @driver_type ||= if (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby") && defined?(OCI8)
42
42
  :oci
43
43
  # JRuby
44
44
  elsif (defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby")
@@ -67,18 +67,18 @@ module PLSQL
67
67
  @raw_driver == :jdbc
68
68
  end
69
69
 
70
- def logoff #:nodoc:
70
+ def logoff # :nodoc:
71
71
  # Rollback any uncommited transactions
72
72
  rollback
73
73
  # Common cleanup activities before logoff, should be called from particular driver method
74
74
  drop_session_ruby_temporary_tables
75
75
  end
76
76
 
77
- def commit #:nodoc:
77
+ def commit # :nodoc:
78
78
  raise NoMethodError, "Not implemented for this raw driver"
79
79
  end
80
80
 
81
- def rollback #:nodoc:
81
+ def rollback # :nodoc:
82
82
  raise NoMethodError, "Not implemented for this raw driver"
83
83
  end
84
84
 
@@ -98,21 +98,21 @@ module PLSQL
98
98
  raise NoMethodError, "Not implemented for this raw driver"
99
99
  end
100
100
 
101
- def select_first(sql, *bindvars) #:nodoc:
101
+ def select_first(sql, *bindvars) # :nodoc:
102
102
  cursor = cursor_from_query(sql, bindvars, prefetch_rows: 1)
103
103
  cursor.fetch
104
104
  ensure
105
105
  cursor.close rescue nil
106
106
  end
107
107
 
108
- def select_hash_first(sql, *bindvars) #:nodoc:
108
+ def select_hash_first(sql, *bindvars) # :nodoc:
109
109
  cursor = cursor_from_query(sql, bindvars, prefetch_rows: 1)
110
110
  cursor.fetch_hash
111
111
  ensure
112
112
  cursor.close rescue nil
113
113
  end
114
114
 
115
- def select_all(sql, *bindvars, &block) #:nodoc:
115
+ def select_all(sql, *bindvars, &block) # :nodoc:
116
116
  cursor = cursor_from_query(sql, bindvars)
117
117
  results = []
118
118
  row_count = 0
@@ -129,7 +129,7 @@ module PLSQL
129
129
  cursor.close rescue nil
130
130
  end
131
131
 
132
- def select_hash_all(sql, *bindvars, &block) #:nodoc:
132
+ def select_hash_all(sql, *bindvars, &block) # :nodoc:
133
133
  cursor = cursor_from_query(sql, bindvars)
134
134
  results = []
135
135
  row_count = 0
@@ -146,11 +146,11 @@ module PLSQL
146
146
  cursor.close rescue nil
147
147
  end
148
148
 
149
- def exec(sql, *bindvars) #:nodoc:
149
+ def exec(sql, *bindvars) # :nodoc:
150
150
  raise NoMethodError, "Not implemented for this raw driver"
151
151
  end
152
152
 
153
- def parse(sql) #:nodoc:
153
+ def parse(sql) # :nodoc:
154
154
  raise NoMethodError, "Not implemented for this raw driver"
155
155
  end
156
156
 
@@ -181,7 +181,7 @@ module PLSQL
181
181
 
182
182
  # all_synonyms view is quite slow therefore
183
183
  # this implementation is overriden in OCI connection with faster native OCI method
184
- def describe_synonym(schema_name, synonym_name) #:nodoc:
184
+ def describe_synonym(schema_name, synonym_name) # :nodoc:
185
185
  select_first(
186
186
  "SELECT table_owner, table_name FROM all_synonyms WHERE owner = :owner AND synonym_name = :synonym_name",
187
187
  schema_name.to_s.upcase, synonym_name.to_s.upcase)
data/lib/plsql/helpers.rb CHANGED
@@ -1,6 +1,6 @@
1
- module PLSQL #:nodoc:
2
- module ArrayHelpers #:nodoc:
3
- def self.to_hash(keys, values) #:nodoc:
1
+ module PLSQL # :nodoc:
2
+ module ArrayHelpers # :nodoc:
3
+ def self.to_hash(keys, values) # :nodoc:
4
4
  (0...keys.size).inject({}) { |hash, i| hash[keys[i]] = values[i]; hash }
5
5
  end
6
6
  end
@@ -46,7 +46,7 @@ rescue LoadError, NameError
46
46
  end
47
47
 
48
48
  module PLSQL
49
- class JDBCConnection < Connection #:nodoc:
49
+ class JDBCConnection < Connection # :nodoc:
50
50
  def self.create_raw(params)
51
51
  database = params[:database]
52
52
  url = if ENV["TNS_ADMIN"] && database && !params[:host] && !params[:url]
@@ -98,7 +98,7 @@ module PLSQL
98
98
  cs.close rescue nil
99
99
  end
100
100
 
101
- class CallableStatement #:nodoc:
101
+ class CallableStatement # :nodoc:
102
102
  def initialize(conn, sql)
103
103
  @sql = sql
104
104
  @connection = conn
@@ -145,7 +145,7 @@ module PLSQL
145
145
  end
146
146
  end
147
147
 
148
- class Cursor #:nodoc:
148
+ class Cursor # :nodoc:
149
149
  include Connection::CursorCommon
150
150
 
151
151
  attr_reader :result_set
@@ -223,8 +223,6 @@ module PLSQL
223
223
  end
224
224
 
225
225
  RUBY_CLASS_TO_SQL_TYPE = {
226
- Fixnum => java.sql.Types::INTEGER,
227
- Bignum => java.sql.Types::INTEGER,
228
226
  Integer => java.sql.Types::INTEGER,
229
227
  Float => java.sql.Types::FLOAT,
230
228
  BigDecimal => java.sql.Types::NUMERIC,
@@ -24,7 +24,7 @@ if (oci8_version_ints <=> required_oci8_version) < 0
24
24
  end
25
25
 
26
26
  module PLSQL
27
- class OCIConnection < Connection #:nodoc:
27
+ class OCIConnection < Connection # :nodoc:
28
28
  def self.create_raw(params)
29
29
  connection_string = if params[:host]
30
30
  "//#{params[:host]}:#{params[:port] || 1521}/#{params[:database]}"
@@ -64,7 +64,7 @@ module PLSQL
64
64
  true
65
65
  end
66
66
 
67
- class Cursor #:nodoc:
67
+ class Cursor # :nodoc:
68
68
  include Connection::CursorCommon
69
69
 
70
70
  attr_reader :raw_cursor
@@ -157,7 +157,7 @@ module PLSQL
157
157
  [DateTime, nil]
158
158
  when "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE"
159
159
  [Time, nil]
160
- when "TABLE", "VARRAY", "OBJECT", "XMLTYPE"
160
+ when "TABLE", "VARRAY", "OBJECT", "XMLTYPE", "OPAQUE/XMLTYPE"
161
161
  # create Ruby class for collection
162
162
  klass = OCI8::Object::Base.get_class_by_typename(metadata[:sql_type_name])
163
163
  unless klass
@@ -289,7 +289,11 @@ module PLSQL
289
289
  # ActiveRecord Oracle enhanced adapter puts OCI8EnhancedAutoRecover wrapper around OCI8
290
290
  # in this case we need to pass original OCI8 connection
291
291
  else
292
- raw_connection.instance_variable_get(:@connection)
292
+ if raw_connection.instance_variable_defined?(:@raw_connection)
293
+ raw_connection.instance_variable_get(:@raw_connection)
294
+ else
295
+ raw_connection.instance_variable_get(:@connection)
296
+ end
293
297
  end
294
298
  end
295
299
 
data/lib/plsql/package.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module PLSQL
2
- module PackageClassMethods #:nodoc:
2
+ module PackageClassMethods # :nodoc:
3
3
  def find(schema, package)
4
4
  package_name = package.to_s.upcase
5
5
  find_in_schema(schema, package_name) || find_by_synonym(schema, package_name)
@@ -32,7 +32,7 @@ module PLSQL
32
32
  end
33
33
  end
34
34
 
35
- class Package #:nodoc:
35
+ class Package # :nodoc:
36
36
  extend PackageClassMethods
37
37
 
38
38
  def initialize(schema, package, override_schema_name = nil)
@@ -56,7 +56,7 @@ module PLSQL
56
56
  private
57
57
 
58
58
  def method_missing(method, *args, &block)
59
- method = method.to_s
59
+ method = +method.to_s
60
60
  method.chop! if (assignment = method[/=$/])
61
61
 
62
62
  case (object = self[method])
@@ -1,5 +1,5 @@
1
1
  module PLSQL
2
- module ProcedureClassMethods #:nodoc:
2
+ module ProcedureClassMethods # :nodoc:
3
3
  def find(schema, procedure, package = nil, override_schema_name = nil)
4
4
  if package.nil?
5
5
  if (row = schema.select_first(
@@ -53,12 +53,12 @@ module PLSQL
53
53
  end
54
54
  end
55
55
 
56
- module ProcedureCommon #:nodoc:
56
+ module ProcedureCommon # :nodoc:
57
57
  attr_reader :arguments, :argument_list, :out_list, :return
58
58
  attr_reader :schema, :schema_name, :package, :procedure
59
59
 
60
60
  # return type string from metadata that can be used in DECLARE block or table definition
61
- def self.type_to_sql(metadata) #:nodoc:
61
+ def self.type_to_sql(metadata) # :nodoc:
62
62
  case metadata[:data_type]
63
63
  when "NUMBER"
64
64
  precision, scale = metadata[:data_precision], metadata[:data_scale]
@@ -82,7 +82,15 @@ module PLSQL
82
82
  end
83
83
 
84
84
  # get procedure argument metadata from data dictionary
85
- def get_argument_metadata #:nodoc:
85
+ def get_argument_metadata # :nodoc:
86
+ if (@schema.connection.database_version <=> [18, 0, 0, 0]) >= 0
87
+ get_argument_metadata_from_18c
88
+ else
89
+ get_argument_metadata_below_18c
90
+ end
91
+ end
92
+
93
+ def get_argument_metadata_below_18c # :nodoc:
86
94
  @arguments = {}
87
95
  @argument_list = {}
88
96
  @out_list = {}
@@ -118,6 +126,9 @@ module PLSQL
118
126
  data_type, in_out, data_length, data_precision, data_scale, char_used,
119
127
  char_length, type_owner, type_name, type_subname, defaulted = r
120
128
 
129
+ # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN"
130
+ data_type = "PL/SQL BOOLEAN" if data_type == "BOOLEAN"
131
+
121
132
  @overloaded ||= !overload.nil?
122
133
  # if not overloaded then store arguments at key 0
123
134
  overload ||= 0
@@ -197,7 +208,103 @@ module PLSQL
197
208
  construct_argument_list_for_overloads
198
209
  end
199
210
 
200
- def construct_argument_list_for_overloads #:nodoc:
211
+ # get procedure argument metadata from data dictionary
212
+ def get_argument_metadata_from_18c # :nodoc:
213
+ @arguments = {}
214
+ @argument_list = {}
215
+ @out_list = {}
216
+ @return = {}
217
+ @overloaded = false
218
+
219
+ # store tmp tables for each overload for table parameters with types defined inside packages
220
+ @tmp_table_names = {}
221
+ # store if tmp tables are created for specific overload
222
+ @tmp_tables_created = {}
223
+
224
+ @schema.select_all(
225
+ "SELECT subprogram_id, object_name, TO_NUMBER(overload), argument_name, position,
226
+ data_type, in_out, data_length, data_precision, data_scale, char_used,
227
+ char_length, type_owner, nvl(type_subname, type_name),
228
+ decode(type_object_type, 'PACKAGE', type_name, null), type_object_type, defaulted
229
+ FROM all_arguments
230
+ WHERE object_id = :object_id
231
+ AND owner = :owner
232
+ AND object_name = :procedure_name
233
+ ORDER BY overload, sequence",
234
+ @object_id, @schema_name, @procedure
235
+ ) do |r|
236
+
237
+ subprogram_id, _object_name, overload, argument_name, position,
238
+ data_type, in_out, data_length, data_precision, data_scale, char_used,
239
+ char_length, type_owner, type_name, type_package, type_object_type, defaulted = r
240
+
241
+ # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN"
242
+ data_type = "PL/SQL BOOLEAN" if data_type == "BOOLEAN"
243
+
244
+ @overloaded ||= !overload.nil?
245
+ # if not overloaded then store arguments at key 0
246
+ overload ||= 0
247
+ @arguments[overload] ||= {}
248
+ @return[overload] ||= nil
249
+ @tmp_table_names[overload] ||= []
250
+
251
+ sql_type_name = build_sql_type_name(type_owner, type_package, type_name)
252
+
253
+ tmp_table_name = nil
254
+ # type defined inside package
255
+ if type_package
256
+ if collection_type?(data_type)
257
+ tmp_table_name = "#{Connection::RUBY_TEMP_TABLE_PREFIX}#{@schema.connection.session_id}_#{@object_id}_#{subprogram_id}_#{position}"
258
+ end
259
+ end
260
+
261
+ argument_metadata = {
262
+ position: position && position.to_i,
263
+ data_type: data_type,
264
+ in_out: in_out,
265
+ data_length: data_length && data_length.to_i,
266
+ data_precision: data_precision && data_precision.to_i,
267
+ data_scale: data_scale && data_scale.to_i,
268
+ char_used: char_used,
269
+ char_length: char_length && char_length.to_i,
270
+ type_owner: type_owner,
271
+ type_name: type_name,
272
+ # TODO: should be renamed to type_package, when support for legacy database versions is dropped
273
+ # due to the explicit change declaration of types in oracle plsql_type-catalogs (type_package + type_name),
274
+ # the assignment of type + subtype was switched here for 18c and beyond
275
+ type_subname: type_package,
276
+ sql_type_name: sql_type_name,
277
+ defaulted: defaulted,
278
+ type_object_type: type_object_type
279
+ }
280
+ if tmp_table_name
281
+ @tmp_table_names[overload] << [(argument_metadata[:tmp_table_name] = tmp_table_name), argument_metadata]
282
+ end
283
+
284
+ if composite_type?(data_type)
285
+ case data_type
286
+ when "PL/SQL RECORD", "REF CURSOR"
287
+ argument_metadata[:fields] = get_field_definitions(argument_metadata)
288
+ when "PL/SQL TABLE", "TABLE", "VARRAY"
289
+ argument_metadata[:element] = get_element_definition(argument_metadata)
290
+ end
291
+ end
292
+
293
+ # if function has return value
294
+ if argument_name.nil? && in_out == "OUT"
295
+ @return[overload] = argument_metadata
296
+ else
297
+ # sometime there are empty IN arguments in all_arguments view for procedures without arguments (e.g. for DBMS_OUTPUT.DISABLE)
298
+ @arguments[overload][argument_name.downcase.to_sym] = argument_metadata if argument_name
299
+ end
300
+ end
301
+ # if procedure is without arguments then create default empty argument list for default overload
302
+ @arguments[0] = {} if @arguments.keys.empty?
303
+
304
+ construct_argument_list_for_overloads
305
+ end
306
+
307
+ def construct_argument_list_for_overloads # :nodoc:
201
308
  @overloads = @arguments.keys.sort
202
309
  @overloads.each do |overload|
203
310
  @argument_list[overload] = @arguments[overload].keys.sort { |k1, k2| @arguments[overload][k1][:position] <=> @arguments[overload][k2][:position] }
@@ -205,10 +312,10 @@ module PLSQL
205
312
  end
206
313
  end
207
314
 
208
- def ensure_tmp_tables_created(overload) #:nodoc:
315
+ def ensure_tmp_tables_created(overload) # :nodoc:
209
316
  return if @tmp_tables_created.nil? || @tmp_tables_created[overload]
210
317
  @tmp_table_names[overload] && @tmp_table_names[overload].each do |table_name, argument_metadata|
211
- sql = "CREATE GLOBAL TEMPORARY TABLE #{table_name} (\n"
318
+ sql = +"CREATE GLOBAL TEMPORARY TABLE #{table_name} (\n"
212
319
  element_metadata = argument_metadata[:element]
213
320
  case element_metadata[:data_type]
214
321
  when "PL/SQL RECORD"
@@ -229,22 +336,210 @@ module PLSQL
229
336
  @tmp_tables_created[overload] = true
230
337
  end
231
338
 
339
+ def build_sql_type_name(type_owner, type_package, type_name) # :nodoc:
340
+ if type_owner == nil || type_owner == "PUBLIC"
341
+ type_owner_res = ""
342
+ else
343
+ type_owner_res = "#{type_owner}."
344
+ end
345
+
346
+ if type_package == nil
347
+ type_name_res = type_name
348
+ else
349
+ type_name_res = "#{type_package}.#{type_name}"
350
+ end
351
+ type_name_res && "#{type_owner_res}#{type_name_res}"
352
+ end
353
+
354
+ def get_field_definitions(argument_metadata) # :nodoc:
355
+ fields = {}
356
+ case argument_metadata[:type_object_type]
357
+ when "PACKAGE"
358
+ @schema.select_all(
359
+ "SELECT attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, length, precision, scale, char_used
360
+ FROM ALL_PLSQL_TYPES t, ALL_PLSQL_TYPE_ATTRS ta
361
+ WHERE t.OWNER = :owner AND t.type_name = :type_name AND t.package_name = :package_name
362
+ AND ta.OWNER = t.owner AND ta.TYPE_NAME = t.TYPE_NAME AND ta.PACKAGE_NAME = t.PACKAGE_NAME
363
+ ORDER BY attr_no",
364
+ @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname]) do |r|
365
+
366
+ attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, attr_length, attr_precision, attr_scale, attr_char_used = r
367
+
368
+ # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN"
369
+ attr_type_name = "PL/SQL BOOLEAN" if attr_type_name == "BOOLEAN"
370
+
371
+ fields[attr_name.downcase.to_sym] = {
372
+ position: attr_no.to_i,
373
+ data_type: attr_type_owner == nil ? attr_type_name : get_composite_type(attr_type_owner, attr_type_name, attr_type_package),
374
+ in_out: argument_metadata[:in_out],
375
+ data_length: attr_length && attr_length.to_i,
376
+ data_precision: attr_precision && attr_precision.to_i,
377
+ data_scale: attr_scale && attr_scale.to_i,
378
+ char_used: attr_char_used == nil ? "0" : attr_char_used,
379
+ char_length: attr_char_used && attr_length && attr_length.to_i,
380
+ type_owner: attr_type_owner,
381
+ type_name: attr_type_owner && attr_type_name,
382
+ type_subname: attr_type_package,
383
+ sql_type_name: attr_type_owner && build_sql_type_name(attr_type_owner, attr_type_package, attr_type_name),
384
+ defaulted: argument_metadata[:defaulted]
385
+ }
386
+
387
+ if fields[attr_name.downcase.to_sym][:data_type] == "TABLE" && fields[attr_name.downcase.to_sym][:type_subname] != nil
388
+ fields[attr_name.downcase.to_sym][:fields] = get_field_definitions(fields[attr_name.downcase.to_sym])
389
+ end
390
+ end
391
+ when "TABLE", "VIEW"
392
+ @schema.select_all(
393
+ "SELECT column_id, column_name, data_type, data_length, data_precision, data_scale, char_length, char_used
394
+ FROM ALL_TAB_COLS WHERE OWNER = :owner AND TABLE_NAME = :type_name
395
+ ORDER BY column_id",
396
+ @schema_name, argument_metadata[:type_name]) do |r|
397
+
398
+ col_no, col_name, col_type_name, col_length, col_precision, col_scale, col_char_length, col_char_used = r
399
+
400
+ fields[col_name.downcase.to_sym] = {
401
+ position: col_no.to_i,
402
+ data_type: col_type_name,
403
+ in_out: argument_metadata[:in_out],
404
+ data_length: col_length && col_length.to_i,
405
+ data_precision: col_precision && col_precision.to_i,
406
+ data_scale: col_scale && col_scale.to_i,
407
+ char_used: col_char_used == nil ? "0" : col_char_used,
408
+ char_length: col_char_length && col_char_length.to_i,
409
+ type_owner: nil,
410
+ type_name: nil,
411
+ type_subname: nil,
412
+ sql_type_name: nil,
413
+ defaulted: argument_metadata[:defaulted]
414
+ }
415
+ end
416
+ end
417
+ fields
418
+ end
419
+
420
+ def get_element_definition(argument_metadata) # :nodoc:
421
+ element_metadata = {}
422
+ if collection_type?(argument_metadata[:data_type])
423
+ case argument_metadata[:type_object_type]
424
+ when "PACKAGE"
425
+ r = @schema.select_first(
426
+ "SELECT elem_type_owner, elem_type_name, elem_type_package, length, precision, scale, char_used, index_by
427
+ FROM ALL_PLSQL_COLL_TYPES t
428
+ WHERE t.OWNER = :owner AND t.TYPE_NAME = :type_name AND t.PACKAGE_NAME = :package_name",
429
+ @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname])
430
+
431
+ elem_type_owner, elem_type_name, elem_type_package, elem_length, elem_precision, elem_scale, elem_char_used, index_by = r
432
+
433
+ # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN"
434
+ elem_type_name = "PL/SQL BOOLEAN" if elem_type_name == "BOOLEAN"
435
+
436
+ if index_by == "VARCHAR2"
437
+ raise ArgumentError, "Index-by Varchar-Table (associative array) #{argument_metadata[:type_name]} is not supported"
438
+ end
439
+
440
+ element_metadata = {
441
+ position: 1,
442
+ data_type: if elem_type_owner == nil
443
+ elem_type_name
444
+ else
445
+ elem_type_package != nil ? "PL/SQL RECORD" : "OBJECT"
446
+ end,
447
+ in_out: argument_metadata[:in_out],
448
+ data_length: elem_length && elem_length.to_i,
449
+ data_precision: elem_precision && elem_precision.to_i,
450
+ data_scale: elem_scale && elem_scale.to_i,
451
+ char_used: elem_char_used,
452
+ char_length: elem_char_used && elem_length && elem_length.to_i,
453
+ type_owner: elem_type_owner,
454
+ type_name: elem_type_name,
455
+ type_subname: elem_type_package,
456
+ sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, elem_type_package, elem_type_name),
457
+ type_object_type: elem_type_package != nil ? "PACKAGE" : nil,
458
+ defaulted: argument_metadata[:defaulted]
459
+ }
460
+
461
+ if elem_type_package != nil
462
+ element_metadata[:fields] = get_field_definitions(element_metadata)
463
+ end
464
+ when "TYPE"
465
+ r = @schema.select_first(
466
+ "SELECT elem_type_owner, elem_type_name, length, precision, scale, char_used
467
+ FROM ALL_COLL_TYPES t
468
+ WHERE t.owner = :owner AND t.TYPE_NAME = :type_name",
469
+ @schema_name, argument_metadata[:type_name]
470
+ )
471
+ elem_type_owner, elem_type_name, elem_length, elem_precision, elem_scale, elem_char_used = r
472
+
473
+ # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN"
474
+ elem_type_name = "PL/SQL BOOLEAN" if elem_type_name == "BOOLEAN"
475
+
476
+ element_metadata = {
477
+ position: 1,
478
+ data_type: elem_type_owner == nil ? elem_type_name : "OBJECT",
479
+ in_out: argument_metadata[:in_out],
480
+ data_length: elem_length && elem_length.to_i,
481
+ data_precision: elem_precision && elem_precision.to_i,
482
+ data_scale: elem_scale && elem_scale.to_i,
483
+ char_used: elem_char_used,
484
+ char_length: elem_char_used && elem_length && elem_length.to_i,
485
+ type_owner: elem_type_owner,
486
+ type_name: elem_type_name,
487
+ type_subname: nil,
488
+ sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, nil, elem_type_name),
489
+ defaulted: argument_metadata[:defaulted]
490
+ }
491
+ end
492
+ else
493
+ element_metadata = {
494
+ position: 1,
495
+ data_type: "PL/SQL RECORD",
496
+ in_out: argument_metadata[:in_out],
497
+ data_length: nil,
498
+ data_precision: nil,
499
+ data_scale: nil,
500
+ char_used: "B",
501
+ char_length: 0,
502
+ type_owner: argument_metadata[:type_owner],
503
+ type_name: argument_metadata[:type_name],
504
+ type_subname: argument_metadata[:type_subname],
505
+ sql_type_name: build_sql_type_name(argument_metadata[:type_owner], argument_metadata[:type_subname], argument_metadata[:type_name]),
506
+ defaulted: argument_metadata[:defaulted]
507
+ }
508
+
509
+ if element_metadata[:type_subname] != nil
510
+ element_metadata[:fields] = get_field_definitions(element_metadata)
511
+ end
512
+ end
513
+ element_metadata
514
+ end
515
+
516
+ def get_composite_type(type_owner, type_name, type_package)
517
+ r = @schema.select_first("SELECT typecode FROM all_plsql_types WHERE owner = :owner AND type_name = :type_name AND package_name = :type_package
518
+ UNION ALL
519
+ SELECT typecode FROM all_types WHERE owner = :owner AND type_name = :type_name",
520
+ type_owner, type_name, type_package, type_owner, type_name)
521
+ typecode = r[0]
522
+ raise ArgumentError, "#{type_name} type #{build_sql_type_name(type_owner, type_package, type_name)} definition inside package is not supported as part of other type definition," <<
523
+ " use CREATE TYPE outside package" if typecode == "COLLECTION"
524
+ typecode
525
+ end
526
+
232
527
  PLSQL_COMPOSITE_TYPES = ["PL/SQL RECORD", "PL/SQL TABLE", "TABLE", "VARRAY", "REF CURSOR"].freeze
233
- def composite_type?(data_type) #:nodoc:
528
+ def composite_type?(data_type) # :nodoc:
234
529
  PLSQL_COMPOSITE_TYPES.include? data_type
235
530
  end
236
531
 
237
532
  PLSQL_COLLECTION_TYPES = ["PL/SQL TABLE", "TABLE", "VARRAY"].freeze
238
- def collection_type?(data_type) #:nodoc:
533
+ def collection_type?(data_type) # :nodoc:
239
534
  PLSQL_COLLECTION_TYPES.include? data_type
240
535
  end
241
536
 
242
- def overloaded? #:nodoc:
537
+ def overloaded? # :nodoc:
243
538
  @overloaded
244
539
  end
245
540
  end
246
541
 
247
- class Procedure #:nodoc:
542
+ class Procedure # :nodoc:
248
543
  extend ProcedureClassMethods
249
544
  include ProcedureCommon
250
545