Thread: RULES doesn't work as expected
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)
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
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
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