Thread: BUG #15316: pg_restore failes to load data that is constrainted by afunctional check constraints
BUG #15316: pg_restore failes to load data that is constrainted by afunctional check constraints
From
PG Bug reporting form
Date:
The following bug has been logged on the website: Bug reference: 15316 Logged by: Lloyd Albin Email address: lalbin@scharp.org PostgreSQL version: 10.4 Operating system: OpenSUSE Description: I have found an edge case where pg_dump and pg_restore fails to restore databases with check constraints that points to data in another table that is restored after the table containing the check constraint. While our original test case used two schema's, you can also create this same issue using a single schema. This has been tested and found to be a problem on PostgreSQL 9.5.2, 10.3 and 10.4. On Windows, Enterprise SUSE and OpenSUSE. The single schema error message: ERROR: new row for relation "table_a" violates check constraint "table_a_chk_billing_acct_type" The two schema error message: COPY failed for table "table_a": ERROR: relation "table_b" does not exist The real reason for both error messages is the fact that the check constraints get applied when the table is created in the pre-data portion of the restore process. The check constraint needs to be moved to the post-data portion of the restore process, so that the data will be there at the time the check constraint is applied. # Create our source database createdb test_db_1 # Start psql to create the data within the database psql -d test_db_1 -- Create the schema for the lookup table CREATE SCHEMA schema_b; -- Create the lookup table CREATE TABLE schema_b.table_b ( type VARCHAR NOT NULL, "desc" VARCHAR NOT NULL, CONSTRAINT table_b_pk PRIMARY KEY(type, "desc") ); -- Create the schema for our main table CREATE SCHEMA schema_a; -- Create the check constraint function CREATE OR REPLACE FUNCTION schema_b.check_lu_table_b (varchar, varchar) RETURNS boolean AS' SELECT CASE WHEN b."desc" IS NULL THEN FALSE ELSE TRUE END FROM (SELECT $2 AS "desc", $1 AS type) a LEFT JOIN schema_b.table_b b USING (type, "desc") 'LANGUAGE 'sql' VOLATILE RETURNS NULL ON NULL INPUT; -- Create the main table, using the check constraint function CREATE TABLE schema_a.table_a ( tp_id SERIAL, billing_acct_type VARCHAR(20), CONSTRAINT "table_a_pk" PRIMARY KEY(tp_id), CONSTRAINT "table_a_chk_billing_acct_type" CHECK (schema_b.check_lu_table_b('BillAcctType', billing_acct_type)) ); -- Insert the test data INSERT INTO schema_b.table_b VALUES ('BillAcctType', 'Invoice'); INSERT INTO schema_a.table_a (billing_acct_type) VALUES ('Invoice'); #Backup the test_db_1 database to test the restoration pg_dump -Fc test_db_1 -f test_db_1.pg_dump # Create the Database into createdb test_db_2 # Failed Load pg_restore -d test_db_2 test_db_1.pg_dump pg_restore: [archiver (db)] Error while PROCESSING TOC: pg_restore: [archiver (db)] Error from TOC entry 2770; 0 20015425 TABLE DATA table_a postgres pg_restore: [archiver (db)] COPY failed for table "table_a": ERROR: new row for relation "table_a" violates check constraint "table_a_chk_billing_acct_type" DETAIL: Failing row contains (1, Invoice). CONTEXT: COPY table_a, line 1: "1 Invoice" WARNING: errors ignored on restore: 1 You may see both single schema and double schema examples and my workaround to restore the database on my blog post: https://lloyd.thealbins.com/Restoring%20a%20database%20with%20check%20constraints Lloyd Albin Fred Hutchinson Cancer Research Center
Re: BUG #15316: pg_restore failes to load data that is constrainted by a functional check constraints
From
Tom Lane
Date:
=?utf-8?q?PG_Bug_reporting_form?= <noreply@postgresql.org> writes: > I have found an edge case where pg_dump and pg_restore fails to restore > databases with check constraints that points to data in another table that > is restored after the table containing the check constraint. This is an unsupported case.[1] In general, table CHECK constraints are only allowed to concern themselves with the data in the particular row that they're checking. While we can't actually stop you from cheating by hiding the subquery in a function, we're not going to consider it a bug that such a setup doesn't work reliably. I'd suggest rethinking your data representation so that you can make the tables' relationship into a regular foreign key constraint. Those, the system understands well enough to maintain in a dump/reload context. regards, tom lane [1] Specifically, we disclaim support for SQL feature F671, "Subqueries in CHECK constraints".