]> granicus.if.org Git - postgresql/commitdiff
Do ScalarArrayOp estimation correctly when array is a stable expression.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 21 Feb 2014 22:10:46 +0000 (17:10 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 21 Feb 2014 22:10:46 +0000 (17:10 -0500)
Most estimation functions apply estimate_expression_value to see if they
can reduce an expression to a constant; the key difference is that it
allows evaluation of stable as well as immutable functions in hopes of
ending up with a simple Const node.  scalararraysel didn't get the memo
though, and neither did gincost_opexpr/gincost_scalararrayopexpr.  Fix
that, and remove a now-unnecessary estimate_expression_value step in the
subsidiary function scalararraysel_containment.

Per complaint from Alexey Klyukin.  Back-patch to 9.3.  The problem
goes back further, but I'm hesitant to change estimation behavior in
long-stable release branches.

src/backend/utils/adt/array_selfuncs.c
src/backend/utils/adt/selfuncs.c

index e35edf8ec8440bb695c0ff6881d3368077247147..20eb358a6201a02e084c3cae4ef2833578ee3548 100644 (file)
@@ -68,11 +68,13 @@ static int  float_compare_desc(const void *key1, const void *key2);
  * scalararraysel_containment
  *             Estimate selectivity of ScalarArrayOpExpr via array containment.
  *
- * scalararraysel() has already verified that the operator of a
- * ScalarArrayOpExpr is the array element type's default equality or
- * inequality operator.  If we have const =/<> ANY/ALL (array_var)
- * then we can estimate the selectivity as though this were an array
- * containment operator, array_var op ARRAY[const].
+ * If we have const =/<> ANY/ALL (array_var) then we can estimate the
+ * selectivity as though this were an array containment operator,
+ * array_var op ARRAY[const].
+ *
+ * scalararraysel() has already verified that the ScalarArrayOpExpr's operator
+ * is the array element type's default equality or inequality operator, and
+ * has aggressively simplified both inputs to constants.
  *
  * Returns selectivity (0..1), or -1 if we fail to estimate selectivity.
  */
@@ -99,9 +101,8 @@ scalararraysel_containment(PlannerInfo *root,
        }
 
        /*
-        * Aggressively reduce leftop to a constant, if possible.
+        * leftop must be a constant, else punt.
         */
-       leftop = estimate_expression_value(root, leftop);
        if (!IsA(leftop, Const))
        {
                ReleaseVariableStats(vardata);
index d525ca4546bf55702bbb27f3d21b6d97fa5320d9..f70bdaa328f8f81f6c6cc9f88895eb0670416b6f 100644 (file)
@@ -1735,6 +1735,10 @@ scalararraysel(PlannerInfo *root,
        leftop = (Node *) linitial(clause->args);
        rightop = (Node *) lsecond(clause->args);
 
+       /* aggressively reduce both sides to constants */
+       leftop = estimate_expression_value(root, leftop);
+       rightop = estimate_expression_value(root, rightop);
+
        /* get nominal (after relabeling) element type of rightop */
        nominal_element_type = get_base_element_type(exprType(rightop));
        if (!OidIsValid(nominal_element_type))
@@ -6856,7 +6860,8 @@ gincost_pattern(IndexOptInfo *index, int indexcol,
  * appropriately.  If the query is unsatisfiable, return false.
  */
 static bool
-gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
+gincost_opexpr(PlannerInfo *root, IndexOptInfo *index, OpExpr *clause,
+                          GinQualCounts *counts)
 {
        Node       *leftop = get_leftop((Expr *) clause);
        Node       *rightop = get_rightop((Expr *) clause);
@@ -6880,6 +6885,9 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
                operand = NULL;                 /* keep compiler quiet */
        }
 
+       /* aggressively reduce to a constant, and look through relabeling */
+       operand = estimate_expression_value(root, operand);
+
        if (IsA(operand, RelabelType))
                operand = (Node *) ((RelabelType *) operand)->arg;
 
@@ -6918,7 +6926,8 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
  * by N, causing gincostestimate to scale up its estimates accordingly.
  */
 static bool
-gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
+gincost_scalararrayopexpr(PlannerInfo *root,
+                                                 IndexOptInfo *index, ScalarArrayOpExpr *clause,
                                                  double numIndexEntries,
                                                  GinQualCounts *counts)
 {
@@ -6943,6 +6952,9 @@ gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
        if ((indexcol = find_index_column(leftop, index)) < 0)
                elog(ERROR, "could not match index to operand");
 
+       /* aggressively reduce to a constant, and look through relabeling */
+       rightop = estimate_expression_value(root, rightop);
+
        if (IsA(rightop, RelabelType))
                rightop = (Node *) ((RelabelType *) rightop)->arg;
 
@@ -7160,7 +7172,8 @@ gincostestimate(PG_FUNCTION_ARGS)
                clause = rinfo->clause;
                if (IsA(clause, OpExpr))
                {
-                       matchPossible = gincost_opexpr(index,
+                       matchPossible = gincost_opexpr(root,
+                                                                                  index,
                                                                                   (OpExpr *) clause,
                                                                                   &counts);
                        if (!matchPossible)
@@ -7168,7 +7181,8 @@ gincostestimate(PG_FUNCTION_ARGS)
                }
                else if (IsA(clause, ScalarArrayOpExpr))
                {
-                       matchPossible = gincost_scalararrayopexpr(index,
+                       matchPossible = gincost_scalararrayopexpr(root,
+                                                                                                         index,
                                                                                                (ScalarArrayOpExpr *) clause,
                                                                                                          numEntries,
                                                                                                          &counts);