Eu obtive um dump do meu banco de dados PostgreSQL com:
pg_dump -U user-name -d db-name -f dumpfile
que eu prossigo para restaurar em outro banco de dados com:
psql X -U postgres -d db-name-b -f dumpfile
Meu problema é que o banco de dados contém restrições referenciais, verificações e gatilhos e alguns desses (verificações, parece em particular) falham durante a restauração, pois as informações não são carregadas na ordem que faria com que essas verificações fossem honradas. Por exemplo, a inserção de uma linha em uma tabela pode ser associada a um CHECK
que chama uma plpgsql
função que verifica se uma condição é válida em alguma outra tabela não relacionada. Se essa última tabela não for carregada psql
antes da primeira, ocorrerá um erro.
O seguinte é um SSCCE que produz um banco de dados que, uma vez despejado pg_dump
, não pode ser restaurado:
CREATE OR REPLACE FUNCTION fail_if_b_empty () RETURNS BOOLEAN AS $$
SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;
CREATE TABLE IF NOT EXISTS a (
i INTEGER NOT NULL
);
INSERT INTO a(i) VALUES (0),(1);
CREATE TABLE IF NOT EXISTS b (
i INTEGER NOT NULL
);
INSERT INTO b(i) VALUES (0);
ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty());
Existe uma maneira de desabilitar (a partir da linha de comando) todas essas restrições durante a restauração de despejo e habilitá-las novamente depois? Estou executando o PostgreSQL 9.1.
Então você procura outras tabelas em uma
CHECK
restrição .CHECK
restrições devem executarIMMUTABLE
verificações. O que passa OK para uma linha de uma vez deve passar OK a qualquer momento. É assim que asCHECK
restrições são definidas no padrão SQL. Essa também é a razão dessa restrição no manual :Ainda assim, as expressões em
CHECK
restrições podem usar funções, mesmo funções definidas pelo usuário. Esses devem serIMMUTABLE
, mas o Postgres não impõe isso atualmente. De acordo com esta discussão relacionada em pgsql-hackers , uma razão é permitir referências à hora atual, que não éIMMUTABLE
por natureza.Mas você está procurando linhas de outra tabela, o que viola completamente como as
CHECK
restrições devem funcionar. Não me surpreende quepg_dump
não forneça isso.Mova seu cheque em outra tabela para um gatilho (que é a ferramenta certa), e deve funcionar com versões modernas do Postgres.
PostgreSQL 9.2 ou posterior
Embora o acima seja verdadeiro para qualquer versão do Postgres, várias ferramentas foram introduzidas com o Postgres 9.2 para ajudar com sua situação:
opção pg_dump
--exclude-table-data
Uma solução simples seria despejar o banco de dados sem dados para a tabela violadora com:
Em seguida, anexe apenas os dados para esta tabela no final do dump com:
Mas podem ocorrer complicações com outras restrições na mesma tabela. Existe uma solução ainda melhor :
Solução:
NOT VALID
Até o Postgres 9.1, o
NOT VALID
modificador estava disponível apenas para restrições FK. Isso foi estendido paraCHECK
restrições no Postgres 9.2. O manual:Um arquivo de despejo simples do Postgres consiste em três "seções":
pre_data
data
post-data
O Postgres 9.2 também introduziu uma opção para despejar seções separadamente com
-- section=sectionname
, mas isso não está ajudando com o problema em questão.Aqui é onde fica interessante. O manual:
Minha ênfase em negrito.
Você pode alterar a
CHECK
restrição incorreta paraNOT VALID
, que move a restrição para apost-data
seção. Solte e recrie:Uma única instrução é mais rápida e exclui condições de corrida com transações simultâneas. (Dois comandos em uma única transação também funcionariam.)
Isso deve resolver seu problema. Você pode até deixar a restrição nesse estado , já que isso reflete melhor o que ela realmente faz: verifica novas linhas, mas não dá garantias para os dados existentes. Não há nada de errado com uma
NOT VALID
restrição de verificação. Se preferir, pode validá-lo mais tarde:Mas então você está de volta ao status quo ante.
Parece que isso se deve à forma como
pg_dump
cria o dump. Olhando para o dump real, vi que aCHECK
restrição estava presente no arquivo de dump usando a sintaxe que faz parte doCREATE TABLE
comando:Isso cria a falha na restauração do banco de dados, pois a verificação é feita antes que a tabela
a
ou a tabelab
contenham quaisquer dados. Se, no entanto, o arquivo de despejo for editado eCHECK
adicionado usando a seguinte sintaxe, no final do arquivo de despejo:... então não há problema na restauração.
A mesma lógica exata pode ser implementada usando um
TRIGGER
como no script a seguir:Neste caso, no entanto,
pg_dump
cria (por padrão) o gatilho no final do arquivo de despejo (e não naCREATE TABLE
instrução como no caso de uma verificação) e assim a restauração é bem-sucedida.