Oracle scheduler job log output - oracle

I'm using dbms_scheduler to execute a PL/SQL stored procedure. I would like to be able to have that code create some text logging output and associate it with the run to verify it's working, but I can't find anything to do that in the docs. Is there a facility to do this that I'm missing? This is an 11g database running under Unix. It would be real nice if I could use dbms_output so I could also run it from sqlplus and get output.

There are a bunch of Oracle Scheduler data dictionary views that will help you monitor jobs. Here are two documentation pages related to that:
Monitoring Jobs
Monitoring and Managing the Scheduler
Moreover, Oracle Scheduler declares some internal Scheduler variables that you can use like any other PL/SQL identifier in your PL/SQL stored procedure. Here is the list of these variables.
If you want to log application specific information, I suggest you create your own log table. You can then insert into this table from within your stored procedure. You can even insert any of the Scheduler's internal variables there, like job_name and job_scheduled_start.

i make a table JOB_LOG
insert into that table from inside your procedure...

I agree with what the others have said. Here's the actual nuts and bolts, but with a nice interface, too. The way I typically do this:
Make a logging table:
CREATE TABLE job_log (
ts TIMESTAMP DEFAULT SYSTIMESTAMP PRIMARY KEY
, message VARCHAR2(255)
);
Make a stored proc that easily writes into your log table:
CREATE OR REPLACE PROCEDURE job_logger (v_message VARCHAR2)
IS
BEGIN
INSERT INTO job_log(message) VALUES (v_message);
COMMIT;
END;
/
Then within your job, you are probably running a stored procedure. Within your own stored procedure, simply add lines that call the job_logger() procedure to write to your log. This keeps the ugly INSERT ... COMMIT clutter out of your interesting stored proc code.
CREATE OR REPLACE PROCEDURE foo
IS
BEGIN
job_logger('Starting job foo.');
...
{your code here}
...
job_logger('Another message that will be logged.');
...
job_logger('Completed running job foo.');
EXCEPTION
...
job_logger('Oops, something bad happened!');
...
END;
/
Your log table is automatically timestamped and indexed by the primary key. To view the log, you might run this
SELECT * FROM job_log ORDER BY ts DESC;
Now if would rather not use the Oracle scheduler, and want instead to use the DBMS_OUTPUT way of writing output, and want to run this under a Unix shell, that is possible also.
You would make a script that calls sqlplus, somewhat like this. If your user is SCOTT and the stored proc is called FOO,
#!/bin/sh
. /whatever/script/that/sets/your/oracle/environment
echo "
set serveroutput on feedback off
exec foo
" | sqlplus -s -l scott/tiger#orcl
Note, the -s flag suppresses the Oracle SQL Plus banner for cleaner output. The -l flag makes it so that sqlplus will abort if the password is bad or something else wrong, rather than try to prompt for username. Feedback off suppresses the PL/SQL "Anonymous block completed" message.
If you want to schedule this, you can call it from cron like this:
00 00 * * * /path/to/the/above/script.sh > /where/you/want/your/output/saved.log 2>&1

Related

Submitted Oracle job using dbms_job.submit and it failed but I don't know where to look for an error message

We are initiating the rebuilding of many materialized views by using dbms_job.submit to execute a stored procedure that perform the rebuilding. However, I am having trouble trying to figure out how to determine if a submitted job failed. The issue that I am having is that the job is failing but I cannot identify what the issue is. So, I am trying to start out with a simple example, which is probably failing on a permission issue but I don't know where to look for the error message.
I have the following test procedure that I want to initiate using dbms_job.submit.
CREATE OR REPLACE PROCEDURE MYLANID.JUNKPROC
AS
lv_msg varchar2(3000);
BEGIN
INSERT INTO MYLANID.junk_log ( msg ) VALUES ('Hello World' );
commit;
EXCEPTION
WHEN OTHERS THEN
lv_msg := SUBSTR(sqlerrm, 1, 3000);
INSERT INTO MYLANID.junk_log ( msg ) VALUES (lv_msg);
END;
/
Note that this table is used above:
CREATE TABLE MYLANID.JUNK_LOG (
EVENT_TIME TIMESTAMP(6) DEFAULT systimestamp,
MSG VARCHAR2(3000 BYTE))
To submit the above procedure as a job, I execute the following anonymous block.
declare l_jobid binary_integer;
BEGIN
dbms_job.submit(job => l_jobid, what => 'BEGIN MYLANID.JUNKPROC; END;');
DBMS_OUTPUT.PUT_LINE('l_jobid:' || l_jobid);
commit;
END;
I then execute the following SQL...
select * from all_jobs;
...to see one record that represents my submitted job. When I re-query the all_jobs view, I see that this record quickly disappears from the view within a few seconds, presumably when the job completes. All is happy so far. I would like to use the presence of a record in the all_jobs view to determine whether a submitted job is running or has failed. I expect to be able to tell if it failed by looking at the ALL_JOBS.FAILURES column having a non null value > 0.
The problem, probably a permission issue, begins when I switch to another schema and I switch all of the occurrences of the above SQL and replace "MYSCHEMA" with "ANOTHERSCHEMA" that I also have access to. For example, I create the following
Table: ANOTHERSCHEMA.JUNK_LOG
Procedure: ANOTHERSCHEMA.JUNKPROC
I am even able to execute the stored procedure successfully in a query window while logged in as MYSCHEMA:
EXEC ANOTHERSCHEMA.JUNKPROC
However, if I execute the following code to submit a job that involves running the same ANOTHERSCHEMA procedure but by submitting it as a JOB...
declare l_jobid binary_integer;
BEGIN
dbms_job.submit(job => l_jobid, what => 'BEGIN ANOTHERSCHEMA.JUNKPROC; END;');
DBMS_OUTPUT.PUT_LINE('l_jobid:' || l_jobid);
commit;
END;
...then, when I query the jobs ALL_JOBS view...
select * from all_jobs;
...I see that the job has a positive value for the column FAILURE and I have no record of what the error was. This FAILURE count value continues to gradually increment over time as Oracle presumably retries up to 16? times until the job is marked BROKEN in the ALL_JOBS view.
But this is just a simple example and I don't know where to look for the error message that would tell me why the job using ANOTEHRSCHEMA references failed.
Where Do I look for the error log of failed jobs? I'm wondering if this will be somewhere only the DBA can see...
Update:
The above is just a simple test example. In my actual real world situation, my log shows that the job was submitted but I never see anything in USER_JOBS or even DBA_JOBS, which should show everything. I don't understand why the dbms_job.submit procedure would return the job number of the submitted job indicating that it was submitted but no job is visible in the DBA_JOBS view! The job that I did submit should have taken a long time to run, so I don't expect that it completed faster than I could notice.
First off, you probably shouldn't be using dbms_job. That package has been superseded for some time by the dbms_scheduler package which is significantly more powerful and flexible. If you are using Oracle 19c or later, Oracle automatically migrates dbms_job jobs to dbms_scheduler.
If you are using an Oracle version prior to 19c and a dbms_job job fails, the error information is written to the database alert log. That tends to be a bit of a pain to query from SQL particularly if you're not a DBA. You can define an external table that reads the alert log to make it queryable. Assuming you're on 11g, there is a view, x$dbgalertext, that presents the alert log information in a way that you can query it but DBAs generally aren't going to rush to give users permission on x$ tables.
If you use dbms_scheduler instead (or if you are on 19c or later and your dbms_job jobs get converted to dbms_scheduler jobs), errors are written to dba_scheduler_job_run_details. dbms_scheduler in general gives you a lot more logging information than dbms_job does so you can see things like the history of successful runs without needing to add a bunch of instrumentation code to your procedures.

View results of pl/sql stored procedure in Toad?

I'm new to Oracle, and I use Toad Data Point to create and test stored procedures.
I created this simple stored procedure:
CREATE OR REPLACE PROCEDURE dummy_sp (
p_recordset OUT SYS_REFCURSOR) AS
BEGIN
OPEN p_recordset FOR
select sysdate, user from dual;
END dummy_sp ;
/
I executed this, and the result from Toad is Executed Successfully.
Now, I would like to view the results of this stored procedure. In Toad Data Point I type the following:
variable mycursor refcursor;
call dummy_sp ( :mycursor );
I get a popup asking for a parameter. I click OK and I get the error ORA-00900: invalid SQL statement.
How can I see the result of SP dummy_sp in Toad Data Point?
In SQL Server I can run exec usp_sales and see the results of a select statement. There has to be something like that in Oracle and Toad, right?
Here you go, using Toad Data Point.
Execute the stored procedure with a bind variable in it, like :mycursor, and then make sure to configure the type as CURSOR and direction as OUT when Toad Data Point prompts you for the bind variable settings.
Here's the result:
Finally, if you wish to avoid the popup for bind variables, you can execute the procedure directly from the object explorer:
Right-click the procedure and choose Operations / Execute Procedure, and Toad will run it, without prompting for data type.
In case you need a workaround while you wait for help with your tool, the default, free IDE for Oracle Database makes this pretty easy.
If you execute the program using the code editor, it will automatically grab any outputs, whether those be OUT params or RETURNs from a function, including your refcursor
Or if your GUI has proper SQLPlus script execution support (SQL Developer does, not sure about your program):
var x refcursor
exec dummy_sp(:x);
print :x;
And the output:
PL/SQL procedure successfully completed.
SYSDATE USER
------------------- --------------------------------------------------------------------------------------------------------------------------------
27-JUN-19 13.58.47 HR

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.

Run SCRIPT from PL/SQL Block

How to use "START SCRIPT" in pl/sql block ?
I want to use something like this
declare
begin
proc(para1,para2);
execute immediate 'start prompt1' ;
end;
/
Also I want to know , can i get a value from prompt1 into my PL/SQL block where am calling the script ? Because I need to use the value to perform some operations in the PL/SQL block.
It is 2012 2017. Scripts are a clunky and brittle hangover from the last millennium. Oracle has a fantastic range of functionality we can execute in PL/SQL, plus there's Java Stored Procedures, and there's scheduling for starting jobs. Other than running DDL to create or amend schemas there is hardly any need for scripts in an Oracle database environment; even DDL scripts should be triggered from an external client, probably a build tool such as TeamCity.
In particular I would regard attempting to run a SQL script from a PL/SQL program as an architectural failure. What are you doing with the script which you cannot do with a stored procedure?
As for passing input to a stored procedure, that's what parameters are for. PL/SQL isn't interactive, we need a client to enter the values. Depending on the scenario this can be done asynchronously (values in a file or a table) or synchronously (calling the stored procedure from SQL*Plus, SQL Developer or a bespoke front end).
Having said all that, in the real world we work with messy architectures with inter-dependencies between the database and the external OS. So what can we do?
We can write a Java Stored Procedure to execute shell commands. This is the venerable solution, having been around since Oracle 8i. Find out more.
In 10g Oracle replace DBMS_JOB with DBMS_SCHEDULER. Once of the enhancements of this tool is its ability to run external jobs i.e. shell scripts. Find out more.
Since Oracle 11g R1 external tables support pre-processor scripts, which run shell commands before querying the table. Find out more.
Note that all these options demand elevated access (grants on DIRECTORY objects, security credentials, etc). These can only be granted by privileged users (i.e. DBAs). Unless our database has an astonishingly lax security configuration there is no way for us to run an arbitrary shell script from PL/SQL.
Finally, it is not clear what benefit you expect from running a SQL script in PL/SQL. Remember that PL/SQL runs on the database server, so it can't see scripts on the client machine. This seems relevant in the light of the requirement to accept user input.
Perhaps the simplest solution is reconfiguration of the original script. Split out the necessary PL/SQL call into a block and then just call the named script:
begin
proc(para1,para2);
end;
/
#prompt1.sql
You can write a pl/sql block in SqlPlus to check for a parameter from a table then execute a script. In the script to be executed (MyScript.sql below), the statement terminators must be ";" instead of "/"
declare
vMyParameter number := 0;
begin
select count(*) into vMyParameter
from MyTable
where MyCheckValue = 'Y';
if vMyParameter = 1 then
#MyFolder/MyScript.sql;
end if;
end;
/
If you're using sql*plus (or a tool that is using it) then you can do something like this:
set serveroutput on
variable a number;
begin
:a := &promt;
dbms_output.put_line(:a);
end;
/
If it runs in batch then you can do:
variable a number;
begin
:a := &1;
dbms_output.put_line(:a);
end;
and get the value for :a as a parameter-
sqlplus sdad/fdsfd#fdggd #<your_script.sql> <val_for_a>
Another practice is to execute on one *.bat with parameters, like:
Example c:/oracle/bin/sqlplus.exe -w #c:/name
sql %1 %2 #c:/output.sql
execute immediate 'start prompt1' ;
Execute immediate is to execute SQL statements , not arbitrary commands.
can i get a value from prompt1 into my PL/SQL block where am calling the script
You can run a run script - but I doubt you can capture input from an SQL script, esp within a PL/SQL block

Explain Plan for Query in a Stored Procedure

I have a stored procedure that consists of a single select query used to insert into another table based on some minor math that is done to the arguments in the procedure. Can I generate the plan used for this query by referencing the procedure somehow, or do I have to copy and paste the query and create bind variables for the input parameters?
Use SQL Trace and TKPROF. For example, open SQL*Plus, and then issue the following code:-
alter session set tracefile_identifier = 'something-unique'
alter session set sql_trace = true;
alter session set events '10046 trace name context forever, level 8';
select 'right-before-my-sp' from dual;
exec your_stored_procedure
alter session set sql_trace = false;
Once this has been done, go look in your database's UDUMP directory for a TRC file with "something-unique" in the filename. Format this TRC file with TKPROF, and then open the formatted file and search for the string "right-before-my-sp". The SQL command issued by your stored procedure should be shortly after this section, and immediately under that SQL statement will be the plan for the SQL statement.
Edit: For the purposes of full disclosure, I should thank all those who gave me answers on this thread last week that helped me learn how to do this.
From what I understand, this was done on purpose. The idea is that individual queries within the procedure are considered separately by the optimizer, so EXPLAIN PLAN doesn't make sense against a stored proc, which could contain multiple queries/statements.
The current answer is NO, you can't run it against a proc, and you must run it against the individual statements themselves. Tricky when you have variables and calculations, but that's the way it is.
Many tools, such as Toad or SQL Developer, will prompt you for the bind variable values when you execute an explain plan. You would have to do so manually in SQL*Plus or other tools.
You could also turn on SQL tracing and execute the stored procedure, then retrieve the explain plan from the trace file.
Be careful that you do not just retrieve the explain plan for the SELECT statement. The presence of the INSERT clause can change the optimizer goal from first rows to all rows.

Resources