diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 8002fcf..25f6b33 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -460,6 +460,23 @@ def get_element_definition(argument_metadata) # :nodoc: if elem_type_package != nil element_metadata[:fields] = get_field_definitions(element_metadata) + elsif elem_type_name && elem_type_name =~ /\A(.+)%ROWTYPE\z/ + # TABLE OF table%ROWTYPE: Oracle stores elem_type_name as "TABLE_NAME%ROWTYPE" + rowtype_table_name = $1 + check_owner = elem_type_owner || @schema_name + object_type_row = @schema.select_first( + "SELECT object_type FROM ALL_OBJECTS WHERE owner = :owner AND object_name = :name AND object_type IN ('TABLE', 'VIEW')", + check_owner, rowtype_table_name) + if object_type_row + element_metadata[:type_owner] ||= check_owner + element_metadata[:type_name] = rowtype_table_name + element_metadata[:sql_type_name] = build_sql_type_name(check_owner, nil, rowtype_table_name) + element_metadata[:data_type] = "PL/SQL RECORD" + element_metadata[:type_object_type] = object_type_row[0] + element_metadata[:fields] = get_field_definitions(element_metadata) + else + raise ArgumentError, "Could not resolve #{check_owner}.#{rowtype_table_name} to a table or view for #{elem_type_name}" + end end when "TYPE" r = @schema.select_first( diff --git a/spec/plsql/procedure_spec.rb b/spec/plsql/procedure_spec.rb index ec0d344..581c32e 100644 --- a/spec/plsql/procedure_spec.rb +++ b/spec/plsql/procedure_spec.rb @@ -2426,3 +2426,69 @@ def new_candidate(status) expect(field_names.none? { |name| name.to_s.start_with?("sys_nc") }).to be true end end + +describe "Function with TABLE OF %ROWTYPE parameter defined in package" do + before(:all) do + plsql.connect! CONNECTION_PARAMS + plsql.execute "DROP PACKAGE test_rowtype_pkg" rescue nil + plsql.execute "DROP TABLE test_rowtype_tbl" rescue nil + plsql.execute "CREATE TABLE test_rowtype_tbl (id NUMBER, name VARCHAR2(50))" + plsql.execute <<-SQL + CREATE OR REPLACE PACKAGE test_rowtype_pkg IS + TYPE t_tab IS TABLE OF test_rowtype_tbl%ROWTYPE; + FUNCTION test_fn(p_tab IN t_tab) RETURN NUMBER; + END; + SQL + plsql.execute <<-SQL + CREATE OR REPLACE PACKAGE BODY test_rowtype_pkg IS + FUNCTION test_fn(p_tab IN t_tab) RETURN NUMBER IS + BEGIN + RETURN p_tab.COUNT; + END; + END; + SQL + end + + after(:all) do + plsql.execute "DROP PACKAGE test_rowtype_pkg" rescue nil + plsql.execute "DROP TABLE test_rowtype_tbl" rescue nil + plsql.logoff + end + + it "should execute function with TABLE OF %ROWTYPE parameter" do + result = plsql.test_rowtype_pkg.test_fn([{ id: 1, name: "test" }]) + expect(result).to eq(1) + end +end + +describe "Function with TABLE OF RECORD parameter defined in package (workaround for %ROWTYPE)" do + before(:all) do + plsql.connect! CONNECTION_PARAMS + plsql.execute "DROP PACKAGE test_record_pkg" rescue nil + plsql.execute <<-SQL + CREATE OR REPLACE PACKAGE test_record_pkg IS + TYPE t_rec IS RECORD (id NUMBER, name VARCHAR2(50)); + TYPE t_tab IS TABLE OF t_rec; + FUNCTION test_fn(p_tab IN t_tab) RETURN NUMBER; + END; + SQL + plsql.execute <<-SQL + CREATE OR REPLACE PACKAGE BODY test_record_pkg IS + FUNCTION test_fn(p_tab IN t_tab) RETURN NUMBER IS + BEGIN + RETURN p_tab.COUNT; + END; + END; + SQL + end + + after(:all) do + plsql.execute "DROP PACKAGE test_record_pkg" rescue nil + plsql.logoff + end + + it "should execute function with TABLE OF RECORD parameter" do + result = plsql.test_record_pkg.test_fn([{ id: 1, name: "test" }]) + expect(result).to eq(1) + end +end