From 18f8a79aeb8d153b5b19a387e8e796d0b82b1be5 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Wed, 17 Jul 2019 18:00:15 +0900
Subject: [PATCH v2] Use root parent's permissions when read child table stats

Author: Dilip Kumar
Reviewed by: Amit Langote
---
 src/backend/nodes/outfuncs.c         |  1 +
 src/backend/optimizer/util/relnode.c | 11 +++++++
 src/backend/utils/adt/selfuncs.c     | 57 ++++++++++++++++++++++++++++++++++--
 src/include/nodes/pathnodes.h        |  5 ++++
 4 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 8e31fae47f..7a8461e24f 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2276,6 +2276,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
 	WRITE_BOOL_FIELD(consider_partitionwise_join);
 	WRITE_BITMAPSET_FIELD(top_parent_relids);
 	WRITE_NODE_FIELD(partitioned_child_rels);
+	WRITE_UINT_FIELD(inh_root_parent);
 }
 
 static void
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 6054bd2b53..059042a9f6 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -259,6 +259,16 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
 			rel->top_parent_relids = bms_copy(parent->relids);
 
 		/*
+		 * For inheritance child relations, also set inh_root_parent.  If
+		 * 'parent' is itself a child relation, simply use its value of
+		 * inh_root_parent.
+		 */
+		if (parent->rtekind == RTE_RELATION)
+			rel->inh_root_parent = parent->inh_root_parent > 0 ?
+										parent->inh_root_parent :
+										parent->relid;
+
+		/*
 		 * Also propagate lateral-reference information from appendrel parent
 		 * rels to their child rels.  We intentionally give each child rel the
 		 * same minimum parameterization, even though it's quite possible that
@@ -279,6 +289,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
 	else
 	{
 		rel->top_parent_relids = NULL;
+		rel->inh_root_parent = 0;
 		rel->direct_lateral_relids = NULL;
 		rel->lateral_relids = NULL;
 		rel->lateral_referencers = NULL;
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 66449b85b1..2651bf7cf2 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -4593,8 +4593,17 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
 								/* Get index's table for permission check */
 								RangeTblEntry *rte;
 								Oid			userid;
+								RelOptInfo	*rel = index->rel;
 
-								rte = planner_rt_fetch(index->rel->relid, root);
+								/*
+								 * For an inheritance child table, check
+								 * permissions using the root parent's RTE.
+								 */
+								if (rel->inh_root_parent > 0)
+									rte = planner_rt_fetch(rel->inh_root_parent,
+														   root);
+								else
+									rte = planner_rt_fetch(rel->relid, root);
 								Assert(rte->rtekind == RTE_RELATION);
 
 								/*
@@ -4678,6 +4687,48 @@ examine_simple_variable(PlannerInfo *root, Var *var,
 		if (HeapTupleIsValid(vardata->statsTuple))
 		{
 			Oid			userid;
+			RelOptInfo *rel;
+			Oid			relid = rte->relid;
+			int			varattno = var->varattno;
+
+			rel = root->simple_rel_array[var->varno];
+
+			/*
+			 * For an inheritance child table, check permissions using the
+			 * root parent's RTE and column.
+			 */
+			if (rel->inh_root_parent > 0)
+			{
+				rte = planner_rt_fetch(rel->inh_root_parent, root);
+
+				/*
+				 * Reverse-map the column's attribute number to that in the
+				 * root parent using the child table's Var translation list.
+				 */
+				if (varattno > 0)
+				{
+					AppendRelInfo *appinfo = root->append_rel_array[rel->relid];
+					ListCell   *l;
+					bool		found = false;
+
+					Assert(appinfo != NULL);
+					varattno = 1;
+					foreach(l, appinfo->translated_vars)
+					{
+						if (equal(var, lfirst(l)))
+						{
+							found = true;
+							break;
+						}
+						varattno++;
+					}
+					/*
+					 * The query can only select columns present in the parent
+					 * table, so we must have found one.
+					 */
+					Assert(found);
+				}
+			}
 
 			/*
 			 * Check if user has permission to read this column.  We require
@@ -4689,9 +4740,9 @@ examine_simple_variable(PlannerInfo *root, Var *var,
 
 			vardata->acl_ok =
 				rte->securityQuals == NIL &&
-				((pg_class_aclcheck(rte->relid, userid,
+				((pg_class_aclcheck(relid, userid,
 									ACL_SELECT) == ACLCHECK_OK) ||
-				 (pg_attribute_aclcheck(rte->relid, var->varattno, userid,
+				 (pg_attribute_aclcheck(relid, varattno, userid,
 										ACL_SELECT) == ACLCHECK_OK));
 		}
 		else
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 441e64eca9..84c5f99766 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -720,6 +720,11 @@ typedef struct RelOptInfo
 	List	  **partexprs;		/* Non-nullable partition key expressions. */
 	List	  **nullable_partexprs; /* Nullable partition key expressions. */
 	List	   *partitioned_child_rels; /* List of RT indexes. */
+
+	Index		inh_root_parent;	/* For otherrels, this is the RT index of
+									 * inheritance root table mentioned in the
+									 * query from which this relation
+									 * originated. */
 } RelOptInfo;
 
 /*
-- 
2.11.0

