@@ -1255,6 +1255,10 @@ choose_best_statistics(List *stats, char requiredkind,
1255
1255
/*
1256
1256
* Collect attributes and expressions in remaining (unestimated)
1257
1257
* clauses fully covered by this statistic object.
1258
+ *
1259
+ * We know already estimated clauses have both clause_attnums and
1260
+ * clause_exprs set to NULL. We leave the pointers NULL if already
1261
+ * estimated, or we reset them to NULL after estimating the clause.
1258
1262
*/
1259
1263
for (i = 0 ; i < nclauses ; i ++ )
1260
1264
{
@@ -1758,39 +1762,65 @@ statext_mcv_clauselist_selectivity(PlannerInfo *root, List *clauses, int varReli
1758
1762
/* record which clauses are simple (single column or expression) */
1759
1763
simple_clauses = NULL ;
1760
1764
1761
- listidx = 0 ;
1765
+ listidx = -1 ;
1762
1766
foreach (l , clauses )
1763
1767
{
1768
+ /* Increment the index before we decide if to skip the clause. */
1769
+ listidx ++ ;
1770
+
1764
1771
/*
1765
- * If the clause is not already estimated and is compatible with
1766
- * the selected statistics object (all attributes and expressions
1767
- * covered), mark it as estimated and add it to the list to
1768
- * estimate.
1772
+ * Ignore clauses from which we did not extract any attnums or
1773
+ * expressions (this needs to be consistent with what we do in
1774
+ * choose_best_statistics).
1775
+ *
1776
+ * This also eliminates already estimated clauses - both those
1777
+ * estimated before and during applying extended statistics.
1778
+ *
1779
+ * XXX This check is needed because both bms_is_subset and
1780
+ * stat_covers_expressions return true for empty attnums and
1781
+ * expressions.
1769
1782
*/
1770
- if (!bms_is_member (listidx , * estimatedclauses ) &&
1771
- bms_is_subset (list_attnums [listidx ], stat -> keys ) &&
1772
- stat_covers_expressions (stat , list_exprs [listidx ], NULL ))
1773
- {
1774
- /* record simple clauses (single column or expression) */
1775
- if ((list_attnums [listidx ] == NULL &&
1776
- list_length (list_exprs [listidx ]) == 1 ) ||
1777
- (list_exprs [listidx ] == NIL &&
1778
- bms_membership (list_attnums [listidx ]) == BMS_SINGLETON ))
1779
- simple_clauses = bms_add_member (simple_clauses ,
1780
- list_length (stat_clauses ));
1781
-
1782
- /* add clause to list and mark as estimated */
1783
- stat_clauses = lappend (stat_clauses , (Node * ) lfirst (l ));
1784
- * estimatedclauses = bms_add_member (* estimatedclauses , listidx );
1785
-
1786
- bms_free (list_attnums [listidx ]);
1787
- list_attnums [listidx ] = NULL ;
1788
-
1789
- list_free (list_exprs [listidx ]);
1790
- list_exprs [listidx ] = NULL ;
1791
- }
1783
+ if (!list_attnums [listidx ] && !list_exprs [listidx ])
1784
+ continue ;
1792
1785
1793
- listidx ++ ;
1786
+ /*
1787
+ * The clause was not estimated yet, and we've extracted either
1788
+ * attnums of expressions from it. Ignore it if it's not fully
1789
+ * covered by the chosen statistics.
1790
+ *
1791
+ * We need to check both attributes and expressions, and reject
1792
+ * if either is not covered.
1793
+ */
1794
+ if (!bms_is_subset (list_attnums [listidx ], stat -> keys ) ||
1795
+ !stat_covers_expressions (stat , list_exprs [listidx ], NULL ))
1796
+ continue ;
1797
+
1798
+ /*
1799
+ * Now we know the clause is compatible (we have either atttnums
1800
+ * or expressions extracted from it), and was not estimated yet.
1801
+ */
1802
+
1803
+ /* record simple clauses (single column or expression) */
1804
+ if ((list_attnums [listidx ] == NULL &&
1805
+ list_length (list_exprs [listidx ]) == 1 ) ||
1806
+ (list_exprs [listidx ] == NIL &&
1807
+ bms_membership (list_attnums [listidx ]) == BMS_SINGLETON ))
1808
+ simple_clauses = bms_add_member (simple_clauses ,
1809
+ list_length (stat_clauses ));
1810
+
1811
+ /* add clause to list and mark it as estimated */
1812
+ stat_clauses = lappend (stat_clauses , (Node * ) lfirst (l ));
1813
+ * estimatedclauses = bms_add_member (* estimatedclauses , listidx );
1814
+
1815
+ /*
1816
+ * Reset the pointers, so that choose_best_statistics knows this
1817
+ * clause was estimated and does not consider it again.
1818
+ */
1819
+ bms_free (list_attnums [listidx ]);
1820
+ list_attnums [listidx ] = NULL ;
1821
+
1822
+ list_free (list_exprs [listidx ]);
1823
+ list_exprs [listidx ] = NULL ;
1794
1824
}
1795
1825
1796
1826
if (is_or )
0 commit comments