-- -- RULES -- From Jan's original setup_ruletest.sql and run_ruletest.sql -- - thomas 1998-09-13 --
-- -- Tables and rules for the view test -- createtable rtest_t1 (a int4, b int4); createtable rtest_t2 (a int4, b int4); createtable rtest_t3 (a int4, b int4);
create view rtest_v1 asselect * from rtest_t1; create rule rtest_v1_ins asoninsertto rtest_v1 do instead insertinto rtest_t1 values (new.a, new.b); create rule rtest_v1_upd asonupdateto rtest_v1 do instead update rtest_t1 set a = new.a, b = new.b where a = old.a; create rule rtest_v1_del asondeleteto rtest_v1 do instead deletefrom rtest_t1 where a = old.a; -- Test comments
COMMENT ON RULE rtest_v1_bad ON rtest_v1 IS'bad rule';
COMMENT ON RULE rtest_v1_del ON rtest_v1 IS'delete rule';
COMMENT ON RULE rtest_v1_del ON rtest_v1 ISNULL; -- -- Tables and rules for the constraint update/delete test -- -- Note: -- Now that we have multiple action rule support, we check -- both possible syntaxes to define them (The last action -- can but must not have a semicolon at the end). -- createtable rtest_system (sysname text, sysdesc text); createtable rtest_interface (sysname text, ifname text); createtable rtest_person (pname text, pdesc text); createtable rtest_admin (pname text, sysname text);
create rule rtest_sys_upd asonupdateto rtest_system do also ( update rtest_interface set sysname = new.sysname where sysname = old.sysname; update rtest_admin set sysname = new.sysname where sysname = old.sysname
);
create rule rtest_sys_del asondeleteto rtest_system do also ( deletefrom rtest_interface where sysname = old.sysname; deletefrom rtest_admin where sysname = old.sysname;
);
create rule rtest_pers_upd asonupdateto rtest_person do also update rtest_admin set pname = new.pname where pname = old.pname;
create rule rtest_pers_del asondeleteto rtest_person do also deletefrom rtest_admin where pname = old.pname;
-- -- Tables and rules for the logging test -- createtable rtest_emp (ename char(20), salary numeric); createtable rtest_emplog (ename char(20), who name, action char(10), newsal numeric, oldsal numeric); createtable rtest_empmass (ename char(20), salary numeric);
-- -- Tables and rules for the multiple cascaded qualified instead -- rule test -- createtable rtest_t4 (a int4, b text); createtable rtest_t5 (a int4, b text); createtable rtest_t6 (a int4, b text); createtable rtest_t7 (a int4, b text); createtable rtest_t8 (a int4, b text); createtable rtest_t9 (a int4, b text);
create rule rtest_t4_ins1 asoninsertto rtest_t4 where new.a >= 10and new.a < 20 do instead insertinto rtest_t5 values (new.a, new.b);
create rule rtest_t4_ins2 asoninsertto rtest_t4 where new.a >= 20and new.a < 30 do insertinto rtest_t6 values (new.a, new.b);
create rule rtest_t5_ins asoninsertto rtest_t5 where new.a > 15 do insertinto rtest_t7 values (new.a, new.b);
create rule rtest_t6_ins asoninsertto rtest_t6 where new.a > 25 do instead insertinto rtest_t8 values (new.a, new.b);
-- -- Tables and rules for the rule fire order test -- -- As of PG 7.3, the rules should fire in order by name, regardless -- of INSTEAD attributes or creation order. -- createtable rtest_order1 (a int4); createtable rtest_order2 (a int4, b int4, c text);
create sequence rtest_seq;
create rule rtest_order_r3 asoninsertto rtest_order1 do instead insertinto rtest_order2 values (new.a, nextval('rtest_seq'), 'rule 3 - this should run 3rd');
create rule rtest_order_r4 asoninsertto rtest_order1 where a < 100 do instead insertinto rtest_order2 values (new.a, nextval('rtest_seq'), 'rule 4 - this should run 4th');
create rule rtest_order_r2 asoninsertto rtest_order1 do insertinto rtest_order2 values (new.a, nextval('rtest_seq'), 'rule 2 - this should run 2nd');
create rule rtest_order_r1 asoninsertto rtest_order1 do instead insertinto rtest_order2 values (new.a, nextval('rtest_seq'), 'rule 1 - this should run 1st');
-- -- Tables and rules for the instead nothing test -- createtable rtest_nothn1 (a int4, b text); createtable rtest_nothn2 (a int4, b text); createtable rtest_nothn3 (a int4, b text); createtable rtest_nothn4 (a int4, b text);
create rule rtest_nothn_r1 asoninsertto rtest_nothn1 where new.a >= 10and new.a < 20 do instead nothing;
create rule rtest_nothn_r2 asoninsertto rtest_nothn1 where new.a >= 30and new.a < 40 do instead nothing;
create rule rtest_nothn_r3 asoninsertto rtest_nothn2 where new.a >= 100 do instead insertinto rtest_nothn3 values (new.a, new.b);
create rule rtest_nothn_r4 asoninsertto rtest_nothn2
do instead nothing;
-- -- Tests on a view that is select * of a table -- and has insert/update/delete instead rules to -- behave close like the real table. --
-- -- We need test date later -- insertinto rtest_t2 values (1, 21); insertinto rtest_t2 values (2, 22); insertinto rtest_t2 values (3, 23);
-- delete with constant expression deletefrom rtest_v1 where a = 1; select * from rtest_v1; insertinto rtest_v1 values (1, 11); deletefrom rtest_v1 where b = 12; select * from rtest_v1; insertinto rtest_v1 values (2, 12); insertinto rtest_v1 values (2, 13); select * from rtest_v1;
** Remember the delete rule on rtest_v1: It says
** DO INSTEAD DELETEFROM rtest_t1 WHERE a = old.a
** So this time both rows with a = 2 must get deleted
\p
\r deletefrom rtest_v1 where b = 12; select * from rtest_v1; deletefrom rtest_v1;
-- insert select insertinto rtest_v1 select * from rtest_t2; select * from rtest_v1; deletefrom rtest_v1;
-- same with swapped targetlist insertinto rtest_v1 (b, a) select b, a from rtest_t2; select * from rtest_v1;
-- now with only one target attribute insertinto rtest_v1 (a) select a from rtest_t3; select * from rtest_v1; select * from rtest_v1 where b isnull;
-- let attribute a differ (must be done on rtest_t1 - see above) update rtest_t1 set a = a + 10where b isnull; deletefrom rtest_v1 where b isnull; select * from rtest_v1;
-- now updates with constant expression update rtest_v1 set b = 42where a = 2; select * from rtest_v1; update rtest_v1 set b = 99where b = 42; select * from rtest_v1; update rtest_v1 set b = 88where b < 50; select * from rtest_v1; deletefrom rtest_v1; insertinto rtest_v1 select rtest_t2.a, rtest_t3.b from rtest_t2, rtest_t3 where rtest_t2.a = rtest_t3.a; select * from rtest_v1;
-- updates in a mergejoin update rtest_v1 set b = rtest_t2.b from rtest_t2 where rtest_v1.a = rtest_t2.a; select * from rtest_v1; insertinto rtest_v1 select * from rtest_t3; select * from rtest_v1; update rtest_t1 set a = a + 10where b > 30; select * from rtest_v1; update rtest_v1 set a = rtest_t3.a + 20from rtest_t3 where rtest_v1.b = rtest_t3.b; select * from rtest_v1;
-- -- Test for constraint updates/deletes -- insertinto rtest_system values ('orion', 'Linux Jan Wieck'); insertinto rtest_system values ('notjw', 'WinNT Jan Wieck (notebook)'); insertinto rtest_system values ('neptun', 'Fileserver');
update rtest_system set sysname = 'pluto'where sysname = 'neptun';
select * from rtest_interface; select * from rtest_admin;
update rtest_person set pname = 'jwieck'where pdesc = 'Jan Wieck';
-- Note: use ORDER BY here to ensure consistent output across all systems. -- The above UPDATE affects two rows with equal keys, so they could be -- updated in either order depending on the whim of the local qsort().
select * from rtest_admin orderby pname, sysname;
deletefrom rtest_system where sysname = 'orion';
select * from rtest_interface; select * from rtest_admin;
select ename, who = current_useras"matches user", action, newsal, oldsal from rtest_emplog orderby ename, action, newsal; insertinto rtest_empmass values ('meyer', '4000.00'); insertinto rtest_empmass values ('maier', '5000.00'); insertinto rtest_empmass values ('mayr', '6000.00'); insertinto rtest_emp select * from rtest_empmass; select ename, who = current_useras"matches user", action, newsal, oldsal from rtest_emplog orderby ename, action, newsal; update rtest_empmass set salary = salary + '1000.00'; update rtest_emp set salary = rtest_empmass.salary from rtest_empmass where rtest_emp.ename = rtest_empmass.ename; select ename, who = current_useras"matches user", action, newsal, oldsal from rtest_emplog orderby ename, action, newsal; deletefrom rtest_emp using rtest_empmass where rtest_emp.ename = rtest_empmass.ename; select ename, who = current_useras"matches user", action, newsal, oldsal from rtest_emplog orderby ename, action, newsal;
-- -- Multiple cascaded qualified instead rule test -- insertinto rtest_t4 values (1, 'Record should go to rtest_t4'); insertinto rtest_t4 values (2, 'Record should go to rtest_t4'); insertinto rtest_t4 values (10, 'Record should go to rtest_t5'); insertinto rtest_t4 values (15, 'Record should go to rtest_t5'); insertinto rtest_t4 values (19, 'Record should go to rtest_t5 and t7'); insertinto rtest_t4 values (20, 'Record should go to rtest_t4 and t6'); insertinto rtest_t4 values (26, 'Record should go to rtest_t4 and t8'); insertinto rtest_t4 values (28, 'Record should go to rtest_t4 and t8'); insertinto rtest_t4 values (30, 'Record should go to rtest_t4'); insertinto rtest_t4 values (40, 'Record should go to rtest_t4');
select * from rtest_t4; select * from rtest_t5; select * from rtest_t6; select * from rtest_t7; select * from rtest_t8;
insertinto rtest_t9 values (1, 'Record should go to rtest_t4'); insertinto rtest_t9 values (2, 'Record should go to rtest_t4'); insertinto rtest_t9 values (10, 'Record should go to rtest_t5'); insertinto rtest_t9 values (15, 'Record should go to rtest_t5'); insertinto rtest_t9 values (19, 'Record should go to rtest_t5 and t7'); insertinto rtest_t9 values (20, 'Record should go to rtest_t4 and t6'); insertinto rtest_t9 values (26, 'Record should go to rtest_t4 and t8'); insertinto rtest_t9 values (28, 'Record should go to rtest_t4 and t8'); insertinto rtest_t9 values (30, 'Record should go to rtest_t4'); insertinto rtest_t9 values (40, 'Record should go to rtest_t4');
insertinto rtest_t4 select * from rtest_t9 where a < 20;
select * from rtest_t4; select * from rtest_t5; select * from rtest_t6; select * from rtest_t7; select * from rtest_t8;
insertinto rtest_t4 select * from rtest_t9 where b ~ 'and t8';
select * from rtest_t4; select * from rtest_t5; select * from rtest_t6; select * from rtest_t7; select * from rtest_t8;
insertinto rtest_t4 select a + 1, b from rtest_t9 where a in (20, 30, 40);
select * from rtest_t4; select * from rtest_t5; select * from rtest_t6; select * from rtest_t7; select * from rtest_t8;
-- -- Check that the ordering of rules fired is correct -- insertinto rtest_order1 values (1); select * from rtest_order2;
insertinto rtest_nothn2 select * from rtest_nothn4;
select * from rtest_nothn2; select * from rtest_nothn3;
createtable rtest_view1 (a int4, b text, v bool); createtable rtest_view2 (a int4); createtable rtest_view3 (a int4, b text); createtable rtest_view4 (a int4, b text, c int4); create view rtest_vview1 asselect a, b from rtest_view1 X where0 < (select count(*) from rtest_view2 Y where Y.a = X.a); create view rtest_vview2 asselect a, b from rtest_view1 where v; create view rtest_vview3 asselect a, b from rtest_vview2 X where0 < (select count(*) from rtest_view2 Y where Y.a = X.a); create view rtest_vview4 asselect X.a, X.b, count(Y.a) as refcount from rtest_view1 X, rtest_view2 Y where X.a = Y.a groupby X.a, X.b; create function rtest_viewfunc1(int4) returns int4as 'select count(*)::int4 from rtest_view2 where a = $1'
language sql; create view rtest_vview5 asselect a, b, rtest_viewfunc1(a) as refcount from rtest_view1;
select * from rtest_vview1; select * from rtest_vview2; select * from rtest_vview3; select * from rtest_vview4 orderby a, b; select * from rtest_vview5;
insertinto rtest_view3 select * from rtest_vview1 where a < 7; select * from rtest_view3; deletefrom rtest_view3;
insertinto rtest_view3 select * from rtest_vview2 where a != 5and b !~ '2'; select * from rtest_view3; deletefrom rtest_view3;
insertinto rtest_view3 select * from rtest_vview3; select * from rtest_view3; deletefrom rtest_view3;
insertinto rtest_view4 select * from rtest_vview4 where3 > refcount; select * from rtest_view4 orderby a, b; deletefrom rtest_view4;
insertinto rtest_view4 select * from rtest_vview5 where a > 2and refcount = 0; select * from rtest_view4; deletefrom rtest_view4; -- -- Test for computations in views -- createtable rtest_comp (
part text,
unit char(4),
size float
);
createtable rtest_unitfact (
unit char(4),
factor float
);
create view rtest_vcomp as select X.part, (X.size * Y.factor) as size_in_cm from rtest_comp X, rtest_unitfact Y where X.unit = Y.unit;
select * from rtest_vcomp where size_in_cm > 10.0orderby size_in_cm using >;
-- -- In addition run the (slightly modified) queries from the -- programmers manual section on the rule system. -- CREATETABLE shoe_data (
shoename char(10), -- primary key
sh_avail integer, -- available # of pairs
slcolor char(10), -- preferred shoelace color
slminlen float, -- minimum shoelace length
slmaxlen float, -- maximum shoelace length
slunit char(8) -- length unit
);
CREATETABLE shoelace_data (
sl_name char(10), -- primary key
sl_avail integer, -- available # of pairs
sl_color char(10), -- shoelace color
sl_len float, -- shoelace length
sl_unit char(8) -- length unit
);
CREATETABLE unit (
un_name char(8), -- the primary key
un_fact float-- factor to transform to cm
);
CREATE VIEW shoe AS SELECT sh.shoename,
sh.sh_avail,
sh.slcolor,
sh.slminlen,
sh.slminlen * un.un_fact AS slminlen_cm,
sh.slmaxlen,
sh.slmaxlen * un.un_fact AS slmaxlen_cm,
sh.slunit FROM shoe_data sh, unit un WHERE sh.slunit = un.un_name;
CREATE VIEW shoelace AS SELECT s.sl_name,
s.sl_avail,
s.sl_color,
s.sl_len,
s.sl_unit,
s.sl_len * u.un_fact AS sl_len_cm FROM shoelace_data s, unit u WHERE s.sl_unit = u.un_name;
CREATE VIEW shoe_ready AS SELECT rsh.shoename,
rsh.sh_avail,
rsl.sl_name,
rsl.sl_avail,
int4smaller(rsh.sh_avail, rsl.sl_avail) AS total_avail FROM shoe rsh, shoelace rsl WHERE rsl.sl_color = rsh.slcolor AND rsl.sl_len_cm >= rsh.slminlen_cm AND rsl.sl_len_cm <= rsh.slmaxlen_cm;
INSERTINTO unit VALUES ('cm', 1.0); INSERTINTO unit VALUES ('m', 100.0); INSERTINTO unit VALUES ('inch', 2.54);
-- SELECTs in doc SELECT * FROM shoelace ORDERBY sl_name; SELECT * FROM shoe_ready WHERE total_avail >= 2ORDERBY1;
CREATETABLE shoelace_log (
sl_name char(10), -- shoelace changed
sl_avail integer, -- new available value
log_who name, -- who did it
log_when timestamp -- when
);
-- Want "log_who" to be CURRENT_USER, -- but that is non-portable for the regression test -- - thomas 1999-02-21
CREATE RULE log_shoelace ASONUPDATETO shoelace_data WHERE NEW.sl_avail != OLD.sl_avail
DO INSERTINTO shoelace_log VALUES (
NEW.sl_name,
NEW.sl_avail, 'Al Bundy', 'epoch'
);
UPDATE shoelace_data SET sl_avail = 6WHERE sl_name = 'sl7';
insertinto shoelace_ok select * from shoelace_arrive;
SELECT * FROM shoelace ORDERBY sl_name;
SELECT * FROM shoelace_log ORDERBY sl_name;
CREATE VIEW shoelace_obsolete AS SELECT * FROM shoelace WHERENOTEXISTS
(SELECT shoename FROM shoe WHERE slcolor = sl_color);
CREATE VIEW shoelace_candelete AS SELECT * FROM shoelace_obsolete WHERE sl_avail = 0;
insertinto shoelace values ('sl9', 0, 'pink', 35.0, 'inch', 0.0); insertinto shoelace values ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0); -- Unsupported (even though a similar updatable view construct is) insertinto shoelace values ('sl10', 1000, 'magenta', 40.0, 'inch', 0.0) on conflict do nothing;
SELECT * FROM shoelace_obsolete ORDERBY sl_len_cm; SELECT * FROM shoelace_candelete;
DELETEFROM shoelace WHEREEXISTS
(SELECT * FROM shoelace_candelete WHERE sl_name = shoelace.sl_name);
SELECT * FROM shoelace ORDERBY sl_name;
SELECT * FROM shoe ORDERBY shoename; SELECT count(*) FROM shoe;
-- -- Simple test of qualified ON INSERT ... this did not work in 7.0 ... -- createtable rules_foo (f1 int); createtable rules_foo2 (f1 int);
create rule rules_foorule asoninsertto rules_foo where f1 < 100
do instead nothing;
insertinto rules_foo values(1); insertinto rules_foo values(1001); select * from rules_foo;
drop rule rules_foorule on rules_foo;
-- this should fail because f1 is not exposed for unqualified reference: create rule rules_foorule asoninsertto rules_foo where f1 < 100
do instead insertinto rules_foo2 values (f1); -- this is the correct way: create rule rules_foorule asoninsertto rules_foo where f1 < 100
do instead insertinto rules_foo2 values (new.f1);
select * from rules_foo; select * from rules_foo2;
drop rule rules_foorule on rules_foo; droptable rules_foo; droptable rules_foo2;
-- -- Test rules containing INSERT ... SELECT, which is a very ugly special -- case as of 7.1. Example is based on bug report from Joel Burton. -- createtable pparent (pid int, txt text); insertinto pparent values (1,'parent1'); insertinto pparent values (2,'parent2');
create view vview as select pparent.pid, txt, descrip from
pparent leftjoin cchild using (pid);
create rule rrule as onupdateto vview do instead
( insertinto cchild (pid, descrip) select old.pid, new.descrip where old.descrip isnull; update cchild set descrip = new.descrip where cchild.pid = old.pid;
);
select * from vview; update vview set descrip='test1'where pid=1; select * from vview; update vview set descrip='test2'where pid=2; select * from vview; update vview set descrip='test3'where pid=3; select * from vview; select * from cchild;
drop rule rrule on vview; drop view vview; droptable pparent; droptable cchild;
-- -- Check that ruleutils are working --
-- temporarily disable fancy output, so view changes create less diff noise
\a\t
SELECT viewname, definition FROM pg_views WHERE schemaname = 'pg_catalog' ORDERBY viewname;
SELECT tablename, rulename, definition FROM pg_rules WHERE schemaname = 'pg_catalog' ORDERBY tablename, rulename;
-- restore normal output mode
\a\t
-- -- CREATE OR REPLACE RULE --
CREATETABLE ruletest_tbl (a int, b int); CREATETABLE ruletest_tbl2 (a int, b int);
-- Check that rewrite rules splitting one INSERT into multiple -- conditional statements does not disable FK checking. createtable rule_and_refint_t1 (
id1a integer,
id1b integer,
insertinto rule_and_refint_t3 values (1, 11, 11, 'row1'); insertinto rule_and_refint_t3 values (1, 11, 12, 'row2'); insertinto rule_and_refint_t3 values (1, 12, 11, 'row3'); insertinto rule_and_refint_t3 values (1, 12, 12, 'row4'); insertinto rule_and_refint_t3 values (1, 11, 13, 'row5'); insertinto rule_and_refint_t3 values (1, 13, 11, 'row6'); -- Ordinary table insertinto rule_and_refint_t3 values (1, 13, 11, 'row6') on conflict do nothing; -- rule not fired, so fk violation insertinto rule_and_refint_t3 values (1, 13, 11, 'row6') on conflict (id3a, id3b, id3c) do update set id3b = excluded.id3b; -- rule fired, so unsupported insertinto shoelace values ('sl9', 0, 'pink', 35.0, 'inch', 0.0) on conflict (sl_name) do update set sl_avail = excluded.sl_avail;
create rule rule_and_refint_t3_ins asoninsertto rule_and_refint_t3 where (exists (select1from rule_and_refint_t3 where (((rule_and_refint_t3.id3a = new.id3a) and (rule_and_refint_t3.id3b = new.id3b)) and (rule_and_refint_t3.id3c = new.id3c))))
do instead update rule_and_refint_t3 set data = new.data where (((rule_and_refint_t3.id3a = new.id3a) and (rule_and_refint_t3.id3b = new.id3b)) and (rule_and_refint_t3.id3c = new.id3c));
-- -- disallow dropping a view's rule (bug #5072) --
create view rules_fooview asselect'rules_foo'::text; drop rule "_RETURN"on rules_fooview; drop view rules_fooview;
-- -- We used to allow converting a table to a view by creating a "_RETURN" -- rule for it, but no more. --
createtable rules_fooview (x int, y text); create rule "_RETURN"asonselectto rules_fooview do instead select1as x, 'aaa'::text as y; droptable rules_fooview;
-- likewise, converting a partitioned table or partition to view is not allowed createtable rules_fooview (x int, y text) partition by list (x); create rule "_RETURN"asonselectto rules_fooview do instead select1as x, 'aaa'::text as y;
createtable rules_fooview_part partition of rules_fooview forvaluesin (1); create rule "_RETURN"asonselectto rules_fooview_part do instead select1as x, 'aaa'::text as y;
droptable rules_fooview;
-- -- check for planner problems with complex inherited UPDATES --
createtable id (id serial primarykey, name text); -- currently, must respecify PKEY for each inherited subtable createtable test_1 (id integerprimarykey) inherits (id); createtable test_2 (id integerprimarykey) inherits (id); createtable test_3 (id integerprimarykey) inherits (id);
create view id_ordered asselect * from id orderby id;
create rule update_id_ordered asonupdateto id_ordered
do instead update id set name = new.name where id = old.id;
select * from id_ordered; update id_ordered set name = 'update 2'where id = 2; update id_ordered set name = 'update 4'where id = 4; update id_ordered set name = 'update 5'where id = 5; select * from id_ordered;
droptable id cascade;
-- -- check corner case where an entirely-dummy subplan is created by -- constraint exclusion --
create temp table t1 (a integerprimarykey);
create temp table t1_1 (check (a >= 0and a < 10)) inherits (t1); create temp table t1_2 (check (a >= 10and a < 20)) inherits (t1);
create rule t1_ins_1 asoninsertto t1 where new.a >= 0and new.a < 10
do instead insertinto t1_1 values (new.a); create rule t1_ins_2 asoninsertto t1 where new.a >= 10and new.a < 20
do instead insertinto t1_2 values (new.a);
create rule t1_upd_1 asonupdateto t1 where old.a >= 0and old.a < 10
do instead update t1_1 set a = new.a where a = old.a; create rule t1_upd_2 asonupdateto t1 where old.a >= 10and old.a < 20
do instead update t1_2 set a = new.a where a = old.a;
set constraint_exclusion = on;
insertinto t1 select * from generate_series(5,19,1) g; update t1 set a = 4where a = 5;
select * from only t1; select * from only t1_1; select * from only t1_2;
reset constraint_exclusion;
-- test FOR UPDATE in rules
createtable rules_base(f1 int, f2 int); insertinto rules_base values(1,2), (11,12); create rule r1 asonupdateto rules_base do instead select * from rules_base where f1 = 1forupdate; update rules_base set f2 = f2 + 1; createorreplace rule r1 asonupdateto rules_base do instead select * from rules_base where f1 = 11forupdate of rules_base; update rules_base set f2 = f2 + 1; createorreplace rule r1 asonupdateto rules_base do instead select * from rules_base where f1 = 11forupdate of old; -- error droptable rules_base;
-- test various flavors of pg_get_viewdef()
select pg_get_viewdef('shoe'::regclass) as unpretty; select pg_get_viewdef('shoe'::regclass,true) as pretty; select pg_get_viewdef('shoe'::regclass,0) as prettier;
-- -- check multi-row VALUES in rules --
createtable rules_src(f1 int, f2 intdefault0); createtable rules_log(f1 int, f2 int, tag text, id serial); insertinto rules_src values(1,2), (11,12); create rule r1 asonupdateto rules_src do also insertinto rules_log values(old.*, 'old', default), (new.*, 'new', default); update rules_src set f2 = f2 + 1; update rules_src set f2 = f2 * 10; select * from rules_src; select * from rules_log; create rule r2 asonupdateto rules_src do also values(old.*, 'old'), (new.*, 'new'); update rules_src set f2 = f2 / 10; create rule r3 asoninsertto rules_src do also insertinto rules_log values(null, null, '-', default), (new.*, 'new', default); insertinto rules_src values(22,23), (33,default); select * from rules_src; select * from rules_log; create rule r4 asondeleteto rules_src do notify rules_src_deletion;
-- -- Ensure an aliased target relation for insert is correctly deparsed. -- create rule r5 asoninsertto rules_src do instead insertinto rules_log AS trgt SELECT NEW.* RETURNING trgt.f1, trgt.f2; create rule r6 asonupdateto rules_src do instead UPDATE rules_log AS trgt SET tag = 'updated'WHERE trgt.f1 = new.f1;
-- -- Check deparse disambiguation of INSERT/UPDATE/DELETE targets. -- create rule r7 asondeleteto rules_src do instead with wins as (insertinto int4_tbl as trgt values (0) returning *),
wupd as (update int4_tbl trgt set f1 = f1+1 returning *),
wdel as (deletefrom int4_tbl trgt where f1 = 0 returning *) insertinto rules_log AS trgt select old.* from wins, wupd, wdel
returning trgt.f1, trgt.f2;
-- check display of all rules added above
\d+ rules_src
-- -- Also check multiassignment deparsing. -- createtable rule_t1(f1 int, f2 int); createtable rule_dest(f1 int, f2 int[], tag text); create rule rr asonupdateto rule_t1 do instead UPDATE rule_dest trgt SET (f2[1], f1, tag) = (SELECT new.f2, new.f1, 'updated'::varchar) WHERE trgt.f1 = new.f1 RETURNING new.*;
\d+ rule_t1 droptable rule_t1, rule_dest;
-- -- Test implicit LATERAL references to old/new in rules -- CREATETABLE rule_t1(a int, b text DEFAULT'xxx', c int); CREATE VIEW rule_v1 ASSELECT * FROM rule_t1; CREATE RULE v1_ins ASONINSERTTO rule_v1
DO ALSO INSERTINTO rule_t1 SELECT * FROM (SELECT a + 10FROM rule_t1 WHERE a = NEW.a) tt; CREATE RULE v1_upd ASONUPDATETO rule_v1
DO ALSO UPDATE rule_t1 t SET c = tt.a * 10 FROM (SELECT a FROM rule_t1 WHERE a = OLD.a) tt WHERE t.a = tt.a; INSERTINTO rule_v1 VALUES (1, 'a'), (2, 'b'); UPDATE rule_v1 SET b = upper(b); SELECT * FROM rule_t1; DROPTABLE rule_t1 CASCADE;
-- -- check alter rename rule -- CREATETABLE rule_t1 (a INT); CREATE VIEW rule_v1 ASSELECT * FROM rule_t1;
CREATE RULE InsertRule AS ONINSERTTO rule_v1
DO INSTEAD INSERTINTO rule_t1 VALUES(new.a);
ALTER RULE InsertRule ON rule_v1 RENAMEto NewInsertRule;
INSERTINTO rule_v1 VALUES(1); SELECT * FROM rule_v1;
\d+ rule_v1
-- -- error conditions for alter rename rule -- ALTER RULE InsertRule ON rule_v1 RENAMETO NewInsertRule; -- doesn't exist ALTER RULE NewInsertRule ON rule_v1 RENAMETO"_RETURN"; -- already exists ALTER RULE "_RETURN"ON rule_v1 RENAMETO abc; -- ON SELECT rule cannot be renamed
DROP VIEW rule_v1; DROPTABLE rule_t1;
-- -- check display of VALUES in view definitions -- create view rule_v1 asvalues(1,2);
\d+ rule_v1 altertable rule_v1 renamecolumn column2 to q2;
\d+ rule_v1 drop view rule_v1; create view rule_v1(x) asvalues(1,2);
\d+ rule_v1 drop view rule_v1; create view rule_v1(x) asselect * from (values(1,2)) v;
\d+ rule_v1 drop view rule_v1; create view rule_v1(x) asselect * from (values(1,2)) v(q,w);
\d+ rule_v1 drop view rule_v1;
-- -- Check DO INSTEAD rules with ON CONFLICT -- CREATETABLE hats (
hat_name char(10) primarykey,
hat_color char(10) -- hat color
);
CREATETABLE hat_data (
hat_name char(10),
hat_color char(10) -- hat color
); createuniqueindex hat_data_unique_idx on hat_data (hat_name COLLATE"C" bpchar_pattern_ops);
-- DO NOTHING with ON CONFLICT CREATE RULE hat_nosert ASONINSERTTO hats
DO INSTEAD INSERTINTO hat_data VALUES (
NEW.hat_name,
NEW.hat_color) ON CONFLICT (hat_name COLLATE"C" bpchar_pattern_ops) WHERE hat_color = 'green'
DO NOTHING
RETURNING *; SELECT definition FROM pg_rules WHERE tablename = 'hats'ORDERBY rulename;
-- Works (projects row) INSERTINTO hats VALUES ('h7', 'black') RETURNING *; -- Works (does nothing) INSERTINTO hats VALUES ('h7', 'black') RETURNING *; SELECT tablename, rulename, definition FROM pg_rules WHERE tablename = 'hats'; DROP RULE hat_nosert ON hats;
-- DO NOTHING without ON CONFLICT CREATE RULE hat_nosert_all ASONINSERTTO hats
DO INSTEAD INSERTINTO hat_data VALUES (
NEW.hat_name,
NEW.hat_color) ON CONFLICT
DO NOTHING
RETURNING *; SELECT definition FROM pg_rules WHERE tablename = 'hats'ORDERBY rulename; DROP RULE hat_nosert_all ON hats;
-- DO UPDATE with a WHERE clause CREATE RULE hat_upsert ASONINSERTTO hats
DO INSTEAD INSERTINTO hat_data VALUES (
NEW.hat_name,
NEW.hat_color) ON CONFLICT (hat_name)
DO UPDATE SET hat_name = hat_data.hat_name, hat_color = excluded.hat_color WHERE excluded.hat_color <> 'forbidden'AND hat_data.* != excluded.*
RETURNING *; SELECT definition FROM pg_rules WHERE tablename = 'hats'ORDERBY rulename;
-- Works (does upsert) INSERTINTO hats VALUES ('h8', 'black') RETURNING *; SELECT * FROM hat_data WHERE hat_name = 'h8'; INSERTINTO hats VALUES ('h8', 'white') RETURNING *; SELECT * FROM hat_data WHERE hat_name = 'h8'; INSERTINTO hats VALUES ('h8', 'forbidden') RETURNING *; SELECT * FROM hat_data WHERE hat_name = 'h8'; SELECT tablename, rulename, definition FROM pg_rules WHERE tablename = 'hats'; -- ensure explain works for on insert conflict rules explain (costs off) INSERTINTO hats VALUES ('h8', 'forbidden') RETURNING *;
-- ensure upserting into a rule, with a CTE (different offsets!) works WITH data(hat_name, hat_color) AS MATERIALIZED ( VALUES ('h8', 'green'),
('h9', 'blue'),
('h7', 'forbidden')
) INSERTINTO hats SELECT * FROM data
RETURNING *; EXPLAIN (costs off) WITH data(hat_name, hat_color) AS MATERIALIZED ( VALUES ('h8', 'green'),
('h9', 'blue'),
('h7', 'forbidden')
) INSERTINTO hats SELECT * FROM data
RETURNING *; SELECT * FROM hat_data WHERE hat_name IN ('h8', 'h9', 'h7') ORDERBY hat_name;
DROP RULE hat_upsert ON hats;
droptable hats; droptable hat_data;
-- test for pg_get_functiondef properly regurgitating SET parameters -- Note that the function is kept around to stress pg_dump. CREATE FUNCTION func_with_set_params() RETURNS integer AS'select 1;'
LANGUAGE SQL SET search_path TO PG_CATALOG SET extra_float_digits TO2 SET work_mem TO'4MB' SET datestyle to iso, mdy SET local_preload_libraries TO"Mixed/Case", 'c:/''a"/path', '', '0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789'
IMMUTABLE STRICT; SELECT pg_get_functiondef('func_with_set_params()'::regprocedure);
-- test rename for a rule defined on a partitioned table CREATETABLE rules_parted_table (a int) PARTITION BY LIST (a); CREATETABLE rules_parted_table_1 PARTITION OF rules_parted_table FORVALUESIN (1); CREATE RULE rules_parted_table_insert ASONINSERTto rules_parted_table
DO INSTEAD INSERTINTO rules_parted_table_1 VALUES (NEW.*); ALTER RULE rules_parted_table_insert ON rules_parted_table RENAMETO rules_parted_table_insert_redirect; DROPTABLE rules_parted_table;
-- -- test MERGE -- CREATETABLE rule_merge1 (a int, b text); CREATETABLE rule_merge2 (a int, b text); CREATE RULE rule1 ASONINSERTTO rule_merge1
DO INSTEAD INSERTINTO rule_merge2 VALUES (NEW.*); CREATE RULE rule2 ASONUPDATETO rule_merge1
DO INSTEAD UPDATE rule_merge2 SET a = NEW.a, b = NEW.b WHERE a = OLD.a; CREATE RULE rule3 ASONDELETETO rule_merge1
DO INSTEAD DELETEFROM rule_merge2 WHERE a = OLD.a;
-- MERGE not supported for table with rules
MERGE INTO rule_merge1 t USING (SELECT1AS a) s ON t.a = s.a WHEN MATCHED AND t.a < 2THEN UPDATESET b = b || ' updated by merge' WHEN MATCHED AND t.a > 2THEN DELETE WHENNOT MATCHED THEN INSERTVALUES (s.a, '');
-- should be ok with the other table though
MERGE INTO rule_merge2 t USING (SELECT1AS a) s ON t.a = s.a WHEN MATCHED AND t.a < 2THEN UPDATESET b = b || ' updated by merge' WHEN MATCHED AND t.a > 2THEN DELETE WHENNOT MATCHED THEN INSERTVALUES (s.a, '');
-- also ok if the rules are disabled ALTERTABLE rule_merge1 DISABLE RULE rule1; ALTERTABLE rule_merge1 DISABLE RULE rule2; ALTERTABLE rule_merge1 DISABLE RULE rule3;
MERGE INTO rule_merge1 t USING (SELECT1AS a) s ON t.a = s.a WHEN MATCHED AND t.a < 2THEN UPDATESET b = b || ' updated by merge' WHEN MATCHED AND t.a > 2THEN DELETE WHENNOT MATCHED THEN INSERTVALUES (s.a, '');
-- test deparsing CREATETABLE sf_target(id int, data text, filling int[]);
CREATE FUNCTION merge_sf_test()
RETURNS TABLE(action text, a int, b text,
id int, data text, filling int[],
old_id int, old_data text, old_filling int[],
new_id int, new_data text, new_filling int[])
LANGUAGE sql
BEGIN ATOMIC
MERGE INTO sf_target t USING rule_merge1 s ON (s.a = t.id) WHEN MATCHED AND (s.a + t.id) = 42 THENUPDATESET data = repeat(t.data, s.a) || s.b, id = length(s.b) WHENNOT MATCHED AND (s.b ISNOTNULL) THENINSERT (data, id) VALUES (s.b, s.a) WHEN MATCHED AND length(s.b || t.data) > 10 THENUPDATESET data = s.b WHEN MATCHED AND s.a > 200 THENUPDATESET filling[s.a] = t.id WHEN MATCHED AND s.a > 100 THENDELETE WHEN MATCHED THEN DO NOTHING WHENNOT MATCHED AND s.a > 200 THENINSERTDEFAULTVALUES WHENNOT MATCHED AND s.a > 100 THENINSERT (id, data) OVERRIDING USER VALUE VALUES (s.a, DEFAULT) WHENNOT MATCHED AND s.a > 0 THENINSERT VALUES (s.a, s.b, DEFAULT) WHENNOT MATCHED THENINSERT (filling[1], id) VALUES (s.a, s.a)
RETURNING WITH (OLD AS o, NEW AS n)
merge_action() AS action, *, o.*, n.*;
END;
\sf merge_sf_test
CREATE FUNCTION merge_sf_test2()
RETURNS void
LANGUAGE sql
BEGIN ATOMIC
MERGE INTO sf_target t USING rule_merge1 s ON (s.a = t.id) WHENNOT MATCHED THENINSERT (data, id) VALUES (s.a, s.a) WHEN MATCHED THENUPDATESET data = s.b WHENNOT MATCHED BY SOURCE THENDELETE;
END;
\sf merge_sf_test2
DROP FUNCTION merge_sf_test; DROP FUNCTION merge_sf_test2; DROPTABLE sf_target;
-- -- Test enabling/disabling -- CREATETABLE ruletest1 (a int); CREATETABLE ruletest2 (b int);
SET SESSION AUTHORIZATION regress_rule_user1; INSERTINTO ruletest_v1 VALUES (1);
RESET SESSION AUTHORIZATION;
-- Test that main query's relation's permissions are checked before -- the rule action's relation's. CREATETABLE ruletest_t3 (x int); CREATE RULE rule2 ASONUPDATETO ruletest_t1
DO INSTEAD INSERTINTO ruletest_t2 VALUES (OLD.*); REVOKEALLON ruletest_t2 FROM regress_rule_user1; REVOKEALLON ruletest_t3 FROM regress_rule_user1; ALTERTABLE ruletest_t1 OWNER TO regress_rule_user1; SET SESSION AUTHORIZATION regress_rule_user1; UPDATE ruletest_t1 t1 SET x = 0FROM ruletest_t3 t3 WHERE t1.x = t3.x;
RESET SESSION AUTHORIZATION; SELECT * FROM ruletest_t1; SELECT * FROM ruletest_t2;
DROP VIEW ruletest_v1; DROP RULE rule2 ON ruletest_t1; DROPTABLE ruletest_t3; DROPTABLE ruletest_t2; DROPTABLE ruletest_t1;
DROP USER regress_rule_user1;
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.