Tanto em procedimentos chamados pelo comando CALL,
quanto em blocos de código anônimos (comando DO),
é possível finalizar as transações usando os comandos
COMMIT e ROLLBACK.
Uma nova transação é iniciada automaticamente após o término de uma
transação que usa estes comandos, portanto, não existe comando
START TRANSACTION separado.
(Note que BEGIN e END
possuem significados diferentes no PL/pgSQL.)
A seguir está um exemplo simples:
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();
Uma nova transação começa com as características de transação
padrão, como o nível de isolamento da transação.
Nos casos em que as transações são efetivadas de maneira cíclica,
pode-se desejar iniciar as novas transações automaticamente com
as mesmas características da anterior.
Os comandos COMMIT AND CHAIN e
ROLLBACK AND CHAIN fazem isto.
O controle de transação só é possível em chamadas para
CALL ou DO feitas a partir
do nível mais alto, ou chamadas para CALL ou
DO aninhadas sem qualquer outro comando interveniente.
Por exemplo, se a pilha de chamadas for
CALL proc1() → CALL proc2()
→ CALL proc3(), então o segundo e terceiro
procedimentos podem executar ações de controle de transação.
Mas se a pilha de chamadas for
CALL proc1() → SELECT
func2() → CALL proc3(),
então o último procedimento não pode fazer controle de transação,
devido ao SELECT no meio.
PL/pgSQL não tem suporte para
pontos de salvamento (comandos
SAVEPOINT/ROLLBACK TO
SAVEPOINT/RELEASE SAVEPOINT).
Os padrões de uso típicos para pontos de salvamento podem ser
substituídos por blocos com tratadores de exceção
(veja Captura de erros).
Internamente, um bloco com tratadores de exceção forma uma
subtransação, o que significa que as transações não podem ser
finalizadas dentro desse bloco.
Considerações especiais se aplicam aos laços de cursor. Veja este exemplo:
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, os cursores são fechados automaticamente na efetivação
da transação.
Entretanto, um cursor criado como parte de um laço como este é
automaticamente convertido em cursor persistente
(holdable) pelo primeiro
COMMIT ou ROLLBACK,
significando que o cursor é totalmente avaliado no primeiro
COMMIT ou ROLLBACK,
em vez de linha por linha.
O cursor ainda é removido automaticamente após o laço, então isto
é praticamente invisível para o usuário.
Mas é preciso ter em mente que quaisquer bloqueios de tabela ou de
linha obtidos pela consulta do cursor não serão mais mantidos após
a primeira execução do COMMIT ou do
ROLLBACK.
Não são permitidos comandos de controle de transação em laços de
cursor acionados por comandos que não são de leitura apenas
(por exemplo, UPDATE ... RETURNING).