From 77585bce03042e8fee62d8df0dde9c008a904699 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 21 Feb 2014 17:10:46 -0500 Subject: [PATCH] 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. --- src/backend/utils/adt/array_selfuncs.c | 15 ++++++++------- src/backend/utils/adt/selfuncs.c | 22 ++++++++++++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c index e35edf8ec8..20eb358a62 100644 --- a/src/backend/utils/adt/array_selfuncs.c +++ b/src/backend/utils/adt/array_selfuncs.c @@ -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); diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index d525ca4546..f70bdaa328 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -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); -- 2.40.0