41.8. Gestión de transacciones #

En los procedimientos invocados por el comando CALL, así como en los bloques de código anónimos (comando DO), es posible finalizar transacciones utilizando los comandos COMMIT y ROLLBACK. Se inicia una nueva transacción automáticamente después de finalizar una transacción utilizando estos comandos, por lo que no hay un comando START TRANSACTION separado. (Ten en cuenta que BEGIN y END tienen significados diferentes en PL/pgSQL).

Aquí tienes un simple ejemplo:

CREATE PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
    FOR i IN 0..9 LOOP
        INSERT INTO test1 (a) VALUES (i);
        IF i % 2 = 0 THEN
            COMMIT;
        ELSE
            ROLLBACK;
        END IF;
    END LOOP;
END;
$$;

CALL transaction_test1();

Una nueva transacción comienza con las características de transacción por defecto, como el nivel de aislamiento. En los casos en que las transacciones se confirman (commit) en un bucle, podría ser deseable iniciar nuevas transacciones automáticamente con las mismas características que la anterior. Los comandos COMMIT AND CHAIN y ROLLBACK AND CHAIN logran esto.

El control de transacciones solo es posible en invocaciones CALL o DO desde el nivel superior o invocaciones CALL o DO anidadas sin ningún otro comando intermedio. Por ejemplo, si la pila de llamadas es CALL proc1()CALL proc2()CALL proc3(), entonces el segundo y tercer procedimiento pueden realizar acciones de control de transacciones. Pero si la pila de llamadas es CALL proc1()SELECT func2()CALL proc3(), entonces el último procedimiento no puede realizar el control de transacciones, debido al SELECT intermedio.

PL/pgSQL no admite puntos de salvaguarda (savepoints) (comandos SAVEPOINT/ROLLBACK TO SAVEPOINT/RELEASE SAVEPOINT). Los patrones de uso típicos para los puntos de salvaguarda se pueden reemplazar por bloques con manejadores de excepciones (consulta la Section 41.6.8). Internamente, un bloque con manejadores de excepciones forma una subtransacción, lo que significa que las transacciones no pueden finalizar dentro de dicho bloque.

Se aplican consideraciones especiales a los bucles de cursor. Considera este ejemplo:

CREATE PROCEDURE transaction_test2()
LANGUAGE plpgsql
AS $$
DECLARE
    r RECORD;
BEGIN
    FOR r IN SELECT * FROM test2 ORDER BY x LOOP
        INSERT INTO test1 (a) VALUES (r.x);
        COMMIT;
    END LOOP;
END;
$$;

CALL transaction_test2();

Normalmente, los cursores se cierran automáticamente al confirmar la transacción. Sin embargo, un cursor creado como parte de un bucle como este se convierte automáticamente en un cursor persistente (holdable) por el primer COMMIT o ROLLBACK. Eso significa que el cursor se evalúa por completo en el primer COMMIT o ROLLBACK en lugar de fila por fila. El cursor se elimina automáticamente después del bucle, por lo que esto es mayormente invisible para el usuario. Pero se debe tener en cuenta que cualquier bloqueo de tabla o fila tomado por la consulta del cursor ya no se mantendrá después del primer COMMIT o ROLLBACK.

No se permiten comandos de transacción en bucles de cursor impulsados por comandos que no sean de solo lectura (por ejemplo, UPDATE ... RETURNING).