1--
2-- RULES
3-- From Jan's original setup_ruletest.sql and run_ruletest.sql
4-- - thomas 1998-09-13
5--
6--
7-- Tables and rules for the view test
8--
9CREATE TABLE rtest_t1 (
10    a int4,
11    b int4
12);
13
14CREATE TABLE rtest_t2 (
15    a int4,
16    b int4
17);
18
19CREATE TABLE rtest_t3 (
20    a int4,
21    b int4
22);
23
24CREATE VIEW rtest_v1 AS
25SELECT
26    *
27FROM
28    rtest_t1;
29
30CREATE RULE rtest_v1_ins AS ON INSERT TO rtest_v1
31    DO INSTEAD
32    INSERT INTO rtest_t1 VALUES (NEW.a, NEW.b);
33
34CREATE RULE rtest_v1_upd AS ON UPDATE
35    TO rtest_v1
36        DO INSTEAD
37        UPDATE
38            rtest_t1 SET
39            a = NEW.a,
40            b = NEW.b WHERE
41            a = OLD.a;
42
43CREATE RULE rtest_v1_del AS ON DELETE TO rtest_v1
44    DO INSTEAD
45    DELETE FROM rtest_t1
46    WHERE a = OLD.a;
47
48-- Test comments
49COMMENT ON RULE rtest_v1_bad ON rtest_v1 IS 'bad rule';
50
51COMMENT ON RULE rtest_v1_del ON rtest_v1 IS 'delete rule';
52
53COMMENT ON RULE rtest_v1_del ON rtest_v1 IS NULL;
54
55--
56-- Tables and rules for the constraint update/delete test
57--
58-- Note:
59-- 	Now that we have multiple action rule support, we check
60-- 	both possible syntaxes to define them (The last action
61--  can but must not have a semicolon at the end).
62--
63CREATE TABLE rtest_system (
64    sysname text,
65    sysdesc text
66);
67
68CREATE TABLE rtest_interface (
69    sysname text,
70    ifname text
71);
72
73CREATE TABLE rtest_person (
74    pname text,
75    pdesc text
76);
77
78CREATE TABLE rtest_admin (
79    pname text,
80    sysname text
81);
82
83CREATE RULE rtest_sys_upd AS ON UPDATE
84    TO rtest_system
85        DO ALSO
86        ( UPDATE
87                rtest_interface SET
88                sysname = NEW.sysname WHERE
89                sysname = OLD.sysname;
90
91UPDATE
92    rtest_admin
93SET
94    sysname = new.sysname
95WHERE
96    sysname = old.sysname);
97
98CREATE RULE rtest_sys_del AS ON DELETE TO rtest_system
99    DO ALSO
100    ( DELETE FROM rtest_interface
101        WHERE sysname = OLD.sysname;
102
103DELETE FROM rtest_admin
104WHERE sysname = old.sysname;
105
106);
107
108CREATE RULE rtest_pers_upd AS ON UPDATE
109    TO rtest_person
110        DO ALSO
111        UPDATE
112            rtest_admin SET
113            pname = NEW.pname WHERE
114            pname = OLD.pname;
115
116CREATE RULE rtest_pers_del AS ON DELETE TO rtest_person
117    DO ALSO
118    DELETE FROM rtest_admin
119    WHERE pname = OLD.pname;
120
121--
122-- Tables and rules for the logging test
123--
124CREATE TABLE rtest_emp (
125    ename char(20),
126    salary money
127);
128
129CREATE TABLE rtest_emplog (
130    ename char(20),
131    who name,
132    action char(10),
133    newsal money,
134    oldsal money
135);
136
137CREATE TABLE rtest_empmass (
138    ename char(20),
139    salary money
140);
141
142CREATE RULE rtest_emp_ins AS ON INSERT TO rtest_emp DO INSERT INTO rtest_emplog VALUES (NEW.ename, CURRENT_USER, 'hired', NEW.salary, '0.00');
143
144CREATE RULE rtest_emp_upd AS ON UPDATE
145    TO rtest_emp WHERE
146    NEW.salary != OLD.salary DO INSERT INTO rtest_emplog VALUES (NEW.ename, CURRENT_USER, 'honored', NEW.salary, OLD.salary);
147
148CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog VALUES (OLD.ename, CURRENT_USER, 'fired', '0.00', OLD.salary);
149
150--
151-- Tables and rules for the multiple cascaded qualified instead
152-- rule test
153--
154CREATE TABLE rtest_t4 (
155    a int4,
156    b text
157);
158
159CREATE TABLE rtest_t5 (
160    a int4,
161    b text
162);
163
164CREATE TABLE rtest_t6 (
165    a int4,
166    b text
167);
168
169CREATE TABLE rtest_t7 (
170    a int4,
171    b text
172);
173
174CREATE TABLE rtest_t8 (
175    a int4,
176    b text
177);
178
179CREATE TABLE rtest_t9 (
180    a int4,
181    b text
182);
183
184CREATE RULE rtest_t4_ins1 AS ON INSERT TO rtest_t4 WHERE
185    NEW.a >= 10
186    AND NEW.a < 20
187        DO INSTEAD
188        INSERT INTO rtest_t5 VALUES (NEW.a, NEW.b);
189
190CREATE RULE rtest_t4_ins2 AS ON INSERT TO rtest_t4 WHERE
191    NEW.a >= 20
192    AND NEW.a < 30 DO INSERT INTO rtest_t6 VALUES (NEW.a, NEW.b);
193
194CREATE RULE rtest_t5_ins AS ON INSERT TO rtest_t5 WHERE
195    NEW.a > 15 DO INSERT INTO rtest_t7 VALUES (NEW.a, NEW.b);
196
197CREATE RULE rtest_t6_ins AS ON INSERT TO rtest_t6 WHERE
198    NEW.a > 25
199        DO INSTEAD
200        INSERT INTO rtest_t8 VALUES (NEW.a, NEW.b);
201
202--
203-- Tables and rules for the rule fire order test
204--
205-- As of PG 7.3, the rules should fire in order by name, regardless
206-- of INSTEAD attributes or creation order.
207--
208CREATE TABLE rtest_order1 (
209    a int4
210);
211
212CREATE TABLE rtest_order2 (
213    a int4,
214    b int4,
215    c text
216);
217
218CREATE SEQUENCE rtest_seq;
219
220CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1
221    DO INSTEAD
222    INSERT INTO rtest_order2 VALUES (NEW.a, nextval('rtest_seq'), 'rule 3 - this should run 3rd');
223
224CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE
225    a < 100
226        DO INSTEAD
227        INSERT INTO rtest_order2 VALUES (NEW.a, nextval('rtest_seq'), 'rule 4 - this should run 4th');
228
229CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 VALUES (NEW.a, nextval('rtest_seq'), 'rule 2 - this should run 2nd');
230
231CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1
232    DO INSTEAD
233    INSERT INTO rtest_order2 VALUES (NEW.a, nextval('rtest_seq'), 'rule 1 - this should run 1st');
234
235--
236-- Tables and rules for the instead nothing test
237--
238CREATE TABLE rtest_nothn1 (
239    a int4,
240    b text
241);
242
243CREATE TABLE rtest_nothn2 (
244    a int4,
245    b text
246);
247
248CREATE TABLE rtest_nothn3 (
249    a int4,
250    b text
251);
252
253CREATE TABLE rtest_nothn4 (
254    a int4,
255    b text
256);
257
258CREATE RULE rtest_nothn_r1 AS ON INSERT TO rtest_nothn1 WHERE
259    NEW.a >= 10
260    AND NEW.a < 20
261        DO INSTEAD
262        NOTHING;
263
264CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE
265    NEW.a >= 30
266    AND NEW.a < 40
267        DO INSTEAD
268        NOTHING;
269
270CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE
271    NEW.a >= 100
272        DO INSTEAD
273        INSERT INTO rtest_nothn3 VALUES (NEW.a, NEW.b);
274
275CREATE RULE rtest_nothn_r4 AS ON INSERT TO rtest_nothn2
276    DO INSTEAD
277    NOTHING;
278
279--
280-- Tests on a view that is select * of a table
281-- and has insert/update/delete instead rules to
282-- behave close like the real table.
283--
284--
285-- We need test date later
286--
287INSERT INTO rtest_t2
288    VALUES (1, 21);
289
290INSERT INTO rtest_t2
291    VALUES (2, 22);
292
293INSERT INTO rtest_t2
294    VALUES (3, 23);
295
296INSERT INTO rtest_t3
297    VALUES (1, 31);
298
299INSERT INTO rtest_t3
300    VALUES (2, 32);
301
302INSERT INTO rtest_t3
303    VALUES (3, 33);
304
305INSERT INTO rtest_t3
306    VALUES (4, 34);
307
308INSERT INTO rtest_t3
309    VALUES (5, 35);
310
311-- insert values
312INSERT INTO rtest_v1
313    VALUES (1, 11);
314
315INSERT INTO rtest_v1
316    VALUES (2, 12);
317
318SELECT
319    *
320FROM
321    rtest_v1;
322
323-- delete with constant expression
324DELETE FROM rtest_v1
325WHERE a = 1;
326
327SELECT
328    *
329FROM
330    rtest_v1;
331
332INSERT INTO rtest_v1
333    VALUES (1, 11);
334
335DELETE FROM rtest_v1
336WHERE b = 12;
337
338SELECT
339    *
340FROM
341    rtest_v1;
342
343INSERT INTO rtest_v1
344    VALUES (2, 12);
345
346INSERT INTO rtest_v1
347    VALUES (2, 13);
348
349SELECT
350    *
351FROM
352    rtest_v1;
353
354* * Remember the DELETE rule ON rtest_v1: It says * *
355    DO INSTEAD
356    DELETE FROM rtest_t1
357    WHERE a = old.a * * So this time BOTH ROWS WITH a = 2 must get deleted \p
358        \r
359        DELETE FROM rtest_v1
360        WHERE b = 12;
361
362SELECT
363    *
364FROM
365    rtest_v1;
366
367DELETE FROM rtest_v1;
368
369-- insert select
370INSERT INTO rtest_v1
371SELECT
372    *
373FROM
374    rtest_t2;
375
376SELECT
377    *
378FROM
379    rtest_v1;
380
381DELETE FROM rtest_v1;
382
383-- same with swapped targetlist
384INSERT INTO rtest_v1 (b, a)
385SELECT
386    b,
387    a
388FROM
389    rtest_t2;
390
391SELECT
392    *
393FROM
394    rtest_v1;
395
396-- now with only one target attribute
397INSERT INTO rtest_v1 (a)
398SELECT
399    a
400FROM
401    rtest_t3;
402
403SELECT
404    *
405FROM
406    rtest_v1;
407
408SELECT
409    *
410FROM
411    rtest_v1
412WHERE
413    b ISNULL;
414
415-- let attribute a differ (must be done on rtest_t1 - see above)
416UPDATE
417    rtest_t1
418SET
419    a = a + 10
420WHERE
421    b ISNULL;
422
423DELETE FROM rtest_v1
424WHERE b ISNULL;
425
426SELECT
427    *
428FROM
429    rtest_v1;
430
431-- now updates with constant expression
432UPDATE
433    rtest_v1
434SET
435    b = 42
436WHERE
437    a = 2;
438
439SELECT
440    *
441FROM
442    rtest_v1;
443
444UPDATE
445    rtest_v1
446SET
447    b = 99
448WHERE
449    b = 42;
450
451SELECT
452    *
453FROM
454    rtest_v1;
455
456UPDATE
457    rtest_v1
458SET
459    b = 88
460WHERE
461    b < 50;
462
463SELECT
464    *
465FROM
466    rtest_v1;
467
468DELETE FROM rtest_v1;
469
470INSERT INTO rtest_v1
471SELECT
472    rtest_t2.a,
473    rtest_t3.b
474FROM
475    rtest_t2,
476    rtest_t3
477WHERE
478    rtest_t2.a = rtest_t3.a;
479
480SELECT
481    *
482FROM
483    rtest_v1;
484
485-- updates in a mergejoin
486UPDATE
487    rtest_v1
488SET
489    b = rtest_t2.b
490FROM
491    rtest_t2
492WHERE
493    rtest_v1.a = rtest_t2.a;
494
495SELECT
496    *
497FROM
498    rtest_v1;
499
500INSERT INTO rtest_v1
501SELECT
502    *
503FROM
504    rtest_t3;
505
506SELECT
507    *
508FROM
509    rtest_v1;
510
511UPDATE
512    rtest_t1
513SET
514    a = a + 10
515WHERE
516    b > 30;
517
518SELECT
519    *
520FROM
521    rtest_v1;
522
523UPDATE
524    rtest_v1
525SET
526    a = rtest_t3.a + 20
527FROM
528    rtest_t3
529WHERE
530    rtest_v1.b = rtest_t3.b;
531
532SELECT
533    *
534FROM
535    rtest_v1;
536
537--
538-- Test for constraint updates/deletes
539--
540INSERT INTO rtest_system
541    VALUES ('orion', 'Linux Jan Wieck');
542
543INSERT INTO rtest_system
544    VALUES ('notjw', 'WinNT Jan Wieck (notebook)');
545
546INSERT INTO rtest_system
547    VALUES ('neptun', 'Fileserver');
548
549INSERT INTO rtest_interface
550    VALUES ('orion', 'eth0');
551
552INSERT INTO rtest_interface
553    VALUES ('orion', 'eth1');
554
555INSERT INTO rtest_interface
556    VALUES ('notjw', 'eth0');
557
558INSERT INTO rtest_interface
559    VALUES ('neptun', 'eth0');
560
561INSERT INTO rtest_person
562    VALUES ('jw', 'Jan Wieck');
563
564INSERT INTO rtest_person
565    VALUES ('bm', 'Bruce Momjian');
566
567INSERT INTO rtest_admin
568    VALUES ('jw', 'orion');
569
570INSERT INTO rtest_admin
571    VALUES ('jw', 'notjw');
572
573INSERT INTO rtest_admin
574    VALUES ('bm', 'neptun');
575
576UPDATE
577    rtest_system
578SET
579    sysname = 'pluto'
580WHERE
581    sysname = 'neptun';
582
583SELECT
584    *
585FROM
586    rtest_interface;
587
588SELECT
589    *
590FROM
591    rtest_admin;
592
593UPDATE
594    rtest_person
595SET
596    pname = 'jwieck'
597WHERE
598    pdesc = 'Jan Wieck';
599
600-- Note: use ORDER BY here to ensure consistent output across all systems.
601-- The above UPDATE affects two rows with equal keys, so they could be
602-- updated in either order depending on the whim of the local qsort().
603SELECT
604    *
605FROM
606    rtest_admin
607ORDER BY
608    pname,
609    sysname;
610
611DELETE FROM rtest_system
612WHERE sysname = 'orion';
613
614SELECT
615    *
616FROM
617    rtest_interface;
618
619SELECT
620    *
621FROM
622    rtest_admin;
623
624--
625-- Rule qualification test
626--
627INSERT INTO rtest_emp
628    VALUES ('wiecc', '5000.00');
629
630INSERT INTO rtest_emp
631    VALUES ('gates', '80000.00');
632
633UPDATE
634    rtest_emp
635SET
636    ename = 'wiecx'
637WHERE
638    ename = 'wiecc';
639
640UPDATE
641    rtest_emp
642SET
643    ename = 'wieck',
644    salary = '6000.00'
645WHERE
646    ename = 'wiecx';
647
648UPDATE
649    rtest_emp
650SET
651    salary = '7000.00'
652WHERE
653    ename = 'wieck';
654
655DELETE FROM rtest_emp
656WHERE ename = 'gates';
657
658SELECT
659    ename,
660    who = CURRENT_USER AS "matches user",
661    action,
662    newsal,
663    oldsal
664FROM
665    rtest_emplog
666ORDER BY
667    ename,
668    action,
669    newsal;
670
671INSERT INTO rtest_empmass
672    VALUES ('meyer', '4000.00');
673
674INSERT INTO rtest_empmass
675    VALUES ('maier', '5000.00');
676
677INSERT INTO rtest_empmass
678    VALUES ('mayr', '6000.00');
679
680INSERT INTO rtest_emp
681SELECT
682    *
683FROM
684    rtest_empmass;
685
686SELECT
687    ename,
688    who = CURRENT_USER AS "matches user",
689    action,
690    newsal,
691    oldsal
692FROM
693    rtest_emplog
694ORDER BY
695    ename,
696    action,
697    newsal;
698
699UPDATE
700    rtest_empmass
701SET
702    salary = salary + '1000.00';
703
704UPDATE
705    rtest_emp
706SET
707    salary = rtest_empmass.salary
708FROM
709    rtest_empmass
710WHERE
711    rtest_emp.ename = rtest_empmass.ename;
712
713SELECT
714    ename,
715    who = CURRENT_USER AS "matches user",
716    action,
717    newsal,
718    oldsal
719FROM
720    rtest_emplog
721ORDER BY
722    ename,
723    action,
724    newsal;
725
726DELETE FROM rtest_emp USING rtest_empmass
727WHERE rtest_emp.ename = rtest_empmass.ename;
728
729SELECT
730    ename,
731    who = CURRENT_USER AS "matches user",
732    action,
733    newsal,
734    oldsal
735FROM
736    rtest_emplog
737ORDER BY
738    ename,
739    action,
740    newsal;
741
742--
743-- Multiple cascaded qualified instead rule test
744--
745INSERT INTO rtest_t4
746    VALUES (1, 'Record should go to rtest_t4');
747
748INSERT INTO rtest_t4
749    VALUES (2, 'Record should go to rtest_t4');
750
751INSERT INTO rtest_t4
752    VALUES (10, 'Record should go to rtest_t5');
753
754INSERT INTO rtest_t4
755    VALUES (15, 'Record should go to rtest_t5');
756
757INSERT INTO rtest_t4
758    VALUES (19, 'Record should go to rtest_t5 and t7');
759
760INSERT INTO rtest_t4
761    VALUES (20, 'Record should go to rtest_t4 and t6');
762
763INSERT INTO rtest_t4
764    VALUES (26, 'Record should go to rtest_t4 and t8');
765
766INSERT INTO rtest_t4
767    VALUES (28, 'Record should go to rtest_t4 and t8');
768
769INSERT INTO rtest_t4
770    VALUES (30, 'Record should go to rtest_t4');
771
772INSERT INTO rtest_t4
773    VALUES (40, 'Record should go to rtest_t4');
774
775SELECT
776    *
777FROM
778    rtest_t4;
779
780SELECT
781    *
782FROM
783    rtest_t5;
784
785SELECT
786    *
787FROM
788    rtest_t6;
789
790SELECT
791    *
792FROM
793    rtest_t7;
794
795SELECT
796    *
797FROM
798    rtest_t8;
799
800DELETE FROM rtest_t4;
801
802DELETE FROM rtest_t5;
803
804DELETE FROM rtest_t6;
805
806DELETE FROM rtest_t7;
807
808DELETE FROM rtest_t8;
809
810INSERT INTO rtest_t9
811    VALUES (1, 'Record should go to rtest_t4');
812
813INSERT INTO rtest_t9
814    VALUES (2, 'Record should go to rtest_t4');
815
816INSERT INTO rtest_t9
817    VALUES (10, 'Record should go to rtest_t5');
818
819INSERT INTO rtest_t9
820    VALUES (15, 'Record should go to rtest_t5');
821
822INSERT INTO rtest_t9
823    VALUES (19, 'Record should go to rtest_t5 and t7');
824
825INSERT INTO rtest_t9
826    VALUES (20, 'Record should go to rtest_t4 and t6');
827
828INSERT INTO rtest_t9
829    VALUES (26, 'Record should go to rtest_t4 and t8');
830
831INSERT INTO rtest_t9
832    VALUES (28, 'Record should go to rtest_t4 and t8');
833
834INSERT INTO rtest_t9
835    VALUES (30, 'Record should go to rtest_t4');
836
837INSERT INTO rtest_t9
838    VALUES (40, 'Record should go to rtest_t4');
839
840INSERT INTO rtest_t4
841SELECT
842    *
843FROM
844    rtest_t9
845WHERE
846    a < 20;
847
848SELECT
849    *
850FROM
851    rtest_t4;
852
853SELECT
854    *
855FROM
856    rtest_t5;
857
858SELECT
859    *
860FROM
861    rtest_t6;
862
863SELECT
864    *
865FROM
866    rtest_t7;
867
868SELECT
869    *
870FROM
871    rtest_t8;
872
873INSERT INTO rtest_t4
874SELECT
875    *
876FROM
877    rtest_t9
878WHERE
879    b ~ 'and t8';
880
881SELECT
882    *
883FROM
884    rtest_t4;
885
886SELECT
887    *
888FROM
889    rtest_t5;
890
891SELECT
892    *
893FROM
894    rtest_t6;
895
896SELECT
897    *
898FROM
899    rtest_t7;
900
901SELECT
902    *
903FROM
904    rtest_t8;
905
906INSERT INTO rtest_t4
907SELECT
908    a + 1,
909    b
910FROM
911    rtest_t9
912WHERE
913    a IN (20, 30, 40);
914
915SELECT
916    *
917FROM
918    rtest_t4;
919
920SELECT
921    *
922FROM
923    rtest_t5;
924
925SELECT
926    *
927FROM
928    rtest_t6;
929
930SELECT
931    *
932FROM
933    rtest_t7;
934
935SELECT
936    *
937FROM
938    rtest_t8;
939
940--
941-- Check that the ordering of rules fired is correct
942--
943INSERT INTO rtest_order1
944    VALUES (1);
945
946SELECT
947    *
948FROM
949    rtest_order2;
950
951--
952-- Check if instead nothing w/without qualification works
953--
954INSERT INTO rtest_nothn1
955    VALUES (1, 'want this');
956
957INSERT INTO rtest_nothn1
958    VALUES (2, 'want this');
959
960INSERT INTO rtest_nothn1
961    VALUES (10, 'don''t want this');
962
963INSERT INTO rtest_nothn1
964    VALUES (19, 'don''t want this');
965
966INSERT INTO rtest_nothn1
967    VALUES (20, 'want this');
968
969INSERT INTO rtest_nothn1
970    VALUES (29, 'want this');
971
972INSERT INTO rtest_nothn1
973    VALUES (30, 'don''t want this');
974
975INSERT INTO rtest_nothn1
976    VALUES (39, 'don''t want this');
977
978INSERT INTO rtest_nothn1
979    VALUES (40, 'want this');
980
981INSERT INTO rtest_nothn1
982    VALUES (50, 'want this');
983
984INSERT INTO rtest_nothn1
985    VALUES (60, 'want this');
986
987SELECT
988    *
989FROM
990    rtest_nothn1;
991
992INSERT INTO rtest_nothn2
993    VALUES (10, 'too small');
994
995INSERT INTO rtest_nothn2
996    VALUES (50, 'too small');
997
998INSERT INTO rtest_nothn2
999    VALUES (100, 'OK');
1000
1001INSERT INTO rtest_nothn2
1002    VALUES (200, 'OK');
1003
1004SELECT
1005    *
1006FROM
1007    rtest_nothn2;
1008
1009SELECT
1010    *
1011FROM
1012    rtest_nothn3;
1013
1014DELETE FROM rtest_nothn1;
1015
1016DELETE FROM rtest_nothn2;
1017
1018DELETE FROM rtest_nothn3;
1019
1020INSERT INTO rtest_nothn4
1021    VALUES (1, 'want this');
1022
1023INSERT INTO rtest_nothn4
1024    VALUES (2, 'want this');
1025
1026INSERT INTO rtest_nothn4
1027    VALUES (10, 'don''t want this');
1028
1029INSERT INTO rtest_nothn4
1030    VALUES (19, 'don''t want this');
1031
1032INSERT INTO rtest_nothn4
1033    VALUES (20, 'want this');
1034
1035INSERT INTO rtest_nothn4
1036    VALUES (29, 'want this');
1037
1038INSERT INTO rtest_nothn4
1039    VALUES (30, 'don''t want this');
1040
1041INSERT INTO rtest_nothn4
1042    VALUES (39, 'don''t want this');
1043
1044INSERT INTO rtest_nothn4
1045    VALUES (40, 'want this');
1046
1047INSERT INTO rtest_nothn4
1048    VALUES (50, 'want this');
1049
1050INSERT INTO rtest_nothn4
1051    VALUES (60, 'want this');
1052
1053INSERT INTO rtest_nothn1
1054SELECT
1055    *
1056FROM
1057    rtest_nothn4;
1058
1059SELECT
1060    *
1061FROM
1062    rtest_nothn1;
1063
1064DELETE FROM rtest_nothn4;
1065
1066INSERT INTO rtest_nothn4
1067    VALUES (10, 'too small');
1068
1069INSERT INTO rtest_nothn4
1070    VALUES (50, 'too small');
1071
1072INSERT INTO rtest_nothn4
1073    VALUES (100, 'OK');
1074
1075INSERT INTO rtest_nothn4
1076    VALUES (200, 'OK');
1077
1078INSERT INTO rtest_nothn2
1079SELECT
1080    *
1081FROM
1082    rtest_nothn4;
1083
1084SELECT
1085    *
1086FROM
1087    rtest_nothn2;
1088
1089SELECT
1090    *
1091FROM
1092    rtest_nothn3;
1093
1094CREATE TABLE rtest_view1 (
1095    a int4,
1096    b text,
1097    v bool
1098);
1099
1100CREATE TABLE rtest_view2 (
1101    a int4
1102);
1103
1104CREATE TABLE rtest_view3 (
1105    a int4,
1106    b text
1107);
1108
1109CREATE TABLE rtest_view4 (
1110    a int4,
1111    b text,
1112    c int4
1113);
1114
1115CREATE VIEW rtest_vview1 AS
1116SELECT
1117    a,
1118    b
1119FROM
1120    rtest_view1 X
1121WHERE
1122    0 < (
1123        SELECT
1124            count(*)
1125        FROM
1126            rtest_view2 Y
1127        WHERE
1128            Y.a = X.a);
1129
1130CREATE VIEW rtest_vview2 AS
1131SELECT
1132    a,
1133    b
1134FROM
1135    rtest_view1
1136WHERE
1137    v;
1138
1139CREATE VIEW rtest_vview3 AS
1140SELECT
1141    a,
1142    b
1143FROM
1144    rtest_vview2 X
1145WHERE
1146    0 < (
1147        SELECT
1148            count(*)
1149        FROM
1150            rtest_view2 Y
1151        WHERE
1152            Y.a = X.a);
1153
1154CREATE VIEW rtest_vview4 AS
1155SELECT
1156    X.a,
1157    X.b,
1158    count(Y.a) AS refcount
1159FROM
1160    rtest_view1 X,
1161    rtest_view2 Y
1162WHERE
1163    X.a = Y.a
1164GROUP BY
1165    X.a,
1166    X.b;
1167
1168CREATE FUNCTION rtest_viewfunc1 (int4)
1169    RETURNS int4
1170    AS 'select count(*)::int4 from rtest_view2 where a = $1'
1171    LANGUAGE sql;
1172
1173CREATE VIEW rtest_vview5 AS
1174SELECT
1175    a,
1176    b,
1177    rtest_viewfunc1 (a) AS refcount
1178FROM
1179    rtest_view1;
1180
1181INSERT INTO rtest_view1
1182    VALUES (1, 'item 1', 't');
1183
1184INSERT INTO rtest_view1
1185    VALUES (2, 'item 2', 't');
1186
1187INSERT INTO rtest_view1
1188    VALUES (3, 'item 3', 't');
1189
1190INSERT INTO rtest_view1
1191    VALUES (4, 'item 4', 'f');
1192
1193INSERT INTO rtest_view1
1194    VALUES (5, 'item 5', 't');
1195
1196INSERT INTO rtest_view1
1197    VALUES (6, 'item 6', 'f');
1198
1199INSERT INTO rtest_view1
1200    VALUES (7, 'item 7', 't');
1201
1202INSERT INTO rtest_view1
1203    VALUES (8, 'item 8', 't');
1204
1205INSERT INTO rtest_view2
1206    VALUES (2);
1207
1208INSERT INTO rtest_view2
1209    VALUES (2);
1210
1211INSERT INTO rtest_view2
1212    VALUES (4);
1213
1214INSERT INTO rtest_view2
1215    VALUES (5);
1216
1217INSERT INTO rtest_view2
1218    VALUES (7);
1219
1220INSERT INTO rtest_view2
1221    VALUES (7);
1222
1223INSERT INTO rtest_view2
1224    VALUES (7);
1225
1226INSERT INTO rtest_view2
1227    VALUES (7);
1228
1229SELECT
1230    *
1231FROM
1232    rtest_vview1;
1233
1234SELECT
1235    *
1236FROM
1237    rtest_vview2;
1238
1239SELECT
1240    *
1241FROM
1242    rtest_vview3;
1243
1244SELECT
1245    *
1246FROM
1247    rtest_vview4
1248ORDER BY
1249    a,
1250    b;
1251
1252SELECT
1253    *
1254FROM
1255    rtest_vview5;
1256
1257INSERT INTO rtest_view3
1258SELECT
1259    *
1260FROM
1261    rtest_vview1
1262WHERE
1263    a < 7;
1264
1265SELECT
1266    *
1267FROM
1268    rtest_view3;
1269
1270DELETE FROM rtest_view3;
1271
1272INSERT INTO rtest_view3
1273SELECT
1274    *
1275FROM
1276    rtest_vview2
1277WHERE
1278    a != 5
1279    AND b !~ '2';
1280
1281SELECT
1282    *
1283FROM
1284    rtest_view3;
1285
1286DELETE FROM rtest_view3;
1287
1288INSERT INTO rtest_view3
1289SELECT
1290    *
1291FROM
1292    rtest_vview3;
1293
1294SELECT
1295    *
1296FROM
1297    rtest_view3;
1298
1299DELETE FROM rtest_view3;
1300
1301INSERT INTO rtest_view4
1302SELECT
1303    *
1304FROM
1305    rtest_vview4
1306WHERE
1307    3 > refcount;
1308
1309SELECT
1310    *
1311FROM
1312    rtest_view4
1313ORDER BY
1314    a,
1315    b;
1316
1317DELETE FROM rtest_view4;
1318
1319INSERT INTO rtest_view4
1320SELECT
1321    *
1322FROM
1323    rtest_vview5
1324WHERE
1325    a > 2
1326    AND refcount = 0;
1327
1328SELECT
1329    *
1330FROM
1331    rtest_view4;
1332
1333DELETE FROM rtest_view4;
1334
1335--
1336-- Test for computations in views
1337--
1338CREATE TABLE rtest_comp (
1339    part text,
1340    unit char(4),
1341    size float
1342);
1343
1344CREATE TABLE rtest_unitfact (
1345    unit char(4),
1346    factor float
1347);
1348
1349CREATE VIEW rtest_vcomp AS
1350SELECT
1351    X.part,
1352    (X.size * Y.factor) AS size_in_cm
1353FROM
1354    rtest_comp X,
1355    rtest_unitfact Y
1356WHERE
1357    X.unit = Y.unit;
1358
1359INSERT INTO rtest_unitfact
1360    VALUES ('m', 100.0);
1361
1362INSERT INTO rtest_unitfact
1363    VALUES ('cm', 1.0);
1364
1365INSERT INTO rtest_unitfact
1366    VALUES ('inch', 2.54);
1367
1368INSERT INTO rtest_comp
1369    VALUES ('p1', 'm', 5.0);
1370
1371INSERT INTO rtest_comp
1372    VALUES ('p2', 'm', 3.0);
1373
1374INSERT INTO rtest_comp
1375    VALUES ('p3', 'cm', 5.0);
1376
1377INSERT INTO rtest_comp
1378    VALUES ('p4', 'cm', 15.0);
1379
1380INSERT INTO rtest_comp
1381    VALUES ('p5', 'inch', 7.0);
1382
1383INSERT INTO rtest_comp
1384    VALUES ('p6', 'inch', 4.4);
1385
1386SELECT
1387    *
1388FROM
1389    rtest_vcomp
1390ORDER BY
1391    part;
1392
1393SELECT
1394    *
1395FROM
1396    rtest_vcomp
1397WHERE
1398    size_in_cm > 10.0
1399ORDER BY
1400    size_in_cm USING >;
1401
1402--
1403-- In addition run the (slightly modified) queries from the
1404-- programmers manual section on the rule system.
1405--
1406CREATE TABLE shoe_data (
1407    shoename char(10), -- primary key
1408    sh_avail integer, -- available # of pairs
1409    slcolor char(10), -- preferred shoelace color
1410    slminlen float, -- minimum shoelace length
1411    slmaxlen float, -- maximum shoelace length
1412    slunit char(8) -- length unit
1413);
1414
1415CREATE TABLE shoelace_data (
1416    sl_name char(10), -- primary key
1417    sl_avail integer, -- available # of pairs
1418    sl_color char(10), -- shoelace color
1419    sl_len float, -- shoelace length
1420    sl_unit char(8) -- length unit
1421);
1422
1423CREATE TABLE unit (
1424    un_name char(8), -- the primary key
1425    un_fact float -- factor to transform to cm
1426);
1427
1428CREATE VIEW shoe AS
1429SELECT
1430    sh.shoename,
1431    sh.sh_avail,
1432    sh.slcolor,
1433    sh.slminlen,
1434    sh.slminlen * un.un_fact AS slminlen_cm,
1435    sh.slmaxlen,
1436    sh.slmaxlen * un.un_fact AS slmaxlen_cm,
1437    sh.slunit
1438FROM
1439    shoe_data sh,
1440    unit un
1441WHERE
1442    sh.slunit = un.un_name;
1443
1444CREATE VIEW shoelace AS
1445SELECT
1446    s.sl_name,
1447    s.sl_avail,
1448    s.sl_color,
1449    s.sl_len,
1450    s.sl_unit,
1451    s.sl_len * u.un_fact AS sl_len_cm
1452FROM
1453    shoelace_data s,
1454    unit u
1455WHERE
1456    s.sl_unit = u.un_name;
1457
1458CREATE VIEW shoe_ready AS
1459SELECT
1460    rsh.shoename,
1461    rsh.sh_avail,
1462    rsl.sl_name,
1463    rsl.sl_avail,
1464    int4smaller(rsh.sh_avail, rsl.sl_avail) AS total_avail
1465FROM
1466    shoe rsh,
1467    shoelace rsl
1468WHERE
1469    rsl.sl_color = rsh.slcolor
1470    AND rsl.sl_len_cm >= rsh.slminlen_cm
1471    AND rsl.sl_len_cm <= rsh.slmaxlen_cm;
1472
1473INSERT INTO unit
1474    VALUES ('cm', 1.0);
1475
1476INSERT INTO unit
1477    VALUES ('m', 100.0);
1478
1479INSERT INTO unit
1480    VALUES ('inch', 2.54);
1481
1482INSERT INTO shoe_data
1483    VALUES ('sh1', 2, 'black', 70.0, 90.0, 'cm');
1484
1485INSERT INTO shoe_data
1486    VALUES ('sh2', 0, 'black', 30.0, 40.0, 'inch');
1487
1488INSERT INTO shoe_data
1489    VALUES ('sh3', 4, 'brown', 50.0, 65.0, 'cm');
1490
1491INSERT INTO shoe_data
1492    VALUES ('sh4', 3, 'brown', 40.0, 50.0, 'inch');
1493
1494INSERT INTO shoelace_data
1495    VALUES ('sl1', 5, 'black', 80.0, 'cm');
1496
1497INSERT INTO shoelace_data
1498    VALUES ('sl2', 6, 'black', 100.0, 'cm');
1499
1500INSERT INTO shoelace_data
1501    VALUES ('sl3', 0, 'black', 35.0, 'inch');
1502
1503INSERT INTO shoelace_data
1504    VALUES ('sl4', 8, 'black', 40.0, 'inch');
1505
1506INSERT INTO shoelace_data
1507    VALUES ('sl5', 4, 'brown', 1.0, 'm');
1508
1509INSERT INTO shoelace_data
1510    VALUES ('sl6', 0, 'brown', 0.9, 'm');
1511
1512INSERT INTO shoelace_data
1513    VALUES ('sl7', 7, 'brown', 60, 'cm');
1514
1515INSERT INTO shoelace_data
1516    VALUES ('sl8', 1, 'brown', 40, 'inch');
1517
1518-- SELECTs in doc
1519SELECT
1520    *
1521FROM
1522    shoelace
1523ORDER BY
1524    sl_name;
1525
1526SELECT
1527    *
1528FROM
1529    shoe_ready
1530WHERE
1531    total_avail >= 2
1532ORDER BY
1533    1;
1534
1535CREATE TABLE shoelace_log (
1536    sl_name char(10), -- shoelace changed
1537    sl_avail integer, -- new available value
1538    log_who name, -- who did it
1539    log_when timestamp -- when
1540);
1541
1542-- Want "log_who" to be CURRENT_USER,
1543-- but that is non-portable for the regression test
1544-- - thomas 1999-02-21
1545CREATE RULE log_shoelace AS ON UPDATE
1546    TO shoelace_data WHERE
1547    NEW.sl_avail != OLD.sl_avail DO INSERT INTO shoelace_log VALUES (NEW.sl_name, NEW.sl_avail, 'Al Bundy', 'epoch');
1548
1549UPDATE
1550    shoelace_data
1551SET
1552    sl_avail = 6
1553WHERE
1554    sl_name = 'sl7';
1555
1556SELECT
1557    *
1558FROM
1559    shoelace_log;
1560
1561CREATE RULE shoelace_ins AS ON INSERT TO shoelace
1562    DO INSTEAD
1563    INSERT INTO shoelace_data VALUES (NEW.sl_name, NEW.sl_avail, NEW.sl_color, NEW.sl_len, NEW.sl_unit);
1564
1565CREATE RULE shoelace_upd AS ON UPDATE
1566    TO shoelace
1567        DO INSTEAD
1568        UPDATE
1569            shoelace_data SET
1570            sl_name = NEW.sl_name,
1571            sl_avail = NEW.sl_avail,
1572            sl_color = NEW.sl_color,
1573            sl_len = NEW.sl_len,
1574            sl_unit = NEW.sl_unit WHERE
1575            sl_name = OLD.sl_name;
1576
1577CREATE RULE shoelace_del AS ON DELETE TO shoelace
1578    DO INSTEAD
1579    DELETE FROM shoelace_data
1580    WHERE sl_name = OLD.sl_name;
1581
1582CREATE TABLE shoelace_arrive (
1583    arr_name char(10),
1584    arr_quant integer
1585);
1586
1587CREATE TABLE shoelace_ok (
1588    ok_name char(10),
1589    ok_quant integer
1590);
1591
1592CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok
1593    DO INSTEAD
1594    UPDATE
1595        shoelace SET
1596        sl_avail = sl_avail + NEW.ok_quant WHERE
1597        sl_name = NEW.ok_name;
1598
1599INSERT INTO shoelace_arrive
1600    VALUES ('sl3', 10);
1601
1602INSERT INTO shoelace_arrive
1603    VALUES ('sl6', 20);
1604
1605INSERT INTO shoelace_arrive
1606    VALUES ('sl8', 20);
1607
1608SELECT
1609    *
1610FROM
1611    shoelace
1612ORDER BY
1613    sl_name;
1614
1615INSERT INTO shoelace_ok
1616SELECT
1617    *
1618FROM
1619    shoelace_arrive;
1620
1621SELECT
1622    *
1623FROM
1624    shoelace
1625ORDER BY
1626    sl_name;
1627
1628SELECT
1629    *
1630FROM
1631    shoelace_log
1632ORDER BY
1633    sl_name;
1634
1635CREATE VIEW shoelace_obsolete AS
1636SELECT
1637    *
1638FROM
1639    shoelace
1640WHERE
1641    NOT EXISTS (
1642        SELECT
1643            shoename
1644        FROM
1645            shoe
1646        WHERE
1647            slcolor = sl_color);
1648
1649CREATE VIEW shoelace_candelete AS
1650SELECT
1651    *
1652FROM
1653    shoelace_obsolete
1654WHERE
1655    sl_avail = 0;
1656
1657INSERT INTO shoelace
1658    VALUES ('sl9', 0, 'pink', 35.0, 'inch', 0.0);
1659
1660INSERT INTO shoelace
1661    VALUES ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0);
1662
1663-- Unsupported (even though a similar updatable view construct is)
1664INSERT INTO shoelace
1665    VALUES ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0)
1666ON CONFLICT
1667    DO NOTHING;
1668
1669SELECT
1670    *
1671FROM
1672    shoelace_obsolete
1673ORDER BY
1674    sl_len_cm;
1675
1676SELECT
1677    *
1678FROM
1679    shoelace_candelete;
1680
1681DELETE FROM shoelace
1682WHERE EXISTS (
1683        SELECT
1684            *
1685        FROM
1686            shoelace_candelete
1687        WHERE
1688            sl_name = shoelace.sl_name);
1689
1690SELECT
1691    *
1692FROM
1693    shoelace
1694ORDER BY
1695    sl_name;
1696
1697SELECT
1698    *
1699FROM
1700    shoe
1701ORDER BY
1702    shoename;
1703
1704SELECT
1705    count(*)
1706FROM
1707    shoe;
1708
1709--
1710-- Simple test of qualified ON INSERT ... this did not work in 7.0 ...
1711--
1712CREATE TABLE rules_foo (
1713    f1 int
1714);
1715
1716CREATE TABLE rules_foo2 (
1717    f1 int
1718);
1719
1720CREATE RULE rules_foorule AS ON INSERT TO rules_foo WHERE
1721    f1 < 100
1722        DO INSTEAD
1723        NOTHING;
1724
1725INSERT INTO rules_foo
1726    VALUES (1);
1727
1728INSERT INTO rules_foo
1729    VALUES (1001);
1730
1731SELECT
1732    *
1733FROM
1734    rules_foo;
1735
1736DROP RULE rules_foorule ON rules_foo;
1737
1738-- this should fail because f1 is not exposed for unqualified reference:
1739CREATE RULE rules_foorule AS ON INSERT TO rules_foo WHERE
1740    f1 < 100
1741        DO INSTEAD
1742        INSERT INTO rules_foo2 VALUES (f1);
1743
1744-- this is the correct way:
1745CREATE RULE rules_foorule AS ON INSERT TO rules_foo WHERE
1746    f1 < 100
1747        DO INSTEAD
1748        INSERT INTO rules_foo2 VALUES (NEW.f1);
1749
1750INSERT INTO rules_foo
1751    VALUES (2);
1752
1753INSERT INTO rules_foo
1754    VALUES (100);
1755
1756SELECT
1757    *
1758FROM
1759    rules_foo;
1760
1761SELECT
1762    *
1763FROM
1764    rules_foo2;
1765
1766DROP RULE rules_foorule ON rules_foo;
1767
1768DROP TABLE rules_foo;
1769
1770DROP TABLE rules_foo2;
1771
1772--
1773-- Test rules containing INSERT ... SELECT, which is a very ugly special
1774-- case as of 7.1.  Example is based on bug report from Joel Burton.
1775--
1776CREATE TABLE pparent (
1777    pid int,
1778    txt text
1779);
1780
1781INSERT INTO pparent
1782    VALUES (1, 'parent1');
1783
1784INSERT INTO pparent
1785    VALUES (2, 'parent2');
1786
1787CREATE TABLE cchild (
1788    pid int,
1789    descrip text
1790);
1791
1792INSERT INTO cchild
1793    VALUES (1, 'descrip1');
1794
1795CREATE VIEW vview AS
1796SELECT
1797    pparent.pid,
1798    txt,
1799    descrip
1800FROM
1801    pparent
1802    LEFT JOIN cchild USING (pid);
1803
1804CREATE RULE rrule AS ON UPDATE
1805    TO vview
1806        DO INSTEAD
1807        (INSERT INTO cchild (pid, descrip)
1808            SELECT
1809                OLD.pid,
1810                NEW.descrip WHERE
1811                OLD.descrip ISNULL;
1812
1813UPDATE
1814    cchild
1815SET
1816    descrip = new.descrip
1817WHERE
1818    cchild.pid = old.pid;
1819
1820);
1821
1822SELECT
1823    *
1824FROM
1825    vview;
1826
1827UPDATE
1828    vview
1829SET
1830    descrip = 'test1'
1831WHERE
1832    pid = 1;
1833
1834SELECT
1835    *
1836FROM
1837    vview;
1838
1839UPDATE
1840    vview
1841SET
1842    descrip = 'test2'
1843WHERE
1844    pid = 2;
1845
1846SELECT
1847    *
1848FROM
1849    vview;
1850
1851UPDATE
1852    vview
1853SET
1854    descrip = 'test3'
1855WHERE
1856    pid = 3;
1857
1858SELECT
1859    *
1860FROM
1861    vview;
1862
1863SELECT
1864    *
1865FROM
1866    cchild;
1867
1868DROP RULE rrule ON vview;
1869
1870DROP VIEW vview;
1871
1872DROP TABLE pparent;
1873
1874DROP TABLE cchild;
1875
1876--
1877-- Check that ruleutils are working
1878--
1879-- temporarily disable fancy output, so view changes create less diff noise
1880a \t
1881SELECT
1882    viewname,
1883    definition
1884FROM
1885    pg_views
1886WHERE
1887    schemaname IN ('pg_catalog', 'public')
1888ORDER BY
1889    viewname;
1890
1891SELECT
1892    tablename,
1893    rulename,
1894    definition
1895FROM
1896    pg_rules
1897WHERE
1898    schemaname IN ('pg_catalog', 'public')
1899ORDER BY
1900    tablename,
1901    rulename;
1902
1903-- restore normal output mode
1904a \t
1905--
1906-- CREATE OR REPLACE RULE
1907--
1908CREATE TABLE ruletest_tbl (
1909    a int,
1910    b int
1911);
1912
1913CREATE TABLE ruletest_tbl2 (
1914    a int,
1915    b int
1916);
1917
1918CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
1919    DO INSTEAD
1920    INSERT INTO ruletest_tbl2
1921        VALUES (
1922            10, 10
1923);
1924
1925INSERT INTO ruletest_tbl
1926    VALUES (99, 99);
1927
1928CREATE OR REPLACE RULE myrule AS ON INSERT TO ruletest_tbl
1929    DO INSTEAD
1930    INSERT INTO ruletest_tbl2
1931        VALUES (
1932            1000, 1000
1933);
1934
1935INSERT INTO ruletest_tbl
1936    VALUES (99, 99);
1937
1938SELECT
1939    *
1940FROM
1941    ruletest_tbl2;
1942
1943-- Check that rewrite rules splitting one INSERT into multiple
1944-- conditional statements does not disable FK checking.
1945CREATE TABLE rule_and_refint_t1 (
1946    id1a integer,
1947    id1b integer,
1948    PRIMARY KEY (id1a, id1b)
1949);
1950
1951CREATE TABLE rule_and_refint_t2 (
1952    id2a integer,
1953    id2c integer,
1954    PRIMARY KEY (id2a, id2c)
1955);
1956
1957CREATE TABLE rule_and_refint_t3 (
1958    id3a integer,
1959    id3b integer,
1960    id3c integer,
1961    data text,
1962    PRIMARY KEY (id3a, id3b, id3c),
1963    FOREIGN KEY (id3a, id3b) REFERENCES rule_and_refint_t1 (id1a, id1b),
1964    FOREIGN KEY (id3a, id3c) REFERENCES rule_and_refint_t2 (id2a, id2c)
1965);
1966
1967INSERT INTO rule_and_refint_t1
1968    VALUES (1, 11);
1969
1970INSERT INTO rule_and_refint_t1
1971    VALUES (1, 12);
1972
1973INSERT INTO rule_and_refint_t1
1974    VALUES (2, 21);
1975
1976INSERT INTO rule_and_refint_t1
1977    VALUES (2, 22);
1978
1979INSERT INTO rule_and_refint_t2
1980    VALUES (1, 11);
1981
1982INSERT INTO rule_and_refint_t2
1983    VALUES (1, 12);
1984
1985INSERT INTO rule_and_refint_t2
1986    VALUES (2, 21);
1987
1988INSERT INTO rule_and_refint_t2
1989    VALUES (2, 22);
1990
1991INSERT INTO rule_and_refint_t3
1992    VALUES (1, 11, 11, 'row1');
1993
1994INSERT INTO rule_and_refint_t3
1995    VALUES (1, 11, 12, 'row2');
1996
1997INSERT INTO rule_and_refint_t3
1998    VALUES (1, 12, 11, 'row3');
1999
2000INSERT INTO rule_and_refint_t3
2001    VALUES (1, 12, 12, 'row4');
2002
2003INSERT INTO rule_and_refint_t3
2004    VALUES (1, 11, 13, 'row5');
2005
2006INSERT INTO rule_and_refint_t3
2007    VALUES (1, 13, 11, 'row6');
2008
2009-- Ordinary table
2010INSERT INTO rule_and_refint_t3
2011    VALUES (1, 13, 11, 'row6')
2012ON CONFLICT
2013    DO NOTHING;
2014
2015-- rule not fired, so fk violation
2016INSERT INTO rule_and_refint_t3
2017    VALUES (1, 13, 11, 'row6')
2018ON CONFLICT (id3a, id3b, id3c)
2019    DO UPDATE SET
2020        id3b = excluded.id3b;
2021
2022-- rule fired, so unsupported
2023INSERT INTO shoelace
2024    VALUES ('sl9', 0, 'pink', 35.0, 'inch', 0.0)
2025ON CONFLICT (sl_name)
2026    DO UPDATE SET
2027        sl_avail = excluded.sl_avail;
2028
2029CREATE RULE rule_and_refint_t3_ins AS ON INSERT TO rule_and_refint_t3 WHERE (EXISTS (
2030        SELECT
2031            1 FROM
2032            rule_and_refint_t3 WHERE (((rule_and_refint_t3.id3a = NEW.id3a)
2033                AND (rule_and_refint_t3.id3b = NEW.id3b))
2034            AND (rule_and_refint_t3.id3c = NEW.id3c))))
2035    DO INSTEAD
2036    UPDATE
2037        rule_and_refint_t3 SET
2038        data = NEW.data WHERE (((rule_and_refint_t3.id3a = NEW.id3a)
2039            AND (rule_and_refint_t3.id3b = NEW.id3b))
2040        AND (rule_and_refint_t3.id3c = NEW.id3c));
2041
2042INSERT INTO rule_and_refint_t3
2043    VALUES (1, 11, 13, 'row7');
2044
2045INSERT INTO rule_and_refint_t3
2046    VALUES (1, 13, 11, 'row8');
2047
2048--
2049-- disallow dropping a view's rule (bug #5072)
2050--
2051CREATE VIEW rules_fooview AS
2052SELECT
2053    'rules_foo'::text;
2054
2055DROP RULE "_RETURN" ON rules_fooview;
2056
2057DROP VIEW rules_fooview;
2058
2059--
2060-- test conversion of table to view (needed to load some pg_dump files)
2061--
2062CREATE TABLE rules_fooview (
2063    x int,
2064    y text
2065);
2066
2067SELECT
2068    xmin,
2069    *
2070FROM
2071    rules_fooview;
2072
2073CREATE RULE "_RETURN" AS ON
2074SELECT
2075    TO rules_fooview
2076        DO INSTEAD
2077        SELECT
2078            1 AS x,
2079            'aaa'::text AS y;
2080
2081SELECT
2082    *
2083FROM
2084    rules_fooview;
2085
2086SELECT
2087    xmin,
2088    *
2089FROM
2090    rules_fooview;
2091
2092-- fail, views don't have such a column
2093SELECT
2094    reltoastrelid,
2095    relkind,
2096    relfrozenxid
2097FROM
2098    pg_class
2099WHERE
2100    oid = 'rules_fooview'::regclass;
2101
2102DROP VIEW rules_fooview;
2103
2104-- trying to convert a partitioned table to view is not allowed
2105CREATE TABLE rules_fooview (
2106    x int,
2107    y text
2108)
2109PARTITION BY LIST (x);
2110
2111CREATE RULE "_RETURN" AS ON
2112SELECT
2113    TO rules_fooview
2114        DO INSTEAD
2115        SELECT
2116            1 AS x,
2117            'aaa'::text AS y;
2118
2119-- nor can one convert a partition to view
2120CREATE TABLE rules_fooview_part PARTITION OF rules_fooview
2121FOR VALUES IN (1);
2122
2123CREATE RULE "_RETURN" AS ON
2124SELECT
2125    TO rules_fooview_part
2126        DO INSTEAD
2127        SELECT
2128            1 AS x,
2129            'aaa'::text AS y;
2130
2131--
2132-- check for planner problems with complex inherited UPDATES
2133--
2134CREATE TABLE id (
2135    id serial PRIMARY KEY,
2136    name text
2137);
2138
2139-- currently, must respecify PKEY for each inherited subtable
2140CREATE TABLE test_1 (
2141    id integer PRIMARY KEY
2142)
2143INHERITS (
2144    id
2145);
2146
2147CREATE TABLE test_2 (
2148    id integer PRIMARY KEY
2149)
2150INHERITS (
2151    id
2152);
2153
2154CREATE TABLE test_3 (
2155    id integer PRIMARY KEY
2156)
2157INHERITS (
2158    id
2159);
2160
2161INSERT INTO test_1 (name)
2162    VALUES ('Test 1');
2163
2164INSERT INTO test_1 (name)
2165    VALUES ('Test 2');
2166
2167INSERT INTO test_2 (name)
2168    VALUES ('Test 3');
2169
2170INSERT INTO test_2 (name)
2171    VALUES ('Test 4');
2172
2173INSERT INTO test_3 (name)
2174    VALUES ('Test 5');
2175
2176INSERT INTO test_3 (name)
2177    VALUES ('Test 6');
2178
2179CREATE VIEW id_ordered AS
2180SELECT
2181    *
2182FROM
2183    id
2184ORDER BY
2185    id;
2186
2187CREATE RULE update_id_ordered AS ON UPDATE
2188    TO id_ordered
2189        DO INSTEAD
2190        UPDATE
2191            id SET
2192            name = NEW.name WHERE
2193            id = OLD.id;
2194
2195SELECT
2196    *
2197FROM
2198    id_ordered;
2199
2200UPDATE
2201    id_ordered
2202SET
2203    name = 'update 2'
2204WHERE
2205    id = 2;
2206
2207UPDATE
2208    id_ordered
2209SET
2210    name = 'update 4'
2211WHERE
2212    id = 4;
2213
2214UPDATE
2215    id_ordered
2216SET
2217    name = 'update 5'
2218WHERE
2219    id = 5;
2220
2221SELECT
2222    *
2223FROM
2224    id_ordered;
2225
2226DROP TABLE id CASCADE;
2227
2228--
2229-- check corner case where an entirely-dummy subplan is created by
2230-- constraint exclusion
2231--
2232CREATE temp TABLE t1 (
2233    a integer PRIMARY KEY
2234);
2235
2236CREATE temp TABLE t1_1 (
2237    CHECK (a >= 0 AND a < 10)
2238)
2239INHERITS (
2240    t1
2241);
2242
2243CREATE temp TABLE t1_2 (
2244    CHECK (a >= 10 AND a < 20)
2245)
2246INHERITS (
2247    t1
2248);
2249
2250CREATE RULE t1_ins_1 AS ON INSERT TO t1 WHERE
2251    NEW.a >= 0
2252    AND NEW.a < 10
2253        DO INSTEAD
2254        INSERT INTO t1_1 VALUES (NEW.a);
2255
2256CREATE RULE t1_ins_2 AS ON INSERT TO t1 WHERE
2257    NEW.a >= 10
2258    AND NEW.a < 20
2259        DO INSTEAD
2260        INSERT INTO t1_2 VALUES (NEW.a);
2261
2262CREATE RULE t1_upd_1 AS ON UPDATE
2263    TO t1 WHERE
2264    OLD.a >= 0
2265    AND OLD.a < 10
2266        DO INSTEAD
2267        UPDATE
2268            t1_1 SET
2269            a = NEW.a WHERE
2270            a = OLD.a;
2271
2272CREATE RULE t1_upd_2 AS ON UPDATE
2273    TO t1 WHERE
2274    OLD.a >= 10
2275    AND OLD.a < 20
2276        DO INSTEAD
2277        UPDATE
2278            t1_2 SET
2279            a = NEW.a WHERE
2280            a = OLD.a;
2281
2282SET constraint_exclusion = ON;
2283
2284INSERT INTO t1
2285SELECT
2286    *
2287FROM
2288    generate_series(5, 19, 1) g;
2289
2290UPDATE
2291    t1
2292SET
2293    a = 4
2294WHERE
2295    a = 5;
2296
2297SELECT
2298    *
2299FROM
2300    ONLY t1;
2301
2302SELECT
2303    *
2304FROM
2305    ONLY t1_1;
2306
2307SELECT
2308    *
2309FROM
2310    ONLY t1_2;
2311
2312RESET constraint_exclusion;
2313
2314-- test various flavors of pg_get_viewdef()
2315SELECT
2316    pg_get_viewdef('shoe'::regclass) AS unpretty;
2317
2318SELECT
2319    pg_get_viewdef('shoe'::regclass, TRUE) AS pretty;
2320
2321SELECT
2322    pg_get_viewdef('shoe'::regclass, 0) AS prettier;
2323
2324--
2325-- check multi-row VALUES in rules
2326--
2327CREATE TABLE rules_src (
2328    f1 int,
2329    f2 int
2330);
2331
2332CREATE TABLE rules_log (
2333    f1 int,
2334    f2 int,
2335    tag text
2336);
2337
2338INSERT INTO rules_src
2339    VALUES (1, 2), (11, 12);
2340
2341CREATE RULE r1 AS ON UPDATE
2342    TO rules_src
2343        DO ALSO
2344        INSERT INTO rules_log VALUES (OLD.*, 'old'), (NEW.*, 'new');
2345
2346UPDATE
2347    rules_src
2348SET
2349    f2 = f2 + 1;
2350
2351UPDATE
2352    rules_src
2353SET
2354    f2 = f2 * 10;
2355
2356SELECT
2357    *
2358FROM
2359    rules_src;
2360
2361SELECT
2362    *
2363FROM
2364    rules_log;
2365
2366CREATE RULE r2 AS ON UPDATE
2367    TO rules_src
2368        DO ALSO
2369    VALUES (OLD.*,
2370        'old'),
2371    (NEW.*,
2372        'new');
2373
2374UPDATE
2375    rules_src
2376SET
2377    f2 = f2 / 10;
2378
2379SELECT
2380    *
2381FROM
2382    rules_src;
2383
2384SELECT
2385    *
2386FROM
2387    rules_log;
2388
2389CREATE RULE r3 AS ON DELETE TO rules_src DO NOTIFY rules_src_deletion;
2390
2391\d+ rules_src
2392--
2393-- Ensure an aliased target relation for insert is correctly deparsed.
2394--
2395CREATE RULE r4 AS ON INSERT TO rules_src
2396    DO INSTEAD
2397    INSERT INTO rules_log AS trgt
2398    SELECT
2399        NEW.* RETURNING
2400        trgt.f1,
2401        trgt.f2;
2402
2403CREATE RULE r5 AS ON UPDATE
2404    TO rules_src
2405        DO INSTEAD
2406        UPDATE
2407            rules_log AS trgt SET
2408            tag = 'updated' WHERE
2409            trgt.f1 = NEW.f1;
2410
2411\d+ rules_src
2412--
2413-- check alter rename rule
2414--
2415CREATE TABLE rule_t1 (
2416    a int
2417);
2418
2419CREATE VIEW rule_v1 AS
2420SELECT
2421    *
2422FROM
2423    rule_t1;
2424
2425CREATE RULE InsertRule AS ON INSERT TO rule_v1
2426    DO INSTEAD
2427    INSERT INTO rule_t1 VALUES (NEW.a);
2428
2429ALTER RULE InsertRule ON rule_v1 RENAME TO NewInsertRule;
2430
2431INSERT INTO rule_v1
2432    VALUES (1);
2433
2434SELECT
2435    *
2436FROM
2437    rule_v1;
2438
2439\d+ rule_v1
2440--
2441-- error conditions for alter rename rule
2442--
2443ALTER RULE InsertRule ON rule_v1 RENAME TO NewInsertRule;
2444
2445-- doesn't exist
2446ALTER RULE NewInsertRule ON rule_v1 RENAME TO "_RETURN";
2447
2448-- already exists
2449ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc;
2450
2451-- ON SELECT rule cannot be renamed
2452DROP VIEW rule_v1;
2453
2454DROP TABLE rule_t1;
2455
2456--
2457-- check display of VALUES in view definitions
2458--
2459CREATE VIEW rule_v1 AS
2460VALUES (1,
2461    2);
2462
2463\d+ rule_v1
2464DROP VIEW rule_v1;
2465
2466CREATE VIEW rule_v1 (x) AS
2467VALUES (1,
2468    2);
2469
2470\d+ rule_v1
2471DROP VIEW rule_v1;
2472
2473CREATE VIEW rule_v1 (x) AS
2474SELECT
2475    *
2476FROM (
2477    VALUES (1, 2)) v;
2478
2479\d+ rule_v1
2480DROP VIEW rule_v1;
2481
2482CREATE VIEW rule_v1 (x) AS
2483SELECT
2484    *
2485FROM (
2486    VALUES (1, 2)) v (q, w);
2487
2488\d+ rule_v1
2489DROP VIEW rule_v1;
2490
2491--
2492-- Check DO INSTEAD rules with ON CONFLICT
2493--
2494CREATE TABLE hats (
2495    hat_name char(10) PRIMARY KEY,
2496    hat_color char(10) -- hat color
2497);
2498
2499CREATE TABLE hat_data (
2500    hat_name char(10),
2501    hat_color char(10) -- hat color
2502);
2503
2504CREATE UNIQUE INDEX hat_data_unique_idx ON hat_data (hat_name COLLATE "C" bpchar_pattern_ops);
2505
2506-- DO NOTHING with ON CONFLICT
2507CREATE RULE hat_nosert AS ON INSERT TO hats
2508    DO INSTEAD
2509    INSERT INTO hat_data VALUES (NEW.hat_name, NEW.hat_color)
2510ON CONFLICT (hat_name COLLATE "C" bpchar_pattern_ops)
2511WHERE
2512    hat_color = 'green'
2513        DO NOTHING RETURNING
2514        *;
2515
2516SELECT
2517    definition
2518FROM
2519    pg_rules
2520WHERE
2521    tablename = 'hats'
2522ORDER BY
2523    rulename;
2524
2525-- Works (projects row)
2526INSERT INTO hats
2527    VALUES ('h7', 'black')
2528RETURNING
2529    *;
2530
2531-- Works (does nothing)
2532INSERT INTO hats
2533    VALUES ('h7', 'black')
2534RETURNING
2535    *;
2536
2537SELECT
2538    tablename,
2539    rulename,
2540    definition
2541FROM
2542    pg_rules
2543WHERE
2544    tablename = 'hats';
2545
2546DROP RULE hat_nosert ON hats;
2547
2548-- DO NOTHING without ON CONFLICT
2549CREATE RULE hat_nosert_all AS ON INSERT TO hats
2550    DO INSTEAD
2551    INSERT INTO hat_data VALUES (NEW.hat_name, NEW.hat_color)
2552ON CONFLICT
2553    DO NOTHING RETURNING
2554    *;
2555
2556SELECT
2557    definition
2558FROM
2559    pg_rules
2560WHERE
2561    tablename = 'hats'
2562ORDER BY
2563    rulename;
2564
2565DROP RULE hat_nosert_all ON hats;
2566
2567-- Works (does nothing)
2568INSERT INTO hats
2569    VALUES ('h7', 'black')
2570RETURNING
2571    *;
2572
2573-- DO UPDATE with a WHERE clause
2574CREATE RULE hat_upsert AS ON INSERT TO hats
2575    DO INSTEAD
2576    INSERT INTO hat_data VALUES (NEW.hat_name, NEW.hat_color)
2577ON CONFLICT (hat_name)
2578    DO UPDATE SET
2579        hat_name = hat_data.hat_name, hat_color = excluded.hat_color WHERE
2580        excluded.hat_color <> 'forbidden'
2581        AND hat_data.* != excluded.* RETURNING
2582        *;
2583
2584SELECT
2585    definition
2586FROM
2587    pg_rules
2588WHERE
2589    tablename = 'hats'
2590ORDER BY
2591    rulename;
2592
2593-- Works (does upsert)
2594INSERT INTO hats
2595    VALUES ('h8', 'black')
2596RETURNING
2597    *;
2598
2599SELECT
2600    *
2601FROM
2602    hat_data
2603WHERE
2604    hat_name = 'h8';
2605
2606INSERT INTO hats
2607    VALUES ('h8', 'white')
2608RETURNING
2609    *;
2610
2611SELECT
2612    *
2613FROM
2614    hat_data
2615WHERE
2616    hat_name = 'h8';
2617
2618INSERT INTO hats
2619    VALUES ('h8', 'forbidden')
2620RETURNING
2621    *;
2622
2623SELECT
2624    *
2625FROM
2626    hat_data
2627WHERE
2628    hat_name = 'h8';
2629
2630SELECT
2631    tablename,
2632    rulename,
2633    definition
2634FROM
2635    pg_rules
2636WHERE
2637    tablename = 'hats';
2638
2639-- ensure explain works for on insert conflict rules
2640EXPLAIN (
2641    COSTS OFF
2642) INSERT INTO hats
2643    VALUES ('h8', 'forbidden')
2644RETURNING
2645    *;
2646
2647-- ensure upserting into a rule, with a CTE (different offsets!) works
2648WITH data (
2649    hat_name,
2650    hat_color
2651) AS MATERIALIZED (
2652    VALUES (
2653            'h8', 'green'
2654),
2655        (
2656            'h9', 'blue'
2657),
2658        (
2659            'h7', 'forbidden'
2660))
2661INSERT INTO hats
2662SELECT
2663    *
2664FROM
2665    data
2666RETURNING
2667    *;
2668
2669EXPLAIN (
2670    COSTS OFF
2671) WITH data (hat_name,
2672    hat_color) AS MATERIALIZED (
2673    VALUES ('h8', 'green'),
2674        ('h9', 'blue'),
2675        ('h7', 'forbidden'))
2676INSERT INTO hats
2677SELECT
2678    *
2679FROM
2680    data
2681RETURNING
2682    *;
2683
2684SELECT
2685    *
2686FROM
2687    hat_data
2688WHERE
2689    hat_name IN ('h8', 'h9', 'h7')
2690ORDER BY
2691    hat_name;
2692
2693DROP RULE hat_upsert ON hats;
2694
2695DROP TABLE hats;
2696
2697DROP TABLE hat_data;
2698
2699-- test for pg_get_functiondef properly regurgitating SET parameters
2700-- Note that the function is kept around to stress pg_dump.
2701CREATE FUNCTION func_with_set_params ()
2702    RETURNS integer
2703    AS 'select 1;'
2704    LANGUAGE SQL
2705    SET search_path TO PG_CATALOG SET extra_float_digits TO 2 SET work_mem TO '4MB' SET datestyle TO iso, mdy SET local_preload_libraries TO "Mixed/Case", 'c:/''a"/path', '', '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789' IMMUTABLE STRICT;
2706
2707SELECT
2708    pg_get_functiondef('func_with_set_params()'::regprocedure);
2709
2710-- tests for pg_get_*def with invalid objects
2711SELECT
2712    pg_get_constraintdef(0);
2713
2714SELECT
2715    pg_get_functiondef(0);
2716
2717SELECT
2718    pg_get_indexdef(0);
2719
2720SELECT
2721    pg_get_ruledef(0);
2722
2723SELECT
2724    pg_get_statisticsobjdef (0);
2725
2726SELECT
2727    pg_get_triggerdef(0);
2728
2729SELECT
2730    pg_get_viewdef(0);
2731
2732SELECT
2733    pg_get_function_arguments(0);
2734
2735SELECT
2736    pg_get_function_identity_arguments(0);
2737
2738SELECT
2739    pg_get_function_result(0);
2740
2741SELECT
2742    pg_get_function_arg_default (0, 0);
2743
2744SELECT
2745    pg_get_function_arg_default ('pg_class'::regclass, 0);
2746
2747SELECT
2748    pg_get_partkeydef (0);
2749
2750-- test rename for a rule defined on a partitioned table
2751CREATE TABLE rules_parted_table (
2752    a int
2753)
2754PARTITION BY LIST (a);
2755
2756CREATE TABLE rules_parted_table_1 PARTITION OF rules_parted_table
2757FOR VALUES IN (1);
2758
2759CREATE RULE rules_parted_table_insert AS ON INSERT TO rules_parted_table
2760    DO INSTEAD
2761    INSERT INTO rules_parted_table_1 VALUES (NEW.*);
2762
2763ALTER RULE rules_parted_table_insert ON rules_parted_table RENAME TO rules_parted_table_insert_redirect;
2764
2765DROP TABLE rules_parted_table;
2766
2767--
2768-- Test enabling/disabling
2769--
2770CREATE TABLE ruletest1 (
2771    a int
2772);
2773
2774CREATE TABLE ruletest2 (
2775    b int
2776);
2777
2778CREATE RULE rule1 AS ON INSERT TO ruletest1
2779    DO INSTEAD
2780    INSERT INTO ruletest2 VALUES (NEW.*);
2781
2782INSERT INTO ruletest1
2783    VALUES (1);
2784
2785ALTER TABLE ruletest1 DISABLE RULE rule1;
2786
2787INSERT INTO ruletest1
2788    VALUES (2);
2789
2790ALTER TABLE ruletest1 ENABLE RULE rule1;
2791
2792SET session_replication_role = REPLICA;
2793
2794INSERT INTO ruletest1
2795    VALUES (3);
2796
2797ALTER TABLE ruletest1 ENABLE REPLICA RULE rule1;
2798
2799INSERT INTO ruletest1
2800    VALUES (4);
2801
2802RESET session_replication_role;
2803
2804INSERT INTO ruletest1
2805    VALUES (5);
2806
2807SELECT
2808    *
2809FROM
2810    ruletest1;
2811
2812SELECT
2813    *
2814FROM
2815    ruletest2;
2816
2817DROP TABLE ruletest1;
2818
2819DROP TABLE ruletest2;
2820
2821