Suppose we have a package PACK
package PACK is procedure DO; end PACK;
package body PACK is
procedure DO is begin DBMS_OUTPUT.PUT_LINE('Hello from PACK'); end;
end PACK;
Why does execution of the block
begin
PACK.do;
execute immediate 'alter package PACK compile';
end;
never end (session seems to be hanging)? However, separate execution of the first and the second line (in different anonymous blocks) is successful.
The package is been in use, that means an instance of it is still active. So, unless it is been killed, you cannot alter its state.
When a procedure or any stored function is been invoked, a locked is acquired by that session over that object state. Unless the caller completes the module, the lock remain active.
In your case, you are trying to alter the package within same PL/SQL block which called it. It results with deadlock. The PL/SQL block trying to dynamically execute your DDL, but there's lock already in place, when the package is first called!
Please note that same PL/SQL can still call the package after this
dynamic DDL (It can be DROP too!). So for consistency sake, the lock
is not released unless the entire PL/SQL is been completed!
ORA-04021: timeout occurred while waiting to lock object ..
Where-as ,when you call in a separate PL/SQL block, the lock would already be released. Before the DDL is invoked.
Trying running this SQL in a different session.
select * from v$access where object = 'PACK';
Related
Hopefully this is a simple question. Say I have a block like this:
BEGIN
a_random_procedure ('input','output');
... DML statements ...
END;
Question: Will DML statements execute only after a_random_procedure is completed? For that matter, will anything after a_random_procedure execute only after it is completed?
ADD-ON: What about when a_random_procedure is executing another procedure within it?
Yes, the "DML statements" will execute only after "a_random_procedure" is completed. If you have another procedure within it, the first procedure will wait until the procedure within it is completed too. In any moment when you call another procedure or function, the next code line will wait until the procedure or function called before, has finished his execution
PL/SQL is like in name of launguage - procedural, so the answer for Your question is yes, dml will be executed after procedure finish, even if procedure calls other procs/functions. Yo can take care about case when Your procedure crash, then it will not be completed, and then thera are 2 options, if the exception in procedure is handled then Your dml will be executed. If exception is not handled, it will be populated level up, in this case to Your anonymous block, and crash(stop) it as well and it will not execute DML.
i m getting below error when i m trying to execute procedure "PROCEDURE_NAME" under procedure "CALLING_PROCEDURE_NAME".
But my PROCEDURE_NAME is already in valid state and successfully using in some other procedures.
ORA-04068: existing state of packages has been discarded
ORA-04065: not executed, altered or dropped stored procedure ""PROCEDURE_NAME""
ORA-06508: PL/SQL: could not find program unit being called: ""PROCEDURE_NAME""
ORA-06512: at ""CALLING_PROCEDURE_NAME"", line LINE_NO
ORA-06512: at line 1
But my PROCEDURE_NAME is already in valid state and successfully using
in some other procedures.
The session where the package is currently called, it retains that state of the package. If you recompile the package, then the moment the package is called in that session again, you will hit this error.
You can execute DBMS_SESSION.RESET_PACKAGE; to free the memory, cursors, and package variables after the PL/SQL call that made the invocation finishes running.
You could close all existing sessions and re-execute.
You could make the package, SERIALLY_REUSABLE Packages by using PRAGMA SERIALLY_REUSABLE; statement. If a package is SERIALLY_REUSABLE, its package state is stored in a work area in a small pool in the system global area (SGA). The package state persists only for the life of a server call.
I have a wrapper procedure(proc_main) that calls some procedures within.
create or replace Procedure proc_main
as
begin
proc_child1;
proc_child2;
proc_child3;
proc_compile_invalids; -- This invokes "alter procedure <procedure_name> compile" statement for all the invalids.
end;
/
proc_child procedures apply some processing logic that involves some steps to rename the tables within.
This invalidates the procedures which is the reason why I have the proc_compile_invalids procedure to set them to a valid state again.
My problem is: when I execute the proc_main procedure, it invalidates the main procedure along with the inner child ones.
Hence, When the proc_compile_invalids is called as a last step, it hangs as it is trying to recompile the main calling procedure.
Obviously, it is not an issue if i remove the last step and execute it separately.
I know I could separate them out as 2 different calls by commenting the compile proc and executing it as a stand alone.
And i also am aware it is a cosmetic step as oracle would try to compile a procedure before executing the next time. So, the invalids become valid anyway.
But, at the end of the execution for that day, they all are in an invalid state and I get questioned by the powers be if it can be avoided !
So, just wanted to know if I can avoid separating the calls and still retain it as a last step in the main procedure.
Any thoughts/pointers much appreciated.
You can use dynamic SQL to break the dependency:
CREATE OR REPLACE PROCEDURE proc_main AS
BEGIN
EXECUTE IMMEDIATE 'BEGIN proc_child1; END;';
EXECUTE IMMEDIATE 'BEGIN proc_child2; END;';
EXECUTE IMMEDIATE 'BEGIN proc_child3; END;';
proc_compile_invalids; -- This invokes
-- "alter procedure <procedure_name> compile"
-- statement for all the invalids.
END;
Oracle 11g onward
You can use compile_schema procedure of dbms_utility package instead of proc_compile_ivalids in your main procedure to recompile all invalid procedures, functions, packages, and triggers in the specified schema
create or replace Procedure proc_main
as
begin
Proc_child1;
proc_child2;
proc_child3;
dbms_utility.compile_schema(schema, false);
end;
Is it possible to display comments to user while executing a procedure in a package. My package has 3 procedures. I am calling each one after other. I want to display comments on console like procedure xyz is executing, procedure executed successfully. I added comments inside procedure like DBMS_OUTPUT.PUT_LINE('PROCEDURE EXECUTED SUCCESSFULLY') but didn't worked for me.
FYI i am using oracle 11g in windows 7 system.
You can't use DBMS_OUTPUT to display information on a procedure while it is running. This is because DBMS_OUTPUT.put_line doesn't display data on screen, rather, the data is put in a queue that is later read by the calling client (This queue is also invisible outside of its transaction). If you use SQL*Plus the queue is read and displayed automatically at the end of the procedure if you have SET SERVEROUTPUT ON.
Other means exist to follow the progress of a procedure while it is running:
You could write to a file instead. UTL_FILE.put_line will write directly if the parameter autoflush is set to true.
You could set session variables with DBMS_APPLICATION_INFO. These variables can be read with another session by querying v$session.
You could use AUTONOMOUS_TRANSACTIONS to log progress information in a dedicated table. This table can be queried by another session simultaneously.
As you can see you would need another process to read the information while it is written. In some applications, this would be achieved by running the main batch job in a new separate process, for example by calling DBMS_JOB or DBMS_SCHEDULER while the calling transaction loops on the progress table or file until the job is complete.
SQL*Plus is not an interactive client, you will need some more sophisticated environment to achieve this functionality.
This information should be easy to find, but I haven't had any luck.
When I have a BEGIN - END block in a PL/SQL, does it behave as an atomic transaction, that will try to commit on hitting the END block and if anything goes wrong rolls back the changes?
If not, how do I make sure that the code inside the BEGIN - END block behaves like an atomic transaction and how does the block behave "by default"?
EDIT: I am running from a stored procedure and I am using an implicit block, I think.
Firstly, BEGIN..END are merely syntactic elements, and have nothing to do with transactions.
Secondly, in Oracle all individual DML statements are atomic (i.e. they either succeed in full, or rollback any intermediate changes on the first failure) (unless you use the EXCEPTIONS INTO option, which I won't go into here).
If you wish a group of statements to be treated as a single atomic transaction, you'd do something like this:
BEGIN
SAVEPOINT start_tran;
INSERT INTO .... ; -- first DML
UPDATE .... ; -- second DML
BEGIN ... END; -- some other work
UPDATE .... ; -- final DML
EXCEPTION
WHEN OTHERS THEN
ROLLBACK TO start_tran;
RAISE;
END;
That way, any exception will cause the statements in this block to be rolled back, but any statements that were run prior to this block will not be rolled back.
Note that I don't include a COMMIT - usually I prefer the calling process to issue the commit.
It is true that a BEGIN..END block with no exception handler will automatically handle this for you:
BEGIN
INSERT INTO .... ; -- first DML
UPDATE .... ; -- second DML
BEGIN ... END; -- some other work
UPDATE .... ; -- final DML
END;
If an exception is raised, all the inserts and updates will be rolled back; but as soon as you want to add an exception handler, it won't rollback. So I prefer the explicit method using savepoints.
BEGIN-END blocks are the building blocks of PL/SQL, and each PL/SQL unit is contained within at least one such block. Nesting BEGIN-END blocks within PL/SQL blocks is usually done to trap certain exceptions and handle that special exception and then raise unrelated exceptions. Nevertheless, in PL/SQL you (the client) must always issue a commit or rollback for the transaction.
If you wish to have atomic transactions within a PL/SQL containing transaction, you need to declare a PRAGMA AUTONOMOUS_TRANSACTION in the declaration block. This will ensure that any DML within that block can be committed or rolledback independently of the containing transaction.
However, you cannot declare this pragma for nested blocks. You can only declare this for:
Top-level (not nested) anonymous PL/SQL blocks
List item
Local, standalone, and packaged functions and procedures
Methods of a SQL object type
Database triggers
Reference: Oracle
You don't mention if this is an anonymous PL/SQL block or a declarative one ie. Package, Procedure or Function.
However, in PL/SQL a COMMIT must be explicitly made to save your transaction(s) to the database. The COMMIT actually saves all unsaved transactions to the database from your current user's session.
If an error occurs the transaction implicitly does a ROLLBACK.
This is the default behaviour for PL/SQL.
The default behavior of Commit PL/SQL block:
You should explicitly commit or roll back every transaction. Whether you issue the commit or rollback in your PL/SQL program or from a client program depends on the application logic. If you do not commit or roll back a transaction explicitly, the client environment determines its final state.
For example, in the SQLPlus environment, if your PL/SQL block does
not include a COMMIT or ROLLBACK statement, the final state of your
transaction depends on what you do after running the block. If you
execute a data definition, data control, or COMMIT statement or if you
issue the EXIT, DISCONNECT, or QUIT command, Oracle commits the
transaction. If you execute a ROLLBACK statement or abort the SQLPlus
session, Oracle rolls back the transaction.
https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/sqloperations.htm#i7105