Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit65ce07e

Browse files
committed
Teach optimizer's predtest.c more things about ScalarArrayOpExpr.
In particular, make it possible to prove/refute "x IS NULL" and"x IS NOT NULL" predicates from a clause involving a ScalarArrayOpExpreven when we are unable or unwilling to deconstruct the expressioninto an AND/OR tree. This avoids a former unexpected degradation ofplan quality when the size of an ARRAY[] expression or array constantexceeded the arbitrary MAX_SAOP_ARRAY_SIZE limit. For IS-NULL proofs,we don't really care about the values of the individual array elements;at most, we care whether there are any, and for some common cases weneedn't even know that.The main user-visible effect of this is to let the optimizer recognizeapplicability of partial indexes with "x IS NOT NULL" predicates toqueries with "x IN (array)" clauses in some cases where it previouslyfailed to recognize that. The structure of predtest.c is such that abunch of related proofs will now also succeed, but they're probablymuch less useful in the wild.James Coleman, reviewed by David RowleyDiscussion:https://postgr.es/m/CAAaqYe8yKSvzbyu8w-dThRs9aTFMwrFxn_BkTYeXgjqe3CbNjg@mail.gmail.com
1 parentaad21d4 commit65ce07e

File tree

3 files changed

+478
-20
lines changed

3 files changed

+478
-20
lines changed

‎src/backend/optimizer/util/predtest.c

Lines changed: 106 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause,
9999
boolweak);
100100
staticNode*extract_not_arg(Node*clause);
101101
staticNode*extract_strong_not_arg(Node*clause);
102-
staticboolclause_is_strict_for(Node*clause,Node*subexpr);
102+
staticboolclause_is_strict_for(Node*clause,Node*subexpr,boolallow_false);
103103
staticbooloperator_predicate_proof(Expr*predicate,Node*clause,
104104
boolrefute_it,boolweak);
105105
staticbooloperator_same_subexprs_proof(Oidpred_op,Oidclause_op,
@@ -816,7 +816,7 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate,
816816
* This function also implements enforcement of MAX_SAOP_ARRAY_SIZE: if a
817817
* ScalarArrayOpExpr's array has too many elements, we just classify it as an
818818
* atom. (This will result in its being passed as-is to the simple_clause
819-
* functions, which will fail to prove anything about it.)Note that we
819+
* functions,many ofwhich will fail to prove anything about it.)Note that we
820820
* cannot just stop after considering MAX_SAOP_ARRAY_SIZE elements; in general
821821
* that would result in wrong proofs, rather than failing to prove anything.
822822
*/
@@ -1099,8 +1099,8 @@ arrayexpr_cleanup_fn(PredIterInfo info)
10991099
*
11001100
* If the predicate is of the form "foo IS NOT NULL", and we are considering
11011101
* strong implication, we can conclude that the predicate is implied if the
1102-
* clause is strict for "foo", i.e., it must yield NULL when "foo" is NULL.
1103-
* In that case truth of the clauserequires that "foo" isn't NULL.
1102+
* clause is strict for "foo", i.e., it must yieldfalse orNULL when "foo"
1103+
*is NULL.In that case truth of the clauseensures that "foo" isn't NULL.
11041104
* (Again, this is a safe conclusion because "foo" must be immutable.)
11051105
* This doesn't work for weak implication, though.
11061106
*
@@ -1131,7 +1131,7 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause,
11311131
!ntest->argisrow)
11321132
{
11331133
/* strictness of clause for foo implies foo IS NOT NULL */
1134-
if (clause_is_strict_for(clause, (Node*)ntest->arg))
1134+
if (clause_is_strict_for(clause, (Node*)ntest->arg, true))
11351135
return true;
11361136
}
11371137
return false;/* we can't succeed below... */
@@ -1160,8 +1160,8 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause,
11601160
*
11611161
* A clause "foo IS NULL" refutes a predicate "foo IS NOT NULL" in all cases.
11621162
* If we are considering weak refutation, it also refutes a predicate that
1163-
* is strict for "foo", since then the predicate must yieldNULL (and since
1164-
* "foo" appears in the predicate, it's known immutable).
1163+
* is strict for "foo", since then the predicate must yieldfalse or NULL
1164+
*(and since"foo" appears in the predicate, it's known immutable).
11651165
*
11661166
* (The main motivation for covering these IS [NOT] NULL cases is to support
11671167
* using IS NULL/IS NOT NULL as partition-defining constraints.)
@@ -1194,7 +1194,7 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause,
11941194
return false;
11951195

11961196
/* strictness of clause for foo refutes foo IS NULL */
1197-
if (clause_is_strict_for(clause, (Node*)isnullarg))
1197+
if (clause_is_strict_for(clause, (Node*)isnullarg, true))
11981198
return true;
11991199

12001200
/* foo IS NOT NULL refutes foo IS NULL */
@@ -1226,7 +1226,7 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause,
12261226

12271227
/* foo IS NULL weakly refutes any predicate that is strict for foo */
12281228
if (weak&&
1229-
clause_is_strict_for((Node*)predicate, (Node*)isnullarg))
1229+
clause_is_strict_for((Node*)predicate, (Node*)isnullarg, true))
12301230
return true;
12311231

12321232
return false;/* we can't succeed below... */
@@ -1293,17 +1293,30 @@ extract_strong_not_arg(Node *clause)
12931293

12941294

12951295
/*
1296-
* Can we prove that "clause" returns NULL if "subexpr" does?
1296+
* Can we prove that "clause" returns NULL (or FALSE) if "subexpr" is
1297+
* assumed to yield NULL?
12971298
*
1298-
* The base case is that clause and subexpr are equal(). (We assume that
1299-
* the caller knows at least one of the input expressions is immutable,
1300-
* as this wouldn't hold for volatile expressions.)
1299+
* In most places in the planner, "strictness" refers to a guarantee that
1300+
* an expression yields NULL output for a NULL input, and that's mostly what
1301+
* we're looking for here. However, at top level where the clause is known
1302+
* to yield boolean, it may be sufficient to prove that it cannot return TRUE
1303+
* when "subexpr" is NULL. The caller should pass allow_false = true when
1304+
* this weaker property is acceptable. (When this function recurses
1305+
* internally, we pass down allow_false = false since we need to prove actual
1306+
* nullness of the subexpression.)
1307+
*
1308+
* We assume that the caller checked that least one of the input expressions
1309+
* is immutable. All of the proof rules here involve matching "subexpr" to
1310+
* some portion of "clause", so that this allows assuming that "subexpr" is
1311+
* immutable without a separate check.
1312+
*
1313+
* The base case is that clause and subexpr are equal().
13011314
*
13021315
* We can also report success if the subexpr appears as a subexpression
13031316
* of "clause" in a place where it'd force nullness of the overall result.
13041317
*/
13051318
staticbool
1306-
clause_is_strict_for(Node*clause,Node*subexpr)
1319+
clause_is_strict_for(Node*clause,Node*subexpr,boolallow_false)
13071320
{
13081321
ListCell*lc;
13091322

@@ -1336,7 +1349,7 @@ clause_is_strict_for(Node *clause, Node *subexpr)
13361349
{
13371350
foreach(lc, ((OpExpr*)clause)->args)
13381351
{
1339-
if (clause_is_strict_for((Node*)lfirst(lc),subexpr))
1352+
if (clause_is_strict_for((Node*)lfirst(lc),subexpr, false))
13401353
return true;
13411354
}
13421355
return false;
@@ -1346,7 +1359,7 @@ clause_is_strict_for(Node *clause, Node *subexpr)
13461359
{
13471360
foreach(lc, ((FuncExpr*)clause)->args)
13481361
{
1349-
if (clause_is_strict_for((Node*)lfirst(lc),subexpr))
1362+
if (clause_is_strict_for((Node*)lfirst(lc),subexpr, false))
13501363
return true;
13511364
}
13521365
return false;
@@ -1362,16 +1375,89 @@ clause_is_strict_for(Node *clause, Node *subexpr)
13621375
*/
13631376
if (IsA(clause,CoerceViaIO))
13641377
returnclause_is_strict_for((Node*) ((CoerceViaIO*)clause)->arg,
1365-
subexpr);
1378+
subexpr, false);
13661379
if (IsA(clause,ArrayCoerceExpr))
13671380
returnclause_is_strict_for((Node*) ((ArrayCoerceExpr*)clause)->arg,
1368-
subexpr);
1381+
subexpr, false);
13691382
if (IsA(clause,ConvertRowtypeExpr))
13701383
returnclause_is_strict_for((Node*) ((ConvertRowtypeExpr*)clause)->arg,
1371-
subexpr);
1384+
subexpr, false);
13721385
if (IsA(clause,CoerceToDomain))
13731386
returnclause_is_strict_for((Node*) ((CoerceToDomain*)clause)->arg,
1374-
subexpr);
1387+
subexpr, false);
1388+
1389+
/*
1390+
* ScalarArrayOpExpr is a special case. Note that we'd only reach here
1391+
* with a ScalarArrayOpExpr clause if we failed to deconstruct it into an
1392+
* AND or OR tree, as for example if it has too many array elements.
1393+
*/
1394+
if (IsA(clause,ScalarArrayOpExpr))
1395+
{
1396+
ScalarArrayOpExpr*saop= (ScalarArrayOpExpr*)clause;
1397+
Node*scalarnode= (Node*)linitial(saop->args);
1398+
Node*arraynode= (Node*)lsecond(saop->args);
1399+
1400+
/*
1401+
* If we can prove the scalar input to be null, and the operator is
1402+
* strict, then the SAOP result has to be null --- unless the array is
1403+
* empty. For an empty array, we'd get either false (for ANY) or true
1404+
* (for ALL). So if allow_false = true then the proof succeeds anyway
1405+
* for the ANY case; otherwise we can only make the proof if we can
1406+
* prove the array non-empty.
1407+
*/
1408+
if (clause_is_strict_for(scalarnode,subexpr, false)&&
1409+
op_strict(saop->opno))
1410+
{
1411+
intnelems=0;
1412+
1413+
if (allow_false&&saop->useOr)
1414+
return true;/* can succeed even if array is empty */
1415+
1416+
if (arraynode&&IsA(arraynode,Const))
1417+
{
1418+
Const*arrayconst= (Const*)arraynode;
1419+
ArrayType*arrval;
1420+
1421+
/*
1422+
* If array is constant NULL then we can succeed, as in the
1423+
* case below.
1424+
*/
1425+
if (arrayconst->constisnull)
1426+
return true;
1427+
1428+
/* Otherwise, we can compute the number of elements. */
1429+
arrval=DatumGetArrayTypeP(arrayconst->constvalue);
1430+
nelems=ArrayGetNItems(ARR_NDIM(arrval),ARR_DIMS(arrval));
1431+
}
1432+
elseif (arraynode&&IsA(arraynode,ArrayExpr)&&
1433+
!((ArrayExpr*)arraynode)->multidims)
1434+
{
1435+
/*
1436+
* We can also reliably count the number of array elements if
1437+
* the input is a non-multidim ARRAY[] expression.
1438+
*/
1439+
nelems=list_length(((ArrayExpr*)arraynode)->elements);
1440+
}
1441+
1442+
/* Proof succeeds if array is definitely non-empty */
1443+
if (nelems>0)
1444+
return true;
1445+
}
1446+
1447+
/*
1448+
* If we can prove the array input to be null, the proof succeeds in
1449+
* all cases, since ScalarArrayOpExpr will always return NULL for a
1450+
* NULL array. Otherwise, we're done here.
1451+
*/
1452+
returnclause_is_strict_for(arraynode,subexpr, false);
1453+
}
1454+
1455+
/*
1456+
* When recursing into an expression, we might find a NULL constant.
1457+
* That's certainly NULL, whether it matches subexpr or not.
1458+
*/
1459+
if (IsA(clause,Const))
1460+
return ((Const*)clause)->constisnull;
13751461

13761462
return false;
13771463
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp