PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Valores NULL para colunas referential_constraints.unique_constraint_* no esquema de informações

Configuração do teste


Você assume o nome da restrição test_def_abc_id_fkey , o nome padrão resultante de sua configuração no Postgres 11 ou anterior. Vale a pena notar, porém, que os nomes padrão foram aprimorados para o Postgres 12, onde a mesma configuração resulta em test_def_abc_id_abc_id2_fkey . As notas de lançamento do Postgres 12:

Ver:

db<>fiddle aqui

Então vamos usar o nome explícito test_def_abc_fkey para a restrição FK para evitar confusão:
CREATE TABLE test_abc (
  pk  int PRIMARY KEY
, id  int NOT NULL
, id2 int NOT NULL
);

CREATE UNIQUE INDEX test_abc_ids ON test_abc(id,id2);

CREATE TABLE test_def (
  id      int PRIMARY KEY
, abc_id  int
, abc_id2 int
, CONSTRAINT test_def_abc_fkey  -- !
     FOREIGN KEY (abc_id,abc_id2) REFERENCES test_abc(id,id2)
);

E isso funciona no Postgres 9.5 - Postgres 12.
Mesmo no Postgres 9.3.
(Eu estava com a impressão errada de uma restrição real seria necessário.)

Resposta


Sua observação ao consultar o esquema de informações é válida:
SELECT *
FROM   information_schema.referential_constraints
WHERE  constraint_name = 'test_def_abc_fkey';  -- unequivocal name

Obtemos uma linha, mas os três campos unique_constraint_catalog , unique_constraint_schema e unique_constraint_name são NULL .

A explicação parece simples. Essas colunas descrevem, como o manual coloca:

Mas não há UNIQUE restrição , apenas um UNIQUE índice . Um ÚNICO restrição é implementada usando um UNIQUE índice no Postgres. As restrições são definidas pelo padrão SQL, os índices são detalhes de implementação. Existem diferenças como a que você descobriu. Relacionado:

O mesmo teste com um UNIQUE real restrição mostra os dados como esperado:

db<>fiddle aqui

Então isso parece fazer sentido. Especialmente porque o esquema de informações também é definido pelo comitê de padrões SQL e os índices não são padronizados, apenas restrições. (Nenhuma informação de índice nas visualizações do esquema de informações.)

Tudo limpo? Não exatamente.

No entanto


Há outra visualização de esquema de informações key_column_usage . Sua última coluna é descrita como:

Negrito ênfase minha. Aqui, a posição ordinal da coluna no índice está listado de qualquer maneira:
SELECT *
FROM   information_schema.key_column_usage
WHERE  constraint_name = 'test_def_abc_fkey';

Ver:

db<>fiddle aqui

Parece inconsistente.

O que é pior, o manual afirma que uma CHAVE PRIMÁRIA real ou ÚNICO restrição seria necessária para a criação de uma FOREIGN KEY restrição:

Parece ser um bug de documentação ? Se ninguém puder apontar onde estou errando aqui, apresentarei um relatório de bug.

Relacionado:

Solução


No Postgres, o catálogo do sistema é a verdadeira fonte da verdade. Ver:

Então você pode usar algo assim (como eu também adicionei no fiddle acima de):
SELECT c.conname
     , c.conrelid::regclass  AS fk_table, k1.fk_columns
     , c.confrelid::regclass AS ref_table, k2.ref_key_columns
FROM   pg_catalog.pg_constraint c
LEFT   JOIN LATERAL (
   SELECT ARRAY (
      SELECT a.attname
      FROM   pg_catalog.pg_attribute a
           , unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
      WHERE  a.attrelid = c.conrelid
      AND    a.attnum = k.attnum
      ORDER  BY k.ord
      ) AS fk_columns
   ) k1 ON true
LEFT   JOIN LATERAL (
   SELECT ARRAY (
      SELECT a.attname
      FROM   pg_catalog.pg_attribute a
           , unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
      WHERE  a.attrelid = c.confrelid
      AND    a.attnum = k.attnum
      ORDER  BY k.ord
      ) AS ref_key_columns
   ) k2 ON true
WHERE  conname = 'test_def_abc_fkey';

Devoluções:
conname           | fk_table | fk_columns       | ref_table | ref_key_columns
:---------------- | :------- | :--------------- | :-------- | :--------------
test_def_abc_fkey | test_def | {abc_id,abc_id2} | test_abc  | {id,id2}       

Relacionado: