@@ -1316,10 +1316,38 @@ choose_best_statistics(List *stats, char requiredkind, bool inh,
13161316 * statext_is_compatible_clause_internal
13171317 *Determines if the clause is compatible with MCV lists.
13181318 *
1319- * Does the heavy lifting of actually inspecting the clauses for
1320- * statext_is_compatible_clause. It needs to be split like this because
1321- * of recursion. The attnums bitmap is an input/output parameter collecting
1322- * attribute numbers from all compatible clauses (recursively).
1319+ * To be compatible, the given clause must be a combination of supported
1320+ * clauses built from Vars or sub-expressions (where a sub-expression is
1321+ * something that exactly matches an expression found in statistics objects).
1322+ * This function recursively examines the clause and extracts any
1323+ * sub-expressions that will need to be matched against statistics.
1324+ *
1325+ * Currently, we only support the following types of clauses:
1326+ *
1327+ * (a) OpExprs of the form (Var/Expr op Const), or (Const op Var/Expr), where
1328+ * the op is one of ("=", "<", ">", ">=", "<=")
1329+ *
1330+ * (b) (Var/Expr IS [NOT] NULL)
1331+ *
1332+ * (c) combinations using AND/OR/NOT
1333+ *
1334+ * (d) ScalarArrayOpExprs of the form (Var/Expr op ANY (array)) or (Var/Expr
1335+ * op ALL (array))
1336+ *
1337+ * In the future, the range of supported clauses may be expanded to more
1338+ * complex cases, for example (Var op Var).
1339+ *
1340+ * Arguments:
1341+ * clause: (sub)clause to be inspected (bare clause, not a RestrictInfo)
1342+ * relid: rel that all Vars in clause must belong to
1343+ * *attnums: input/output parameter collecting attribute numbers of all
1344+ *mentioned Vars. Note that we do not offset the attribute numbers,
1345+ *so we can't cope with system columns.
1346+ * *exprs: input/output parameter collecting primitive subclauses within
1347+ *the clause tree
1348+ *
1349+ * Returns false if there is something we definitively can't handle.
1350+ * On true return, we can proceed to match the *exprs against statistics.
13231351 */
13241352static bool
13251353statext_is_compatible_clause_internal (PlannerInfo * root ,Node * clause ,
@@ -1343,10 +1371,14 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
13431371if (var -> varlevelsup > 0 )
13441372return false;
13451373
1346- /* Also skip system attributes (we don't allow stats on those). */
1374+ /*
1375+ * Also reject system attributes and whole-row Vars (we don't allow
1376+ * stats on those).
1377+ */
13471378if (!AttrNumberIsForUserDefinedAttr (var -> varattno ))
13481379return false;
13491380
1381+ /* OK, record the attnum for later permissions checks. */
13501382* attnums = bms_add_member (* attnums ,var -> varattno );
13511383
13521384return true;
@@ -1501,7 +1533,7 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
15011533foreach (lc ,expr -> args )
15021534{
15031535/*
1504- *Had wefound incompatible clause in the arguments, treat the
1536+ *If wefind an incompatible clause in the arguments, treat the
15051537 * whole clause as incompatible.
15061538 */
15071539if (!statext_is_compatible_clause_internal (root ,
@@ -1540,27 +1572,28 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
15401572 * statext_is_compatible_clause
15411573 *Determines if the clause is compatible with MCV lists.
15421574 *
1543- * Currently, we only support the following types of clauses:
1575+ * See statext_is_compatible_clause_internal, above, for the basic rules.
1576+ * This layer deals with RestrictInfo superstructure and applies permissions
1577+ * checks to verify that it's okay to examine all mentioned Vars.
15441578 *
1545- * (a) OpExprs of the form (Var/Expr op Const), or (Const op Var/Expr), where
1546- * the op is one of ("=", "<", ">", ">=", "<=")
1579+ * Arguments:
1580+ * clause: clause to be inspected (in RestrictInfo form)
1581+ * relid: rel that all Vars in clause must belong to
1582+ * *attnums: input/output parameter collecting attribute numbers of all
1583+ *mentioned Vars. Note that we do not offset the attribute numbers,
1584+ *so we can't cope with system columns.
1585+ * *exprs: input/output parameter collecting primitive subclauses within
1586+ *the clause tree
15471587 *
1548- * (b) (Var/Expr IS [NOT] NULL)
1549- *
1550- * (c) combinations using AND/OR/NOT
1551- *
1552- * (d) ScalarArrayOpExprs of the form (Var/Expr op ANY (array)) or (Var/Expr
1553- * op ALL (array))
1554- *
1555- * In the future, the range of supported clauses may be expanded to more
1556- * complex cases, for example (Var op Var).
1588+ * Returns false if there is something we definitively can't handle.
1589+ * On true return, we can proceed to match the *exprs against statistics.
15571590 */
15581591static bool
15591592statext_is_compatible_clause (PlannerInfo * root ,Node * clause ,Index relid ,
15601593Bitmapset * * attnums ,List * * exprs )
15611594{
15621595RangeTblEntry * rte = root -> simple_rte_array [relid ];
1563- RestrictInfo * rinfo = ( RestrictInfo * ) clause ;
1596+ RestrictInfo * rinfo ;
15641597int clause_relid ;
15651598Oid userid ;
15661599
@@ -1589,8 +1622,9 @@ statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid,
15891622}
15901623
15911624/* Otherwise it must be a RestrictInfo. */
1592- if (!IsA (rinfo ,RestrictInfo ))
1625+ if (!IsA (clause ,RestrictInfo ))
15931626return false;
1627+ rinfo = (RestrictInfo * )clause ;
15941628
15951629/* Pseudoconstants are not really interesting here. */
15961630if (rinfo -> pseudoconstant )
@@ -1612,34 +1646,48 @@ statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid,
16121646 */
16131647userid = rte -> checkAsUser ?rte -> checkAsUser :GetUserId ();
16141648
1649+ /* Table-level SELECT privilege is sufficient for all columns */
16151650if (pg_class_aclcheck (rte -> relid ,userid ,ACL_SELECT )!= ACLCHECK_OK )
16161651{
16171652Bitmapset * clause_attnums = NULL ;
1653+ int attnum = -1 ;
16181654
1619- /* Don't have table privilege, must check individual columns */
1620- if (* exprs != NIL )
1655+ /*
1656+ * We have to check per-column privileges. *attnums has the attnums
1657+ * for individual Vars we saw, but there may also be Vars within
1658+ * subexpressions in *exprs. We can use pull_varattnos() to extract
1659+ * those, but there's an impedance mismatch: attnums returned by
1660+ * pull_varattnos() are offset by FirstLowInvalidHeapAttributeNumber,
1661+ * while attnums within *attnums aren't. Convert *attnums to the
1662+ * offset style so we can combine the results.
1663+ */
1664+ while ((attnum = bms_next_member (* attnums ,attnum )) >=0 )
16211665{
1622- pull_varattnos ((Node * )exprs ,relid ,& clause_attnums );
1623- clause_attnums = bms_add_members (clause_attnums ,* attnums );
1666+ clause_attnums =
1667+ bms_add_member (clause_attnums ,
1668+ attnum - FirstLowInvalidHeapAttributeNumber );
16241669}
1625- else
1626- clause_attnums = * attnums ;
16271670
1628- if (bms_is_member (InvalidAttrNumber ,clause_attnums ))
1629- {
1630- /* Have a whole-row reference, must have access to all columns */
1631- if (pg_attribute_aclcheck_all (rte -> relid ,userid ,ACL_SELECT ,
1632- ACLMASK_ALL )!= ACLCHECK_OK )
1633- return false;
1634- }
1635- else
1671+ /* Now merge attnums from *exprs into clause_attnums */
1672+ if (* exprs != NIL )
1673+ pull_varattnos ((Node * )* exprs ,relid ,& clause_attnums );
1674+
1675+ attnum = -1 ;
1676+ while ((attnum = bms_next_member (clause_attnums ,attnum )) >=0 )
16361677{
1637- /*Check thecolumns referenced by the clause */
1638- int attnum = -1 ;
1678+ /*Undo theoffset */
1679+ AttrNumber attno = attnum + FirstLowInvalidHeapAttributeNumber ;
16391680
1640- while ((attnum = bms_next_member (clause_attnums ,attnum )) >=0 )
1681+ if (attno == InvalidAttrNumber )
1682+ {
1683+ /* Whole-row reference, so must have access to all columns */
1684+ if (pg_attribute_aclcheck_all (rte -> relid ,userid ,ACL_SELECT ,
1685+ ACLMASK_ALL )!= ACLCHECK_OK )
1686+ return false;
1687+ }
1688+ else
16411689{
1642- if (pg_attribute_aclcheck (rte -> relid ,attnum ,userid ,
1690+ if (pg_attribute_aclcheck (rte -> relid ,attno ,userid ,
16431691ACL_SELECT )!= ACLCHECK_OK )
16441692return false;
16451693}