CREATE TABLE employees 
AS 
   SELECT * FROM hr.employees 
                        Table created.
Name that -24381! (once)
CREATE OR REPLACE PACKAGE std_errs  
IS  
   failure_in_forall   EXCEPTION;  
   PRAGMA EXCEPTION_INIT (failure_in_forall, -24381);  
END; 
                        Package created.
First, Without SAVE EXCEPTIONS
DECLARE  
   TYPE namelist_t IS TABLE OF VARCHAR2 (5000);  
  
   enames_with_errors   namelist_t  
      := namelist_t ('ABC',  
                     'DEF',  
                     RPAD ('BIGBIGGERBIGGEST', 1000, 'ABC'),  
                     'LITTLE',  
                     RPAD ('BIGBIGGERBIGGEST', 3000, 'ABC'),  
                     'SMITHIE');  
BEGIN  
   FORALL indx IN 1 .. enames_with_errors.COUNT  
      UPDATE employees  
         SET first_name = enames_with_errors (indx);  
  
   ROLLBACK;  
EXCEPTION  
   WHEN OTHERS  
   THEN  
      DBMS_OUTPUT.put_line (  
         'Updated ' || SQL%ROWCOUNT || ' rows.');  
      DBMS_OUTPUT.put_line (SQLERRM);  
      ROLLBACK;  
END; 
                        Statement processed.
Updated 214 rows.
ORA-12899: value too large for column "SQL_JHLEPKYBSTKDHLYUTUGBYVTDW"."EMPLOYEES"."FIRST_NAME" (actual: 1000, maximum: 20)
Now With SAVE EXCEPTIONS
DECLARE  
   TYPE namelist_t IS TABLE OF VARCHAR2 (5000);  
  
   enames_with_errors   namelist_t  
      := namelist_t ('ABC',  
                     'DEF',  
                     RPAD ('BIGBIGGERBIGGEST', 1000, 'ABC'),  
                     'LITTLE',  
                     RPAD ('BIGBIGGERBIGGEST', 3000, 'ABC'),  
                     'SMITHIE');  
BEGIN  
   FORALL indx IN 1 .. enames_with_errors.COUNT SAVE EXCEPTIONS  
      UPDATE employees  
         SET first_name = enames_with_errors (indx);  
  
   ROLLBACK;  
EXCEPTION  
   WHEN std_errs.failure_in_forall  
   THEN  
      DBMS_OUTPUT.put_line (SQLERRM);  
      DBMS_OUTPUT.put_line (  
         'Updated ' || SQL%ROWCOUNT || ' rows.');  
  
      FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT  
      LOOP  
         DBMS_OUTPUT.put_line (  
               'Error '  
            || indx  
            || ' occurred on index '  
            || SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX  
            || ' attempting to update name to "'  
            || enames_with_errors (  
                  SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX)  
            || '"');  
         DBMS_OUTPUT.put_line (  
               'Oracle error is '  
            || SQLERRM (  
                  -1 * SQL%BULK_EXCEPTIONS (indx).ERROR_CODE));  
      END LOOP;  
  
      ROLLBACK;  
END; 
                        Statement processed.
ORA-24381: error(s) in array DML
Updated 428 rows.
Error 1 occurred on index 3 attempting to update name to "BIGBIGGERBIGGESTABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC"
Oracle error is ORA-12899: value too large for column (actual: , maximum: )
Error 2 occurred on index 5 attempting to update name to "BIGBIGGERBIGGESTABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB"
Oracle error is ORA-12899: value too large for column (actual: , maximum: )
Now Explore SAVE EXCEPTIONS with Sparse Bind Arrays
CREATE TABLE plch_employees  
(  
   employee_id   INTEGER,  
   last_name     VARCHAR2 (100),  
   salary        NUMBER (8, 0)  
) 
                        Table created.
BEGIN 
   INSERT INTO plch_employees 
        VALUES (100, 'Ninhursag ', 1000000); 
 
   INSERT INTO plch_employees 
        VALUES (200, 'Inanna', 1000000); 
 
   INSERT INTO plch_employees 
        VALUES (300, 'Enlil', 1000000); 
 
   COMMIT; 
END; 
                        Statement processed.
INDICES OF - BETWEEN - Complications!
DECLARE  
   TYPE employee_aat IS TABLE OF employees.employee_id%TYPE  
      INDEX BY PLS_INTEGER;  
  
   l_employees         employee_aat;  
BEGIN  
   l_employees (1) := 100;  
   l_employees (2) := 200;  
   l_employees (3) := 300;  
   l_employees (4) := 200;  
   l_employees (5) := 100;  
  
   FORALL l_index IN INDICES OF l_employees BETWEEN 3 AND 5  
     SAVE EXCEPTIONS  
      UPDATE plch_employees  
         SET salary =  
                  salary  
                * CASE employee_id WHEN 200 THEN 1 ELSE 100 END  
       WHERE employee_id = l_employees (l_index);  
EXCEPTION  
   WHEN std_errs.failure_in_forall  
   THEN  
      DBMS_OUTPUT.put_line ('Errors:');  
  
      FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT  
      LOOP  
         DBMS_OUTPUT.put_line (  
            SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX);  
      END LOOP;  
  
      ROLLBACK;  
END; 
                        Statement processed.
Errors:
1
3
Correlate ERROR INDEX Back to Bind Array
DECLARE 
   TYPE employee_aat IS TABLE OF employees.employee_id%TYPE 
      INDEX BY PLS_INTEGER; 
 
   l_employees   employee_aat; 
 
   FUNCTION bind_array_index_for (bind_array_in    IN employee_aat, 
                                  error_index_in   IN PLS_INTEGER, 
                                  start_in         IN PLS_INTEGER) 
      RETURN PLS_INTEGER 
   IS 
      l_index   PLS_INTEGER := start_in; 
   BEGIN 
      FOR indx IN 1 .. error_index_in - 1 
      LOOP 
         l_index := bind_array_in.NEXT (l_index); 
      END LOOP; 
 
      RETURN l_index; 
   END; 
BEGIN 
   BEGIN 
      l_employees (1) := 100; 
      l_employees (100) := 200; 
      l_employees (500) := 300; 
 
      FORALL l_index IN INDICES OF l_employees SAVE EXCEPTIONS 
         UPDATE plch_employees 
            SET salary = salary * CASE employee_id WHEN 200 THEN 1 ELSE 100 END 
          WHERE employee_id = l_employees (l_index); 
   EXCEPTION 
      WHEN std_errs.failure_in_forall 
      THEN 
         DBMS_OUTPUT.put_line ('Errors:'); 
 
         FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT 
         LOOP 
            DBMS_OUTPUT.put_line ( 
                  SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX 
               || ' -> ' 
               || bind_array_index_for (l_employees, 
                                        SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX, 
                                        l_employees.FIRST)); 
         END LOOP; 
 
         ROLLBACK; 
   END; 
 
   BEGIN 
      l_employees (1) := 100; 
      l_employees (2) := 200; 
      l_employees (3) := 300; 
      l_employees (4) := 200; 
      l_employees (5) := 100; 
 
      FORALL l_index IN INDICES OF l_employees BETWEEN 3 AND 5 SAVE EXCEPTIONS 
         UPDATE plch_employees 
            SET salary = salary * CASE employee_id WHEN 200 THEN 1 ELSE 100 END 
          WHERE employee_id = l_employees (l_index); 
   EXCEPTION 
      WHEN std_errs.failure_in_forall 
      THEN 
         DBMS_OUTPUT.put_line ('Errors:'); 
 
         FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT 
         LOOP 
            DBMS_OUTPUT.put_line ( 
                  SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX 
               || ' -> ' 
               || bind_array_index_for (l_employees, 
                                        SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX, 
                                        3)); 
         END LOOP; 
 
         ROLLBACK; 
   END; 
END;
                        Statement processed.
Errors:
1 -> 1
3 -> 500
Errors:
1 -> 3
3 -> 5