*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.87 2003/01/10 21:08:11 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.88 2003/01/13 18:10:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void fix_expr_references(Plan *plan, Node *node);
static bool fix_expr_references_walker(Node *node, void *context);
-static void mark_qual_expressions(List *quals);
static void set_join_references(Join *join, List *rtable);
static void set_uppernode_references(Plan *plan, Index subvarno);
static Node *join_references_mutator(Node *node,
case T_SeqScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
break;
case T_IndexScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
fix_expr_references(plan,
(Node *) ((IndexScan *) plan)->indxqual);
fix_expr_references(plan,
case T_TidScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
fix_expr_references(plan,
(Node *) ((TidScan *) plan)->tideval);
break;
*/
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
/* Recurse into subplan too */
rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid,
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
rtable);
Assert(rte->rtekind == RTE_FUNCTION);
set_join_references((Join *) plan, rtable);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
- mark_qual_expressions(((Join *) plan)->joinqual);
break;
case T_MergeJoin:
set_join_references((Join *) plan, rtable);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
- mark_qual_expressions(((Join *) plan)->joinqual);
fix_expr_references(plan,
(Node *) ((MergeJoin *) plan)->mergeclauses);
break;
set_join_references((Join *) plan, rtable);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
- mark_qual_expressions(((Join *) plan)->joinqual);
fix_expr_references(plan,
(Node *) ((HashJoin *) plan)->hashclauses);
break;
set_uppernode_references(plan, (Index) 0);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
break;
case T_Result:
set_uppernode_references(plan, (Index) OUTER);
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
- mark_qual_expressions(plan->qual);
fix_expr_references(plan, ((Result *) plan)->resconstantqual);
- mark_qual_expressions((List *) ((Result *) plan)->resconstantqual);
break;
case T_Append:
return expression_tree_walker(node, fix_expr_references_walker, context);
}
-/*
- * mark_qual_expressions
- * Do final cleanup on qualifier expressions (not targetlists!)
- *
- * SubPlans appearing at the top level of a qual expression are marked
- * to indicate that they need not distinguish UNKNOWN (null) from FALSE
- * results; this can save processing time in some cases.
- */
-static void
-mark_qual_expressions(List *quals)
-{
- List *qual;
-
- foreach(qual, quals)
- {
- Node *node = lfirst(qual);
-
- if (IsA(node, SubPlan))
- ((SubPlan *) node)->unknownEqFalse = true;
- }
-}
-
/*
* set_join_references
* Modifies the target list of a join node to reference its subplans,
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.65 2003/01/13 00:29:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.66 2003/01/13 18:10:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
List *targetlist, List **paramIds);
static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
static Node *replace_correlation_vars_mutator(Node *node, void *context);
-static Node *process_sublinks_mutator(Node *node, void *context);
+static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
static bool finalize_primnode(Node *node, finalize_primnode_results *results);
* Convert a bare SubLink (as created by the parser) into a SubPlan.
*
* We are given the raw SubLink and the already-processed lefthand argument
- * list (use this instead of the SubLink's own field).
+ * list (use this instead of the SubLink's own field). We are also told if
+ * this expression appears at top level of a WHERE/HAVING qual.
*
* The result is whatever we need to substitute in place of the SubLink
* node in the executable expression. This will be either the SubPlan
* containing InitPlan Param nodes.
*/
static Node *
-make_subplan(SubLink *slink, List *lefthand)
+make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
{
SubPlan *node = makeNode(SubPlan);
Query *subquery = (Query *) (slink->subselect);
node->exprs = NIL;
node->paramIds = NIL;
node->useHashTable = false;
- node->unknownEqFalse = false;
+ /* At top level of a qual, can treat UNKNOWN the same as FALSE */
+ node->unknownEqFalse = isTopQual;
node->setParam = NIL;
node->parParam = NIL;
node->args = NIL;
/*
* Expand SubLinks to SubPlans in the given expression.
+ *
+ * The isQual argument tells whether or not this expression is a WHERE/HAVING
+ * qualifier expression. If it is, any sublinks appearing at top level need
+ * not distinguish FALSE from UNKNOWN return values.
*/
Node *
-SS_process_sublinks(Node *expr)
+SS_process_sublinks(Node *expr, bool isQual)
{
- /* No setup needed for tree walk, so away we go */
- return process_sublinks_mutator(expr, NULL);
+ /* The only context needed is the initial are-we-in-a-qual flag */
+ return process_sublinks_mutator(expr, &isQual);
}
static Node *
-process_sublinks_mutator(Node *node, void *context)
+process_sublinks_mutator(Node *node, bool *isTopQual)
{
+ bool locTopQual;
+
if (node == NULL)
return NULL;
if (IsA(node, SubLink))
/*
* First, recursively process the lefthand-side expressions, if any.
*/
+ locTopQual = false;
lefthand = (List *)
- process_sublinks_mutator((Node *) sublink->lefthand, context);
+ process_sublinks_mutator((Node *) sublink->lefthand, &locTopQual);
/*
* Now build the SubPlan node and make the expr to return.
*/
- return make_subplan(sublink, lefthand);
+ return make_subplan(sublink, lefthand, *isTopQual);
}
/*
*/
Assert(!is_subplan(node));
+ /*
+ * If we recurse down through anything other than a List node, we are
+ * definitely not at top qual level anymore.
+ */
+ if (IsA(node, List))
+ locTopQual = *isTopQual;
+ else
+ locTopQual = false;
+
return expression_tree_mutator(node,
process_sublinks_mutator,
- context);
+ (void *) &locTopQual);
}
/*