From eb11d8fbe02530dc6f4fbfa162c59baae46df80c Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Wed, 28 Feb 2018 20:20:08 -0300 Subject: [PATCH v3 3/3] fixups --- src/backend/catalog/partition.c | 52 ++++++++++++---------- src/backend/executor/execPartition.c | 81 +++++++++++++--------------------- src/backend/optimizer/prep/prepunion.c | 59 ++++++++++++++++++++----- src/include/optimizer/prep.h | 15 +++---- 4 files changed, 115 insertions(+), 92 deletions(-) diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index 9d1ad09595..ef2ef3aa80 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -192,7 +192,7 @@ static int get_partition_bound_num_indexes(PartitionBoundInfo b); static int get_greatest_modulus(PartitionBoundInfo b); static uint64 compute_hash_value(int partnatts, FmgrInfo *partsupfunc, Datum *values, bool *isnull); -static Oid get_partition_parent_recurse(Oid relid, bool getroot); +static Oid get_partition_parent_recurse(Relation inhRel, Oid relid, bool getroot); /* * RelationBuildPartitionDesc @@ -1385,8 +1385,10 @@ check_default_allows_bound(Relation parent, Relation default_rel, /* * get_partition_parent + * Obtain direct parent or topmost ancestor of given relation * - * Returns inheritance parent of a partition by scanning pg_inherits + * Returns direct inheritance parent of a partition by scanning pg_inherits; + * or, if 'getroot' is true, the topmost parent in the inheritance hierarchy. * * Note: Because this function assumes that the relation whose OID is passed * as an argument will have precisely one parent, it should only be called @@ -1395,26 +1397,32 @@ check_default_allows_bound(Relation parent, Relation default_rel, Oid get_partition_parent(Oid relid, bool getroot) { - Oid parentOid = get_partition_parent_recurse(relid, getroot); + Relation inhRel; + Oid parentOid; + inhRel = heap_open(InheritsRelationId, AccessShareLock); + + parentOid = get_partition_parent_recurse(inhRel, relid, getroot); if (parentOid == InvalidOid) elog(ERROR, "could not find parent of relation %u", relid); + heap_close(inhRel, AccessShareLock); + return parentOid; } +/* + * get_partition_parent_recurse + * Recursive part of get_partition_parent + */ static Oid -get_partition_parent_recurse(Oid relid, bool getroot) +get_partition_parent_recurse(Relation inhRel, Oid relid, bool getroot) { - Form_pg_inherits form; - Relation catalogRelation; SysScanDesc scan; ScanKeyData key[2]; HeapTuple tuple; Oid result = InvalidOid; - catalogRelation = heap_open(InheritsRelationId, AccessShareLock); - ScanKeyInit(&key[0], Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, F_OIDEQ, @@ -1424,28 +1432,26 @@ get_partition_parent_recurse(Oid relid, bool getroot) BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(1)); - scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, true, + /* Obtain the direct parent, and release resources before recursing */ + scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId, true, NULL, 2, key); - tuple = systable_getnext(scan); if (HeapTupleIsValid(tuple)) - { - form = (Form_pg_inherits) GETSTRUCT(tuple); - result = form->inhparent; - - if (getroot) - result = get_partition_parent_recurse(result, getroot); - } - + result = ((Form_pg_inherits) GETSTRUCT(tuple))->inhparent; systable_endscan(scan); - heap_close(catalogRelation, AccessShareLock); /* - * If we recursed and got InvalidOid as parent, that means we reached the - * root of this partition tree in the form of 'relid' itself. + * If we were asked to recurse, do so now. Except that if we didn't get a + * valid parent, then the 'relid' argument was already the topmost parent, + * so return that. */ - if (getroot && !OidIsValid(result)) - return relid; + if (getroot) + { + if (OidIsValid(result)) + return get_partition_parent_recurse(inhRel, result, getroot); + else + return relid; + } return result; } diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 3f7b61dc37..7ea0295d3c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -65,6 +65,7 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel) int num_update_rri = 0, update_rri_index = 0; PartitionTupleRouting *proute; + int nparts; /* * Get the information about the partition tree after locking all the @@ -75,14 +76,12 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel) proute->partition_dispatch_info = RelationGetPartitionDispatchInfo(rel, &proute->num_dispatch, &leaf_parts); - proute->num_partitions = list_length(leaf_parts); - proute->partitions = (ResultRelInfo **) palloc(proute->num_partitions * - sizeof(ResultRelInfo *)); + proute->num_partitions = nparts = list_length(leaf_parts); + proute->partitions = + (ResultRelInfo **) palloc(nparts * sizeof(ResultRelInfo *)); proute->parent_child_tupconv_maps = - (TupleConversionMap **) palloc0(proute->num_partitions * - sizeof(TupleConversionMap *)); - proute->partition_oids = (Oid *) palloc(proute->num_partitions * - sizeof(Oid)); + (TupleConversionMap **) palloc0(nparts * sizeof(TupleConversionMap *)); + proute->partition_oids = (Oid *) palloc(nparts * sizeof(Oid)); /* Set up details specific to the type of tuple routing we are doing. */ if (mtstate && mtstate->operation == CMD_UPDATE) @@ -116,15 +115,12 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel) */ if (mtstate && mtstate->mt_onconflict != ONCONFLICT_NONE) { - proute->partition_arbiter_indexes = (List **) - palloc(proute->num_partitions * - sizeof(List *)); - proute->partition_conflproj_slots = (TupleTableSlot **) - palloc(proute->num_partitions * - sizeof(TupleTableSlot *)); - proute->partition_existing_slots = (TupleTableSlot **) - palloc(proute->num_partitions * - sizeof(TupleTableSlot *)); + proute->partition_arbiter_indexes = + (List **) palloc(nparts * sizeof(List *)); + proute->partition_conflproj_slots = + (TupleTableSlot **) palloc(nparts * sizeof(TupleTableSlot *)); + proute->partition_existing_slots = + (TupleTableSlot **) palloc(nparts * sizeof(TupleTableSlot *)); } i = 0; @@ -537,48 +533,33 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, { /* Convert expressions contain partition's attnos. */ List *conv_setproj; - AppendRelInfo appinfo; TupleDesc tupDesc; /* Need our own slot. */ part_existing_slot = ExecInitExtraTupleSlot(mtstate->ps.state, partrelDesc); - /* First convert references to EXCLUDED pseudo-relation. */ - conv_setproj = map_partition_varattnos((List *) - node->onConflictSet, - INNER_VAR, - partrel, - firstResultRel, NULL); + /* + * First convert references to the EXCLUDED pseudo-relation, which + * was set to INNER_VAR by set_plan_references. + */ + conv_setproj = + map_partition_varattnos((List *) node->onConflictSet, + INNER_VAR, partrel, + firstResultRel, NULL); + /* Then convert references to main target relation. */ - conv_setproj = map_partition_varattnos((List *) - conv_setproj, - firstVarno, - partrel, - firstResultRel, NULL); + conv_setproj = + map_partition_varattnos((List *) conv_setproj, + firstVarno, partrel, + firstResultRel, NULL); - /* - * Need to fix the target entries' resnos too by using - * inheritance translation. - */ - appinfo.type = T_AppendRelInfo; - appinfo.parent_relid = firstVarno; - appinfo.parent_reltype = firstResultRel->rd_rel->reltype; - appinfo.child_relid = partrel->rd_id; - appinfo.child_reltype = partrel->rd_rel->reltype; - appinfo.parent_reloid = firstResultRel->rd_id; - make_inh_translation_list(firstResultRel, partrel, - 1, /* dummy */ - &appinfo.translated_vars); - conv_setproj = adjust_inherited_tlist((List *) conv_setproj, - &appinfo); - - /* - * Add any attributes that are missing in the source list, such - * as, dropped columns in the partition. - */ - conv_setproj = expand_targetlist(conv_setproj, CMD_UPDATE, - firstVarno, partrel); + conv_setproj = + adjust_and_expand_partition_tlist(RelationGetDescr(firstResultRel), + RelationGetDescr(partrel), + RelationGetRelationName(partrel), + firstVarno, + conv_setproj); tupDesc = ExecTypeFromTL(conv_setproj, partrelDesc->tdhasoid); part_conflproj_slot = ExecInitExtraTupleSlot(mtstate->ps.state, diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 4153891f29..c11f6c20ab 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -124,6 +124,8 @@ static Node *adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_context *context); static Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos); +static List *adjust_inherited_tlist(List *tlist, + AppendRelInfo *context); /* @@ -2357,7 +2359,7 @@ adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, * * Note that this is not needed for INSERT because INSERT isn't inheritable. */ -List * +static List * adjust_inherited_tlist(List *tlist, AppendRelInfo *context) { bool changed_it = false; @@ -2379,8 +2381,10 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) continue; /* ignore junk items */ /* - * ignore dummy tlist entry added by exapnd_targetlist() for - * dropped columns in the parent table. + * XXX ugly hack: must ignore dummy tlist entry added by + * expand_targetlist() for dropped columns in the parent table or we + * fail because there is no translation. Must find a better way to + * deal with this case, though. */ if (IsA(tle->expr, Const) && ((Const *) tle->expr)->constisnull) continue; @@ -2423,10 +2427,7 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) if (tle->resjunk) continue; /* ignore junk items */ - /* - * ignore dummy tlist entry added by exapnd_targetlist() for - * dropped columns in the parent table. - */ + /* XXX ugly hack; see above */ if (IsA(tle->expr, Const) && ((Const *) tle->expr)->constisnull) continue; @@ -2444,10 +2445,7 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) if (!tle->resjunk) continue; /* here, ignore non-junk items */ - /* - * ignore dummy tlist entry added by exapnd_targetlist() for - * dropped columns in the parent table. - */ + /* XXX ugly hack; see above */ if (IsA(tle->expr, Const) && ((Const *) tle->expr)->constisnull) continue; @@ -2460,6 +2458,45 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) } /* + * Given a targetlist for the parentRel of the given varno, adjust it to be in + * the correct order and to contain all the needed elements for the given + * partition. + */ +List * +adjust_and_expand_partition_tlist(TupleDesc parentDesc, + TupleDesc partitionDesc, + char *partitionRelname, + int parentVarno, + List *targetlist) +{ + AppendRelInfo appinfo; + List *result_tl; + + /* + * Fist, fix the target entries' resnos, by using inheritance translation. + */ + appinfo.type = T_AppendRelInfo; + appinfo.parent_relid = parentVarno; + appinfo.parent_reltype = InvalidOid; // parentRel->rd_rel->reltype; + appinfo.child_relid = -1; + appinfo.child_reltype = InvalidOid; // partrel->rd_rel->reltype; + appinfo.parent_reloid = 1; // dummy parentRel->rd_id; + make_inh_translation_list(parentDesc, partitionDesc, partitionRelname, + 1, /* dummy */ + &appinfo.translated_vars); + result_tl = adjust_inherited_tlist((List *) targetlist, &appinfo); + + /* + * Add any attributes that are missing in the source list, such + * as dropped columns in the partition. + */ + result_tl = expand_targetlist(result_tl, CMD_UPDATE, + parentVarno, partitionDesc); + + return result_tl; +} + +/* * adjust_appendrel_attrs_multilevel * Apply Var translations from a toplevel appendrel parent down to a child. * diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index d380b419d7..c5263f65dc 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -14,6 +14,7 @@ #ifndef PREP_H #define PREP_H +#include "access/tupdesc.h" #include "nodes/plannodes.h" #include "nodes/relation.h" @@ -42,9 +43,8 @@ extern List *preprocess_targetlist(PlannerInfo *root); extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex); -typedef struct RelationData *Relation; extern List *expand_targetlist(List *tlist, int command_type, - Index result_relation, Relation rel); + Index result_relation, TupleDesc tupdesc); /* * prototypes for prepunion.c @@ -69,11 +69,10 @@ extern SpecialJoinInfo *build_child_join_sjinfo(PlannerInfo *root, extern Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, Relids child_relids, Relids top_parent_relids); -extern void make_inh_translation_list(Relation oldrelation, - Relation newrelation, - Index newvarno, - List **translated_vars); -extern List *adjust_inherited_tlist(List *tlist, - AppendRelInfo *context); +extern List *adjust_and_expand_partition_tlist(TupleDesc parentDesc, + TupleDesc partitionDesc, + char *partitionRelname, + int parentVarno, + List *targetlist); #endif /* PREP_H */ -- 2.11.0