The PL/SQL Channel Error Management in Oracle PL/SQL 6b Continuing Past Exceptions with FORALL and SAVE EXCEPTIONS Steven Feuerstein steven@stevenfeuerstein.com www.stevenfeuerstein.com www.plsqlchallenge.com
Quick Reminders Download code and PowerPoint documents from www.toadworld.com/sf (aka, "PL/SQL Obsession"). Make sure you are comfortable with the material covered in the previous lessons in this series. Basic Concepts, Defining, Raising and Handling Exceptions Copyright 2010 Feuerstein and Associates Page 2
FORALL with SAVE EXCEPTIONS - agenda Quick overview of FORALL FORALL and DML errors Impact of SAVE EXCEPTIONS Working with the SQL%BULK_EXCEPTIONS pseudo-collection Copyright 2010 Feuerstein and Associates Page 3
Quick Overview of FORALL PROCEDURE upd_for_dept (newsal_in IN NUMBER, list_of_emps_in IN DBMS_SQL.NUMBER_TABLE) IS BEGIN FORALL indx IN list_of_emps_in.first.. list_of_emps_in.last UPDATE employees SET salary = newsal_in WHERE employee_id = list_of_emps_in (indx); END; FORALL offers the ability to "bulk process" DML statements. Use of FORALL can improve DML performance by an order of magnitude. It is covered in depth in the " Turbo-charge PL/SQL Execution with Bulk Processing" lesson. In this lesson, we will cover only the exception handlingspecific aspects of FORALL: SAVE EXCEPTIONS. forall_timing.sql Copyright 2010 Feuerstein and Associates Page 4
FORALL and DML Errors FORALLs typically execute multiple DML statements. When an exception occurs in one of those DML statement, the default behavior is: That statement is rolled back and the FORALL stops. All (previous) successful statements are not rolled back. But FORALL is often used for "batch" execution of DML. What if you want the FORALL processing to continue, even if an error occurs in one of the statements? Just add the SAVE EXCEPTIONS clause! Copyright 2010 Feuerstein and Associates Page 5
SAVE EXCEPTIONS and FORALL Oracle PL/SQL Programming PROCEDURE upd_for_dept (newsal_in IN NUMBER, list_of_emps_in IN DBMS_SQL.NUMBER_TABLE) IS BEGIN FORALL indx IN list_of_emps_in.first.. list_of_emps_in.last SAVE EXCEPTIONS UPDATE employees SET salary = newsal_in WHERE employee_id = list_of_emps_in (indx); END; The SAVE EXCEPTIONS clause tells Oracle to save exception information and continue processing all of the DML statements. When the FORALL statement completes, if at least one exception occurred, Oracle then raises an exception and you check the contents of SQL%BULK_EXCEPTIONS. Copyright 2010 Feuerstein and Associates Page 6
Example: FORALL with SAVE EXCEPTIONS Add SAVE EXCEPTIONS to enable FORALL to suppress errors at the statement level. CREATE OR REPLACE PROCEDURE load_books (books_in IN book_obj_list_t) IS bulk_errors EXCEPTION; PRAGMA EXCEPTION_INIT ( bulk_errors, -24381 ); BEGIN FORALL indx IN books_in.first..books_in.last SAVE EXCEPTIONS INSERT INTO book values (books_in(indx)); EXCEPTION WHEN bulk_errors THEN FOR indx in 1..SQL%BULK_EXCEPTIONS.COUNT LOOP log_error (SQL%BULK_EXCEPTIONS(indx).ERROR_INDEX, SQL%BULK_EXCEPTIONS(indx).ERROR_CODE); END LOOP; END; If any exception is encountered, Oracle raises - 24381 when done. Allows processing of all statements, even after an error occurs. Iterate through "pseudo-collection" of errors. bulkexc.sql Copyright 2010 Feuerstein and Associates Page 7
SAVE EXCEPTIONS in Detail For each exception raised, Oracle populates the SQL%BULK_EXCEPTIONS pseudo-collection of records. The record has two fields : ERROR_INDEX and ERROR_CODE. ERROR_INDEX: the index in the bind array for which the error occurred. ERROR_CODE: the number (positive) for the error that was raised It's a pseudo-collection, because it only supports a single method: COUNT. So you iterate from 1 to SQL%BULK_EXCEPTIONS.COUNT to get information about each error. Unfortunately, it does not store the error message. Copyright 2010 Feuerstein and Associates Page 8
Conclusions FORALL is one of the most important performance enhancement features of PL/SQL You should use it whenever you execute DML statements inside a loop. But you must then also decide: what do I do when one of those statements raise an error? If you want to execute all statements, regardless of errors, then add SAVE EXCEPTIONS. And make sure to check the SQL%BULK_ECXEPTIONS pseudo collection in your exception section. Copyright 2010 Feuerstein and Associates Page 9
Next Steps Download the demo.zip if you have not already (www.toadworld.com/sf). Run the sample code yourself to reinforce the lessons. Make sure you are extremely comfortable with and looking for places in your code to use FORALL! Watch the next webinar in this series: DBMS_ERRLOG and LOG ERRORS. Copyright 2010 Feuerstein and Associates Page 10