Home » SQL & PL/SQL » SQL & PL/SQL » Commit/rollback in functions inside package body
- Commit/rollback in functions inside package body [message #11464] Sun, 28 March 2004 12:17 Go to next message
Fil
Messages: 7
Registered: July 2003
Junior Member
Hi, this is really a newbie question I guess...

I have a function inside a package body that has to insert data in several tables.
I'm really a newbie, so maybe there's more than one error in my code.
As far I understood, procedures and functions inside packages don't need commit (at least this is what happens to me in my environment): it seems there's a commit either I explicit call it or not.

But now I'd like to have a way to manage the rollback/commit feature...explicitly...

I'm posting from home (the real code is at office) but if I remember the code -more or less- is:
========================
function fx_insert_in_tbls (
parameters IN...
) RETURN NUMBER

AS
nextTABLE1pk_ NUMBER(10,0);
nextTABLE2pk_ NUMBER(10,0);
nextTABLE3pk_ NUMBER(10,0);

BEGIN

--table1

select SQtable1.NEXTVAL INTO fx_insert_in_tbls.nextTABLE1pk_

INSERT into TABLE1
� ( pk,
���� name,
���� descr )
VALUES
� ( fx_insert_in_tbls.nextTABLE1pk_,
��� some-var-in,
��� someother-var-in);

IF SQLCODE != 0 THEN
��� ROLLBACK;
��� RETURN -1;
END IF;

--table2

select SQtable2.NEXTVAL INTO fx_insert_in_tbls.nextTABLE2pk_

INSERT into TABLE2
� ( pk,
���� name,
���� descr )
VALUES
� ( fx_insert_in_tbls.nextTABLE2pk_,
��� some-var-in,
��� someother-var-in);

IF SQLCODE != 0 THEN
��� ROLLBACK;
��� RETURN -2;
END IF;

--table3

select SQtable3.NEXTVAL INTO fx_insert_in_tbls.nextTABLE3pk_

INSERT into TABLE3
� ( pk,
���� name,
���� descr )
VALUES
� ( fx_insert_in_tbls.nextTABLE3pk_,
��� some-var-in,
��� someother-var-in);

IF SQLCODE != 0 THEN
��� ROLLBACK;
��� RETURN -3;
END IF;
��
�� --if I'm here then everything should ahve gone the right way...
�� COMMIT;
�� RETURN fx_insert_in_tbls.nextTABLE1pk_

END fx_insert_in_tbls;

========================

Oracle compiles tha package w/out errors, but...Is this the right solution?
Please, consider I'm that new to Oracle that I don't even know what to ask about this code: any suggestion, tips, fix... about how to get my target in a better way is really appreciated.

Thank you
Filippo
- Re: Commit/rollback in functions inside package body [message #11465 is a reply to message #11464] Sun, 28 March 2004 13:14 Go to previous messageGo to next message
Barbara Boehmer
Messages: 9105
Registered: November 2002
Location: California, USA
Senior Member
If you exit normally or perform any DDL, then Oracle commits at that point. If there is an abnormal exit or an error, then Oracle does a rollback at that point. Otherwise, Oracle waits for you to tell it whether to commit or rollback. Procedures, functions, and packages are no exception. A commit can be issued inside the procedure or outside the procedure after it is executed. There are various methods of handling various errors, including using exceptions and raise_application_error. There are various exceptions and "when others" can be used to catch anything remaining. Sometimes, however, this can obscure the problem, so it may be preferable to just let it return an erorr message. However, if you are calling it from some application, you won't want to leave anything unhandled, but may comment out the exception when debugging. Please see the brief example below for some common exception handling.

BEGIN
-- your code
EXCEPTION
  WHEN DUP_VAL_ON_INDEX THEN
    RAISE_APPLICATION_ERROR 
      (-20001, 'An attempt was made to enter a duplicate value, where only one such value is allowed.');
  WHEN OTHERS THEN
    RAISE_APPLICATION_ERROR
      (-20002, 'some message');
END;
/


You can also use savepoints, so that you can rollback to any particular savepoint after the last commit. It is sometimes better to have the whole thing commit or the whole thing fail, rather than try to figure out which pieces committed. You can find information and examples of exceptions, raise_application_error and savepoints in the Oracle on-line documentation. You can click on the link below for a handy menu for searching that documentation. It will require that you register for Oracle Technology Network (OTN) but it is free.

- Re: Commit/rollback in functions inside package body [message #11473 is a reply to message #11465] Mon, 29 March 2004 00:08 Go to previous messageGo to next message
Fil
Messages: 7
Registered: July 2003
Junior Member
thank you Barbara, so it seems my code is ok, a part from the fact I forgot to handle exceptions. Is this righ?

I tried something like code you post.. At the end I wrote:
==========================================

--if I'm here then everything should ahve gone the right way...
COMMIT;
RETURN fx_insert_in_tbls.nextTABLE1pk_

EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RETURN -80;
raise_application_error(SQLCODE, SQLERRM,true);

END fx_insert_in_tbls;

==========================================
but i'm not sure it is the right place to put it.
I tried to put error handling code before the last commit but it gave me error. Is there a way to END the exception code? Something like "END EXCEPTION" to put before very last line(s) of code?

Thank you
Filippo
- Re: Commit/rollback in functions inside package body [message #11480 is a reply to message #11473] Mon, 29 March 2004 03:47 Go to previous messageGo to next message
Barbara Boehmer
Messages: 9105
Registered: November 2002
Location: California, USA
Senior Member
If Oracle encounters something (an error) that raises an exception during any portion of the code, it goes immediately to the exception block, executes what is there and then exits. A rollback is not necessary, because it is done automatically.

You are not using raise_application_error properly. The proper format is:

raise_application_error (-20001, 'some message');

where the first parameter is -20001 or -20002 and so on, within a short range of numbers, where -20001 is one end of the range, and the second parameter is text.

I forgot to mention that, if you are going to commit within a function called from SQL, you will need to use pragma autonomous_transaction.

I believe you can only either use raise_application_error or return a value, not both. But you can certainly include the value in the message of your raise_application_error or output it separately with dbms_output or both.

If you do not include an exception block, Oracle will still give you an error message. In fact, it will tell you the correct line of the code, instead of just the line that the exception block is on.

There are also circumstances where the function won't even execute, so it will never reach the exception block, such as an attempt to pass a parameter of the wrong data type.

Please see the example belows for how all of this works, with and without an exception block.

scott@ORA92> -- without exception block:
scott@ORA92> CREATE OR REPLACE FUNCTION test_function
  2    (p_deptno IN dept.deptno%TYPE)
  3    RETURN NUMBER
  4  AS
  5    PRAGMA AUTONOMOUS_TRANSACTION;
  6  BEGIN
  7    INSERT INTO dept (deptno) VALUES (p_deptno);
  8    COMMIT;
  9    RETURN 1;
 10  END test_function;
 11  /

Function created.

scott@ORA92> SHOW ERRORS
No errors.
scott@ORA92> SELECT * FROM dept
  2  /

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

scott@ORA92> -- insert of legitimate deptno succeeds:
scott@ORA92> SELECT test_function (99) FROM DUAL
  2  /

TEST_FUNCTION(99)
-----------------
                1

scott@ORA92> -- attempted insert of duplicate deptno fails:
scott@ORA92> SELECT test_function (40) FROM DUAL
  2  /
SELECT test_function (40) FROM DUAL
       *
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.PK_DEPT) violated
ORA-06512: at "SCOTT.TEST_FUNCTION", line 7

scott@ORA92> -- attempt to pass parameter of wrong datatype fails:
scott@ORA92> SELECT test_function ('abc') FROM DUAL
  2  /
SELECT test_function ('abc') FROM DUAL
                      *
ERROR at line 1:
ORA-01722: invalid number

scott@ORA92> DELETE FROM DEPT WHERE DEPTNO = 99
  2  /

1 row deleted.


scott@ORA92> -- with exception block:
scott@ORA92> CREATE OR REPLACE FUNCTION test_function
  2    (p_deptno IN dept.deptno%TYPE)
  3    RETURN NUMBER
  4  AS
  5    PRAGMA AUTONOMOUS_TRANSACTION;
  6  BEGIN
  7    INSERT INTO dept (deptno) VALUES (p_deptno);
  8    COMMIT;
  9    RETURN 1;
 10  EXCEPTION
 11    WHEN OTHERS THEN
 12  	 RAISE_APPLICATION_ERROR
 13  	   (-20002,
 14  	    '2 The following error occurred: '
 15  	    || CHR(10) || sqlcode || ' ' || sqlerrm);
 16  END test_function;
 17  /

Function created.

scott@ORA92> SHOW ERRORS
No errors.
scott@ORA92> SELECT * FROM dept
  2  /

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

scott@ORA92> -- insert of legitimate deptno succeeds:
scott@ORA92> SELECT test_function (99) FROM DUAL
  2  /

TEST_FUNCTION(99)
-----------------
                1

scott@ORA92> -- attempted insert of duplicate deptno fails:
scott@ORA92> SELECT test_function (40) FROM DUAL
  2  /
SELECT test_function (40) FROM DUAL
       *
ERROR at line 1:
ORA-20002: 2 The following error occurred:
-1 ORA-00001: unique constraint (SCOTT.PK_DEPT) violated
ORA-06512: at "SCOTT.TEST_FUNCTION", line 12

scott@ORA92> -- attempt to pass parameter of wrong datatype fails:
scott@ORA92> SELECT test_function ('abc') FROM DUAL
  2  /
SELECT test_function ('abc') FROM DUAL
                      *
ERROR at line 1:
ORA-01722: invalid number

scott@ORA92> DELETE FROM DEPT WHERE DEPTNO = 99
  2  /

1 row deleted.
- Re: Commit/rollback in functions inside package body [message #11490 is a reply to message #11480] Mon, 29 March 2004 13:46 Go to previous messageGo to next message
William Robertson
Messages: 1643
Registered: August 2003
Location: London, UK
Senior Member
Just to nitpick - rather than
 10 EXCEPTION
 11    WHEN OTHERS THEN
 12  	 RAISE_APPLICATION_ERROR
 13  	   (-20002,
 14  	    'The following error occurred: '
 15  	    || CHR(10) || sqlcode || ' ' || sqlerrm);
 16  END test_function;
 17  /

I prefer
 10 EXCEPTION
 11    WHEN OTHERS THEN
 12  	 RAISE_APPLICATION_ERROR
 13  	   (-20002,
 14  	    'Could not insert value "' || somevar || '" into sometable blah blah',
 15  	    <b>TRUE</b> );
 16  END test_function;
 17  /

Also, going back to the original example, one danger of code like
PROCEDURE myproc
IS
BEGIN
    do_stuff;

    IF some_condition THEN
        ROLLBACK;
    ELSE
        COMMIT;
    END IF;
END;
is the effect it could have on the calling environment. What if you do:
UPDATE sometable SET somecol = 42 WHERE whatever;
<b>MYPROC;</b>
Now the fate of that UPDATE hangs in the balance. If MYPROC feels like it the whole transaction could be rolled back, or committed. It could be safer to use something like:
PROCEDURE myproc
IS
BEGIN
    SAVEPOINT startofmyproc;
    do_stuff;

    IF some_condition THEN
        ROLLBACK TO startofmyproc;
    END IF;
END;

Now if something goes wrong you can roll back only what was done within MYPROC, leaving anything else back as it was.
- Re: Commit/rollback in functions inside package body [message #11519 is a reply to message #11490] Tue, 30 March 2004 12:33 Go to previous messageGo to next message
Fil
Messages: 7
Registered: July 2003
Junior Member
Thank you very much Barbara and William.
Once again I'm not at office, I'll try tomorrow...

just the last question:
I tried yesterday raising error with RAISE_APPLICATION_ERROR, but it gave me an error, something like wrong number of arguments.

I saw that on your code you are using two parameters (Barbara)or three (Williams).
What is the correct approach to call this utility?

Thank a lot again

Filippo
- Re: Commit/rollback in functions inside package body [message #11526 is a reply to message #11519] Tue, 30 March 2004 20:42 Go to previous message
William Robertson
Messages: 1643
Registered: August 2003
Location: London, UK
Senior Member
See RAISE_APPLICATION_ERROR.

Set the optional third parameter to TRUE if you are re-raising an exception and you want to keep the error stack (SQLERRM). The default FALSE is useful when you are using RAISE_APPLICATION_ERROR to raise a new exception and there is no existing error stack.

Since the TRUE setting keeps the existing error stack you don't need to concatenate SQLERRM explicitly.
Previous Topic: Scrubbing Procedure - Need help
Next Topic: IS or AS in a proc/package?
Goto Forum:
  


Current Time: Mon Apr 28 02:30:37 CDT 2025