bulk upload and trigger - oracle

Few of questions for bulk-bind and trigger (Oracle 10g)
1) Will row level trigger execute in case of bulk binding ?
2) If yes then, is there any option to surpress the execution only for bulk binding ?
3) If no then, is there a way to execute row level trigger in bulk binding ?
4) Will performance hamper in case row level trigger executes for bulk binding ?

Triggers are still enabled and fired when bulk-bind inserts are performed. There is nothing intinsic you can do to stop that, but of course you can put your own logic in the trigger and the code that does the bulk insert like as follows...
In a package specification:
create or replace package my_packags is
in_bulk_mode boolean default false;
... -- rest of package spec
end;
In the trigger:
begin
if NOT my_package.in_bulk_mode then
-- do the trigger stuff
end if;
end;
In the calling code:
my_package.in_bulk_mode := true;
-- do the bulk insert
my_package.in_bulk_mode := false;

Triggers execute within the SQL engine. Bulk-binding impacts the way that the calling language (pl/sql or any OCI language) calls the SQL engine, by reducing the number of calls/statements, but should not bypass any triggers.
(Imagine you have used a trigger to add validation, logging or other constraint to a database, but a third-party application would bypass it simply through using a bulk operation - this would be a recipe for data corruption and security issues).
Your statement level trigger should fire once.
You could 'disable' your trigger by making it check an in-memory session variable before doing anything else, and explicitly setting it before a bulk operation.
Row level triggers would still fire on a per-row basis, which could have a lot more impact.

Related

Error logging/debugging mechanism for PL/SQL code

I want to create an error logging and debugging mechanism for my PLSQL code.
There will be a log_Error table in which i will inserting the errors/debugs.
I am planning to insert debugs periodically in my code so that it will be easy for me to identify till which point my code is getting execution
In the exception section i will be inserting the error messages in this log table.
Also,I want a mechanism in which i can enable this logging mechanism for a particular session instead of all the sessions by default.
If this logging happens by default, it will create unnecessary performance impact and create unwanted logs
Can you please suggest and approach in which i am able to enable/disable logging mechanism for a session manually?
You can create a small logging package where you set a flag per session like this
create package debug_log_pk as
bLogflag boolean := false;
end debug_log_pk;
then create a procedure that insert data into your table:
create or replace procedure log_error( ..... )
as
pragma autonomous_transaction;
begin
if debug_log_pk.bLogflag then
insert into logging_table (...) values (...);
commit;
end if;
end;
Somewhere in your program. set:
debug_log_pk.bLogflag := true;
That can be done anywhere in your application code before you want to log, and will apply for the reset of the session. And you can turn logging off as well :)
Also the pragma autonomous_transaction; puts the logging into a separate transaction so it will survive a rollback in the db.
Also have a look at this:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1171766400346817259

Oracle PL/SQL Trigger asking for binds

I'm trying to create my trigger but it's asking for binds EVERY time. It works the way I want it to when I click apply on the window that appears... However, it will log an error...
My trigger checks to see if a client is active or not and do NOT allow changes if it is found to be active...
CREATE Trigger Client_Activity
BEFORE Insert or Update or Delete ON Client
FOR EACH ROW
DECLARE
VAR_AC char(2);
BEGIN
IF UPDATING THEN
SELECT Activity INTO VAR_AC
FROM Client_Additionals
WHERE Activity = :Old.Activity;
IF Activity = 'AC'
THEN Raise_Application_Error(-20999, 'active')
END IF;
END;
/
ORACLE VERSION 12 USING SQLDEVELOPER
You have two syntax errors in your trigger:
The IF is missing an END IF
You need to compare the content of the variable var_ac
You are missing a ; after the Raise_Application_Error()
Putting that together, you can create the trigger without problems.
However, you need to use the "Run Script" button in SQL Developer to run a PL/SQL block like that.
SQL*Plus requires no special handling:

Are Compound Triggers available in Oracle Database Express Edition 10g?

I want to code a Trigger to validate if a column have only a specific value, And if some user try to update or insert a row with the same value raise the trigger. But trigger doesn't compile fine. Do you have any idea? Do you know if Compound triggers are available in 10g?
NOTE: Only one "S" value is available for mon_oficial column. If some user try to insert a new record or update with a second "S" value trigger will fired.
Table:
Trigger:
CREATE OR REPLACE TRIGGER check_mon_oficial_trg
FOR INSERT OR UPDATE
ON monedas
COMPOUND TRIGGER
v_check_moneda NUMBER(8);
BEFORE STATEMENT IS
BEGIN
SELECT COUNT(:NEW.mon_oficial)
INTO v_check_moneda
FROM monedas
WHERE mon_oficial = 'S';
IF
v_check_moneda > 1 THEN
RAISE_APPLICATION_ERROR(-20010, 'Only one official money in table');
END IF;
END BEFORE STATEMENT;
END check_mon_oficial_trg;
Error:
Compound triggers were introduced in 11gR1
Compound Triggers
A compound trigger is a Database Manipulation Language (DML) trigger that can fire at more than one timing point.
The body of a compound trigger supports a common PL/SQL state that the code for all of its sections can access. The common state is established when the triggering statement starts and destroyed when the triggering statement completes, even when the triggering statement causes an error.
Before Release 11.1, application developers modeled the common state with an ancillary package. This approach was both cumbersome to program and subject to memory leak when the triggering statement caused an error and the after-statement trigger did not fire. Compound triggers make it easier to program an approach where you want the actions you implement for the various timing points to share common data.

"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.

Oracle: simulating a "post-commit" trigger

How can I get the equivalent of an "on commit" trigger after inserting some rows into a table?
After inserting several rows into a table, I would like to send a message to an external process that there are rows ready to process. Using a statement-level trigger causes one message per insert, and I would like to send just one message saying "there are rows to be processed."
Create a job. It won't actually be submitted until a commit occurs. (Note: DBMS_SCHEDULER is usually better than DBMS_JOB, but in this case you need to use the old DBMS_JOB package.)
declare
jobnumber number;
begin
dbms_job.submit(job => jobnumber, what => 'insert into test values(''there are rows to process'');');
--do some work here...
commit;
end;
/
As you need to trigger an external process, have a look at DBMS_ALERT instead of DBMS_JOB.
The external process would actively listen on the alert by calling a stored procedure. The stored procedure would return immediately after the alert has been signalled and commited.
Note that DBMS_ALERT is a serialization device. Thus, multiple sessions signalling the same alert name will block just as like they update the same row in a table.
You can set a flag to say "I've sent the message".
To be sure you 'reset' the flag on commit, use dbms_transaction.local_transaction_id then you can simply do a
IF v_flag IS NULL OR dbms_transaction.local_transaction_id != v_flag THEN
v_flag := dbms_transaction.local_transaction_id;
generate message
END IF;
Using Oracle Advanced Queueing you can enqueue an array of records with a listener on the queue table.
The records will load, and the listener can then kick off any process you wish, even a web service call
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28419/d_aq.htm#i1001754

Resources