I have a procedure which should execute one at a time. I mean when the procedure is executing other process/user should not be able to execute the same procedure.
Only after the procedure executes and the the next time it can be executed
Please help
To serialize execution of a procedure you could use dbms_lock package and specifically allocate_unique(), release() procedures and request() function of that package. Here is an example, in which we create a package which will regulate lock acquiring process:
Specification of the package
create or replace package proc_lock as
function request_lock( p_lock_name in varchar2) return varchar2;
procedure release_lock(p_l_handle in varchar2);
end;
Package body
create or replace package body proc_lock as
function request_lock( p_lock_name in varchar2) return varchar2
is
l_request number;
l_lock_handle varchar2(1000);
begin
dbms_lock.allocate_unique(p_lock_name, l_lock_handle);
-- waits 5 sec trying to acquire a lock
l_request := dbms_lock.request(l_lock_handle, timeout=>5);
if l_request <> 0
then
raise_application_error(-20001, 'Lock cannot be acquired.');
end if;
return l_lock_handle;
end;
procedure release_lock(p_l_handle in varchar2)
is
begin
if dbms_lock.release(p_l_handle) > 0
then
raise_application_error(-20000, 'Cannot release lock');
end if;
end;
end;
Here is a simple procedure, which should be serialized
create or replace procedure test_proc
is
l_handle varchar2(1000); -- lock handle
begin
-- trying to acquire a lock
l_handle := proc_lock.request_lock('test');
-- here goes all usefull work that this procedure
-- would do if lock acquired successfully
dbms_output.put_line('procedure is working');
-- mimic large amount of work
dbms_lock.sleep(10);
dbms_output.put_line('procedure is done');
-- release the lock after work is done
proc_lock.release_lock(l_handle);
end;
Test case:
--Session #1
SQL> exec test_proc;
--Session #2 at the same time
SQL> exec test_proc;
BEGIN test_proc; END;
*
ERROR at line 1:
ORA-20001: Lock cannot be acquired.
ORA-06512: at "HR.PROC_LOCK", line 11
ORA-06512: at "HR.TEST_PROC", line 6
ORA-06512: at line 1
--Session #1
SQL> exec test_proc;
procedure is working
procedure is done
PL/SQL procedure successfully completed.
Find out more about dbms_lock package.
Related
I have written below procedure in oracle but its getting compiled with error.
CREATE OR REPLACE PROCEDURE PROC_MIGRATE_ONEIBER
AS
BEGIN
-- EXECUTE PROCEDURE ONEFIBER_LNK_MIGRATE;
execute ONEFIBER_LNK_MIGRATE;
execute ONEFIBER_LNK_MIGRATE_CITY;
execute ONEFIBER_LNK_MIGRATE_NLDC;
END;
-- NULL;
END PROC_MIGRATE_ONEIBER;
I have to execute 3 procedures in one main procedure without any IN or OUT parameters. But its not working
Just remove the execute keyword. Whenever you want to call another procedure within the procedure you can directly use the procedure name and parameters, If any.
CREATE OR REPLACE PROCEDURE PROC_MIGRATE_ONEIBER AS
BEGIN
-- EXECUTE PROCEDURE ONEFIBER_LNK_MIGRATE;
ONEFIBER_LNK_MIGRATE;
ONEFIBER_LNK_MIGRATE_CITY;
ONEFIBER_LNK_MIGRATE_NLDC;
--END;
-- NULL;
END PROC_MIGRATE_ONEIBER;
/
Update: Check this small code of how it should be. All procedures created in this answer are just for demo. (Make sure that the procedure that you are calling is not INVALID)
SQL>
SQL> CREATE OR REPLACE PROCEDURE ONEFIBER_LNK_MIGRATE AS
2 BEGIN
3 NULL;
4 END;
5 /
Procedure created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE ONEFIBER_LNK_MIGRATE_CITY AS
2 BEGIN
3 NULL;
4 END;
5 /
Procedure created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE ONEFIBER_LNK_MIGRATE_NLDC AS
2 BEGIN
3 NULL;
4 END;
5 /
Procedure created.
SQL>
SQL> CREATE OR REPLACE PROCEDURE PROC_MIGRATE_ONEIBER AS
2 BEGIN
3 ONEFIBER_LNK_MIGRATE;
4 ONEFIBER_LNK_MIGRATE_CITY;
5 ONEFIBER_LNK_MIGRATE_NLDC;
6 END PROC_MIGRATE_ONEIBER;
7 /
Procedure created.
SQL>
I am using Oracle 12c database and trying to run a package using SQL commands.
CREATE OR REPLACE PACKAGE "PK_CP_OTM" as
FUNCTION F_CP_OPTIMIZATION (
v_current_day IN VARCHAR2,
v_branch_code IN VARCHAR2)
RETURN VARCHAR2;
END PK_CP_OTM;
When I try to execute it using:
DECLARE
BEGIN
EXECUTE IMMEDIATE PK_CP_OTM.F_CP_OPTIMIZATION('20190409','BRNCD001');
END;
It shows:
ORA-00900: invalid SQL statement
ORA-06512: at line 3
00900. 00000 - "invalid SQL statement"
Thanks for your help.
As #Littlefoot said, you don't need dynamic SQL here, you can make a static call; but as you are calling a function you do need somewhere to put the result of the call:
declare
l_result varchar2(30); -- make it a suitable size
begin
l_result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
end;
/
In SQL*Plus, SQL Developer and SQLcl you can use the execute client command (which might have caused some confusion) and a bind variable for the result:
var result varchar2(30);
exec :result := pk_cp_otm.f_cp_optimization('20190409','BRNCD001');
print result
There's nothing dynamic here, so - why would you use dynamic SQL at all?
Anyway: if you insist, then you'll have to select the function into something (e.g. a local variable). Here's an example
First, the package:
SQL> set serveroutput on
SQL>
SQL> create or replace package pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2;
6 end pk_cp_otm;
7 /
Package created.
SQL> create or replace package body pk_cp_otm
2 as
3 function f_cp_optimization (v_current_day in varchar2,
4 v_branch_code in varchar2)
5 return varchar2
6 is
7 begin
8 return 'Littlefoot';
9 end;
10 end pk_cp_otm;
11 /
Package body created.
How to call the function?
SQL> declare
2 l_result varchar2 (20);
3 begin
4 execute immediate
5 'select pk_cp_otm.f_cp_optimization (''1'', ''2'') from dual'
6 into l_result;
7
8 dbms_output.put_line ('result = ' || l_result);
9 end;
10 /
result = Littlefoot
PL/SQL procedure successfully completed.
SQL>
Inside packA I have a procedure:
procedure testA
is
v1 varchar2(3200) = 'schema1.packB.test2('''||P1||''','''||P2||''',''Name1'',''Name2'',20,30)';
begin
EXECUTE IMMEDIATE v1;
end;
when I test it:
begin
packA.testA();
end;
I get error: "invalid SQL statement"
But, when I execute v1 from the command line, like:
excecute schema1.packB.test2('ABC','DEF','Name1','Name2',20,30);
it's working.
I printed v1 to see what is executed, and looks exactly the same as "schema1.packB.test2('ABC','DEF','Name1','Name2',20,30)"
You need to include BEGIN..END when running a stored procedure using EXECUTE IMMEDIATE.
v1 varchar2(3200) = 'BEGIN schema1.packB.test2('''||P1||''','''||P2||''',''Name1'',''Name2'',20,30) END;';
EXECUTE IMMEDIATE runs an SQL(DML/select) statements or PL/SQL anonymous block
Also, consider using BIND variables instead of PL/SQL variables directly.
'schema1.packB.test2( :p1, :p2, :p3, :p4 ,20,30)' USING P1,P2, 'Name1', 'Name2'
You need a block to use execute immediate to call a procedure.
For example:
SQL> create or replace package pck is
2 procedure proc;
3 end;
4 /
Package created.
SQL> create or replace package body pck is
2 procedure proc is
3 begin
4 null;
5 end;
6 end;
7 /
Package body created.
SQL> begin
2 execute immediate 'pck.proc;';
3 end;
4 /
begin
*
ERROR at line 1:
ORA-00900: invalid SQL statement
ORA-06512: at line 2
SQL> begin
2 execute immediate 'begin pck.proc; end;';
3 end;
4 /
PL/SQL procedure successfully completed.
Also, while using an execute immediate, consider passing parameters with bind variables. For example, you can (better) re-write the following
begin
execute immediate 'begin pck.proc(''x''); end;';
end;
as
begin
execute immediate 'begin pck.proc(:1); end;' using 'x';
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.
This is the package specification:
CREATE OR REPLACE PACKAGE employee_info
IS
PROCEDURE p;
FUNCTION f RETURN BOOLEAN;
END employee_info;
This is the package body:
CREATE OR REPLACE PACKAGE body employee_info
IS
PROCEDURE p IS
BEGIN
dbms_output.put_line('This is procedure');
dbms_output.put_line(chr(10));
END;
FUNCTION f RETURN BOOLEAN IS
BEGIN
dbms_output.put_line('This is function ');
dbms_output.put_line(chr(10));
RETURN true;
END;
BEGIN
dbms_output.put_line('This is the initialization section of package body');
END employee_info;
When should I use this initialization section of the package?
As in the above example, when I first execute the code then only i can see that begin..end of package body is executed and for rest of call it is not executed.
I am executing the procedure and function using below statements:
execute employee_info.p;
declare
p1 boolean;
begin
p1 := employee_info.f;
end;
Package initialization section as the name suggest is executed when package is initialized. This happens when first procedure/function from the package is executed after session is established or after package is (re)compiled. The purpose is to initialize the global state of the package that can be used during session lifetime. All package global variables are kept and you can access them later.
Example:
HUSQVIK#hq_pdb_tcp> CREATE OR REPLACE PACKAGE test_package
2 IS
3 PROCEDURE foo;
4 END;
5 /
Package created.
HUSQVIK#hq_pdb_tcp> CREATE OR REPLACE PACKAGE BODY test_package
2 IS
3 PROCEDURE foo
4 IS
5 BEGIN
6 DBMS_OUTPUT.PUT_LINE('Procedure executed. ');
7 END;
8
9 BEGIN
10 DBMS_OUTPUT.PUT_LINE('Package initialized. ');
11 END;
12 /
Package body created.
HUSQVIK#hq_pdb_tcp> EXEC test_package.foo
Package initialized.
Procedure executed.
PL/SQL procedure successfully completed.
HUSQVIK#hq_pdb_tcp> EXEC test_package.foo
Procedure executed.
PL/SQL procedure successfully completed.
HUSQVIK#hq_pdb_tcp>
You see that after package is compiled the initialization section is executed when procedure foo is executed. The package is initialized now. Any subsequent execution of foo executes only the procedure.