Eu obtive um despejo do meu banco de dados PostgreSQL com:
pg_dump -U user-name -d db-name -f dumpfile
que depois procuro 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 algumas delas (verificações ao que parece, em particular) falham durante a restauração, pois as informações não são carregadas na ordem em que essas verificações sejam respeitadas. Por exemplo, a inserção de uma linha em uma tabela pode estar associada a uma CHECK
que chama uma plpgsql
função que verifica se uma condição está em alguma outra tabela não relacionada. Se essa última tabela não for carregada psql
antes da anterior, ocorrerá um erro.
A seguir, é apresentado um SSCCE que produz um banco de dados com o qual 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 desativar (na linha de comando) todas essas restrições durante a restauração de despejo e ativá-las novamente depois? Estou executando o PostgreSQL 9.1.
fonte
-X
e-d
opções parapg_dump
.pg_dump
produz um despejo que é restaurável em um banco de dados vazio.CHECK
restrição, todas as garantias serão anuladas, porque isso não é oficialmente suportado, apenas tolerado. Mas declarar aCHECK
restriçãoNOT VALID
fez funcionar para mim em todos os aspectos. Pode haver casos de canto eu nunca toquei ...Respostas:
Então, você consulta outras tabelas com uma
CHECK
restrição .CHECK
as restrições devem executarIMMUTABLE
verificações. O que passa OK por 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 ( por documentação ):Agora, expressões em
CHECK
restrições podem usar funções, mesmo funções definidas pelo usuário. Essas devem ser restritas aIMMUTABLE
funções, mas o Postgres atualmente não impõe isso. De acordo com essa discussão relacionada ao pgsql-hackers , uma razão é permitir referências ao horário atual, o 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 estou surpreso quepg_dump
não consiga prever 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 no Postgres 9.2 para ajudar na 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, acrescente 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 :
NOT VALID
Existe o
NOT VALID
modificador para restrições. Disponível apenas para restrição FK na v9.1, mas isso foi estendido àsCHECK
restrições na 9.2. Por documentação: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
-- section=sectionname
, mas isso não está ajudando no problema em questão.Aqui é onde fica interessante. Por documentação:
Negrito ênfase minha.
Você pode alterar a
CHECK
restrição incorreta paraNOT VALID
, que move a restrição para apost-data
seção. Soltar e recriar:Isso deve resolver seu problema. Você pode até deixar a restrição nesse estado , pois isso reflete melhor o que realmente faz: verifique novas linhas, mas não dê garantias para os dados existentes. Não há nada de errado com uma
NOT VALID
restrição de cheque. Se preferir, você pode validá-lo mais tarde:Mas então você está de volta ao status quo ante.
fonte
pg_dump
os gatilhos são adicionados no final do arquivo de despejo, enquanto cria osCHECK
s como parte doCREATE TABLE
comando. Portanto, a restauração também poderia ter sido bem-sucedida no caso de verificação se apg_dump
ferramenta usasse uma abordagem diferente. Não consigo entender por que meu DDL está OK se eu usar gatilhos, mas não como OK se eu usar verificações, pois a mesma lógica é implementada nos dois casos (você pode ver a versão do script usando gatilhos na minha própria resposta).pg_dump
deve gerar DDL diferente para restrições de verificação (por exemplo, adicionando todas elas no final), você deve publicá-lo na lista de discussão do Postgres como uma solicitação de aprimoramento. Mas concordo com Erwin que você está usando mal as restrições de verificação para algo para o qual não foram projetadas. Portanto, eu não esperaria que essa solicitação de mudança fosse implementada em um futuro próximo. Btw: seu SSCCE seria melhor modelado usando uma chave estrangeira entre as duas tabelas.Parece que isso se deve à maneira como
pg_dump
cria o despejo. Observando o despejo real, vi que aCHECK
restrição estava presente no arquivo de despejo usando a sintaxe que faz parte doCREATE TABLE
comando:Isso cria a falha na restauração do banco de dados, à medida que a verificação é realizada antes que a tabela
a
ou a tabelab
contenha 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 a
TRIGGER
como no script a seguir:Nesse 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, portanto, a restauração é bem-sucedida.fonte