From a1bff8ae83f355922261645dcf57602305a9a5cf Mon Sep 17 00:00:00 2001
From: Japin Li <japinli@hotmail.com>
Date: Thu, 4 Aug 2022 22:46:17 +0800
Subject: [PATCH v1 1/1] Fix unrecognized node type about statistics on
 expressions

Commit a4d75c86bf supported extended statistics on expressions, however
it checks the column privilege pass a wrong pointer to pull_varattnos().

There has another bug when checking the attribute privilege, since the
bitmap contains the offset by FirstLowInvalidHeapAttributeNumber.
---
 src/backend/statistics/extended_stats.c |  7 +++++--
 src/test/regress/expected/stats_ext.out |  9 +++++++++
 src/test/regress/sql/stats_ext.sql      | 10 ++++++++++
 3 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/src/backend/statistics/extended_stats.c b/src/backend/statistics/extended_stats.c
index d2aa8d0ca3..a6a312d3de 100644
--- a/src/backend/statistics/extended_stats.c
+++ b/src/backend/statistics/extended_stats.c
@@ -1619,7 +1619,7 @@ statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid,
 		/* Don't have table privilege, must check individual columns */
 		if (*exprs != NIL)
 		{
-			pull_varattnos((Node *) exprs, relid, &clause_attnums);
+			pull_varattnos((Node *) *exprs, relid, &clause_attnums);
 			clause_attnums = bms_add_members(clause_attnums, *attnums);
 		}
 		else
@@ -1639,7 +1639,10 @@ statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid,
 
 			while ((attnum = bms_next_member(clause_attnums, attnum)) >= 0)
 			{
-				if (pg_attribute_aclcheck(rte->relid, attnum, userid,
+				/* bit #s are offset by FirstLowInvalidHeapAttributeNumber */
+				AttrNumber	attno = attnum + FirstLowInvalidHeapAttributeNumber;
+
+				if (pg_attribute_aclcheck(rte->relid, attno, userid,
 										  ACL_SELECT) != ACLCHECK_OK)
 					return false;
 			}
diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out
index 8f5fd546eb..5f9040ae48 100644
--- a/src/test/regress/expected/stats_ext.out
+++ b/src/test/regress/expected/stats_ext.out
@@ -3251,6 +3251,15 @@ DELETE FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak
 -- Tidy up
 DROP OPERATOR <<< (int, int);
 DROP FUNCTION op_leak(int, int);
+-- Test for bug 17570.
+RESET SESSION AUTHORIZATION;
+CREATE TABLE priv_test_tbl1(a INT, b VARCHAR);
+INSERT INTO priv_test_tbl1(a, b) SELECT i, i FROM generate_series(1,100) s(i);
+CREATE STATISTICS priv_test_tbl1_stats (mcv) ON (a), (b) FROM priv_test_tbl1;
+CREATE ROLE priv_test_user1;
+SET SESSION AUTHORIZATION priv_test_user1;
+SELECT * FROM priv_test_tbl1 WHERE a = 1 AND b = '1';
+ERROR:  permission denied for table priv_test_tbl1
 RESET SESSION AUTHORIZATION;
 DROP SCHEMA tststats CASCADE;
 NOTICE:  drop cascades to 2 other objects
diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql
index 5fd865f509..8a65229c05 100644
--- a/src/test/regress/sql/stats_ext.sql
+++ b/src/test/regress/sql/stats_ext.sql
@@ -1642,6 +1642,16 @@ DELETE FROM tststats.priv_test_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak
 -- Tidy up
 DROP OPERATOR <<< (int, int);
 DROP FUNCTION op_leak(int, int);
+
+-- Test for bug 17570.
+RESET SESSION AUTHORIZATION;
+CREATE TABLE priv_test_tbl1(a INT, b VARCHAR);
+INSERT INTO priv_test_tbl1(a, b) SELECT i, i FROM generate_series(1,100) s(i);
+CREATE STATISTICS priv_test_tbl1_stats (mcv) ON (a), (b) FROM priv_test_tbl1;
+CREATE ROLE priv_test_user1;
+SET SESSION AUTHORIZATION priv_test_user1;
+SELECT * FROM priv_test_tbl1 WHERE a = 1 AND b = '1';
+
 RESET SESSION AUTHORIZATION;
 DROP SCHEMA tststats CASCADE;
 DROP USER regress_stats_user1;
-- 
2.17.1

