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)