UPDATE FOR PORTION OF + table inheritance misroutes leftover rows to parent

From: SATYANARAYANA NARLAPURAM <satyanarlapuram(at)gmail(dot)com>
To: PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: UPDATE FOR PORTION OF + table inheritance misroutes leftover rows to parent
Date: 2026-04-07 09:28:50
Message-ID: CAHg+QDcsXsUVaZ+JwM02yDRQEi=cL_rTH_ROLDYgOx004sQu7A@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi hackers,

I found a bug with UPDATE ... FOR PORTION OF when used with traditional
table inheritance. When an UPDATE targets a parent table and the matching
row lives in a child that has extra columns, the temporal leftover rows are
inserted into the parent table instead of back into the child. This causes
child-specific column values to be lost.

Reproduction:

SET datestyle TO ISO, YMD;

CREATE TABLE parent (
id int4range,
valid_at daterange,
name text
);
CREATE TABLE child (
description text
) INHERITS (parent);

INSERT INTO child (id, valid_at, name, description)
VALUES ('[1,2)', '[2018-01-01,2019-01-01)', 'one', 'initial');

UPDATE parent
FOR PORTION OF valid_at FROM '2018-04-01' TO '2018-10-01'
SET name = 'one^1';

Expected: all three resulting rows stay in "child" with description
preserved:

child | [1,2) | [2018-01-01,2018-04-01) | one | initial
child | [1,2) | [2018-04-01,2018-10-01) | one^1 | initial
child | [1,2) | [2018-10-01,2019-01-01) | one | initial

Actual: the two leftover rows land in "parent", losing the description
column:

parent | [1,2) | [2018-01-01,2018-04-01) | one
child | [1,2) | [2018-04-01,2018-10-01) | one^1 | initial
parent | [1,2) | [2018-10-01,2019-01-01) | one

Root cause:

In ExecForPortionOfLeftovers(), the code unconditionally redirects leftover
inserts to ri_RootResultRelInfo whenever the current resultRelInfo has one
set:

if (resultRelInfo->ri_RootResultRelInfo)
resultRelInfo = resultRelInfo->ri_RootResultRelInfo;

The comment says “If there are partitions, we must insert into the root
table, so we get tuple routing.” That logic makes sense for partitioned
tables, because tuple routing will forward the INSERT to the correct
partition.

However, this breaks traditional inheritance. In that case there’s no tuple
routing, so the insert ends up going directly into the parent table. On top
of that, the fp_Leftover slot uses the root’s tuple descriptor, which
doesn’t include the child’s extra columns. Attached a draft patch to fix
this issue and also added tests.

Thanks,
Satya

Attachment Content-Type Size
v1-0001-fpo-inheritance-fix.patch application/octet-stream 5.2 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Antonin Houska 2026-04-07 09:29:17 Re: Adding REPACK [concurrently]
Previous Message Alvaro Herrera 2026-04-07 09:22:18 Re: Adding REPACK [concurrently]