*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.15 2004/01/10 00:30:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.16 2004/01/10 18:13:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* has_nullable_targetlist
* Check a subquery in the range table to see if all the non-junk
- * targetlist items are simple variables (and, hence, will correctly
- * go to NULL when examined above the point of an outer join).
+ * targetlist items are simple variables or strict functions of simple
+ * variables (and, hence, will correctly go to NULL when examined above
+ * the point of an outer join).
*
- * A possible future extension is to accept strict functions of simple
- * variables, eg, "x + 1".
+ * NOTE: it would be correct (and useful) to ignore output columns that aren't
+ * actually referenced by the enclosing query ... but we do not have that
+ * information available at this point.
*/
static bool
has_nullable_targetlist(Query *subquery)
if (tle->resdom->resjunk)
continue;
- /* Okay if tlist item is a simple Var */
- if (tle->expr && IsA(tle->expr, Var))
- continue;
+ /* Must contain a Var of current level */
+ if (!contain_vars_of_level((Node *) tle->expr, 0))
+ return false;
- return false;
+ /* Must not contain any non-strict constructs */
+ if (contain_nonstrict_functions((Node *) tle->expr))
+ return false;
+
+ /* This one's OK, keep scanning */
}
return true;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.160 2004/01/05 18:04:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.161 2004/01/10 18:13:53 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
* Returns true if any nonstrict construct is found --- ie, anything that
* could produce non-NULL output with a NULL input.
*
- * XXX we do not examine sub-selects to see if they contain uses of
- * nonstrict functions. It's not real clear if that is correct or not...
- * for the current usage it does not matter, since inline_function()
- * rejects cases with sublinks.
+ * The idea here is that the caller has verified that the expression contains
+ * one or more Var or Param nodes (as appropriate for the caller's need), and
+ * now wishes to prove that the expression result will be NULL if any of these
+ * inputs is NULL. If we return false, then the proof succeeded.
*/
bool
contain_nonstrict_functions(Node *clause)
{
if (node == NULL)
return false;
+ if (IsA(node, Aggref))
+ {
+ /* an aggregate could return non-null with null input */
+ return true;
+ }
if (IsA(node, FuncExpr))
{
FuncExpr *expr = (FuncExpr *) node;
switch (expr->boolop)
{
- case OR_EXPR:
case AND_EXPR:
- /* OR, AND are inherently non-strict */
+ case OR_EXPR:
+ /* AND, OR are inherently non-strict */
return true;
default:
break;
}
}
+ if (IsA(node, SubLink))
+ {
+ /* In some cases a sublink might be strict, but in general not */
+ return true;
+ }
+ if (IsA(node, SubPlan))
+ return true;
if (IsA(node, CaseExpr))
return true;
+ if (IsA(node, CaseWhen))
+ return true;
/* NB: ArrayExpr might someday be nonstrict */
if (IsA(node, CoalesceExpr))
return true;
return true;
if (IsA(node, BooleanTest))
return true;
- if (IsA(node, SubLink))
- {
- SubLink *sublink = (SubLink *) node;
- List *opid;
-
- foreach(opid, sublink->operOids)
- {
- if (!op_strict(lfirsto(opid)))
- return true;
- }
- /* else fall through to check args */
- }
return expression_tree_walker(node, contain_nonstrict_functions_walker,
context);
}