Lembro-me de ter levantado um ponto quase idêntico quando o PG9 estava em estado alfa. Aqui estava a resposta de Tom Lane (desenvolvedor principal do PG de alto perfil):
http://archives.postgresql.org/pgsql-general/2010-01/msg00221.php
Resumindo:não vai consertar.
Para não dizer que concordo com sua sugestão de que o comportamento atual é um bug. Olhe pelo ângulo oposto:é o comportamento de
NOT DEFERRABLE
isso está incorreto. De fato, a violação da restrição neste UPDATE nunca deve acontecer em nenhum caso, pois ao final do UPDATE a restrição é satisfeita. O estado no final do comando é o que importa. Os estados intermediários durante a execução de uma única instrução não devem ser expostos ao usuário.
Parece que o PostgreSQL implementa a restrição não adiável verificando duplicatas após cada linha atualizada e falhando imediatamente após a primeira duplicata, o que é essencialmente falho. Mas este é um problema conhecido, provavelmente tão antigo quanto o PostgreSQL. Atualmente a solução para isso é precisamente usar uma restrição DEFERRABLE. E há alguma ironia em que você está olhando para ele como deficiente porque não falha, enquanto de alguma forma deveria ser a solução para a falha em primeiro lugar!
Resumo do status quo desde o PostgreSQL 9.1
-
NOT DEFERRABLE
UNIQUE
ouPRIMARY KEY
as restrições são verificadas após cada linha .
-
DEFERRABLE
restrições definidas comoIMMEDIATE
(INITIALLY IMMEDIATE
ou viaSET CONSTRAINTS
) são verificados após cada instrução .
-
DEFERRABLE
restrições definidas comoDEFERRED
(INITIALLY DEFERRED
ou viaSET CONSTRAINTS
) são verificados após cada transação .
Observe o tratamento especial de
UNIQUE
/ PRIMARY KEY
restrições.Citando a página de manual para CREATE TABLE
:
Uma restrição que não é adiável será verificada imediatamente após cada comando .
Embora afirme mais abaixo em Compatibilidade seção em
Non-deferred uniqueness constraints
:
Quando umUNIQUE
ouPRIMARY KEY
a restrição não é adiável, o PostgreSQL verifica a exclusividade imediatamente sempre que uma linha é inserida ou modificada. O padrão SQL diz que a exclusividade deve ser forçada somente no final da instrução; isso faz diferença quando, por exemplo, um único comando atualiza vários valores de chave. Para obter um comportamento compatível com o padrão, declare a restrição comoDEFERRABLE
mas não adiado (ou seja,INITIALLY IMMEDIATE
). Esteja ciente de que isso pode ser significativamente mais lento do que a verificação imediata de exclusividade.
Minha ênfase em negrito.
Se você precisar de alguma
FOREIGN KEY
restrições para referenciar a(s) coluna(s), DEFERRABLE
não é uma opção porque (por documentação):
As colunas referenciadas devem ser as colunas de uma restrição de chave primária ou exclusiva não adiável na tabela referenciada.