Skip to content

Commit a43f430

Browse files
committed
Improve has_nullable_targetlist() to allow strict functions of simple
variables, not just simple variables. This was foreseen in the original coding of this routine, but not implemented until now. Responds to performance gripe from Laurent Perez.
1 parent 47f8f33 commit a43f430

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

src/backend/optimizer/prep/prepjointree.c

+15-9
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
*
1818
* IDENTIFICATION
19-
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.15 2004/01/10 00:30:21 tgl Exp $
19+
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.16 2004/01/10 18:13:53 tgl Exp $
2020
*
2121
*-------------------------------------------------------------------------
2222
*/
@@ -439,11 +439,13 @@ is_simple_subquery(Query *subquery)
439439
/*
440440
* has_nullable_targetlist
441441
* Check a subquery in the range table to see if all the non-junk
442-
* targetlist items are simple variables (and, hence, will correctly
443-
* go to NULL when examined above the point of an outer join).
442+
* targetlist items are simple variables or strict functions of simple
443+
* variables (and, hence, will correctly go to NULL when examined above
444+
* the point of an outer join).
444445
*
445-
* A possible future extension is to accept strict functions of simple
446-
* variables, eg, "x + 1".
446+
* NOTE: it would be correct (and useful) to ignore output columns that aren't
447+
* actually referenced by the enclosing query ... but we do not have that
448+
* information available at this point.
447449
*/
448450
static bool
449451
has_nullable_targetlist(Query *subquery)
@@ -458,11 +460,15 @@ has_nullable_targetlist(Query *subquery)
458460
if (tle->resdom->resjunk)
459461
continue;
460462

461-
/* Okay if tlist item is a simple Var */
462-
if (tle->expr && IsA(tle->expr, Var))
463-
continue;
463+
/* Must contain a Var of current level */
464+
if (!contain_vars_of_level((Node *) tle->expr, 0))
465+
return false;
464466

465-
return false;
467+
/* Must not contain any non-strict constructs */
468+
if (contain_nonstrict_functions((Node *) tle->expr))
469+
return false;
470+
471+
/* This one's OK, keep scanning */
466472
}
467473
return true;
468474
}

src/backend/optimizer/util/clauses.c

+21-19
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.160 2004/01/05 18:04:39 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.161 2004/01/10 18:13:53 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -697,10 +697,10 @@ contain_volatile_functions_walker(Node *node, void *context)
697697
* Returns true if any nonstrict construct is found --- ie, anything that
698698
* could produce non-NULL output with a NULL input.
699699
*
700-
* XXX we do not examine sub-selects to see if they contain uses of
701-
* nonstrict functions. It's not real clear if that is correct or not...
702-
* for the current usage it does not matter, since inline_function()
703-
* rejects cases with sublinks.
700+
* The idea here is that the caller has verified that the expression contains
701+
* one or more Var or Param nodes (as appropriate for the caller's need), and
702+
* now wishes to prove that the expression result will be NULL if any of these
703+
* inputs is NULL. If we return false, then the proof succeeded.
704704
*/
705705
bool
706706
contain_nonstrict_functions(Node *clause)
@@ -713,6 +713,11 @@ contain_nonstrict_functions_walker(Node *node, void *context)
713713
{
714714
if (node == NULL)
715715
return false;
716+
if (IsA(node, Aggref))
717+
{
718+
/* an aggregate could return non-null with null input */
719+
return true;
720+
}
716721
if (IsA(node, FuncExpr))
717722
{
718723
FuncExpr *expr = (FuncExpr *) node;
@@ -745,16 +750,25 @@ contain_nonstrict_functions_walker(Node *node, void *context)
745750

746751
switch (expr->boolop)
747752
{
748-
case OR_EXPR:
749753
case AND_EXPR:
750-
/* OR, AND are inherently non-strict */
754+
case OR_EXPR:
755+
/* AND, OR are inherently non-strict */
751756
return true;
752757
default:
753758
break;
754759
}
755760
}
761+
if (IsA(node, SubLink))
762+
{
763+
/* In some cases a sublink might be strict, but in general not */
764+
return true;
765+
}
766+
if (IsA(node, SubPlan))
767+
return true;
756768
if (IsA(node, CaseExpr))
757769
return true;
770+
if (IsA(node, CaseWhen))
771+
return true;
758772
/* NB: ArrayExpr might someday be nonstrict */
759773
if (IsA(node, CoalesceExpr))
760774
return true;
@@ -764,18 +778,6 @@ contain_nonstrict_functions_walker(Node *node, void *context)
764778
return true;
765779
if (IsA(node, BooleanTest))
766780
return true;
767-
if (IsA(node, SubLink))
768-
{
769-
SubLink *sublink = (SubLink *) node;
770-
List *opid;
771-
772-
foreach(opid, sublink->operOids)
773-
{
774-
if (!op_strict(lfirsto(opid)))
775-
return true;
776-
}
777-
/* else fall through to check args */
778-
}
779781
return expression_tree_walker(node, contain_nonstrict_functions_walker,
780782
context);
781783
}

0 commit comments

Comments
 (0)