Thread: RULES doesn't work as expected

RULES doesn't work as expected

From
"John Hansen"
Date:
It seems rules don't work as expected.
I could be wrong,... In which case, what am I doing wrong?

Clearly, the first insert below should not update the table as well.

... John


CREATE TABLE test (a text, b int4[]);

CREATE RULE test_rule AS 
  ON INSERT TO test 
  WHERE exists(SELECT 1 FROM test WHERE a = NEW.a)
  DO INSTEAD
    UPDATE test SET b = b + NEW.b WHERE a = NEW.a;


db1=# INSERT INTO test (a,b) VALUES (1,'{1}'::int4[]);
INSERT 0 1
db1=# SELECT * FROM test;
 a |   b
---+-------
 1 | {1,1}
(1 row)

db1=# INSERT INTO test (a,b) VALUES (1,'{1}'::int4[]);
INSERT 0 0
db1=# SELECT * FROM test;
 a |    b
---+---------
 1 | {1,1,1}
(1 row)



Re: RULES doesn't work as expected

From
Richard Huxton
Date:
Removed cc to pgsql-patches since that's not the list for this.

John Hansen wrote:
> It seems rules don't work as expected.
> I could be wrong,... In which case, what am I doing wrong?

A rule is like a macro, rewriting the query plan. You're trying to use
it as though it is a trigger. The side-effects of rules can be quite
subtle and catches most of us out at least once.

> Clearly, the first insert below should not update the table as well.

> CREATE TABLE test (a text, b int4[]);
>
> CREATE RULE test_rule AS
>   ON INSERT TO test
>   WHERE exists(SELECT 1 FROM test WHERE a = NEW.a)
>   DO INSTEAD
>     UPDATE test SET b = b + NEW.b WHERE a = NEW.a;
>
>
> db1=# INSERT INTO test (a,b) VALUES (1,'{1}'::int4[]);

The NEW.a doesn't refer to a variable as such, it refers to the
updated/inserted value of an actual row in "test". Does that clarify?

In your particular usage you'd want to consider concurrency and locking
issues too.

Repost your question on the general/sql lists if you'd like some
discussion. It's probably worth checking the list archives too - plenty
in there about rule/trigger differences.
--
   Richard Huxton
   Archonet Ltd

Re: RULES doesn't work as expected

From
"John Hansen"
Date:
UmlnaHQsIGV4Y2VwdDoNCg0KY3JlYXRlIHRhYmxlIHRlc3QgKGEgdGV4dCwg
YiBpbnQpOyANCmNyZWF0ZSBvciByZXBsYWNlIHJ1bGUgdGVzdF9ydWxlIGFz
IG9uIGluc2VydCB0byB0ZXN0IHdoZXJlIGV4aXN0cyhzZWxlY3QgMSBmcm9t
IHRlc3Qgd2hlcmUgYSA9IE5FVy5hKSBkbyBpbnN0ZWFkIHNlbGVjdCAqIGZy
b20gdGVzdDsgDQoNCmluc2VydCBpbnRvIHRlc3QgKGEsYikgVkFMVUVTICgn
Zmlyc3QnLDIpOw0KICAgYSAgIHwgYg0KLS0tLS0tLSstLS0NCiBmaXJzdCB8
IDINCigxIHJvdykNCg0Kc2VsZWN0ICogZnJvbSB0ZXN0Ow0KICAgYSAgIHwg
Yg0KLS0tLS0tLSstLS0NCiBmaXJzdCB8IDINCigxIHJvdykNCg0KTm93LCB0
aGUgc2VsZWN0IG9uIHRoZSBmaXJzdCBpbnNlcnQgc2hvdWxkIE5PVCBoYXZl
IGhhcHBlbmVkLi4uLi4gU2luY2UgdGhpcyBpcyBhIGRvIGluc3RlYWQgcnVs
ZS4NClRoZSBpbnNlcnQgc2hvdWxkIG9mIGNvdXJzZSBoYXBwZW4sIHNpbmNl
IGl0J3Mgbm90IHByZXNlbnQgaW4gdGhlIHRhYmxlLg0KDQpPciBhbSBJIG1p
c3NpbmcgdGhlIHBvaW50IGNvbXBsZXRlbHk/DQoNCi4uLiBKb2huDQoNCj4g
LS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogUmljaGFyZCBI
dXh0b24gW21haWx0bzpkZXZAYXJjaG9uZXQuY29tXSANCj4gU2VudDogV2Vk
bmVzZGF5LCBKYW51YXJ5IDEyLCAyMDA1IDEwOjIyIFBNDQo+IFRvOiBKb2hu
IEhhbnNlbg0KPiBDYzogcGdzcWwtYnVnc0Bwb3N0Z3Jlc3FsLm9yZw0KPiBT
dWJqZWN0OiBSZTogW0JVR1NdIFJVTEVTIGRvZXNuJ3Qgd29yayBhcyBleHBl
Y3RlZA0KPiANCj4gUmVtb3ZlZCBjYyB0byBwZ3NxbC1wYXRjaGVzIHNpbmNl
IHRoYXQncyBub3QgdGhlIGxpc3QgZm9yIHRoaXMuDQo+IA0KPiBKb2huIEhh
bnNlbiB3cm90ZToNCj4gPiBJdCBzZWVtcyBydWxlcyBkb24ndCB3b3JrIGFz
IGV4cGVjdGVkLg0KPiA+IEkgY291bGQgYmUgd3JvbmcsLi4uIEluIHdoaWNo
IGNhc2UsIHdoYXQgYW0gSSBkb2luZyB3cm9uZz8NCj4gDQo+IEEgcnVsZSBp
cyBsaWtlIGEgbWFjcm8sIHJld3JpdGluZyB0aGUgcXVlcnkgcGxhbi4gWW91
J3JlIA0KPiB0cnlpbmcgdG8gdXNlIGl0IGFzIHRob3VnaCBpdCBpcyBhIHRy
aWdnZXIuIFRoZSBzaWRlLWVmZmVjdHMgDQo+IG9mIHJ1bGVzIGNhbiBiZSBx
dWl0ZSBzdWJ0bGUgYW5kIGNhdGNoZXMgbW9zdCBvZiB1cyBvdXQgYXQgbGVh
c3Qgb25jZS4NCj4gDQo+ID4gQ2xlYXJseSwgdGhlIGZpcnN0IGluc2VydCBi
ZWxvdyBzaG91bGQgbm90IHVwZGF0ZSB0aGUgdGFibGUgYXMgd2VsbC4NCj4g
DQo+ID4gQ1JFQVRFIFRBQkxFIHRlc3QgKGEgdGV4dCwgYiBpbnQ0W10pOw0K
PiA+IA0KPiA+IENSRUFURSBSVUxFIHRlc3RfcnVsZSBBUyANCj4gPiAgIE9O
IElOU0VSVCBUTyB0ZXN0IA0KPiA+ICAgV0hFUkUgZXhpc3RzKFNFTEVDVCAx
IEZST00gdGVzdCBXSEVSRSBhID0gTkVXLmEpDQo+ID4gICBETyBJTlNURUFE
DQo+ID4gICAgIFVQREFURSB0ZXN0IFNFVCBiID0gYiArIE5FVy5iIFdIRVJF
IGEgPSBORVcuYTsNCj4gPiANCj4gPiANCj4gPiBkYjE9IyBJTlNFUlQgSU5U
TyB0ZXN0IChhLGIpIFZBTFVFUyAoMSwnezF9Jzo6aW50NFtdKTsNCj4gDQo+
IFRoZSBORVcuYSBkb2Vzbid0IHJlZmVyIHRvIGEgdmFyaWFibGUgYXMgc3Vj
aCwgaXQgcmVmZXJzIHRvIA0KPiB0aGUgdXBkYXRlZC9pbnNlcnRlZCB2YWx1
ZSBvZiBhbiBhY3R1YWwgcm93IGluICJ0ZXN0Ii4gRG9lcyANCj4gdGhhdCBj
bGFyaWZ5Pw0KPiANCj4gSW4geW91ciBwYXJ0aWN1bGFyIHVzYWdlIHlvdSdk
IHdhbnQgdG8gY29uc2lkZXIgY29uY3VycmVuY3kgDQo+IGFuZCBsb2NraW5n
IGlzc3VlcyB0b28uDQo+IA0KPiBSZXBvc3QgeW91ciBxdWVzdGlvbiBvbiB0
aGUgZ2VuZXJhbC9zcWwgbGlzdHMgaWYgeW91J2QgbGlrZSANCj4gc29tZSBk
aXNjdXNzaW9uLiBJdCdzIHByb2JhYmx5IHdvcnRoIGNoZWNraW5nIHRoZSBs
aXN0IA0KPiBhcmNoaXZlcyB0b28gLSBwbGVudHkgaW4gdGhlcmUgYWJvdXQg
cnVsZS90cmlnZ2VyIGRpZmZlcmVuY2VzLg0KPiAtLQ0KPiAgICBSaWNoYXJk
IEh1eHRvbg0KPiAgICBBcmNob25ldCBMdGQNCj4gDQo+IA0K

Re: RULES doesn't work as expected

From
Richard Huxton
Date:
John Hansen wrote:
> Right, except:
>
> create table test (a text, b int); create or replace rule test_rule
> as on insert to test where exists(select 1 from test where a = NEW.a)
> do instead select * from test;
>
> insert into test (a,b) VALUES ('first',2); a   | b -------+--- first
> | 2 (1 row)
>
> select * from test; a   | b -------+--- first | 2 (1 row)
>
> Now, the select on the first insert should NOT have happened.....
> Since this is a do instead rule. The insert should of course happen,
> since it's not present in the table.
>
> Or am I missing the point completely?

You are, but it's not your fault. You're still thinking of it as a
sequence of instructions, try thinking of it as a single expression that
gets evaluated.

To quote from the (v8.0) docs (ch 32 - The Rule System), for your case:
"Qualification given and INSTEAD
     the query tree from the rule action with the rule qualification and
the original query tree's qualification; and the original query tree
with the negated rule qualification added"

So, in your case you get two branches:
1. INSERT ... WHERE NOT EXISTS (...)
2. SELECT * FROM TEST WHERE EXISTS (...)

Is this making sense?
--
   Richard Huxton
   Archonet Ltd