0001_merge_v24_onconflict_work.patch

application/octet-stream

Filename: 0001_merge_v24_onconflict_work.patch
Type: application/octet-stream
Part: 1
Message: Re: [HACKERS] MERGE SQL Statement for PG11

Patch

Format: unified
Series: patch v24
File+
src/backend/catalog/heap.c 1 1
src/backend/catalog/partition.c 45 17
src/backend/commands/tablecmds.c 9 6
src/backend/executor/execPartition.c 7 7
src/backend/optimizer/prep/preptlist.c 12 13
src/backend/optimizer/prep/prepunion.c 72 10
src/include/catalog/partition.h 1 1
src/include/optimizer/prep.h 10 0
commit 86580b5d2c9b75c356393340a41fb22ba7ca4203
Author: Pavan Deolasee <pavan.deolasee@gmail.com>
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 */