Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 72153c0

Browse files
committed
Improve the tests to see if ScalarArrayOpExpr is strict. Original coding
would basically punt in all cases for 'foo <> ALL (array)', which resulted in a performance regression for NOT IN compared to what we were doing in 8.1 and before. Per report from Pavel Stehule.
1 parent a6fefc8 commit 72153c0

File tree

1 file changed

+59
-5
lines changed

1 file changed

+59
-5
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.207 2006/01/31 21:39:24 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.208 2006/02/06 22:21:12 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -70,6 +70,7 @@ static bool contain_mutable_functions_walker(Node *node, void *context);
7070
static bool contain_volatile_functions_walker(Node *node, void *context);
7171
static bool contain_nonstrict_functions_walker(Node *node, void *context);
7272
static Relids find_nonnullable_rels_walker(Node *node, bool top_level);
73+
static bool is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK);
7374
static bool set_coercionform_dontcare_walker(Node *node, void *context);
7475
static Node *eval_const_expressions_mutator(Node *node,
7576
eval_const_expressions_context *context);
@@ -816,8 +817,11 @@ contain_nonstrict_functions_walker(Node *node, void *context)
816817
}
817818
if (IsA(node, ScalarArrayOpExpr))
818819
{
819-
/* inherently non-strict, consider null scalar and empty array */
820-
return true;
820+
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
821+
822+
if (!is_strict_saop(expr, false))
823+
return true;
824+
/* else fall through to check args */
821825
}
822826
if (IsA(node, BoolExpr))
823827
{
@@ -937,10 +941,9 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
937941
}
938942
else if (IsA(node, ScalarArrayOpExpr))
939943
{
940-
/* Strict if it's "foo op ANY array" and op is strict */
941944
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
942945

943-
if (expr->useOr && op_strict(expr->opno))
946+
if (is_strict_saop(expr, true))
944947
result = find_nonnullable_rels_walker((Node *) expr->args, false);
945948
}
946949
else if (IsA(node, BoolExpr))
@@ -991,6 +994,57 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
991994
return result;
992995
}
993996

997+
/*
998+
* Can we treat a ScalarArrayOpExpr as strict?
999+
*
1000+
* If "falseOK" is true, then a "false" result can be considered strict,
1001+
* else we need to guarantee an actual NULL result for NULL input.
1002+
*
1003+
* "foo op ALL array" is strict if the op is strict *and* we can prove
1004+
* that the array input isn't an empty array. We can check that
1005+
* for the cases of an array constant and an ARRAY[] construct.
1006+
*
1007+
* "foo op ANY array" is strict in the falseOK sense if the op is strict.
1008+
* If not falseOK, the test is the same as for "foo op ALL array".
1009+
*/
1010+
static bool
1011+
is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK)
1012+
{
1013+
Node *rightop;
1014+
1015+
/* The contained operator must be strict. */
1016+
if (!op_strict(expr->opno))
1017+
return false;
1018+
/* If ANY and falseOK, that's all we need to check. */
1019+
if (expr->useOr && falseOK)
1020+
return true;
1021+
/* Else, we have to see if the array is provably non-empty. */
1022+
Assert(list_length(expr->args) == 2);
1023+
rightop = (Node *) lsecond(expr->args);
1024+
if (rightop && IsA(rightop, Const))
1025+
{
1026+
Datum arraydatum = ((Const *) rightop)->constvalue;
1027+
bool arrayisnull = ((Const *) rightop)->constisnull;
1028+
ArrayType *arrayval;
1029+
int nitems;
1030+
1031+
if (arrayisnull)
1032+
return false;
1033+
arrayval = DatumGetArrayTypeP(arraydatum);
1034+
nitems = ArrayGetNItems(ARR_NDIM(arrayval), ARR_DIMS(arrayval));
1035+
if (nitems > 0)
1036+
return true;
1037+
}
1038+
else if (rightop && IsA(rightop, ArrayExpr))
1039+
{
1040+
ArrayExpr *arrayexpr = (ArrayExpr *) rightop;
1041+
1042+
if (arrayexpr->elements != NIL && !arrayexpr->multidims)
1043+
return true;
1044+
}
1045+
return false;
1046+
}
1047+
9941048

9951049
/*****************************************************************************
9961050
* Check for "pseudo-constant" clauses

0 commit comments

Comments
 (0)