Executing functions in sequence defined in a package - oracle

I've been given the task of converting a stored procedure, with several CRUD operations, to a package with functions defined.
When I created the package in Oracle SQL Developer, I defined may functions:
FUNCTION func1 RETURN NUMBER;
FUNCTION func2 RETURN NUMBER;
etc...
I have corresponding code in the 'package body':
FUNCTION func1 RETURN NUMBER
IS
BEGIN
-- some CRUD operation
END;
RETURN 0;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('FUNCTION func1: error ' || ERR_NUM || ', Msg:' || ERR_MSG);
ROLLBACK;
END func1;
When I run them, I can choose which function to run from the list supplied. My question is what do I need to write or do to have all functions run in sequence with one command?
thanks

If you need to run some procedures in a given order, you need to build a procedure or an anonymous block that calls the procedures in the right order.
For example:
create or replace package aPackage is
procedure runAll;
end;
create or replace package body aPackage is
procedure proc1 is
begin
dbms_output.put_line('Procedure 1');
end proc1;
--
procedure proc2 is
begin
dbms_output.put_line('Procedure 2');
end proc2;
procedure runAll is
begin
proc1;
--
proc2;
--
end runAll;
end;
The call:
SQL> exec aPackage.runAll;
Procedure 1
Procedure 2
PL/SQL procedure successfully completed.
SQL>
I used procedures just to call them without need to assign the result to a variable, but the idea is the same for functions.
With functions:
create or replace package aPackageFun is
function runAll return number;
end;
create or replace package body aPackageFun is
function fun1 return number is
begin
dbms_output.put_line('Inside function 1');
return 1;
end fun1;
--
function fun2 return number is
begin
dbms_output.put_line('Inside function 2');
return 2;
end fun2;
function runAll return number is
vNum1 number;
vNum2 number;
begin
vNum1 := fun1();
--
vNum2 := fun2();
--
return vNum1 + vNum2;
end runAll;
end;
The call:
SQL> select aPackageFun.runAll() from dual;
APACKAGEFUN.RUNALL()
--------------------
3
Inside function 1
Inside function 2
SQL>
About your code, notice that you have a commit after a return: the commit will never be executed.

Related

PL/SQL "all_search" procedure is not a procedure or is undefined

This function is inside a package, but when I call the function the following error appears: PL/SQL "all_search" is not a procedure or is undefined. Someone can help me?
CREATE OR REPLACE PACKAGE employee_tab IS
FUNCTION all_search (ID_EMP in NUMBER) RETURN O_T_EMPL PIPELINED;
END employee_tab;
/
CREATE OR REPLACE TYPE O_T_EMPL AS TABLE OF O_EMPLOYEE;
/
CREATE OR REPLACE PACKAGE BODY employee_tab IS
FUNCTION all_search (ID_EMP in NUMBER) RETURN O_T_EMPL PIPELINED
IS
TAB_OBJC_EMP O_T_EMPL;
MY_QUERY_SEARCH VARCHAR2(400);
REF_C SYS_REFCURSOR;
MAX_ROW NUMBER := 25;
BEGIN
MY_QUERY_SEARCH := 'SELECT *
FROM EMPLOYEES
WHERE EMPLOYEE_ID = ID_EMP';
open REF_C for MY_QUERY_SEARCH using ID_EMP;
loop
--
fetch REF_C bulk collect into TAB_OBJC_EMP limit MAX_ROW;
exit when TAB_OBJC_EMP.count = 0;
for i in 1..TAB_OBJC_SEE.count
--
loop
pipe row(O_EMPLOYEE(TAB_OBJC_EMP(i).V_O_EMP_ID,
TAB_OBJC_EMP(i).V_O_HIRE_ID,
TAB_OBJC_EMP(i).V_O_DEP_ID)
);
end loop;
--
END loop;
--
CLOSE REF_C;
RETURN;
--
END all_search;
END employee_tab;
/
call function: employee_tab.all_search(1);
You need to assign the result of the function to something, try something like:
DECLARE
l_emp_id NUMBER;
BEGIN
SELECT EMP_ID
INTO l_emp_id
FROM TABLE(employee_tab.all_search(1))
WHERE rownum = 1;
DBMS_OUTPUT.put_line(TO_CHAR(EMP_ID));
END;
/

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

Procedure checking set up parameters (PL/SQL, ORACLE)

In the package I have couple of procedure that set global variables, example below:
...
PROCEDURE setA (pp IN VARCHAR2)
IS BEGIN global_vName := pp; END;
PROCEDURE setB (qq IN VARCHAR2)
IS BEGIN global_vColor := qq; END;
FUNCTION getA RETURN VARCHAR2
IS BEGIN RETURN global_vName; END;
FUNCTION getB RETURN VARCHAR2
IS BEGIN RETURN global_vColor; END;
...
Now in the PL/SQL block I'm doing test if they are working correclty:
Begin
mypack.setA('NameA');
mypack.setB('ColorB');
End;
How to write a procedure that will check if global_vName and global_vColor are set up?
If they are null procedure should return exception. Please help.
Do you mean this?
FUNCTION getA RETURN VARCHAR2 IS
BEGIN
IF global_vName IS NULL THEN
RAISE NO_DATA_FOUND;
END IF;
RETURN global_vName;
END;
There is no possibility to execute some code after the end statement - you should write it explicitly if you need additional check. As I understand, you want be sure that global variables are always initialized, so you can use the package initialization:
create or replace package body mypack as
PROCEDURE setA (pp IN VARCHAR2)
IS BEGIN global_vName := pp; END;
PROCEDURE setB (qq IN VARCHAR2)
IS BEGIN global_vColor := qq; END;
FUNCTION getA RETURN VARCHAR2
IS BEGIN RETURN global_vName; END;
FUNCTION getB RETURN VARCHAR2
IS BEGIN RETURN global_vColor; END;
< here are your other functions and procedures >
begin
-- here is an initialization section
setA('NameA');
setB('ColorB');
end mypack;
The initialization section will be executed automatically by Oracle before the first user's call to package (function, procedure, cursor, variable, etc.). So you can be sure that your variables are always initialized.

Oracle PL/SQL: Call DML procedure from a function

I have a procedure that has DML commands. the procedure accepts a variable of type out, and it returns a value.
i need call this procedure from a function.
the goal isĀ  that the function will return the value of the variable out returns the procedure.
(i need it for SSIS, but I believe that it is useful in other cases.)
During attempts, I got these errors:
ORA-14551: cannot perform a DML operation inside a query tips.
ORA-06519: active autonomous transaction detected and rolled back.
I'm looking for the right syntax to do it.
Example of a solution that works:
The procedure:
create or replace procedure MyProc(outRes OUT NUMBER)
is
begin
update some_table set some_description = 'abc';
commit;
if (some_condition) then
outRes := 666;
else
outRes := 999;
end if;
end MyProc;
Note: You must do commit; at the end of the DML command.
The function:
CREATE or replace FUNCTION MyFunc
RETURN int IS
PRAGMA AUTONOMOUS_TRANSACTION;
myVar number;
begin
MyProc(myVar);
return myVar;
END MyFunc;
Note that at the beginning of the function has: PRAGMA AUTONOMOUS_TRANSACTION;
And this function call:
select MyFunc() as res from dual;
Here is an example of what you need to do. Do know this is UNTESTED, but should give you a general idea of which way to go. This is known as Dynamic SQL and uses bind variables. There's a lot more I don't know such as the data type your procedure spits out and what not... so if it's not varchar2 then change it accordingly...
FUNCTION myFunc(procedure_call varchar2) RETURN VARCHAR2
IS
v_out1 varchar2(500);
BEGIN
EXECUTE IMMEDIATE 'begin '||procedure_call||'( :out1 ); end;' using v_out1;
RETURN v_out;
END;

Join between a collection and a table

I have a problem with procedures in PL/SQL. I have a public procedure declared in a package and I want to call another procedure(private) inside the first one.
PROCEDURE show_notesforstudent (number_id IN number) as
...
DBMS_OUTPUT.PUT_LINE('The notes for the student with number_id X are: '|| Y);
DBMS_OUTPUT.PUT_LINE('here is the call for the private procedure');
erase_student(number_id);
END;
This code is a general example, my code is bigger and I can't put it all here. Here is only the main idea.
For this call I face this error: "Error(31,5): PLS-00313: 'erase_student' not declared in this scope".
The implementation of erase_student procedure is:
PROCEDURE erase_student(n_id students.number_id%type) AS
student_inexistent EXCEPTION;
PRAGMA EXCEPTION_INIT(student_inexistent, -20002);
counter integer;
BEGIN
SELECT COUNT(nmber_id) INTO counter FROM studens where number_id = n_id;
IF counter = 0 THEN
raise student_inexistent;
END IF;
DELETE FROM students WHERE number_id = n_id;
EXCEPTION
WHEN student_inexistent THEN
raise_application_error (-20002, 'Student with number_id' || n_id || ' doesn't exists in database');
END stergere_student;`
Lets simplify your code and make it syntactically correct:
CREATE OR REPLACE PACKAGE package_name
AS
PROCEDURE show_notesforstudent (number_id IN number);
END;
/
CREATE OR REPLACE PACKAGE BODY package_name
AS
PROCEDURE show_notesforstudent (number_id IN number)
AS
BEGIN
erase_student(number_id);
END;
PROCEDURE erase_student(n_id NUMBER) AS BEGIN NULL; END;
END;
/
However, it still won't compile as we get PLS-00313: 'ERASE_STUDENT' not declared in this scope. It can be fixed by re-organising the package to ensure that the private procedure is declared before it is called; like this:
CREATE OR REPLACE PACKAGE BODY package_name
AS
PROCEDURE erase_student(n_id NUMBER) AS BEGIN NULL; END; -- Header and body
PROCEDURE show_notesforstudent (number_id IN number)
AS
BEGIN
erase_student(number_id);
END;
END;
/
However, if you want to keep the order of the procedures in the package then you could just use a forward declaration to declare the header for the private procedure before it is called and declare the body afterwards; like this:
CREATE OR REPLACE PACKAGE BODY package_name
AS
PROCEDURE erase_student(n_id NUMBER); -- Header only
PROCEDURE show_notesforstudent (number_id IN number)
AS
BEGIN
erase_student(number_id);
END;
PROCEDURE erase_student(n_id NUMBER) AS BEGIN NULL; END; -- Header and body
END;
/

Resources