From 49248c88201a4872d94d890f69ca529d49339a2c Mon Sep 17 00:00:00 2001
From: "houzj.fnst" <houzj.fnst@cn.fujitsu.com>
Date: Mon, 24 May 2021 20:44:31 +0800
Subject: [PATCH] -Recursive-search-parent-partkeyexpr

---
 src/backend/commands/tablecmds.c     |  4 +--
 src/backend/executor/execMain.c      |  7 ++--
 src/backend/optimizer/util/plancat.c |  2 +-
 src/backend/utils/cache/partcache.c  | 48 ++++++++++++++++++++++++----
 src/backend/utils/cache/relcache.c   |  2 ++
 src/include/utils/partcache.h        |  2 +-
 src/include/utils/rel.h              |  1 +
 7 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 11e91c4ad3..e48e4a5631 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -17280,7 +17280,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd,
 	 */
 	partBoundConstraint = get_qual_from_partbound(attachrel, rel, cmd->bound);
 	partConstraint = list_concat(partBoundConstraint,
-								 RelationGetPartitionQual(rel));
+								 RelationGetPartitionQual(rel, NULL));
 
 	/* Skip validation if there are no constraints to validate. */
 	if (partConstraint)
@@ -18082,7 +18082,7 @@ DetachAddConstraintIfNeeded(List **wqueue, Relation partRel)
 {
 	List	   *constraintExpr;
 
-	constraintExpr = RelationGetPartitionQual(partRel);
+	constraintExpr = RelationGetPartitionQual(partRel, NULL);
 	constraintExpr = (List *) eval_const_expressions(NULL, (Node *) constraintExpr);
 
 	/*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 8ddbc6d0c2..91bbc5bc25 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1738,12 +1738,13 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
 	 */
 	if (resultRelInfo->ri_PartitionCheckExpr == NULL)
 	{
+		List *partexprs = NIL;
 		/*
 		 * Ensure that the qual tree and prepared expression are in the
 		 * query-lifespan context.
 		 */
 		MemoryContext oldcxt = MemoryContextSwitchTo(estate->es_query_cxt);
-		List	   *qual = RelationGetPartitionQual(resultRelInfo->ri_RelationDesc);
+		List	   *qual = RelationGetPartitionQual(resultRelInfo->ri_RelationDesc, &partexprs);
 
 		/*
 		 * If we have been passed the parent relation, optimize the evaluation
@@ -1757,16 +1758,12 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
 		if (parentrel)
 		{
 			replace_partexpr_with_dummy_var_context cxt;
-			List   *partexprs = RelationGetPartitionKey(parentrel)->partexprs;
 			ListCell *lc;
 			AttrNumber attrno = 1;
 			TupleDesc	partexprs_tupdesc;
 
 			partexprs_tupdesc = CreateTemplateTupleDesc(list_length(partexprs));
 
-			partexprs = map_partition_varattnos(partexprs, 1,
-												resultRelInfo->ri_RelationDesc,
-												parentrel);
 			foreach(lc, partexprs)
 			{
 				Expr   *expr = lfirst(lc);
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5194fdbbf..f274538ba5 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -2399,7 +2399,7 @@ set_baserel_partition_constraint(Relation relation, RelOptInfo *rel)
 	 * implicit-AND format, we'd have to explicitly convert it to explicit-AND
 	 * format and back again.
 	 */
-	partconstr = RelationGetPartitionQual(relation);
+	partconstr = RelationGetPartitionQual(relation, NULL);
 	if (partconstr)
 	{
 		partconstr = (List *) expression_planner((Expr *) partconstr);
diff --git a/src/backend/utils/cache/partcache.c b/src/backend/utils/cache/partcache.c
index 21e60f0c5e..69bc431a69 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -38,7 +38,7 @@
 
 
 static void RelationBuildPartitionKey(Relation relation);
-static List *generate_partition_qual(Relation rel);
+static List *generate_partition_qual(Relation rel, List **partkeys);
 
 /*
  * RelationGetPartitionKey -- get partition key, if relation is partitioned
@@ -273,13 +273,13 @@ RelationBuildPartitionKey(Relation relation)
  * Returns a list of partition quals
  */
 List *
-RelationGetPartitionQual(Relation rel)
+RelationGetPartitionQual(Relation rel, List **partkeys)
 {
 	/* Quick exit */
 	if (!rel->rd_rel->relispartition)
 		return NIL;
 
-	return generate_partition_qual(rel);
+	return generate_partition_qual(rel, partkeys);
 }
 
 /*
@@ -305,7 +305,7 @@ get_partition_qual_relid(Oid relid)
 		Relation	rel = relation_open(relid, AccessShareLock);
 		List	   *and_args;
 
-		and_args = generate_partition_qual(rel);
+		and_args = generate_partition_qual(rel, NULL);
 
 		/* Convert implicit-AND list format to boolean expression */
 		if (and_args == NIL)
@@ -333,7 +333,7 @@ get_partition_qual_relid(Oid relid)
  * into long-lived cache contexts, especially if we fail partway through.
  */
 static List *
-generate_partition_qual(Relation rel)
+generate_partition_qual(Relation rel, List **partkeys)
 {
 	HeapTuple	tuple;
 	MemoryContext oldcxt;
@@ -349,7 +349,12 @@ generate_partition_qual(Relation rel)
 
 	/* If we already cached the result, just return a copy */
 	if (rel->rd_partcheckvalid)
+	{
+		if (partkeys != NULL && rel->rd_keyexpr_list != NIL)
+			*partkeys = list_concat(*partkeys, copyObject(rel->rd_keyexpr_list));
+
 		return copyObject(rel->rd_partcheck);
+	}
 
 	/*
 	 * Grab at least an AccessShareLock on the parent table.  Must do this
@@ -381,9 +386,31 @@ generate_partition_qual(Relation rel)
 
 	ReleaseSysCache(tuple);
 
+	/* Save partition key expressions */
+	if (partkeys != NULL)
+	{
+		PartitionKey key = RelationGetPartitionKey(parent);
+		if (key != NULL && key->partexprs != NIL)
+			*partkeys = list_concat(*partkeys, copyObject(key->partexprs));
+	}
+
 	/* Add the parent's quals to the list (if any) */
 	if (parent->rd_rel->relispartition)
-		result = list_concat(generate_partition_qual(parent), my_qual);
+	{
+		List *temp_partkeys;
+		if (partkeys != NULL)
+		{
+			temp_partkeys = *partkeys;
+			*partkeys = NIL;
+		}
+
+		result = list_concat(generate_partition_qual(parent, partkeys), my_qual);
+
+		if (partkeys != NULL)
+		{
+			*partkeys = list_concat(*partkeys, temp_partkeys);
+		}
+	}
 	else
 		result = my_qual;
 
@@ -394,10 +421,13 @@ generate_partition_qual(Relation rel)
 	 * here.
 	 */
 	result = map_partition_varattnos(result, 1, rel, parent);
+	if (partkeys != NULL)
+		*partkeys = map_partition_varattnos(*partkeys, 1, rel, parent);
 
 	/* Assert that we're not leaking any old data during assignments below */
 	Assert(rel->rd_partcheckcxt == NULL);
 	Assert(rel->rd_partcheck == NIL);
+	Assert(rel->rd_keyexpr_list == NIL);
 
 	/*
 	 * Save a copy in the relcache.  The order of these operations is fairly
@@ -416,10 +446,16 @@ generate_partition_qual(Relation rel)
 										  RelationGetRelationName(rel));
 		oldcxt = MemoryContextSwitchTo(rel->rd_partcheckcxt);
 		rel->rd_partcheck = copyObject(result);
+		if (partkeys != NULL && *partkeys != NIL)
+			rel->rd_keyexpr_list = copyObject(*partkeys);
 		MemoryContextSwitchTo(oldcxt);
 	}
 	else
+	{
 		rel->rd_partcheck = NIL;
+		rel->rd_keyexpr_list = NIL;
+	}
+
 	rel->rd_partcheckvalid = true;
 
 	/* Keep the parent locked until commit */
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index fd05615e76..f7527da0d8 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1161,6 +1161,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	relation->rd_pdcxt = NULL;
 	relation->rd_pddcxt = NULL;
 	relation->rd_partcheck = NIL;
+	relation->rd_keyexpr_list = NIL;
 	relation->rd_partcheckvalid = false;
 	relation->rd_partcheckcxt = NULL;
 
@@ -6041,6 +6042,7 @@ load_relcache_init_file(bool shared)
 		rel->rd_pdcxt = NULL;
 		rel->rd_pddcxt = NULL;
 		rel->rd_partcheck = NIL;
+		rel->rd_keyexpr_list = NIL;
 		rel->rd_partcheckvalid = false;
 		rel->rd_partcheckcxt = NULL;
 		rel->rd_indexprs = NIL;
diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h
index a451bfb239..4762bc9fed 100644
--- a/src/include/utils/partcache.h
+++ b/src/include/utils/partcache.h
@@ -48,7 +48,7 @@ typedef struct PartitionKeyData
 
 
 extern PartitionKey RelationGetPartitionKey(Relation rel);
-extern List *RelationGetPartitionQual(Relation rel);
+extern List *RelationGetPartitionQual(Relation rel, List **partkeys);
 extern Expr *get_partition_qual_relid(Oid relid);
 
 /*
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 774ac5b2b1..111287b130 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -143,6 +143,7 @@ typedef struct RelationData
 
 	/* data managed by RelationGetPartitionQual: */
 	List	   *rd_partcheck;	/* partition CHECK quals */
+	List	   *rd_keyexpr_list;	/* partition key exprs used in CHECK quals */
 	bool		rd_partcheckvalid;	/* true if list has been computed */
 	MemoryContext rd_partcheckcxt;	/* private cxt for rd_partcheck, if any */
 
-- 
2.18.4

