From 513ea0a893d7e680e4cebe7026d2594f4576d028 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Mon, 11 Oct 2021 13:49:26 +0200 Subject: [PATCH 01/14] Try to resolve package synonyms like utl_file.file_type --- lib/plsql/procedure.rb | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index c9ec875..559fbc0 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -219,15 +219,21 @@ def get_argument_metadata_from_18c #:nodoc: @tmp_tables_created = {} @schema.select_all( - "SELECT subprogram_id, object_name, TO_NUMBER(overload), argument_name, position, - data_type, in_out, data_length, data_precision, data_scale, char_used, - char_length, type_owner, nvl(type_subname, type_name), - decode(type_object_type, 'PACKAGE', type_name, null), type_object_type, defaulted - FROM all_arguments - WHERE object_id = :object_id - AND owner = :owner - AND object_name = :procedure_name - ORDER BY overload, sequence", + "SELECT a.subprogram_id, a.object_name, TO_NUMBER(a.overload), a.argument_name, a.position, + a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale, a.char_used, + a.char_length, nvl(o.owner, a.type_owner), nvl(a.type_subname, nvl(o.object_name, a.type_name)) type_name, + CASE + WHEN a.type_object_type = 'PACKAGE' THEN a.type_name + WHEN o.object_type = 'PACKAGE' THEN o.object_name + ELSE null + END type_subname, nvl(o.object_type, a.type_object_type), a.defaulted + FROM all_arguments a + LEFT JOIN all_synonyms s ON a.type_owner = s.owner AND a.type_name = s.synonym_name + LEFT JOIN all_objects o ON s.table_owner = o.owner AND s.table_name = o.object_name AND o.object_type = 'PACKAGE' + WHERE a.object_id = :object_id + AND a.owner = :owner + AND a.object_name = :procedure_name + ORDER BY a.overload, a.sequence", @object_id, @schema_name, @procedure ) do |r| From 4c5959dc90d6b461091e585398c479020f671d15 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Mon, 11 Oct 2021 14:51:26 +0200 Subject: [PATCH 02/14] Field definitions do not necessarily have to come from the current schema; the type owner should take precedence --- lib/plsql/procedure.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index c9ec875..45b9bd9 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -355,7 +355,7 @@ def get_field_definitions(argument_metadata) #:nodoc: WHERE t.OWNER = :owner AND t.type_name = :type_name AND t.package_name = :package_name AND ta.OWNER = t.owner AND ta.TYPE_NAME = t.TYPE_NAME AND ta.PACKAGE_NAME = t.PACKAGE_NAME ORDER BY attr_no", - @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname]) do |r| + argument_metadata[:type_owner], argument_metadata[:type_name], argument_metadata[:type_subname]) do |r| attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, attr_length, attr_precision, attr_scale, attr_char_used = r From 38bd95c6561c9d0973a393e2855fffbe5be54e80 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Mon, 11 Oct 2021 15:18:39 +0200 Subject: [PATCH 03/14] Split lookup against all_objects into second query; alleviates the poor performance --- lib/plsql/procedure.rb | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 559fbc0..0f96d5e 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -221,15 +221,11 @@ def get_argument_metadata_from_18c #:nodoc: @schema.select_all( "SELECT a.subprogram_id, a.object_name, TO_NUMBER(a.overload), a.argument_name, a.position, a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale, a.char_used, - a.char_length, nvl(o.owner, a.type_owner), nvl(a.type_subname, nvl(o.object_name, a.type_name)) type_name, - CASE - WHEN a.type_object_type = 'PACKAGE' THEN a.type_name - WHEN o.object_type = 'PACKAGE' THEN o.object_name - ELSE null - END type_subname, nvl(o.object_type, a.type_object_type), a.defaulted + a.char_length, a.type_owner, nvl(a.type_subname, a.type_name) type_name, + case when a.type_object_type = 'PACKAGE' then a.type_name end type_package, a.type_object_type, a.defaulted, + s.table_owner synonym_owner, s.table_name synonym_name FROM all_arguments a LEFT JOIN all_synonyms s ON a.type_owner = s.owner AND a.type_name = s.synonym_name - LEFT JOIN all_objects o ON s.table_owner = o.owner AND s.table_name = o.object_name AND o.object_type = 'PACKAGE' WHERE a.object_id = :object_id AND a.owner = :owner AND a.object_name = :procedure_name @@ -239,7 +235,8 @@ def get_argument_metadata_from_18c #:nodoc: subprogram_id, object_name, overload, argument_name, position, data_type, in_out, data_length, data_precision, data_scale, char_used, - char_length, type_owner, type_name, type_package, type_object_type, defaulted = r + char_length, type_owner, type_name, type_package, type_object_type, defaulted, + synonym_dest_owner, synonym_dest_name = r @overloaded ||= !overload.nil? # if not overloaded then store arguments at key 0 @@ -248,6 +245,20 @@ def get_argument_metadata_from_18c #:nodoc: @return[overload] ||= nil @tmp_table_names[overload] ||= [] + unless synonym_dest_owner.nil? + puts 'Synonym not nil' + @schema.select_all( + "SELECT o.owner, o.object_name, o.object_type + FROM all_objects o + WHERE o.owner = :synonym_owner + AND o.object_name = :synonym_name + AND o.object_type = 'PACKAGE'", + synonym_dest_owner, synonym_dest_name + ) do |r2| + type_owner, type_package, type_object_type = r2 + end + end + sql_type_name = build_sql_type_name(type_owner, type_package, type_name) tmp_table_name = nil From 1f328bf8e63e19a4b2543d16bbd5aea4eb790eb2 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Mon, 11 Oct 2021 20:02:28 +0200 Subject: [PATCH 04/14] Field definitions do not necessarily have to come from the current schema; the type owner should take precedence --- lib/plsql/procedure.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 45b9bd9..199282f 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -384,7 +384,7 @@ def get_field_definitions(argument_metadata) #:nodoc: "SELECT column_id, column_name, data_type, data_length, data_precision, data_scale, char_length, char_used FROM ALL_TAB_COLS WHERE OWNER = :owner AND TABLE_NAME = :type_name ORDER BY column_id", - @schema_name, argument_metadata[:type_name]) do |r| + argument_metadata[:type_owner], argument_metadata[:type_name]) do |r| col_no, col_name, col_type_name, col_length, col_precision, col_scale, col_char_length, col_char_used = r @@ -417,7 +417,7 @@ def get_element_definition(argument_metadata) #:nodoc: "SELECT elem_type_owner, elem_type_name, elem_type_package, length, precision, scale, char_used, index_by FROM ALL_PLSQL_COLL_TYPES t WHERE t.OWNER = :owner AND t.TYPE_NAME = :type_name AND t.PACKAGE_NAME = :package_name", - @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname]) + argument_metadata[:type_owner], argument_metadata[:type_name], argument_metadata[:type_subname]) elem_type_owner, elem_type_name, elem_type_package, elem_length, elem_precision, elem_scale, elem_char_used, index_by = r @@ -454,7 +454,7 @@ def get_element_definition(argument_metadata) #:nodoc: "SELECT elem_type_owner, elem_type_name, length, precision, scale, char_used FROM ALL_COLL_TYPES t WHERE t.owner = :owner AND t.TYPE_NAME = :type_name", - @schema_name, argument_metadata[:type_name] + argument_metadata[:type_owner], argument_metadata[:type_name] ) elem_type_owner, elem_type_name, elem_length, elem_precision, elem_scale, elem_char_used = r From 6befbcc92e62e995d32307e7e45282ac6eaad836 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Mon, 11 Oct 2021 19:59:07 +0200 Subject: [PATCH 05/14] Try to resolve type synonyms - also for elements and table/view types --- lib/plsql/procedure.rb | 65 ++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 0f96d5e..a36e775 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -220,15 +220,15 @@ def get_argument_metadata_from_18c #:nodoc: @schema.select_all( "SELECT a.subprogram_id, a.object_name, TO_NUMBER(a.overload), a.argument_name, a.position, - a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale, a.char_used, - a.char_length, a.type_owner, nvl(a.type_subname, a.type_name) type_name, - case when a.type_object_type = 'PACKAGE' then a.type_name end type_package, a.type_object_type, a.defaulted, - s.table_owner synonym_owner, s.table_name synonym_name + a.data_type, a.in_out, a.data_length, a.data_precision, a.data_scale, a.char_used, + a.char_length, a.type_owner, nvl(a.type_subname, a.type_name) type_name, + case when a.type_object_type = 'PACKAGE' then a.type_name end type_package, a.type_object_type, a.defaulted, + s.table_owner synonym_owner, s.table_name synonym_name FROM all_arguments a LEFT JOIN all_synonyms s ON a.type_owner = s.owner AND a.type_name = s.synonym_name WHERE a.object_id = :object_id - AND a.owner = :owner - AND a.object_name = :procedure_name + AND a.owner = :owner + AND a.object_name = :procedure_name ORDER BY a.overload, a.sequence", @object_id, @schema_name, @procedure ) do |r| @@ -246,16 +246,21 @@ def get_argument_metadata_from_18c #:nodoc: @tmp_table_names[overload] ||= [] unless synonym_dest_owner.nil? - puts 'Synonym not nil' + #puts 'Synonym not nil' @schema.select_all( "SELECT o.owner, o.object_name, o.object_type FROM all_objects o - WHERE o.owner = :synonym_owner - AND o.object_name = :synonym_name - AND o.object_type = 'PACKAGE'", + WHERE o.owner = :synonym_owner + AND o.object_name = :synonym_name + AND o.object_type IN ('PACKAGE', 'TYPE')", synonym_dest_owner, synonym_dest_name ) do |r2| - type_owner, type_package, type_object_type = r2 + tmp_owner, tmp_name, tmp_type = r2 + if tmp_type == 'PACKAGE' + type_owner, type_package, type_object_type = tmp_owner, tmp_name, tmp_type + else + type_owner, type_name, type_object_type = tmp_owner, tmp_name, tmp_type + end end end @@ -363,15 +368,22 @@ def build_sql_type_name(type_owner, type_package, type_name) #:nodoc: end def get_field_definitions(argument_metadata) #:nodoc: + puts "#### get_field_definitions: #{argument_metadata[:type_object_type]}, #{argument_metadata[:type_owner]}, #{argument_metadata[:type_subname]}, #{argument_metadata[:type_name]}" fields = {} case argument_metadata[:type_object_type] when "PACKAGE" @schema.select_all( - "SELECT attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, length, precision, scale, char_used - FROM ALL_PLSQL_TYPES t, ALL_PLSQL_TYPE_ATTRS ta - WHERE t.OWNER = :owner AND t.type_name = :type_name AND t.package_name = :package_name - AND ta.OWNER = t.owner AND ta.TYPE_NAME = t.TYPE_NAME AND ta.PACKAGE_NAME = t.PACKAGE_NAME - ORDER BY attr_no", + "SELECT ta.attr_no, ta.attr_name, + nvl(s.table_owner, attr_type_owner) attr_type_owner, + CASE WHEN ta.attr_type_package IS NOT NULL THEN ta.attr_type_name ELSE nvl(s.table_name, ta.attr_type_name) END attr_type_name, + CASE WHEN ta.attr_type_package IS NOT NULL THEN nvl(s.table_name, ta.attr_type_package) END attr_type_package, + ta.length, ta.precision, ta.scale, ta.char_used + FROM all_plsql_type_attrs ta + LEFT JOIN all_synonyms s ON ta.attr_type_owner = s.owner AND nvl(ta.attr_type_package, ta.attr_type_name) = s.synonym_name + WHERE ta.owner = :owner + AND ta.type_name = :type_name + AND ta.package_name = :package_name + ORDER BY ta.attr_no", @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname]) do |r| attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, attr_length, attr_precision, attr_scale, attr_char_used = r @@ -426,14 +438,21 @@ def get_field_definitions(argument_metadata) #:nodoc: end def get_element_definition(argument_metadata) #:nodoc: + puts "#### get_element_definition: #{argument_metadata[:type_object_type]}, #{argument_metadata[:type_owner]}, #{argument_metadata[:type_subname]}, #{argument_metadata[:type_name]}" element_metadata = {} if collection_type?(argument_metadata[:data_type]) case argument_metadata[:type_object_type] when "PACKAGE" r = @schema.select_first( - "SELECT elem_type_owner, elem_type_name, elem_type_package, length, precision, scale, char_used, index_by - FROM ALL_PLSQL_COLL_TYPES t - WHERE t.OWNER = :owner AND t.TYPE_NAME = :type_name AND t.PACKAGE_NAME = :package_name", + "SELECT nvl(s.table_owner, t.elem_type_owner) elem_type_owner, + CASE WHEN t.elem_type_package IS NOT NULL THEN t.elem_type_name ELSE nvl(s.table_name, t.elem_type_name) END elem_type_name, + CASE WHEN t.elem_type_package IS NOT NULL THEN nvl(s.table_name, t.elem_type_package) END elem_type_package_new, + length, precision, scale, char_used, index_by + FROM all_plsql_coll_types t + LEFT JOIN all_synonyms s ON t.elem_type_owner = s.owner AND nvl(t.elem_type_package, t.elem_type_name) = s.synonym_name + WHERE t.owner = :owner + AND t.type_name = :type_name + AND t.package_name = :package_name", @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname]) elem_type_owner, elem_type_name, elem_type_package, elem_length, elem_precision, elem_scale, elem_char_used, index_by = r @@ -468,9 +487,11 @@ def get_element_definition(argument_metadata) #:nodoc: end when "TYPE" r = @schema.select_first( - "SELECT elem_type_owner, elem_type_name, length, precision, scale, char_used - FROM ALL_COLL_TYPES t - WHERE t.owner = :owner AND t.TYPE_NAME = :type_name", + "SELECT nvl(s.table_owner, t.elem_type_owner), nvl(s.table_name, t.elem_type_name), t.length, t.precision, t.scale, t.char_used + FROM all_coll_types t + LEFT JOIN all_synonyms s ON t.elem_type_owner = s.owner AND t.elem_type_name = s.synonym_name + WHERE t.owner = :owner + AND t.type_name = :type_name", @schema_name, argument_metadata[:type_name] ) elem_type_owner, elem_type_name, elem_length, elem_precision, elem_scale, elem_char_used = r From 244bcd6ceff4689c10ef31d92e00aaed6b9361e1 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Tue, 12 Oct 2021 18:09:37 +0200 Subject: [PATCH 06/14] Allow variable declarations that do not end with a semicolon --- lib/plsql/variable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plsql/variable.rb b/lib/plsql/variable.rb index 33825de..9aa254d 100644 --- a/lib/plsql/variable.rb +++ b/lib/plsql/variable.rb @@ -9,7 +9,7 @@ def find(schema, variable, package, override_schema_name = nil) AND type = 'PACKAGE' AND UPPER(text) LIKE :variable_name", override_schema_name || schema.schema_name, package, "%#{variable_upcase}%").each do |row| - if row[0] =~ /^\s*#{variable_upcase}\s+(CONSTANT\s+)?([A-Z0-9_. %]+(\([\w\s,]+\))?)\s*(NOT\s+NULL)?\s*((:=|DEFAULT).*)?;\s*(--.*)?$/i + if row[0] =~ /^\s*#{variable_upcase}\s+(CONSTANT\s+)?([A-Z0-9_. %]+(\([\w\s,]+\))?)\s*(NOT\s+NULL)?\s*((:=|DEFAULT).*)?;?\s*(--.*)?$/i return new(schema, variable, package, $2.strip, override_schema_name) end end From 00ebb3dafc549092a8d6e2b9666e60aa79f5ff57 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Wed, 13 Oct 2021 13:07:52 +0200 Subject: [PATCH 07/14] 18c: Resolve %ROWTYPE within an element --- lib/plsql/procedure.rb | 88 ++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 20 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index c9ec875..4baab72 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -425,26 +425,74 @@ def get_element_definition(argument_metadata) #:nodoc: raise ArgumentError, "Index-by Varchar-Table (associative array) #{argument_metadata[:type_name]} is not supported" end - element_metadata = { - position: 1, - data_type: if elem_type_owner == nil - elem_type_name - else - elem_type_package != nil ? "PL/SQL RECORD" : "OBJECT" - end, - in_out: argument_metadata[:in_out], - data_length: elem_length && elem_length.to_i, - data_precision: elem_precision && elem_precision.to_i, - data_scale: elem_scale && elem_scale.to_i, - char_used: elem_char_used, - char_length: elem_char_used && elem_length && elem_length.to_i, - type_owner: elem_type_owner, - type_name: elem_type_name, - type_subname: elem_type_package, - sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, elem_type_package, elem_type_name), - type_object_type: elem_type_package != nil ? "PACKAGE" : nil, - defaulted: argument_metadata[:defaulted] - } + if elem_type_name.match('%ROWTYPE') + fields = {} + @schema.select_all( + "select column_id, column_name, data_type, data_length, data_precision, data_scale, char_used, char_length + FROM all_tab_columns + where owner = :owner and table_name = :table_name + order by column_id", + elem_type_owner, elem_type_name.sub('%ROWTYPE', '')) do |r| + + rowtype_column_id, rowtype_column_name, rowtype_data_type, rowtype_data_length, rowtype_data_precision, rowtype_data_scale, rowtype_char_used, rowtype_char_length = r + + fields[rowtype_column_name.downcase.to_sym] = { + position: rowtype_column_id.to_i, + data_type: rowtype_data_type, + in_out: 'OUT', + data_length: rowtype_data_length && rowtype_data_length.to_i, + data_precision: rowtype_data_precision && rowtype_data_precision.to_i, + data_scale: rowtype_data_scale && rowtype_data_scale.to_i, + char_used: rowtype_char_used == nil ? "0" : rowtype_char_used, + char_length: rowtype_char_length && rowtype_data_length && rowtype_data_length.to_i, + type_owner: nil, + type_name: nil, + type_subname: nil, + sql_type_name: nil, + defaulted: 'N' + } + end + element_metadata = { + position: 1, + data_type: "PL/SQL RECORD", + in_out: argument_metadata[:in_out], + data_length: elem_length && elem_length.to_i, + data_precision: elem_precision && elem_precision.to_i, + data_scale: elem_scale && elem_scale.to_i, + char_used: elem_char_used, + char_length: elem_char_used && elem_length && elem_length.to_i, + type_owner: elem_type_owner, + type_name: elem_type_name, + type_subname: elem_type_package, + sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, elem_type_package, elem_type_name), + type_object_type: elem_type_package != nil ? "PACKAGE" : nil, + defaulted: argument_metadata[:defaulted], + fields: fields + } + else + element_metadata = { + position: 1, + data_type: if elem_type_owner == nil + elem_type_name + elsif elem_type_package != nil + "PL/SQL RECORD" + else + "OBJECT" + end, + in_out: argument_metadata[:in_out], + data_length: elem_length && elem_length.to_i, + data_precision: elem_precision && elem_precision.to_i, + data_scale: elem_scale && elem_scale.to_i, + char_used: elem_char_used, + char_length: elem_char_used && elem_length && elem_length.to_i, + type_owner: elem_type_owner, + type_name: elem_type_name, + type_subname: elem_type_package, + sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, elem_type_package, elem_type_name), + type_object_type: elem_type_package != nil ? "PACKAGE" : nil, + defaulted: argument_metadata[:defaulted] + } + end if elem_type_package != nil element_metadata[:fields] = get_field_definitions(element_metadata) From de8b2e570121979a3ad2cacc614c7775f80299c9 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Wed, 13 Oct 2021 15:22:20 +0200 Subject: [PATCH 08/14] Exclude hidden columns --- lib/plsql/procedure.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 835f5af..32db848 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -412,6 +412,7 @@ def get_field_definitions(argument_metadata) #:nodoc: @schema.select_all( "SELECT column_id, column_name, data_type, data_length, data_precision, data_scale, char_length, char_used FROM ALL_TAB_COLS WHERE OWNER = :owner AND TABLE_NAME = :type_name + AND hidden_column != 'YES' ORDER BY column_id", argument_metadata[:type_owner], argument_metadata[:type_name]) do |r| From 54429b57b7bd771cabe6956c82ad5d053d21ca79 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Wed, 13 Oct 2021 15:24:45 +0200 Subject: [PATCH 09/14] Fix "no implicit conversion of Time into String" if column data type is "timestamp(6) with local timezone"; before 18c, this was represented as "timestamp with local timezone" --- lib/plsql/procedure.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 32db848..da14f49 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -418,6 +418,9 @@ def get_field_definitions(argument_metadata) #:nodoc: col_no, col_name, col_type_name, col_length, col_precision, col_scale, col_char_length, col_char_used = r + if col_type_name.match('TIMESTAMP\(\d+\) WITH LOCAL TIME ZONE') + col_type_name = 'TIMESTAMP WITH LOCAL TIME ZONE' + end fields[col_name.downcase.to_sym] = { position: col_no.to_i, data_type: col_type_name, From d0d5bebbe18124a3af3b8732d866413c1bc08531 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Wed, 13 Oct 2021 13:07:52 +0200 Subject: [PATCH 10/14] 18c: Resolve %ROWTYPE within an element --- lib/plsql/procedure.rb | 90 ++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 21 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index c9ec875..1a741b4 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -367,7 +367,7 @@ def get_field_definitions(argument_metadata) #:nodoc: data_precision: attr_precision && attr_precision.to_i, data_scale: attr_scale && attr_scale.to_i, char_used: attr_char_used == nil ? "0" : attr_char_used, - char_length: attr_char_used && attr_length && attr_length.to_i, + char_length: attr_char_used && attr_char_used.to_i, type_owner: attr_type_owner, type_name: attr_type_owner && attr_type_name, type_subname: attr_type_package, @@ -425,26 +425,74 @@ def get_element_definition(argument_metadata) #:nodoc: raise ArgumentError, "Index-by Varchar-Table (associative array) #{argument_metadata[:type_name]} is not supported" end - element_metadata = { - position: 1, - data_type: if elem_type_owner == nil - elem_type_name - else - elem_type_package != nil ? "PL/SQL RECORD" : "OBJECT" - end, - in_out: argument_metadata[:in_out], - data_length: elem_length && elem_length.to_i, - data_precision: elem_precision && elem_precision.to_i, - data_scale: elem_scale && elem_scale.to_i, - char_used: elem_char_used, - char_length: elem_char_used && elem_length && elem_length.to_i, - type_owner: elem_type_owner, - type_name: elem_type_name, - type_subname: elem_type_package, - sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, elem_type_package, elem_type_name), - type_object_type: elem_type_package != nil ? "PACKAGE" : nil, - defaulted: argument_metadata[:defaulted] - } + if elem_type_name.match('%ROWTYPE') + fields = {} + @schema.select_all( + "select column_id, column_name, data_type, data_length, data_precision, data_scale, char_used, char_length + FROM all_tab_columns + where owner = :owner and table_name = :table_name + order by column_id", + elem_type_owner, elem_type_name.sub('%ROWTYPE', '')) do |r| + + rowtype_column_id, rowtype_column_name, rowtype_data_type, rowtype_data_length, rowtype_data_precision, rowtype_data_scale, rowtype_char_used, rowtype_char_length = r + + fields[rowtype_column_name.downcase.to_sym] = { + position: rowtype_column_id.to_i, + data_type: rowtype_data_type, + in_out: 'OUT', + data_length: rowtype_data_length && rowtype_data_length.to_i, + data_precision: rowtype_data_precision && rowtype_data_precision.to_i, + data_scale: rowtype_data_scale && rowtype_data_scale.to_i, + char_used: rowtype_char_used == nil ? "0" : rowtype_char_used, + char_length: rowtype_char_length && rowtype_char_length.to_i, + type_owner: nil, + type_name: nil, + type_subname: nil, + sql_type_name: nil, + defaulted: 'N' + } + end + element_metadata = { + position: 1, + data_type: "PL/SQL RECORD", + in_out: argument_metadata[:in_out], + data_length: elem_length && elem_length.to_i, + data_precision: elem_precision && elem_precision.to_i, + data_scale: elem_scale && elem_scale.to_i, + char_used: elem_char_used, + char_length: elem_char_used && elem_length && elem_length.to_i, + type_owner: elem_type_owner, + type_name: elem_type_name, + type_subname: elem_type_package, + sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, elem_type_package, elem_type_name), + type_object_type: elem_type_package != nil ? "PACKAGE" : nil, + defaulted: argument_metadata[:defaulted], + fields: fields + } + else + element_metadata = { + position: 1, + data_type: if elem_type_owner == nil + elem_type_name + elsif elem_type_package != nil + "PL/SQL RECORD" + else + "OBJECT" + end, + in_out: argument_metadata[:in_out], + data_length: elem_length && elem_length.to_i, + data_precision: elem_precision && elem_precision.to_i, + data_scale: elem_scale && elem_scale.to_i, + char_used: elem_char_used, + char_length: elem_char_used && elem_length && elem_length.to_i, + type_owner: elem_type_owner, + type_name: elem_type_name, + type_subname: elem_type_package, + sql_type_name: elem_type_owner && build_sql_type_name(elem_type_owner, elem_type_package, elem_type_name), + type_object_type: elem_type_package != nil ? "PACKAGE" : nil, + defaulted: argument_metadata[:defaulted] + } + end if elem_type_package != nil element_metadata[:fields] = get_field_definitions(element_metadata) From 2eedc94c090bd3a14ec6fe9105716dbbd5867fb0 Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Wed, 13 Oct 2021 20:35:59 +0200 Subject: [PATCH 11/14] Make char length determination consistent --- lib/plsql/procedure.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 33a9de1..d50120b 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -160,7 +160,7 @@ def get_argument_metadata_below_18c #:nodoc: data_precision: data_precision && data_precision.to_i, data_scale: data_scale && data_scale.to_i, char_used: char_used, - char_length: char_length && char_length.to_i, + char_length: char_used && char_length && char_length.to_i, type_owner: type_owner, type_name: type_name, type_subname: type_subname, @@ -282,7 +282,7 @@ def get_argument_metadata_from_18c #:nodoc: data_precision: data_precision && data_precision.to_i, data_scale: data_scale && data_scale.to_i, char_used: char_used, - char_length: char_length && char_length.to_i, + char_length: char_used && char_length && char_length.to_i, type_owner: type_owner, type_name: type_name, # TODO: should be renamed to type_package, when support for legacy database versions is dropped @@ -396,7 +396,7 @@ def get_field_definitions(argument_metadata) #:nodoc: data_precision: attr_precision && attr_precision.to_i, data_scale: attr_scale && attr_scale.to_i, char_used: attr_char_used == nil ? "0" : attr_char_used, - char_length: attr_char_used && attr_char_used.to_i, + char_length: attr_char_used && attr_length && attr_length.to_i, type_owner: attr_type_owner, type_name: attr_type_owner && attr_type_name, type_subname: attr_type_package, @@ -429,7 +429,7 @@ def get_field_definitions(argument_metadata) #:nodoc: data_precision: col_precision && col_precision.to_i, data_scale: col_scale && col_scale.to_i, char_used: col_char_used == nil ? "0" : col_char_used, - char_length: col_char_length && col_char_length.to_i, + char_length: col_char_used && col_char_length && col_char_length.to_i, type_owner: nil, type_name: nil, type_subname: nil, @@ -484,7 +484,7 @@ def get_element_definition(argument_metadata) #:nodoc: data_precision: rowtype_data_precision && rowtype_data_precision.to_i, data_scale: rowtype_data_scale && rowtype_data_scale.to_i, char_used: rowtype_char_used == nil ? "0" : rowtype_char_used, - char_length: rowtype_char_length && rowtype_char_length.to_i, + char_length: rowtype_char_used && rowtype_char_length && rowtype_char_length.to_i, type_owner: nil, type_name: nil, type_subname: nil, From 403ef6a867eb37b2338feee913721f405ad4329e Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Thu, 14 Oct 2021 13:29:39 +0200 Subject: [PATCH 12/14] Try to fix nested types - type declared inside a package, referencing a schema-level table type --- lib/plsql/procedure.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index d50120b..f2e52e4 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -388,9 +388,17 @@ def get_field_definitions(argument_metadata) #:nodoc: attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, attr_length, attr_precision, attr_scale, attr_char_used = r + composite_type = nil + if attr_type_owner != nil + if attr_type_package != nil + composite_type = get_composite_type(attr_type_owner, attr_type_name, attr_type_package) + else + composite_type = 'TABLE' + end + end fields[attr_name.downcase.to_sym] = { position: attr_no.to_i, - data_type: attr_type_owner == nil ? attr_type_name : get_composite_type(attr_type_owner, attr_type_name, attr_type_package), + data_type: attr_type_owner == nil ? attr_type_name : composite_type, in_out: argument_metadata[:in_out], data_length: attr_length && attr_length.to_i, data_precision: attr_precision && attr_precision.to_i, @@ -401,8 +409,12 @@ def get_field_definitions(argument_metadata) #:nodoc: type_name: attr_type_owner && attr_type_name, type_subname: attr_type_package, sql_type_name: attr_type_owner && build_sql_type_name(attr_type_owner, attr_type_package, attr_type_name), - defaulted: argument_metadata[:defaulted] + defaulted: argument_metadata[:defaulted], + type_object_type: composite_type && composite_type == 'TABLE' ? 'TYPE' : nil } + if composite_type == 'TABLE' + fields[attr_name.downcase.to_sym][:element] = get_element_definition(fields[attr_name.downcase.to_sym]) + end if fields[attr_name.downcase.to_sym][:data_type] == "TABLE" && fields[attr_name.downcase.to_sym][:type_subname] != nil fields[attr_name.downcase.to_sym][:fields] = get_field_definitions(fields[attr_name.downcase.to_sym]) @@ -509,7 +521,7 @@ def get_element_definition(argument_metadata) #:nodoc: defaulted: argument_metadata[:defaulted], fields: fields } - else + else element_metadata = { position: 1, data_type: if elem_type_owner == nil From cbdc13fe7c18759f53ad435000c033c147b5a5dd Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Fri, 15 Oct 2021 12:24:10 +0200 Subject: [PATCH 13/14] Map new PL/SQL types to old types --- lib/plsql/procedure.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index f2e52e4..72a28b0 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -388,6 +388,9 @@ def get_field_definitions(argument_metadata) #:nodoc: attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, attr_length, attr_precision, attr_scale, attr_char_used = r + attr_type_name = 'PLS_INTEGER' if attr_type_name == 'PL/SQL PLS INTEGER' + attr_type_name = 'BINARY_INTEGER' if attr_type_name == 'PL/SQL BINARY INTEGER' + composite_type = nil if attr_type_owner != nil if attr_type_package != nil From 0409a090712488185711c07920bf38b488ad019c Mon Sep 17 00:00:00 2001 From: Jochen Schug <4573581+joschug@users.noreply.github.com> Date: Wed, 20 Oct 2021 10:36:26 +0200 Subject: [PATCH 14/14] Remove debug output --- lib/plsql/procedure.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index a36e775..8415aae 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -246,7 +246,6 @@ def get_argument_metadata_from_18c #:nodoc: @tmp_table_names[overload] ||= [] unless synonym_dest_owner.nil? - #puts 'Synonym not nil' @schema.select_all( "SELECT o.owner, o.object_name, o.object_type FROM all_objects o @@ -368,7 +367,6 @@ def build_sql_type_name(type_owner, type_package, type_name) #:nodoc: end def get_field_definitions(argument_metadata) #:nodoc: - puts "#### get_field_definitions: #{argument_metadata[:type_object_type]}, #{argument_metadata[:type_owner]}, #{argument_metadata[:type_subname]}, #{argument_metadata[:type_name]}" fields = {} case argument_metadata[:type_object_type] when "PACKAGE" @@ -438,7 +436,6 @@ def get_field_definitions(argument_metadata) #:nodoc: end def get_element_definition(argument_metadata) #:nodoc: - puts "#### get_element_definition: #{argument_metadata[:type_object_type]}, #{argument_metadata[:type_owner]}, #{argument_metadata[:type_subname]}, #{argument_metadata[:type_name]}" element_metadata = {} if collection_type?(argument_metadata[:data_type]) case argument_metadata[:type_object_type]