INSERT ou SELECT estratégia para sempre retornar uma linha?

Usando o Postgres 9.6, segui a estratégia recomendada emhttps://stackoverflow.com/a/40325406/435563 fazer umINSERT ouSELECT e retorne o ID resultante:

with ins as (
  insert into prop (prop_type, norm, hash, symbols)
  values (
    $1, $2, $3, $4
  ) on conflict (hash) do
    update set prop_type = 'jargon' where false
  returning id)
select id from ins
union all
select id from prop where hash = $3

No entanto, às vezes isso não retorna nada. Eu esperava que retornasse uma linha, não importa o quê. Como posso corrigi-lo para garantir que ele sempre retorne um ID?

NB, apesar de não retornar uma linha, a linha parece existir na inspeção. Acredito que o problema possa estar relacionado à tentativa de adicionar o mesmo registro por duas sessões simultaneamente.

A tabela em questão é definida como:

create table prop (
  id serial primary key,
  prop_type text not null references prop_type(name),
  norm text not null,
  hash text not null unique,
  symbols jsonb
);

Dados:

EDT DETAIL:  parameters: $1 = 'jargon', $2 = 'j2', $3 = 'lXWkZSmoSE0mZ+n4xpWB', $4 = '[]'

Se eu mudarprop_type = 'jargon' paraprop_type = 'foo' funciona! Parece que a trava não está correta se a expressão não mudar nada, mesmo considerandowhere false cláusula. Isso realmente precisa depender de eu adivinhar um valor que não estaria na linha? Ou existe uma maneira melhor de garantir que você obtenha o bloqueio?

---ATUALIZAR ---

A situação geral é que o aplicativo tentou salvar um gráfico acíclico direcionado usando um pool de conexão (... com confirmação automática) e estava usando essa consulta para obter a identificação enquanto perdia duplicações. [Acontece que muito mais inteligente é usar uma transação e apenas serializar para uma conexão. Mas o comportamento quando há contenção aqui é estranho.]

A restrição de chave estrangeira não parece afetar a inserção - por exemplo:

create table foo(i int unique, prop_id int references prop(id));
insert into foo values (1, 208);
insert into foo values (1, 208) 
on conflict (i) do update set prop_id = 208 where false;
--> INSERT 0 0
insert into foo values (1, 208) 
on conflict (i) do update set prop_id = -208 where false;
--> INSERT 0 0

Observe um com fk 208 válido e o outro com -208 inválido. Se eu conectar um select a um deles com o padrão completo, em situações sem contenção, os dois retornarão i = 1 conforme o esperado.

questionAnswers(2)

yourAnswerToTheQuestion