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):
https://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 DEFERRABLEUNIQUEouPRIMARY KEYas restrições são verificadas após cada linha .
-
DEFERRABLErestrições definidas comoIMMEDIATE(INITIALLY IMMEDIATEou viaSET CONSTRAINTS) são verificados após cada instrução .
-
DEFERRABLErestrições definidas comoDEFERRED(INITIALLY DEFERREDou 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 umUNIQUEouPRIMARY KEYa 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 comoDEFERRABLEmas 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.