I am using SQL developer. I have a stored procedure that is running a long time. I need to trace what happens during that run time.
I tried with DBMS_output.put_line('trace');. But it print after the stored procedure has completed. Also I can't use DBMS_trace (might be older version I am using).
So I came up with idea. I would like to insert into table during stored procedure run time. How can I Commit only that insert query in stored procedure?
I see two possibilities.
Either you write a procedure which inserts log messages into a table. Declare this procedure with PRAGMA AUTONOMOUS_TRANSACTION:
CREATE OR REPLACE PROCEDURE WriteLogMsg(LogMessage IN VARCHAR2) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO T_LOG_ENTRIES (LOG_DATE, LOG_MESSAGE)
VALUES (CURRENT_TIMESTAMP, LogMessage);
COMMIT;
END WriteLogMsg;
Or use the DBMS_APPLICATION_INFO package:
PROCEDURE LONG_RUNNING_PROCEDURE IS
BEGIN
DBMS_APPLICATION_INFO.SET_MODULE('LONG_RUNNING_PROCEDURE', 'Starting');
...
DBMS_APPLICATION_INFO.SET_ACTION('Still working, please be patient');
...
DBMS_APPLICATION_INFO.SET_ACTION('Finished');
-- DBMS_APPLICATION_INFO.SET_MODULE(NULL, NULL); -> removes entries for MODULE and ACTION
END;
While the procedure is running you can query information with
SELECT USERNAME, MODULE, ACTION
from V$SESSION
where USERNAME = ...;
In this case you have to use the Pragma Autonomous transactions.
Create a new procedure with Pragma Autonomous.
PROCEDURE test_autonomous
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
insert ....
commit;
END test_autonomous;
now call this procedure in your code. this will do your trick. You can all use the parameters to pas some data you want to insert.
Related
I would like to audit specific procedure for specific user.
For example i have a stored procedure prc_user_error and i have user which name of Ktd.
When the Ktd user execute prc_user_error procedure should be audited.
I cant use trigger. Also fine grained auditing cant use for execute.
Can you please help me ?
Thanks,
How about setting up your procedure like this and test for the name(s) and exit without doing anything in your procedure. If coded correctly than nothing should be printed in my example
create or replace procedure sp as
v_user varchar2(32) := SYS_CONTEXT( 'USERENV', 'SESSION_USER' );
begin dbms_output.put_line(v_user);
end;
/
begin
sp;
end;
IDK how you want to audit it, but assume to insert a record into some table:
create table myAudit( auditTime TIMESTAMP, auditUser VARCHAR2(30));
in procedure:
insert into myAudit values (SYSTIMESTAMP, SYS_CONTEXT ('USERENV','SESSION_USER') );
I'm using Ref Cursor as output parameter for PLSQL Procedure. I need to maintain the exact start and end time of proc in log table.
The dummy code below:
Procedure(P1 IN NUMBER, P_REF_CUR OUT SYS_REFCURSOR)
IS
V_TS TIMESTAMP;
BEGIN
V_TS := SYSTIMESTAMP;
<Business logic here to generate SELECT query for Ref Cursor...>;
OPEN P_REF_CUR FOR <SELECT QUERY>;
INSERT INTO LOG_TABLE(ID, STR_TIME,END_TIME,..) VALUES
(1,V_TS,SYSTIMESTAMP,...);
END;
The select query for Ref Cursor sometimes takes 2-3 mins to execute but in log table I see the difference between STR_TIME and END_TIME as only few seconds.
How can I capture the total time taken by procedure including the query execution time?
Once your procedure hands the ref cursor back to the calling process, it has no way of knowing what will happen to it. The caller may never even fetch all of the rows from the cursor. It’s for the caller to log what happens next.
You may try to split this procedure into two packaged procedures, and apply set timing on :
SQL> create or replace package myPkg is
procedure pr1(P1 IN NUMBER);
procedure pr2(P_REF_CUR OUT SYS_REFCURSOR);
end;
/
SQL> create or replace package body myPkg is
v_ts timestamp;
procedure pr1(P1 IN NUMBER) is
begin
v_ts := SYSTIMESTAMP;
<Business logic here to generate SELECT query for Ref Cursor...>;
end;
procedure pr2(P_REF_CUR OUT SYS_REFCURSOR) is
begin
open P_REF_CUR for <SELECT QUERY>;
insert into log_table(ID, STR_TIME,END_TIME,..) values(1,V_TS,SYSTIMESTAMP,...);
end;
end;
/
SQL> set timing on;
SQL> var v_p1 number:=107;
SQL> var v_rc refcursor;
SQL> exec myPkg.pr1( :v_p1 );
PL/SQL procedure successfully completed
Executed in 152,25 seconds
SQL> exec myPkg.pr2( :v_rc );
PL/SQL procedure successfully completed
Executed in 12,34 seconds
SQL> print v_rc;
You can't tell from inside the procedure. The OPEN FOR statement:
... associates a cursor variable with a query, allocates database resources to process the query, identifies the result set, and positions the cursor before the first row of the result set.
All you can time in your procedure is how long it takes to generate the query text and how long it takes to open the cursor. The procedure then ends, and the caller takes over the OUT ref cursor. You can't see anything about what happens to the cursor from here.
The caller than (presumably) fetches the data, which is taking the bulk of the time; but may also be doing other processing. You need the caller to log the time between it calling your procedure and when it closes the ref cursor when it's finished with it - but that will still include any additional processing it does, so you can't separate out how much is actually from the cursor query processing and fetching.
If that is close enough then you could potentially have a second procedure that closes the cursor and logs the time, if you don't want that the caller to have to worry about it. You could have the 'open' cursor record the start time in a session variable (making the package stateful) and have the 'close' procedure retrieve that and insert the logging record; or have the 'open' do the initial insert into the logging table with a null end time, and then have the 'close' update that record with the actual end time. But again, it's only approximate.
if you really want to do it all in that procedure then you would have to do all the query processing within it, which probably means bulk collecting the cursor into a collection and using that collection type as the OUT parameter, adjusting your caller to iterate over that instead of the cursor. That has more memory overhead too of course, so may not be practical.
In SQL Server I can create stored procedures which creates a temp table, insert values into it, and then return a select from that temp table to be the result set for a composite Crystal Report.
I have no idea how to perform it in Oracle stored procedures.
I know I can create a string variable and then execute immediate. But then I don't know how to insert values, and that the result set will be the Crystal Report source.
You may try it using plsql procedure as follows.
CREATE PROCEDURE testRS (lcout OUT sys_refcursor) AS
BEGIN
OPEN lcout
FOR
SELECT object_name, object_type
FROM user_objects;
END testRS;
sys_refcursor is a weak cursor, meaning it can point to any query, and no type is enforced.
To execute under sqlplus (similar API should be available under crystal report), you will need to define a sqlplus variable, which holds resultset from cursor inside the procedure.
-- Define sqlplus variable
SQL> var ncc refcursor;
-- Call to procedure.
SQL> exec TESTPKG.testRS( :ncc );
PL/SQL procedure successfully completed.
-- Display the resultset.
SQL> print :ncc;
Hope it helps,
Dhimant
I am trying to call my procedure inside a trigger.
The trigger is created successfully but the procedure is calling being called.
I am using oracle 10g with SQL developer tool.
I have tried to see the dbms_output but nothing shows in DBMS_OUTPUT console except"set serveroutput on" when i update the table.
My trigger is
create or replace
TRIGGER trig_sample
AFTER UPDATE
ON sample_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
SAMPLE_PROC(:NEW.PARAM1, :NEW.PARAM2 ,:NEW.PRAMA3);
END;
procedure is
CREATE or REPLACE Procedure SAMPLE_PROC(PARAM1 NUMBER,PARAM2 NUMBER,PARAM3 varchar2)
BEGIN
DBMS_OUTPUT.put_line('test : '||test);
UPDATE SAMPLE_TABLE SET STATUS = 'VA'
WHERE SAMPLE_ID = '2012';
END;
In my procedure i have used DBMS_OUTPUT.put_line('test : '||test);
but could not see any output. Please provide any suggestions to view the DBMS output in console and how to check the trigger is called or not?
I want to create temporary table in stored procedure and access it in the same but I got error that ORA-00942:Table or view does not exists.
Following is the procedure that i tried,
Create procedure myproc
IS
stmt varchar2(1000);
BEGIN
stmt:='CREATE GLOBAL TEMPORARY table temp(list if columns) ON COMMIT DELETE ROWS';
execute immediate stmt;
insert into temp values('list of column values');
END;
This is the way I used to create temporary table but I got error, is there any other way to perform this task?
Just create it first (once, outside of your procedure), and then use it in your procedure. You don't want to (try to) create it on every call of the procedure.
create global temporary table tmp(x clob)
on commit delete rows;
create or replace procedure...
-- use tmp here
end;
Create or replace procedure myprocedure
is
stmt varchar2(1000);
stmt2 varchar2(1000);
begin
stmt := 'create global temporary table temp(id number(10))';
execute immediate stmt;
stmt2 := 'insert into temp(id) values (10)';
execute immediate stmt2;
end;
I have edited this answer as it was wrong. I am a recent MSSQL convert and because of the way oracle implements global temp tables, if you really DO need to use temp tables, creating them once and leaving them there is the way to go. Unless you use dynamic sql in your procs exclusively (have fun debugging), you will not be able to successfully compile your package unless the tables referenced already exist. Oracle validates any objects referenced in methods that you attempt to compile, which is why you got the 942 error. I love the way Oracle manages scope with these global temp tables. That, alone, sold me on the idea.
Use this
Create of replace procedure myprocedure
is
stmt varchar2(1000);
stmt2 varchar2(1000);
begin
stmt := 'create global temporary table temp(id number(10))';
execute immediate stmt;
stmt2 := 'insert into temp(id) values (10)';
execute immediate stmt2;
end;
CREATE OR REPLACE PROCEDURE myproc IS
BEGIN
CREATE GLOBAL TEMPORARY TABLE temp (id NUMBER(10)) ON COMMIT DELETE ROWS AS
SELECT 10 FROM dual;
END;
/