Initialization section of the package - oracle

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.

Related

PLSQL Subtype of Nested Table PLS-00355: use of pl/sql table not allowed in this context

Edit: as per the answers, this works in 21C but not before. Looks like it is an Oracle bug that was fixed. The workaround in previous versions is provided as the accepted answer.
In PL/SQL, a subtype of a nested table behaves inconsistently compared to a regular nested table. It seems like it is not possible to use a subtype of a nested table. Is this correct?
create or replace package test_subtype_pkg
is
type t_foos is table of varchar2(10);
subtype t_bars is t_foos;
procedure main;
end;
/
The following l_bars := t_bars() fails to compile with PLS-00355: use of pl/sql table not allowed in this context
create or replace package body test_subtype_pkg
is
procedure main
is
l_foos t_foos;
l_bars t_bars;
begin
l_foos := t_foos(); -- compiles correctly
l_bars := t_bars(); -- PLS-00355: use of pl/sql table not allowed in this context
end;
end;
/
However, the following compiles without error. During run time it fails with ORA-06531: Reference to uninitialized collection:
create or replace package body test_subtype_pkg
is
procedure main
is
l_bars t_bars;
begin
l_bars.extend; -- At run time, ORA-06531: Reference to uninitialized collection
l_bars(1) := 'foo';
end;
end;
/
Is it possible to use a subtype of a nested table?
You can use the sub-type but it only appears to work if you call the constructor from the base-type:
create or replace package test_subtype_pkg
is
type t_foos is table of varchar2(10);
subtype t_bars is t_foos;
procedure main;
end;
/
create or replace package body test_subtype_pkg
is
procedure main
is
l_foos t_foos;
l_bars t_bars;
begin
l_foos := new t_foos();
l_bars := new t_foos();
l_bars.extend;
l_bars(1) := 'foo';
end;
end;
/
Note: the NEW keyword is optional.
Compiles without errors and then:
BEGIN
test_subtype_pkg.main();
END;
/
Works without a runtime error.
Note: You get the runtime error in your second example because you do not initialise the collection as you never call a constructor.
Oracle 18 fiddle
I don't have 18c; this is 21cXE and both codes work OK.
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
SQL> create or replace package test_subtype_pkg
2 is
3 type t_foos is table of varchar2(10);
4 subtype t_bars is t_foos;
5
6 procedure main;
7 end;
8 /
Package created.
You said that this failed on your database; it works for me:
SQL> create or replace package body test_subtype_pkg
2 is
3 procedure main
4 is
5 l_foos t_foos;
6 l_bars t_bars;
7 begin
8 l_foos := t_foos(); -- compiles correctly
9 l_bars := t_bars(); -- PLS-00355: use of pl/sql table not allowed in this context
10 end;
11 end;
12 /
Package body created.
SQL> exec test_subtype_pkg.main;
PL/SQL procedure successfully completed.
SQL>
Your code that compiles, but doesn't work - it is because you really didn't initialize the collection (see line #5 which shows how to do it):
SQL> create or replace package body test_subtype_pkg
2 is
3 procedure main
4 is
5 l_bars t_bars := t_bars();
6 begin
7 l_bars.extend; -- At run time, ORA-06531: Reference to uninitialized collection
8 l_bars(1) := 'foo';
9 end;
10 end;
11 /
Package body created.
SQL> exec test_subtype_pkg.main;
PL/SQL procedure successfully completed.
SQL>

Executing functions in sequence defined in a package

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.

Package in Oracle (facing error while calling it)

I am using Oracle 11G database. I have created a package as described below:
create or replace package forward_emp is
Function emp_sal_avg return number;
Procedure emp_new_sal;
End forward_emp;
/
package created.
Then I created the package body:
create or replace package body forward_emp is
Function emp_sal_avg return number is
avg_sal emp.salary%type;
Begin
Select avg (salary) into avg_sal
from emp;
Return avg_sal;
End emp_sal_avg;
Procedure emp_new_sal is
Begin
Insert into Emp (salary) values (emp_sal_avg);
End emp_new_sal;
End forward_emp;
/
Package body created.
Now when I tried calling the package its is showing error.
Call forward_emp.emp_new_sal;
ORA- 06576: not a valid function or procedure.
Please help. Not been able to understand the problem.
CALL is a SQL statement, not a PL/SQL statement, not a SQLPLUS command. CALL can be used in SQLPLUS directly, but, when you execute a function, the returning result should be stored somewhere, hence into clause of the call statement is needed. And parenthesis, even if a function or a stored procedure has no arguments, kind of mandatory.
Here is an example:
SQL> create or replace package pkg as
2 function f1 return number;
3 procedure p1;
4 end;
5 /
Package created.
SQL> create or replace package body pkg as
2 function f1 return number is
3 begin
4 return 12345;
5 end;
6 procedure p1 is
7 begin
8 null; -- does nothing
9 end;
10 end;
11 /
Package body created.
Now let's execute those procedure and function defined withing the PKG package:
-- variable, which is going to store result the function returns
SQL> variable f_res number;
-- executing the F1 function
SQL> call pkg.f1() into :f_res;
Call completed.
-- print the result
SQL> print f_res;
F_RES
----------
12345
-- executing the P1 procedure
SQL> call pkg.p1();
Call completed.
This what happens if we simply omit parenthesis or do not specify into clause when executing a stored procedure or a type method using CALL statement:
SQL> call pkg.p1;
call pkg.p1
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
SQL> call pkg.f1 into :f_res;
call pkg.f1 into :f_res
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
SQL> call pkg.f1();
call pkg.f1()
*
ERROR at line 1:
ORA-06576: not a valid function or procedure name
I think you're trying to use CALL as a SQL*Plus command. As AHWNN pointed out, in sqlplus you would use EXECUTE to run the procedure. However you could in SQL test with CALL by using an anonymous block:
BEGIN
CALL the_pack.the_proc;
END;
/

Oracle 10g procedure executing no parallel

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.

Procedure in package specification

I have a package named save_db_values
I have two procedures named store_records and another one called db_activities.
db_activities will be called from my application by passing all values in db_activities I will be calling store_records procedure to do insert and delete.
Do I need to define store_records procedure in package specification? When I did not define store_records in specification I am getting error store_records not declared in this scope.
store_records procedure I do not want to expose and hence I did not add in specification.
How can I resolve this issue?
If you do not want some procedures to be publicly available you may not to declare them in the package specification. Declare them only in the package body. The cause of the error you are facing is declaration order of the procedures in the package body or lack of forward declaration. For example:
create or replace package Test_pkg as
2 procedure Proc1;
3 end;
4 /
Package created
create or replace package body Test_pkg as
2
3 procedure proc1 is
4 begin
5 proc2;
6 end;
7
8 procedure Proc2 is
9 begin
10 dbms_output.put_line('proc2 is being executed');
11 end;
12
13 end;
14 /
Warning: Package body created with compilation errors
Error: PLS-00313: 'PROC2' not declared in this scope
This is happening because we are calling Proc2 which declared later in the package. In this case our choices are:
Declare pro2 before the procedure which calls it
create or replace package body Test_pkg as
2
3
4 procedure Proc2 is
5 begin
6 dbms_output.put_line('proc2 is being executed');
7 end;
8
9 procedure proc1 is
10 begin
11 proc2;
12 end;
13
14 end;
15 /
Package body created
Use forward declaration.
create or replace package body Test_pkg as
2
3 procedure Proc2;
4
5 procedure proc1 is
6 begin
7 proc2;
8 end;
9
10 procedure Proc2 is
11 begin
12 dbms_output.put_line('proc2 is being executed');
13 end;
14
15
16 end;
17 /
Package body created
SQL> exec test_pkg.Proc1;
proc2 is being executed
PL/SQL procedure successfully completed
You can declare procedures just in the body, but the order in which they appear is relevant; the calling procedure must be defined after the called procedure. Or you use a forward declaration to make it easier:
package save_db_values is
procedure db_activities;
end save_db_values;
package body save_db_values is
procedure store records; -- forward declaration
procedure db_activities is
begin
store_records;
end;
procedure store records is
begin
null;
end;
end save_db_values;
It is happening because of writing procedure's body in the package body .
if you are not declaring any procedure in the package specification then you should write it at first place.
it will work :)

Resources