Thread: Referential Integrity problem

Referential Integrity problem

From
James Gregory
Date:
I hope this one is just some misunderstanding on my part.

I have a table structure like so (scroll down for executive summary):

create table common (
        createdate timestamp default current_timestamp,
        modifydate timestamp default current_timestamp,
        syncdate timestamp default '1900-01-01'
);

create table saleable_item (
        id serial primary key,
        sale_id integer references sale,
        stock integer default 0,
        baseprice float default 0.00
) inherits (common);

create table product (
        title_id integer references title,
        format_id integer references format
) inherits (saleable_item);

create table chart (
        id serial primary key,
        name text
) inherits (common);

create table chartitem (
        id serial primary key,
        chart_id integer references chart,
        position integer,
        product_id integer references saleable_item
) inherits (common);

That's the minimum I can show you to demonstrate this unfortunately. So,
there is a product table that inherits a saleable_item table,
saleable_item defines fields relating to stuff that you'd sell (products
is a poorly named table, but it's for historical reasons). saleable_item
in turn inherits from common - which defines some fields I need to store
about every record - in particular information to help me syncronise
this database with another one.

The chart and chartitem table are meant to represent listings of
products or rather, saleable_items that my client wants to draw
attention to. So you put an entry into chart to give this collection of
products a descriptive name, and then each item in the chart refers to
this chart by its ID.

Here's the problem:

# insert into chartitem (chart_id, position, product_id) values
(1073741826, 1, 1073741827);
ERROR:  $2 referential integrity violation - key referenced from
chartitem not found in saleable_item

the product ID does exist:

# select id from product where id = 1073741827;
     id
------------
 1073741827
(1 row)

And of course it exists in saleable_item as well (since that is where
the ID field is inherited from).

Now I assume that something has gone wrong in inheriting the primary key
- is there anything I'm missing? I'm sure I've done this sort of thing
before.

# select version();

version
--------------------------------------------------------------------------------------------------------
 PostgreSQL 7.3.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.2.1
(Mandrake Linux 9.1 3.2.1-7mdk)
(1 row)

Many thanks,

James.



Re: Referential Integrity problem

From
Stephan Szabo
Date:
On 19 Mar 2003, James Gregory wrote:

> I hope this one is just some misunderstanding on my part.

Referential integrity constraints currently apply only to the explicitly
named table.  In addition, the saleable_item primary key on id is not
inherited by product (and so there can be duplicates in product - even if
you put a unique constraint on product(id), you still can have duplicates
between saleable_item and product).



Re: Referential Integrity problem

From
James Gregory
Date:
On Wed, 2003-03-19 at 00:08, Stephan Szabo wrote:
> On 19 Mar 2003, James Gregory wrote:
>
> > I hope this one is just some misunderstanding on my part.
>
> Referential integrity constraints currently apply only to the explicitly
> named table.  In addition, the saleable_item primary key on id is not
> inherited by product (and so there can be duplicates in product - even if
> you put a unique constraint on product(id), you still can have duplicates
> between saleable_item and product).

Ar. Is there a way to do what I need to do? No insertions should ever
occur in the "supertable" - is the best way forward to write a trigger
that just tests if the id exists in the supertable? With this assertion
that no inserts will occur in the supertable, is it sufficient to
qualify my references to say saleable_item.id?

This behaviour seems inconsistent (to me anyway). Is it likely to
change? Why isn't the primary key inherited?

Am I correct then in my understanding that postgres's inheritance is
merely a table templating system rather than inheritance, per se? - that
is, it seems to me that if it were inheritance that storing a list of
saleable_items and filling it with products should be entirely
equivalent to storing a list of products. Why is this not so?

Thanks for your help,

James.



Re: Referential Integrity problem

From
Stephan Szabo
Date:
On 19 Mar 2003, James Gregory wrote:

> On Wed, 2003-03-19 at 00:08, Stephan Szabo wrote:
> > On 19 Mar 2003, James Gregory wrote:
> >
> > > I hope this one is just some misunderstanding on my part.
> >
> > Referential integrity constraints currently apply only to the explicitly
> > named table.  In addition, the saleable_item primary key on id is not
> > inherited by product (and so there can be duplicates in product - even if
> > you put a unique constraint on product(id), you still can have duplicates
> > between saleable_item and product).
>
> Ar. Is there a way to do what I need to do? No insertions should ever
> occur in the "supertable" - is the best way forward to write a trigger
> that just tests if the id exists in the supertable? With this assertion
> that no inserts will occur in the supertable, is it sufficient to
> qualify my references to say saleable_item.id?

No, because the triggers still are only going to reference explicitly
saleable_item.  I believe there's a somewhat complicated work-around using
a new table that contains just ids that is referenced by saleable_item,
product and chart_item with triggers for dealing with changes to
saleable_item and product.

> This behaviour seems inconsistent (to me anyway). Is it likely to
> change? Why isn't the primary key inherited?
>
> Am I correct then in my understanding that postgres's inheritance is
> merely a table templating system rather than inheritance, per se? - that
> is, it seems to me that if it were inheritance that storing a list of
> saleable_items and filling it with products should be entirely
> equivalent to storing a list of products. Why is this not so?

Inheritance needs alot of work.  There have been various discussions in
the past (see -general and -hackers archives), but I don't believe that a
plan that satisfied everyone was ever reached.



Re: Referential Integrity problem

From
James Gregory
Date:
On Wed, 2003-03-19 at 00:47, Stephan Szabo wrote:
> On 19 Mar 2003, James Gregory wrote:
>
> > On Wed, 2003-03-19 at 00:08, Stephan Szabo wrote:
> > > On 19 Mar 2003, James Gregory wrote:
> > >
> > > > I hope this one is just some misunderstanding on my part.
> > >
> > > Referential integrity constraints currently apply only to the explicitly
> > > named table.  In addition, the saleable_item primary key on id is not
> > > inherited by product (and so there can be duplicates in product - even if
> > > you put a unique constraint on product(id), you still can have duplicates
> > > between saleable_item and product).
> >
> > Ar. Is there a way to do what I need to do? No insertions should ever
> > occur in the "supertable" - is the best way forward to write a trigger
> > that just tests if the id exists in the supertable? With this assertion
> > that no inserts will occur in the supertable, is it sufficient to
> > qualify my references to say saleable_item.id?
>
> No, because the triggers still are only going to reference explicitly
> saleable_item.  I believe there's a somewhat complicated work-around using
> a new table that contains just ids that is referenced by saleable_item,
> product and chart_item with triggers for dealing with changes to
> saleable_item and product.

Ok, so, it seems to me that what I need to do is create trigger
functions to implement this check. They will basically consist of a
check to maintain referential integrity with this inherited structure,
and throw an exception if the proposed modification would break that.
Then, assuming all the checks passed and no exception was thrown it
would simply return the new row.

So I would need one trigger for inserts and updates, and another for
deletes.

So at this point I have two options - write a script to write a
different trigger function for each inherited table, or, use some
postgres magic in this trigger function to infer what table the new
record is intended for, and then query the system tables to do the right
thing.

The script sounds like a bad idea, just from a maintenance standpoint.
So, is there a way to infer what I need to know from within a trigger?
Alternatively, can I specify the table name as a parameter, and use that
to do the system table queries?

Thanks,

James.



Re: Referential Integrity problem

From
Stephan Szabo
Date:
On 19 Mar 2003, James Gregory wrote:

> Ok, so, it seems to me that what I need to do is create trigger
> functions to implement this check. They will basically consist of a
> check to maintain referential integrity with this inherited structure,
> and throw an exception if the proposed modification would break that.
> Then, assuming all the checks passed and no exception was thrown it
> would simply return the new row.

> The script sounds like a bad idea, just from a maintenance standpoint.
> So, is there a way to infer what I need to know from within a trigger?
> Alternatively, can I specify the table name as a parameter, and use that
> to do the system table queries?

You can give arguments at CREATE TRIGGER time and do stuff based on the
arguments from there.  You'll need to be careful to make sure all of the
concurrency and modification of the pk side of the constraint works
properly.

As a note, you'll need triggers on saleable_item and product to deal with
modifications to the pk-side of the constraint.  The one on saleable_item
isn't strictly necessary since you don't plan to modify it, but it's
probably good from a consistancy stanpoint.  You'll also need triggers on
any other saleable_item subclasses.