-- should still work INSERTINTO voo VALUES(13,'zit2'); -- works now INSERTINTO voo VALUES(14,'zoo2') RETURNING *;
SELECT * FROM foo; SELECT * FROM voo;
CREATEORREPLACE RULE voo_u ASONUPDATETO voo DO INSTEAD UPDATE foo SET f1 = new.f1, f2 = new.f2 WHERE f1 = old.f1
RETURNING f1, f2;
update voo set f1 = f1 + 1where f2 = 'zoo2'; update voo set f1 = f1 + 1where f2 = 'zoo2' RETURNING *, f1*2;
SELECT * FROM foo; SELECT * FROM voo;
CREATEORREPLACE RULE voo_d ASONDELETETO voo DO INSTEAD DELETEFROM foo WHERE f1 = old.f1
RETURNING f1, f2;
DELETEFROM foo WHERE f1 = 13; DELETEFROM foo WHERE f2 = 'zit' RETURNING *;
SELECT * FROM foo; SELECT * FROM voo;
-- Check use of a whole-row variable for an un-flattenable view CREATE TEMP VIEW foo_v ASSELECT * FROM foo OFFSET 0; UPDATE foo SET f2 = foo_v.f2 FROM foo_v WHERE foo_v.f1 = foo.f1
RETURNING foo_v; SELECT * FROM foo;
-- Check use of a whole-row variable for an inlined set-returning function CREATE FUNCTION foo_f() RETURNS SETOF foo AS
$$ SELECT * FROM foo OFFSET 0 $$ LANGUAGE sql STABLE; UPDATE foo SET f2 = foo_f.f2 FROM foo_f() WHERE foo_f.f1 = foo.f1
RETURNING foo_f; SELECT * FROM foo; DROP FUNCTION foo_f();
-- As above, but SRF is defined to return a composite type CREATE TYPE foo_t AS (f1 int, f2 text, f3 int, f4 int8); CREATE FUNCTION foo_f() RETURNS SETOF foo_t AS
$$ SELECT * FROM foo OFFSET 0 $$ LANGUAGE sql STABLE; UPDATE foo SET f2 = foo_f.f2 FROM foo_f() WHERE foo_f.f1 = foo.f1
RETURNING foo_f; SELECT * FROM foo; DROP FUNCTION foo_f(); DROP TYPE foo_t;
CREATE TEMP VIEW joinview AS SELECT foo.*, other FROM foo JOIN joinme ON (f2 = f2j);
SELECT * FROM joinview;
CREATE RULE joinview_u ASONUPDATETO 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 + 1WHERE f3 = 57 RETURNING *, other + 1;
SELECT * FROM joinview; SELECT * FROM foo; SELECT * FROM voo;
-- Check aliased target relation INSERTINTO foo AS bar DEFAULTVALUES RETURNING *; -- ok INSERTINTO foo AS bar DEFAULTVALUES RETURNING foo.*; -- fails, wrong name INSERTINTO foo AS bar DEFAULTVALUES RETURNING bar.*; -- ok INSERTINTO foo AS bar DEFAULTVALUES RETURNING bar.f3; -- ok
-- -- Test RETURNING OLD/NEW. -- -- Start with new data, to ensure predictable TIDs. --
TRUNCATE foo; INSERTINTO foo VALUES (1, 'xxx', 10, 20), (2, 'more', 42, 141), (3, 'zoo2', 57, 99);
-- Error cases INSERTINTO foo DEFAULTVALUES RETURNING WITH (nonsuch AS something) *; INSERTINTO foo DEFAULTVALUES RETURNING WITH (new AS foo) *; INSERTINTO foo DEFAULTVALUES RETURNING WITH (old AS o, new AS n, old AS o) *; INSERTINTO foo DEFAULTVALUES RETURNING WITH (old AS o, new AS n, new AS n) *; INSERTINTO foo DEFAULTVALUES RETURNING WITH (old AS x, new AS x) *;
-- INSERT has NEW, but not OLD EXPLAIN (verbose, costs off) INSERTINTO foo VALUES (4)
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *; INSERTINTO foo VALUES (4)
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
-- INSERT ... ON CONFLICT ... UPDATE has OLD and NEW CREATEUNIQUEINDEX foo_f1_idx ON foo (f1); EXPLAIN (verbose, costs off) INSERTINTO foo VALUES (4, 'conflict'), (5, 'ok') ON CONFLICT (f1) DO UPDATESET f2 = excluded.f2||'ed', f3 = -1
RETURNING WITH (OLD AS o, NEW AS n)
o.tableoid::regclass, o.ctid, o.*,
n.tableoid::regclass, n.ctid, n.*, *; INSERTINTO foo VALUES (4, 'conflict'), (5, 'ok') ON CONFLICT (f1) DO UPDATESET f2 = excluded.f2||'ed', f3 = -1
RETURNING WITH (OLD AS o, NEW AS n)
o.tableoid::regclass, o.ctid, o.*,
n.tableoid::regclass, n.ctid, n.*, *;
-- UPDATE has OLD and NEW EXPLAIN (verbose, costs off) UPDATE foo SET f4 = 100WHERE f1 = 5
RETURNING old.tableoid::regclass, old.ctid, old.*, old,
new.tableoid::regclass, new.ctid, new.*, new,
old.f4::text||'->'||new.f4::text ASchange; UPDATE foo SET f4 = 100WHERE f1 = 5
RETURNING old.tableoid::regclass, old.ctid, old.*, old,
new.tableoid::regclass, new.ctid, new.*, new,
old.f4::text||'->'||new.f4::text ASchange;
-- DELETE has OLD, but not NEW EXPLAIN (verbose, costs off) DELETEFROM foo WHERE f1 = 5
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *; DELETEFROM foo WHERE f1 = 5
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
-- RETURNING OLD and NEW from subquery EXPLAIN (verbose, costs off) INSERTINTO foo VALUES (5, 'subquery test')
RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
(SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max; INSERTINTO foo VALUES (5, 'subquery test')
RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
(SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
EXPLAIN (verbose, costs off) UPDATE foo SET f4 = 100WHERE f1 = 5
RETURNING (SELECT old.f4 = new.f4),
(SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
(SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max; UPDATE foo SET f4 = 100WHERE f1 = 5
RETURNING (SELECT old.f4 = new.f4),
(SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
(SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
EXPLAIN (verbose, costs off) DELETEFROM foo WHERE f1 = 5
RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
(SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max; DELETEFROM foo WHERE f1 = 5
RETURNING (SELECT max(old.f4 + x) FROM generate_series(1, 10) x) old_max,
(SELECT max(new.f4 + x) FROM generate_series(1, 10) x) new_max;
-- DELETE turned into UPDATE by a rule has OLD and NEW CREATE RULE foo_del_rule ASONDELETETO foo DO INSTEAD UPDATE foo SET f2 = f2||' (deleted)', f3 = -1, f4 = -1WHERE f1 = OLD.f1
RETURNING *; EXPLAIN (verbose, costs off) DELETEFROM foo WHERE f1 = 4 RETURNING old.*,new.*, *; DELETEFROM foo WHERE f1 = 4 RETURNING old.*,new.*, *;
-- UPDATE on view with rule EXPLAIN (verbose, costs off) UPDATE joinview SET f3 = f3 + 1WHERE f3 = 57
RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3; UPDATE joinview SET f3 = f3 + 1WHERE f3 = 57
RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3;
-- UPDATE on view with INSTEAD OF trigger CREATE FUNCTION joinview_upd_trig_fn() RETURNS trigger
LANGUAGE plpgsql AS
$$
BEGIN
RAISE NOTICE 'UPDATE: % -> %', old, new; UPDATE foo SET f1 = new.f1, f3 = new.f3, f4 = new.f4 * 10 FROM joinme WHERE f2 = f2j AND f2 = old.f2
RETURNING new.f1, new.f4 INTO new.f1, new.f4; -- should fail RETURN NEW;
END;
$$; CREATETRIGGER joinview_upd_trig INSTEAD OF UPDATEON joinview FOREACH ROW EXECUTE FUNCTION joinview_upd_trig_fn(); DROP RULE joinview_u ON joinview; UPDATE joinview SET f3 = f3 + 1, f4 = 7WHERE f3 = 58
RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3; -- should fail
CREATEORREPLACE FUNCTION joinview_upd_trig_fn() RETURNS trigger
LANGUAGE plpgsql AS
$$
BEGIN
RAISE NOTICE 'UPDATE: % -> %', old, new; UPDATE foo SET f1 = new.f1, f3 = new.f3, f4 = new.f4 * 10 FROM joinme WHERE f2 = f2j AND f2 = old.f2
RETURNING WITH (new AS n) new.f1, n.f4 INTO new.f1, new.f4; -- now ok RETURN NEW;
END;
$$; EXPLAIN (verbose, costs off) UPDATE joinview SET f3 = f3 + 1, f4 = 7WHERE f3 = 58
RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3; UPDATE joinview SET f3 = f3 + 1, f4 = 7WHERE f3 = 58
RETURNING old.*, new.*, *, new.f3 - old.f3 AS delta_f3; -- should succeed
-- Test wholerow & dropped column handling ALTERTABLE foo DROPCOLUMN f3 CASCADE; UPDATE foo SET f4 = f4 + 1 RETURNING old.f3; -- should fail UPDATE foo SET f4 = f4 + 1 RETURNING old, new;
-- Test schema-qualified table name in RETURNING list CREATETABLE public.tt(a int, b int); INSERTINTO public.tt VALUES (1, 10); UPDATE public.tt SET b = b * 2 RETURNING a, b, old.b, new.b, tt.b, public.tt.b; DROPTABLE public.tt;
-- Test cross-partition updates and attribute mapping CREATETABLE foo_parted (a int, b float8, c text) PARTITION BY LIST (a); CREATETABLE foo_part_s1 PARTITION OF foo_parted FORVALUESIN (1); CREATETABLE foo_part_s2 PARTITION OF foo_parted FORVALUESIN (2); CREATETABLE foo_part_d1 (c text, a int, b float8); ALTERTABLE foo_parted ATTACH PARTITION foo_part_d1 FORVALUESIN (3); CREATETABLE foo_part_d2 (b float8, c text, a int); ALTERTABLE foo_parted ATTACH PARTITION foo_part_d2 FORVALUESIN (4);
UPDATE foo_parted SET a = 2, b = b + 1, c = c || '->P2'WHERE a = 1
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
UPDATE foo_parted SET a = 1, b = b + 1, c = c || '->P1'WHERE a = 3
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
UPDATE foo_parted SET a = 3, b = b + 1, c = c || '->P3'WHERE a = 1
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
UPDATE foo_parted SET a = 4, b = b + 1, c = c || '->P4'WHERE a = 3
RETURNING old.tableoid::regclass, old.ctid, old.*,
new.tableoid::regclass, new.ctid, new.*, *;
-- cross-partition update that uses ReturningExpr nodes, without returning -- old/new table values CREATE VIEW foo_parted_v ASSELECT *, 'xxx'AS dummy FROM foo_parted; UPDATE foo_parted_v SET a = 1, c = c || '->P1'WHERE a = 2AND c = 'P2'
RETURNING 'P2:'||old.dummy, 'P1:'||new.dummy;
-- Test deparsing CREATE FUNCTION foo_update()
RETURNS void
LANGUAGE sql
BEGIN ATOMIC WITH u1 AS ( UPDATE foo SET f1 = f1 + 1 RETURNING old.*, new.*
), u2 AS ( UPDATE foo SET f1 = f1 + 1 RETURNING WITH (OLD AS"old foo") "old foo".*, new.*
), u3 AS ( UPDATE foo SET f1 = f1 + 1 RETURNING WITH (NEW AS"new foo") old.*, "new foo".*
) UPDATE foo SET f1 = f1 + 1
RETURNING WITH (OLD AS o, NEW AS n)
o.*, n.*, o, n, o.f1 = n.f1, o = n,
(SELECT o.f2 = n.f2),
(SELECT count(*) FROM foo WHERE foo.f1 = o.f4),
(SELECT count(*) FROM foo WHERE foo.f4 = n.f4),
(SELECT count(*) FROM foo WHERE foo = o),
(SELECT count(*) FROM foo WHERE foo = n);
END;
\sf foo_update DROP FUNCTION foo_update;
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 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.