On Wed, Oct 14, 2020 at 6:04 PM Heikki Linnakangas <hlinn...@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


Reply via email to