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ísticaSIGNALRESIGNAL
ContextoCualquier lugarSolo dentro de un handler
Crea nuevo errorNo, propaga el existente
Puede modificarTodas las propiedadesSolo las que especifiques
Sin argumentosNo válidoRelanza 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