How to ensure that two procedures are never executed simultanously? - oracle

Procedure 1 checks document status and changes it to the next step.
Procedure 2 checks document status and reverts it by one step.
The issue: if accidentally the procedures get called simultaneously, procedure 2 changes the status first, and then procedure 1 doesn't execute as it should, because it gets the wrong status.
Is it possible to ensure that they never execute simultaneously for the same document?

You can set modules of the procedures with:
DBMS_APPLICATION_INFO.SET_MODULE()
And then check whenever the module is running:
SELECT 1
FROM v$session
WHERE MODULE = <your MODULE>;

Related

Strange oracle job behavior

I face a problem with an oracle job
This job runs every 10 min and it calls a procedure from a package.
Inside the procedure, there is a select and then a loop.
The select could return from 10 to 1000 rows
For one week everything was running fine (, but suddenly it is like the job is not calling the procedure.
It runs successfully every 10 minutes but the procedure is not affecting the rows.
I run the procedure on its own and it works properly.
DBMS Scheduler Run details not showing anything. Everything was successfull. The only difference it that before the problem the run duration was 5 to 30 seconds, and after the problem the duration is just one second.
Do you know what else to look?
Log what's going on within the procedure. How? Create an autonomous transaction procedure which inserts log info into a separate table and commits; as it is an autonomous transaction procedure, that commit won't affect the rest of the transaction (i.e. the main procedure itself).
Log every step of the procedure and then review the result. There's probably something going on, but - it is difficult to guess what. One option might be that you used the
exception
when others then null;
exception handler which successfully hides the problem.

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

Why did plsql_profiler produce no data rows?

DECLARE
v_run_no binary_integer;
v_run_time_in_sec number;
BEGIN
dbms_profiler.start_profiler('Profiling my proc', 'Tom', v_run_no);
schema.my_package.my_proc();
dbms_profiler.stop_profiler();
-- Calculate the TOTAL_TIME for each unit in the run by summing the TOTAL_TIME
-- from each data record in the unit and writing it to the TOTAL_TIME column
-- in the plsql_profiler_units table.
dbms_profiler.rollup_run(v_run_no);
-- Grab total run time for display
SELECT r.RUN_TOTAL_TIME / 1000000000
INTO v_run_time_in_sec
FROM ucms_crim_conv.plsql_profiler_runs r
WHERE r.RUNID = v_run_no;
dbms_output.put_line('Profiled as run ' || v_run_no || ' in ' || v_run_time_in_sec || ' total sec.');
END;
I've run this same script to profile a different procedure call, by changing ONLY the schema.my_package.my_proc(); line to call a different procedure, and everything went fine.
This time, after the script completes, I can see a row with a value in the TOTAL_TIME column for the run id in the plsql_profiler_runs table.
Previously I would also see 2 rows in plsql_profiler_units, one for the anonymous calling block, and 1 for the procedure being profiled, with associated rows in plsql_profiler_data for each unit. However, this time, I see only the anonymous block in plsql_profiler_units, and the only plsql_profiler_data records for this run id are for the calling anonymous block, not the procedure itself, which is obviously what I'm interested in.
Why might this happen? What can I do to fix it and see data for my procedure?
According to the DBMS_PROFILER reference:
Security Model
The profiler only gathers data for units for which a user has CREATE
privilege; you cannot use the package to profile units for which
EXECUTE ONLY access has been granted. In general, if a user can debug
a unit, the same user can profile it. However, a unit can be profiled
whether or not it has been compiled DEBUG. Oracle advises that modules
that are being profiled should be compiled DEBUG, since this provides
additional information about the unit in the database.
I was able to reproduce your issue when profiled procedure was created in another schema and my profiling user lacked either CREATE ANY PROCEDURE or ALTER ANY PROCEDURE privileges. When he had both - everything ran just fine. Probably you reference another schema's package and suffer the same issue.

Sequence of procedures and packages followed in a job

I have a scheduled job that runs every day. In that job I have called some stored procedures from various packages. I would like to know is there a sequence that is followed in Oracle i.e the sequence in which I have called them or the stored procedure are executed in any random order.
if you're saying you have a single job (vs one job for each SP) that calls packages like
begin
pkgA.procA;
pkgB.procB;
pkgC.procC;
...
end;
then they are executed in the order you have them in the pl/sql anonymous block.
if you have 1 job for each API call though, then they will either execute in parallel or in any random order.

Display comments to user while executing Oracle procedure

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.

Resources