Commit e69785de authored by Tom Lane's avatar Tom Lane

Further tweaking of parsetree & plantree representation of SubLinks.

Simplify SubLink by storing just a List of operator OIDs, instead of
a list of incomplete OpExprs --- that was a bizarre and bulky choice,
with no redeeming social value since we have to build new OpExprs
anyway when forming the plan tree.
parent 36ea2679
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.18 2002/12/12 15:49:21 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.19 2003/01/10 21:08:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -838,6 +838,18 @@ find_expr_references_walker(Node *node, ...@@ -838,6 +838,18 @@ find_expr_references_walker(Node *node,
&context->addrs); &context->addrs);
/* fall through to examine arguments */ /* fall through to examine arguments */
} }
if (IsA(node, SubLink))
{
SubLink *sublink = (SubLink *) node;
List *opid;
foreach(opid, sublink->operOids)
{
add_object_address(OCLASS_OPERATOR, (Oid) lfirsti(opid), 0,
&context->addrs);
}
/* fall through to examine arguments */
}
if (is_subplan(node)) if (is_subplan(node))
{ {
/* Extra work needed here if we ever need this case */ /* Extra work needed here if we ever need this case */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.121 2002/12/15 16:17:45 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.122 2003/01/10 21:08:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2023,8 +2023,8 @@ ExecInitExpr(Expr *node, PlanState *parent) ...@@ -2023,8 +2023,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
sstate->sub_estate = NULL; sstate->sub_estate = NULL;
sstate->planstate = NULL; sstate->planstate = NULL;
sstate->oper = (List *) sstate->exprs = (List *)
ExecInitExpr((Expr *) subplan->oper, parent); ExecInitExpr((Expr *) subplan->exprs, parent);
sstate->args = (List *) sstate->args = (List *)
ExecInitExpr((Expr *) subplan->args, parent); ExecInitExpr((Expr *) subplan->args, parent);
...@@ -2156,7 +2156,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent) ...@@ -2156,7 +2156,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
sstate->sub_estate = NULL; sstate->sub_estate = NULL;
sstate->planstate = NULL; sstate->planstate = NULL;
sstate->oper = (List *) ExecInitExpr((Expr *) node->oper, parent); sstate->exprs = (List *) ExecInitExpr((Expr *) node->exprs, parent);
sstate->args = (List *) ExecInitExpr((Expr *) node->args, parent); sstate->args = (List *) ExecInitExpr((Expr *) node->args, parent);
sstate->xprstate.expr = (Expr *) node; sstate->xprstate.expr = (Expr *) node;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.41 2003/01/09 20:50:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.42 2003/01/10 21:08:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -110,6 +110,7 @@ ExecSubPlan(SubPlanState *node, ...@@ -110,6 +110,7 @@ ExecSubPlan(SubPlanState *node,
Datum rowresult = BoolGetDatum(!useOr); Datum rowresult = BoolGetDatum(!useOr);
bool rownull = false; bool rownull = false;
int col = 1; int col = 1;
List *plst;
if (subLinkType == EXISTS_SUBLINK) if (subLinkType == EXISTS_SUBLINK)
{ {
...@@ -155,45 +156,19 @@ ExecSubPlan(SubPlanState *node, ...@@ -155,45 +156,19 @@ ExecSubPlan(SubPlanState *node,
* For ALL, ANY, and MULTIEXPR sublinks, iterate over combining * For ALL, ANY, and MULTIEXPR sublinks, iterate over combining
* operators for columns of tuple. * operators for columns of tuple.
*/ */
foreach(lst, node->oper) plst = subplan->paramIds;
foreach(lst, node->exprs)
{ {
ExprState *exprstate = (ExprState *) lfirst(lst); ExprState *exprstate = (ExprState *) lfirst(lst);
OpExpr *expr = (OpExpr *) exprstate->expr; int paramid = lfirsti(plst);
Param *prm = lsecond(expr->args);
ParamExecData *prmdata; ParamExecData *prmdata;
Datum expresult; Datum expresult;
bool expnull; bool expnull;
/* /*
* The righthand side of the expression should be either a * Load up the Param representing this column of the sub-select.
* Param or a function call or RelabelType node taking a Param
* as arg (these nodes represent run-time type coercions
* inserted by the parser to get to the input type needed by
* the operator). Find the Param node and insert the actual
* righthand-side value into the param's econtext slot.
*
* XXX possible improvement: could make a list of the ParamIDs
* at startup time, instead of repeating this check at each row.
*/ */
if (!IsA(prm, Param)) prmdata = &(econtext->ecxt_param_exec_vals[paramid]);
{
switch (nodeTag(prm))
{
case T_FuncExpr:
prm = lfirst(((FuncExpr *) prm)->args);
break;
case T_RelabelType:
prm = (Param *) (((RelabelType *) prm)->arg);
break;
default:
/* will fail below */
break;
}
if (!IsA(prm, Param))
elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result");
}
Assert(prm->paramkind == PARAM_EXEC);
prmdata = &(econtext->ecxt_param_exec_vals[prm->paramid]);
Assert(prmdata->execPlan == NULL); Assert(prmdata->execPlan == NULL);
prmdata->value = heap_getattr(tup, col, tdesc, prmdata->value = heap_getattr(tup, col, tdesc,
&(prmdata->isnull)); &(prmdata->isnull));
...@@ -236,6 +211,8 @@ ExecSubPlan(SubPlanState *node, ...@@ -236,6 +211,8 @@ ExecSubPlan(SubPlanState *node,
break; /* needn't look at any more columns */ break; /* needn't look at any more columns */
} }
} }
plst = lnext(plst);
col++; col++;
} }
...@@ -312,6 +289,8 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) ...@@ -312,6 +289,8 @@ ExecInitSubPlan(SubPlanState *node, EState *estate)
*/ */
node->needShutdown = false; node->needShutdown = false;
node->curTuple = NULL; node->curTuple = NULL;
node->hashtable = NULL;
node->hashnulls = NULL;
/* /*
* create an EState for the subplan * create an EState for the subplan
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.234 2003/01/09 20:50:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.235 2003/01/10 21:08:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -809,10 +809,10 @@ _copySubLink(SubLink *from) ...@@ -809,10 +809,10 @@ _copySubLink(SubLink *from)
SubLink *newnode = makeNode(SubLink); SubLink *newnode = makeNode(SubLink);
COPY_SCALAR_FIELD(subLinkType); COPY_SCALAR_FIELD(subLinkType);
COPY_SCALAR_FIELD(operIsEquals);
COPY_SCALAR_FIELD(useOr); COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(lefthand); COPY_NODE_FIELD(lefthand);
COPY_NODE_FIELD(oper); COPY_NODE_FIELD(operName);
COPY_INTLIST_FIELD(operOids);
COPY_NODE_FIELD(subselect); COPY_NODE_FIELD(subselect);
return newnode; return newnode;
...@@ -828,10 +828,13 @@ _copySubPlan(SubPlan *from) ...@@ -828,10 +828,13 @@ _copySubPlan(SubPlan *from)
COPY_SCALAR_FIELD(subLinkType); COPY_SCALAR_FIELD(subLinkType);
COPY_SCALAR_FIELD(useOr); COPY_SCALAR_FIELD(useOr);
COPY_NODE_FIELD(oper); COPY_NODE_FIELD(exprs);
COPY_INTLIST_FIELD(paramIds);
COPY_NODE_FIELD(plan); COPY_NODE_FIELD(plan);
COPY_SCALAR_FIELD(plan_id); COPY_SCALAR_FIELD(plan_id);
COPY_NODE_FIELD(rtable); COPY_NODE_FIELD(rtable);
COPY_SCALAR_FIELD(useHashTable);
COPY_SCALAR_FIELD(unknownEqFalse);
COPY_INTLIST_FIELD(setParam); COPY_INTLIST_FIELD(setParam);
COPY_INTLIST_FIELD(parParam); COPY_INTLIST_FIELD(parParam);
COPY_NODE_FIELD(args); COPY_NODE_FIELD(args);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.178 2003/01/09 20:50:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.179 2003/01/10 21:08:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -287,10 +287,10 @@ static bool ...@@ -287,10 +287,10 @@ static bool
_equalSubLink(SubLink *a, SubLink *b) _equalSubLink(SubLink *a, SubLink *b)
{ {
COMPARE_SCALAR_FIELD(subLinkType); COMPARE_SCALAR_FIELD(subLinkType);
COMPARE_SCALAR_FIELD(operIsEquals);
COMPARE_SCALAR_FIELD(useOr); COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(lefthand); COMPARE_NODE_FIELD(lefthand);
COMPARE_NODE_FIELD(oper); COMPARE_NODE_FIELD(operName);
COMPARE_INTLIST_FIELD(operOids);
COMPARE_NODE_FIELD(subselect); COMPARE_NODE_FIELD(subselect);
return true; return true;
...@@ -301,10 +301,13 @@ _equalSubPlan(SubPlan *a, SubPlan *b) ...@@ -301,10 +301,13 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
{ {
COMPARE_SCALAR_FIELD(subLinkType); COMPARE_SCALAR_FIELD(subLinkType);
COMPARE_SCALAR_FIELD(useOr); COMPARE_SCALAR_FIELD(useOr);
COMPARE_NODE_FIELD(oper); COMPARE_NODE_FIELD(exprs);
COMPARE_INTLIST_FIELD(paramIds);
/* should compare plans, but have to settle for comparing plan IDs */ /* should compare plans, but have to settle for comparing plan IDs */
COMPARE_SCALAR_FIELD(plan_id); COMPARE_SCALAR_FIELD(plan_id);
COMPARE_NODE_FIELD(rtable); COMPARE_NODE_FIELD(rtable);
COMPARE_SCALAR_FIELD(useHashTable);
COMPARE_SCALAR_FIELD(unknownEqFalse);
COMPARE_INTLIST_FIELD(setParam); COMPARE_INTLIST_FIELD(setParam);
COMPARE_INTLIST_FIELD(parParam); COMPARE_INTLIST_FIELD(parParam);
COMPARE_NODE_FIELD(args); COMPARE_NODE_FIELD(args);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.191 2003/01/09 20:50:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.192 2003/01/10 21:08:11 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -658,10 +658,10 @@ _outSubLink(StringInfo str, SubLink *node) ...@@ -658,10 +658,10 @@ _outSubLink(StringInfo str, SubLink *node)
WRITE_NODE_TYPE("SUBLINK"); WRITE_NODE_TYPE("SUBLINK");
WRITE_ENUM_FIELD(subLinkType, SubLinkType); WRITE_ENUM_FIELD(subLinkType, SubLinkType);
WRITE_BOOL_FIELD(operIsEquals);
WRITE_BOOL_FIELD(useOr); WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(lefthand); WRITE_NODE_FIELD(lefthand);
WRITE_NODE_FIELD(oper); WRITE_NODE_FIELD(operName);
WRITE_INTLIST_FIELD(operOids);
WRITE_NODE_FIELD(subselect); WRITE_NODE_FIELD(subselect);
} }
...@@ -672,10 +672,13 @@ _outSubPlan(StringInfo str, SubPlan *node) ...@@ -672,10 +672,13 @@ _outSubPlan(StringInfo str, SubPlan *node)
WRITE_ENUM_FIELD(subLinkType, SubLinkType); WRITE_ENUM_FIELD(subLinkType, SubLinkType);
WRITE_BOOL_FIELD(useOr); WRITE_BOOL_FIELD(useOr);
WRITE_NODE_FIELD(oper); WRITE_NODE_FIELD(exprs);
WRITE_INTLIST_FIELD(paramIds);
WRITE_NODE_FIELD(plan); WRITE_NODE_FIELD(plan);
WRITE_INT_FIELD(plan_id); WRITE_INT_FIELD(plan_id);
WRITE_NODE_FIELD(rtable); WRITE_NODE_FIELD(rtable);
WRITE_BOOL_FIELD(useHashTable);
WRITE_BOOL_FIELD(unknownEqFalse);
WRITE_INTLIST_FIELD(setParam); WRITE_INTLIST_FIELD(setParam);
WRITE_INTLIST_FIELD(parParam); WRITE_INTLIST_FIELD(parParam);
WRITE_NODE_FIELD(args); WRITE_NODE_FIELD(args);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.145 2003/01/09 20:50:51 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.146 2003/01/10 21:08:11 tgl Exp $
* *
* NOTES * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
...@@ -531,10 +531,10 @@ _readSubLink(void) ...@@ -531,10 +531,10 @@ _readSubLink(void)
READ_LOCALS(SubLink); READ_LOCALS(SubLink);
READ_ENUM_FIELD(subLinkType, SubLinkType); READ_ENUM_FIELD(subLinkType, SubLinkType);
READ_BOOL_FIELD(operIsEquals);
READ_BOOL_FIELD(useOr); READ_BOOL_FIELD(useOr);
READ_NODE_FIELD(lefthand); READ_NODE_FIELD(lefthand);
READ_NODE_FIELD(oper); READ_NODE_FIELD(operName);
READ_INTLIST_FIELD(operOids);
READ_NODE_FIELD(subselect); READ_NODE_FIELD(subselect);
READ_DONE(); READ_DONE();
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.86 2002/12/14 00:17:55 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.87 2003/01/10 21:08:11 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -42,6 +42,7 @@ typedef struct ...@@ -42,6 +42,7 @@ typedef struct
static void fix_expr_references(Plan *plan, Node *node); static void fix_expr_references(Plan *plan, Node *node);
static bool fix_expr_references_walker(Node *node, void *context); 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_join_references(Join *join, List *rtable);
static void set_uppernode_references(Plan *plan, Index subvarno); static void set_uppernode_references(Plan *plan, Index subvarno);
static Node *join_references_mutator(Node *node, static Node *join_references_mutator(Node *node,
...@@ -88,10 +89,12 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -88,10 +89,12 @@ set_plan_references(Plan *plan, List *rtable)
case T_SeqScan: case T_SeqScan:
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
break; break;
case T_IndexScan: case T_IndexScan:
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((IndexScan *) plan)->indxqual); (Node *) ((IndexScan *) plan)->indxqual);
fix_expr_references(plan, fix_expr_references(plan,
...@@ -100,6 +103,7 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -100,6 +103,7 @@ set_plan_references(Plan *plan, List *rtable)
case T_TidScan: case T_TidScan:
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((TidScan *) plan)->tideval); (Node *) ((TidScan *) plan)->tideval);
break; break;
...@@ -114,6 +118,7 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -114,6 +118,7 @@ set_plan_references(Plan *plan, List *rtable)
*/ */
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
/* Recurse into subplan too */ /* Recurse into subplan too */
rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid, rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid,
...@@ -129,6 +134,7 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -129,6 +134,7 @@ set_plan_references(Plan *plan, List *rtable)
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid, rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
rtable); rtable);
Assert(rte->rtekind == RTE_FUNCTION); Assert(rte->rtekind == RTE_FUNCTION);
...@@ -139,13 +145,17 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -139,13 +145,17 @@ set_plan_references(Plan *plan, List *rtable)
set_join_references((Join *) plan, rtable); set_join_references((Join *) plan, rtable);
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
mark_qual_expressions(((Join *) plan)->joinqual);
break; break;
case T_MergeJoin: case T_MergeJoin:
set_join_references((Join *) plan, rtable); set_join_references((Join *) plan, rtable);
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
mark_qual_expressions(((Join *) plan)->joinqual);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((MergeJoin *) plan)->mergeclauses); (Node *) ((MergeJoin *) plan)->mergeclauses);
break; break;
...@@ -153,7 +163,9 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -153,7 +163,9 @@ set_plan_references(Plan *plan, List *rtable)
set_join_references((Join *) plan, rtable); set_join_references((Join *) plan, rtable);
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
mark_qual_expressions(((Join *) plan)->joinqual);
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((HashJoin *) plan)->hashclauses); (Node *) ((HashJoin *) plan)->hashclauses);
break; break;
...@@ -180,6 +192,7 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -180,6 +192,7 @@ set_plan_references(Plan *plan, List *rtable)
set_uppernode_references(plan, (Index) 0); set_uppernode_references(plan, (Index) 0);
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
break; break;
case T_Result: case T_Result:
...@@ -193,7 +206,9 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -193,7 +206,9 @@ set_plan_references(Plan *plan, List *rtable)
set_uppernode_references(plan, (Index) OUTER); set_uppernode_references(plan, (Index) OUTER);
fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) plan->qual);
mark_qual_expressions(plan->qual);
fix_expr_references(plan, ((Result *) plan)->resconstantqual); fix_expr_references(plan, ((Result *) plan)->resconstantqual);
mark_qual_expressions((List *) ((Result *) plan)->resconstantqual);
break; break;
case T_Append: case T_Append:
...@@ -268,6 +283,28 @@ fix_expr_references_walker(Node *node, void *context) ...@@ -268,6 +283,28 @@ fix_expr_references_walker(Node *node, void *context)
return expression_tree_walker(node, fix_expr_references_walker, context); 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 * set_join_references
* Modifies the target list of a join node to reference its subplans, * Modifies the target list of a join node to reference its subplans,
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.120 2002/12/15 16:17:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.121 2003/01/10 21:08:13 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -721,7 +721,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node, ...@@ -721,7 +721,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
* mistakenly think that something like "WHERE random() < 0.5" can be treated * mistakenly think that something like "WHERE random() < 0.5" can be treated
* as a constant qualification. * as a constant qualification.
* *
* XXX we do not examine sublinks/subplans to see if they contain uses of * XXX we do not examine sub-selects to see if they contain uses of
* mutable functions. It's not real clear if that is correct or not... * mutable functions. It's not real clear if that is correct or not...
*/ */
bool bool
...@@ -759,6 +759,18 @@ contain_mutable_functions_walker(Node *node, void *context) ...@@ -759,6 +759,18 @@ contain_mutable_functions_walker(Node *node, void *context)
return true; return true;
/* else fall through to check args */ /* else fall through to check args */
} }
if (IsA(node, SubLink))
{
SubLink *sublink = (SubLink *) node;
List *opid;
foreach(opid, sublink->operOids)
{
if (op_volatile((Oid) lfirsti(opid)) != PROVOLATILE_IMMUTABLE)
return true;
}
/* else fall through to check args */
}
return expression_tree_walker(node, contain_mutable_functions_walker, return expression_tree_walker(node, contain_mutable_functions_walker,
context); context);
} }
...@@ -776,7 +788,7 @@ contain_mutable_functions_walker(Node *node, void *context) ...@@ -776,7 +788,7 @@ contain_mutable_functions_walker(Node *node, void *context)
* volatile function) is found. This test prevents invalid conversions * volatile function) is found. This test prevents invalid conversions
* of volatile expressions into indexscan quals. * of volatile expressions into indexscan quals.
* *
* XXX we do not examine sublinks/subplans to see if they contain uses of * XXX we do not examine sub-selects to see if they contain uses of
* volatile functions. It's not real clear if that is correct or not... * volatile functions. It's not real clear if that is correct or not...
*/ */
bool bool
...@@ -814,6 +826,18 @@ contain_volatile_functions_walker(Node *node, void *context) ...@@ -814,6 +826,18 @@ contain_volatile_functions_walker(Node *node, void *context)
return true; return true;
/* else fall through to check args */ /* else fall through to check args */
} }
if (IsA(node, SubLink))
{
SubLink *sublink = (SubLink *) node;
List *opid;
foreach(opid, sublink->operOids)
{
if (op_volatile((Oid) lfirsti(opid)) == PROVOLATILE_VOLATILE)
return true;
}
/* else fall through to check args */
}
return expression_tree_walker(node, contain_volatile_functions_walker, return expression_tree_walker(node, contain_volatile_functions_walker,
context); context);
} }
...@@ -830,7 +854,7 @@ contain_volatile_functions_walker(Node *node, void *context) ...@@ -830,7 +854,7 @@ contain_volatile_functions_walker(Node *node, void *context)
* Returns true if any nonstrict construct is found --- ie, anything that * Returns true if any nonstrict construct is found --- ie, anything that
* could produce non-NULL output with a NULL input. * could produce non-NULL output with a NULL input.
* *
* XXX we do not examine sublinks/subplans to see if they contain uses of * 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... * nonstrict functions. It's not real clear if that is correct or not...
* for the current usage it does not matter, since inline_function() * for the current usage it does not matter, since inline_function()
* rejects cases with sublinks. * rejects cases with sublinks.
...@@ -887,6 +911,18 @@ contain_nonstrict_functions_walker(Node *node, void *context) ...@@ -887,6 +911,18 @@ contain_nonstrict_functions_walker(Node *node, void *context)
return true; return true;
if (IsA(node, BooleanTest)) if (IsA(node, BooleanTest))
return true; return true;
if (IsA(node, SubLink))
{
SubLink *sublink = (SubLink *) node;
List *opid;
foreach(opid, sublink->operOids)
{
if (!op_strict((Oid) lfirsti(opid)))
return true;
}
/* else fall through to check args */
}
return expression_tree_walker(node, contain_nonstrict_functions_walker, return expression_tree_walker(node, contain_nonstrict_functions_walker,
context); context);
} }
...@@ -2130,8 +2166,8 @@ substitute_actual_parameters_mutator(Node *node, ...@@ -2130,8 +2166,8 @@ substitute_actual_parameters_mutator(Node *node,
* walker on all the expression subtrees of the given Query node. * walker on all the expression subtrees of the given Query node.
* *
* expression_tree_walker will handle SubPlan nodes by recursing normally * expression_tree_walker will handle SubPlan nodes by recursing normally
* into the "oper" and "args" lists (which are expressions belonging to the * into the "exprs" and "args" lists (which are expressions belonging to
* outer plan). It will not touch the completed subplan, however. Since * the outer plan). It will not touch the completed subplan, however. Since
* there is no link to the original Query, it is not possible to recurse into * there is no link to the original Query, it is not possible to recurse into
* subselects of an already-planned expression tree. This is OK for current * subselects of an already-planned expression tree. This is OK for current
* uses, but may need to be revisited in future. * uses, but may need to be revisited in future.
...@@ -2224,11 +2260,6 @@ expression_tree_walker(Node *node, ...@@ -2224,11 +2260,6 @@ expression_tree_walker(Node *node,
{ {
SubLink *sublink = (SubLink *) node; SubLink *sublink = (SubLink *) node;
/*
* We only recurse into the lefthand list (the incomplete
* OpExpr nodes in the oper list are deemed uninteresting,
* perhaps even confusing).
*/
if (expression_tree_walker((Node *) sublink->lefthand, if (expression_tree_walker((Node *) sublink->lefthand,
walker, context)) walker, context))
return true; return true;
...@@ -2243,8 +2274,8 @@ expression_tree_walker(Node *node, ...@@ -2243,8 +2274,8 @@ expression_tree_walker(Node *node,
{ {
SubPlan *subplan = (SubPlan *) node; SubPlan *subplan = (SubPlan *) node;
/* recurse into the oper list, but not into the Plan */ /* recurse into the exprs list, but not into the Plan */
if (expression_tree_walker((Node *) subplan->oper, if (expression_tree_walker((Node *) subplan->exprs,
walker, context)) walker, context))
return true; return true;
/* also examine args list */ /* also examine args list */
...@@ -2451,7 +2482,7 @@ query_tree_walker(Query *query, ...@@ -2451,7 +2482,7 @@ query_tree_walker(Query *query,
* and qualifier clauses during the planning stage. * and qualifier clauses during the planning stage.
* *
* expression_tree_mutator will handle a SubPlan node by recursing into * expression_tree_mutator will handle a SubPlan node by recursing into
* the "oper" and "args" lists (which belong to the outer plan), but it * the "exprs" and "args" lists (which belong to the outer plan), but it
* will simply copy the link to the inner plan, since that's typically what * will simply copy the link to the inner plan, since that's typically what
* expression tree mutators want. A mutator that wants to modify the subplan * expression tree mutators want. A mutator that wants to modify the subplan
* can force appropriate behavior by recognizing SubPlan expression nodes * can force appropriate behavior by recognizing SubPlan expression nodes
...@@ -2567,8 +2598,7 @@ expression_tree_mutator(Node *node, ...@@ -2567,8 +2598,7 @@ expression_tree_mutator(Node *node,
case T_SubLink: case T_SubLink:
{ {
/* /*
* We transform the lefthand side, but not the oper list nor * We transform the lefthand side, but not the subquery.
* the subquery.
*/ */
SubLink *sublink = (SubLink *) node; SubLink *sublink = (SubLink *) node;
SubLink *newnode; SubLink *newnode;
...@@ -2584,10 +2614,10 @@ expression_tree_mutator(Node *node, ...@@ -2584,10 +2614,10 @@ expression_tree_mutator(Node *node,
SubPlan *newnode; SubPlan *newnode;
FLATCOPY(newnode, subplan, SubPlan); FLATCOPY(newnode, subplan, SubPlan);
/* transform exprs list */
MUTATE(newnode->exprs, subplan->exprs, List *);
/* transform args list (params to be passed to subplan) */ /* transform args list (params to be passed to subplan) */
MUTATE(newnode->args, subplan->args, List *); MUTATE(newnode->args, subplan->args, List *);
/* transform oper list as well */
MUTATE(newnode->oper, subplan->oper, List *);
/* but not the sub-Plan itself, which is referenced as-is */ /* but not the sub-Plan itself, which is referenced as-is */
return (Node *) newnode; return (Node *) newnode;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.42 2002/12/14 00:17:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.43 2003/01/10 21:08:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -107,13 +107,13 @@ pull_varnos_walker(Node *node, pull_varnos_context *context) ...@@ -107,13 +107,13 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
{ {
/* /*
* Already-planned subquery. Examine the args list (parameters to * Already-planned subquery. Examine the args list (parameters to
* be passed to subquery), as well as the "oper" list which is * be passed to subquery), as well as the exprs list which is
* executed by the outer query. But short-circuit recursion into * executed by the outer query. But short-circuit recursion into
* the subquery itself, which would be a waste of effort. * the subquery itself, which would be a waste of effort.
*/ */
SubPlan *subplan = (SubPlan *) node; SubPlan *subplan = (SubPlan *) node;
if (pull_varnos_walker((Node *) subplan->oper, if (pull_varnos_walker((Node *) subplan->exprs,
context)) context))
return true; return true;
if (pull_varnos_walker((Node *) subplan->args, if (pull_varnos_walker((Node *) subplan->args,
...@@ -190,13 +190,13 @@ contain_var_reference_walker(Node *node, ...@@ -190,13 +190,13 @@ contain_var_reference_walker(Node *node,
{ {
/* /*
* Already-planned subquery. Examine the args list (parameters to * Already-planned subquery. Examine the args list (parameters to
* be passed to subquery), as well as the "oper" list which is * be passed to subquery), as well as the exprs list which is
* executed by the outer query. But short-circuit recursion into * executed by the outer query. But short-circuit recursion into
* the subquery itself, which would be a waste of effort. * the subquery itself, which would be a waste of effort.
*/ */
SubPlan *subplan = (SubPlan *) node; SubPlan *subplan = (SubPlan *) node;
if (contain_var_reference_walker((Node *) subplan->oper, if (contain_var_reference_walker((Node *) subplan->exprs,
context)) context))
return true; return true;
if (contain_var_reference_walker((Node *) subplan->args, if (contain_var_reference_walker((Node *) subplan->args,
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.393 2003/01/10 11:02:51 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.394 2003/01/10 21:08:13 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -5430,10 +5430,9 @@ opt_interval: ...@@ -5430,10 +5430,9 @@ opt_interval:
r_expr: row IN_P select_with_parens r_expr: row IN_P select_with_parens
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1;
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
/* operIsEquals and useOr will be set later */ n->lefthand = $1;
n->operName = makeList1(makeString("="));
n->subselect = $3; n->subselect = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -5441,10 +5440,9 @@ r_expr: row IN_P select_with_parens ...@@ -5441,10 +5440,9 @@ r_expr: row IN_P select_with_parens
{ {
/* Make an IN node */ /* Make an IN node */
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1;
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
/* operIsEquals and useOr will be set later */ n->lefthand = $1;
n->operName = makeList1(makeString("="));
n->subselect = $4; n->subselect = $4;
/* Stick a NOT on top */ /* Stick a NOT on top */
$$ = (Node *) makeA_Expr(NOT, NIL, NULL, (Node *) n); $$ = (Node *) makeA_Expr(NOT, NIL, NULL, (Node *) n);
...@@ -5453,10 +5451,9 @@ r_expr: row IN_P select_with_parens ...@@ -5453,10 +5451,9 @@ r_expr: row IN_P select_with_parens
%prec Op %prec Op
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1;
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL);
n->subLinkType = $3; n->subLinkType = $3;
/* operIsEquals and useOr will be set later */ n->lefthand = $1;
n->operName = $2;
n->subselect = $4; n->subselect = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -5464,10 +5461,9 @@ r_expr: row IN_P select_with_parens ...@@ -5464,10 +5461,9 @@ r_expr: row IN_P select_with_parens
%prec Op %prec Op
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = $1;
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL);
n->subLinkType = MULTIEXPR_SUBLINK; n->subLinkType = MULTIEXPR_SUBLINK;
/* operIsEquals and useOr will be set later */ n->lefthand = $1;
n->operName = $2;
n->subselect = $3; n->subselect = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -5848,10 +5844,9 @@ a_expr: c_expr { $$ = $1; } ...@@ -5848,10 +5844,9 @@ a_expr: c_expr { $$ = $1; }
if (IsA($3, SubLink)) if (IsA($3, SubLink))
{ {
SubLink *n = (SubLink *)$3; SubLink *n = (SubLink *)$3;
n->lefthand = makeList1($1);
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
/* operIsEquals and useOr will be set later */ n->lefthand = makeList1($1);
n->operName = makeList1(makeString("="));
$$ = (Node *)n; $$ = (Node *)n;
} }
else else
...@@ -5877,10 +5872,9 @@ a_expr: c_expr { $$ = $1; } ...@@ -5877,10 +5872,9 @@ a_expr: c_expr { $$ = $1; }
{ {
/* Make an IN node */ /* Make an IN node */
SubLink *n = (SubLink *)$4; SubLink *n = (SubLink *)$4;
n->lefthand = makeList1($1);
n->oper = (List *) makeSimpleA_Expr(OP, "=", NULL, NULL);
n->subLinkType = ANY_SUBLINK; n->subLinkType = ANY_SUBLINK;
/* operIsEquals and useOr will be set later */ n->lefthand = makeList1($1);
n->operName = makeList1(makeString("="));
/* Stick a NOT on top */ /* Stick a NOT on top */
$$ = (Node *) makeA_Expr(NOT, NIL, NULL, (Node *) n); $$ = (Node *) makeA_Expr(NOT, NIL, NULL, (Node *) n);
} }
...@@ -5903,10 +5897,9 @@ a_expr: c_expr { $$ = $1; } ...@@ -5903,10 +5897,9 @@ a_expr: c_expr { $$ = $1; }
| a_expr qual_all_Op sub_type select_with_parens %prec Op | a_expr qual_all_Op sub_type select_with_parens %prec Op
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = makeList1($1);
n->oper = (List *) makeA_Expr(OP, $2, NULL, NULL);
n->subLinkType = $3; n->subLinkType = $3;
/* operIsEquals and useOr will be set later */ n->lefthand = makeList1($1);
n->operName = $2;
n->subselect = $4; n->subselect = $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -6447,18 +6440,18 @@ c_expr: columnref { $$ = (Node *) $1; } ...@@ -6447,18 +6440,18 @@ c_expr: columnref { $$ = (Node *) $1; }
| select_with_parens %prec UMINUS | select_with_parens %prec UMINUS
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = NIL;
n->oper = NIL;
n->subLinkType = EXPR_SUBLINK; n->subLinkType = EXPR_SUBLINK;
n->lefthand = NIL;
n->operName = NIL;
n->subselect = $1; n->subselect = $1;
$$ = (Node *)n; $$ = (Node *)n;
} }
| EXISTS select_with_parens | EXISTS select_with_parens
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->lefthand = NIL;
n->oper = NIL;
n->subLinkType = EXISTS_SUBLINK; n->subLinkType = EXISTS_SUBLINK;
n->lefthand = NIL;
n->operName = NIL;
n->subselect = $2; n->subselect = $2;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -6610,6 +6603,7 @@ in_expr: select_with_parens ...@@ -6610,6 +6603,7 @@ in_expr: select_with_parens
{ {
SubLink *n = makeNode(SubLink); SubLink *n = makeNode(SubLink);
n->subselect = $1; n->subselect = $1;
/* other fields will be filled later */
$$ = (Node *)n; $$ = (Node *)n;
} }
| '(' expr_list ')' { $$ = (Node *)$2; } | '(' expr_list ')' { $$ = (Node *)$2; }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.139 2003/01/09 20:50:52 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.140 2003/01/10 21:08:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -366,8 +366,8 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -366,8 +366,8 @@ transformExpr(ParseState *pstate, Node *expr)
* These fields should be NIL already, but make sure. * These fields should be NIL already, but make sure.
*/ */
sublink->lefthand = NIL; sublink->lefthand = NIL;
sublink->oper = NIL; sublink->operName = NIL;
sublink->operIsEquals = FALSE; sublink->operOids = NIL;
sublink->useOr = FALSE; sublink->useOr = FALSE;
} }
else if (sublink->subLinkType == EXPR_SUBLINK) else if (sublink->subLinkType == EXPR_SUBLINK)
...@@ -392,8 +392,8 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -392,8 +392,8 @@ transformExpr(ParseState *pstate, Node *expr)
* fields should be NIL already, but make sure. * fields should be NIL already, but make sure.
*/ */
sublink->lefthand = NIL; sublink->lefthand = NIL;
sublink->oper = NIL; sublink->operName = NIL;
sublink->operIsEquals = FALSE; sublink->operOids = NIL;
sublink->useOr = FALSE; sublink->useOr = FALSE;
} }
else else
...@@ -403,20 +403,14 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -403,20 +403,14 @@ transformExpr(ParseState *pstate, Node *expr)
List *right_list = qtree->targetList; List *right_list = qtree->targetList;
int row_length = length(left_list); int row_length = length(left_list);
bool needNot = false; bool needNot = false;
List *op; List *op = sublink->operName;
char *opname; char *opname = strVal(llast(op));
List *elist; List *elist;
/* transform lefthand expressions */ /* transform lefthand expressions */
foreach(elist, left_list) foreach(elist, left_list)
lfirst(elist) = transformExpr(pstate, lfirst(elist)); lfirst(elist) = transformExpr(pstate, lfirst(elist));
/* get the combining-operator name */
Assert(IsA(sublink->oper, A_Expr));
op = ((A_Expr *) sublink->oper)->name;
opname = strVal(llast(op));
sublink->oper = NIL;
/* /*
* If the expression is "<> ALL" (with unqualified opname) * If the expression is "<> ALL" (with unqualified opname)
* then convert it to "NOT IN". This is a hack to improve * then convert it to "NOT IN". This is a hack to improve
...@@ -428,15 +422,10 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -428,15 +422,10 @@ transformExpr(ParseState *pstate, Node *expr)
sublink->subLinkType = ANY_SUBLINK; sublink->subLinkType = ANY_SUBLINK;
opname = pstrdup("="); opname = pstrdup("=");
op = makeList1(makeString(opname)); op = makeList1(makeString(opname));
sublink->operName = op;
needNot = true; needNot = true;
} }
/* Set operIsEquals if op is unqualified "=" */
if (length(op) == 1 && strcmp(opname, "=") == 0)
sublink->operIsEquals = TRUE;
else
sublink->operIsEquals = FALSE;
/* Set useOr if op is "<>" (possibly qualified) */ /* Set useOr if op is "<>" (possibly qualified) */
if (strcmp(opname, "<>") == 0) if (strcmp(opname, "<>") == 0)
sublink->useOr = TRUE; sublink->useOr = TRUE;
...@@ -451,19 +440,21 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -451,19 +440,21 @@ transformExpr(ParseState *pstate, Node *expr)
opname); opname);
/* /*
* Scan subquery's targetlist to find values that will * To build the list of combining operator OIDs, we must
* scan subquery's targetlist to find values that will
* be matched against lefthand values. We need to * be matched against lefthand values. We need to
* ignore resjunk targets, so doing the outer * ignore resjunk targets, so doing the outer
* iteration over right_list is easier than doing it * iteration over right_list is easier than doing it
* over left_list. * over left_list.
*/ */
sublink->operOids = NIL;
while (right_list != NIL) while (right_list != NIL)
{ {
TargetEntry *tent = (TargetEntry *) lfirst(right_list); TargetEntry *tent = (TargetEntry *) lfirst(right_list);
Node *lexpr; Node *lexpr;
Operator optup; Operator optup;
Form_pg_operator opform; Form_pg_operator opform;
OpExpr *newop;
right_list = lnext(right_list); right_list = lnext(right_list);
if (tent->resdom->resjunk) if (tent->resdom->resjunk)
...@@ -496,14 +487,8 @@ transformExpr(ParseState *pstate, Node *expr) ...@@ -496,14 +487,8 @@ transformExpr(ParseState *pstate, Node *expr)
" to be used with quantified predicate subquery", " to be used with quantified predicate subquery",
opname); opname);
newop = makeNode(OpExpr); sublink->operOids = lappendi(sublink->operOids,
newop->opno = oprid(optup); oprid(optup));
newop->opfuncid = InvalidOid;
newop->opresulttype = opform->oprresult;
newop->opretset = false;
newop->args = NIL; /* for now */
sublink->oper = lappend(sublink->oper, newop);
ReleaseSysCache(optup); ReleaseSysCache(optup);
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.131 2003/01/09 20:50:52 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.132 2003/01/10 21:08:15 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -167,6 +167,7 @@ static bool tleIsArrayAssign(TargetEntry *tle); ...@@ -167,6 +167,7 @@ static bool tleIsArrayAssign(TargetEntry *tle);
static char *generate_relation_name(Oid relid); static char *generate_relation_name(Oid relid);
static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes); static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes);
static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2); static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2);
static void print_operator_name(StringInfo buf, List *opname);
static char *get_relid_attribute_name(Oid relid, AttrNumber attnum); static char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
#define only_marker(rte) ((rte)->inh ? "" : "ONLY ") #define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
...@@ -2111,6 +2112,9 @@ get_rule_expr(Node *node, deparse_context *context, ...@@ -2111,6 +2112,9 @@ get_rule_expr(Node *node, deparse_context *context,
* rule deparsing, only while EXPLAINing a query * rule deparsing, only while EXPLAINing a query
* plan. For now, just punt. * plan. For now, just punt.
*/ */
if (((SubPlan *) node)->useHashTable)
appendStringInfo(buf, "(hashed subplan)");
else
appendStringInfo(buf, "(subplan)"); appendStringInfo(buf, "(subplan)");
} }
break; break;
...@@ -2619,7 +2623,6 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) ...@@ -2619,7 +2623,6 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
Query *query = (Query *) (sublink->subselect); Query *query = (Query *) (sublink->subselect);
List *l; List *l;
char *sep; char *sep;
OpExpr *oper;
bool need_paren; bool need_paren;
appendStringInfoChar(buf, '('); appendStringInfoChar(buf, '(');
...@@ -2647,11 +2650,10 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) ...@@ -2647,11 +2650,10 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
need_paren = true; need_paren = true;
/* /*
* XXX we assume here that we can get away without qualifying the * XXX we regurgitate the originally given operator name, with or without
* operator name. Since the name may imply multiple physical * schema qualification. This is not necessarily 100% right but it's
* operators it's rather difficult to do otherwise --- in fact, if the * the best we can do, since the operators actually used might not all
* operators are in different namespaces any attempt to qualify would * be in the same schema.
* surely fail.
*/ */
switch (sublink->subLinkType) switch (sublink->subLinkType)
{ {
...@@ -2660,26 +2662,27 @@ get_sublink_expr(SubLink *sublink, deparse_context *context) ...@@ -2660,26 +2662,27 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
break; break;
case ANY_SUBLINK: case ANY_SUBLINK:
if (sublink->operIsEquals) if (length(sublink->operName) == 1 &&
strcmp(strVal(lfirst(sublink->operName)), "=") == 0)
{ {
/* Represent it as IN */ /* Represent = ANY as IN */
appendStringInfo(buf, "IN "); appendStringInfo(buf, "IN ");
} }
else else
{ {
oper = (OpExpr *) lfirst(sublink->oper); print_operator_name(buf, sublink->operName);
appendStringInfo(buf, "%s ANY ", get_opname(oper->opno)); appendStringInfo(buf, " ANY ");
} }
break; break;
case ALL_SUBLINK: case ALL_SUBLINK:
oper = (OpExpr *) lfirst(sublink->oper); print_operator_name(buf, sublink->operName);
appendStringInfo(buf, "%s ALL ", get_opname(oper->opno)); appendStringInfo(buf, " ALL ");
break; break;
case MULTIEXPR_SUBLINK: case MULTIEXPR_SUBLINK:
oper = (OpExpr *) lfirst(sublink->oper); print_operator_name(buf, sublink->operName);
appendStringInfo(buf, "%s ", get_opname(oper->opno)); appendStringInfoChar(buf, ' ');
break; break;
case EXPR_SUBLINK: case EXPR_SUBLINK:
...@@ -3274,6 +3277,29 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2) ...@@ -3274,6 +3277,29 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
return buf.data; return buf.data;
} }
/*
* Print out a possibly-qualified operator name
*/
static void
print_operator_name(StringInfo buf, List *opname)
{
int nnames = length(opname);
if (nnames == 1)
appendStringInfo(buf, "%s", strVal(lfirst(opname)));
else
{
appendStringInfo(buf, "OPERATOR(");
while (nnames-- > 1)
{
appendStringInfo(buf, "%s.",
quote_identifier(strVal(lfirst(opname))));
opname = lnext(opname);
}
appendStringInfo(buf, "%s)", strVal(lfirst(opname)));
}
}
/* /*
* get_relid_attribute_name * get_relid_attribute_name
* Get an attribute name by its relations Oid and its attnum * Get an attribute name by its relations Oid and its attnum
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.171 2003/01/09 20:50:53 tgl Exp $ * $Id: catversion.h,v 1.172 2003/01/10 21:08:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200301091 #define CATALOG_VERSION_NO 200301101
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execnodes.h,v 1.88 2002/12/18 00:14:47 tgl Exp $ * $Id: execnodes.h,v 1.89 2003/01/10 21:08:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -445,15 +445,21 @@ typedef struct BoolExprState ...@@ -445,15 +445,21 @@ typedef struct BoolExprState
* SubPlanState node * SubPlanState node
* ---------------- * ----------------
*/ */
/* this struct is private in nodeSubplan.c: */
typedef struct SubPlanHashTableData *SubPlanHashTable;
typedef struct SubPlanState typedef struct SubPlanState
{ {
ExprState xprstate; ExprState xprstate;
EState *sub_estate; /* subselect plan has its own EState */ EState *sub_estate; /* subselect plan has its own EState */
struct PlanState *planstate; /* subselect plan's state tree */ struct PlanState *planstate; /* subselect plan's state tree */
List *exprs; /* states of combining expression(s) */
List *args; /* states of argument expression(s) */
bool needShutdown; /* TRUE = need to shutdown subplan */ bool needShutdown; /* TRUE = need to shutdown subplan */
HeapTuple curTuple; /* copy of most recent tuple from subplan */ HeapTuple curTuple; /* copy of most recent tuple from subplan */
List *oper; /* states for executable combining exprs */ /* these are used when hashing the subselect's output: */
List *args; /* states of argument expression(s) */ SubPlanHashTable hashtable; /* hash table for no-nulls subselect rows */
SubPlanHashTable hashnulls; /* hash table for rows with null(s) */
} SubPlanState; } SubPlanState;
/* ---------------- /* ----------------
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: primnodes.h,v 1.76 2003/01/09 20:50:53 tgl Exp $ * $Id: primnodes.h,v 1.77 2003/01/10 21:08:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -381,25 +381,18 @@ typedef struct BoolExpr ...@@ -381,25 +381,18 @@ typedef struct BoolExpr
* it must be replaced in the expression tree by a SubPlan node during * it must be replaced in the expression tree by a SubPlan node during
* planning. * planning.
* *
* NOTE: in the raw output of gram.y, lefthand contains a list of (raw) * NOTE: in the raw output of gram.y, lefthand contains a list of raw
* expressions, and oper contains a single A_Expr (not a list!) containing * expressions; useOr and operOids are not filled in yet. Also, subselect
* the string name of the operator, but no arguments. Also, subselect is * is a raw parsetree. During parse analysis, the parser transforms the
* a raw parsetree. During parse analysis, the parser transforms the
* lefthand expression list using normal expression transformation rules. * lefthand expression list using normal expression transformation rules.
* It replaces oper with a list of OpExpr nodes, one per lefthand expression. * It fills operOids with the OIDs representing the specific operator(s)
* These nodes represent the parser's resolution of exactly which operator * to apply to each pair of lefthand and targetlist expressions.
* to apply to each pair of lefthand and targetlist expressions. However, * And subselect is transformed to a Query. This is the representation
* we have not constructed complete Expr trees for these operations yet: * seen in saved rules and in the rewriter.
* the args fields of the OpExpr nodes are NIL. And subselect is transformed *
* to a Query. This is the representation seen in saved rules and in the * In EXISTS and EXPR SubLinks, lefthand, operName, and operOids are unused
* rewriter. * and are always NIL. useOr is not significant either for these sublink
* * types.
* In EXISTS and EXPR SubLinks, both lefthand and oper are unused and are
* always NIL. useOr is not significant either for these sublink types.
*
* The operIsEquals field is TRUE when the combining operator was written as
* "=" --- if the subLinkType is ANY_SUBLINK, this means the operation is
* equivalent to "IN". This case allows special optimizations to be used.
* ---------------- * ----------------
*/ */
typedef enum SubLinkType typedef enum SubLinkType
...@@ -412,13 +405,12 @@ typedef struct SubLink ...@@ -412,13 +405,12 @@ typedef struct SubLink
{ {
Expr xpr; Expr xpr;
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */ SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
bool operIsEquals; /* TRUE if combining operator is "=" */
bool useOr; /* TRUE to combine column results with bool useOr; /* TRUE to combine column results with
* "OR" not "AND" */ * "OR" not "AND" */
List *lefthand; /* list of outer-query expressions on the List *lefthand; /* list of outer-query expressions on the
* left */ * left */
List *oper; /* list of arg-less OpExpr nodes for List *operName; /* originally specified operator name */
* combining operators */ List *operOids; /* OIDs of actual combining operators */
Node *subselect; /* subselect as Query* or parsetree */ Node *subselect; /* subselect as Query* or parsetree */
} SubLink; } SubLink;
...@@ -427,15 +419,16 @@ typedef struct SubLink ...@@ -427,15 +419,16 @@ typedef struct SubLink
* *
* The planner replaces SubLink nodes in expression trees with SubPlan * The planner replaces SubLink nodes in expression trees with SubPlan
* nodes after it has finished planning the subquery. SubPlan contains * nodes after it has finished planning the subquery. SubPlan contains
* a sub-plantree and rtable instead of a sub-Query. Its "oper" field * a sub-plantree and rtable instead of a sub-Query.
* corresponds to the original SubLink's oper list, but has been expanded *
* into valid executable expressions representing the application of the * In an ordinary subplan, "exprs" points to a list of executable expressions
* combining operator(s) to the lefthand expressions and values from the * (OpExpr trees) for the combining operators; their left-hand arguments are
* inner targetlist. The original lefthand expressions now appear as * the original lefthand expressions, and their right-hand arguments are
* left-hand arguments of the OpExpr nodes, while the inner targetlist items * PARAM_EXEC Param nodes representing the outputs of the sub-select.
* are represented by PARAM_EXEC Param nodes. (Note: if the sub-select * (NOTE: runtime coercion functions may be inserted as well.) But if the
* becomes an InitPlan rather than a SubPlan, the rebuilt oper list is * sub-select becomes an initplan rather than a subplan, these executable
* part of the outer plan tree and so is not stored in the oper field.) * expressions are part of the outer plan's expression tree (and the SubPlan
* node itself is not). In this case "exprs" is NIL to avoid duplication.
* *
* The planner also derives lists of the values that need to be passed into * The planner also derives lists of the values that need to be passed into
* and out of the subplan. Input values are represented as a list "args" of * and out of the subplan. Input values are represented as a list "args" of
...@@ -444,7 +437,7 @@ typedef struct SubLink ...@@ -444,7 +437,7 @@ typedef struct SubLink
* The values are assigned to the global PARAM_EXEC params indexed by parParam * The values are assigned to the global PARAM_EXEC params indexed by parParam
* (the parParam and args lists must have the same length). setParam is a * (the parParam and args lists must have the same length). setParam is a
* list of the PARAM_EXEC params that are computed by the sub-select, if it * list of the PARAM_EXEC params that are computed by the sub-select, if it
* is an initPlan. * is an initplan.
*/ */
typedef struct SubPlan typedef struct SubPlan
{ {
...@@ -453,8 +446,9 @@ typedef struct SubPlan ...@@ -453,8 +446,9 @@ typedef struct SubPlan
SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */ SubLinkType subLinkType; /* EXISTS, ALL, ANY, MULTIEXPR, EXPR */
bool useOr; /* TRUE to combine column results with bool useOr; /* TRUE to combine column results with
* "OR" not "AND" */ * "OR" not "AND" */
List *oper; /* list of executable expressions for /* The combining operators, transformed to executable expressions: */
* combining operators (with arguments) */ List *exprs; /* list of OpExpr expression trees */
List *paramIds; /* IDs of Params embedded in the above */
/* The subselect, transformed to a Plan: */ /* The subselect, transformed to a Plan: */
struct Plan *plan; /* subselect plan itself */ struct Plan *plan; /* subselect plan itself */
int plan_id; /* dummy thing because of we haven't equal int plan_id; /* dummy thing because of we haven't equal
...@@ -462,10 +456,16 @@ typedef struct SubPlan ...@@ -462,10 +456,16 @@ typedef struct SubPlan
* could put *plan itself somewhere else * could put *plan itself somewhere else
* (TopPlan node ?)... */ * (TopPlan node ?)... */
List *rtable; /* range table for subselect */ List *rtable; /* range table for subselect */
/* Information about execution strategy: */
bool useHashTable; /* TRUE to store subselect output in a hash
* table (implies we are doing "IN") */
bool unknownEqFalse; /* TRUE if it's okay to return FALSE when
* the spec result is UNKNOWN; this allows
* much simpler handling of null values */
/* Information for passing params into and out of the subselect: */ /* Information for passing params into and out of the subselect: */
/* setParam and parParam are lists of integers (param IDs) */ /* setParam and parParam are lists of integers (param IDs) */
List *setParam; /* non-correlated EXPR & EXISTS subqueries List *setParam; /* initplan subqueries have to set these
* have to set some Params for paren Plan */ * Params for parent plan */
List *parParam; /* indices of input Params from parent plan */ List *parParam; /* indices of input Params from parent plan */
List *args; /* exprs to pass as parParam values */ List *args; /* exprs to pass as parParam values */
} SubPlan; } SubPlan;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment