I have a question and I am not finding the answer from google.
This may be a simple question since I'm a beginner I have this doubt.
Can we declare a function in Package specification and use the same function for forward declaration ?
CREATE OR REPLACE PACKAGE pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER;
PROCEDURE proc_test (id number);
END pckg_test ;
CREATE OR REPLACE PACKAGE BODY pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER; --fwd declaration
PROCEDURE proc_test (id number) is
BEGIN
....
calling fun_test
....
END;
FUNCTION fun_test(ID NUMBER) RETURN NUMBER is
BEGIN
....
END;
END pckg_test;
You can't (forward) declare the function in the body, because it has already been declared in the specification.
This is simple to test with very minor filling-out of your pseudocode:
CREATE OR REPLACE PACKAGE pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER;
PROCEDURE proc_test (id number);
END pckg_test ;
/
Package PCKG_TEST compiled
CREATE OR REPLACE PACKAGE BODY pckg_test IS
FUNCTION fun_test(ID NUMBER) RETURN NUMBER; --fwd declaration
PROCEDURE proc_test (id number) is
x number;
BEGIN
x := fun_test(1);
END;
FUNCTION fun_test(ID NUMBER) RETURN NUMBER is
BEGIN
return 42;
END;
END pckg_test;
/
Package Body PCKG_TEST compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
2/1 PLS-00305: previous use of 'FUN_TEST' (at line 2) conflicts with this use
2/1 PL/SQL: Item ignored
2/10 PLS-00328: A subprogram body must be defined for the forward declaration of FUN_TEST.
Errors: check compiler log
The PLS-00305 is because of your forward declaration, which is the same (name and data types) as that in the package specification.
The PLS-00328 is slightly misleading; the full declaration of fun_test seems to be being linked to the public specification, and the forward declaration - even though it is itself throwing an error - then has no matching full declaration.
If you just remove or comment out the forward declaration then it compiles successfully:
CREATE OR REPLACE PACKAGE BODY pckg_test IS
--FUNCTION fun_test(ID NUMBER) RETURN NUMBER; --fwd declaration
PROCEDURE proc_test (id number) is
x number;
BEGIN
x := fun_test(1);
END;
FUNCTION fun_test(ID NUMBER) RETURN NUMBER is
BEGIN
return 42;
END;
END pckg_test;
/
Package Body PCKG_TEST compiled
You don't need (and are not alowed) a forward declaration of fun_test within the package body because it is publicly declared in the package specification - that public spec makes the function available throughout the package body. So, proc_test can still call fun_test even though it comes first in the body code. The public specification has the same effect as a forward declaration would.
so it means i can give fwd declaration only for private subprograms ?
Yes.
Related
I try to do the following :
CREATE OR REPLACE PACKAGE my_package AS
-- Declare the global variable
my_variable VARCHAR(255);
END my_package;
/
CREATE OR REPLACE PACKAGE BODY my_package AS
-- Assign a value to the global variable
my_variable := 'test';
END my_package;
/
But this does highlight := and throw the following error :
LINE/COL ERROR
--------- -------------------------------------------------------------
3/15 PLS-00103: Encountered the symbol "=" when expecting one of the following: constant exception <an identifier> <a double-quoted delimited-identifier> table columns long double ref char time timestamp interval date binary national character nchar The symbol "<an identifier>" was substituted for "=" to continue.
Errors: check compiler log
How can I create a package with in it a global variable so I can use it as follow :
my_package.my_variable
If you want to use it in SQL then create a function to wrap the variable:
CREATE OR REPLACE PACKAGE my_package AS
FUNCTION get_my_variable
RETURN VARCHAR2;
END my_package;
/
CREATE OR REPLACE PACKAGE BODY my_package AS
-- Declare the package variable
-- It can be public, if declared in the package specification
-- Or private, if declared in the package body
my_variable VARCHAR(255);
FUNCTION get_my_variable
RETURN VARCHAR2
IS
BEGIN
RETURN my_variable;
END;
BEGIN
-- Assign a value to the global variable
my_variable := 'test';
END my_package;
/
Then you can use it in SQL:
SELECT my_package.get_my_variable() FROM DUAL;
Outputs:
MY_PACKAGE.GET_MY_VARIABLE()
test
fiddle
You are missing a BEGIN block:
CREATE OR REPLACE PACKAGE BODY my_package AS
BEGIN
-- Assign a value to the global variable
my_variable := 10;
END my_package;
/
Hey guys I am having an issue where I get an error when I try to add the second private header underneath my first private header.
CREATE OR REPLACE PACKAGE TEST IS
PROCEDURE TEST2(VARIABLE1 IN NUMBER, VARIABLE2 OUT NUMBER);
END;
CREATE OR REPLACE PACK BODY TEST IS
FUNCTION PRIVATE1 (VARIABLE1 IN NUMBER)
RETURN NUMBER;
FUNCTION PRIVATE2 (VARIABLE2 IN NUMBER)
RETURN NUMBER;
PROCEDURE TEST2(VARIABLE IN NUMBER, VARIABLE OUT NUMBER)
BEGIN
......
END;
FUNCTION PRIVATE1 (VARIABLE1 IN NUMBER)
RETURN NUMBER
IS
BEGIN
........
END;
FUNCTION PRIVATE2 (VARIABLE2 IN NUMBER)
RETURN NUMBER
IS
BEGIN
.......
END;
END;
Any suggestions on how I can fix it?
FUNCTION PRIVATE2 (VARIABLE2 IN NUMBER)
RETURN NUMBER; // REMOVE semi colon from here
IS
BEGIN
.......
END;
You are probably using private function in SQL - this is not supported. In order to use function in SQL you have to define it in the package specification.
We need source code of private1 and private2 functions in order to be able to help more.
[Edit] Here is the example of the package that will fail to compile due to using private function in SQL:
create or replace package test_pkg is
end;
/
create or replace package body test_pkg is
function F1 return number is
begin
return 2;
end;
function F2 return number is
lnNumber number;
begin
select F1 -- function declared only in the package body
into lnNumber
from dual;
return lnNumber + 1;
end;
end;
/
PLS-00231: function 'F1' may not be used in SQL
PL/SQL: ORA-00904: "F1": invalid identifier
PL/SQL: SQL Statement ignored
I have this issue that is confusing me.
I know that in order to use , let's say an associative array type as a procedure parameter or as a function's return type you need to create a package ; because associative arrays can only be used in PL/SQL blocks .
And so I did , this is my package schema :
CREATE OR REPLACE PACKAGE some_package AS
TYPE vector IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
TYPE MATRIX IS TABLE OF vector INDEX BY PLS_INTEGER;
PROCEDURE printMatrix (p_matrix IN MATRIX);
FUNCTION BUILD_MATRIX(p_row_count IN INTEGER , p_column_count IN INTEGER) RETURN MATRIX;
END some_package;
/
My body package:
CREATE OR REPLACE PACKAGE BODY some_package AS
PROCEDURE printMatrix (p_matrix IN MATRIX)
IS
BEGIN
FOR i in p_matrix.first..p_matrix.last LOOP
FOR j in p_matrix(i).first..p_matrix(i).last LOOP
DBMS_OUTPUT.PUT_LINE(p_matrix(i)(j));
END LOOP;
DBMS_OUTPUT.PUT_LINE(CHR(10));
END LOOP;
DBMS_OUTPUT.PUT_LINE(CHR(10));
END printMatrix;
FUNCTION BUILD_MATRIX(p_row_count IN INTEGER , p_column_count IN INTEGER)
RETURN MATRIX IS
TYPE vector IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
TYPE MATRIX IS TABLE OF vector INDEX BY PLS_INTEGER;
v_my_matrix MATRIX;
v_my_row vector;
v_contor_row INTEGER;
v_contor_column INTEGER;
BEGIN
FOR v_contor_row IN 0..p_row_count LOOP
FOR v_contor_column IN 0..p_column_count LOOP
v_my_row(v_contor_column) := 0 + MOD(ABS(DBMS_RANDOM.RANDOM),30);
END LOOP;
v_my_matrix(v_contor_row) := v_my_row;
END LOOP;
return v_my_matrix;
END;
END some_package;
/
But for some unknown reasons , I get these errors :
Error(9,12): PLS-00323: subprogram or cursor 'BUILD_MATRIX' is
declared in a package specification and must be defined in the package
body
Error(19,3): PL/SQL: Item ignored
Error(20,13): PLS-00498: illegal use of a type before its declaration
I don't undertand what I did wrong , the headers' types of my procedure and function are the same with the implementations : same parameters, same return type ... What am I doing wrong ?
Thank you for your time.
Just comment these declarations in the function body:
FUNCTION BUILD_MATRIX(p_row_count IN INTEGER , p_column_count IN INTEGER)
RETURN MATRIX IS
-- TYPE vector IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
-- TYPE MATRIX IS TABLE OF vector INDEX BY PLS_INTEGER;
v_my_matrix MATRIX;
There are declared in the package, you don't need to "rededefine" them in the function.
If you declare them as local in this place with the same names as in the body, then they hide types declared in the package, and Oracle complains, because the function declaration from the package doesn't match with definition in the body (they use different types - even if their names are the same).
I have a package body as give bellow. I need to call a function named TESTING() inside the function body and call another query. Code is given bellow
CREATE OR REPLACE PACKAGE BODY TEST_PCAKAGE AS -- body
FUNCTION OUTER_FUNCTION (
INPUT_A IN VARCHAR2,
INPUT_B IN DATE,
) RETURN REF_CURSOR_TYPE IS
CUR_CA_RECEIPTS REF_CURSOR_TYPE;
BEGIN
OPEN CUR_CA_RECEIPTS FOR
TESTING();
SELECT * FROM TEST_TABLE;
RETURN CUR_CA_RECEIPTS;
END OUTER_FUNCTION;
END TEST_PCAKAGE ;
when creating this package body, it gives me errors. Can anyone please tell me how to do this?
Error : Error(14,1): PLS-00428: an INTO clause is expected in this SELECT statement
create or replace
FUNCTION "TESTING" RETURN VARCHAR2
AS
BEGIN
RETURN('SUCCESS');
END;
I'm guessing you'r trying to return the cursor from the function
Try this :
CREATE OR REPLACE PACKAGE BODY TEST_PCAKAGE AS -- body
FUNCTION OUTER_FUNCTION (
INPUT_A IN VARCHAR2,
INPUT_B IN DATE,
) RETURN REF_CURSOR_TYPE IS
-- use sys_refcursor for dynamic cursors
CUR_CA_RECEIPTS sys_refcursor;
BEGIN
-- Open the cursor for a query and not a function
OPEN CUR_CA_RECEIPTS FOR SELECT * FROM TEST_TABLE;
-- i'm guessing this is for debug
TESTING();
-- you can now iterate it in a different procedure
RETURN CUR_CA_RECEIPTS;
END OUTER_FUNCTION;
END TEST_PCAKAGE ;
reference: How to make a wrapper to return something other than ref cursor
I've got many wrapped functions that are similar to the one below, only they return different columns of course. How can i put them all in one package. because what the examples below does is replace my wrapper package everytime.
I want to know how to remove the global declarations on top so that i can add many in the same package each with different return columns
create or replace package WrapperSample is
type TResultRow is record(
if_type codes.cd%type
,number_infected Integer);
type TResultRowList is table of TResultRow;
function GetADedIcWarningsProv
(
p_hos_id in work_entity_data.hos_id%type
,p_date in date
) return TResultRowList
pipelined;
end WrapperSample;
/
create or replace package body WrapperSample is
function GetADedIcWarningsProv
(
p_hos_id in work_entity_data.hos_id%type
,p_date in date
) return TResultRowList
pipelined is
v_refcur eOdatatypes_package.eOrefcur;
currentRow TResultRow;
begin
v_refcur := YourSchema.getADedIcWarningsProv(p_hos_id, p_date);
loop
fetch v_refcur
INTO currentRow;
exit when v_refcur%NotFound;
pipe row(currentRow);
end loop;
close v_refcur;
return;
end;
end WrapperSample;
/
you would use one record definition and one table definition per different column set.
create or replace package WrapperSample is
type R_WarningsProv is record(/*...*/);
type T_WarningsProv is table of R_WarningsProv ;
function GetADedIcWarningsProv(/*...*/) return T_WarningsProv pipelined;
type R_OtherFunction is record(/*...*/);
type T_OtherFunction is table of R_OtherFunction ;
function OtherFunction(/*...*/) return T_OtherFunction pipelined;
/* Multiple functions can use the same types as long as
they share the same column definition */
function SomeOtherFunction(/*...*/) return T_OtherFunction pipelined;
end WrapperSample;