From 6b3c80fc37d0c034cc2072921da756728e3e3c3e Mon Sep 17 00:00:00 2001
From: Justin Pryzby <pryzbyj@telsasoft.com>
Date: Sat, 25 Sep 2021 18:20:03 -0500
Subject: [PATCH 4/5] f! check inh

statext_expressions_load
examine_variable
estimate_multivariate_ndistinct

TODO: pg_stats_ext_exprs needs to expose inh flag
---
 src/backend/statistics/dependencies.c   |  5 -----
 src/backend/statistics/extended_stats.c |  9 ++-------
 src/backend/utils/adt/selfuncs.c        | 27 ++++++++-----------------
 src/include/statistics/statistics.h     |  2 +-
 src/test/regress/expected/stats_ext.out | 11 ++++++++--
 src/test/regress/sql/stats_ext.sql      |  4 +++-
 6 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c
index 835f4bdf7a..02cf0efc66 100644
--- a/src/backend/statistics/dependencies.c
+++ b/src/backend/statistics/dependencies.c
@@ -1596,11 +1596,6 @@ dependencies_clauselist_selectivity(PlannerInfo *root,
 		int			nexprs;
 		int			k;
 		MVDependencies *deps;
-		RangeTblEntry	*rte = root->simple_rte_array[rel->relid];
-
-		/* If it's an inheritence tree, skip statistics (which do not include child stats) */
-		if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
-			break;
 
 		/* skip statistics that are not of the correct type */
 		if (stat->kind != STATS_EXT_DEPENDENCIES)
diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index 5a43d7e39a..231b153c15 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -1706,7 +1706,6 @@ statext_mcv_clauselist_selectivity(PlannerInfo *root, List *clauses, int varReli
 	List	  **list_exprs;		/* expressions matched to any statistic */
 	int			listidx;
 	Selectivity sel = (is_or) ? 0.0 : 1.0;
-	RangeTblEntry *rte = root->simple_rte_array[rel->relid];
 
 	/* check if there's any stats that might be useful for us. */
 	if (!has_stats_of_kind(rel->statlist, STATS_EXT_MCV))
@@ -1759,10 +1758,6 @@ statext_mcv_clauselist_selectivity(PlannerInfo *root, List *clauses, int varReli
 		Bitmapset  *simple_clauses;
 		RangeTblEntry *rte = root->simple_rte_array[rel->relid];
 
-		/* If it's an inheritence tree, skip statistics (which do not include child stats) */
-		if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
-			break;
-
 		/* find the best suited statistics object for these attnums */
 		stat = choose_best_statistics(rel->statlist, STATS_EXT_MCV, rte->inh,
 									  list_attnums, list_exprs,
@@ -2414,7 +2409,7 @@ serialize_expr_stats(AnlExprData *exprdata, int nexprs)
  * identified by the supplied index.
  */
 HeapTuple
-statext_expressions_load(Oid stxoid, int idx)
+statext_expressions_load(Oid stxoid, bool inh, int idx)
 {
 	bool		isnull;
 	Datum		value;
@@ -2424,7 +2419,7 @@ statext_expressions_load(Oid stxoid, int idx)
 	HeapTupleData tmptup;
 	HeapTuple	tup;
 
-	htup = SearchSysCache2(STATEXTDATASTXOID, ObjectIdGetDatum(stxoid), BoolGetDatum(false));
+	htup = SearchSysCache2(STATEXTDATASTXOID, ObjectIdGetDatum(stxoid), inh);
 	if (!HeapTupleIsValid(htup))
 		elog(ERROR, "cache lookup failed for statistics object %u", stxoid);
 
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index ede393115d..8a6bc29636 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3915,10 +3915,6 @@ estimate_multivariate_ndistinct(PlannerInfo *root, RelOptInfo *rel,
 	StatisticExtInfo *matched_info = NULL;
 	RangeTblEntry		*rte = root->simple_rte_array[rel->relid];
 
-	/* If it's an inheritence tree, skip statistics (which do not include child stats) */
-	if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
-		return false;
-
 	/* bail out immediately if the table has no extended statistics */
 	if (!rel->statlist)
 		return false;
@@ -5237,13 +5233,6 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
 			if (vardata->statsTuple)
 				break;
 
-			/* If it's an inheritence tree, skip statistics (which do not include child stats) */
-			{
-				RangeTblEntry *rte = planner_rt_fetch(onerel->relid, root);
-				if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
-					break;
-			}
-
 			/* skip stats without per-expression stats */
 			if (info->kind != STATS_EXT_EXPRESSIONS)
 				continue;
@@ -5262,22 +5251,22 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
 				/* found a match, see if we can extract pg_statistic row */
 				if (equal(node, expr))
 				{
-					HeapTuple	t = statext_expressions_load(info->statOid, pos);
-
-					/* Get statistic object's table for permission check */
-					RangeTblEntry *rte;
+					RangeTblEntry *rte = planner_rt_fetch(onerel->relid, root);
 					Oid			userid;
+					bool		inh;
 
-					vardata->statsTuple = t;
+					Assert(rte->rtekind == RTE_RELATION);
 
 					/*
 					 * XXX Not sure if we should cache the tuple somewhere.
 					 * Now we just create a new copy every time.
 					 */
-					vardata->freefunc = ReleaseDummy;
+					inh = root->append_rel_array == NULL ? false :
+						root->append_rel_array[onerel->relid]->parent_relid != 0;
+					vardata->statsTuple =
+						statext_expressions_load(info->statOid, inh, pos);
 
-					rte = planner_rt_fetch(onerel->relid, root);
-					Assert(rte->rtekind == RTE_RELATION);
+					vardata->freefunc = ReleaseDummy;
 
 					/*
 					 * Use checkAsUser if it's set, in case we're accessing
diff --git a/src/include/statistics/statistics.h b/src/include/statistics/statistics.h
index 02ee41b9f3..3868e43f8a 100644
--- a/src/include/statistics/statistics.h
+++ b/src/include/statistics/statistics.h
@@ -125,6 +125,6 @@ extern StatisticExtInfo *choose_best_statistics(List *stats, char requiredkind,
 												Bitmapset **clause_attnums,
 												List **clause_exprs,
 												int nclauses);
-extern HeapTuple statext_expressions_load(Oid stxoid, int idx);
+extern HeapTuple statext_expressions_load(Oid stxoid, bool inh, int idx);
 
 #endif							/* STATISTICS_H */
diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out
index 67234b9fc2..35edc6a361 100644
--- a/src/test/regress/expected/stats_ext.out
+++ b/src/test/regress/expected/stats_ext.out
@@ -176,7 +176,6 @@ CREATE STATISTICS ab1_a_b_stats ON a, b FROM ab1;
 ANALYZE ab1;
 DROP TABLE ab1 CASCADE;
 NOTICE:  drop cascades to table ab1c
--- Ensure non-inherited stats are not applied to inherited query
 CREATE TABLE stxdinh(i int, j int);
 CREATE TABLE stxdinh1() INHERITS(stxdinh);
 INSERT INTO stxdinh SELECT a, a/10 FROM generate_series(1,9)a;
@@ -191,11 +190,19 @@ SELECT * FROM check_estimated_rows('SELECT * FROM stxdinh* GROUP BY 1,2');
 
 CREATE STATISTICS stxdinh ON i,j FROM stxdinh;
 VACUUM ANALYZE stxdinh, stxdinh1;
+-- Ensure non-inherited stats are not applied to inherited query
 -- Since the stats object does not include inherited stats, it should not affect the estimates
 SELECT * FROM check_estimated_rows('SELECT * FROM stxdinh* GROUP BY 1,2');
  estimated | actual 
 -----------+--------
-      1000 |   1008
+      1008 |   1008
+(1 row)
+
+-- Ensure correct (non-inherited) stats are applied to inherited query
+SELECT * FROM check_estimated_rows('SELECT * FROM ONLY stxdinh GROUP BY 1,2');
+ estimated | actual 
+-----------+--------
+         9 |      9
 (1 row)
 
 DROP TABLE stxdinh, stxdinh1;
diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql
index 2371043ca1..8490da9558 100644
--- a/src/test/regress/sql/stats_ext.sql
+++ b/src/test/regress/sql/stats_ext.sql
@@ -112,7 +112,6 @@ CREATE STATISTICS ab1_a_b_stats ON a, b FROM ab1;
 ANALYZE ab1;
 DROP TABLE ab1 CASCADE;
 
--- Ensure non-inherited stats are not applied to inherited query
 CREATE TABLE stxdinh(i int, j int);
 CREATE TABLE stxdinh1() INHERITS(stxdinh);
 INSERT INTO stxdinh SELECT a, a/10 FROM generate_series(1,9)a;
@@ -122,8 +121,11 @@ VACUUM ANALYZE stxdinh, stxdinh1;
 SELECT * FROM check_estimated_rows('SELECT * FROM stxdinh* GROUP BY 1,2');
 CREATE STATISTICS stxdinh ON i,j FROM stxdinh;
 VACUUM ANALYZE stxdinh, stxdinh1;
+-- Ensure non-inherited stats are not applied to inherited query
 -- Since the stats object does not include inherited stats, it should not affect the estimates
 SELECT * FROM check_estimated_rows('SELECT * FROM stxdinh* GROUP BY 1,2');
+-- Ensure correct (non-inherited) stats are applied to inherited query
+SELECT * FROM check_estimated_rows('SELECT * FROM ONLY stxdinh GROUP BY 1,2');
 DROP TABLE stxdinh, stxdinh1;
 
 -- Ensure inherited stats ARE applied to inherited query in partitioned table
-- 
2.17.0

