PL/SQL Function Return View RowType internal exception - oracle

I have the below function which compiles. DOC_ISSUE_REFERENCE STANDS for a VIEW
CREATE OR REPLACE
PACKAGE BODY INHOUSE_CUST_API
AS
FUNCTION Get_Budget_Doc(
company IN VARCHAR2,
budget_process_id IN VARCHAR2,
budget_ptemplate_id IN VARCHAR2)
RETURN DOC_ISSUE_REFERENCE%ROWTYPE
IS
enhDocItem ENHANCED_DOC_REFERENCE_OBJECT%ROWTYPE;
docKeyValue VARCHAR2(150);
docIssueRef DOC_ISSUE_REFERENCE%ROWTYPE;
BEGIN
docKeyValue := company||'^'||budget_process_id||'^'||budget_ptemplate_id||'^';
-- dbms_output.put_line(docKeyValue);
SELECT *
INTO enhDocItem
FROM ENHANCED_DOC_REFERENCE_OBJECT
WHERE KEY_VALUE= docKeyValue;
SELECT *
INTO docIssueRef
FROM DOC_ISSUE_REFERENCE
WHERE DOC_NO = enhDocItem.DOC_NO;
RETURN docIssueRef;
END Get_Budget_Doc;
END INHOUSE_CUST_API;
the point here that when I call the function I receive
ORA-06553: PLS-801: internal error [55018]
06553. 00000 - "PLS-%s: %s"
*Cause:
*Action:
which does not show any thing or help. I am sure that both selects return 1 row only. any help is appreciated

this is my solution depending on Ilia Maskov comment
the package is
create or replace
PACKAGE INHOUSE_CUST_API
AS
TYPE doc_rec
IS
RECORD
(
doc_Title doc_issue_reference.title%Type,
doc_Number DOC_ISSUE_REFERENCE.DOC_NO%TYPE,
doc_Type DOC_ISSUE_REFERENCE.FILE_TYPE%TYPE,
doc_FileName DOC_ISSUE_REFERENCE.FILE_NAME%TYPE,
doc_Path DOC_ISSUE_REFERENCE.PATH%TYPE);
TYPE doc_rec_tab IS TABLE OF doc_rec;
FUNCTION Get_Budget_Doc(
company IN VARCHAR2,
budget_process_id IN VARCHAR2,
budget_ptemplate_id IN VARCHAR2)
RETURN doc_rec_tab PIPELINED;
END INHOUSE_CUST_API;
and the body is
create or replace
PACKAGE BODY INHOUSE_CUST_API
AS
FUNCTION Get_Budget_Doc(
company IN VARCHAR2,
budget_process_id IN VARCHAR2,
budget_ptemplate_id IN VARCHAR2)
RETURN doc_rec_tab PIPELINED
IS
enhDocItem ENHANCED_DOC_REFERENCE_OBJECT%ROWTYPE;
-- docIssueRef DOC_ISSUE_REFERENCE%ROWTYPE;
docKeyValue ENHANCED_DOC_REFERENCE_OBJECT.KEY_VALUE%TYPE;
docIssueRef_rec doc_rec;
docTable doc_rec_tab;
BEGIN
docKeyValue := company||'^'||budget_process_id||'^'||budget_ptemplate_id||'^';
<<outer_loop>>
FOR doc_no_rec IN (SELECT DOC_NO FROM ENHANCED_DOC_REFERENCE_OBJECT WHERE KEY_VALUE= docKeyValue) LOOP
--dbms_output.put_line(doc_no_rec.rownum);
<<inner_loop>>
FOR rec_ IN(SELECT Title, DOC_NO,FILE_TYPE,FILE_NAME,PATH FROM DOC_ISSUE_REFERENCE WHERE DOC_NO = doc_no_rec.DOC_NO) LOOP
PIPE row(rec_);
END LOOP inner_loop;
END LOOP outer_loop;
RETURN;
END Get_Budget_Doc;
END INHOUSE_CUST_API;

Related

Pipelining Between PL/SQL Table Functions

I have a package with 2 pipelined functions. When I'm trying to call one function with another function as it's argument I'm getting "ORA-06553: PLS-306: wrong number or types of arguments in call" error.
Here is the package:
create or replace NONEDITIONABLE TYPE RESULTING_RECORD_RT as object
(
CALENDAR NVARCHAR2(1024),
PRODUCT NVARCHAR2(1024),
MEASURE NVARCHAR2(1024),
VALUE NUMBER
);
/
create or replace NONEDITIONABLE TYPE RESULTING_COLS_RT IS TABLE OF RESULTING_RECORD_RT;
/
create or replace package pipe_pkg as
function pipe_func_emp return RESULTING_COLS_RT PIPELINED;
function pipe_func_emp2(input_Set IN resulting_cols_rt) return RESULTING_COLS_RT PIPELINED;
end;
/
create or replace package body pipe_pkg as
function pipe_func_emp return RESULTING_COLS_RT
PIPELINED
is
test_tbl resulting_cols_rt:= resulting_cols_rt();
begin
test_tbl.extend;
test_tbl(1):=resulting_record_rt('A','B','C',1);
test_tbl.extend;
test_tbl(2):=resulting_record_rt('A','B','D',2);
PIPE ROW(test_tbl(1));
PIPE ROW(test_tbl(2));
return;
end;
function pipe_func_emp2(input_Set IN resulting_cols_rt) return RESULTING_COLS_RT
PIPELINED
is
v_tmp NVARCHAR2(10240);
l_res SYS_REFCURSOR;
recs resulting_record_rt;
begin
open l_res for select * from table(input_Set);
loop
fetch l_res into recs;
PIPE ROW(recs);
exit when l_res%notfound;
end loop;
close l_res;
return;
end;
end;
/
I'm calling the functions as follows:
select * from TABLE(pipe_pkg.pipe_func_emp2(CURSOR(select * from TABLE(pipe_pkg.pipe_func_emp()))));
And the call throws error:
ORA-06553: PLS-306: wrong number or types of arguments in call to 'PIPE_FUNC_EMP2'
06553. 00000 - "PLS-%s: %s"
What am I doing wrong?
The function pipe_func_emp2 expected RESULTING_COLS_RT as it's argument, but got REF CURSOR. These are incompatible types.
Try following reproducible example of a chaining of the pipelined functions:
create or replace type somerow as object (id int, val varchar2 (8))
/
create or replace type sometab is table of somerow
/
create or replace package pack as
function func1 return sometab pipelined;
function func2 (cur sys_refcursor) return sometab pipelined;
end;
/
create or replace package body pack as
function func1 return sometab pipelined is
tab sometab := sometab (somerow (1,'AAA'), somerow (2,'BBB'));
begin
for i in 1..tab.count loop
pipe row (tab(i));
end loop;
return;
end;
function func2 (cur sys_refcursor) return sometab pipelined is
sr somerow;
begin
loop
fetch cur into sr;
exit when cur%notfound;
pipe row (sr);
end loop;
close cur;
return;
end;
end;
/
The query and it's outcome:
select *
from table (pack.func2 (
cursor (select value (p) from table (pack.func1()) p )))
/
ID VAL
---------- --------
1 AAA
2 BBB

PL/SQL Function return custom type exception

I have created a package which holds a custom type and a function that returns the custom type as below;
create or replace
PACKAGE INHOUSE_CUST_API
AS
TYPE doc_rec
IS
RECORD
(
doc_Title doc_issue_reference.title%Type,
doc_Number DOC_ISSUE_REFERENCE.DOC_NO%TYPE,
doc_Type DOC_ISSUE_REFERENCE.FILE_TYPE%TYPE,
doc_FileName DOC_ISSUE_REFERENCE.FILE_NAME%TYPE,
doc_Path DOC_ISSUE_REFERENCE.PATH%TYPE);
FUNCTION Get_Budget_Doc(
company IN VARCHAR2,
budget_process_id IN VARCHAR2,
budget_ptemplate_id IN VARCHAR2)
RETURN doc_rec;
END INHOUSE_CUST_API;
after that, I created the body of the function as below
create or replace
PACKAGE BODY INHOUSE_CUST_API
AS
FUNCTION Get_Budget_Doc(
company IN VARCHAR2,
budget_process_id IN VARCHAR2,
budget_ptemplate_id IN VARCHAR2)
RETURN doc_rec
IS
enhDocItem ENHANCED_DOC_REFERENCE_OBJECT%ROWTYPE;
docIssueRef DOC_ISSUE_REFERENCE%ROWTYPE;
docKeyValue VARCHAR2(150);
docIssueRef_rec doc_rec;
BEGIN
docKeyValue := company||'^'||budget_process_id||'^'||budget_ptemplate_id||'^';
--dbms_output.put_line(docKeyValue);
SELECT *
INTO enhDocItem
FROM ENHANCED_DOC_REFERENCE_OBJECT
WHERE KEY_VALUE= docKeyValue;
SELECT *
INTO docIssueRef
FROM DOC_ISSUE_REFERENCE
WHERE DOC_NO = enhDocItem.DOC_NO;
docIssueRef_rec.doc_Title :=docIssueRef.Title;
docIssueRef_rec.doc_Number:=docIssueRef.DOC_NO;
docIssueRef_rec.doc_Type :=docIssueRef.FILE_TYPE;
docIssueRef_rec.doc_Path :=docIssueRef.PATH;
RETURN docIssueRef_rec;
END Get_Budget_Doc;
END INHOUSE_CUST_API;
when I try to call the function as like
select INHOUSE_CUST_API.Get_Budget_Doc('param1','param2','param3') from dual;
I receive this exception
ORA-00902: invalid datatype
00902. 00000 - "invalid datatype"
*Cause:
*Action:
any help is appreciated.
You might want to use a table function to return your custom type. Here is a very simple example:
CREATE OR REPLACE PACKAGE brianl.deleteme AS
TYPE doc_rec_t IS RECORD
(
name VARCHAR2( 10 )
, age NUMBER( 3 )
);
TYPE doc_rec_tt IS TABLE OF doc_rec_t;
FUNCTION age( p_name IN VARCHAR2, p_age IN NUMBER, p_years IN INTEGER )
RETURN doc_rec_tt
PIPELINED;
END deleteme;
CREATE OR REPLACE PACKAGE BODY brianl.deleteme AS
FUNCTION age( p_name IN VARCHAR2, p_age IN NUMBER, p_years IN INTEGER )
RETURN doc_rec_tt
PIPELINED AS
l_ret doc_rec_t;
BEGIN
l_ret.name := p_name;
l_ret.age := p_age;
FOR i IN 1 .. p_years
LOOP
PIPE ROW (l_ret);
l_ret.age := l_ret.age + 1;
END LOOP;
END age;
END deleteme;
Invoke as follows:
SELECT * FROM TABLE( brianl.deleteme.age( 'Brian', 67, 3 ) );
The results:
NAME AGE
Brian 67
Brian 68
Brian 69
a SELECT statement in direct mode cann't return a complex data type like a record.

Error PLS-00103 when create package with Oracle

I'm trying create package with oracle, although I have read many examples in docs oracle and built code same this tutorial but I still error this.
The following code:
create table manage_emplyee
(
f_name varchar(20),
l_name varchar(20)
);
// Specification
create or replace package fn2
as
procedure manage_emplyee(v_fname in VARCHAR2, v_lname in VARCHAR2);
procedure manage_emplyee_delete(v_fname in VARCHAR2);
end;
/
create or replace package body fn2
as
--Procedure Implementation
procedure manage_emplyee(v_fname in VARCHAR2, v_lname in VARCHAR2)
is
begin
insert into manage_emplyee VALUES (v_lname, v_lname);
end manage_emplyee;
// body
procedure manage_emplyee_delete (v_fname in VARCHAR2)
is
begin
delete manage_emplyee where v_fname = v_fname;
end manage_emplyee_delete;
end fn2;
/
Error
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
begin end function pragma procedure
Please help me fix it, thanks so much !
There are many things incorrect, so here is a correct version.
Run the table script first -
create table manage_emplyee
(
f_name varchar(20),
l_name varchar(20)
);
Run the Spec script after that
create or replace package fn2
as
procedure manage_emplyee(v_fname VARCHAR2,
v_lname VARCHAR2);
procedure manage_emplyee_delete(v_fname VARCHAR2);
end;
/
Run the body script after that
create or replace package body fn2
as
procedure manage_emplyee(v_fname VARCHAR2, v_lname VARCHAR2)
is
begin
insert into manage_emplyee VALUES (v_lname, v_lname);
end ;
procedure manage_emplyee_delete (v_fname VARCHAR2)
is
begin
delete from manage_emplyee where f_name = v_fname;
end ;
end;
/
The syntax for delete from table_name was incorrect.
I am sure, you want to match f_name from table with v_fname from the input variable to delete the data. Earlier you were matching v_fname with v_fname in your code, which will always be true (except for when its passed NULL) and you would end up loosing all your test data
*NOTE -
Adding IN explicitly is not required, the default type is IN for parameters in PLSQL procedures

PL/SQL Return Types of Result Set Variables or Query Do Not Match

I am trying to use a GET stored procedure/cursor to show the GAME NAME of a Lottery Game Table I created in a lottery game database.
Here is the code:
CREATE OR REPLACE PROCEDURE GetLotteryGameName (
p_lgid IN NUMBER,
p_value out VARCHAR2,
p_field IN VARCHAR2
)
IS
BEGIN
SELECT GAMENAME
INTO p_value
FROM LOTTERYGAME
WHERE LOTTERYGAMEID = p_lgid;
END GetLotteryGameName;
CREATE OR REPLACE PACKAGE GETLOTTERYGAMENAMEPKG IS
PROCEDURE GetLotteryGameName (
p_lgid IN NUMBER,
p_value out VARCHAR2,
p_field IN VARCHAR2
);
TYPE per_ref_cursor IS REF CURSOR;
PROCEDURE GetGameName (p_lgid IN NUMBER, p_ref OUT per_ref_cursor);
END GETLOTTERYGAMENAMEPKG;
CREATE OR REPLACE PACKAGE BODY GETLOTTERYGAMENAMEPKG IS
PROCEDURE GetLotteryGameName (
p_lgid IN NUMBER,
p_value out VARCHAR2,
p_field IN VARCHAR2
)
IS
BEGIN
SELECT GAMENAME
INTO p_value
FROM LOTTERYGAME
WHERE LOTTERYGAMEID = p_lgid;
END GetLotteryGameName;
PROCEDURE GetName
(p_lgid IN NUMBER,
p_ref OUT per_ref_cursor) IS
BEGIN
OPEN p_ref FOR
SELECT GAMENAME
FROM LOTTERYGAME
WHERE LOTTERYGAMEID = p_lgid;
END GetName;
END GETLOTTERYGAMENAMEPKG;
DECLARE
v_cursor GETLOTTERYGAMENAMEPKG.per_ref_cursor;
v_lgid LOTTERYGAME.LOTTERYGAMEID%TYPE;
v_gamename LOTTERYGAME.GAMENAME%TYPE;
BEGIN
GETLOTTERYGAMENAMEPKG.GetName (p_lgid = 2,
p_ref => v_cursor);
LOOP
FETCH v_cursor
INTO v_lgid, v_gamename;
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_lgid || ',' || v_gamename);
END LOOP;
CLOSE v_cursor;
END;
When I run the above declare statement, I get the following error:
06504. 00000 - "PL/SQL: Return types of Result Set variables or query do not match"
*Cause: Number and/or types of columns in a query does not match declared
return type of a result set variable, or declared types of two Result
Set variables do not match.
I know there is an error somewhere in this code, I just don't know what I'm looking for, or how to set myself up to avoid future failures like this.
Any help is much appreciated,
Cheers,
FBF
As the error says, you SELECT only GAMENAME in your SELECT but attempt to put into v_lgid, v_gamename.
So adding LOTTERYGAMEID to your CURSOR's SELECT
Or Change your anonymous block.
PROCEDURE GetName
(p_lgid IN NUMBER,
p_ref OUT per_ref_cursor) IS
BEGIN
OPEN p_ref FOR
SELECT GAMENAME,LOTTERYGAMEID
FROM LOTTERYGAME
WHERE LOTTERYGAMEID = p_lgid;
END GetName;
You should also correct the syntax error in:
GETLOTTERYGAMENAMEPKG.GetName (p_lgid = 2,
p_ref => v_cursor);
which should read
GETLOTTERYGAMENAMEPKG.GetName (p_lgid => 2,
p_ref => v_cursor);
Share and enjoy.

How to call an Oracle PL/SQL object super method

I'd like to call an overridden PL/SQL method. Here's an example:
-- super class
create or replace type test as object
(
n number,
member procedure proc(SELF in out nocopy test, s varchar2)
)
alter type test not final
/
create or replace type body test is
member procedure proc(SELF in out nocopy test, s varchar2) is
begin
dbms_output.put_line('test1: n='||nvl(self.n, 'null')||' s='||s);
self.n := to_number(s);
end;
end;
/
-- derived class
create or replace type test2 under test
(
overriding member procedure proc(SELF in out nocopy test2, s varchar2)
)
/
Now I want to invoke the inherited version of the proc method. When I try to do an explicit cast like treat(self as test).proc(s); it won't compile because of PLS-00363: expression 'SYS_TREAT' cannot be used as an assignment target
The type body compiles when I use a local variable:
create or replace type body test2 is
overriding member procedure proc(SELF in out nocopy test2, s varchar2) is
O test;
begin
O := treat(self as test);
O.proc(s);
end;
end;
/
But when I run my example like this
declare
obj test2;
begin
obj := test2(0);
obj.proc('1');
end;
...it throws ORA-21780: Maximum number of object durations exceeded.
Is there any way to call test::proc (without serializing/deserializing)?
And... after proc has been called, how can any changed attributes (namely n) be reflected in obj ?
Update (Thanks, tbone):
I changed the organization of my methods using template methods ('before' and 'after'). I add them whenever I need to extend a method.
create or replace type test as object
(
n number,
member procedure proc (SELF in out nocopy test, s varchar2),
member procedure afterProc (SELF in out nocopy test, s varchar2)
member procedure beforeProc(SELF in out nocopy test, s varchar2),
)
not final
/
create or replace type body test is
member procedure proc(SELF in out nocopy test, s varchar2) is
begin
beforeProc(s);
dbms_output.put_line('test1: n='||nvl(n, 'null')||' s='||s);
n := to_number(s);
afterProc(s);
end;
member procedure afterProc (SELF in out nocopy test, s varchar2) is begin null; end;
member procedure beforeProc(SELF in out nocopy test, s varchar2) is begin null; end;
end;
/
To access the super methods, try either general invocation or generalized expression. For example, using a person supertype and student subtype:
CREATE OR REPLACE TYPE person_typ AS OBJECT (
idno number,
name varchar2(30),
phone varchar2(20),
MAP MEMBER FUNCTION get_idno RETURN NUMBER,
MEMBER FUNCTION show RETURN VARCHAR2)
NOT FINAL;
CREATE OR REPLACE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
-- function that can be overriden by subtypes MEMBER FUNCTION show RETURN VARCHAR2 IS BEGIN
RETURN 'Id: ' || TO_CHAR(idno) || ', Name: ' || name;
END;
END;
CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30),
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2)
NOT FINAL;
CREATE TYPE BODY student_typ AS
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
RETURN (self AS person_typ).show || ' -- Major: ' || major ;
END;
END;
-- Using Generalized Invocation
DECLARE
myvar student_typ := student_typ(100, 'Sam', '6505556666', 100, 'Math');
name VARCHAR2(100);
BEGIN
name := (myvar AS person_typ).show; --Generalized invocation
END;
-- Using Generalized Expression
DECLARE
myvar2 student_typ := student_typ(101, 'Sam', '6505556666', 100, 'Math');
name2 VARCHAR2(100);
BEGIN
name2 := person_typ.show((myvar2 AS person_typ)); -- Generalized expression
END;
EDIT:
If you are on 10g, you'll need to organize the functions a bit different, but same functionality from the child to call the super method:
CREATE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
-- static function that can be called by subtypes
STATIC FUNCTION show_super (person_obj in person_typ) RETURN VARCHAR2 IS
BEGIN
RETURN 'Id: ' || TO_CHAR(person_obj.idno) || ', Name: ' || person_obj.name;
END;
-- function that can be overriden by subtypes
MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
RETURN person_typ.show_super ( SELF );
END;
END;
CREATE TYPE student_typ UNDER person_typ (
dept_id NUMBER,
major VARCHAR2(30),
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2)
NOT FINAL;
CREATE TYPE BODY student_typ AS
OVERRIDING MEMBER FUNCTION show RETURN VARCHAR2 IS
BEGIN
RETURN person_typ.show_super ( SELF ) || ' -- Major: ' || major ;
END;
END;
Now you'd call show_super() from student for the person method, or just show() for the student method.
From the docs, hope that helps.

Resources