Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e8655a7

Browse files
committed
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.
1 parent 5a7e758 commit e8655a7

File tree

2 files changed

+26
-11
lines changed

2 files changed

+26
-11
lines changed

src/backend/utils/adt/array_selfuncs.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,13 @@ static int float_compare_desc(const void *key1, const void *key2);
6868
* scalararraysel_containment
6969
* Estimate selectivity of ScalarArrayOpExpr via array containment.
7070
*
71-
* scalararraysel() has already verified that the operator of a
72-
* ScalarArrayOpExpr is the array element type's default equality or
73-
* inequality operator. If we have const =/<> ANY/ALL (array_var)
74-
* then we can estimate the selectivity as though this were an array
75-
* containment operator, array_var op ARRAY[const].
71+
* If we have const =/<> ANY/ALL (array_var) then we can estimate the
72+
* selectivity as though this were an array containment operator,
73+
* array_var op ARRAY[const].
74+
*
75+
* scalararraysel() has already verified that the ScalarArrayOpExpr's operator
76+
* is the array element type's default equality or inequality operator, and
77+
* has aggressively simplified both inputs to constants.
7678
*
7779
* Returns selectivity (0..1), or -1 if we fail to estimate selectivity.
7880
*/
@@ -99,9 +101,8 @@ scalararraysel_containment(PlannerInfo *root,
99101
}
100102

101103
/*
102-
* Aggressively reduce leftop to a constant, if possible.
104+
* leftop must be a constant, else punt.
103105
*/
104-
leftop = estimate_expression_value(root, leftop);
105106
if (!IsA(leftop, Const))
106107
{
107108
ReleaseVariableStats(vardata);

src/backend/utils/adt/selfuncs.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,6 +1734,10 @@ scalararraysel(PlannerInfo *root,
17341734
leftop = (Node *) linitial(clause->args);
17351735
rightop = (Node *) lsecond(clause->args);
17361736

1737+
/* aggressively reduce both sides to constants */
1738+
leftop = estimate_expression_value(root, leftop);
1739+
rightop = estimate_expression_value(root, rightop);
1740+
17371741
/* get nominal (after relabeling) element type of rightop */
17381742
nominal_element_type = get_base_element_type(exprType(rightop));
17391743
if (!OidIsValid(nominal_element_type))
@@ -6855,7 +6859,8 @@ gincost_pattern(IndexOptInfo *index, int indexcol,
68556859
* appropriately. If the query is unsatisfiable, return false.
68566860
*/
68576861
static bool
6858-
gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
6862+
gincost_opexpr(PlannerInfo *root, IndexOptInfo *index, OpExpr *clause,
6863+
GinQualCounts *counts)
68596864
{
68606865
Node *leftop = get_leftop((Expr *) clause);
68616866
Node *rightop = get_rightop((Expr *) clause);
@@ -6879,6 +6884,9 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
68796884
operand = NULL; /* keep compiler quiet */
68806885
}
68816886

6887+
/* aggressively reduce to a constant, and look through relabeling */
6888+
operand = estimate_expression_value(root, operand);
6889+
68826890
if (IsA(operand, RelabelType))
68836891
operand = (Node *) ((RelabelType *) operand)->arg;
68846892

@@ -6917,7 +6925,8 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
69176925
* by N, causing gincostestimate to scale up its estimates accordingly.
69186926
*/
69196927
static bool
6920-
gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
6928+
gincost_scalararrayopexpr(PlannerInfo *root,
6929+
IndexOptInfo *index, ScalarArrayOpExpr *clause,
69216930
double numIndexEntries,
69226931
GinQualCounts *counts)
69236932
{
@@ -6942,6 +6951,9 @@ gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
69426951
if ((indexcol = find_index_column(leftop, index)) < 0)
69436952
elog(ERROR, "could not match index to operand");
69446953

6954+
/* aggressively reduce to a constant, and look through relabeling */
6955+
rightop = estimate_expression_value(root, rightop);
6956+
69456957
if (IsA(rightop, RelabelType))
69466958
rightop = (Node *) ((RelabelType *) rightop)->arg;
69476959

@@ -7159,15 +7171,17 @@ gincostestimate(PG_FUNCTION_ARGS)
71597171
clause = rinfo->clause;
71607172
if (IsA(clause, OpExpr))
71617173
{
7162-
matchPossible = gincost_opexpr(index,
7174+
matchPossible = gincost_opexpr(root,
7175+
index,
71637176
(OpExpr *) clause,
71647177
&counts);
71657178
if (!matchPossible)
71667179
break;
71677180
}
71687181
else if (IsA(clause, ScalarArrayOpExpr))
71697182
{
7170-
matchPossible = gincost_scalararrayopexpr(index,
7183+
matchPossible = gincost_scalararrayopexpr(root,
7184+
index,
71717185
(ScalarArrayOpExpr *) clause,
71727186
numEntries,
71737187
&counts);

0 commit comments

Comments
 (0)