RESIGNAL
RESIGNAL se usa dentro de un handler para relanzar el error capturado, opcionalmente modificando sus propiedades. Es útil cuando quieres registrar el error, añadir contexto o transformarlo antes de propagarlo.
Sintaxis
-- Relanzar el mismo error
RESIGNAL;
-- Relanzar modificando propiedades
RESIGNAL
SET MESSAGE_TEXT = 'Nuevo mensaje';
-- Relanzar con nuevo SQLSTATE
RESIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Error transformado';Relanzar el mismo error
DELIMITER //
CREATE PROCEDURE ejemplo_resignal_basico()
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- Registrar el error (en producción: INSERT en tabla de logs)
SELECT 'Error registrado en log' AS log;
-- Relanzar el error original
RESIGNAL;
END;
-- Esto genera un error
INSERT INTO tabla_inexistente VALUES (1);
END //
DELIMITER ;Al llamar este procedimiento, primero se muestra el log y luego se propaga el error original al llamador.
Modificar el mensaje
DELIMITER //
CREATE PROCEDURE crear_pedido_seguro(
IN p_cliente_id INT,
IN p_producto_id INT,
IN p_cantidad INT
)
BEGIN
DECLARE v_error_original VARCHAR(200);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
v_error_original = MESSAGE_TEXT;
RESIGNAL SET MESSAGE_TEXT =
CONCAT('Error al crear pedido para cliente ', p_cliente_id, ': ', v_error_original);
END;
-- Insertar pedido (puede fallar por FK, etc.)
INSERT INTO pedidos (cliente_id, fecha, total, estado)
VALUES (p_cliente_id, CURDATE(), 0, 'pendiente');
INSERT INTO detalle_pedidos (pedido_id, producto_id, cantidad, precio_unitario)
VALUES (LAST_INSERT_ID(), p_producto_id, p_cantidad,
(SELECT precio FROM productos WHERE id = p_producto_id));
END //
DELIMITER ;Si hay un error, el mensaje incluye contexto adicional sobre qué cliente y qué operación falló.
Transformar errores
DELIMITER //
CREATE PROCEDURE api_actualizar_precio(
IN p_producto_id INT,
IN p_nuevo_precio DECIMAL(10,2)
)
BEGIN
-- Capturar cualquier error de bajo nivel
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- Transformar en un error amigable para la API
RESIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Error interno al actualizar el precio. Contacte al administrador.';
END;
IF p_nuevo_precio <= 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'El precio debe ser positivo';
END IF;
UPDATE productos SET precio = p_nuevo_precio WHERE id = p_producto_id;
IF ROW_COUNT() = 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Producto no encontrado';
END IF;
SELECT 'Precio actualizado' AS resultado;
END //
DELIMITER ;RESIGNAL vs SIGNAL
| Característica | SIGNAL | RESIGNAL |
|---|---|---|
| Contexto | Cualquier lugar | Solo dentro de un handler |
| Crea nuevo error | Sí | No, propaga el existente |
| Puede modificar | Todas las propiedades | Solo las que especifiques |
| Sin argumentos | No válido | Relanza el error tal cual |
RESIGNAL sin argumentos
RESIGNAL sin argumentos relanza el error exactamente como fue capturado:
DELIMITER //
CREATE PROCEDURE wrapper_con_log()
BEGIN
DECLARE v_error_code INT;
DECLARE v_error_msg VARCHAR(200);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1
v_error_code = MYSQL_ERRNO,
v_error_msg = MESSAGE_TEXT;
-- Registrar error
-- INSERT INTO error_log (codigo, mensaje, fecha) VALUES (v_error_code, v_error_msg, NOW());
-- Propagar sin modificar
RESIGNAL;
END;
-- Lógica del procedimiento...
SELECT * FROM tabla_inexistente;
END //
DELIMITER ;Ejemplo práctico: capas de error
DELIMITER //
CREATE PROCEDURE capa_datos(IN prod_id INT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RESIGNAL SET MESSAGE_TEXT = CONCAT('[DATOS] Error al acceder producto ', prod_id);
END;
SELECT nombre, precio FROM productos WHERE id = prod_id;
END //
CREATE PROCEDURE capa_negocio(IN prod_id INT)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RESIGNAL SET MESSAGE_TEXT = CONCAT('[NEGOCIO] ', MESSAGE_TEXT);
END;
IF prod_id <= 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'ID de producto inválido';
END IF;
CALL capa_datos(prod_id);
END //
DELIMITER ;Cada capa añade contexto al error, facilitando la depuración.
Limpieza
DROP PROCEDURE IF EXISTS ejemplo_resignal_basico;
DROP PROCEDURE IF EXISTS crear_pedido_seguro;
DROP PROCEDURE IF EXISTS api_actualizar_precio;
DROP PROCEDURE IF EXISTS wrapper_con_log;
DROP PROCEDURE IF EXISTS capa_datos;
DROP PROCEDURE IF EXISTS capa_negocio;En el siguiente artículo veremos SHOW ERRORS para inspeccionar los errores generados por la última sentencia.
Escrito por Eduardo Lázaro
