PL/SQL - will statements execute only once a procedure is completed? - oracle

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.

Related

Calling another PL/SQL procedure within a procedure

I'm new to PL/SQL & would greatly appreciate help in this. I've created a procedure to copy contracts. Now I want to call another procedure from within this procedure which shall copy all the programs related to the contract I'm copying. One contract can have multiple programs.
You cal call another procedure in another package by using PackageName.ProcedureName(vcParameters => 'InputParameter1'); If the procedure is in the same package you could do it without the PackageName, so just ProcedureName(vcParameters => 'InputParameter1');
You call a procedure by simply putting its name and parameters in your code, e.g.
begin
dbms_output.put_line('Demo');
end;
or within a procedure,
create or replace procedure demo
as
begin
dbms_output.put_line('Demo');
end;
I have used dbms_output.put_line as an example of a procedure, but obviously any other procedure would be called the same way:
begin
foo;
bar(1);
demo(true, 'Bananas', date '2018-01-01');
end;
For some reason, many beginners are tempted to add exec before the procedure call. I don't know where that comes from because PL/SQL has no such keyword. Possibly they are thinking of the SQL*Plus execute command, which can be abbreviated to exec. However, SQL*Plus is a separate command line utility with its own commands that have nothing to do with the PL/SQL language.

ORACLE trigger before procedure execution

Is it possible to fire a trigger before a specific procedure starts execution?
For example I have a package "A", and a procedure "B" inside package "A".
So when I call A.B procedure i want to fire a trigger.
I'm using oracle 11gR2.
is it possible to fire a trigger before a specific procedure starts execution?
No, you cannot manually fire a trigger without any DML operation on the table. Triggers are designed to act implicitly on any DML action. Trigger is a (side)effect of an action and not an action in itself.
I don't think you need a trigger for your requirement. You could call a procedure before executing the procedure A.B. Put your business logic accordingly. PL/SQL is a procedural language. So, if you put another procedure say procedure C before A.B, then A.C will be executed before A.B.
Triggers cannot be called directly. Instead they are fired automatically when you perform an insert/update or delete on a table that has triggers. So like in your case, on calling A.B procedure, you can perform an insert / update or delete that will force a trigger to fire.
If you have an existing trigger on a table and you want its logic to be executed under other circumstances, then place the logic in a procedure and call that procedure from the trigger, and from any other code that needs to execute it.

Why execution of this block never ends?

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';

Scheduler Oracle Stored Procedure

I have a simple stored procedure I wanted Oracle to execute weekly and I have put it in the Oracle Scheduler. It was created fine and the scheduled task seems to execute (no error) but my stored procedure does not execute. I have admin right on the database and I do not get any error. Just do not get the result I wanted.
Below is the details of the job:
The creation was successful
The stored procedure is a simple one
create or replace
PROCEDURE DELETEBOGUSLETTERRECORDS AS
BEGIN
DELETE FROM BOGUSLETTERS;
COMMIT;
END DELETEBOGUSLETTERRECORDS;
The procedure was tested outside the scheduler, executed fine and all records in the specified tables were deleted.
However, that same procedure was not executed properly when it was scheduled. I even had the job run immediately, but after it was run, the records were not deleted. No error whatsoever.
What is the issue? Thanks!
I am not sure, but we execute the procedure like this:
[ Type of Job: PL/SQL Block ]
BEGIN
SCHEMA_NAME.STORED_PROC_NAME;
END;
And they run fine like this.

compiling invalid oracle procedures

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;

Resources