Procedure to insert records asynchronously - oracle

I have a package where I am calling a procedure to insert records to a table and I am calling this procedure twice with a interval of 2 minutes using sys.DBMS_LOCK.sleep (<>);
Problem I facing is my calling form which is from application is still open till the insertion completes.
How can I make sure that when I submit my page and page should close, insertion should happen in backend some kind of asynchronous call. In database procedure are there any asynchronous key word to do this kind of activity?
Thanks
Update
putData(empNo,EmpName);
sys.DBMS_LOCK.sleep (<>);
putData(empNo,EmpName);
and due to the above my page stays till the second procedure finishes. I would like to close the page as soon as the first procedure finishes or when user submits the page.
Update 2
DBMS_JOB.SUBMIT(ln_dummy, 'begin putData('||empNo,EmpName||'); end;');
gives me compilation error wrong number of arguments to call Submit.
How can I resolve this?

Your PutData() procedure is expecting two parameters. You might think you're passing two parameters but you're not. Also, if EmpName is a string - which seems likely - you'll need to wrap it in escaped quotes. Basically you're writing dynamic SQL here, which is always tricky.
Try this:
DBMS_JOB.SUBMIT(ln_dummy, 'begin putData('||empNo||','''||EmpName||'''); end;');
"Other problem is how to run the these jobs at a interval of 10
minutes"
SUBMIT() can take an INTERVAL parameter. It's in the documentation for DBMS_JOB. Find out more.
However, if you want each iterationn to work with different parameter values you probably need to re-think your application design. You should have a procedure which polls a table for values to process.
Or use a queue. It depends on what you're really trying to achieve.

Related

PL/SQL - retrieve output

Is there a way to retrieve output from PL/SQL continuously rather than wait until the SP completes its execution. Continuously mean as when it executes the execute immediate.
Any other mechanism to retrieve pl/sql output?
As per Oracle docs
Output that you create using PUT or PUT_LINE is buffered in the SGA. The output cannot be retrieved until the PL/SQL program unit from which it was buffered returns to its caller. So, for example, Enterprise Manager or SQL*Plus do not display DBMS_OUTPUT messages until the PL/SQL program completes.
As far as I know, there is a way, but not with DBMS_OUTPUT.PUT_LINE. Technique I use is:
create a log table which will accept values you'd normally display using DBMS_OUTPUT.PUT_LINE. Columns I use are
ID (a sequence, to be able to sort data)
Date (to know what happened when; might not be enough for sorting purposes because operations that take very short time to finish might have the same timestamp)
Message (a VARCHAR2 column, large enough to accept the whole information)
create a logging procedure which will be inserting values into that table. It should be an autonomous transaction so that you could COMMIT within (and be able to access data from other sessions), without affecting the main transaction
Doing so, you'd
start your PL/SQL procedure
call the logging procedure whenever appropriate (basically, where you'd put the DBMS_OUTPUT.PUT_LINE call)
in another session, periodically query the log table as select * from log_table order by ID desc
Additionally, you could write a simple Apex application with one report page which selects from the logging table and refreshes periodically (for example, every 10 seconds or so) and view the main PL/SQL procedure's execution.
The approach that Littlefoot has provided is what I normally use as well.
However, there is another approach that you can try for a specific use case. Let's say you have a long-running batch job (like a payroll process for example). You do not wish to be tied down in front of the screen monitoring the progress. But you want to know as soon as the processing of any of the rows of data hits an error so that you can take action or inform a relevant team. In this case, you could add code to send out emails with all the information from the database as soon as the processing of a row hits an error (or meets any condition you specify).
You can do this using the functions and procedures provided in the 'UTL_MAIL' package. UTL_MAIL Documentation from Oracle
For monitoring progress without the overhead of logging to tables and autonomous transactions. I use:
DBMS_APPLICATION.SET_CLIENT_INFO( TO_CHAR(SYSDATE, 'HH24:MI:SS') || ' On step A' );
and then monitor in v$session.client_infofor your session. It's all in memory and won't persist of course but it is a quick and easy ~zero cost way of posting progress.
Another option (Linux/UNIX) for centralised logging that is persistent and again avoids logging in the database more generally viewable that I like is interfacing to syslog and having Splunk or similar pick these up. If you have Splunk or similar then this makes the monitoring viewable without having to connect to the database query directly. See this post here for how to do this.
https://community.oracle.com/thread/2343125

"who_called_me" equivalent for Hibernate

We know that it is possible to dynamically figure out the name of the procedure or package that is currently executing as explained here and here. This generally applies to statements being executed from other stored procedures (compiled) in the database.
The problem:
We have been trying to log all UPDATE activity on a specific column (called STATE) by placing a trigger on the table and invoking who_called_me from within the trigger. The purpose of doing this is apparently as per the application design the column STATE could get updated by multiple pieces of code (residing in the database) based on certain business conditions. In addition to that, the column could also get updated by the application which is a hibernate based application and at times when the update happens by a hibernate query the who_called_me function returns nothing. There are multiple parts in the application that could also UPDATE the column STATE based on certain conditions.
The who_called_me strategy is working well for us in cases where a stored procedure (which resides in the database) issues the UPDATE statement and who_called_me is successfully capturing the corresponding owner, name, line no. etc. of the stored procedure. But in case the UPDATE happens from hibernate, the function captures no details.
Is there a way to capture which hibernate query UPDATEd the row through the trigger? Or is there any other way?
Note: The trigger code is similar to the answer posted on this question.
you can track the query with ora_sql_text function, e.g. this is the function I use for that:
-- getting sql code, which is calling the current event, as clob
function getEventSQLtext
return clob
is
sqllob clob;
sql_text ora_name_list_t;
dummy integer;
begin
dummy := ora_sql_txt(sql_text);
dbms_lob.createtemporary(sqllob,false);
for i in 1..sql_text.count loop
dbms_lob.writeappend(sqllob,length(sql_text(i)),sql_text(i));
end loop;
return sqllob;
if dummy is null then null; end if; -- removing warning of non-used variable :)
end;
This will be a query which is generated by hibernate and this is the only information you can get because this should be the only thing hibernate can do with DB.
It turns out, the who_called_me approach works better for stored procedure calls where the stack trace can point exactly which line invoked a DML. In, case of hibernate it is possible that the code may not call a stored procedure but in-turn may have individual DMLs which get invoked based on certain conditions. As opposed to other answer given by #simon, the ora_sql_txt function may only work in system event triggers or I may be wrong, but either way it is not capable of capturing the SQL Statement issued by Hibernate (tested that it does not works and retunrs a NULL value).
So at the end of the day, to find what SQL Hibernate is using, DB Trace files and Hibernate debug level logs is the only way for now.

How to fire a trigger after finishing data insert in a table

I have a table A into which I am inserting data. Then some calculation is being done updating the same table A.
I want to fire a trigger, which calls a Procedure A after the completion of data insertion ( after insert and update ).
How do I do this?
Is there any other way to do it automatically... Or do I have to run Procedure A manualy after the completion of data insertion in table A.
More simply, I would like to know how to fire a trigger after inserting a few rows and a commit, i.e. not for each row.
You can define your trigger to be fired for each row or for each statement (FOR EACH ROW option).
If I understood you right, you would like to fire the trigger after a bunch of statements? Don't think you can. Even if you can, I would rather not do it. They scatter your program flow / logic and make it harder to understand later how your software works.
Regards
If I understand your question correctly, you want the trigger to fire after you completed your transaction consisting of several insert/update statements? If that is the case, I think you should consider calling your Procedure A in your program flow right after the insert/update operations are done.
In other words: A trigger would only be useful, if it should be called for each row or for each statement.
Add one column to your table: e.g "FINAL_ACTION". Leave this column untouched untill your anticipated final action. Then have your trigger get fired only with this clause:
REFERENCING NEW AS NEWREC OLD AS OLDREC
FOR EACH ROW
WHEN (NEWREC.FINAL_ACTION <> OLDREC.FINAL_ACTION)
DECLARE
--YOUR DECLARATIONS
BEGIN
--DO SOMETHING
END;

Oracle PL/SQL: a scheduled procedure, leading to firing of a trigger?

Okay, I'm new to Oracle PL/SQL and I've stumbled across a problem that I cannot figure out.
I have a procedure that leads to transferring data from one table to another and a trigger that activates on the insertion in the second table. I scheduled that procedure to run every minute (for testing - would be daily once I've figured it out), using the DBMS_JOB.SUBMIT - the scheduled part works perfectly, however after the completion of the procedure the trigger is not fired. I tried with before and after insert clauses, but it is still not working. If I call the procedure directly it works and it does fire the trigger just fine. So... I'm already wondering whether the scheduled procedure can fire the trigger at all?!
This is the schedule's code:
DECLARE
VJOBN BINARY_INTEGER;
BEGIN
DBMS_JOB.SUBMIT(
JOB => VJOBN,
INTERVAL => 'SYSDATE + 1/2880',
WHAT => 'BEGIN my_procedure(); END;'
);
END;
create or replace TRIGGER TO_PRJ
AFTER INSERT ON PROJECTS
FOR EACH ROW
BEGIN
IF INSERTING
THEN DBMS_OUTPUT.PUT_LINE('INSERTED PROJECT WITH ID: '||:NEW.PROJECT_ID||')
END IF;
END;​
Table PROJECTS has ID number, name varchar2, and some other that are not important.
The procedure transfers the ID and the name from orders to projects.
P.S. I'm using http://apex.oracle.com and when I get the timestamp from it the time is actually 6 hours behind me - not sure if it can be of any significance...
DBMS_OUTPUT and DBMS_JOB do not work the way you are trying to use them. The scheduled job is probably running, the trigger is firing - but since DBMS_OUTPUTneeds to be activated in the session that executes the DBMS_OUTPUT commands (i.e. the internal session used by DBMS_JOB) you will never see any output.
DBMS_OUTPUT's output is not visible across session, so the session that issues the DBMS_JOB.submit command will NOT receive the output, even if DBMS_OUTPUT is activated for that session.
Try using scheduler, it's much better then jobs. And bring there code of trigger and tables, it may help

Oracle: How to execute an insert trigger without delaying the insert response?

The trigger below is delaying my insert response. How can I prevent this?
create or replace
TRIGGER GETHTTPONINSERT
BEFORE INSERT ON TABLENAME
FOR EACH ROW
Declare
--
BEGIN
-- The inserted data is transfered via HTTP to a remote location
END;
EDIT People are telling me to do batch jobs, but I would rather have the data earlier than having 100% consistency. The advantage of the trigger is that it happens as soon as the data arrives, but I can't afford the insert response delay.
One approach is to have the trigger create a dbms_job that runs once (each) time to perform the http transfer. The dbms_job creation is relatively quick and you can think of this as effectively spawning a new thread in parallel.
See http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:7267435205059 for further info - his example deals with sending email, but the idea is the same.
There is a perfect solution for this exact situation called Database Change Notification.
You can think of it almost exactly like an async trigger.
You use the DBMS_Change_Notification package to tell oracle which tables to watch and what to do when a change occurs. You can monitor for DML and DDL, you can have Oracle batch the changes (i.e. wait for 10 changes to occur before firing). It will call a sproc with an object containing all the rowids of the changed rows... you can decide how to handle, including calling HTTP. It will not have to finish for the insert to commit.
Documentation for 10gR2
Maybe you could create a local table that store the info do you have to transfer, and create a job that executes every X minutes. The job read from the table, transfer all the data and delete the transfered data from the table.
Isn't it possible to use the Oracle replication options? You send your inserted data via http to a remote location in an after or before statement trigger. What will happen when there is a rollback? Your hhtp send message will not be rollbacked so you have inconsistent data.
well obviously, you could prevent the delay by removing the Trigger....
Else, the trigger will ALWAYS be executed before your insert, thats what the TRIGGER BEFORE INSERT is made for.
Or maybe you could give us more details on what you need exactly?
If you are getting to this question after 2020, look at DBMS_CQ_NOTIFICATION:
https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/DBMS_CQ_NOTIFICATION.html

Resources