5.15. Acompanhamento de dependência #

Quando é criada uma estrutura de banco de dados complexa, envolvendo muitas tabelas com restrições de chave estrangeira, visões, gatilhos, funções, etc., é criada implicitamente uma rede de dependências entre os objetos. Por exemplo, uma tabela com uma restrição de chave estrangeira depende da tabela à qual faz referência.

Para garantir a integridade de toda a estrutura do banco de dados, o PostgreSQL não permite excluir um objeto quando há outros objetos dependentes dele. Por exemplo, tentar excluir a tabela de produtos declarada na Seção 5.5.5, onde a tabela de pedidos depende dela, produz a seguinte mensagem de erro:

DROP TABLE produtos;
ERRO:  não é possível remover tabela produtos, porque outros objetos dependem dela
DETALHE:  restrição pedidos_num_produto_fkey na tabela pedidos depende da tabela produtos
DICA:  Use DROP ... CASCADE para remover os objetos dependentes também.

A mensagem de erro contém uma dica útil: se não quiser se preocupar com a exclusão de todos os objetos dependentes individualmente, então você poderá executar

DROP TABLE produtos CASCADE;
NOTA:  removendo em cascata a restrição pedidos_num_produto_fkey na tabela pedidos
DROP TABLE

e todos os objetos dependentes serão removidos, assim como quaisquer objetos que dependam deles também, recursivamente. Neste caso, o comando não remove a tabela de pedidos, apenas remove a restrição de chave estrangeira. O comando termina por aí, porque nada mais depende da restrição de chave estrangeira. (Se quiser verificar o que DROP ... CASCADE vai fazer, então execute DROP sem CASCADE e leia a linha DETALHE da mensagem de erro)

Quase todos os comandos DROP no PostgreSQL permitem especificar CASCADE. Obviamente, a natureza das possíveis dependências varia conforme o tipo do objeto. Também pode ser escrito RESTRICT em vez de CASCADE para obter o comportamento padrão, que é evitar a exclusão de objetos dos quais quaisquer outros objetos dependem.

Nota

Segundo o padrão SQL, é necessário especificar RESTRICT ou CASCADE em um comando DROP. Na realidade, nenhum sistema de banco de dados impõe esta regra, mas se o comportamento padrão é RESTRICT ou CASCADE varia entre os sistemas.

Se o comando DROP incluir vários objetos, só será necessário usar CASCADE quando houver dependências fora do grupo especificado. Por exemplo, ao se escrever DROP TABLE tab1, tab2, a existência de uma chave estrangeira referenciando tab1 oriunda de tab2 não significa que CASCADE seja necessário para obter sucesso.

Para funções ou procedimentos definidos pelo usuário cujo corpo é definido como uma cadeia de caracteres, o PostgreSQL rastreia as dependências associadas às propriedades da função visíveis externamente, como seus tipos de dados de argumentos e resultados, mas não as dependências que só podem ser conhecidas examinando o corpo da função. Como exemplo, considere a seguinte situação:

CREATE TYPE arco_iris AS ENUM ('vermelho', 'laranja', 'amarelo',
                               'verde', 'azul', 'anil', 'violeta');

CREATE TABLE minhas_cores (cor arco_iris, nota text);

CREATE FUNCTION obter_nota_pela_cor (arco_iris) RETURNS text AS
  'SELECT nota FROM minhas_cores WHERE cor = $1'
  LANGUAGE SQL;

(Veja a Seção 36.5 para obter uma explicação das funções da linguagem SQL.) O PostgreSQL saberá que a função obter_nota_pela_cor depende do tipo de dados arco_iris: excluir o tipo de dados forçaria a exclusão da função, porque o tipo de dados de seu argumento não estaria mais definido. Mas o PostgreSQL não vai considerar obter_nota_pela_cor como dependente da tabela minhas_cores, portanto não vai excluir a função se a tabela for excluída. Embora haja desvantagens nessa abordagem, também há benefícios. A função ainda é válida em algum sentido se a tabela estiver ausente, embora executá-la cause um erro; criar uma nova tabela com o mesmo nome permitiria que a função voltasse a funcionar novamente.