Re: [HACKERS] UPDATE of partition key
David Rowley <david.rowley@2ndquadrant.com>
On 14 November 2017 at 01:55, David Rowley <david.rowley@2ndquadrant.com> wrote:
> I'll try to continue with the review tomorrow, but I think some other
> reviews are also looming too.
I started looking at this again today. Here's the remainder of my review.
29. ExecSetupChildParentMap gets called here for non-partitioned relations.
Maybe that's not the best function name? The function only seems to do
that when perleaf is True.
Is a leaf a partition of a partitioned table? It's not that clear the
meaning here.
/*
* If we found that we need to collect transition tuples then we may also
* need tuple conversion maps for any children that have TupleDescs that
* aren't compatible with the tuplestores. (We can share these maps
* between the regular and ON CONFLICT cases.)
*/
if (mtstate->mt_transition_capture != NULL ||
mtstate->mt_oc_transition_capture != NULL)
{
int numResultRelInfos;
numResultRelInfos = (mtstate->mt_partition_tuple_slot != NULL ?
mtstate->mt_num_partitions :
mtstate->mt_nplans);
ExecSetupChildParentMap(mtstate, targetRelInfo, numResultRelInfos,
(mtstate->mt_partition_dispatch_info != NULL));
30. The following chunk of code is giving me a headache trying to
verify which arrays are which size:
ExecSetupPartitionTupleRouting(rel,
mtstate->resultRelInfo,
(operation == CMD_UPDATE ? nplans : 0),
node->nominalRelation,
estate,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
&subplan_leaf_map,
&partition_tuple_slot,
&num_parted, &num_partitions);
mtstate->mt_partition_dispatch_info = partition_dispatch_info;
mtstate->mt_num_dispatch = num_parted;
mtstate->mt_partitions = partitions;
mtstate->mt_num_partitions = num_partitions;
mtstate->mt_parentchild_tupconv_maps = partition_tupconv_maps;
mtstate->mt_subplan_partition_offsets = subplan_leaf_map;
mtstate->mt_partition_tuple_slot = partition_tuple_slot;
mtstate->mt_root_tuple_slot = MakeTupleTableSlot();
I know this patch is not completely responsible for it, but you're not
making things any better.
Would it not be better to invent some PartitionTupleRouting struct and
make that struct a member of ModifyTableState and CopyState, then just
pass the pointer to that struct to ExecSetupPartitionTupleRouting()
and have it fill in the required details? I think the complexity of
this is already on the high end, I think you really need to do the
refactor before this gets any worse.
The signature of the function is a bit scary!
extern void ExecSetupPartitionTupleRouting(Relation rel,
ResultRelInfo *update_rri,
int num_update_rri,
Index resultRTindex,
EState *estate,
PartitionDispatch **pd,
ResultRelInfo ***partitions,
TupleConversionMap ***tup_conv_maps,
int **subplan_leaf_map,
TupleTableSlot **partition_tuple_slot,
int *num_parted, int *num_partitions);
What do you think?
31. The following code seems incorrect:
/*
* If this is an UPDATE and a BEFORE UPDATE trigger is present, we may
* need to do update tuple routing.
*/
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_update_before_row &&
operation == CMD_UPDATE)
update_tuple_routing_needed = true;
Shouldn't this be setting update_tuple_routing_needed to false if
there are no before row update triggers? Otherwise, you're setting it
to true regardless of if there are any partition key columns being
UPDATEd. That would make the work you're doing in
inheritance_planner() to set part_cols_updated a waste of time.
Also, this bit of code is a bit confused.
/* Decide whether we need to perform update tuple routing. */
if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
update_tuple_routing_needed = false;
/*
* Build state for tuple routing if it's an INSERT or if it's an UPDATE of
* partition key.
*/
if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
(operation == CMD_INSERT || update_tuple_routing_needed))
The first if test would not be required if you fixed the code where
you set update_tuple_routing_needed = true regardless if its a
partitioned table or not.
So basically, you need to take the node->part_cols_updated from the
planner, if that's true then perform your test for before row update
triggers, set a bool to false if there are none, then proceed to setup
the partition tuple routing for partition table inserts or if your
bool is still true. Right?
32. "WCO" abbreviation is not that common and might need to be expanded.
* Below are required as reference objects for mapping partition
* attno's in expressions such as WCO and RETURNING.
Searching for other comments which mention "WCO" they're all around
places that is easy to understand they mean "With Check Option", e.g.
next to a variable with a more descriptive name. That's not the case
here.
33. "are anyway newly allocated", should "anyway" be "always"?
Otherwise, it does not make sense.
* If this result rel is one of the subplan result rels, let
* ExecEndPlan() close it. For INSERTs, this does not apply because
* all leaf partition result rels are anyway newly allocated.
34. Comment added which mentions a member that does not exist.
* all_part_cols contains all attribute numbers from the parent that are
* used as partitioning columns by the parent or some descendent which is
* itself partitioned.
*
I've not looked at the test coverage as I see Thomas has been looking
at that in some detail.
I'm going to set this patch as waiting for author now.
Thanks again for working on this.
--
David Rowley http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
Commits
-
Avoid referencing off the end of subplan_partition_offsets.
- 945f71db8452 11.0 landed
-
Allow UPDATE to move rows between partitions.
- 2f178441044b 11.0 landed
-
Remove useless lookup of root partitioned rel in ExecInitModifyTable().
- dca48d145e0e 11.0 cited
-
Factor error generation out of ExecPartitionCheck.
- 19c47e7c8202 11.0 landed
-
Minor preparatory refactoring for UPDATE row movement.
- ef6087ee5fa8 11.0 landed
-
Simplify and encapsulate tuple routing support code.
- cc6337d2fed5 11.0 landed
-
Avoid coercing a whole-row variable that is already coerced.
- 1c497fa72df7 11.0 landed
-
Use ResultRelInfo ** rather than ResultRelInfo * for tuple routing.
- 60f7c0abef03 11.0 landed
-
Make RelationGetPartitionDispatchInfo expand depth-first.
- 77b6b5e9ceca 11.0 cited
-
Expand partitioned tables in PartDesc order.
- 30833ba154e0 11.0 cited
-
Use a real RT index when setting up partition tuple routing.
- f81a91db4d1c 10.0 cited
-
Fix transition tables for partition/inheritance.
- 501ed02cf6f4 10.0 cited
-
Fix confusion about number of subplans in partitioned INSERT setup.
- 78a030a44196 10.0 cited
-
Prevent BEFORE triggers from violating partitioning constraints.
- 15ce775faa42 10.0 cited
-
Fire per-statement triggers on partitioned tables.
- e180c8aa8caf 10.0 cited
-
Fix reporting of violations in ExecConstraints, again.
- c0a8ae7be392 10.0 cited
-
Don't scan partitioned tables.
- d3cc37f1d801 10.0 cited
-
Allow FDWs to push down quals without breaking EvalPlanQual rechecks.
- 5fc4c26db512 9.6.0 cited