@@ -1316,10 +1316,38 @@ choose_best_statistics(List *stats, char requiredkind, bool inh,
1316
1316
* statext_is_compatible_clause_internal
1317
1317
* Determines if the clause is compatible with MCV lists.
1318
1318
*
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.
1323
1351
*/
1324
1352
static bool
1325
1353
statext_is_compatible_clause_internal (PlannerInfo * root , Node * clause ,
@@ -1343,10 +1371,14 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
1343
1371
if (var -> varlevelsup > 0 )
1344
1372
return false;
1345
1373
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
+ */
1347
1378
if (!AttrNumberIsForUserDefinedAttr (var -> varattno ))
1348
1379
return false;
1349
1380
1381
+ /* OK, record the attnum for later permissions checks. */
1350
1382
* attnums = bms_add_member (* attnums , var -> varattno );
1351
1383
1352
1384
return true;
@@ -1501,7 +1533,7 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
1501
1533
foreach (lc , expr -> args )
1502
1534
{
1503
1535
/*
1504
- * Had we found incompatible clause in the arguments, treat the
1536
+ * If we find an incompatible clause in the arguments, treat the
1505
1537
* whole clause as incompatible.
1506
1538
*/
1507
1539
if (!statext_is_compatible_clause_internal (root ,
@@ -1540,27 +1572,28 @@ statext_is_compatible_clause_internal(PlannerInfo *root, Node *clause,
1540
1572
* statext_is_compatible_clause
1541
1573
* Determines if the clause is compatible with MCV lists.
1542
1574
*
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.
1544
1578
*
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
1547
1587
*
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.
1557
1590
*/
1558
1591
static bool
1559
1592
statext_is_compatible_clause (PlannerInfo * root , Node * clause , Index relid ,
1560
1593
Bitmapset * * attnums , List * * exprs )
1561
1594
{
1562
1595
RangeTblEntry * rte = root -> simple_rte_array [relid ];
1563
- RestrictInfo * rinfo = ( RestrictInfo * ) clause ;
1596
+ RestrictInfo * rinfo ;
1564
1597
int clause_relid ;
1565
1598
Oid userid ;
1566
1599
@@ -1589,8 +1622,9 @@ statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid,
1589
1622
}
1590
1623
1591
1624
/* Otherwise it must be a RestrictInfo. */
1592
- if (!IsA (rinfo , RestrictInfo ))
1625
+ if (!IsA (clause , RestrictInfo ))
1593
1626
return false;
1627
+ rinfo = (RestrictInfo * ) clause ;
1594
1628
1595
1629
/* Pseudoconstants are not really interesting here. */
1596
1630
if (rinfo -> pseudoconstant )
@@ -1612,34 +1646,48 @@ statext_is_compatible_clause(PlannerInfo *root, Node *clause, Index relid,
1612
1646
*/
1613
1647
userid = rte -> checkAsUser ? rte -> checkAsUser : GetUserId ();
1614
1648
1649
+ /* Table-level SELECT privilege is sufficient for all columns */
1615
1650
if (pg_class_aclcheck (rte -> relid , userid , ACL_SELECT ) != ACLCHECK_OK )
1616
1651
{
1617
1652
Bitmapset * clause_attnums = NULL ;
1653
+ int attnum = -1 ;
1618
1654
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 )
1621
1665
{
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 );
1624
1669
}
1625
- else
1626
- clause_attnums = * attnums ;
1627
1670
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 )
1636
1677
{
1637
- /* Check the columns referenced by the clause */
1638
- int attnum = -1 ;
1678
+ /* Undo the offset */
1679
+ AttrNumber attno = attnum + FirstLowInvalidHeapAttributeNumber ;
1639
1680
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
1641
1689
{
1642
- if (pg_attribute_aclcheck (rte -> relid , attnum , userid ,
1690
+ if (pg_attribute_aclcheck (rte -> relid , attno , userid ,
1643
1691
ACL_SELECT ) != ACLCHECK_OK )
1644
1692
return false;
1645
1693
}
0 commit comments