Обсуждение: Data visibility

Поиск
Список
Период
Сортировка

Data visibility

От
Rafal Pietrak
Дата:
Hi,

I'm trying to write a trigger function, that would update an
'associated' TEBLE on INSERT to master table:

CREATE TABLE master (id int not null unique, info text, ....);
CREATE TABLE aux (master int references master(id), info text, ...);
CREATE FUNCTION adjust() RETURNS "trigger" AS $$ BEGIN
    new.id := 1000-old.id;
    INSERT INTO aux (master, info) VALUES (new.id, 'hello world');
    RETURN new;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER pico BEFORE INSERT ON master FOR EACH ROW EXECUTE
PROCEDURE adjust();

Note, that the trigger function ADJUST() *computs* the ID value for
MASTER. The value computed complies to all MASTER table constraints, so
it should be usable as foreing key for the insert statement that
follows, but it isn't - I get foreign key reference violation fault at
that point.

Now, normaly (e.g. in SQL sequence as typed into the psql command line
utility), when I:
BEGIN;
INSERT INTO master (id,...)...;
SELECT * from master;
ROLLBACK;
SELECT * from master;

... the first SELECT above shows the newly inserted values, despite the
fact, that the transaction didn't commit, yet. And when the transaction
rolls back, the data automagically disapear (second SELECT). I
understand this is normal.

But in my trigger function "adjust()", executed within a transaction
opened by "INSERT INTO master", the 'fresh' data (set by "new.id :=
value") isn't visible to other commands (like: INSERT INTO aux...).

Is this intentional?

Theoretically: would it violate corrent database application coding
style/standards (SQL standard?), if the new.* data was in fact visible
for statements inside such transaction, like the INSERT AUX above?

BTW: May be there is other solution for my "INSERT ... AUX" which I
cannot see myself? One thing, though: I cannot have TRIGGER AFTER INSERT
do the job of putting the correct data into AUX TABLE, since that table
takes intermediate data used during MASTER.ID computation, and it is
required, that those intermediate data never-ever get into the MASTER
table itself (or any other table apart from the AUX table - where they
must reside. It's one of the reasons for AUX table to exist).
--
-R

Re: Data visibility

От
Rafal Pietrak
Дата:
On Sun, 2006-10-15 at 20:01 +0200, Rafal Pietrak wrote:
>     new.id := 1000-old.id;

Sory, correction.

Of cource, this ID update looks more like the following (OLD.* isn't
valid at this point):

    new.id := 1000 - new.id;

--
-R

Re: Data visibility

От
Tom Lane
Дата:
Rafal Pietrak <rafal@zorro.isa-geek.com> writes:
> CREATE TABLE master (id int not null unique, info text, ....);
> CREATE TABLE aux (master int references master(id), info text, ...);
> CREATE FUNCTION adjust() RETURNS "trigger" AS $$ BEGIN
>     new.id := 1000-old.id;
>     INSERT INTO aux (master, info) VALUES (new.id, 'hello world');
>     RETURN new;
> END $$ LANGUAGE plpgsql;
> CREATE TRIGGER pico BEFORE INSERT ON master FOR EACH ROW EXECUTE
> PROCEDURE adjust();

> But in my trigger function "adjust()", executed within a transaction
> opened by "INSERT INTO master", the 'fresh' data (set by "new.id :=
> value") isn't visible to other commands (like: INSERT INTO aux...).

Well, of course not: it's a BEFORE trigger, so the row insertion hasn't
actually happened yet.  I think you need to split this operation into a
BEFORE trigger that changes the ID, and an AFTER trigger that propagates
the data into the other table.

            regards, tom lane

Re: Data visibility

От
Rafal Pietrak
Дата:
On Sun, 2006-10-15 at 15:15 -0400, Tom Lane wrote:
> Well, of course not: it's a BEFORE trigger, so the row insertion hasn't
> actually happened yet.  I think you need to split this operation into a
> BEFORE trigger that changes the ID, and an AFTER trigger that propagates
> the data into the other table.

Hmm. I tried that, But I'm stuck with finding a way to propagate the
'intermediate data' between BEFORE/AFTER triggers, *outside* of a TABLE
structure. That data is easily accesable inside the BEFORE TRIGGER as
simple variable.

But, would it work if I drop foreign key constraint on AUX table in
BEFORE INSERT trigger function, and resotre it back in AFTER INSERT? ...
simply rising an error (thus aborting INSERT) if the later fails? Are
there scenarios, leading to foreign key consistancy loss if I do that?

Ideas?

--
-R

Re: Data visibility

От
Tom Lane
Дата:
Rafal Pietrak <rafal@zorro.isa-geek.com> writes:
> Hmm. I tried that, But I'm stuck with finding a way to propagate the
> 'intermediate data' between BEFORE/AFTER triggers, *outside* of a TABLE
> structure. That data is easily accesable inside the BEFORE TRIGGER as
> simple variable.

Um ... what data do you think is visible to the BEFORE trigger but not
the AFTER trigger?  They both see both states of the row, if that's what
you're wondering.

            regards, tom lane

Re: Data visibility

От
Rafal Pietrak
Дата:
On Sun, 2006-10-15 at 18:16 -0400, Tom Lane wrote:
> Rafal Pietrak <rafal@zorro.isa-geek.com> writes:
> > Hmm. I tried that, But I'm stuck with finding a way to propagate the
> > 'intermediate data' between BEFORE/AFTER triggers, *outside* of a TABLE
> > structure. That data is easily accesable inside the BEFORE TRIGGER as
> > simple variable.
>
> Um ... what data do you think is visible to the BEFORE trigger but not
> the AFTER trigger?  They both see both states of the row, if that's what
> you're wondering.

No, no. I don't 'think' the data is lost between BEFORE and AFTER. I
*make* them disapear.... as I cannot find any place to pass them over.
The MASTSTER table does not contain columns for them ... and will not.
But in the BEFORE trigger function, I have them as local variables.

Are there ways to have my private 'virtual placeholder'? - like *NEW*
and *OLD* are? Placeholders which are outside of any table, and
available just inside the INSERT transaction, but throuout *all* it's
triggers.

Taking reference from other languages, I might think of some sort of
static variables:
CREATE FUNCTION piko() ....$$ DECLARE priv RECORD STATIC; BEGIN ....
END;
... or
CREATE FUNCTION piko(priv RECORD STATIC) ....

so that another function used for another trigger on that same table
will have access to the same record, which would retain data throught
the transactoin?

Just ideas. But may be there are currently tools to have such
functionality?

But if nothing like this is available, I think I'll need an additional
table, identical to AUX - sort of AUX shadow, but without foreign key
constraint to MASTER, so that I can put my data there in BEFORE, then
copy those into the AUX in AFTER, and purge the aux-shadow on exit from
AFTER.

In any case, discussion helps. Thenx.

--
-R