Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6b0208e

Browse files
committed
Fix partition tuple routing with dropped attributes
When trying to insert a tuple into a partitioned table, the routing to the correct partition has been messed up by mixing when a tuple needs to be stored in an intermediate parent's slot and when a tuple needs to be converted because of attribute changes between the immediate parent relation and the parent relation one level above that (the grandparent). This could trigger errors like the following: ERROR: cannot extract attribute from empty tuple slot SQL state: XX000 This was not detected because regression tests with dropped attributes only included tests with two levels of partitioning, and this can be triggered with three levels or more. This fixes bug #15733, which has been introduced by 34295b8. The bug happens only on REL_11_STABLE and HEAD gains the regression tests added for this bug. Reported-by: Petr Fedorov Author: Amit Langote, Michael Paquier Discussion: https://postgr.es/m/15733-7692379e310b80ec@postgresql.org
1 parent a7ca25c commit 6b0208e

File tree

3 files changed

+93
-15
lines changed

3 files changed

+93
-15
lines changed

src/backend/executor/execPartition.c

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -253,16 +253,25 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
253253
partdesc = RelationGetPartitionDesc(rel);
254254

255255
/*
256-
* Convert the tuple to this parent's layout, if different from the
257-
* current relation.
256+
* Use the slot dedicated to this level's parent. All parents except
257+
* the root have a dedicated slot. For the root parent, we just use
258+
* the original input slot.
258259
*/
259-
myslot = dispatch->tupslot;
260-
if (myslot != NULL && map != NULL)
260+
myslot = dispatch->tupslot == NULL ? slot : dispatch->tupslot;
261+
262+
/*
263+
* If the tuple layout of this level's parent is different from the
264+
* previous level's parent, convert the tuple and store it into its
265+
* dedicated slot.
266+
*/
267+
if (myslot != slot)
261268
{
262-
tuple = do_convert_tuple(tuple, map);
269+
if (map != NULL)
270+
tuple = do_convert_tuple(tuple, map);
263271
ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
264-
slot = myslot;
265272
}
273+
else
274+
Assert(map == NULL);
266275

267276
/*
268277
* Extract partition key from tuple. Expression evaluation machinery
@@ -272,8 +281,8 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
272281
* partitioning level has different tuple descriptor from the parent.
273282
* So update ecxt_scantuple accordingly.
274283
*/
275-
ecxt->ecxt_scantuple = slot;
276-
FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
284+
ecxt->ecxt_scantuple = myslot;
285+
FormPartitionKeyDatum(dispatch, myslot, estate, values, isnull);
277286

278287
/*
279288
* Nothing for get_partition_for_tuple() to do if there are no
@@ -309,19 +318,19 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
309318
dispatch = pd[-dispatch->indexes[cur_index]];
310319

311320
/*
312-
* Release the dedicated slot, if it was used. Create a copy of
313-
* the tuple first, for the next iteration.
321+
* Make a copy of the tuple for the next level of routing. If
322+
* this level's parent had a dedicated slot, we must clear its
323+
* tuple too, which would be the copy we made in the last
324+
* iteration.
314325
*/
315-
if (slot == myslot)
316-
{
317-
tuple = ExecCopySlotTuple(myslot);
326+
tuple = ExecCopySlotTuple(myslot);
327+
if (myslot != slot)
318328
ExecClearTuple(myslot);
319-
}
320329
}
321330
}
322331

323332
/* Release the tuple in the lowest parent's dedicated slot. */
324-
if (slot == myslot)
333+
if (myslot != slot)
325334
ExecClearTuple(myslot);
326335

327336
/* A partition was not found. */

src/test/regress/expected/insert.out

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,47 @@ select tableoid::regclass, * from mlparted_def;
629629
mlparted_defd | 70 | 100 |
630630
(4 rows)
631631

632+
-- Check multi-level tuple routing with attributes dropped from the
633+
-- top-most parent. First remove the last attribute.
634+
alter table mlparted add d int, add e int;
635+
alter table mlparted drop e;
636+
create table mlparted5 partition of mlparted
637+
for values from (1, 40) to (1, 50) partition by range (c);
638+
create table mlparted5_ab partition of mlparted5
639+
for values from ('a') to ('c') partition by list (c);
640+
create table mlparted5_a partition of mlparted5_ab for values in ('a');
641+
create table mlparted5_b (d int, b int, c text, a int);
642+
alter table mlparted5_ab attach partition mlparted5_b for values in ('b');
643+
truncate mlparted;
644+
insert into mlparted values (1, 2, 'a', 1);
645+
insert into mlparted values (1, 40, 'a', 1); -- goes to mlparted5_a
646+
insert into mlparted values (1, 45, 'b', 1); -- goes to mlparted5_b
647+
select tableoid::regclass, * from mlparted order by a, b, c, d;
648+
tableoid | a | b | c | d
649+
-------------+---+----+---+---
650+
mlparted11 | 1 | 2 | a | 1
651+
mlparted5_a | 1 | 40 | a | 1
652+
mlparted5_b | 1 | 45 | b | 1
653+
(3 rows)
654+
655+
alter table mlparted drop d;
656+
truncate mlparted;
657+
-- Remove the before last attribute.
658+
alter table mlparted add e int, add d int;
659+
alter table mlparted drop e;
660+
insert into mlparted values (1, 2, 'a', 1);
661+
insert into mlparted values (1, 40, 'a', 1); -- goes to mlparted5_a
662+
insert into mlparted values (1, 45, 'b', 1); -- goes to mlparted5_b
663+
select tableoid::regclass, * from mlparted order by a, b, c, d;
664+
tableoid | a | b | c | d
665+
-------------+---+----+---+---
666+
mlparted11 | 1 | 2 | a | 1
667+
mlparted5_a | 1 | 40 | a | 1
668+
mlparted5_b | 1 | 45 | b | 1
669+
(3 rows)
670+
671+
alter table mlparted drop d;
672+
drop table mlparted5;
632673
-- check that message shown after failure to find a partition shows the
633674
-- appropriate key description (or none) in various situations
634675
create table key_desc (a int, b int) partition by list ((a+0));

src/test/regress/sql/insert.sql

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,34 @@ insert into mlparted values (70, 100);
401401

402402
select tableoid::regclass, * from mlparted_def;
403403

404+
-- Check multi-level tuple routing with attributes dropped from the
405+
-- top-most parent. First remove the last attribute.
406+
alter table mlparted add d int, add e int;
407+
alter table mlparted drop e;
408+
create table mlparted5 partition of mlparted
409+
for values from (1, 40) to (1, 50) partition by range (c);
410+
create table mlparted5_ab partition of mlparted5
411+
for values from ('a') to ('c') partition by list (c);
412+
create table mlparted5_a partition of mlparted5_ab for values in ('a');
413+
create table mlparted5_b (d int, b int, c text, a int);
414+
alter table mlparted5_ab attach partition mlparted5_b for values in ('b');
415+
truncate mlparted;
416+
insert into mlparted values (1, 2, 'a', 1);
417+
insert into mlparted values (1, 40, 'a', 1); -- goes to mlparted5_a
418+
insert into mlparted values (1, 45, 'b', 1); -- goes to mlparted5_b
419+
select tableoid::regclass, * from mlparted order by a, b, c, d;
420+
alter table mlparted drop d;
421+
truncate mlparted;
422+
-- Remove the before last attribute.
423+
alter table mlparted add e int, add d int;
424+
alter table mlparted drop e;
425+
insert into mlparted values (1, 2, 'a', 1);
426+
insert into mlparted values (1, 40, 'a', 1); -- goes to mlparted5_a
427+
insert into mlparted values (1, 45, 'b', 1); -- goes to mlparted5_b
428+
select tableoid::regclass, * from mlparted order by a, b, c, d;
429+
alter table mlparted drop d;
430+
drop table mlparted5;
431+
404432
-- check that message shown after failure to find a partition shows the
405433
-- appropriate key description (or none) in various situations
406434
create table key_desc (a int, b int) partition by list ((a+0));

0 commit comments

Comments
 (0)