commit 86580b5d2c9b75c356393340a41fb22ba7ca4203 Author: Pavan Deolasee Date: Tue Mar 20 10:56:33 2018 +0530 Apply patch(es) from ON CONFLICT DO NOTHING work diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 3d80ff9e5b..13489162df 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1776,7 +1776,7 @@ heap_drop_with_catalog(Oid relid) elog(ERROR, "cache lookup failed for relation %u", relid); if (((Form_pg_class) GETSTRUCT(tuple))->relispartition) { - parentOid = get_partition_parent(relid); + parentOid = get_partition_parent(relid, false); LockRelationOid(parentOid, AccessExclusiveLock); /* diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index 786c05df73..8dc73ae092 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -192,6 +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(Relation inhRel, Oid relid, bool getroot); /* * RelationBuildPartitionDesc @@ -1384,24 +1385,43 @@ 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 * when it is known that the relation is a partition. */ Oid -get_partition_parent(Oid relid) +get_partition_parent(Oid relid, bool 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(Relation inhRel, Oid relid, bool getroot) { - Form_pg_inherits form; - Relation catalogRelation; SysScanDesc scan; ScanKeyData key[2]; HeapTuple tuple; - Oid result; - - catalogRelation = heap_open(InheritsRelationId, AccessShareLock); + Oid result = InvalidOid; ScanKeyInit(&key[0], Anum_pg_inherits_inhrelid, @@ -1412,18 +1432,26 @@ get_partition_parent(Oid relid) 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)) - elog(ERROR, "could not find tuple for parent of relation %u", relid); - - form = (Form_pg_inherits) GETSTRUCT(tuple); - result = form->inhparent; - + if (HeapTupleIsValid(tuple)) + result = ((Form_pg_inherits) GETSTRUCT(tuple))->inhparent; systable_endscan(scan); - heap_close(catalogRelation, AccessShareLock); + + /* + * 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) + { + if (OidIsValid(result)) + return get_partition_parent_recurse(inhRel, result, getroot); + else + return relid; + } return result; } @@ -2505,7 +2533,7 @@ generate_partition_qual(Relation rel) return copyObject(rel->rd_partcheck); /* Grab at least an AccessShareLock on the parent table */ - parent = heap_open(get_partition_parent(RelationGetRelid(rel)), + parent = heap_open(get_partition_parent(RelationGetRelid(rel), false), AccessShareLock); /* Get pg_class.relpartbound */ diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 218224a156..6003afdd03 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1292,7 +1292,7 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid, */ if (is_partition && relOid != oldRelOid) { - state->partParentOid = get_partition_parent(relOid); + state->partParentOid = get_partition_parent(relOid, false); if (OidIsValid(state->partParentOid)) LockRelationOid(state->partParentOid, AccessExclusiveLock); } @@ -5843,7 +5843,8 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode) /* If rel is partition, shouldn't drop NOT NULL if parent has the same */ if (rel->rd_rel->relispartition) { - Oid parentId = get_partition_parent(RelationGetRelid(rel)); + Oid parentId = get_partition_parent(RelationGetRelid(rel), + false); Relation parent = heap_open(parentId, AccessShareLock); TupleDesc tupDesc = RelationGetDescr(parent); AttrNumber parent_attnum; @@ -14360,7 +14361,7 @@ ATExecDetachPartition(Relation rel, RangeVar *name) if (!has_superclass(idxid)) continue; - Assert((IndexGetRelation(get_partition_parent(idxid), false) == + Assert((IndexGetRelation(get_partition_parent(idxid, false), false) == RelationGetRelid(rel))); idx = index_open(idxid, AccessExclusiveLock); @@ -14489,7 +14490,7 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name) /* Silently do nothing if already in the right state */ currParent = !has_superclass(partIdxId) ? InvalidOid : - get_partition_parent(partIdxId); + get_partition_parent(partIdxId, false); if (currParent != RelationGetRelid(parentIdx)) { IndexInfo *childInfo; @@ -14722,8 +14723,10 @@ validatePartitionedIndex(Relation partedIdx, Relation partedTbl) /* make sure we see the validation we just did */ CommandCounterIncrement(); - parentIdxId = get_partition_parent(RelationGetRelid(partedIdx)); - parentTblId = get_partition_parent(RelationGetRelid(partedTbl)); + parentIdxId = get_partition_parent(RelationGetRelid(partedIdx), + false); + parentTblId = get_partition_parent(RelationGetRelid(partedTbl), + false); parentIdx = relation_open(parentIdxId, AccessExclusiveLock); parentTbl = relation_open(parentTblId, AccessExclusiveLock); Assert(!parentIdx->rd_index->indisvalid); diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index ce9a4e16cf..4147121575 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -19,6 +19,7 @@ #include "executor/executor.h" #include "mb/pg_wchar.h" #include "miscadmin.h" +#include "optimizer/prep.h" #include "utils/lsyscache.h" #include "utils/rls.h" #include "utils/ruleutils.h" @@ -64,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 @@ -74,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) diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 8603feef2b..e2995e6592 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -53,8 +53,6 @@ #include "utils/rel.h" -static List *expand_targetlist(List *tlist, int command_type, - Index result_relation, Relation rel); /* @@ -116,7 +114,8 @@ preprocess_targetlist(PlannerInfo *root) tlist = parse->targetList; if (command_type == CMD_INSERT || command_type == CMD_UPDATE) tlist = expand_targetlist(tlist, command_type, - result_relation, target_relation); + result_relation, + RelationGetDescr(target_relation)); /* * Add necessary junk columns for rowmarked rels. These values are needed @@ -230,7 +229,7 @@ preprocess_targetlist(PlannerInfo *root) expand_targetlist(parse->onConflict->onConflictSet, CMD_UPDATE, result_relation, - target_relation); + RelationGetDescr(target_relation)); if (target_relation) heap_close(target_relation, NoLock); @@ -247,13 +246,13 @@ preprocess_targetlist(PlannerInfo *root) /* * expand_targetlist - * Given a target list as generated by the parser and a result relation, - * add targetlist entries for any missing attributes, and ensure the - * non-junk attributes appear in proper field order. + * Given a target list as generated by the parser and a result relation's + * tuple descriptor, add targetlist entries for any missing attributes, and + * ensure the non-junk attributes appear in proper field order. */ -static List * +List * expand_targetlist(List *tlist, int command_type, - Index result_relation, Relation rel) + Index result_relation, TupleDesc tupdesc) { List *new_tlist = NIL; ListCell *tlist_item; @@ -266,14 +265,14 @@ expand_targetlist(List *tlist, int command_type, * The rewriter should have already ensured that the TLEs are in correct * order; but we have to insert TLEs for any missing attributes. * - * Scan the tuple description in the relation's relcache entry to make - * sure we have all the user attributes in the right order. + * Scan the tuple description to make sure we have all the user attributes + * in the right order. */ - numattrs = RelationGetNumberOfAttributes(rel); + numattrs = tupdesc->natts; for (attrno = 1; attrno <= numattrs; attrno++) { - Form_pg_attribute att_tup = TupleDescAttr(rel->rd_att, attrno - 1); + Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1); TargetEntry *new_tle = NULL; if (tlist_item != NULL) diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index f087369f75..8bba97be74 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -112,8 +112,9 @@ static void expand_single_inheritance_child(PlannerInfo *root, PlanRowMark *top_parentrc, Relation childrel, List **appinfos, RangeTblEntry **childrte_p, Index *childRTindex_p); -static void make_inh_translation_list(Relation oldrelation, - Relation newrelation, +static void make_inh_translation_list(TupleDesc old_tupdesc, + TupleDesc new_tupdesc, + char *new_rel_name, Index newvarno, List **translated_vars); static Bitmapset *translate_col_privs(const Bitmapset *parent_privs, @@ -1764,7 +1765,10 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, appinfo->child_relid = childRTindex; appinfo->parent_reltype = parentrel->rd_rel->reltype; appinfo->child_reltype = childrel->rd_rel->reltype; - make_inh_translation_list(parentrel, childrel, childRTindex, + make_inh_translation_list(RelationGetDescr(parentrel), + RelationGetDescr(childrel), + RelationGetRelationName(childrel), + childRTindex, &appinfo->translated_vars); appinfo->parent_reloid = parentOID; *appinfos = lappend(*appinfos, appinfo); @@ -1828,16 +1832,18 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, * For paranoia's sake, we match type/collation as well as attribute name. */ static void -make_inh_translation_list(Relation oldrelation, Relation newrelation, +make_inh_translation_list(TupleDesc old_tupdesc, TupleDesc new_tupdesc, + char *new_rel_name, Index newvarno, List **translated_vars) { List *vars = NIL; - TupleDesc old_tupdesc = RelationGetDescr(oldrelation); - TupleDesc new_tupdesc = RelationGetDescr(newrelation); int oldnatts = old_tupdesc->natts; int newnatts = new_tupdesc->natts; int old_attno; + bool equal_tupdescs; + + equal_tupdescs = equalTupleDescs(old_tupdesc, new_tupdesc); for (old_attno = 0; old_attno < oldnatts; old_attno++) { @@ -1864,7 +1870,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation, * When we are generating the "translation list" for the parent table * of an inheritance set, no need to search for matches. */ - if (oldrelation == newrelation) + if (equal_tupdescs) { vars = lappend(vars, makeVar(newvarno, (AttrNumber) (old_attno + 1), @@ -1901,16 +1907,16 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation, } if (new_attno >= newnatts) elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"", - attname, RelationGetRelationName(newrelation)); + attname, new_rel_name); } /* Found it, check type and collation match */ if (atttypid != att->atttypid || atttypmod != att->atttypmod) elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type", - attname, RelationGetRelationName(newrelation)); + attname, new_rel_name); if (attcollation != att->attcollation) elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation", - attname, RelationGetRelationName(newrelation)); + attname, new_rel_name); vars = lappend(vars, makeVar(newvarno, (AttrNumber) (new_attno + 1), @@ -2408,6 +2414,15 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) if (tle->resjunk) continue; /* ignore junk items */ + /* + * 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; + /* Look up the translation of this column: it must be a Var */ if (tle->resno <= 0 || tle->resno > list_length(context->translated_vars)) @@ -2446,6 +2461,10 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) if (tle->resjunk) continue; /* ignore junk items */ + /* XXX ugly hack; see above */ + if (IsA(tle->expr, Const) && ((Const *) tle->expr)->constisnull) + continue; + if (tle->resno == attrno) new_tlist = lappend(new_tlist, tle); else if (tle->resno > attrno) @@ -2460,6 +2479,10 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) if (!tle->resjunk) continue; /* here, ignore non-junk items */ + /* XXX ugly hack; see above */ + if (IsA(tle->expr, Const) && ((Const *) tle->expr)->constisnull) + continue; + tle->resno = attrno; new_tlist = lappend(new_tlist, tle); attrno++; @@ -2468,6 +2491,45 @@ adjust_inherited_tlist(List *tlist, AppendRelInfo *context) return new_tlist; } +/* + * 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/catalog/partition.h b/src/include/catalog/partition.h index 2faf0ca26e..70ddb225a1 100644 --- a/src/include/catalog/partition.h +++ b/src/include/catalog/partition.h @@ -51,7 +51,7 @@ extern PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, extern void check_new_partition_bound(char *relname, Relation parent, PartitionBoundSpec *spec); -extern Oid get_partition_parent(Oid relid); +extern Oid get_partition_parent(Oid relid, bool getroot); extern List *get_qual_from_partbound(Relation rel, Relation parent, PartitionBoundSpec *spec); extern List *map_partition_varattnos(List *expr, int fromrel_varno, diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index 38608770a2..7074bae79a 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,6 +43,9 @@ extern List *preprocess_targetlist(PlannerInfo *root); extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex); +extern List *expand_targetlist(List *tlist, int command_type, + Index result_relation, TupleDesc tupdesc); + /* * prototypes for prepunion.c */ @@ -65,4 +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 List *adjust_and_expand_partition_tlist(TupleDesc parentDesc, + TupleDesc partitionDesc, + char *partitionRelname, + int parentVarno, + List *targetlist); + #endif /* PREP_H */