Обсуждение: rules on INSERT can't UPDATE new instance?

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

rules on INSERT can't UPDATE new instance?

От
Louis-David Mitterrand
Дата:
 From the create_rule man page this example is offered:

  CREATE RULE example_5 AS
           ON INERT TO emp WHERE new.salary > 5000
           DO
            UPDATE NEWSET SET salary = 5000;

But what is "NEWSET"? Is it a keyword?

My problem is that on an insert with an invalid amount I try to perform
an update with a corrected amount, but the action part of the rule
doesn't affect or "see" the newly inserted row (or so it seems).

I tried: CREATE RULE ON INSERT TO bid WHERE new.price > limit
         DO UPDATE bid SET price = 0.1;

and all price columns in the bid table would be set to 0.1 _except_ the
newly inserted row.

Am I missing something obvious?

TIA

--
Louis-David Mitterrand - ldm@apartia.org - http://www.apartia.fr

Re: rules on INSERT can't UPDATE new instance?

От
"Stephan Szabo"
Дата:
Although not exactly what you were asking about, it might be easier to get
the effect with a before insert trigger written in plpgsql.

(only minimally tested -- and against a 6.5 db - and replace the 100 and 0.1
with real values)
create function checktriggerfunc() returns opaque as '
begin
 if (NEW.price>100) then
  NEW.price=0.1;
end if;
return NEW;
end;
' language 'plpgsql';

create trigger checktrigger before insert on bid for each row
execute procedure checktriggerfunc();

----- Original Message -----
From: "Louis-David Mitterrand" <cunctator@apartia.ch>
To: <pgsql-general@hub.org>
Sent: Saturday, May 20, 2000 2:00 AM
Subject: [GENERAL] rules on INSERT can't UPDATE new instance?


>
>  From the create_rule man page this example is offered:
>
>   CREATE RULE example_5 AS
>            ON INERT TO emp WHERE new.salary > 5000
>            DO
>             UPDATE NEWSET SET salary = 5000;
>
> But what is "NEWSET"? Is it a keyword?
>
> My problem is that on an insert with an invalid amount I try to perform
> an update with a corrected amount, but the action part of the rule
> doesn't affect or "see" the newly inserted row (or so it seems).
>
> I tried: CREATE RULE ON INSERT TO bid WHERE new.price > limit
>          DO UPDATE bid SET price = 0.1;
>
> and all price columns in the bid table would be set to 0.1 _except_ the
> newly inserted row.
>
> Am I missing something obvious?



Re: rules on INSERT can't UPDATE new instance?

От
Bruce Momjian
Дата:
>
>  From the create_rule man page this example is offered:
>
>   CREATE RULE example_5 AS
>            ON INERT TO emp WHERE new.salary > 5000
>            DO
>             UPDATE NEWSET SET salary = 5000;
>
> But what is "NEWSET"? Is it a keyword?

It should be:

CREATE RULE example_5 AS
    ON INERT TO emp WHERE new.salary > 5000
    DO
        UPDATE emp SET salary = 5000
        WHERE emp.oid = new.oid;

Fixing now.

>
> My problem is that on an insert with an invalid amount I try to perform
> an update with a corrected amount, but the action part of the rule
> doesn't affect or "see" the newly inserted row (or so it seems).
>
> I tried: CREATE RULE ON INSERT TO bid WHERE new.price > limit
>          DO UPDATE bid SET price = 0.1;
>
> and all price columns in the bid table would be set to 0.1 _except_ the
> newly inserted row.
>
> Am I missing something obvious?

No, buggy documentation.  My book has a section on rules too, but you
should be fine now.

--
  Bruce Momjian                        |  http://www.op.net/~candle
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: rules on INSERT can't UPDATE new instance?

От
Louis-David Mitterrand
Дата:
On Sat, May 20, 2000 at 07:35:38AM -0400, Bruce Momjian wrote:
> >  From the create_rule man page this example is offered:
> >
> >   CREATE RULE example_5 AS
> >            ON INERT TO emp WHERE new.salary > 5000
> >            DO
> >             UPDATE NEWSET SET salary = 5000;
> >
> > But what is "NEWSET"? Is it a keyword?
>
> It should be:
>
> CREATE RULE example_5 AS
>     ON INERT TO emp WHERE new.salary > 5000
>     DO
>         UPDATE emp SET salary = 5000
>         WHERE emp.oid = new.oid;
>
> Fixing now.

But this doesn't work in PG 7.0:

auction=> create table test (price float);
CREATE
auction=> create rule price_control AS ON INSERT TO test WHERE new.price > 100 DO UPDATE test SET price = 100 where
test.oid= new.oid; 
CREATE 27913 1
auction=> INSERT INTO test VALUES (101);
INSERT 27914 1
auction=> SELECT test.*;
 price
-------
   101
(1 row)


--
Louis-David Mitterrand - ldm@apartia.org - http://www.apartia.fr

MACINTOSH == Most Applications Crash If Not The Operatings System Hangs

Re: rules on INSERT can't UPDATE new instance?

От
Bruce Momjian
Дата:
> On Sat, May 20, 2000 at 07:35:38AM -0400, Bruce Momjian wrote:
> > >  From the create_rule man page this example is offered:
> > >
> > >   CREATE RULE example_5 AS
> > >            ON INERT TO emp WHERE new.salary > 5000
> > >            DO
> > >             UPDATE NEWSET SET salary = 5000;
> > >
> > > But what is "NEWSET"? Is it a keyword?
> >
> > It should be:
> >
> > CREATE RULE example_5 AS
> >     ON INERT TO emp WHERE new.salary > 5000
> >     DO
> >         UPDATE emp SET salary = 5000
> >         WHERE emp.oid = new.oid;
> >
> > Fixing now.
>
> But this doesn't work in PG 7.0:
>
> auction=> create table test (price float);
> CREATE
> auction=> create rule price_control AS ON INSERT TO test WHERE new.price > 100 DO UPDATE test SET price = 100 where
test.oid= new.oid; 
> CREATE 27913 1
> auction=> INSERT INTO test VALUES (101);
> INSERT 27914 1
> auction=> SELECT test.*;
>  price
> -------
>    101
> (1 row)

Yes, I see it failing too.  I tried old.oid, and that failed too.

I know there is a recursive problem with rules acting on their own
table, where if you have an INSERT rule that performs an INSERT on the
same table, the rules keep firing in a loop.

I thought an INSERT rule with an UPDATE action would work on the same
table, but that fails.  Seems the rule is firing before the INSERT
happens.

I am not really sure what to recommend.  The INSERT rule clearly doesn't
fix cases where someone UPDATE's the row to != 100.  A CHECK constraint
could be used to force the column to contain 100, but that doesn't
silently fix non-100 values, which seemed to be your goal.  A trigger
will allow this kind of action, on INSERT and UPDATE, though they are a
little more complicated than rules.

--
  Bruce Momjian                        |  http://www.op.net/~candle
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: rules on INSERT can't UPDATE new instance?

От
Louis-David Mitterrand
Дата:
On Sat, May 20, 2000 at 10:41:53AM -0400, Bruce Momjian wrote:
> > But this doesn't work in PG 7.0:
> >
> > auction=> create table test (price float);
> > CREATE
> > auction=> create rule price_control AS ON INSERT TO test WHERE new.price > 100 DO UPDATE test SET price = 100 where
test.oid= new.oid; 
> > CREATE 27913 1
> > auction=> INSERT INTO test VALUES (101);
> > INSERT 27914 1
> > auction=> SELECT test.*;
> >  price
> > -------
> >    101
> > (1 row)
>
> Yes, I see it failing too.  I tried old.oid, and that failed too.
>
> I know there is a recursive problem with rules acting on their own
> table, where if you have an INSERT rule that performs an INSERT on the
> same table, the rules keep firing in a loop.
>
> I thought an INSERT rule with an UPDATE action would work on the same
> table, but that fails.  Seems the rule is firing before the INSERT
> happens.
>
> I am not really sure what to recommend.  The INSERT rule clearly doesn't
> fix cases where someone UPDATE's the row to != 100.  A CHECK constraint
> could be used to force the column to contain 100, but that doesn't
> silently fix non-100 values, which seemed to be your goal.  A trigger
> will allow this kind of action, on INSERT and UPDATE, though they are a
> little more complicated than rules.

Thanks for all your help. You are right: this seems more like the job of
a trigger and I am exploring that topic in depth right now.

Cheers,

--
Louis-David Mitterrand - ldm@apartia.org - http://www.apartia.fr

       Parkinson's Law:  Work expands to fill the time alloted it.

Re: rules on INSERT can't UPDATE new instance?

От
Tom Lane
Дата:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> I thought an INSERT rule with an UPDATE action would work on the same
> table, but that fails.  Seems the rule is firing before the INSERT
> happens.

Yes, a trigger is the right way to do surgery on a tuple before it is
stored.  Rules are good for generating additional SQL queries that will
insert/update/delete other tuples (usually, but not necessarily, in
other tables).  Even if it worked, a rule would be a horribly
inefficient way to handle modification of the about-to-be-inserted
tuple, because (being an independent query) it'd have to scan the table
to find the tuple you are talking about!

The reason the additional queries are done before the original command
is explained thus in the source code:

     * The original query is appended last if not instead
     * because update and delete rule actions might not do
     * anything if they are invoked after the update or
     * delete is performed. The command counter increment
     * between the query execution makes the deleted (and
     * maybe the updated) tuples disappear so the scans
     * for them in the rule actions cannot find them.

This seems to make sense for UPDATE/DELETE, but I wonder whether
the ordering should be different for the INSERT case: perhaps it
should be original-query-first in that case.

            regards, tom lane

Re: rules on INSERT can't UPDATE new instance?

От
Bruce Momjian
Дата:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > I thought an INSERT rule with an UPDATE action would work on the same
> > table, but that fails.  Seems the rule is firing before the INSERT
> > happens.
>
> Yes, a trigger is the right way to do surgery on a tuple before it is
> stored.  Rules are good for generating additional SQL queries that will
> insert/update/delete other tuples (usually, but not necessarily, in
> other tables).  Even if it worked, a rule would be a horribly
> inefficient way to handle modification of the about-to-be-inserted
> tuple, because (being an independent query) it'd have to scan the table
> to find the tuple you are talking about!
>
> The reason the additional queries are done before the original command
> is explained thus in the source code:
>
>      * The original query is appended last if not instead
>      * because update and delete rule actions might not do
>      * anything if they are invoked after the update or
>      * delete is performed. The command counter increment
>      * between the query execution makes the deleted (and
>      * maybe the updated) tuples disappear so the scans
>      * for them in the rule actions cannot find them.
>
> This seems to make sense for UPDATE/DELETE, but I wonder whether
> the ordering should be different for the INSERT case: perhaps it
> should be original-query-first in that case.
>

Thanks, Tom.  I was writing the Trigger section of my book the past few
days, and this helped me define when to use rules and when to use
triggers.


--
  Bruce Momjian                        |  http://www.op.net/~candle
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: rules on INSERT can't UPDATE new instance?

От
Bruce Momjian
Дата:
Is the INSERT rule re-ordering mentioned a TODO item?

> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > I thought an INSERT rule with an UPDATE action would work on the same
> > table, but that fails.  Seems the rule is firing before the INSERT
> > happens.
>
> Yes, a trigger is the right way to do surgery on a tuple before it is
> stored.  Rules are good for generating additional SQL queries that will
> insert/update/delete other tuples (usually, but not necessarily, in
> other tables).  Even if it worked, a rule would be a horribly
> inefficient way to handle modification of the about-to-be-inserted
> tuple, because (being an independent query) it'd have to scan the table
> to find the tuple you are talking about!
>
> The reason the additional queries are done before the original command
> is explained thus in the source code:
>
>      * The original query is appended last if not instead
>      * because update and delete rule actions might not do
>      * anything if they are invoked after the update or
>      * delete is performed. The command counter increment
>      * between the query execution makes the deleted (and
>      * maybe the updated) tuples disappear so the scans
>      * for them in the rule actions cannot find them.
>
> This seems to make sense for UPDATE/DELETE, but I wonder whether
> the ordering should be different for the INSERT case: perhaps it
> should be original-query-first in that case.
>
>             regards, tom lane
>


--
  Bruce Momjian                        |  http://www.op.net/~candle
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: rules on INSERT can't UPDATE new instance?

От
Tom Lane
Дата:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Is the INSERT rule re-ordering mentioned a TODO item?

Darn if I know.  I threw the thought out for discussion, but didn't
see any comments.  I'm not in a hurry to change it, unless there's
consensus that we should.

            regards, tom lane


>> Bruce Momjian <pgman@candle.pha.pa.us> writes:
>>>> I thought an INSERT rule with an UPDATE action would work on the same
>>>> table, but that fails.  Seems the rule is firing before the INSERT
>>>> happens.
>>
>> Yes, a trigger is the right way to do surgery on a tuple before it is
>> stored.  Rules are good for generating additional SQL queries that will
>> insert/update/delete other tuples (usually, but not necessarily, in
>> other tables).  Even if it worked, a rule would be a horribly
>> inefficient way to handle modification of the about-to-be-inserted
>> tuple, because (being an independent query) it'd have to scan the table
>> to find the tuple you are talking about!
>>
>> The reason the additional queries are done before the original command
>> is explained thus in the source code:
>>
>> * The original query is appended last if not instead
>> * because update and delete rule actions might not do
>> * anything if they are invoked after the update or
>> * delete is performed. The command counter increment
>> * between the query execution makes the deleted (and
>> * maybe the updated) tuples disappear so the scans
>> * for them in the rule actions cannot find them.
>>
>> This seems to make sense for UPDATE/DELETE, but I wonder whether
>> the ordering should be different for the INSERT case: perhaps it
>> should be original-query-first in that case.