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.
Related
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
i am trying to call a function from stored procedure in Oracle, but not getting any idea how to do.
my function has two IN parameter and one OUT parameter.
in my procedure i am using out sys refcursor . Any refrence or example will help me a lot.
Here is a simple example for calling function inside procedure. Also as mentioned by APC using OUT in function is a bad practice. Instead you can return your required output. And I'm not sure how you are using sys_refcursor, so modify your procedure accordingly
CREATE OR REPLACE FUNCTION SUM_OF_2(NUM1 IN NUMBER,NUM2 IN NUMBER) RETURN NUMBER
IS
RESULT_SUM NUMBER;
BEGIN
RESULT_SUM:=NUM1+NUM2;
RETURN RESULT_SUM;
END;
CREATE OR REPLACE PROCEDURE CALL_FUNCTON(NUM1 NUMBER,NUM2 NUMBER)
AS
V_FINAL_RESULT NUMBER;
BEGIN
V_FINAL_RESULT:=SUM_OF_2(NUM1,NUM2);
DBMS_OUTPUT.PUT_LINE(V_FINAL_RESULT);
END;
BEGIN
CALL_FUNCTON(5,10);
END;
/
CHECK DEMO HERE
Not sure on what your requirement is , maybe you are just trying the code for education purposes. Generally I have not seen much code which uses OUT parameter with functions, in case you want to return multiple values to the caller object then you could use a procedure with more then one OUT variables. There are some limitation on how an oracle function with OUT parameter would differ from a normal function.
CREATE OR REPLACE FUNCTION temp_demo_func(out_var1 OUT NUMBER)
RETURN VARCHAR2 IS
BEGIN
out_var1 := 1;
RETURN 'T';
EXCEPTION
WHEN OTHERS THEN
RETURN 'F';
END temp_demo_func;
/
CREATE OR REPLACE PROCEDURE temp_demo_proc
(
in_var1 NUMBER
,cur_refcur_out OUT SYS_REFCURSOR
) IS
res VARCHAR2(1);
out_var1 NUMBER;
BEGIN
res := temp_demo_func(out_var1 => out_var1);
dbms_output.put_line(out_var1);
OPEN cur_refcur_out FOR
SELECT in_var1
,out_var1
,res
FROM dual;
END;
/
set serveroutput on
declare
cur_refcur_out Sys_Refcursor;
in_var1 number := 22;
begin
temp_demo_proc(in_var1 => in_var1
,cur_refcur_out => cur_refcur_out);
end;
/
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.
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;
/
I have the following code
CREATE OR REPLACE FUNCTION slow_function (p_in IN NUMBER)
RETURN NUMBER
AS
BEGIN
DBMS_LOCK.sleep(1);
RETURN p_in;
END;
/
CREATE OR REPLACE PACKAGE cached_lookup_api AS
FUNCTION get_cached_value (p_id IN NUMBER)
RETURN NUMBER;
PROCEDURE clear_cache;
END cached_lookup_api;
/
CREATE OR REPLACE PACKAGE BODY cached_lookup_api AS
TYPE t_tab IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
g_tab t_tab;
g_last_use DATE := SYSDATE;
g_max_cache_age NUMBER := 10/(24*60); -- 10 minutes
-- -----------------------------------------------------------------
FUNCTION get_cached_value (p_id IN NUMBER)
RETURN NUMBER AS
l_value NUMBER;
BEGIN
IF (SYSDATE - g_last_use) > g_max_cache_age THEN
-- Older than 10 minutes. Delete cache.
g_last_use := SYSDATE;
clear_cache;
END IF;
BEGIN
l_value := g_tab(p_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Call function and cache data.
l_value := slow_function(p_id);
g_tab(p_id) := l_value;
END;
RETURN l_value;
END get_cached_value;
-- -----------------------------------------------------------------
-- -----------------------------------------------------------------
PROCEDURE clear_cache AS
BEGIN
g_tab.delete;
END;
-- -----------------------------------------------------------------
END cached_lookup_api;
/
I want to pass two parameters "pi_value1" and "pi_value2" both of varchar2 to the function slow_function instead of "p_in". Is is possible to cache the results with two in parameters in oracle 10g .
the above code works fine with 1 parameter.
Please any one explain?
You'd need to create a two-dimensional array type to cache the values. Something along the lines of this (omitting the cache expiration code since that isn't changing)
CREATE OR REPLACE PACKAGE BODY cached_lookup_api
AS
TYPE t_pi_value2_tbl IS TABLE OF NUMBER
INDEX BY VARCHAR2(100);
TYPE t_cache IS TABLE OF t_pi_value2_tbl
INDEX BY VARCHAR2(100);
g_cache t_cache;
FUNCTION get_cached_value( p_pi_value1 IN VARCHAR2,
p_pi_value2 IN VARCHAR2 )
IS
BEGIN
RETURN g_cache(p_pi_value1)(p_pi_value2);
EXCEPTION
WHEN no_data_found
THEN
g_cache(p_pi_value1)(p_pi_value2) := slow_function( p_pi_value1, p_pi_value2 );
RETURN g_cache(p_pi_value1)(p_pi_value2);
END;
END;