Skip to main content

:: How Commit Works in PL SQL Functions/Triggers ::

COMMIT in Functions/Triggers.
+++++++++++++++++++

It Triggers/functions may be led to bulk associated transactions. This may lead to transaction atomicity failure.

Please find the below test case from Oracle.

Step 1:
---------

SQL> CREATE TABLE COMMIT_TRIG_TEST_TABLE1(T INT);

Table created.

SQL> CREATE TABLE COMMIT_TRIG_TEST_TABLE2(T INT,CHECK (T NOT IN(0)));

Table created.

Step 2:
---------
CREATE OR REPLACE FUNCTION INSERT_DATA(NUM IN NUMBER)
RETURN VARCHAR2 IS
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO COMMIT_TRIG_TEST_TABLE1 VALUES('||NUM||')';
RETURN 'INSERT OK';
END;

Step 3:
---------
CREATE OR REPLACE TRIGGER COMMIT_TRIG
BEFORE INSERT ON COMMIT_TRIG_TEST_TABLE1
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO COMMIT_TRIG_TEST_TABLE2 VALUES(:NEW.T);
END;

Step 4:
--------
However, we know that if the function having dml operations, then we can't make that function as a part of SQL statement. So, please use the below method for inserting

the data.

SQL> VAR V VARCHAR2(10);
SQL> EXEC :V :=INSERT_DATA(10);

PL/SQL procedure successfully completed.

SQL> PRINT V;

V
------------------
INSERT OK

Please observer this statement in INSERT_DATA function .

This insert statement is associated with two transactions.

1. By itself.

2.INSERT INTO COMMIT_TRIG_TEST_TABLE2 VALUES:

InTrigger Body Asper Atomocity(ACID), whether the transaction must Commit/Rollback.


+INSERT ON TABLE1 (Success)+ }

==> TRANSACTION is sucess.

+INSERT ON TABLE2 (Success)+ }


SQL> SELECT * FROM COMMIT_TRIG_TEST_TABLE1;

T
----------
10

SQL> SELECT * FROM COMMIT_TRIG_TEST_TABLE2;

T
----------
10


That's why this EXEC :V :=INSERT_DATA(10) is sucessfull.

Step 5
--------

SQL> DELETE FROM COMMIT_TRIG_TEST_TABLE1;

SQL> DELETE FROM COMMIT_TRIG_TEST_TABLE2;

SQL> exec :v :=insert_data(0);
BEGIN :v :=insert_data(0); END;
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.SYS_C009672) violated
ORA-06512: at "SCOTT.COMMIT_TRIG", line 3
ORA-04088: error during execution of trigger 'SCOTT.COMMIT_TRIG'
ORA-06512: at "SCOTT.INSERT_DATA", line 4
ORA-06512: at line 1

Here the transactions are as below

+INSERT ON TABLE1 (Success)+}

==> TRANSACTION is failure.

+INSERT ON TABLE2 (Failure)+}

As per Automocity rule, whether the transaction must be sucess/fail. However, here the transaction is having both.

That's why the total transaction is rolled back. So, INSERT ON TABLE1 also rolled back here.

SQL> SELECT * FROM COMMIT_TRIG_TEST_TABLE1;

no rows selected

SQL> SELECT * FROM COMMIT_TRIG_TEST_TABLE2;

no rows selected

Even though if you have autonomous_transactions, those must and should statisfy this automoctiy.


Now, how to insert element '0' in first table.

Step 6
--------

CREATE OR REPLACE FUNCTION INSERT_DATA(NUM IN NUMBER)
RETURN VARCHAR2 IS
pragma autonomous_transaction;
BEGIN
INSERT INTO COMMIT_TRIG_TEST_TABLE1 VALUES(NUM);
COMMIT;
RETURN 'INSERT OK';
END;

Need to make the trigger always commits.Even though it fails, it needs to commit for satisfying the automocity.

CREATE OR REPLACE TRIGGER COMMIT_TRIG
BEFORE INSERT ON COMMIT_TRIG_TEST_TABLE1
FOR EACH ROW
DECLARE
pragma autonomous_transaction;
BEGIN
INSERT INTO COMMIT_TRIG_TEST_TABLE2 VALUES(:NEW.T);
commit;
exception when others then
COMMIT;
END;

SQL> select insert_data(0) from dual;

INSERT_DATA(0)
--------------------------------------------------------------------------------
INSERT OK


SQL> select * from commit_trig_test_table1;

T
----------
0

SQL> select * from commit_trig_test_table2;

no rows selected


--Dinesh

Comments

Popular posts from this blog

Parallel Operations With pl/pgSQL

Hi, I am pretty sure that, there will be a right heading for this post. For now, i am going with this. If you could suggest me proper heading, i will update it :-) OK. let me explain the situation. Then will let you know what i am trying to do here, and how i did it. Situation here is, We have a table, which we need to run update on “R” no.of records. The update query is using some joins to get the desired result, and do update the table.  To process these “R” no.of records, it is taking “H” no.of hours. That too, it’s giving load on the production server. So, we planned to run this UPDATE as batch process.  Per a batch process, we took “N” no.or records. To process this batch UPDATE, it is taking “S” no.of seconds. With the above batch process, production server is pretty stable, and doing great. So, we planned to run these Batch updates parallel.  I mean, “K” sessions, running different record UPDATEs. Of-course, we can also increase the Batch size here.  But

How To Send E-Mail From PostgreSQL

Hi , If you want to send E-Mails from PostgreSQL, then use the below Python 3.2 Script as below. I have used ActivePython 3.2 with PostgreSQL 9.1 for sending E-Mails from PostgreSQL. If you want to configure the Python 3.2 with PostgreSQL 9.1 then, please refer the below steps. http://manojadinesh.blogspot.in/2012/06/fatal-python-error-pyinitialize-unable.html Once, your Python 3.2 successful then follow the below steps to send an e-mail. Step 1 ===== postgres=# CREATE OR REPLACE FUNCTION public.send_email(_from Text,_password Text,smtp Text,port INT,receiver text, subject text, send_message text) RETURNS TEXT  LANGUAGE plpython3u AS $function$ import smtplib sender = _from receivers = receiver message = ("From: %s\nTo: %s\nSubject: %s\n\n %s"  % (_from,receiver,subject,send_message)) try:   smtpObj = smtplib.SMTP(smtp,port)   smtpObj.starttls()   smtpObj.login(_from, _password)   smtpObj.sendmail(sender, receivers,message)   print ('Successf

::Pipelined in Oracle as well in PostgreSQL::

Pipelined Table Functions:- [ORACLE] =========================== If you want to return multiple rows to the calling environment, then piplined table functions is prefred. It will increase the dbperformance as well. Ex:- Step 1: ----------- CREATE TABLE EMP(EMPNO INT,ENAME VARCHAR2(10),SAL INT); Step 2: ----------- Insert sample data. Step 3: ----------- Create an object for the row type casting. CREATE OR REPLACE TYPE emp_row AS OBJECT ( empno INT, ename VARCHAR2(20), SAL INT ); Step 4: ----------- Create a Return Type for the pipelined function. CREATE OR REPLACE TYPE emp_table_type AS TABLE OF emp_row; Step 5: ----------- CREATE OR REPLACE FUNCTION emp_pipe_function RETURN emp_table_type PIPELINED IS BEGIN FOR rec in (select * from emp) LOOP PIPE ROW (emp_row(rec.empno,rec.ename,rec.sal)); END LOOP; RETURN; END; Step 6: ---------- SQL> select * from table(emp_pipe_function); EMPNO ENAME SAL ---------- ----