-- -- Test INSERT/UPDATE/DELETE RETURNING -- -- Simple cases CREATE TEMP TABLE foo (f1 serial, f2 text, f3 int default 42); INSERT INTO foo (f2,f3) VALUES ('test', DEFAULT), ('More', 11), (upper('more'), 7+9) RETURNING *, f1+f3 AS sum; f1 | f2 | f3 | sum ----+------+----+----- 1 | test | 42 | 43 2 | More | 11 | 13 3 | MORE | 16 | 19 (3 rows) SELECT * FROM foo; f1 | f2 | f3 ----+------+---- 1 | test | 42 2 | More | 11 3 | MORE | 16 (3 rows) UPDATE foo SET f2 = lower(f2), f3 = DEFAULT RETURNING foo.*, f1+f3 AS sum13; f1 | f2 | f3 | sum13 ----+------+----+------- 1 | test | 42 | 43 2 | more | 42 | 44 3 | more | 42 | 45 (3 rows) SELECT * FROM foo; f1 | f2 | f3 ----+------+---- 1 | test | 42 2 | more | 42 3 | more | 42 (3 rows) DELETE FROM foo WHERE f1 > 2 RETURNING f3, f2, f1, least(f1,f3); f3 | f2 | f1 | least ----+------+----+------- 42 | more | 3 | 3 (1 row) SELECT * FROM foo; f1 | f2 | f3 ----+------+---- 1 | test | 42 2 | more | 42 (2 rows) -- Subplans and initplans in the RETURNING list INSERT INTO foo SELECT f1+10, f2, f3+99 FROM foo RETURNING *, f1+112 IN (SELECT q1 FROM int8_tbl) AS subplan, EXISTS(SELECT * FROM int4_tbl) AS initplan; f1 | f2 | f3 | subplan | initplan ----+------+-----+---------+---------- 11 | test | 141 | t | t 12 | more | 141 | f | t (2 rows) UPDATE foo SET f3 = f3 * 2 WHERE f1 > 10 RETURNING *, f1+112 IN (SELECT q1 FROM int8_tbl) AS subplan, EXISTS(SELECT * FROM int4_tbl) AS initplan; f1 | f2 | f3 | subplan | initplan ----+------+-----+---------+---------- 11 | test | 282 | t | t 12 | more | 282 | f | t (2 rows) DELETE FROM foo WHERE f1 > 10 RETURNING *, f1+112 IN (SELECT q1 FROM int8_tbl) AS subplan, EXISTS(SELECT * FROM int4_tbl) AS initplan; f1 | f2 | f3 | subplan | initplan ----+------+-----+---------+---------- 11 | test | 282 | t | t 12 | more | 282 | f | t (2 rows) -- Joins UPDATE foo SET f3 = f3*2 FROM int4_tbl i WHERE foo.f1 + 123455 = i.f1 RETURNING foo.*, i.f1 as "i.f1"; f1 | f2 | f3 | i.f1 ----+------+----+-------- 1 | test | 84 | 123456 (1 row) SELECT * FROM foo; f1 | f2 | f3 ----+------+---- 2 | more | 42 1 | test | 84 (2 rows) DELETE FROM foo USING int4_tbl i WHERE foo.f1 + 123455 = i.f1 RETURNING foo.*, i.f1 as "i.f1"; f1 | f2 | f3 | i.f1 ----+------+----+-------- 1 | test | 84 | 123456 (1 row) SELECT * FROM foo; f1 | f2 | f3 ----+------+---- 2 | more | 42 (1 row) -- Check inheritance cases CREATE TEMP TABLE foochild (fc int) INHERITS (foo); INSERT INTO foochild VALUES(123,'child',999,-123); ALTER TABLE foo ADD COLUMN f4 int8 DEFAULT 99; SELECT * FROM foo; f1 | f2 | f3 | f4 -----+-------+-----+---- 2 | more | 42 | 99 123 | child | 999 | 99 (2 rows) SELECT * FROM foochild; f1 | f2 | f3 | fc | f4 -----+-------+-----+------+---- 123 | child | 999 | -123 | 99 (1 row) UPDATE foo SET f4 = f4 + f3 WHERE f4 = 99 RETURNING *; f1 | f2 | f3 | f4 -----+-------+-----+------ 2 | more | 42 | 141 123 | child | 999 | 1098 (2 rows) SELECT * FROM foo; f1 | f2 | f3 | f4 -----+-------+-----+------ 2 | more | 42 | 141 123 | child | 999 | 1098 (2 rows) SELECT * FROM foochild; f1 | f2 | f3 | fc | f4 -----+-------+-----+------+------ 123 | child | 999 | -123 | 1098 (1 row) UPDATE foo SET f3 = f3*2 FROM int8_tbl i WHERE foo.f1 = i.q2 RETURNING *; f1 | f2 | f3 | f4 | q1 | q2 -----+-------+------+------+------------------+----- 123 | child | 1998 | 1098 | 4567890123456789 | 123 (1 row) SELECT * FROM foo; f1 | f2 | f3 | f4 -----+-------+------+------ 2 | more | 42 | 141 123 | child | 1998 | 1098 (2 rows) SELECT * FROM foochild; f1 | f2 | f3 | fc | f4 -----+-------+------+------+------ 123 | child | 1998 | -123 | 1098 (1 row) DELETE FROM foo USING int8_tbl i WHERE foo.f1 = i.q2 RETURNING *; f1 | f2 | f3 | f4 | q1 | q2 -----+-------+------+------+------------------+----- 123 | child | 1998 | 1098 | 4567890123456789 | 123 (1 row) SELECT * FROM foo; f1 | f2 | f3 | f4 ----+------+----+----- 2 | more | 42 | 141 (1 row) SELECT * FROM foochild; f1 | f2 | f3 | fc | f4 ----+----+----+----+---- (0 rows) DROP TABLE foochild; -- Rules and views CREATE TEMP VIEW voo AS SELECT f1, f2 FROM foo; CREATE RULE voo_i AS ON INSERT TO voo DO INSTEAD INSERT INTO foo VALUES(new.*, 57); INSERT INTO voo VALUES(11,'zit'); -- fails: INSERT INTO voo VALUES(12,'zoo') RETURNING *, f1*2; ERROR: cannot perform INSERT RETURNING on relation "voo" HINT: You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause. -- fails, incompatible list: CREATE OR REPLACE RULE voo_i AS ON INSERT TO voo DO INSTEAD INSERT INTO foo VALUES(new.*, 57) RETURNING *; ERROR: RETURNING list has too many entries CREATE OR REPLACE RULE voo_i AS ON INSERT TO voo DO INSTEAD INSERT INTO foo VALUES(new.*, 57) RETURNING f1, f2; -- should still work INSERT INTO voo VALUES(13,'zit2'); -- works now INSERT INTO voo VALUES(14,'zoo2') RETURNING *; f1 | f2 ----+------ 14 | zoo2 (1 row) SELECT * FROM foo; f1 | f2 | f3 | f4 ----+------+----+----- 2 | more | 42 | 141 11 | zit | 57 | 99 13 | zit2 | 57 | 99 14 | zoo2 | 57 | 99 (4 rows) SELECT * FROM voo; f1 | f2 ----+------ 2 | more 11 | zit 13 | zit2 14 | zoo2 (4 rows) CREATE OR REPLACE RULE voo_u AS ON UPDATE TO voo DO INSTEAD UPDATE foo SET f1 = new.f1, f2 = new.f2 WHERE f1 = old.f1 RETURNING f1, f2; update voo set f1 = f1 + 1 where f2 = 'zoo2'; update voo set f1 = f1 + 1 where f2 = 'zoo2' RETURNING *, f1*2; f1 | f2 | ?column? ----+------+---------- 16 | zoo2 | 32 (1 row) SELECT * FROM foo; f1 | f2 | f3 | f4 ----+------+----+----- 2 | more | 42 | 141 11 | zit | 57 | 99 13 | zit2 | 57 | 99 16 | zoo2 | 57 | 99 (4 rows) SELECT * FROM voo; f1 | f2 ----+------ 2 | more 11 | zit 13 | zit2 16 | zoo2 (4 rows) CREATE OR REPLACE RULE voo_d AS ON DELETE TO voo DO INSTEAD DELETE FROM foo WHERE f1 = old.f1 RETURNING f1, f2; DELETE FROM foo WHERE f1 = 13; DELETE FROM foo WHERE f2 = 'zit' RETURNING *; f1 | f2 | f3 | f4 ----+-----+----+---- 11 | zit | 57 | 99 (1 row) SELECT * FROM foo; f1 | f2 | f3 | f4 ----+------+----+----- 2 | more | 42 | 141 16 | zoo2 | 57 | 99 (2 rows) SELECT * FROM voo; f1 | f2 ----+------ 2 | more 16 | zoo2 (2 rows) -- Try a join case CREATE TEMP TABLE joinme (f2j text, other int); INSERT INTO joinme VALUES('more', 12345); INSERT INTO joinme VALUES('zoo2', 54321); INSERT INTO joinme VALUES('other', 0); CREATE TEMP VIEW joinview AS SELECT foo.*, other FROM foo JOIN joinme ON (f2 = f2j); SELECT * FROM joinview; f1 | f2 | f3 | f4 | other ----+------+----+-----+------- 2 | more | 42 | 141 | 12345 16 | zoo2 | 57 | 99 | 54321 (2 rows) CREATE RULE joinview_u AS ON UPDATE TO joinview DO INSTEAD UPDATE foo SET f1 = new.f1, f3 = new.f3 FROM joinme WHERE f2 = f2j AND f2 = old.f2 RETURNING foo.*, other; UPDATE joinview SET f1 = f1 + 1 WHERE f3 = 57 RETURNING *, other + 1; f1 | f2 | f3 | f4 | other | ?column? ----+------+----+----+-------+---------- 17 | zoo2 | 57 | 99 | 54321 | 54322 (1 row) SELECT * FROM joinview; f1 | f2 | f3 | f4 | other ----+------+----+-----+------- 2 | more | 42 | 141 | 12345 17 | zoo2 | 57 | 99 | 54321 (2 rows) SELECT * FROM foo; f1 | f2 | f3 | f4 ----+------+----+----- 2 | more | 42 | 141 17 | zoo2 | 57 | 99 (2 rows) SELECT * FROM voo; f1 | f2 ----+------ 2 | more 17 | zoo2 (2 rows) -- Check aliased target relation INSERT INTO foo AS bar DEFAULT VALUES RETURNING *; -- ok f1 | f2 | f3 | f4 ----+----+----+---- 4 | | 42 | 99 (1 row) INSERT INTO foo AS bar DEFAULT VALUES RETURNING foo.*; -- fails, wrong name ERROR: invalid reference to FROM-clause entry for table "foo" LINE 1: INSERT INTO foo AS bar DEFAULT VALUES RETURNING foo.*; ^ HINT: Perhaps you meant to reference the table alias "bar". INSERT INTO foo AS bar DEFAULT VALUES RETURNING bar.*; -- ok f1 | f2 | f3 | f4 ----+----+----+---- 5 | | 42 | 99 (1 row) INSERT INTO foo AS bar DEFAULT VALUES RETURNING bar.f3; -- ok f3 ---- 42 (1 row)