diff options
author | Robert Haas <rhaas@postgresql.org> | 2016-12-22 17:31:52 -0500 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2016-12-22 17:36:37 -0500 |
commit | 2ac3ef7a01df859c62d0a02333b646d65eaec5ff (patch) | |
tree | 850532b8c6aac27df50cff9c45a5873b4c0da743 /src/backend/commands/copy.c | |
parent | 12bd7dd317e8f4346fb3507578aca790ede6ebea (diff) | |
download | postgresql-2ac3ef7a01df859c62d0a02333b646d65eaec5ff.tar.gz postgresql-2ac3ef7a01df859c62d0a02333b646d65eaec5ff.zip |
Fix tuple routing in cases where tuple descriptors don't match.
The previous coding failed to work correctly when we have a
multi-level partitioned hierarchy where tables at successive levels
have different attribute numbers for the partition key attributes. To
fix, have each PartitionDispatch object store a standalone
TupleTableSlot initialized with the TupleDesc of the corresponding
partitioned table, along with a TupleConversionMap to map tuples from
the its parent's rowtype to own rowtype. After tuple routing chooses
a leaf partition, we must use the leaf partition's tuple descriptor,
not the root table's. To that end, a dedicated TupleTableSlot for
tuple routing is now allocated in EState.
Amit Langote
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r-- | src/backend/commands/copy.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index d5901651db1..aa25a23336d 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -2436,6 +2436,15 @@ CopyFrom(CopyState cstate) estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate); /* + * Initialize a dedicated slot to manipulate tuples of any given + * partition's rowtype. + */ + if (cstate->partition_dispatch_info) + estate->es_partition_tuple_slot = ExecInitExtraTupleSlot(estate); + else + estate->es_partition_tuple_slot = NULL; + + /* * It's more efficient to prepare a bunch of tuples for insertion, and * insert them in one heap_multi_insert() call, than call heap_insert() * separately for every tuple. However, we can't do that if there are @@ -2484,7 +2493,8 @@ CopyFrom(CopyState cstate) for (;;) { - TupleTableSlot *slot; + TupleTableSlot *slot, + *oldslot = NULL; bool skip_tuple; Oid loaded_oid = InvalidOid; @@ -2571,7 +2581,19 @@ CopyFrom(CopyState cstate) map = cstate->partition_tupconv_maps[leaf_part_index]; if (map) { + Relation partrel = resultRelInfo->ri_RelationDesc; + tuple = do_convert_tuple(tuple, map); + + /* + * We must use the partition's tuple descriptor from this + * point on. Use a dedicated slot from this point on until + * we're finished dealing with the partition. + */ + oldslot = slot; + slot = estate->es_partition_tuple_slot; + Assert(slot != NULL); + ExecSetSlotDescriptor(slot, RelationGetDescr(partrel)); ExecStoreTuple(tuple, slot, InvalidBuffer, true); } @@ -2667,6 +2689,10 @@ CopyFrom(CopyState cstate) { resultRelInfo = saved_resultRelInfo; estate->es_result_relation_info = resultRelInfo; + + /* Switch back to the slot corresponding to the root table */ + Assert(oldslot != NULL); + slot = oldslot; } } } @@ -2714,13 +2740,14 @@ CopyFrom(CopyState cstate) * Remember cstate->partition_dispatch_info[0] corresponds to the root * partitioned table, which we must not try to close, because it is * the main target table of COPY that will be closed eventually by - * DoCopy(). + * DoCopy(). Also, tupslot is NULL for the root partitioned table. */ for (i = 1; i < cstate->num_dispatch; i++) { PartitionDispatch pd = cstate->partition_dispatch_info[i]; heap_close(pd->reldesc, NoLock); + ExecDropSingleTupleTableSlot(pd->tupslot); } for (i = 0; i < cstate->num_partitions; i++) { |