Re: partition routing layering in nodeModifyTable.c - Mailing list pgsql-hackers

From Heikki Linnakangas
Subject Re: partition routing layering in nodeModifyTable.c
Date
Msg-id cffe0dd6-8eba-4856-68cf-476fdb8a1235@iki.fi
Whole thread Raw
In response to Re: partition routing layering in nodeModifyTable.c  (Amit Langote <amitlangote09@gmail.com>)
Responses Re: partition routing layering in nodeModifyTable.c
List pgsql-hackers
On Wed, Oct 14, 2020 at 6:04 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:
> I'll continue with the last couple of patches in this thread.

I committed the move of the cross-partition logic to new 
ExecCrossPartitionUpdate() function, with just minor comment editing and 
pgindent. I left out the refactoring around the calls to AFTER ROW 
INSERT/DELETE triggers. I stared at the change for a while, and wasn't 
sure if I liked the patched or the unpatched new version better, so I 
left it alone.

Looking at the last patch, "Revise child-to-root tuple conversion map 
management", that's certainly an improvement. However, I find it 
confusing that sometimes the mapping from child to root is in 
relinfo->ri_ChildToRootMap, and sometimes in 
relinfo->ri_PartitionInfo->pi_PartitionToRootMap. When is each of those 
filled in? If both are set, is it well defined which one is initialized 
first?

In general, I'm pretty confused by the initialization of 
ri_PartitionInfo. Where is initialized, and when? In execnodes.h, the 
definition of ResultRelInfo says:

>     /* info for partition tuple routing (NULL if not set up yet) */
>     struct PartitionRoutingInfo *ri_PartitionInfo;

That implies that the field is initialized lazily. But in 
ExecFindPartition, we have this:

>         if (partidx == partdesc->boundinfo->default_index)
>         {
>             PartitionRoutingInfo *partrouteinfo = rri->ri_PartitionInfo;
> 
>             /*
>              * The tuple must match the partition's layout for the constraint
>              * expression to be evaluated successfully.  If the partition is
>              * sub-partitioned, that would already be the case due to the code
>              * above, but for a leaf partition the tuple still matches the
>              * parent's layout.
>              *
>              * Note that we have a map to convert from root to current
>              * partition, but not from immediate parent to current partition.
>              * So if we have to convert, do it from the root slot; if not, use
>              * the root slot as-is.
>              */
>             if (partrouteinfo)
>             {
>                 TupleConversionMap *map = partrouteinfo->pi_RootToPartitionMap;
> 
>                 if (map)
>                     slot = execute_attr_map_slot(map->attrMap, rootslot,
>                                                  partrouteinfo->pi_PartitionTupleSlot);
>                 else
>                     slot = rootslot;
>             }
> 
>             ExecPartitionCheck(rri, slot, estate, true);
>         }

That check implies that it's not just lazily initialized, the code will 
work differently if ri_PartitionInfo is set or not.

I think all this would be more clear if ri_PartitionInfo and 
ri_ChildToRootMap were both truly lazily initialized, the first time 
they're needed. And if we removed 
ri_PartitionInfo->pi_PartitionToRootMap, and always used 
ri_ChildToRootMap for it.

Maybe remove PartitionRoutingInfo struct altogether, and just move its 
fields directly to ResultRelInfo.

- Heikki



pgsql-hackers by date:

Previous
From: Bruno Lavoie
Date:
Subject: Packaging - Packages names consistency (RPM)
Next
From: Alvaro Herrera
Date:
Subject: Re: Logical Replication - detail message with names of missing columns