=== Applying patches on top of PostgreSQL commit ID e18b0cb7344cb4bd28468f6c0aeeb9b9241d30aa === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Wed Jun 10 13:12:23 UTC 2026 On branch cf/6703 nothing to commit, working tree clean === using 'git am' to apply patch ./v2-0001-fix-DELETE-UPDATE-FOR-PORTION-OF-with-rules.patch === Applying: fix DELETE/UPDATE FOR PORTION OF with rules Using index info to reconstruct a base tree... M src/backend/nodes/nodeFuncs.c M src/test/regress/expected/for_portion_of.out M src/test/regress/sql/for_portion_of.sql Falling back to patching base and 3-way merge... Auto-merging src/test/regress/sql/for_portion_of.sql CONFLICT (content): Merge conflict in src/test/regress/sql/for_portion_of.sql Auto-merging src/test/regress/expected/for_portion_of.out CONFLICT (content): Merge conflict in src/test/regress/expected/for_portion_of.out Auto-merging src/backend/nodes/nodeFuncs.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 fix DELETE/UPDATE FOR PORTION OF with rules When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v2-0001-fix-DELETE-UPDATE-FOR-PORTION-OF-with-rules.patch === patching file src/backend/nodes/nodeFuncs.c Hunk #1 FAILED at 2583. Hunk #2 succeeded at 2589 with fuzz 2 (offset -2 lines). 1 out of 2 hunks FAILED -- saving rejects to file src/backend/nodes/nodeFuncs.c.rej patching file src/test/regress/expected/for_portion_of.out Hunk #1 FAILED at 2097. 1 out of 1 hunk FAILED -- saving rejects to file src/test/regress/expected/for_portion_of.out.rej patching file src/test/regress/sql/for_portion_of.sql Hunk #1 succeeded at 1591 with fuzz 2 (offset 226 lines). Unstaged changes after reset: M src/backend/nodes/nodeFuncs.c M src/test/regress/sql/for_portion_of.sql Removing src/backend/nodes/nodeFuncs.c.rej Removing src/test/regress/expected/for_portion_of.out.rej === using 'git apply' to apply patch ./v2-0001-fix-DELETE-UPDATE-FOR-PORTION-OF-with-rules.patch === Applied patch to 'src/backend/nodes/nodeFuncs.c' cleanly. Applied patch to 'src/test/regress/expected/for_portion_of.out' with conflicts. Applied patch to 'src/test/regress/sql/for_portion_of.sql' with conflicts. U src/test/regress/expected/for_portion_of.out U src/test/regress/sql/for_portion_of.sql diff --cc src/test/regress/expected/for_portion_of.out index 43408972117,0c0a205c44b..00000000000 --- a/src/test/regress/expected/for_portion_of.out +++ b/src/test/regress/expected/for_portion_of.out @@@ -2208,242 -2152,4 +2208,245 @@@ SELECT * FROM fpo_rule ORDER BY f1 (2 rows) DROP TABLE fpo_rule; ++<<<<<<< ours +-- UPDATE/DELETE FOR PORTION OF with table inheritance +-- Leftover rows must stay in the child table, preserving child-specific columns. +CREATE TABLE fpo_inh_parent ( + id int4range, + valid_at daterange, + name text +); +CREATE TABLE fpo_inh_child ( + description text +) INHERITS (fpo_inh_parent); +-- Update targets the parent; the matching row lives in the child. +INSERT INTO fpo_inh_child (id, valid_at, name, description) VALUES + ('[1,2)', '[2018-01-01,2019-01-01)', 'one', 'initial'); +UPDATE fpo_inh_parent FOR PORTION OF valid_at FROM '2018-04-01' TO '2018-10-01' + SET name = 'one^1'; +-- All three rows should be in the child, with description preserved. +SELECT tableoid::regclass, * FROM fpo_inh_parent ORDER BY valid_at; + tableoid | id | valid_at | name +---------------+-------+-------------------------+------- + fpo_inh_child | [1,2) | [2018-01-01,2018-04-01) | one + fpo_inh_child | [1,2) | [2018-04-01,2018-10-01) | one^1 + fpo_inh_child | [1,2) | [2018-10-01,2019-01-01) | one +(3 rows) + +SELECT * FROM fpo_inh_child ORDER BY valid_at; + id | valid_at | name | description +-------+-------------------------+-------+------------- + [1,2) | [2018-01-01,2018-04-01) | one | initial + [1,2) | [2018-04-01,2018-10-01) | one^1 | initial + [1,2) | [2018-10-01,2019-01-01) | one | initial +(3 rows) + +-- No rows should have leaked into the parent. +SELECT * FROM ONLY fpo_inh_parent ORDER BY valid_at; + id | valid_at | name +----+----------+------ +(0 rows) + +-- Same test for DELETE instead of UPDATE: +TRUNCATE fpo_inh_child, fpo_inh_parent; +INSERT INTO fpo_inh_child (id, valid_at, name, description) VALUES + ('[1,2)', '[2018-01-01,2019-01-01)', 'one', 'initial'); +DELETE FROM fpo_inh_parent FOR PORTION OF valid_at FROM '2018-04-01' TO '2018-10-01'; +-- Both rows should be in the child, with description preserved. +SELECT tableoid::regclass, * FROM fpo_inh_parent ORDER BY valid_at; + tableoid | id | valid_at | name +---------------+-------+-------------------------+------ + fpo_inh_child | [1,2) | [2018-01-01,2018-04-01) | one + fpo_inh_child | [1,2) | [2018-10-01,2019-01-01) | one +(2 rows) + +SELECT * FROM fpo_inh_child ORDER BY valid_at; + id | valid_at | name | description +-------+-------------------------+------+------------- + [1,2) | [2018-01-01,2018-04-01) | one | initial + [1,2) | [2018-10-01,2019-01-01) | one | initial +(2 rows) + +-- No rows should have leaked into the parent. +SELECT * FROM ONLY fpo_inh_parent ORDER BY valid_at; + id | valid_at | name +----+----------+------ +(0 rows) + +DROP TABLE fpo_inh_parent CASCADE; +NOTICE: drop cascades to table fpo_inh_child +-- UPDATE FOR PORTION OF with multiple inheritance +-- Leftover rows must stay in the child table, even if the range column's +-- attnum differs between the target parent and child. +CREATE TABLE temporal_parent ( + id int, + valid_at daterange, + name text +); +CREATE TABLE other_parent ( + prefix text, + note text +); +CREATE TABLE mi_child () INHERITS (other_parent, temporal_parent); +-- attnum of the range column is different in temporal_parent and mi_child +SELECT attnum, attname + FROM pg_attribute + WHERE attrelid = 'temporal_parent'::regclass + AND attnum > 0 AND NOT attisdropped + ORDER BY attnum; + attnum | attname +--------+---------- + 1 | id + 2 | valid_at + 3 | name +(3 rows) + +SELECT attnum, attname + FROM pg_attribute + WHERE attrelid = 'mi_child'::regclass + AND attnum > 0 AND NOT attisdropped + ORDER BY attnum; + attnum | attname +--------+---------- + 1 | prefix + 2 | note + 3 | id + 4 | valid_at + 5 | name +(5 rows) + +INSERT INTO mi_child (prefix, note, id, valid_at, name) VALUES + ('pfx', 'memo', 1, daterange('2000-01-01', '2010-01-01'), 'old'); +UPDATE temporal_parent FOR PORTION OF valid_at FROM '2001-01-01' TO '2002-01-01' + SET name = 'new' + WHERE id = 1; +SELECT tableoid::regclass, * FROM temporal_parent ORDER BY valid_at; + tableoid | id | valid_at | name +----------+----+-------------------------+------ + mi_child | 1 | [2000-01-01,2001-01-01) | old + mi_child | 1 | [2001-01-01,2002-01-01) | new + mi_child | 1 | [2002-01-01,2010-01-01) | old +(3 rows) + +SELECT * FROM mi_child ORDER BY valid_at; + prefix | note | id | valid_at | name +--------+------+----+-------------------------+------ + pfx | memo | 1 | [2000-01-01,2001-01-01) | old + pfx | memo | 1 | [2001-01-01,2002-01-01) | new + pfx | memo | 1 | [2002-01-01,2010-01-01) | old +(3 rows) + +SELECT * FROM ONLY temporal_parent ORDER BY valid_at; + id | valid_at | name +----+----------+------ +(0 rows) + +TRUNCATE mi_child, other_parent, temporal_parent; +INSERT INTO mi_child (prefix, note, id, valid_at, name) VALUES + ('pfx', 'memo', 1, daterange('2000-01-01', '2010-01-01'), 'old'); +DELETE FROM temporal_parent FOR PORTION OF valid_at FROM '2001-01-01' TO '2002-01-01' + WHERE id = 1; +SELECT tableoid::regclass, * FROM temporal_parent ORDER BY valid_at; + tableoid | id | valid_at | name +----------+----+-------------------------+------ + mi_child | 1 | [2000-01-01,2001-01-01) | old + mi_child | 1 | [2002-01-01,2010-01-01) | old +(2 rows) + +SELECT * FROM mi_child ORDER BY valid_at; + prefix | note | id | valid_at | name +--------+------+----+-------------------------+------ + pfx | memo | 1 | [2000-01-01,2001-01-01) | old + pfx | memo | 1 | [2002-01-01,2010-01-01) | old +(2 rows) + +SELECT * FROM ONLY temporal_parent ORDER BY valid_at; + id | valid_at | name +----+----------+------ +(0 rows) + +DROP TABLE temporal_parent CASCADE; +NOTICE: drop cascades to table mi_child +-- UPDATE FOR PORTION OF with generated columns +-- The generated column depends on the range column, so it must be +-- recomputed when FOR PORTION OF narrows the range. +CREATE TABLE fpo_generated ( + id int, + valid_at int4range, + range_len int GENERATED ALWAYS AS (upper(valid_at) - lower(valid_at)) STORED, + range_lenv int GENERATED ALWAYS AS (upper(valid_at) - lower(valid_at)) +); +INSERT INTO fpo_generated (id, valid_at) VALUES (1, '[10,100)'); +SELECT * FROM fpo_generated ORDER BY valid_at; + id | valid_at | range_len | range_lenv +----+----------+-----------+------------ + 1 | [10,100) | 90 | 90 +(1 row) + +-- After the FOR PORTION OF (FPO) update, all three resulting rows +-- (leftover-before, updated, and leftover-after) must contain the correct +-- values for range_len and range_lenv. +UPDATE fpo_generated + FOR PORTION OF valid_at FROM 30 TO 70 + SET id = 2; +SELECT * FROM fpo_generated ORDER BY valid_at; + id | valid_at | range_len | range_lenv +----+----------+-----------+------------ + 1 | [10,30) | 20 | 20 + 2 | [30,70) | 40 | 40 + 1 | [70,100) | 30 | 30 +(3 rows) + +-- Also test with a generated column that references both a SET column +-- and the range column. +DROP TABLE fpo_generated; +CREATE TABLE fpo_generated ( + id int, + valid_at int4range, + id_plus_len int GENERATED ALWAYS AS (id + upper(valid_at) - lower(valid_at)) STORED, + id_plus_lenv int GENERATED ALWAYS AS (id + upper(valid_at) - lower(valid_at)) +); +INSERT INTO fpo_generated (id, valid_at) VALUES (1, '[10,100)'); +SELECT * FROM fpo_generated ORDER BY valid_at; + id | valid_at | id_plus_len | id_plus_lenv +----+----------+-------------+-------------- + 1 | [10,100) | 91 | 91 +(1 row) + +UPDATE fpo_generated + FOR PORTION OF valid_at FROM 30 TO 70 + SET id = 2; +SELECT * FROM fpo_generated ORDER BY valid_at; + id | valid_at | id_plus_len | id_plus_lenv +----+----------+-------------+-------------- + 1 | [10,30) | 21 | 21 + 2 | [30,70) | 42 | 42 + 1 | [70,100) | 31 | 31 +(3 rows) + +DROP TABLE fpo_generated; +-- Test that UPDATE OF colname triggers fire if colname is valid_at: +CREATE TABLE fpo_update_of_trigger ( + id int, + valid_at int4range +); +INSERT INTO fpo_update_of_trigger (id, valid_at) VALUES (1, '[10,100)'); +CREATE TRIGGER fpo_before_row1 + BEFORE UPDATE OF valid_at ON fpo_update_of_trigger + FOR EACH ROW EXECUTE PROCEDURE dump_trigger(false, false); +CREATE TRIGGER fpo_before_row2 + BEFORE UPDATE OF valid_at ON fpo_update_of_trigger + FOR EACH STATEMENT EXECUTE PROCEDURE dump_trigger(false, false); +UPDATE fpo_update_of_trigger + FOR PORTION OF valid_at FROM 30 TO 70 + SET id = 2; +NOTICE: fpo_before_row2: BEFORE UPDATE STATEMENT: +NOTICE: old: +NOTICE: new: +NOTICE: fpo_before_row1: BEFORE UPDATE ROW: +NOTICE: old: [10,100) +NOTICE: new: [30,70) +DROP TABLE fpo_update_of_trigger; ++======= ++>>>>>>> theirs RESET datestyle; diff --cc src/test/regress/sql/for_portion_of.sql index 7b08f8cf45e,fd79a9b78e7..00000000000 --- a/src/test/regress/sql/for_portion_of.sql +++ b/src/test/regress/sql/for_portion_of.sql @@@ -1448,147 -1398,4 +1448,150 @@@ SELECT * FROM fpo_rule ORDER BY f1 DROP TABLE fpo_rule; ++<<<<<<< ours +-- UPDATE/DELETE FOR PORTION OF with table inheritance +-- Leftover rows must stay in the child table, preserving child-specific columns. +CREATE TABLE fpo_inh_parent ( + id int4range, + valid_at daterange, + name text +); +CREATE TABLE fpo_inh_child ( + description text +) INHERITS (fpo_inh_parent); + +-- Update targets the parent; the matching row lives in the child. +INSERT INTO fpo_inh_child (id, valid_at, name, description) VALUES + ('[1,2)', '[2018-01-01,2019-01-01)', 'one', 'initial'); +UPDATE fpo_inh_parent FOR PORTION OF valid_at FROM '2018-04-01' TO '2018-10-01' + SET name = 'one^1'; +-- All three rows should be in the child, with description preserved. +SELECT tableoid::regclass, * FROM fpo_inh_parent ORDER BY valid_at; +SELECT * FROM fpo_inh_child ORDER BY valid_at; +-- No rows should have leaked into the parent. +SELECT * FROM ONLY fpo_inh_parent ORDER BY valid_at; + +-- Same test for DELETE instead of UPDATE: +TRUNCATE fpo_inh_child, fpo_inh_parent; +INSERT INTO fpo_inh_child (id, valid_at, name, description) VALUES + ('[1,2)', '[2018-01-01,2019-01-01)', 'one', 'initial'); +DELETE FROM fpo_inh_parent FOR PORTION OF valid_at FROM '2018-04-01' TO '2018-10-01'; +-- Both rows should be in the child, with description preserved. +SELECT tableoid::regclass, * FROM fpo_inh_parent ORDER BY valid_at; +SELECT * FROM fpo_inh_child ORDER BY valid_at; +-- No rows should have leaked into the parent. +SELECT * FROM ONLY fpo_inh_parent ORDER BY valid_at; + +DROP TABLE fpo_inh_parent CASCADE; + +-- UPDATE FOR PORTION OF with multiple inheritance +-- Leftover rows must stay in the child table, even if the range column's +-- attnum differs between the target parent and child. +CREATE TABLE temporal_parent ( + id int, + valid_at daterange, + name text +); +CREATE TABLE other_parent ( + prefix text, + note text +); +CREATE TABLE mi_child () INHERITS (other_parent, temporal_parent); + +-- attnum of the range column is different in temporal_parent and mi_child +SELECT attnum, attname + FROM pg_attribute + WHERE attrelid = 'temporal_parent'::regclass + AND attnum > 0 AND NOT attisdropped + ORDER BY attnum; +SELECT attnum, attname + FROM pg_attribute + WHERE attrelid = 'mi_child'::regclass + AND attnum > 0 AND NOT attisdropped + ORDER BY attnum; + +INSERT INTO mi_child (prefix, note, id, valid_at, name) VALUES + ('pfx', 'memo', 1, daterange('2000-01-01', '2010-01-01'), 'old'); + +UPDATE temporal_parent FOR PORTION OF valid_at FROM '2001-01-01' TO '2002-01-01' + SET name = 'new' + WHERE id = 1; + +SELECT tableoid::regclass, * FROM temporal_parent ORDER BY valid_at; +SELECT * FROM mi_child ORDER BY valid_at; +SELECT * FROM ONLY temporal_parent ORDER BY valid_at; + +TRUNCATE mi_child, other_parent, temporal_parent; +INSERT INTO mi_child (prefix, note, id, valid_at, name) VALUES + ('pfx', 'memo', 1, daterange('2000-01-01', '2010-01-01'), 'old'); + +DELETE FROM temporal_parent FOR PORTION OF valid_at FROM '2001-01-01' TO '2002-01-01' + WHERE id = 1; + +SELECT tableoid::regclass, * FROM temporal_parent ORDER BY valid_at; +SELECT * FROM mi_child ORDER BY valid_at; +SELECT * FROM ONLY temporal_parent ORDER BY valid_at; + +DROP TABLE temporal_parent CASCADE; + +-- UPDATE FOR PORTION OF with generated columns +-- The generated column depends on the range column, so it must be +-- recomputed when FOR PORTION OF narrows the range. +CREATE TABLE fpo_generated ( + id int, + valid_at int4range, + range_len int GENERATED ALWAYS AS (upper(valid_at) - lower(valid_at)) STORED, + range_lenv int GENERATED ALWAYS AS (upper(valid_at) - lower(valid_at)) +); +INSERT INTO fpo_generated (id, valid_at) VALUES (1, '[10,100)'); + +SELECT * FROM fpo_generated ORDER BY valid_at; + +-- After the FOR PORTION OF (FPO) update, all three resulting rows +-- (leftover-before, updated, and leftover-after) must contain the correct +-- values for range_len and range_lenv. +UPDATE fpo_generated + FOR PORTION OF valid_at FROM 30 TO 70 + SET id = 2; + +SELECT * FROM fpo_generated ORDER BY valid_at; + +-- Also test with a generated column that references both a SET column +-- and the range column. +DROP TABLE fpo_generated; +CREATE TABLE fpo_generated ( + id int, + valid_at int4range, + id_plus_len int GENERATED ALWAYS AS (id + upper(valid_at) - lower(valid_at)) STORED, + id_plus_lenv int GENERATED ALWAYS AS (id + upper(valid_at) - lower(valid_at)) +); + +INSERT INTO fpo_generated (id, valid_at) VALUES (1, '[10,100)'); +SELECT * FROM fpo_generated ORDER BY valid_at; + +UPDATE fpo_generated + FOR PORTION OF valid_at FROM 30 TO 70 + SET id = 2; +SELECT * FROM fpo_generated ORDER BY valid_at; +DROP TABLE fpo_generated; + +-- Test that UPDATE OF colname triggers fire if colname is valid_at: +CREATE TABLE fpo_update_of_trigger ( + id int, + valid_at int4range +); +INSERT INTO fpo_update_of_trigger (id, valid_at) VALUES (1, '[10,100)'); +CREATE TRIGGER fpo_before_row1 + BEFORE UPDATE OF valid_at ON fpo_update_of_trigger + FOR EACH ROW EXECUTE PROCEDURE dump_trigger(false, false); +CREATE TRIGGER fpo_before_row2 + BEFORE UPDATE OF valid_at ON fpo_update_of_trigger + FOR EACH STATEMENT EXECUTE PROCEDURE dump_trigger(false, false); +UPDATE fpo_update_of_trigger + FOR PORTION OF valid_at FROM 30 TO 70 + SET id = 2; +DROP TABLE fpo_update_of_trigger; + ++======= ++>>>>>>> theirs RESET datestyle;