Commit 77585bce authored by Tom Lane's avatar Tom Lane

Do ScalarArrayOp estimation correctly when array is a stable expression.

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