1--
2-- RULES
3-- From Jan's original setup_ruletest.sql and run_ruletest.sql
4-- - thomas 1998-09-13
5--
6
7--
8-- Tables and rules for the view test
9--
10create table rtest_t1 (a int4, b int4);
11create table rtest_t2 (a int4, b int4);
12create table rtest_t3 (a int4, b int4);
13
14create view rtest_v1 as select * from rtest_t1;
15create rule rtest_v1_ins as on insert to rtest_v1 do instead
16	insert into rtest_t1 values (new.a, new.b);
17create rule rtest_v1_upd as on update to rtest_v1 do instead
18	update rtest_t1 set a = new.a, b = new.b
19	where a = old.a;
20create rule rtest_v1_del as on delete to rtest_v1 do instead
21	delete from rtest_t1 where a = old.a;
22-- Test comments
23COMMENT ON RULE rtest_v1_bad ON rtest_v1 IS 'bad rule';
24COMMENT ON RULE rtest_v1_del ON rtest_v1 IS 'delete rule';
25COMMENT ON RULE rtest_v1_del ON rtest_v1 IS NULL;
26--
27-- Tables and rules for the constraint update/delete test
28--
29-- Note:
30-- 	Now that we have multiple action rule support, we check
31-- 	both possible syntaxes to define them (The last action
32--  can but must not have a semicolon at the end).
33--
34create table rtest_system (sysname text, sysdesc text);
35create table rtest_interface (sysname text, ifname text);
36create table rtest_person (pname text, pdesc text);
37create table rtest_admin (pname text, sysname text);
38
39create rule rtest_sys_upd as on update to rtest_system do also (
40	update rtest_interface set sysname = new.sysname
41		where sysname = old.sysname;
42	update rtest_admin set sysname = new.sysname
43		where sysname = old.sysname
44	);
45
46create rule rtest_sys_del as on delete to rtest_system do also (
47	delete from rtest_interface where sysname = old.sysname;
48	delete from rtest_admin where sysname = old.sysname;
49	);
50
51create rule rtest_pers_upd as on update to rtest_person do also
52	update rtest_admin set pname = new.pname where pname = old.pname;
53
54create rule rtest_pers_del as on delete to rtest_person do also
55	delete from rtest_admin where pname = old.pname;
56
57--
58-- Tables and rules for the logging test
59--
60create table rtest_emp (ename char(20), salary money);
61create table rtest_emplog (ename char(20), who name, action char(10), newsal money, oldsal money);
62create table rtest_empmass (ename char(20), salary money);
63
64create rule rtest_emp_ins as on insert to rtest_emp do
65	insert into rtest_emplog values (new.ename, current_user,
66			'hired', new.salary, '0.00');
67
68create rule rtest_emp_upd as on update to rtest_emp where new.salary != old.salary do
69	insert into rtest_emplog values (new.ename, current_user,
70			'honored', new.salary, old.salary);
71
72create rule rtest_emp_del as on delete to rtest_emp do
73	insert into rtest_emplog values (old.ename, current_user,
74			'fired', '0.00', old.salary);
75
76--
77-- Tables and rules for the multiple cascaded qualified instead
78-- rule test
79--
80create table rtest_t4 (a int4, b text);
81create table rtest_t5 (a int4, b text);
82create table rtest_t6 (a int4, b text);
83create table rtest_t7 (a int4, b text);
84create table rtest_t8 (a int4, b text);
85create table rtest_t9 (a int4, b text);
86
87create rule rtest_t4_ins1 as on insert to rtest_t4
88		where new.a >= 10 and new.a < 20 do instead
89	insert into rtest_t5 values (new.a, new.b);
90
91create rule rtest_t4_ins2 as on insert to rtest_t4
92		where new.a >= 20 and new.a < 30 do
93	insert into rtest_t6 values (new.a, new.b);
94
95create rule rtest_t5_ins as on insert to rtest_t5
96		where new.a > 15 do
97	insert into rtest_t7 values (new.a, new.b);
98
99create rule rtest_t6_ins as on insert to rtest_t6
100		where new.a > 25 do instead
101	insert into rtest_t8 values (new.a, new.b);
102
103--
104-- Tables and rules for the rule fire order test
105--
106-- As of PG 7.3, the rules should fire in order by name, regardless
107-- of INSTEAD attributes or creation order.
108--
109create table rtest_order1 (a int4);
110create table rtest_order2 (a int4, b int4, c text);
111
112create sequence rtest_seq;
113
114create rule rtest_order_r3 as on insert to rtest_order1 do instead
115	insert into rtest_order2 values (new.a, nextval('rtest_seq'),
116		'rule 3 - this should run 3rd');
117
118create rule rtest_order_r4 as on insert to rtest_order1
119		where a < 100 do instead
120	insert into rtest_order2 values (new.a, nextval('rtest_seq'),
121		'rule 4 - this should run 4th');
122
123create rule rtest_order_r2 as on insert to rtest_order1 do
124	insert into rtest_order2 values (new.a, nextval('rtest_seq'),
125		'rule 2 - this should run 2nd');
126
127create rule rtest_order_r1 as on insert to rtest_order1 do instead
128	insert into rtest_order2 values (new.a, nextval('rtest_seq'),
129		'rule 1 - this should run 1st');
130
131--
132-- Tables and rules for the instead nothing test
133--
134create table rtest_nothn1 (a int4, b text);
135create table rtest_nothn2 (a int4, b text);
136create table rtest_nothn3 (a int4, b text);
137create table rtest_nothn4 (a int4, b text);
138
139create rule rtest_nothn_r1 as on insert to rtest_nothn1
140	where new.a >= 10 and new.a < 20 do instead nothing;
141
142create rule rtest_nothn_r2 as on insert to rtest_nothn1
143	where new.a >= 30 and new.a < 40 do instead nothing;
144
145create rule rtest_nothn_r3 as on insert to rtest_nothn2
146	where new.a >= 100 do instead
147	insert into rtest_nothn3 values (new.a, new.b);
148
149create rule rtest_nothn_r4 as on insert to rtest_nothn2
150	do instead nothing;
151
152--
153-- Tests on a view that is select * of a table
154-- and has insert/update/delete instead rules to
155-- behave close like the real table.
156--
157
158--
159-- We need test date later
160--
161insert into rtest_t2 values (1, 21);
162insert into rtest_t2 values (2, 22);
163insert into rtest_t2 values (3, 23);
164
165insert into rtest_t3 values (1, 31);
166insert into rtest_t3 values (2, 32);
167insert into rtest_t3 values (3, 33);
168insert into rtest_t3 values (4, 34);
169insert into rtest_t3 values (5, 35);
170
171-- insert values
172insert into rtest_v1 values (1, 11);
173insert into rtest_v1 values (2, 12);
174select * from rtest_v1;
175
176-- delete with constant expression
177delete from rtest_v1 where a = 1;
178select * from rtest_v1;
179insert into rtest_v1 values (1, 11);
180delete from rtest_v1 where b = 12;
181select * from rtest_v1;
182insert into rtest_v1 values (2, 12);
183insert into rtest_v1 values (2, 13);
184select * from rtest_v1;
185** Remember the delete rule on rtest_v1: It says
186** DO INSTEAD DELETE FROM rtest_t1 WHERE a = old.a
187** So this time both rows with a = 2 must get deleted
188\p
189\r
190delete from rtest_v1 where b = 12;
191select * from rtest_v1;
192delete from rtest_v1;
193
194-- insert select
195insert into rtest_v1 select * from rtest_t2;
196select * from rtest_v1;
197delete from rtest_v1;
198
199-- same with swapped targetlist
200insert into rtest_v1 (b, a) select b, a from rtest_t2;
201select * from rtest_v1;
202
203-- now with only one target attribute
204insert into rtest_v1 (a) select a from rtest_t3;
205select * from rtest_v1;
206select * from rtest_v1 where b isnull;
207
208-- let attribute a differ (must be done on rtest_t1 - see above)
209update rtest_t1 set a = a + 10 where b isnull;
210delete from rtest_v1 where b isnull;
211select * from rtest_v1;
212
213-- now updates with constant expression
214update rtest_v1 set b = 42 where a = 2;
215select * from rtest_v1;
216update rtest_v1 set b = 99 where b = 42;
217select * from rtest_v1;
218update rtest_v1 set b = 88 where b < 50;
219select * from rtest_v1;
220delete from rtest_v1;
221insert into rtest_v1 select rtest_t2.a, rtest_t3.b
222    from rtest_t2, rtest_t3
223    where rtest_t2.a = rtest_t3.a;
224select * from rtest_v1;
225
226-- updates in a mergejoin
227update rtest_v1 set b = rtest_t2.b from rtest_t2 where rtest_v1.a = rtest_t2.a;
228select * from rtest_v1;
229insert into rtest_v1 select * from rtest_t3;
230select * from rtest_v1;
231update rtest_t1 set a = a + 10 where b > 30;
232select * from rtest_v1;
233update rtest_v1 set a = rtest_t3.a + 20 from rtest_t3 where rtest_v1.b = rtest_t3.b;
234select * from rtest_v1;
235
236--
237-- Test for constraint updates/deletes
238--
239insert into rtest_system values ('orion', 'Linux Jan Wieck');
240insert into rtest_system values ('notjw', 'WinNT Jan Wieck (notebook)');
241insert into rtest_system values ('neptun', 'Fileserver');
242
243insert into rtest_interface values ('orion', 'eth0');
244insert into rtest_interface values ('orion', 'eth1');
245insert into rtest_interface values ('notjw', 'eth0');
246insert into rtest_interface values ('neptun', 'eth0');
247
248insert into rtest_person values ('jw', 'Jan Wieck');
249insert into rtest_person values ('bm', 'Bruce Momjian');
250
251insert into rtest_admin values ('jw', 'orion');
252insert into rtest_admin values ('jw', 'notjw');
253insert into rtest_admin values ('bm', 'neptun');
254
255update rtest_system set sysname = 'pluto' where sysname = 'neptun';
256
257select * from rtest_interface;
258select * from rtest_admin;
259
260update rtest_person set pname = 'jwieck' where pdesc = 'Jan Wieck';
261
262-- Note: use ORDER BY here to ensure consistent output across all systems.
263-- The above UPDATE affects two rows with equal keys, so they could be
264-- updated in either order depending on the whim of the local qsort().
265
266select * from rtest_admin order by pname, sysname;
267
268delete from rtest_system where sysname = 'orion';
269
270select * from rtest_interface;
271select * from rtest_admin;
272
273--
274-- Rule qualification test
275--
276insert into rtest_emp values ('wiecc', '5000.00');
277insert into rtest_emp values ('gates', '80000.00');
278update rtest_emp set ename = 'wiecx' where ename = 'wiecc';
279update rtest_emp set ename = 'wieck', salary = '6000.00' where ename = 'wiecx';
280update rtest_emp set salary = '7000.00' where ename = 'wieck';
281delete from rtest_emp where ename = 'gates';
282
283select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
284insert into rtest_empmass values ('meyer', '4000.00');
285insert into rtest_empmass values ('maier', '5000.00');
286insert into rtest_empmass values ('mayr', '6000.00');
287insert into rtest_emp select * from rtest_empmass;
288select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
289update rtest_empmass set salary = salary + '1000.00';
290update rtest_emp set salary = rtest_empmass.salary from rtest_empmass where rtest_emp.ename = rtest_empmass.ename;
291select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
292delete from rtest_emp using rtest_empmass where rtest_emp.ename = rtest_empmass.ename;
293select ename, who = current_user as "matches user", action, newsal, oldsal from rtest_emplog order by ename, action, newsal;
294
295--
296-- Multiple cascaded qualified instead rule test
297--
298insert into rtest_t4 values (1, 'Record should go to rtest_t4');
299insert into rtest_t4 values (2, 'Record should go to rtest_t4');
300insert into rtest_t4 values (10, 'Record should go to rtest_t5');
301insert into rtest_t4 values (15, 'Record should go to rtest_t5');
302insert into rtest_t4 values (19, 'Record should go to rtest_t5 and t7');
303insert into rtest_t4 values (20, 'Record should go to rtest_t4 and t6');
304insert into rtest_t4 values (26, 'Record should go to rtest_t4 and t8');
305insert into rtest_t4 values (28, 'Record should go to rtest_t4 and t8');
306insert into rtest_t4 values (30, 'Record should go to rtest_t4');
307insert into rtest_t4 values (40, 'Record should go to rtest_t4');
308
309select * from rtest_t4;
310select * from rtest_t5;
311select * from rtest_t6;
312select * from rtest_t7;
313select * from rtest_t8;
314
315delete from rtest_t4;
316delete from rtest_t5;
317delete from rtest_t6;
318delete from rtest_t7;
319delete from rtest_t8;
320
321insert into rtest_t9 values (1, 'Record should go to rtest_t4');
322insert into rtest_t9 values (2, 'Record should go to rtest_t4');
323insert into rtest_t9 values (10, 'Record should go to rtest_t5');
324insert into rtest_t9 values (15, 'Record should go to rtest_t5');
325insert into rtest_t9 values (19, 'Record should go to rtest_t5 and t7');
326insert into rtest_t9 values (20, 'Record should go to rtest_t4 and t6');
327insert into rtest_t9 values (26, 'Record should go to rtest_t4 and t8');
328insert into rtest_t9 values (28, 'Record should go to rtest_t4 and t8');
329insert into rtest_t9 values (30, 'Record should go to rtest_t4');
330insert into rtest_t9 values (40, 'Record should go to rtest_t4');
331
332insert into rtest_t4 select * from rtest_t9 where a < 20;
333
334select * from rtest_t4;
335select * from rtest_t5;
336select * from rtest_t6;
337select * from rtest_t7;
338select * from rtest_t8;
339
340insert into rtest_t4 select * from rtest_t9 where b ~ 'and t8';
341
342select * from rtest_t4;
343select * from rtest_t5;
344select * from rtest_t6;
345select * from rtest_t7;
346select * from rtest_t8;
347
348insert into rtest_t4 select a + 1, b from rtest_t9 where a in (20, 30, 40);
349
350select * from rtest_t4;
351select * from rtest_t5;
352select * from rtest_t6;
353select * from rtest_t7;
354select * from rtest_t8;
355
356--
357-- Check that the ordering of rules fired is correct
358--
359insert into rtest_order1 values (1);
360select * from rtest_order2;
361
362--
363-- Check if instead nothing w/without qualification works
364--
365insert into rtest_nothn1 values (1, 'want this');
366insert into rtest_nothn1 values (2, 'want this');
367insert into rtest_nothn1 values (10, 'don''t want this');
368insert into rtest_nothn1 values (19, 'don''t want this');
369insert into rtest_nothn1 values (20, 'want this');
370insert into rtest_nothn1 values (29, 'want this');
371insert into rtest_nothn1 values (30, 'don''t want this');
372insert into rtest_nothn1 values (39, 'don''t want this');
373insert into rtest_nothn1 values (40, 'want this');
374insert into rtest_nothn1 values (50, 'want this');
375insert into rtest_nothn1 values (60, 'want this');
376
377select * from rtest_nothn1;
378
379insert into rtest_nothn2 values (10, 'too small');
380insert into rtest_nothn2 values (50, 'too small');
381insert into rtest_nothn2 values (100, 'OK');
382insert into rtest_nothn2 values (200, 'OK');
383
384select * from rtest_nothn2;
385select * from rtest_nothn3;
386
387delete from rtest_nothn1;
388delete from rtest_nothn2;
389delete from rtest_nothn3;
390
391insert into rtest_nothn4 values (1, 'want this');
392insert into rtest_nothn4 values (2, 'want this');
393insert into rtest_nothn4 values (10, 'don''t want this');
394insert into rtest_nothn4 values (19, 'don''t want this');
395insert into rtest_nothn4 values (20, 'want this');
396insert into rtest_nothn4 values (29, 'want this');
397insert into rtest_nothn4 values (30, 'don''t want this');
398insert into rtest_nothn4 values (39, 'don''t want this');
399insert into rtest_nothn4 values (40, 'want this');
400insert into rtest_nothn4 values (50, 'want this');
401insert into rtest_nothn4 values (60, 'want this');
402
403insert into rtest_nothn1 select * from rtest_nothn4;
404
405select * from rtest_nothn1;
406
407delete from rtest_nothn4;
408
409insert into rtest_nothn4 values (10, 'too small');
410insert into rtest_nothn4 values (50, 'too small');
411insert into rtest_nothn4 values (100, 'OK');
412insert into rtest_nothn4 values (200, 'OK');
413
414insert into rtest_nothn2 select * from rtest_nothn4;
415
416select * from rtest_nothn2;
417select * from rtest_nothn3;
418
419create table rtest_view1 (a int4, b text, v bool);
420create table rtest_view2 (a int4);
421create table rtest_view3 (a int4, b text);
422create table rtest_view4 (a int4, b text, c int4);
423create view rtest_vview1 as select a, b from rtest_view1 X
424	where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
425create view rtest_vview2 as select a, b from rtest_view1 where v;
426create view rtest_vview3 as select a, b from rtest_vview2 X
427	where 0 < (select count(*) from rtest_view2 Y where Y.a = X.a);
428create view rtest_vview4 as select X.a, X.b, count(Y.a) as refcount
429	from rtest_view1 X, rtest_view2 Y
430	where X.a = Y.a
431	group by X.a, X.b;
432create function rtest_viewfunc1(int4) returns int4 as
433	'select count(*)::int4 from rtest_view2 where a = $1'
434	language sql;
435create view rtest_vview5 as select a, b, rtest_viewfunc1(a) as refcount
436	from rtest_view1;
437
438insert into rtest_view1 values (1, 'item 1', 't');
439insert into rtest_view1 values (2, 'item 2', 't');
440insert into rtest_view1 values (3, 'item 3', 't');
441insert into rtest_view1 values (4, 'item 4', 'f');
442insert into rtest_view1 values (5, 'item 5', 't');
443insert into rtest_view1 values (6, 'item 6', 'f');
444insert into rtest_view1 values (7, 'item 7', 't');
445insert into rtest_view1 values (8, 'item 8', 't');
446
447insert into rtest_view2 values (2);
448insert into rtest_view2 values (2);
449insert into rtest_view2 values (4);
450insert into rtest_view2 values (5);
451insert into rtest_view2 values (7);
452insert into rtest_view2 values (7);
453insert into rtest_view2 values (7);
454insert into rtest_view2 values (7);
455
456select * from rtest_vview1;
457select * from rtest_vview2;
458select * from rtest_vview3;
459select * from rtest_vview4 order by a, b;
460select * from rtest_vview5;
461
462insert into rtest_view3 select * from rtest_vview1 where a < 7;
463select * from rtest_view3;
464delete from rtest_view3;
465
466insert into rtest_view3 select * from rtest_vview2 where a != 5 and b !~ '2';
467select * from rtest_view3;
468delete from rtest_view3;
469
470insert into rtest_view3 select * from rtest_vview3;
471select * from rtest_view3;
472delete from rtest_view3;
473
474insert into rtest_view4 select * from rtest_vview4 where 3 > refcount;
475select * from rtest_view4 order by a, b;
476delete from rtest_view4;
477
478insert into rtest_view4 select * from rtest_vview5 where a > 2 and refcount = 0;
479select * from rtest_view4;
480delete from rtest_view4;
481--
482-- Test for computations in views
483--
484create table rtest_comp (
485	part	text,
486	unit	char(4),
487	size	float
488);
489
490
491create table rtest_unitfact (
492	unit	char(4),
493	factor	float
494);
495
496create view rtest_vcomp as
497	select X.part, (X.size * Y.factor) as size_in_cm
498			from rtest_comp X, rtest_unitfact Y
499			where X.unit = Y.unit;
500
501
502insert into rtest_unitfact values ('m', 100.0);
503insert into rtest_unitfact values ('cm', 1.0);
504insert into rtest_unitfact values ('inch', 2.54);
505
506insert into rtest_comp values ('p1', 'm', 5.0);
507insert into rtest_comp values ('p2', 'm', 3.0);
508insert into rtest_comp values ('p3', 'cm', 5.0);
509insert into rtest_comp values ('p4', 'cm', 15.0);
510insert into rtest_comp values ('p5', 'inch', 7.0);
511insert into rtest_comp values ('p6', 'inch', 4.4);
512
513select * from rtest_vcomp order by part;
514
515select * from rtest_vcomp where size_in_cm > 10.0 order by size_in_cm using >;
516
517--
518-- In addition run the (slightly modified) queries from the
519-- programmers manual section on the rule system.
520--
521CREATE TABLE shoe_data (
522	shoename   char(10),      -- primary key
523	sh_avail   integer,       -- available # of pairs
524	slcolor    char(10),      -- preferred shoelace color
525	slminlen   float,         -- minimum shoelace length
526	slmaxlen   float,         -- maximum shoelace length
527	slunit     char(8)        -- length unit
528);
529
530CREATE TABLE shoelace_data (
531	sl_name    char(10),      -- primary key
532	sl_avail   integer,       -- available # of pairs
533	sl_color   char(10),      -- shoelace color
534	sl_len     float,         -- shoelace length
535	sl_unit    char(8)        -- length unit
536);
537
538CREATE TABLE unit (
539	un_name    char(8),       -- the primary key
540	un_fact    float          -- factor to transform to cm
541);
542
543CREATE VIEW shoe AS
544	SELECT sh.shoename,
545		   sh.sh_avail,
546		   sh.slcolor,
547		   sh.slminlen,
548		   sh.slminlen * un.un_fact AS slminlen_cm,
549		   sh.slmaxlen,
550		   sh.slmaxlen * un.un_fact AS slmaxlen_cm,
551		   sh.slunit
552	  FROM shoe_data sh, unit un
553	 WHERE sh.slunit = un.un_name;
554
555CREATE VIEW shoelace AS
556	SELECT s.sl_name,
557		   s.sl_avail,
558		   s.sl_color,
559		   s.sl_len,
560		   s.sl_unit,
561		   s.sl_len * u.un_fact AS sl_len_cm
562	  FROM shoelace_data s, unit u
563	 WHERE s.sl_unit = u.un_name;
564
565CREATE VIEW shoe_ready AS
566	SELECT rsh.shoename,
567		   rsh.sh_avail,
568		   rsl.sl_name,
569		   rsl.sl_avail,
570		   int4smaller(rsh.sh_avail, rsl.sl_avail) AS total_avail
571	  FROM shoe rsh, shoelace rsl
572	 WHERE rsl.sl_color = rsh.slcolor
573	   AND rsl.sl_len_cm >= rsh.slminlen_cm
574	   AND rsl.sl_len_cm <= rsh.slmaxlen_cm;
575
576INSERT INTO unit VALUES ('cm', 1.0);
577INSERT INTO unit VALUES ('m', 100.0);
578INSERT INTO unit VALUES ('inch', 2.54);
579
580INSERT INTO shoe_data VALUES ('sh1', 2, 'black', 70.0, 90.0, 'cm');
581INSERT INTO shoe_data VALUES ('sh2', 0, 'black', 30.0, 40.0, 'inch');
582INSERT INTO shoe_data VALUES ('sh3', 4, 'brown', 50.0, 65.0, 'cm');
583INSERT INTO shoe_data VALUES ('sh4', 3, 'brown', 40.0, 50.0, 'inch');
584
585INSERT INTO shoelace_data VALUES ('sl1', 5, 'black', 80.0, 'cm');
586INSERT INTO shoelace_data VALUES ('sl2', 6, 'black', 100.0, 'cm');
587INSERT INTO shoelace_data VALUES ('sl3', 0, 'black', 35.0 , 'inch');
588INSERT INTO shoelace_data VALUES ('sl4', 8, 'black', 40.0 , 'inch');
589INSERT INTO shoelace_data VALUES ('sl5', 4, 'brown', 1.0 , 'm');
590INSERT INTO shoelace_data VALUES ('sl6', 0, 'brown', 0.9 , 'm');
591INSERT INTO shoelace_data VALUES ('sl7', 7, 'brown', 60 , 'cm');
592INSERT INTO shoelace_data VALUES ('sl8', 1, 'brown', 40 , 'inch');
593
594-- SELECTs in doc
595SELECT * FROM shoelace ORDER BY sl_name;
596SELECT * FROM shoe_ready WHERE total_avail >= 2 ORDER BY 1;
597
598    CREATE TABLE shoelace_log (
599        sl_name    char(10),      -- shoelace changed
600        sl_avail   integer,       -- new available value
601        log_who    name,          -- who did it
602        log_when   timestamp      -- when
603    );
604
605-- Want "log_who" to be CURRENT_USER,
606-- but that is non-portable for the regression test
607-- - thomas 1999-02-21
608
609    CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data
610        WHERE NEW.sl_avail != OLD.sl_avail
611        DO INSERT INTO shoelace_log VALUES (
612                                        NEW.sl_name,
613                                        NEW.sl_avail,
614                                        'Al Bundy',
615                                        'epoch'
616                                    );
617
618UPDATE shoelace_data SET sl_avail = 6 WHERE  sl_name = 'sl7';
619
620SELECT * FROM shoelace_log;
621
622    CREATE RULE shoelace_ins AS ON INSERT TO shoelace
623        DO INSTEAD
624        INSERT INTO shoelace_data VALUES (
625               NEW.sl_name,
626               NEW.sl_avail,
627               NEW.sl_color,
628               NEW.sl_len,
629               NEW.sl_unit);
630
631    CREATE RULE shoelace_upd AS ON UPDATE TO shoelace
632        DO INSTEAD
633        UPDATE shoelace_data SET
634               sl_name = NEW.sl_name,
635               sl_avail = NEW.sl_avail,
636               sl_color = NEW.sl_color,
637               sl_len = NEW.sl_len,
638               sl_unit = NEW.sl_unit
639         WHERE sl_name = OLD.sl_name;
640
641    CREATE RULE shoelace_del AS ON DELETE TO shoelace
642        DO INSTEAD
643        DELETE FROM shoelace_data
644         WHERE sl_name = OLD.sl_name;
645
646    CREATE TABLE shoelace_arrive (
647        arr_name    char(10),
648        arr_quant   integer
649    );
650
651    CREATE TABLE shoelace_ok (
652        ok_name     char(10),
653        ok_quant    integer
654    );
655
656    CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok
657        DO INSTEAD
658        UPDATE shoelace SET
659               sl_avail = sl_avail + NEW.ok_quant
660         WHERE sl_name = NEW.ok_name;
661
662INSERT INTO shoelace_arrive VALUES ('sl3', 10);
663INSERT INTO shoelace_arrive VALUES ('sl6', 20);
664INSERT INTO shoelace_arrive VALUES ('sl8', 20);
665
666SELECT * FROM shoelace ORDER BY sl_name;
667
668insert into shoelace_ok select * from shoelace_arrive;
669
670SELECT * FROM shoelace ORDER BY sl_name;
671
672SELECT * FROM shoelace_log ORDER BY sl_name;
673
674    CREATE VIEW shoelace_obsolete AS
675	SELECT * FROM shoelace WHERE NOT EXISTS
676	    (SELECT shoename FROM shoe WHERE slcolor = sl_color);
677
678    CREATE VIEW shoelace_candelete AS
679	SELECT * FROM shoelace_obsolete WHERE sl_avail = 0;
680
681insert into shoelace values ('sl9', 0, 'pink', 35.0, 'inch', 0.0);
682insert into shoelace values ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0);
683-- Unsupported (even though a similar updatable view construct is)
684insert into shoelace values ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0)
685  on conflict do nothing;
686
687SELECT * FROM shoelace_obsolete ORDER BY sl_len_cm;
688SELECT * FROM shoelace_candelete;
689
690DELETE FROM shoelace WHERE EXISTS
691    (SELECT * FROM shoelace_candelete
692             WHERE sl_name = shoelace.sl_name);
693
694SELECT * FROM shoelace ORDER BY sl_name;
695
696SELECT * FROM shoe ORDER BY shoename;
697SELECT count(*) FROM shoe;
698
699
700--
701-- Simple test of qualified ON INSERT ... this did not work in 7.0 ...
702--
703create table foo (f1 int);
704create table foo2 (f1 int);
705
706create rule foorule as on insert to foo where f1 < 100
707do instead nothing;
708
709insert into foo values(1);
710insert into foo values(1001);
711select * from foo;
712
713drop rule foorule on foo;
714
715-- this should fail because f1 is not exposed for unqualified reference:
716create rule foorule as on insert to foo where f1 < 100
717do instead insert into foo2 values (f1);
718-- this is the correct way:
719create rule foorule as on insert to foo where f1 < 100
720do instead insert into foo2 values (new.f1);
721
722insert into foo values(2);
723insert into foo values(100);
724
725select * from foo;
726select * from foo2;
727
728drop rule foorule on foo;
729drop table foo;
730drop table foo2;
731
732
733--
734-- Test rules containing INSERT ... SELECT, which is a very ugly special
735-- case as of 7.1.  Example is based on bug report from Joel Burton.
736--
737create table pparent (pid int, txt text);
738insert into pparent values (1,'parent1');
739insert into pparent values (2,'parent2');
740
741create table cchild (pid int, descrip text);
742insert into cchild values (1,'descrip1');
743
744create view vview as
745  select pparent.pid, txt, descrip from
746    pparent left join cchild using (pid);
747
748create rule rrule as
749  on update to vview do instead
750(
751  insert into cchild (pid, descrip)
752    select old.pid, new.descrip where old.descrip isnull;
753  update cchild set descrip = new.descrip where cchild.pid = old.pid;
754);
755
756select * from vview;
757update vview set descrip='test1' where pid=1;
758select * from vview;
759update vview set descrip='test2' where pid=2;
760select * from vview;
761update vview set descrip='test3' where pid=3;
762select * from vview;
763select * from cchild;
764
765drop rule rrule on vview;
766drop view vview;
767drop table pparent;
768drop table cchild;
769
770
771--
772-- Check that ruleutils are working
773--
774
775-- temporarily disable fancy output, so view changes create less diff noise
776\a\t
777
778SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
779
780SELECT tablename, rulename, definition FROM pg_rules
781	ORDER BY tablename, rulename;
782
783-- restore normal output mode
784\a\t
785
786--
787-- CREATE OR REPLACE RULE
788--
789
790CREATE TABLE ruletest_tbl (a int, b int);
791CREATE TABLE ruletest_tbl2 (a int, b int);
792
793CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
794	DO INSTEAD INSERT INTO ruletest_tbl2 VALUES (10, 10);
795
796INSERT INTO ruletest_tbl VALUES (99, 99);
797
798CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
799	DO INSTEAD INSERT INTO ruletest_tbl2 VALUES (1000, 1000);
800
801INSERT INTO ruletest_tbl VALUES (99, 99);
802
803SELECT * FROM ruletest_tbl2;
804
805-- Check that rewrite rules splitting one INSERT into multiple
806-- conditional statements does not disable FK checking.
807create table rule_and_refint_t1 (
808	id1a integer,
809	id1b integer,
810
811	primary key (id1a, id1b)
812);
813
814create table rule_and_refint_t2 (
815	id2a integer,
816	id2c integer,
817
818	primary key (id2a, id2c)
819);
820
821create table rule_and_refint_t3 (
822	id3a integer,
823	id3b integer,
824	id3c integer,
825	data text,
826
827	primary key (id3a, id3b, id3c),
828
829	foreign key (id3a, id3b) references rule_and_refint_t1 (id1a, id1b),
830	foreign key (id3a, id3c) references rule_and_refint_t2 (id2a, id2c)
831);
832
833
834insert into rule_and_refint_t1 values (1, 11);
835insert into rule_and_refint_t1 values (1, 12);
836insert into rule_and_refint_t1 values (2, 21);
837insert into rule_and_refint_t1 values (2, 22);
838
839insert into rule_and_refint_t2 values (1, 11);
840insert into rule_and_refint_t2 values (1, 12);
841insert into rule_and_refint_t2 values (2, 21);
842insert into rule_and_refint_t2 values (2, 22);
843
844insert into rule_and_refint_t3 values (1, 11, 11, 'row1');
845insert into rule_and_refint_t3 values (1, 11, 12, 'row2');
846insert into rule_and_refint_t3 values (1, 12, 11, 'row3');
847insert into rule_and_refint_t3 values (1, 12, 12, 'row4');
848insert into rule_and_refint_t3 values (1, 11, 13, 'row5');
849insert into rule_and_refint_t3 values (1, 13, 11, 'row6');
850-- Ordinary table
851insert into rule_and_refint_t3 values (1, 13, 11, 'row6')
852  on conflict do nothing;
853-- rule not fired, so fk violation
854insert into rule_and_refint_t3 values (1, 13, 11, 'row6')
855  on conflict (id3a, id3b, id3c) do update
856  set id3b = excluded.id3b;
857-- rule fired, so unsupported
858insert into shoelace values ('sl9', 0, 'pink', 35.0, 'inch', 0.0)
859  on conflict (sl_name) do update
860  set sl_avail = excluded.sl_avail;
861
862create rule rule_and_refint_t3_ins as on insert to rule_and_refint_t3
863	where (exists (select 1 from rule_and_refint_t3
864			where (((rule_and_refint_t3.id3a = new.id3a)
865			and (rule_and_refint_t3.id3b = new.id3b))
866			and (rule_and_refint_t3.id3c = new.id3c))))
867	do instead update rule_and_refint_t3 set data = new.data
868	where (((rule_and_refint_t3.id3a = new.id3a)
869	and (rule_and_refint_t3.id3b = new.id3b))
870	and (rule_and_refint_t3.id3c = new.id3c));
871
872insert into rule_and_refint_t3 values (1, 11, 13, 'row7');
873insert into rule_and_refint_t3 values (1, 13, 11, 'row8');
874
875--
876-- disallow dropping a view's rule (bug #5072)
877--
878
879create view fooview as select 'foo'::text;
880drop rule "_RETURN" on fooview;
881drop view fooview;
882
883--
884-- test conversion of table to view (needed to load some pg_dump files)
885--
886
887create table fooview (x int, y text);
888select xmin, * from fooview;
889
890create rule "_RETURN" as on select to fooview do instead
891  select 1 as x, 'aaa'::text as y;
892
893select * from fooview;
894select xmin, * from fooview;  -- fail, views don't have such a column
895
896select reltoastrelid, relkind, relfrozenxid
897  from pg_class where oid = 'fooview'::regclass;
898
899drop view fooview;
900
901-- cannot convert an inheritance parent or child to a view, though
902create table fooview (x int, y text);
903create table fooview_child () inherits (fooview);
904
905create rule "_RETURN" as on select to fooview do instead
906  select 1 as x, 'aaa'::text as y;
907create rule "_RETURN" as on select to fooview_child do instead
908  select 1 as x, 'aaa'::text as y;
909
910drop table fooview cascade;
911
912--
913-- check for planner problems with complex inherited UPDATES
914--
915
916create table id (id serial primary key, name text);
917-- currently, must respecify PKEY for each inherited subtable
918create table test_1 (id integer primary key) inherits (id);
919create table test_2 (id integer primary key) inherits (id);
920create table test_3 (id integer primary key) inherits (id);
921
922insert into test_1 (name) values ('Test 1');
923insert into test_1 (name) values ('Test 2');
924insert into test_2 (name) values ('Test 3');
925insert into test_2 (name) values ('Test 4');
926insert into test_3 (name) values ('Test 5');
927insert into test_3 (name) values ('Test 6');
928
929create view id_ordered as select * from id order by id;
930
931create rule update_id_ordered as on update to id_ordered
932	do instead update id set name = new.name where id = old.id;
933
934select * from id_ordered;
935update id_ordered set name = 'update 2' where id = 2;
936update id_ordered set name = 'update 4' where id = 4;
937update id_ordered set name = 'update 5' where id = 5;
938select * from id_ordered;
939
940set client_min_messages to warning; -- suppress cascade notices
941drop table id cascade;
942reset client_min_messages;
943
944--
945-- check corner case where an entirely-dummy subplan is created by
946-- constraint exclusion
947--
948
949create temp table t1 (a integer primary key);
950
951create temp table t1_1 (check (a >= 0 and a < 10)) inherits (t1);
952create temp table t1_2 (check (a >= 10 and a < 20)) inherits (t1);
953
954create rule t1_ins_1 as on insert to t1
955	where new.a >= 0 and new.a < 10
956	do instead
957	insert into t1_1 values (new.a);
958create rule t1_ins_2 as on insert to t1
959	where new.a >= 10 and new.a < 20
960	do instead
961	insert into t1_2 values (new.a);
962
963create rule t1_upd_1 as on update to t1
964	where old.a >= 0 and old.a < 10
965	do instead
966	update t1_1 set a = new.a where a = old.a;
967create rule t1_upd_2 as on update to t1
968	where old.a >= 10 and old.a < 20
969	do instead
970	update t1_2 set a = new.a where a = old.a;
971
972set constraint_exclusion = on;
973
974insert into t1 select * from generate_series(5,19,1) g;
975update t1 set a = 4 where a = 5;
976
977select * from only t1;
978select * from only t1_1;
979select * from only t1_2;
980
981reset constraint_exclusion;
982
983-- test FOR UPDATE in rules
984
985create table rules_base(f1 int, f2 int);
986insert into rules_base values(1,2), (11,12);
987create rule r1 as on update to rules_base do instead
988  select * from rules_base where f1 = 1 for update;
989update rules_base set f2 = f2 + 1;
990create or replace rule r1 as on update to rules_base do instead
991  select * from rules_base where f1 = 11 for update of rules_base;
992update rules_base set f2 = f2 + 1;
993create or replace rule r1 as on update to rules_base do instead
994  select * from rules_base where f1 = 11 for update of old; -- error
995drop table rules_base;
996
997-- test various flavors of pg_get_viewdef()
998
999select pg_get_viewdef('shoe'::regclass) as unpretty;
1000select pg_get_viewdef('shoe'::regclass,true) as pretty;
1001select pg_get_viewdef('shoe'::regclass,0) as prettier;
1002
1003--
1004-- check multi-row VALUES in rules
1005--
1006
1007create table rules_src(f1 int, f2 int);
1008create table rules_log(f1 int, f2 int, tag text);
1009insert into rules_src values(1,2), (11,12);
1010create rule r1 as on update to rules_src do also
1011  insert into rules_log values(old.*, 'old'), (new.*, 'new');
1012update rules_src set f2 = f2 + 1;
1013update rules_src set f2 = f2 * 10;
1014select * from rules_src;
1015select * from rules_log;
1016create rule r2 as on update to rules_src do also
1017  values(old.*, 'old'), (new.*, 'new');
1018update rules_src set f2 = f2 / 10;
1019select * from rules_src;
1020select * from rules_log;
1021create rule r3 as on delete to rules_src do notify rules_src_deletion;
1022\d+ rules_src
1023
1024--
1025-- Ensure an aliased target relation for insert is correctly deparsed.
1026--
1027create rule r4 as on insert to rules_src do instead insert into rules_log AS trgt SELECT NEW.* RETURNING trgt.f1, trgt.f2;
1028create rule r5 as on update to rules_src do instead UPDATE rules_log AS trgt SET tag = 'updated' WHERE trgt.f1 = new.f1;
1029\d+ rules_src
1030
1031--
1032-- check alter rename rule
1033--
1034CREATE TABLE rule_t1 (a INT);
1035CREATE VIEW rule_v1 AS SELECT * FROM rule_t1;
1036
1037CREATE RULE InsertRule AS
1038    ON INSERT TO rule_v1
1039    DO INSTEAD
1040        INSERT INTO rule_t1 VALUES(new.a);
1041
1042ALTER RULE InsertRule ON rule_v1 RENAME to NewInsertRule;
1043
1044INSERT INTO rule_v1 VALUES(1);
1045SELECT * FROM rule_v1;
1046
1047\d+ rule_v1
1048
1049--
1050-- error conditions for alter rename rule
1051--
1052ALTER RULE InsertRule ON rule_v1 RENAME TO NewInsertRule; -- doesn't exist
1053ALTER RULE NewInsertRule ON rule_v1 RENAME TO "_RETURN"; -- already exists
1054ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc; -- ON SELECT rule cannot be renamed
1055
1056DROP VIEW rule_v1;
1057DROP TABLE rule_t1;
1058
1059--
1060-- check display of VALUES in view definitions
1061--
1062create view rule_v1 as values(1,2);
1063\d+ rule_v1
1064alter table rule_v1 rename column column2 to q2;
1065\d+ rule_v1
1066drop view rule_v1;
1067create view rule_v1(x) as values(1,2);
1068\d+ rule_v1
1069drop view rule_v1;
1070create view rule_v1(x) as select * from (values(1,2)) v;
1071\d+ rule_v1
1072drop view rule_v1;
1073create view rule_v1(x) as select * from (values(1,2)) v(q,w);
1074\d+ rule_v1
1075drop view rule_v1;
1076
1077--
1078-- Check DO INSTEAD rules with ON CONFLICT
1079--
1080CREATE TABLE hats (
1081	hat_name    char(10) primary key,
1082	hat_color   char(10)      -- hat color
1083);
1084
1085CREATE TABLE hat_data (
1086	hat_name    char(10),
1087	hat_color   char(10)      -- hat color
1088);
1089create unique index hat_data_unique_idx
1090  on hat_data (hat_name COLLATE "C" bpchar_pattern_ops);
1091
1092-- DO NOTHING with ON CONFLICT
1093CREATE RULE hat_nosert AS ON INSERT TO hats
1094    DO INSTEAD
1095    INSERT INTO hat_data VALUES (
1096           NEW.hat_name,
1097           NEW.hat_color)
1098        ON CONFLICT (hat_name COLLATE "C" bpchar_pattern_ops) WHERE hat_color = 'green'
1099        DO NOTHING
1100        RETURNING *;
1101SELECT definition FROM pg_rules WHERE tablename = 'hats' ORDER BY rulename;
1102
1103-- Works (projects row)
1104INSERT INTO hats VALUES ('h7', 'black') RETURNING *;
1105-- Works (does nothing)
1106INSERT INTO hats VALUES ('h7', 'black') RETURNING *;
1107SELECT tablename, rulename, definition FROM pg_rules
1108	WHERE tablename = 'hats';
1109DROP RULE hat_nosert ON hats;
1110
1111-- DO NOTHING without ON CONFLICT
1112CREATE RULE hat_nosert_all AS ON INSERT TO hats
1113    DO INSTEAD
1114    INSERT INTO hat_data VALUES (
1115           NEW.hat_name,
1116           NEW.hat_color)
1117        ON CONFLICT
1118        DO NOTHING
1119        RETURNING *;
1120SELECT definition FROM pg_rules WHERE tablename = 'hats' ORDER BY rulename;
1121DROP RULE hat_nosert_all ON hats;
1122
1123-- Works (does nothing)
1124INSERT INTO hats VALUES ('h7', 'black') RETURNING *;
1125
1126-- DO UPDATE with a WHERE clause
1127CREATE RULE hat_upsert AS ON INSERT TO hats
1128    DO INSTEAD
1129    INSERT INTO hat_data VALUES (
1130           NEW.hat_name,
1131           NEW.hat_color)
1132        ON CONFLICT (hat_name)
1133        DO UPDATE
1134           SET hat_name = hat_data.hat_name, hat_color = excluded.hat_color
1135           WHERE excluded.hat_color <>  'forbidden' AND hat_data.* != excluded.*
1136        RETURNING *;
1137SELECT definition FROM pg_rules WHERE tablename = 'hats' ORDER BY rulename;
1138
1139-- Works (does upsert)
1140INSERT INTO hats VALUES ('h8', 'black') RETURNING *;
1141SELECT * FROM hat_data WHERE hat_name = 'h8';
1142INSERT INTO hats VALUES ('h8', 'white') RETURNING *;
1143SELECT * FROM hat_data WHERE hat_name = 'h8';
1144INSERT INTO hats VALUES ('h8', 'forbidden') RETURNING *;
1145SELECT * FROM hat_data WHERE hat_name = 'h8';
1146SELECT tablename, rulename, definition FROM pg_rules
1147	WHERE tablename = 'hats';
1148-- ensure explain works for on insert conflict rules
1149explain (costs off) INSERT INTO hats VALUES ('h8', 'forbidden') RETURNING *;
1150
1151-- ensure upserting into a rule, with a CTE (different offsets!) works
1152WITH data(hat_name, hat_color) AS (
1153    VALUES ('h8', 'green'),
1154        ('h9', 'blue'),
1155        ('h7', 'forbidden')
1156)
1157INSERT INTO hats
1158    SELECT * FROM data
1159RETURNING *;
1160EXPLAIN (costs off) WITH data(hat_name, hat_color) AS (
1161    VALUES ('h8', 'green'),
1162        ('h9', 'blue'),
1163        ('h7', 'forbidden')
1164)
1165INSERT INTO hats
1166    SELECT * FROM data
1167RETURNING *;
1168SELECT * FROM hat_data WHERE hat_name IN ('h8', 'h9', 'h7') ORDER BY hat_name;
1169
1170DROP RULE hat_upsert ON hats;
1171
1172drop table hats;
1173drop table hat_data;
1174
1175-- test for pg_get_functiondef properly regurgitating SET parameters
1176-- Note that the function is kept around to stress pg_dump.
1177CREATE FUNCTION func_with_set_params() RETURNS integer
1178    AS 'select 1;'
1179    LANGUAGE SQL
1180    SET search_path TO PG_CATALOG
1181    SET extra_float_digits TO 2
1182    SET work_mem TO '4MB'
1183    SET datestyle to iso, mdy
1184    SET local_preload_libraries TO "Mixed/Case", 'c:/''a"/path', '', '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789'
1185    IMMUTABLE STRICT;
1186SELECT pg_get_functiondef('func_with_set_params()'::regprocedure);
1187
1188-- tests for pg_get_*def with invalid objects
1189SELECT pg_get_constraintdef(0);
1190SELECT pg_get_functiondef(0);
1191SELECT pg_get_indexdef(0);
1192SELECT pg_get_ruledef(0);
1193SELECT pg_get_triggerdef(0);
1194SELECT pg_get_viewdef(0);
1195SELECT pg_get_function_arguments(0);
1196SELECT pg_get_function_identity_arguments(0);
1197SELECT pg_get_function_result(0);
1198SELECT pg_get_function_arg_default(0, 0);
1199SELECT pg_get_function_arg_default('pg_class'::regclass, 0);
1200