In plsql how can a function use an object declared in a package - oracle

i have a package(that is in beta, just want to make it work):
CREATE OR REPLACE PACKAGE pkg1 AS
type pipeDefinition is record
(
str VARCHAR2(4000),
num NUMBER,
);
type pipeContainer is table of pipeDefinition;
FUNCTION f1(x NUMBER) RETURN
pipeContainer pipelined;
END pkg1;
and the package body
CREATE PACKAGE BODY pkg1 AS
FUNCTION f1(x NUMBER) RETURN
pipeContainer pipelined
IS
BEGIN
FOR i IN 1..x LOOP
PIPE ROW(pipeDefinition('i',i));
END LOOP;
RETURN;
END f1;
END pkg1;
my problems:
1if i try to run the above i get
"error at line:
PIPE ROW(pipeDefinition('i',i));
function pipeDefinition can not be found" (not exactly exactly what it said, but close)
2if i try to use pkg1.pipeDefinition instead i get the same error
"error at line:
PIPE ROW(pipeDefinition('i',i));
function pipeDefinition can not be found"
3if i try to add
type pipeDefinition is record
(
str VARCHAR2(4000),
num NUMBER,
);
type pipeContainer is table of pipeDefinition;
in the package body, it sais
"can not declare more than 1 pipeContainer
and more than 1 pipeDefinition"
4if i try to add
type pipeDefinition2 is record
(
str VARCHAR2(4000),
num NUMBER,
);
type pipeContainer2 is table of pipeDefinition2;
in the package body(and alter the pipeRow line with pipeDefinition2), it sais
"the object referenced is of a diferent kind as to the one the function is suposed to output"
5if i try to add 4 and make the function return pipeContainer2 pipelined it sais
"function mismatch package and body"
6if i try to add 6 and make function return pipeContainer2 pipelined in the package also i get
"pipeContainer2 not defined before using it " in the package creator
can anyone give me some hints?
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Klas Lindbäck, you are my hero!
Solution:
CREATE OR REPLACE PACKAGE pkg1 AS
type pipeDefinition is record
(
str VARCHAR2(4000),
num NUMBER,
);
type pipeContainer is table of pipeDefinition;
FUNCTION f1(x NUMBER) RETURN
pipeContainer pipelined;
END pkg1;
and the package body
CREATE PACKAGE BODY pkg1 AS
FUNCTION f1(x NUMBER) RETURN
outrec1 pipeDefinition;
--removed: pipeContainer pipelined
IS
BEGIN
FOR i IN 1..x LOOP
--removed: PIPE ROW(pipeDefinition('i',i));
--newLines:
outrec1.str := 'a';
outrec1.num := i;
PIPE ROW(outrec1);
--endNewLines.
END LOOP;
RETURN;
END f1;
END pkg1;
and my new pointer function is finally complete! :"D
SELECT * FROM TABLE(pkg1.f1(5));
|str | num|
a | 1
a | 2
a | 3
a | 4
a | 5

Create or replace package pk2 as
type c1 is ref cursor return employees%rowtype;
type outrec is record (
var_num number,
var1 varchar2(50),
var2 varchar2(50));
type outrecset is table of outrec;
function f_trans (c2 c1) return outrecset pipelined;
end pk2;
create or replace package body pk2 as
function f_trans(c2 c1) return outrecset pipelined is
outrec1 outrec;
outrec2 c2%rowtype;
begin
loop
fetch c2 into outrec2;
exit when c2%notfound;
outrec1.var_num := outrec2.employee_id;
outrec1.var1 := outrec2.first_name;
outrec1.var2 := outrec2.last_name;
PIPE ROW(outrec1);
outrec1.var1 := outrec2.email;
outrec1.var2 := outrec2.phone_number;
PIPE ROW(outrec1);
END LOOP;
RETURN;
END f_trans;
END pk2;
please take hint from this code
data type for the record is not declared

Related

push procedure pop function with sequence number in oracle

I want to write code for push with procedure and pop with Function .
create or replace package pushpop_demo as
procedure push(val varchar2);
function pop return varchar2;
end pushpop_demo;
create or replace package body pushpop_demo as
subtype my_string_subtype is varchar2(100);
type varchar2_ntt is table of my_string_subtype;
stuff varchar2_ntt := varchar2_ntt();
procedure push(val varchar2)
is
begin
stuff.extend;
stuff(stuff.last) := val;
end push;
function pop return varchar2
is
subtype my_string_subtype varchar2(100);
begin
if stuff is not empty then
val := stuff(stuff.last);
stuff.delete(stuff.last);
end if;
return val;
end pop ;
but I get error , my question is how can I do this problem with sequence number ??? or other solution .my code does not run anyway . also I do not want use the package .just with procedure and Function .please help me
You need / statement terminators to terminate each PL/SQL block.
You are missing an END; statement at the end of the package body.
You have not declared the VAL variable in the function.
You do not want to re-declare the my_string_subtype type (as it will shadow sub-type declared in the package body).
You can initialise the collection in the declaration section or an alternative is to initialise it in the BEGIN ... END section of the package body.
create or replace package pushpop_demo as
procedure push(val varchar2);
function pop return varchar2;
end pushpop_demo;
/
create or replace package body pushpop_demo as
subtype my_string_subtype is varchar2(100);
type varchar2_ntt is table of my_string_subtype;
stuff varchar2_ntt; -- := varchar2_ntt();
procedure push(val varchar2)
is
begin
stuff.extend;
stuff(stuff.last) := val;
end push;
function pop return varchar2
is
val my_string_subtype;
begin
if stuff is not empty then
val := stuff(stuff.last);
stuff.delete(stuff.last);
end if;
return val;
end pop;
BEGIN
stuff := varchar2_ntt();
END;
/
Then you can use:
BEGIN
pushpop_demo.push('World');
pushpop_demo.push('Hello');
END;
/
and then:
BEGIN
DBMS_OUTPUT.PUT_LINE(pushpop_demo.pop());
DBMS_OUTPUT.PUT_LINE(pushpop_demo.pop());
END;
/
Outputs:
Hello
World
fiddle

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 Table Function - How to return an empty result set?

I'm trying to create a PL/SQL table function. I don't mind if it is PIPELINED or not. I just want it to return a query-able result set.
And I want to start with an empty result set. (Because it is possible that the result set I intend to construct will be empty.)
Is it possible to create a PL/SQL table function that returns zero rows?
In the books I have, and tutorials I can find, I only see examples that must return at least one record.
Example of the problem:
CREATE OR REPLACE PACKAGE z_util AS
TYPE t_row
IS RECORD (
CATEGORY VARCHAR2( 128 CHAR )
, MEASURE NUMBER
);
TYPE t_tab
IS TABLE OF t_row;
FUNCTION f_test
RETURN t_tab;
END z_util;
/
CREATE OR REPLACE PACKAGE BODY z_util AS
FUNCTION f_test
RETURN t_tab IS
retval t_tab;
BEGIN
RETURN retval;
END;
END z_util;
/
SELECT test.*
FROM TABLE ( z_util.f_test ) test;
Output:
Error starting at line : 24 in command -
SELECT test.*
FROM TABLE ( z_util.f_test ) test
Error at Command Line : 25 Column : 14
Error report -
SQL Error: ORA-00902: invalid datatype
00902. 00000 - "invalid datatype"
*Cause:
*Action:
Something like this?
SQL> CREATE TYPE t_row AS OBJECT (id NUMBER, name VARCHAR2 (50));
2 /
Type created.
SQL> CREATE TYPE t_tab IS TABLE OF t_row;
2 /
Type created.
SQL> CREATE OR REPLACE FUNCTION f_test
2 RETURN t_tab
3 AS
4 retval t_tab;
5 BEGIN
6 RETURN retval;
7 END;
8 /
Function created.
SQL> SELECT f_test FROM DUAL;
F_TEST(ID, NAME)
--------------------------------------------------------------------
SQL>
Saying that this is too simple and that it doesn't work while in package:
SQL> CREATE OR REPLACE PACKAGE pkg_test
2 AS
3 FUNCTION f_test
4 RETURN t_tab;
5 END;
6 /
Package created.
SQL> CREATE OR REPLACE PACKAGE BODY pkg_test
2 AS
3 FUNCTION f_test
4 RETURN t_tab
5 AS
6 retval t_tab;
7 BEGIN
8 RETURN retval;
9 END f_test;
10 END pkg_test;
11 /
Package body created.
SQL> select pkg_test.f_test from dual;
F_TEST(ID, NAME)
-------------------------------------------------------
SQL>
Works OK as well. Did you, by any chance, declare type within the package? If so, try to create it at SQL level.
See 6.4.6 Querying a Collection:
Note: In SQL contexts, you cannot use a function whose return type was declared in a package specification.
You cannot unnest the result of function, but the variable with the same data type:
create or replace package utils as
type t_row is record (category varchar2 (8), measure number);
type t_tab is table of t_row;
function passon (t t_tab:=null) return t_tab;
end utils;
/
create or replace package body utils as
function passon (t t_tab:=null) return t_tab is
begin
return t;
end;
end utils;
/
Usage and outcomes:
var rc refcursor
declare
tab1 utils.t_tab := utils.passon (); -- empty
tab2 utils.t_tab := utils.passon (utils.t_tab (utils.t_row ('category', 50)));
begin
open :rc for
select * from table (tab1) union all
select * from table (tab2);
end;
/
CATEGORY MEASURE
-------- ----------
category 50
jsut use a return statment without any parameters.
I have already one table function that splits a string based in token.
I modified the code for you as an example answet for your quetion.
If you pass the first string null, the function will return no rows, otherwise will return each token in separate row based on the second parameter offcurse.
// create needed types
// row object
CREATE OR REPLACE TYPE T_TOKEN_ROW AS OBJECT (
id NUMBER,
token_text VARCHAR2(50)
);
// table object
CREATE OR REPLACE TYPE T_TOKEN_TAB IS TABLE OF t_token_row;
// create table function to toknize a string
// input : P_string : the string to be toknized
// P_separator : a character to separate tokens
// Outputs : each token in separate record with id field
CREATE OR REPLACE FUNCTION PIPE_tokens (P_string varchar2,P_separator char) RETURN t_token_tab PIPELINED
AS
sLine VARCHAR2(2000);
nPos INTEGER;
nPosOld INTEGER;
nIndex INTEGER;
nLength INTEGER;
nCnt INTEGER;
sToken VARCHAR2(200);
BEGIN
if (P_string is null ) then
return ;
else
sLine := P_string;
IF (SUBSTR(sLine, LENGTH(sLine), 1) <> '|') THEN
sLine := sLine || '|';
END IF;
nPos := 0;
sToken := '';
nLength := LENGTH(sLine);
nCnt := 0;
FOR nIndex IN 1..nLength LOOP
IF ((SUBSTR(sLine, nIndex, 1) = P_separator) OR (nIndex = nLength)) THEN
nPosOld := nPos;
nPos := nIndex;
nCnt := nCnt + 1;
sToken := SUBSTR(sLine, nPosOld + 1, nPos - nPosOld - 1);
PIPE ROW(t_token_row(nCnt,sToken));
--tTokenTab(nCnt) := sToken;
END IF;
END LOOP;
RETURN;
end if;
END;
// 2 Test query
select * from table(PIPE_tokens(null,';')) ;
select * from table(PIPE_tokens('5;2;3',';')) ;

How to give the result of a pipelined function as a default parameter?

I have created these 4 types :
record type myrecord1 is (...)
record type myrecord2 is (...)
table tableofmyrecord1 is table of myrecord1;
table tableofmyrecord2 is table of myrecord2;
and 2 functions :
function a(k in tableofmyrecord2) return packageName.tableofmyrecord1 PIPELINED;
function b return packageName.tableofmyrecord2 PIPELINED;
I can effectively give a default parameter ; null, the table empty, a table that I have create, but I can give directly the result of a of pipelined function.
function a return packageName.tOfmyrecord(k in tableofmyrecord2 :=package.b) PIPELINED
This does'nt work.
This solution does'nt work too.
declare
defaultArgOFA :=package.b;
function a return packageName.tOfmyrecord(k in tableofmyrecord2 :=defaultArgOFA) PIPELINED
same error
PLS-00653: aggregate/table functions are not allowed
This error says that you cannot call pipelined functions using PLSQL, so you can't directly write v:=a(). But you can use SQL. Below is an example where pipelined b gets input from pipelined a and multiplies salaries.
Package:
create or replace package pkg is
type tr is record (id int, name varchar2(10), sal int);
type tt is table of tr;
function a return tt pipelined;
function b(par in tt) return tt pipelined;
end pkg;
Body:
create or replace package body pkg is
function a return tt pipelined is
v_tr tr;
begin
v_tr.id := 1; v_tr.name := 'Mark'; v_tr.sal := 100;
pipe row (v_tr);
v_tr.id := 2; v_tr.name := 'Pete'; v_tr.sal := 120;
pipe row (v_tr);
return;
end;
function b(par in tt) return tt pipelined is
v_tr tr;
begin
for i in 1..par.last loop
v_tr := par(i);
v_tr.sal := v_tr.sal * 10;
pipe row (v_tr);
end loop;
return;
end;
end pkg;
And this test worked for me:
select * from table(pkg.b(pkg.a));
Result:
ID NAME SAL
------ ---------- ----------
1 Mark 1000
2 Pete 1200

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.

Resources