Hello again,

A project I am working on has been having problems with pg_dump's output, using 7.3. Our project's database includes functions that do constraint checking for us, as well as circular dependencies. 

We heard about the changes on the pgsql HEAD/7.5, and have given it a try. It fixed nearly all our problems; however, there is one that is cropping up that we feel should be reviewed: check constraints do not get deferred when loading the data back in to the database using pg_dump's default script.

I have written a script which should be able to reproduce the problem we are encountering. We do not have binary data, so we just use the regular SQL output of pg_dump. The functions and tables create just fine, but when it gets to the COPY part of the sql script, it tries to load tables in what really is the wrong order. The check constraint is making sure there is a "plan" before there is a "contract", yet pg_dump is trying to load the contract table before there is anything in the plan table. This may seem weird at first, as the plan table is referencing the contract table's PK. Our intention is to make sure that EVERY contract has at least one plan. 

Please feel free to ask me about this script and associated files. You will most likely want to edit the Test file, and make it point to the correct HEAD/7.5 run environment. I do not specify PGPORT/PGHOST etc in the file, so you will need to make sure you have those set in your environment. 

Jonathan Scott

-- 
Jonathan Scott, Programmer, Vanten K.K.
jwscott@vanten.com	Tel: 03-5919-0266
http://www.vanten.com	Fax: 03-5919-0267
Thu, 26 Feb 2004 16:47:52 +0900
Jonathan Scott <jwscott@vanten.com>
Check Constraints and pg_dump
Jonathan Scott <jwscott@vanten.com> writes:
> The functions and tables create just fine, but when it gets to the
> COPY part of the sql script, it tries to load tables in what really is
> the wrong order. The check constraint is making sure there is a "plan"
> before there is a "contract", yet pg_dump is trying to load the
> contract table before there is anything in the plan table.

Shouldn't you be using a foreign key for that?

I don't see any reasonable way that pg_dump can be expected to
understand that a check constraint expresses a relationship between two
tables.  The semantics of check constraints aren't right for it anyway.

All else being equal, I think the tables will be loaded in OID order,
so a possible workaround is to create the plan table first.  But an
FK seems like a better answer.

			regards, tom lane

Thu, 26 Feb 2004 08:54:59 -0500
Tom Lane <tgl@sss.pgh.pa.us>
Re: Check Constraints and pg_dump 
Tom,

I have another instance of a possible function being used as a check constraint: a function that makes sure there is one row, and only one row in a table. 

At table creation, and the creation of the constraint, there are no rows in the table. So, even if the constraint is a valid one to have, it will fail. 

We use check constraint functions in a few places, and they work just fine for us (minus the case of trying to restore the database from a pg_dump archive). Is it impossible to treat check constraints similar to other constraints and make them deferrable, specifically in the restoration from a pg_dump archive? Is there a specific reason check constraints are handled differently from other constraints?

Jonathan Scott


On Thu, 26 Feb 2004 08:54:59 -0500
Tom Lane <tgl@sss.pgh.pa.us> wrote:

> Jonathan Scott <jwscott@vanten.com> writes:
> > The functions and tables create just fine, but when it gets to the
> > COPY part of the sql script, it tries to load tables in what really is
> > the wrong order. The check constraint is making sure there is a "plan"
> > before there is a "contract", yet pg_dump is trying to load the
> > contract table before there is anything in the plan table.
> 
> Shouldn't you be using a foreign key for that?
> 
> I don't see any reasonable way that pg_dump can be expected to
> understand that a check constraint expresses a relationship between two
> tables.  The semantics of check constraints aren't right for it anyway.
> 
> All else being equal, I think the tables will be loaded in OID order,
> so a possible workaround is to create the plan table first.  But an
> FK seems like a better answer.
> 
> 			regards, tom lane
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 8: explain analyze is your friend
> 


-- 
Jonathan Scott, Programmer, Vanten K.K.
jwscott@vanten.com	Tel: 03-5919-0266
http://www.vanten.com	Fax: 03-5919-0267

Mon, 1 Mar 2004 14:42:34 +0900
Jonathan Scott <jwscott@vanten.com>
Re: Check Constraints and pg_dump
On Thu, 26 Feb 2004, Tom Lane wrote:

> Jonathan Scott <jwscott@vanten.com> writes:
> > The functions and tables create just fine, but when it gets to the
> > COPY part of the sql script, it tries to load tables in what really is
> > the wrong order. The check constraint is making sure there is a "plan"
> > before there is a "contract", yet pg_dump is trying to load the
> > contract table before there is anything in the plan table.
>
> Shouldn't you be using a foreign key for that?

Can you explain how to do this? There is no reference to a plan in the
contract table; the constraint just checks to see that, if a contract
exists, there is at least one plan referencing that contract.

There is of course a foreign key constraint used in the plan table to
make sure that the contract exists.

> I don't see any reasonable way that pg_dump can be expected to
> understand that a check constraint expresses a relationship between two
> tables.  The semantics of check constraints aren't right for it anyway.

What other constraint could one use for a situation like this?

At any rate, I am not sure why pg_dump has to know or care what check
constraints do; if it simply treated them as it does all the other
constraints, and applied them after all the data are loaded, wouldn't
the problem just go away?

cjs
-- 
Curt Sampson  <cjs@cynic.net>   +81 90 7737 2974   http://www.NetBSD.org
    Don't you know, in this new Dark Age, we're all light.  --XTC

Tue, 2 Mar 2004 10:52:52 +0900 (JST)
Curt Sampson <cjs@cynic.net>
Re: Check Constraints and pg_dump 
Curt Sampson <cjs@cynic.net> writes:
> Can you explain how to do this? There is no reference to a plan in the
> contract table; the constraint just checks to see that, if a contract
> exists, there is at least one plan referencing that contract.
> There is of course a foreign key constraint used in the plan table to
> make sure that the contract exists.

If so, how would it be possible to create a plan before creating the
contract?  I don't think the OP's requirements are clearly thought out.

> At any rate, I am not sure why pg_dump has to know or care what check
> constraints do; if it simply treated them as it does all the other
> constraints, and applied them after all the data are loaded, wouldn't
> the problem just go away?

If we did that we'd be slowing bulk loads (since each added check
constraint would incur an additional scan over the table) and
decreasing legibility of the dumped schema (surely you will agree
that it's more readable to keep the constraint in the CREATE TABLE
command).

There is code in CVS tip pg_dump to split out a check constraint from
the parent table when this is the only way to break a circular
dependency.  But I'm disinclined to apply that transformation all the
time, especially when the only reason to do so is to support a misuse
of check constraints.  Check constraints are not intended to handle
cross-table checks, and I'm unwilling to buy into any suggestion that
we should consider that a supported use.

We have talked in the past about supporting SQL's "CREATE ASSERTION"
command, which *is* intended to describe cross-table conditions.
I don't recall that anyone had good ideas about a reasonably efficient
implementation though.

In the meantime, if what's wanted is a one-time check at row insertion,
the right way to express that behavior is with an ON INSERT trigger.

			regards, tom lane

Mon, 01 Mar 2004 22:22:24 -0500
Tom Lane <tgl@sss.pgh.pa.us>
Re: Check Constraints and pg_dump 
On Mon, 1 Mar 2004, Tom Lane wrote:

> Curt Sampson <cjs@cynic.net> writes:
> > Can you explain how to do this? There is no reference to a plan in the
> > contract table; the constraint just checks to see that, if a contract
> > exists, there is at least one plan referencing that contract.
> > There is of course a foreign key constraint used in the plan table to
> > make sure that the contract exists.
>
> If so, how would it be possible to create a plan before creating the
> contract?  I don't think the OP's requirements are clearly thought out.

You create the contract and its first plan at the same time, inserting
the plan first. It works fine.

> > At any rate, I am not sure why pg_dump has to know or care what check
> > constraints do; if it simply treated them as it does all the other
> > constraints, and applied them after all the data are loaded, wouldn't
> > the problem just go away?
>
> If we did that we'd be slowing bulk loads (since each added check
> constraint would incur an additional scan over the table)....

Certainly, but do we not already pay that price for all non-check
constraints? And it slows loads a lot more when you have to edit your
dumps because they are otherwise unloadable. At any rate, this being a
database, I'm inclined more towards correctness than speed.

> and decreasing legibility of the dumped schema (surely you will agree
> that it's more readable to keep the constraint in the CREATE TABLE
> command).

I agree that it's more readable, yes. But again, do we not already pay
that price for all non-check constraints?

> There is code in CVS tip pg_dump to split out a check constraint from
> the parent table when this is the only way to break a circular
> dependency.  But I'm disinclined to apply that transformation all the
> time, especially when the only reason to do so is to support a misuse
> of check constraints.

I'm having great difficulty understanding why this is a "misuse." What
is the proper way to check that a contract cannot exist without at least
one plan?

> Check constraints are not intended to handle
> cross-table checks, and I'm unwilling to buy into any suggestion that
> we should consider that a supported use.

So how do we handle it?

> We have talked in the past about supporting SQL's "CREATE ASSERTION"
> command, which *is* intended to describe cross-table conditions.
> I don't recall that anyone had good ideas about a reasonably efficient
> implementation though.

I would happily settle for an inefficent implementation; that would give
me the choice of correctness versus efficiency, rather than having no
choice at all.

> In the meantime, if what's wanted is a one-time check at row insertion,
> the right way to express that behavior is with an ON INSERT trigger.

That's not an adequate check; it would allow you later to delete the
plan without deleting the contract.

cjs
-- 
Curt Sampson  <cjs@cynic.net>   +81 90 7737 2974   http://www.NetBSD.org
    Don't you know, in this new Dark Age, we're all light.  --XTC

Tue, 2 Mar 2004 12:59:41 +0900 (JST)
Curt Sampson <cjs@cynic.net>
Re: Check Constraints and pg_dump 
On Monday 01 March 2004 22:59, Curt Sampson wrote:
> On Mon, 1 Mar 2004, Tom Lane wrote:
> > Curt Sampson <cjs@cynic.net> writes:
> > > Can you explain how to do this? There is no reference to a plan in the
> > > contract table; the constraint just checks to see that, if a contract
> > > exists, there is at least one plan referencing that contract.
> > > There is of course a foreign key constraint used in the plan table to
> > > make sure that the contract exists.
> >
> > If so, how would it be possible to create a plan before creating the
> > contract?  I don't think the OP's requirements are clearly thought out.
>
> You create the contract and its first plan at the same time, inserting
> the plan first. It works fine.
>
<snip>
> > In the meantime, if what's wanted is a one-time check at row insertion,
> > the right way to express that behavior is with an ON INSERT trigger.
>
> That's not an adequate check; it would allow you later to delete the
> plan without deleting the contract.
>

Wouldn't a FK on both tables be the appropriate schema?  With the FK on 
contract being deffered?

Robert Treat
-- 
Build A Brighter Lamp :: Linux Apache {middleware} PostgreSQL

Tue, 2 Mar 2004 09:45:03 -0500
Robert Treat <xzilla@users.sourceforge.net>
Re: Check Constraints and pg_dump
On Tue, Mar 02, 2004 at 09:45:03 -0500,
  Robert Treat <xzilla@users.sourceforge.net> wrote:
> 
> Wouldn't a FK on both tables be the appropriate schema?  With the FK on 
> contract being deffered?

No, since he only cares that there is at least one plan for a contract,
not a particular plan. You can do something like this as a hack where
when the plan referenced by the contract gets deleted that the contract
has to be changed to reference another plan or be deleted. But I think
using triggers is a better way to do this.

Tue, 2 Mar 2004 11:09:21 -0600
Bruno Wolff III <bruno@wolff.to>
Re: Check Constraints and pg_dump
On Tue, 2 Mar 2004, Robert Treat wrote:

> Wouldn't a FK on both tables be the appropriate schema?  With the FK on
> contract being deffered?

Unfortunately, it appears that an FK must reference a unique column. So this:

    ALTER TABLE contract ADD CONSTRAINT contract_must_have_a_plan
        FOREIGN KEY ( contract_id ) REFERENCES plan ( contract_id )
        INITIALLY DEFERRED;

produces the error message:

    UNIQUE constraint matching given keys for referenced table "plan" not found

Since a plan may have more than one contract.

cjs
-- 
Curt Sampson  <cjs@cynic.net>   +81 90 7737 2974   http://www.NetBSD.org
    Don't you know, in this new Dark Age, we're all light.  --XTC

Wed, 3 Mar 2004 08:25:07 +0900 (JST)
Curt Sampson <cjs@cynic.net>
Re: Check Constraints and pg_dump