compiling invalid oracle procedures - oracle

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;

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.

How to execute procedure in APEX SQL script?

I am trying to understand how to use multiple procedures in APEX SQL script. First I don't really need stored procedure, but not sure how to declare simple procedure in APEX SQL script. So this is my attempt:
create or replace procedure test1 as
begin
DBMS_OUTPUT.ENABLE;
dbms_output.put_line('test1');
end;
execute test1;
This gives me an error:
Error at line 7: PLS-00103: Encountered the symbol "EXECUTE"
So questions - how to create regular/not stored/ procedures in one SQL script and then call them. What is the entry point of execution in APEX SQL script?
UPD (At the first time I understood question totally wrong)
Correct version of a script:
create or replace procedure test1 as
begin
DBMS_OUTPUT.ENABLE;
dbms_output.put_line('test1');
end;
/
begin
test1;
end;
/
Documentation says, that script can contain inly SQL and PL/SQL commands. Commands of sqlplus will be ignored.
OLD VERSION (Let stay here)
In APEX pages you can use PL/SQL anonymous blocks. For example, you can create process (APEX has some types of them) or PL/SQL region, and use following:
declare
...
begin
some_proc(:P_MY_ITEM);
end;
Here you can invoke any procedure and do anything else that allowed by PL/SQL. Also you can use parameters like :P_ITEM_NAME to get and set values of page and application items.

Parallelizing calls in PL/SQL

I have a package with a proc that will execute a number of other procedures, like so:
CREATE PACKAGE BODY pkg IS
CREATE PROCEDURE do
IS
BEGIN
other_pkg.other_proc;
other_pkg2.other_proc2;
other_pkg3.other_proc3;
END;
END;
Is there any way to have the procedures execute in parallel rather than serially?
EDIT:
Is this the proper way to use DBMS_SCHEDULER in this instance:
CREATE PACKAGE BODY pkg IS
CREATE PROCEDURE do
IS
BEGIN
DBMS_SCHEDULER.CREATE_JOB('job_other_pkg.other_proc', 'STORED_PROCEDURE', 'other_pkg.other_proc;');
DBMS_SCHEDULER.RUN_JOB('job_other_pkg.other_proc', FALSE);
-- ...
END;
END;
You can use the dbms_job (or dbms_scheduler) package to submit jobs that will run in parallel. If you are using dbms_job, submitting the jobs will be part of the transaction so the jobs will start once the transaction completes.
CREATE PACKAGE BODY pkg IS
CREATE PROCEDURE do
IS
l_jobno pls_integer;
BEGIN
dbms_job.submit(l_jobno, 'begin other_pkg.other_proc; end;' );
dbms_job.submit(l_jobno, 'begin other_pkg2.other_proc2; end;' );
dbms_job.submit(l_jobno, 'begin other_pkg3.other_proc3; end;' );
END;
END;
If you are using dbms_scheduler, creating a new job is not transactional (i.e. there would be implicit commits each time you created a new job) which may cause problems with transactional integrity if there is other work being done in the transaction where this procedure is called. On the other hand, if you are using dbms_scheduler, it may be easier to create the jobs in advance and simply run them from the procedure (or to use dbms_scheduler to create a chain that runs the job in response to some other action or event such as putting a message on a queue).
Of course, with either solution, you'd need to then build the infrastructure to monitor the progress of these three jobs assuming that you care when and whether they succeed (and whether they generate errors).
If you are going to use DBMS_SCHEDULER
There is no need to use dynamic SQL. You can ditch the EXECUTE IMMEDIATE and just call the DBMS_SCHEDULER package's procedures directly just like you would any other procedure.
When you call RUN_JOB, you need to pass in a second parameter. The use_current_session parameter controls whether the job runs in the current session (and blocks) or whether it runs in a separate session (in which case the current session can continue on and do other things). Since you want to run multiple jobs in parallel, you would need to pass in a value of false.
Although it is not required, it would be more conventional to create the jobs once (with auto_drop set to false) and then just run them from your procedure.
So you would probably want to create the jobs outside the package and then your procedure would just become
CREATE PACKAGE BODY pkg IS
CREATE PROCEDURE do
IS
BEGIN
DBMS_SCHEDULER.RUN_JOB('job_other_pkg.other_proc', false);
DBMS_SCHEDULER.RUN_JOB('job_other_pkg2.other_proc2', false);
DBMS_SCHEDULER.RUN_JOB('job_other_pkg3.other_proc3', false);
END;
END;
Another solution is to hack Oracle's SQL parallelism mechanism. See answer to How to execute a stored procedure in a different session in same time in pl/sql .
It uses William Robertson's great solution Parallel PL/SQL launcher.
(tested with Oracle 10g)

oracle plsql: retrieve runtime parameter values when you call a procedure

I need a generalized method to get list of runtime parameters (values) when I call a procedure. I need something similar to the $$PLSQL_UNIT that returns the name of the running procedure.
(plsql Oracle 10g)
E.g. look at this sample procedure:
(it simply prints its own name and parameters )
CREATE OR REPLACE PROCEDURE MY_PROC(ow in varchar2, tn IN varchar2)
IS
BEGIN
dbms_output.put_line('proc_name: '||$$PLSQL_UNIT||' parameters: '|| ow||' '||tn );
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERRORE: ' ||SQLERRM);
END MY_PROC;
/
Running procedure produces the following output:
SQL>
1 BEGIN
2 IBAD_OWN.MY_PROC('first_par', 'second_par');
3 END;
4 /
proc_name: MY_PROC parameters: first_par second_par
PL/SQL procedure successfully completed.
I'm not satisfy because I can't copy and paste in all my procedures because I have to hard code each procedure to set their right parameter variables.
Thanks in advance for the help.
It isn't possible to dynamically retrieve the values of parameters passed to a procedure in Oracle PL/SQL. The language simply isn't designed to handle this kind of operation.
Incidentally, in a procedure that is located within a package, $$PLSQL_UNIT will only return the package's name. I find it's better to define a consistently-named constant within each procedure that contains the procedure's name.
When I wanted the same functionality as yours I didn't find any good built-in solution.
What I did is: wrote DB-level trigger which modifies original body of function/procedure/package.
This trigger adds immediatly after "begin" dynamically generated piece of code from "user_arguments".
Plus, after that I include into this trigger the code, that logs calls of procs when exception occures.
Plus, you can trace procs calls, and many more interisting things.
But this solution works fine only for preproduction because performance decreases dramatically.
PS. Sorry for my bad English.

Convert a PL/SQL script to a stored procedure

Right now I'm importing and transforming data into an Oracle database as follows:
A program regularly polls specific folders, once a file is found it executes a batch file which does some light transformation in Python & bash and then calls SQL*Loader to load the CSV file into a staging table.
Then, the batch script calls an SQL script (via SQLPlus) to do the final transformation and insert the transformed data into master tables for their respective staging table.
The problem with this method is there's no error-handling on the SQLPlus side, eg. if an 'insert into' statement fails because of a violated constraint (or any other reason), it will still continue to execute the rest of the statements contained in the SQL script.
Ideally, if any exception occurs, I'd prefer all changes to be rolled back and details of the exception inserted into an etl log table.
Stored procedures seem to be a good fit as exception handling is built-in. However, I'm struggling with the syntax - specifically how I can take my big SQL scripts (which are just a combination of INSERT INTO, UPDATE, CREATE, DROP, DELETE, etc statements) and throw them into a stored procedure with some very basic error handling.
What I'm hoping for is either:
a quick & dirty dummy's guide to taking my depressing blob of PL/SQL and get it to execute within a stored procedure OR
Any alternative (if a stored proc isn't appropriate) which offers the same functionality, ie. a way to execute a bunch of SQL statements and rollback if any of these statements throw an exception.
About my attempts - I've tried copying portions of my SQL scripts into a stored procedure but they always fail to compile with the error 'PLS-00103 Encountered the symbol when expecting one of the following'. eg.
CREATE OR REPLACE PROCEDURE ETL_2618A AS
BEGIN
DROP SEQUENCE "METER_REPORTING"."SEQ_2618";
CREATE SEQUENCE SEQ_2618;
END ETL_2618A;
Oracle documentation isn't terribly accessible and I've not had much luck with googling/searching StackOverflow, but I apologise if I've missed something obvious.
To do DDL in PL/SQL you need to use dynamic sql.
CREATE OR REPLACE PROCEDURE testProc IS
s_sql VARCHAR2(500);
BEGIN
s_sql := 'DROP SEQUENCE "METER_REPORTING"."SEQ_2618"';
EXECUTE IMMEDIATE s_sql;
s_sql := 'CREATE SEQUENCE "METER_REPORTING"."SEQ_2618"';
EXECUTE IMMEDIATE s_sql;
EXCEPTION
WHEN OTHERS THEN
NULL;
end testProc;
/
If you run the script in sqlplus you can use:
whenever sqlerror
to control what should happen when an error occurs.
http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12052.htm
Adding exception handling to a PL/SQL proc or script isn't difficult, but of course some coding is required. Here's your procedure dressed up slightly with some very basic error reporting added:
CREATE OR REPLACE PROCEDURE ETL_2618A AS
nCheckpoint NUMBER;
BEGIN
nCheckpoint := 1;
EXECUTE IMMEDIATE 'DROP SEQUENCE "METER_REPORTING"."SEQ_2618"';
nCheckpoint := 2;
EXECUTE IMMEDIATE 'CREATE SEQUENCE SEQ_2618';
RETURN;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ETL_2618A failed at checkpoint ' || nCheckpoint ||
' with error ' || SQLCODE || ' : ' || SQLERRM);
RAISE;
END ETL_2618A;
Not tested on animals - you'll be first! :-)

Resources