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

Commit 72a070a

Browse files
committed
Teach find_nonnullable_rels to handle OR cases: if every arm of an OR
forces a particular relation nonnullable, then we can say that the OR does. This is worth a little extra trouble since it may allow reduction of outer joins to plain joins.
1 parent 46bd3bf commit 72a070a

File tree

1 file changed

+71
-19
lines changed

1 file changed

+71
-19
lines changed

src/backend/optimizer/util/clauses.c

Lines changed: 71 additions & 19 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.233 2007/02/02 00:02:55 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.234 2007/02/16 23:32:08 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -974,12 +974,13 @@ contain_nonstrict_functions_walker(Node *node, void *context)
974974
* the expression to have been AND/OR flattened and converted to implicit-AND
975975
* format.
976976
*
977-
* We don't use expression_tree_walker here because we don't want to
978-
* descend through very many kinds of nodes; only the ones we can be sure
979-
* are strict. We can descend through the top level of implicit AND'ing,
980-
* but not through any explicit ANDs (or ORs) below that, since those are not
981-
* strict constructs. The List case handles the top-level implicit AND list
982-
* as well as lists of arguments to strict operators/functions.
977+
* top_level is TRUE while scanning top-level AND/OR structure; here, showing
978+
* the result is either FALSE or NULL is good enough. top_level is FALSE when
979+
* we have descended below a NOT or a strict function: now we must be able to
980+
* prove that the subexpression goes to NULL.
981+
*
982+
* We don't use expression_tree_walker here because we don't want to descend
983+
* through very many kinds of nodes; only the ones we can be sure are strict.
983984
*/
984985
Relids
985986
find_nonnullable_rels(Node *clause)
@@ -991,6 +992,7 @@ static Relids
991992
find_nonnullable_rels_walker(Node *node, bool top_level)
992993
{
993994
Relids result = NULL;
995+
ListCell *l;
994996

995997
if (node == NULL)
996998
return NULL;
@@ -1003,8 +1005,15 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
10031005
}
10041006
else if (IsA(node, List))
10051007
{
1006-
ListCell *l;
1007-
1008+
/*
1009+
* At top level, we are examining an implicit-AND list: if any of
1010+
* the arms produces FALSE-or-NULL then the result is FALSE-or-NULL.
1011+
* If not at top level, we are examining the arguments of a strict
1012+
* function: if any of them produce NULL then the result of the
1013+
* function must be NULL. So in both cases, the set of nonnullable
1014+
* rels is the union of those found in the arms, and we pass down
1015+
* the top_level flag unmodified.
1016+
*/
10081017
foreach(l, (List *) node)
10091018
{
10101019
result = bms_join(result,
@@ -1037,9 +1046,57 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
10371046
{
10381047
BoolExpr *expr = (BoolExpr *) node;
10391048

1040-
/* NOT is strict, others are not */
1041-
if (expr->boolop == NOT_EXPR)
1042-
result = find_nonnullable_rels_walker((Node *) expr->args, false);
1049+
switch (expr->boolop)
1050+
{
1051+
case AND_EXPR:
1052+
/* At top level we can just recurse (to the List case) */
1053+
if (top_level)
1054+
{
1055+
result = find_nonnullable_rels_walker((Node *) expr->args,
1056+
top_level);
1057+
break;
1058+
}
1059+
/*
1060+
* Below top level, even if one arm produces NULL, the result
1061+
* could be FALSE (hence not NULL). However, if *all* the
1062+
* arms produce NULL then the result is NULL, so we can
1063+
* take the intersection of the sets of nonnullable rels,
1064+
* just as for OR. Fall through to share code.
1065+
*/
1066+
/* FALL THRU */
1067+
case OR_EXPR:
1068+
/*
1069+
* OR is strict if all of its arms are, so we can take the
1070+
* intersection of the sets of nonnullable rels for each arm.
1071+
* This works for both values of top_level.
1072+
*/
1073+
foreach(l, expr->args)
1074+
{
1075+
Relids subresult;
1076+
1077+
subresult = find_nonnullable_rels_walker(lfirst(l),
1078+
top_level);
1079+
if (result == NULL) /* first subresult? */
1080+
result = subresult;
1081+
else
1082+
result = bms_int_members(result, subresult);
1083+
/*
1084+
* If the intersection is empty, we can stop looking.
1085+
* This also justifies the test for first-subresult above.
1086+
*/
1087+
if (bms_is_empty(result))
1088+
break;
1089+
}
1090+
break;
1091+
case NOT_EXPR:
1092+
/* NOT will return null if its arg is null */
1093+
result = find_nonnullable_rels_walker((Node *) expr->args,
1094+
false);
1095+
break;
1096+
default:
1097+
elog(ERROR, "unrecognized boolop: %d", (int) expr->boolop);
1098+
break;
1099+
}
10431100
}
10441101
else if (IsA(node, RelabelType))
10451102
{
@@ -1056,22 +1113,17 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
10561113
}
10571114
else if (IsA(node, NullTest))
10581115
{
1116+
/* IS NOT NULL can be considered strict, but only at top level */
10591117
NullTest *expr = (NullTest *) node;
10601118

1061-
/*
1062-
* IS NOT NULL can be considered strict, but only at top level; else
1063-
* we might have something like NOT (x IS NOT NULL).
1064-
*/
10651119
if (top_level && expr->nulltesttype == IS_NOT_NULL)
10661120
result = find_nonnullable_rels_walker((Node *) expr->arg, false);
10671121
}
10681122
else if (IsA(node, BooleanTest))
10691123
{
1124+
/* Boolean tests that reject NULL are strict at top level */
10701125
BooleanTest *expr = (BooleanTest *) node;
10711126

1072-
/*
1073-
* Appropriate boolean tests are strict at top level.
1074-
*/
10751127
if (top_level &&
10761128
(expr->booltesttype == IS_TRUE ||
10771129
expr->booltesttype == IS_FALSE ||

0 commit comments

Comments
 (0)