what is wrong passing a record type as parameter - oracle

I have the following code snippets:
CREATE OR REPLACE PACKAGE pkg_test1 IS
TYPE t_rec1 is RECORD(c1 number);
FUNCTION f1(p1 t_rec1 ) RETURN VARCHAR2;
END pkg_test1;
CREATE OR REPLACE PACKAGE BODY pkg_test1 IS
FUNCTION f1 (p1 t_rec1) return varchar2 is
BEGIN
RETURN 'a';
END f1;
END pkg_test1;
DECLARE
TYPE t_rec IS RECORD (c1 NUMBER);
v_rec t_rec;
v_var VARCHAR2(15);
BEGIN
v_rec.c1 := 1;
v_var := pkg_test1.f1 (v_rec);
END;
When I execute the anonym code, I received the following error:
PLS-00306: wrong number or types of arguments in call to 'F1'
Can someone help me to see the mistake I make, please?

The type you declare in your anonymous block looks the same to you, but to Oracle it's a completely independent and incompatible type.
From the documentation:
A RECORD type defined in a package specification is incompatible with an identically defined local RECORD type.
You don't need it though; just use the package type:
DECLARE
-- don't create a new type....
--TYPE t_rec IS RECORD (c1 NUMBER);
--v_rec t_rec;
-- use the package type instead
v_rec pkg_test1.t_rec1;
v_var VARCHAR2(15);
BEGIN
v_rec.c1 := 1;
v_var := pkg_test1.f1 (v_rec);
END;
db<>fiddle

Related

PLS-00201 – identifier must be declared, passing a collection to procedure

I'm trying to pass a collection to procedure, but when I compile the package, I'll get this message:"PLS-00201 – identifier must be declared".
this is my code:
create or replace package PACK_DW_TEMP
as
procedure A (.......);
--
procedure B (error_list in out l_error);
end PACK_DW_TEMP;
In the package body I've created the collection in the procedure A and passed it to procedure B
create or replace package body PACK_DW_TEMP
as
procedure A ( ........ )
as
begin
declare
type error IS RECORD(
cod_error NUMBER,
descr_error VARCHAR2(100)
);
type l_errori is table of error;
error_list l_error := l_error();
begin
procedure B(error_list);
end;
end;
Into procedure B:
procedure B ( error_list in out l_error )
as
begin
declare
i NUMBER;
type err IS RECORD(
cod_error NUMBER,
descr_error VARCHAR2(100)
);
type l_err is table of err;
err_list l_err := l_err();
begin
i := 0;
for i in 1..5 loop
err_list(i).cod_err := error_list(i).cod_error;
err_list(i).descr_err := error_list(i).descr_error;
end loop;
end;
end;
My target is to pass the collection to procedure B and to assegn values to the new collection.
You're defining a type called l_err in the package body but in procedure B you're trying to use a type called l_error. Also, you have to define l_error in the package spec, prior to its first use:
create or replace package PACK_DW_TEMP
as
type err IS RECORD(
cod_error NUMBER,
descr_error VARCHAR2(100)
);
type l_error is table of err;
procedure A (.......);
--
procedure B (error_list in out l_error);
end PACK_DW_TEMP;
and remove the definitions of type_err, l_errori, and l_err from the package body.
A type declared locally to a procedure and another type declared locally to another procedure with exactly the signature are not the same types and you cannot pass one to the other. You need to create the type externally to the procedures rather than internally.
Also, you cannot use the type in the signature for the package when it is not declared except internally to the procedure which is declared in the body of the package.
create or replace package PACK_DW_TEMP
as
TYPE error IS RECORD(
cod_error NUMBER,
descr_error VARCHAR2(100)
);
type l_error is table of error;
procedure A;
procedure B (error_list in out l_error);
end PACK_DW_TEMP;
/
and
create or replace package body PACK_DW_TEMP
as
procedure A
as
error_list l_error := l_error();
begin
error_list.EXTEND(2);
error_list(1).cod_error := 1;
error_list(1).descr_error := 'DESCR1';
error_list(2).cod_error := 2;
error_list(2).descr_error := 'DESCR2';
B(error_list);
FOR i IN 1 .. error_list.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(
error_list(i).cod_error || ': ' || error_list(i).descr_error
);
END LOOP;
end;
procedure B ( error_list in out l_error )
as
begin
error_list.EXTEND;
error_list(error_list.COUNT).cod_error := 99;
error_list(error_list.COUNT).descr_error := 'DESCR99';
end;
end;
/
Then you can call it using:
BEGIN
PACK_DW_TEMP.A();
END;
/
Which outputs:
1: DESCR1
2: DESCR2
99: DESCR99
db<>fiddle here

Passing a table of varchar2 to a procedure

I need have a package with procedure accepting a parameter of type table of varchar2(255).
Package spec:
type charArray is table of varchar2(255) index by binary_integer;
Package body:
PROCEDURE call_me (p1 IN charArray, p2 IN VARCHAR2) IS ...
I tried calling this procedure using:
declare
type t_type is table of varchar2(255) index by binary_integer;
l_array t_type;
begin
l_array := ('131240');
pkg._name.call_me (l_array, 'name');
end;
I'm getting this error:
PLS-00306: wrong number or types of arguments in call to 'call_me'
What am I doing wrong?
You've got two types declared with the same definition, but that doesn't make them compatible. In order to pass the table into the package, you must use the type declared in the package:
declare
l_array pkg_name.charArray;
begin
l_array(1) := '131240';
pkg_name.call_me (l_array, 'name');
end;

Pipelined function with a parameter declare with %ROWTYPE

I'm trying to declare a pipelined table function (t) inside a package that takes an argument declared as <tablename>%ROWTYPE. Declaring that function works and the package compiles without any error.
But I would like to use this function inside a procedure (p1) like shown below.
CREATE OR REPLACE PACKAGE BODY t1
AS
-- private
PROCEDURE p1
IS
l_person persons%ROWTYPE;
BEGIN
FOR l_row IN (SELECT *
FROM TABLE (t (l_person)))
LOOP
NULL;
END LOOP;
END;
-- public
FUNCTION t (p_persons_record persons%ROWTYPE)
RETURN t_a_list
PIPELINED
IS
l_a t_a;
BEGIN
l_a.dummy := 'A';
PIPE ROW (l_a);
END;
END;
This sample code does not makes sense but it demonstrates my problem.
It just doesn't compile but gives the following errors:
[Error] PLS-00382 (10: 38): PLS-00382: expression is of wrong type
[Error] PLS-00306 (10: 35): PLS-00306: wrong number or types of arguments in call to 'T'
[Error] ORA-00904 (10: 35): PL/SQL: ORA-00904: "T1"."T": invalid identifier
Can anyone explain what's wrong and how to fix those errors?
Edit:
The package spec is:
CREATE OR REPLACE PACKAGE t1
AS
TYPE t_a IS RECORD (dummy VARCHAR2 (1));
TYPE t_a_list IS TABLE OF t_a;
FUNCTION t (p_persons_record persons%ROWTYPE)
RETURN t_a_list
PIPELINED;
END;
You cannot use a record type in SQL Scope. So a PL/SQL function with a record parameter derived by rowtype attribute cannot be used as table function in SQL.
The only thing you have to rewrite is to use a SQL object on schema level instead of a PL/SQL record.
-- adapt your columns to your table as necessary
CREATE OR REPLACE TYPE g_persons AS OBJECT (
ID int,
C1 int
);
CREATE OR REPLACE PACKAGE t1
AS
TYPE t_a IS RECORD (dummy VARCHAR2 (1));
TYPE t_a_list IS TABLE OF t_a;
FUNCTION t (p_persons_record g_persons_t)
RETURN t_a_list
PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY t1
AS
-- private
PROCEDURE p1
IS
l_person g_persons_t;
BEGIN
l_person.ID := 1; -- init your record some how
l_person.C1 := 1; -- init your record some how
FOR l_row IN (SELECT *
FROM TABLE (t (l_person)))
LOOP
NULL;
END LOOP;
END;
-- public
FUNCTION t (p_persons_record g_persons_t)
RETURN t_a_list
PIPELINED
IS
l_a t_a;
BEGIN
l_a.dummy := 'A';
PIPE ROW (l_a);
END;
END;
/
I think your PACKAGE specification lacks t's declaration. Have you checked that your PACKAGE specification is something similar to this?:
CREATE OR REPLACE PACKAGE t1 AS
PROCEDURE p1;
FUNCTION t (p_persons_record persons%ROWTYPE) RETURN t_a_list PIPELINED;
END;

Can we use a table type parameter as a default null parameter in PLSQL?

I have a record type as follows,
TYPE x_Rec IS RECORD(
master_company x_tab.master_company%TYPE,
report_trans_type x_tab.report_trans_type%TYPE,
balance_version_id x_tab.balance_version_id%TYPE,
reporting_entity x_tab.reporting_entity%TYPE,
year_period_from x_tab.year_period%TYPE,
year_period_to x_tab.year_period%TYPE,
journal_id x_tab.journal_id%TYPE,
row_id x_tab.row_id%TYPE);
and I have created a table type using this record:
TYPE x_rec_tab IS TABLE OF x_Rec INDEX BY PLS_INTEGER;
I want to use this table type in a procedure as a default null parameter.
PROCEDURE x_Balance___(x_param IN NUMBER,
x_rec_ IN x_rec_tab default null)
IS
BEGIN
...My code
END;
It gives the following error message
PLS-00382: expression is of the wrong type
I resolved this by using CAST(null as /*your_type*/) in the Procedure's signature.
For instance, in your case, it will be something like this:
PROCEDURE x_Balance (x_param IN NUMBER,
x_rec_ IN x_rec_tab default cast(null as x_rec_tab))
Then, within the procedure, you just need to check if x_rec_ has elements by using the count method.
This way works for me.
You can't do that with an associative array, as that can never be null. You would get the same error if you tried to assign null to a variable of type x_rec_tab. They also don't have constructors, so you can't use an empty collection instead.
You can do this will a varray or more usefully for your situation a nested table:
create or replace package p42 as
TYPE x_Rec IS RECORD(
master_company x_tab.master_company%TYPE,
report_trans_type x_tab.report_trans_type%TYPE,
balance_version_id x_tab.balance_version_id%TYPE,
reporting_entity x_tab.reporting_entity%TYPE,
year_period_from x_tab.year_period%TYPE,
year_period_to x_tab.year_period%TYPE,
journal_id x_tab.journal_id%TYPE,
row_id x_tab.row_id%TYPE);
-- no index-by clause, so nested table not associative array
TYPE x_rec_tab IS TABLE OF x_Rec;
end p42;
/
Package P42 compiled
show errors
No errors.
create or replace package body p42 as
PROCEDURE x_Balance___(x_param IN NUMBER,
x_rec_ IN x_rec_tab default null)
IS
BEGIN
--...My code
null;
END;
PROCEDURE dummy IS
l_rec_tab x_rec_tab;
BEGIN
l_rec_tab := null;
END;
end p42;
/
Package Body P42 compiled
show errors;
No errors.
You could also default to an empty collection instead:
PROCEDURE x_Balance___(x_param IN NUMBER,
x_rec_ IN x_rec_tab default x_rec_tab())
IS
...
That doesn't really help you much if you have other code that relies on the type being an associative array of course.
Old question but still might be helpful.
You can create a function:
function empty_tab
return x_rec_tab
as
l_tab x_rec_tab;
begin
return l_tab;
end empty_tab;
This way you can (notice that empty_tab is used as default parameter):
PROCEDURE x_Balance___(x_param IN NUMBER,
x_rec_ IN x_rec_tab default empty_tab)
IS
BEGIN
...My code
END;
This is a repeat of #ManuelPerez answer, but I just feel that it could have been explained better.
Create this procedure, casting your optional variable to your datatype like this:
CREATE OR REPLACE PROCEDURE Test_Procedure (
txt_ IN VARCHAR2,
col_formats_ IN dbms_sql.varchar2a DEFAULT cast(null as dbms_sql.varchar2a) )
IS BEGIN
Dbms_Output.Put_Line (txt_);
FOR i_ IN 1 .. 10 LOOP
IF col_formats_.EXISTS(i_) THEN
Dbms_Output.Put_Line (i_ || ' Exists');
ELSE
Dbms_Output.Put_Line (i_ || ' DOES NOT Exist');
END IF;
END LOOP;
END Test_Procedure;
The reason this beats the accepted answer is that it doesn't require you to change the datatype of the incoming variable. Depending on your circumstance, you may not have the flexibility to do that.
Now call your procedure like this if you have a variable to feed the procedure:
DECLARE
txt_ VARCHAR2(100) := 'dummy';
arr_ dbms_sql.varchar2a;
BEGIN
arr_(4) := 'another dummy';
Test_Procedure (txt_, arr_);
END;
Or like this if you don't:
DECLARE
txt_ VARCHAR2(100) := 'dummy';
BEGIN
Test_Procedure (txt_);
END;
Your output will look something like this:
dummy
1 DOES NOT Exist
2 DOES NOT Exist
3 DOES NOT Exist
4 Exists
5 DOES NOT Exist
6 DOES NOT Exist
7 DOES NOT Exist
8 DOES NOT Exist
9 DOES NOT Exist
10 DOES NOT Exist

Oracle Package Error

I want to create a package and inside the package we have a function having a parameter. I have table for TIME_DIM and the granularity of that table is one record/second. I am getting an error while crating this package any one help me on this.
create or replace
PACKAGE PKG_TIME_DIM
IS
Function FUN_TIME_DESC
( TIME_IN IN varchar2 )
RETURN varchar2
IS
TIMEDESC varchar2;
CURSOR c1
IS
SELECT TIME_DESC
from TIME_DIM
where TIME_DESC = TIME_IN;
BEGIN
open c1;
fetch c1 into TIME_DESC;
if c1%notfound then
TIMEDESC := 9999;
end if;
close c1;
RETURN TIMEDESC;
END;
END;
i don't know what error do you get but i see sevral problems:
by the declaration of the TIMEDESC variable the size of varchar2 is missing:
for Example: TIMEDESC varchar2(2000); or better
TIMEDESC TIME_DIM.TIME_DESC%TYPE;
there is a tipo in the following statment
fetch c1 into TIME_DESC;
you have declarated TIMEDESC and not TIME_DESC as the name of the variable
and may be the following is a problem
TIMEDESC := 9999;
TIMEDESC is of type varchar but you assigning number to it
There are many errors here. You appear to be declaring a package specification with code in it. You need both a specification and body. I've added comments on each line that had an issue:
-- Note: "CREATE OR REPLACE PACKAGE" = The specification
CREATE OR REPLACE PACKAGE PKG_TIME_DIM
IS
FUNCTION FUN_TIME_DESC (TIME_IN IN VARCHAR2) RETURN VARCHAR2;
END PKG_TIME_DIM;
/
-- Note: "CREATE OR REPLACE PACKAGE BODY" = Keyword BODY = the body
CREATE OR REPLACE PACKAGE BODY PKG_TIME_DIM
IS
FUNCTION FUN_TIME_DESC (TIME_IN IN VARCHAR2) RETURN VARCHAR2
IS
TIMEDESC VARCHAR2(100 CHAR); -- Need to define length of this variable in characters or bytes
CURSOR c1 IS
SELECT TIME_DESC
FROM TIME_DIM
WHERE TIME_DESC = TIME_IN;
BEGIN
OPEN c1;
FETCH c1 INTO TIMEDESC; -- Changed variable name to match the name you defined
IF c1%NotFound THEN
TIMEDESC := '9999'; -- Put quotes around this since this is a VARCHAR
END IF;
CLOSE c1;
RETURN TIMEDESC;
END FUN_TIME_DESC;
END PKG_TIME_DIM;
/

Resources