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).