Errores de captura
En este tema se describe cómo gestiona Amazon Redshift los errores.
Cuando una consulta o un comando de un procedimiento almacenado provoca un error, las consultas posteriores no se ejecutan y la transacción se revierte. Puede administrar errores mediante un bloque EXCEPTION.
nota
El comportamiento predeterminado es que un error provocará que las consultas posteriores no se ejecuten, aunque no haya condiciones adicionales que generen errores en el procedimiento almacenado.
[ <<label>> ] [ DECLARE declarations ] BEGIN statements EXCEPTION WHEN OTHERS THEN statements END;
Cuando se produce una excepción y agrega un bloque de manejo de excepciones, puede escribir instrucciones RAISE y la mayoría de las demás instrucciones PL/PgSQL. Por ejemplo, puede generar una excepción con un mensaje personalizado o insertar un registro en una tabla de registro.
Al ingresar el bloque de manejo de excepciones, la transacción actual se revierte y se crea una nueva transacción para ejecutar las instrucciones en el bloque. Si las instrucciones en el bloque se ejecutan sin errores, la transacción se confirma y se vuelve a lanzar la excepción. Por último, se cierra el procedimiento almacenado.
La única condición admitida en un bloque de excepciones es OTHERS, que se asocia a cada tipo de error excepto la cancelación de la consulta. Además, si se produce un error en un bloque de manejo de excepciones, este puede ser capturado por un bloque de manejo de excepciones externo.
Cuando se produce un error en el procedimiento NONATOMIC, el error no se vuelve a generar si se gestiona mediante un bloque de excepciones. Consulte la instrucción RAISE
de PL/pgSQL para generar una excepción detectada por el bloque de gestión de excepciones. Esta instrucción solo es válida en bloques de gestión de excepciones. Para obtener más información, consulte RAISE.
Controlar lo que ocurre después de un error en un procedimiento almacenado con el controlador CONTINUE
El controlador CONTINUE
es un tipo de controlador de excepciones que supervisa el flujo de ejecución dentro de un procedimiento almacenado NONATOMIC. Al usarlo, puede atrapar y administrar excepciones sin finalizar el bloque de instrucciones existente. Normalmente, cuando se produce un error en un procedimiento almacenado, el flujo se interrumpe y el error se devuelve a quien llama. Sin embargo, en algunos casos prácticos, la condición de error no es lo suficientemente grave como para justificar la interrupción del flujo. Se recomienda gestionar el error de forma adecuada, utilizando la lógica de gestión de errores que elija en una transacción independiente y, a continuación, seguir ejecutando instrucciones que sigan al error. A continuación se muestra la sintaxis.
[ DECLARE declarations ] BEGIN statements EXCEPTION [ CONTINUE_HANDLER | EXIT_HANDLER ] WHEN OTHERS THEN handler_statements END;
Existen varias tablas del sistema que le ayudarán a recopilar información sobre los distintos tipos de errores. Para obtener más información, consulte STL_LOAD_ERRORS, STL_ERROR y SYS_STREAM_SCAN_ERRORS. También hay tablas adicionales del sistema que puede utilizar para solucionar errores. Encontrará más información al respecto en Referencia de las tablas y vistas de sistema.
Ejemplo
En el siguiente ejemplo se muestra cómo escribir instrucciones en el bloque de manejo de excepciones. El procedimiento almacenado utiliza el comportamiento de administración de transacciones predeterminado.
CREATE TABLE employee (firstname varchar, lastname varchar); INSERT INTO employee VALUES ('Tomas','Smith'); CREATE TABLE employee_error_log (message varchar); CREATE OR REPLACE PROCEDURE update_employee_sp() AS $$ BEGIN UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith'; EXECUTE 'select invalid'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; $$ LANGUAGE plpgsql; CALL update_employee_sp(); INFO: An exception occurred. ERROR: column "invalid" does not exist CONTEXT: SQL statement "select invalid" PL/pgSQL function "update_employee_sp" line 3 at execute statement
En este ejemplo, si llamamos a update_employee_sp
, el mensaje informativo Se ha producido una excepción. se genera y el mensaje de error se inserta en la tabla de registro del registro employee_error_log
. La excepción original se vuelve a lanzar antes de que finalice el procedimiento almacenado. En las consultas siguientes, se muestran los registros resultantes de la ejecución del ejemplo.
SELECT * from employee; firstname | lastname -----------+---------- Tomas | Smith SELECT * from employee_error_log; message ------------------------------------------------ Error message: column "invalid" does not exist
Para obtener más información acerca de RAISE, incluida la ayuda sobre el formato, junto con una lista de niveles adicionales, consulte Instrucciones de PL/pgSQL admitidas.
En el siguiente ejemplo se muestra cómo escribir instrucciones en el bloque de manejo de excepciones. El procedimiento almacenado utiliza el comportamiento de administración de transacciones NONATOMIC. En este ejemplo, no se devuelve ningún error al autor de la llamada una vez finalizada la llamada al procedimiento. La instrucción UPDATE no se revierte debido al error en la instrucción siguiente. Se genera un mensaje informativo y se inserta el mensaje de error en la tabla de registro.
CREATE TABLE employee (firstname varchar, lastname varchar); INSERT INTO employee VALUES ('Tomas','Smith'); CREATE TABLE employee_error_log (message varchar); -- Create the SP in NONATOMIC mode CREATE OR REPLACE PROCEDURE update_employee_sp_2() NONATOMIC AS $$ BEGIN UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith'; EXECUTE 'select invalid'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; $$ LANGUAGE plpgsql; CALL update_employee_sp_2(); INFO: An exception occurred. CALL SELECT * from employee; firstname | lastname -----------+---------- Adam | Smith (1 row) SELECT * from employee_error_log; message ------------------------------------------------ Error message: column "invalid" does not exist (1 row)
En este ejemplo, se muestra cómo crear un procedimiento con dos bloques secundarios. Cuando se llama al procedimiento almacenado, el error del primer bloque secundario se gestiona mediante su bloque de gestión de excepciones. Una vez completado el primer bloque secundario, el procedimiento continúa con la ejecución del segundo bloque secundario. Puede ver en el resultado que no se produce ningún error cuando se completa la llamada al procedimiento. Se confirman las operaciones UPDATE e INSERT en la tabla employee. Los mensajes de error de ambos bloques de excepciones se insertan en la tabla de registro.
CREATE TABLE employee (firstname varchar, lastname varchar); INSERT INTO employee VALUES ('Tomas','Smith'); CREATE TABLE employee_error_log (message varchar); CREATE OR REPLACE PROCEDURE update_employee_sp_3() NONATOMIC AS $$ BEGIN BEGIN UPDATE employee SET firstname = 'Adam' WHERE lastname = 'Smith'; EXECUTE 'select invalid1'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred in the first block.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; BEGIN INSERT INTO employee VALUES ('Edie','Robertson'); EXECUTE 'select invalid2'; EXCEPTION WHEN OTHERS THEN RAISE INFO 'An exception occurred in the second block.'; INSERT INTO employee_error_log VALUES ('Error message: ' || SQLERRM); END; END; $$ LANGUAGE plpgsql; CALL update_employee_sp_3(); INFO: An exception occurred in the first block. INFO: An exception occurred in the second block. CALL SELECT * from employee; firstname | lastname -----------+----------- Adam | Smith Edie | Robertson (2 rows) SELECT * from employee_error_log; message ------------------------------------------------- Error message: column "invalid1" does not exist Error message: column "invalid2" does not exist (2 rows)
El siguiente ejemplo muestra cómo utilizar el controlador de excepciones CONTINUE. En este ejemplo se crean dos tablas y se utilizan en un procedimiento almacenado. El controlador CONTINUE controla el flujo de ejecución en un procedimiento almacenado con un comportamiento de administración de transacciones NONATOMIC.
CREATE TABLE tbl_1 (a int); CREATE TABLE tbl_error_logging(info varchar, err_state varchar, err_msg varchar); CREATE OR REPLACE PROCEDURE sp_exc_handling_1() NONATOMIC AS $$ BEGIN INSERT INTO tbl_1 VALUES (1); -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_1 VALUES ("val"); INSERT INTO tbl_1 VALUES (2); EXCEPTION CONTINUE_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; $$ LANGUAGE plpgsql;
LLame al procedimiento almacenado:
CALL sp_exc_handling_1();
El flujo actua de la siguiente manera:
Se produce un error porque se intenta insertar un tipo de datos incompatible en una columna. El control pasa al bloque EXCEPTION. Al entrar en el bloque de control de excepciones, la transacción actual se revierte y se crea una nueva transacción implícita para ejecutar las instrucciones en ella.
Si las instrucciones de CONTINUE_HANDLER se ejecutan sin errores, el control pasa a la instrucción inmediatamente posterior a la instrucción que provoca la excepción. (Si una instrucción de CONTINUE_HANDLER genera una nueva excepción, puede gestionarla con un controlador de excepciones dentro del bloque EXCEPTION).
Después de llamar al procedimiento almacenado de ejemplo, las tablas contienen los siguientes registros:
Si ejecuta
SELECT * FROM tbl_1;
, se devuelven dos registros que contienen los valores1
y2
.Si ejecuta
SELECT * FROM tbl_error_logging;
, se devuelve un registro con los siguientes valores: Encountered error, 42703 y column "val" does not exist in tbl_1.
El siguiente ejemplo de control de errores adicional utiliza un controlador EXIT y un controlador CONTINUE. Este crea dos tablas: una tabla de datos y una tabla de registro. También crea un procedimiento almacenado que demuestra el control de errores:
CREATE TABLE tbl_1 (a int); CREATE TABLE tbl_error_logging(info varchar, err_state varchar, err_msg varchar); CREATE OR REPLACE PROCEDURE sp_exc_handling_2() NONATOMIC AS $$ BEGIN INSERT INTO tbl_1 VALUES (1); BEGIN INSERT INTO tbl_1 VALUES (100); -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_1 VALUES ("val"); INSERT INTO tbl_1 VALUES (101); EXCEPTION EXIT_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; INSERT INTO tbl_1 VALUES (2); -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_1 VALUES ("val"); INSERT INTO tbl_1 VALUES (3); EXCEPTION CONTINUE_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; $$ LANGUAGE plpgsql;
Tras crear el procedimiento almacenado, llámelo de la siguiente manera:
CALL sp_exc_handling_2();
Cuando se produce un error en el bloque de excepciones interno, que está entre corchetes entre los conjuntos internos BEGIN y END, este lo controla el controlador EXIT. Cualquier error que se produzca en el bloque exterior lo gestiona el controlador CONTINUE.
Después de llamar al procedimiento almacenado de ejemplo, las tablas contienen los siguientes registros:
Si ejecuta
SELECT * FROM tbl_1;
, se devuelven cuatro registros con los valores 1, 2, 3 y 100.Si ejecuta
SELECT * FROM tbl_error_logging;
, se devuelven dos registros Estos tienen los siguientes valores: Encountered error, 42703 y column "val" does not exist in tbl_1.
Si la tabla tbl_error_logging no existe, se genera una excepción.
El siguiente ejemplo muestra cómo utilizar el controlador de excepciones CONTINUE con el bucle FOR. En este ejemplo se crean tres tablas y se utilizan en un bucle FOR dentro de un procedimiento almacenado. El bucle FOR es una variante del conjunto de resultados, lo que significa que itera sobre los resultados de una consulta:
CREATE TABLE tbl_1 (a int); INSERT INTO tbl_1 VALUES (1), (2), (3); CREATE TABLE tbl_2 (a int); CREATE TABLE tbl_error_logging(info varchar, err_state varchar, err_msg varchar); CREATE OR REPLACE PROCEDURE sp_exc_handling_loop() NONATOMIC AS $$ DECLARE rec RECORD; BEGIN FOR rec IN SELECT a FROM tbl_1 LOOP IF rec.a = 2 THEN -- Expect an error for the insert statement following, because of the invalid value INSERT INTO tbl_2 VALUES("val"); ELSE INSERT INTO tbl_2 VALUES (rec.a); END IF; END LOOP; EXCEPTION CONTINUE_HANDLER WHEN OTHERS THEN INSERT INTO tbl_error_logging VALUES ('Encountered error', SQLSTATE, SQLERRM); END; $$ LANGUAGE plpgsql;
LLame al procedimiento almacenado:
CALL sp_exc_handling_loop();
Después de llamar al procedimiento almacenado de ejemplo, las tablas contienen los siguientes registros:
Si ejecuta
SELECT * FROM tbl_2;
, se devuelven dos registros que contienen los valores 1 y 3.Si ejecuta
SELECT * FROM tbl_error_logging;
, se devuelve un registro con los siguientes valores: Encountered error, 42703 y column "val" does not exist in tbl_2.
Notas de uso sobre el controlador CONTINUE:
Las palabras clave CONTINUE_HANDLER y EXIT_HANDLER solo se pueden usar en procedimientos almacenados NONATOMIC.
Las palabras clave CONTINUE_HANDLER y EXIT_HANDLER son opcionales. EXIT_HANDLER es la opción predeterminada.