From: | Stephen Howie <showie(at)centwire(dot)com> |
---|---|
To: | Michael Fuhr <mike(at)fuhr(dot)org> |
Cc: | pgsql-general(at)postgresql(dot)org |
Subject: | Re: Help with transactions |
Date: | 2005-03-21 15:58:27 |
Message-ID: | 423EEF23.300@centwire.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-general |
Thanks for the reply.
I've notice a couple things. I ran a couple test and at first I
couldn't duplicate my error on some test tables. But I then added
inheritance to one of the tables and thats when I got the error again.
It looks like there is an error when obtaining the seq id (nextval) from
the original table and using it on a table that has a foreign key to the
original table by inserting it into the table that inherits the original
table, within a transaction. What I think is happening is since the
insert is on the inherited table the foreign key doesn't see the insert
into the original table until the transaction is committed.
Here is a sample of how I duplicated my error.
By running
SELECT insert_data('A123456789','A','A2345');
on the below schema layout I get this error
ERROR: insert or update on table "table2" violates foreign key
constraint "table2_fk_id_fk"
=====START========
CREATE TABLE table1 (
id serial NOT NULL,
data character(10) NOT NULL
);
CREATE TABLE table2 (
id serial NOT NULL,
fk_id integer NOT NULL,
more_data character(5) NOT NULL
);
CREATE TABLE inherit_table (
even_more_data character(1) NOT NULL
)
INHERITS (table1);
ALTER TABLE ONLY table1
ADD CONSTRAINT table1_pkey PRIMARY KEY (id);
ALTER TABLE ONLY table2
ADD CONSTRAINT table2_pkey PRIMARY KEY (id);
ALTER TABLE ONLY table2
ADD CONSTRAINT table2_fk_id_fk FOREIGN KEY (fk_id) REFERENCES
table1(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
CREATE VIEW view_table1 AS
SELECT table1.id, table1.data
FROM table1;
CREATE VIEW view_table2 AS
SELECT table2.id, table2.fk_id, table2.more_data
FROM table2;
CREATE VIEW view_inherit_table AS
SELECT inherit_table.id, inherit_table.data, inherit_table.even_more_data
FROM inherit_table;
CREATE RULE view_table1_insert AS ON INSERT TO view_table1 DO INSTEAD
INSERT INTO table1 (id, data) VALUES (new.id, new.data);
CREATE RULE view_table2_insert AS ON INSERT TO view_table2 DO INSTEAD
INSERT INTO table2 (id, fk_id, more_data) VALUES (new.id, new.fk_id,
new.more_data);
CREATE RULE view_inherit_table_insert AS ON INSERT TO view_inherit_table
DO INSTEAD INSERT INTO inherit_table (id, data, even_more_data) VALUES
(new.id, new.data, new.even_more_data);
CREATE FUNCTION insert_table2 (integer, character) RETURNS integer
AS '
DECLARE
table2_id INTEGER;
table1_id ALIAS FOR $1;
newdata ALIAS FOR $2;
BEGIN
table2_id = nextval(''table2_id_seq'');
INSERT INTO view_table2 (id, fk_id, more_data) VALUES (table2_id,
table1_id, newdata);
RETURN table2_id;
END;
'
LANGUAGE plpgsql SECURITY DEFINER;
CREATE FUNCTION insert_inherit_table (character, character) RETURNS integer
AS '
DECLARE
table1_id INTEGER;
newdata ALIAS FOR $1;
new_even_more_data ALIAS FOR $2;
BEGIN
table1_id = nextval(''public.table1_id_seq'');
INSERT INTO view_inherit_table (id, data, even_more_data) VALUES
(table1_id, newdata, new_even_more_data);
RETURN table1_id;
END;
'
LANGUAGE plpgsql SECURITY DEFINER;
CREATE FUNCTION insert_data (character, character, character) RETURNS
boolean
AS '
DECLARE
newdata1 ALIAS FOR $1;
newdata2 ALIAS FOR $2;
newdata3 ALIAS FOR $3;
table1_id INTEGER = 0;
table2_id INTEGER = 0;
BEGIN
table1_id = insert_inherit_table(newdata1, newdata2 );
RAISE LOG ''Table1 ID: %'', table1_id;
table2_id = insert_table2(table1_id, newdata3);
IF table2_id > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END;
'
LANGUAGE plpgsql SECURITY DEFINER;
========END===========
Also, in my original schema I'm getting an increment of 2 every time I
run nextval. I can't duplicate this yet but I'm looking into it.
Possibly my error somewhere in the function.
Thanks
-------------------------
Stephen Howie
Michael Fuhr wrote:
>On Fri, Mar 18, 2005 at 09:22:52AM -0500, Stephen Howie wrote:
>
>
>
>>I have a java program that excepts print streams and inserts in into a
>>spool table as a bytea. This fires a pl/pgsql trigger that passes the
>>bytea to a pl/perl function to process the bytea and spits the results
>>as an array back. It then proceeds to insert the data into multiple
>>tables. Problem is that two of the tables data is inserted into inside
>>this transaction, one has a foreign key to the other. As you can guess
>>I get a foreign key violation because the transaction is not committed
>>
>>
>
>A transaction doesn't need to be committed for operations to see
>the effects of previous operations in the same transaction, but
>there could be visibility problems related to what happens when.
>
>Could you post the simplest self-contained example that demonstrates
>the problem? It'll be easier to understand the interactions if we
>can see the exact code. In simple tests I successfully did what
>you describe, so apparently my experiment didn't duplicate what
>you're doing.
>
>What version of PostgreSQL are you using?
>
>
>
>>and as far as I understand PostgreSQL does not support dirty reads or
>>nested transactions.
>>
>>
>
>You probably need neither. PostgreSQL 8.0 supports nested transactions
>in the form of savepoints.
>
>
>
>>1) what is there another way to handle this transaction that would
>>resolve this violation without using dirty reads and
>>
>>
>
>Let's see what you're doing before thinking dirty reads would be a
>solution. Or perhaps you're thinking about them in a slightly
>different sense than transaction literature usually describes.
>
>
>
>>2) It looks like running the trigger after insert on a table does
>>not run as a separate transaction.
>>
>>
>
>Why would it?
>
>
>
>>Is the insert to that table suppose to fail if the trigger fails?
>>To me that defeats the purpose of having a trigger after insert.
>>
>>
>
>An after trigger is about visibility. Here's an excerpt from the
>"Triggers" chapter in the documentation:
>
> Row after triggers are most sensibly used to propagate the updates
> to other tables, or make consistency checks against other tables.
> The reason for this division of labor is that an after trigger
> can be certain it is seeing the final value of the row, while a
> before trigger cannot; there might be other before triggers firing
> after it.
>
>An operation ain't over 'til it's over: if an after trigger doesn't
>like what it sees, it can still abort the operation by raising an
>exception. That doesn't defeat the purpose -- it's part of the
>purpose.
>
>
>
Attachment | Content-Type | Size |
---|---|---|
showie.vcf | text/x-vcard | 190 bytes |
From | Date | Subject | |
---|---|---|---|
Next Message | Michael Fuhr | 2005-03-21 16:15:55 | Re: PHP and Postgres setup |
Previous Message | Richard Huxton | 2005-03-21 15:57:38 | Re: Time Stamp |