Skip to content

Commit 77585bc

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 0c5783f commit 77585bc

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
@@ -1735,6 +1735,10 @@ scalararraysel(PlannerInfo *root,
17351735
leftop = (Node *) linitial(clause->args);
17361736
rightop = (Node *) lsecond(clause->args);
17371737

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

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

@@ -6918,7 +6926,8 @@ gincost_opexpr(IndexOptInfo *index, OpExpr *clause, GinQualCounts *counts)
69186926
* by N, causing gincostestimate to scale up its estimates accordingly.
69196927
*/
69206928
static bool
6921-
gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
6929+
gincost_scalararrayopexpr(PlannerInfo *root,
6930+
IndexOptInfo *index, ScalarArrayOpExpr *clause,
69226931
double numIndexEntries,
69236932
GinQualCounts *counts)
69246933
{
@@ -6943,6 +6952,9 @@ gincost_scalararrayopexpr(IndexOptInfo *index, ScalarArrayOpExpr *clause,
69436952
if ((indexcol = find_index_column(leftop, index)) < 0)
69446953
elog(ERROR, "could not match index to operand");
69456954

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

@@ -7160,15 +7172,17 @@ gincostestimate(PG_FUNCTION_ARGS)
71607172
clause = rinfo->clause;
71617173
if (IsA(clause, OpExpr))
71627174
{
7163-
matchPossible = gincost_opexpr(index,
7175+
matchPossible = gincost_opexpr(root,
7176+
index,
71647177
(OpExpr *) clause,
71657178
&counts);
71667179
if (!matchPossible)
71677180
break;
71687181
}
71697182
else if (IsA(clause, ScalarArrayOpExpr))
71707183
{
7171-
matchPossible = gincost_scalararrayopexpr(index,
7184+
matchPossible = gincost_scalararrayopexpr(root,
7185+
index,
71727186
(ScalarArrayOpExpr *) clause,
71737187
numEntries,
71747188
&counts);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy