mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
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.
This commit is contained in:
parent
36ea26793a
commit
e69785debf
@ -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,
|
|||||||
&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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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 @@
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
* 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
|
|||||||
_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)
|
|||||||
{
|
{
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
||||||
|
@ -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/optimizer/plan/subselect.c,v 1.62 2003/01/09 20:50:51 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.63 2003/01/10 21:08:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "catalog/pg_operator.h"
|
#include "catalog/pg_operator.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "miscadmin.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "nodes/params.h"
|
#include "nodes/params.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
@ -25,6 +26,7 @@
|
|||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "parser/parse_expr.h"
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
@ -59,8 +61,9 @@ typedef struct finalize_primnode_results
|
|||||||
} finalize_primnode_results;
|
} finalize_primnode_results;
|
||||||
|
|
||||||
|
|
||||||
static List *convert_sublink_opers(List *operlist, List *lefthand,
|
static List *convert_sublink_opers(List *lefthand, List *operOids,
|
||||||
List *targetlist, List **setParams);
|
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 *replace_correlation_vars_mutator(Node *node, void *context);
|
||||||
static Node *process_sublinks_mutator(Node *node, void *context);
|
static Node *process_sublinks_mutator(Node *node, void *context);
|
||||||
static bool finalize_primnode(Node *node, finalize_primnode_results *results);
|
static bool finalize_primnode(Node *node, finalize_primnode_results *results);
|
||||||
@ -222,11 +225,14 @@ make_subplan(SubLink *slink, List *lefthand)
|
|||||||
node->rtable = subquery->rtable;
|
node->rtable = subquery->rtable;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill in other fields of the SubPlan node.
|
* Initialize other fields of the SubPlan node.
|
||||||
*/
|
*/
|
||||||
node->subLinkType = slink->subLinkType;
|
node->subLinkType = slink->subLinkType;
|
||||||
node->useOr = slink->useOr;
|
node->useOr = slink->useOr;
|
||||||
node->oper = NIL;
|
node->exprs = NIL;
|
||||||
|
node->paramIds = NIL;
|
||||||
|
node->useHashTable = false;
|
||||||
|
node->unknownEqFalse = false;
|
||||||
node->setParam = NIL;
|
node->setParam = NIL;
|
||||||
node->parParam = NIL;
|
node->parParam = NIL;
|
||||||
node->args = NIL;
|
node->args = NIL;
|
||||||
@ -267,6 +273,7 @@ make_subplan(SubLink *slink, List *lefthand)
|
|||||||
TargetEntry *te = lfirst(plan->targetlist);
|
TargetEntry *te = lfirst(plan->targetlist);
|
||||||
Param *prm;
|
Param *prm;
|
||||||
|
|
||||||
|
Assert(!te->resdom->resjunk);
|
||||||
prm = generate_new_param(te->resdom->restype, te->resdom->restypmod);
|
prm = generate_new_param(te->resdom->restype, te->resdom->restypmod);
|
||||||
node->setParam = lappendi(node->setParam, prm->paramid);
|
node->setParam = lappendi(node->setParam, prm->paramid);
|
||||||
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
||||||
@ -274,19 +281,25 @@ make_subplan(SubLink *slink, List *lefthand)
|
|||||||
}
|
}
|
||||||
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
|
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
|
||||||
{
|
{
|
||||||
List *oper;
|
List *exprs;
|
||||||
|
|
||||||
/* Convert the oper list, but don't put it into the SubPlan node */
|
/* Convert the lefthand exprs and oper OIDs into executable exprs */
|
||||||
oper = convert_sublink_opers(slink->oper,
|
exprs = convert_sublink_opers(lefthand,
|
||||||
lefthand,
|
slink->operOids,
|
||||||
plan->targetlist,
|
plan->targetlist,
|
||||||
&node->setParam);
|
&node->paramIds);
|
||||||
|
node->setParam = nconc(node->setParam, listCopy(node->paramIds));
|
||||||
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
||||||
if (length(oper) > 1)
|
/*
|
||||||
result = (Node *) (node->useOr ? make_orclause(oper) :
|
* The executable expressions are returned to become part of the
|
||||||
make_andclause(oper));
|
* outer plan's expression tree; they are not kept in the initplan
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
if (length(exprs) > 1)
|
||||||
|
result = (Node *) (node->useOr ? make_orclause(exprs) :
|
||||||
|
make_andclause(exprs));
|
||||||
else
|
else
|
||||||
result = (Node *) lfirst(oper);
|
result = (Node *) lfirst(exprs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -296,13 +309,20 @@ make_subplan(SubLink *slink, List *lefthand)
|
|||||||
* We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types
|
* We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types
|
||||||
* to initPlans, even when they are uncorrelated or undirect
|
* to initPlans, even when they are uncorrelated or undirect
|
||||||
* correlated, because we need to scan the output of the subplan
|
* correlated, because we need to scan the output of the subplan
|
||||||
* for each outer tuple. However, we have the option to tack a
|
* for each outer tuple. But if it's an IN (= ANY) test, we might
|
||||||
* MATERIAL node onto the top of an uncorrelated/undirect
|
* be able to use a hashtable to avoid comparing all the tuples.
|
||||||
* correlated subplan, which lets us do the work of evaluating the
|
*/
|
||||||
* subplan only once. We do this if the subplan's top plan node
|
if (subplan_is_hashable(slink, node))
|
||||||
* is anything more complicated than a plain sequential scan, and
|
node->useHashTable = true;
|
||||||
* we do it even for seqscan if the qual appears selective enough
|
/*
|
||||||
* to eliminate many tuples.
|
* Otherwise, we have the option to tack a MATERIAL node onto the top
|
||||||
|
* of the subplan, to reduce the cost of reading it repeatedly. This
|
||||||
|
* is pointless for a direct-correlated subplan, since we'd have to
|
||||||
|
* recompute its results each time anyway. For uncorrelated/undirect
|
||||||
|
* correlated subplans, we add MATERIAL if the subplan's top plan node
|
||||||
|
* is anything more complicated than a plain sequential scan, and we
|
||||||
|
* do it even for seqscan if the qual appears selective enough to
|
||||||
|
* eliminate many tuples.
|
||||||
*
|
*
|
||||||
* XXX It's pretty ugly to be inserting a MATERIAL node at this
|
* XXX It's pretty ugly to be inserting a MATERIAL node at this
|
||||||
* point. Since subquery_planner has already run SS_finalize_plan
|
* point. Since subquery_planner has already run SS_finalize_plan
|
||||||
@ -310,7 +330,7 @@ make_subplan(SubLink *slink, List *lefthand)
|
|||||||
* the MATERIAL node. Possibly this could be fixed by postponing
|
* the MATERIAL node. Possibly this could be fixed by postponing
|
||||||
* SS_finalize_plan processing until setrefs.c is run.
|
* SS_finalize_plan processing until setrefs.c is run.
|
||||||
*/
|
*/
|
||||||
if (node->parParam == NIL)
|
else if (node->parParam == NIL)
|
||||||
{
|
{
|
||||||
bool use_material;
|
bool use_material;
|
||||||
|
|
||||||
@ -365,11 +385,11 @@ make_subplan(SubLink *slink, List *lefthand)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the SubLink's oper list into executable form */
|
/* Convert the lefthand exprs and oper OIDs into executable exprs */
|
||||||
node->oper = convert_sublink_opers(slink->oper,
|
node->exprs = convert_sublink_opers(lefthand,
|
||||||
lefthand,
|
slink->operOids,
|
||||||
plan->targetlist,
|
plan->targetlist,
|
||||||
NULL);
|
&node->paramIds);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make node->args from parParam.
|
* Make node->args from parParam.
|
||||||
@ -398,29 +418,26 @@ make_subplan(SubLink *slink, List *lefthand)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* convert_sublink_opers: convert a SubLink's oper list from the
|
* convert_sublink_opers: given a lefthand-expressions list and a list of
|
||||||
* parser/rewriter format into the executor's format.
|
* operator OIDs, build a list of actually executable expressions. The
|
||||||
|
* righthand sides of the expressions are Params representing the results
|
||||||
|
* of the sub-select.
|
||||||
*
|
*
|
||||||
* The oper list is initially a list of OpExpr nodes with NIL args. We
|
* The paramids of the Params created are returned in the *paramIds list.
|
||||||
* convert it to a list of actually executable expressions, in which the
|
|
||||||
* specified operators are applied to corresponding elements of the
|
|
||||||
* lefthand list and Params representing the results of the subplan.
|
|
||||||
*
|
|
||||||
* If setParams is not NULL, the paramids of the Params created are added
|
|
||||||
* to the *setParams list.
|
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
convert_sublink_opers(List *operlist, List *lefthand,
|
convert_sublink_opers(List *lefthand, List *operOids,
|
||||||
List *targetlist, List **setParams)
|
List *targetlist, List **paramIds)
|
||||||
{
|
{
|
||||||
List *newoper = NIL;
|
List *result = NIL;
|
||||||
List *leftlist = lefthand;
|
|
||||||
List *lst;
|
List *lst;
|
||||||
|
|
||||||
foreach(lst, operlist)
|
*paramIds = NIL;
|
||||||
|
|
||||||
|
foreach(lst, operOids)
|
||||||
{
|
{
|
||||||
OpExpr *oper = (OpExpr *) lfirst(lst);
|
Oid opid = (Oid) lfirsti(lst);
|
||||||
Node *leftop = lfirst(leftlist);
|
Node *leftop = lfirst(lefthand);
|
||||||
TargetEntry *te = lfirst(targetlist);
|
TargetEntry *te = lfirst(targetlist);
|
||||||
Param *prm;
|
Param *prm;
|
||||||
Operator tup;
|
Operator tup;
|
||||||
@ -428,21 +445,21 @@ convert_sublink_opers(List *operlist, List *lefthand,
|
|||||||
Node *left,
|
Node *left,
|
||||||
*right;
|
*right;
|
||||||
|
|
||||||
|
Assert(!te->resdom->resjunk);
|
||||||
|
|
||||||
/* Make the Param node representing the subplan's result */
|
/* Make the Param node representing the subplan's result */
|
||||||
prm = generate_new_param(te->resdom->restype,
|
prm = generate_new_param(te->resdom->restype,
|
||||||
te->resdom->restypmod);
|
te->resdom->restypmod);
|
||||||
|
|
||||||
/* Record its ID if needed */
|
/* Record its ID */
|
||||||
if (setParams)
|
*paramIds = lappendi(*paramIds, prm->paramid);
|
||||||
*setParams = lappendi(*setParams, prm->paramid);
|
|
||||||
|
|
||||||
/* Look up the operator to check its declared input types */
|
/* Look up the operator to get its declared input types */
|
||||||
Assert(IsA(oper, OpExpr));
|
|
||||||
tup = SearchSysCache(OPEROID,
|
tup = SearchSysCache(OPEROID,
|
||||||
ObjectIdGetDatum(oper->opno),
|
ObjectIdGetDatum(opid),
|
||||||
0, 0, 0);
|
0, 0, 0);
|
||||||
if (!HeapTupleIsValid(tup))
|
if (!HeapTupleIsValid(tup))
|
||||||
elog(ERROR, "cache lookup failed for operator %u", oper->opno);
|
elog(ERROR, "cache lookup failed for operator %u", opid);
|
||||||
opform = (Form_pg_operator) GETSTRUCT(tup);
|
opform = (Form_pg_operator) GETSTRUCT(tup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -453,20 +470,86 @@ convert_sublink_opers(List *operlist, List *lefthand,
|
|||||||
*/
|
*/
|
||||||
left = make_operand(leftop, exprType(leftop), opform->oprleft);
|
left = make_operand(leftop, exprType(leftop), opform->oprleft);
|
||||||
right = make_operand((Node *) prm, prm->paramtype, opform->oprright);
|
right = make_operand((Node *) prm, prm->paramtype, opform->oprright);
|
||||||
newoper = lappend(newoper,
|
result = lappend(result,
|
||||||
make_opclause(oper->opno,
|
make_opclause(opid,
|
||||||
oper->opresulttype,
|
opform->oprresult,
|
||||||
oper->opretset,
|
false, /* set-result not allowed */
|
||||||
(Expr *) left,
|
(Expr *) left,
|
||||||
(Expr *) right));
|
(Expr *) right));
|
||||||
|
|
||||||
ReleaseSysCache(tup);
|
ReleaseSysCache(tup);
|
||||||
|
|
||||||
leftlist = lnext(leftlist);
|
lefthand = lnext(lefthand);
|
||||||
targetlist = lnext(targetlist);
|
targetlist = lnext(targetlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return newoper;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* subplan_is_hashable: decide whether we can implement a subplan by hashing
|
||||||
|
*
|
||||||
|
* Caution: the SubPlan node is not completely filled in yet. We can rely
|
||||||
|
* on its plan and parParam fields, however.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
subplan_is_hashable(SubLink *slink, SubPlan *node)
|
||||||
|
{
|
||||||
|
double subquery_size;
|
||||||
|
List *opids;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The sublink type must be "= ANY" --- that is, an IN operator.
|
||||||
|
* (We require the operator name to be unqualified, which may be
|
||||||
|
* overly paranoid, or may not be.) XXX since we also check that the
|
||||||
|
* operators are hashable, the test on operator name may be redundant?
|
||||||
|
*/
|
||||||
|
if (slink->subLinkType != ANY_SUBLINK)
|
||||||
|
return false;
|
||||||
|
if (length(slink->operName) != 1 ||
|
||||||
|
strcmp(strVal(lfirst(slink->operName)), "=") != 0)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* The subplan must not have any direct correlation vars --- else we'd
|
||||||
|
* have to recompute its output each time, so that the hashtable wouldn't
|
||||||
|
* gain anything.
|
||||||
|
*/
|
||||||
|
if (node->parParam != NIL)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* The estimated size of the subquery result must fit in SortMem.
|
||||||
|
* (XXX what about hashtable overhead?)
|
||||||
|
*/
|
||||||
|
subquery_size = node->plan->plan_rows *
|
||||||
|
(MAXALIGN(node->plan->plan_width) + MAXALIGN(sizeof(HeapTupleData)));
|
||||||
|
if (subquery_size > SortMem * 1024L)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* The combining operators must be hashable and strict. (Without
|
||||||
|
* strictness, behavior in the presence of nulls is too unpredictable.
|
||||||
|
* We actually must assume even more than plain strictness, see
|
||||||
|
* nodeSubplan.c for details.)
|
||||||
|
*/
|
||||||
|
foreach(opids, slink->operOids)
|
||||||
|
{
|
||||||
|
Oid opid = (Oid) lfirsti(opids);
|
||||||
|
HeapTuple tup;
|
||||||
|
Form_pg_operator optup;
|
||||||
|
|
||||||
|
tup = SearchSysCache(OPEROID,
|
||||||
|
ObjectIdGetDatum(opid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(tup))
|
||||||
|
elog(ERROR, "cache lookup failed for operator %u", opid);
|
||||||
|
optup = (Form_pg_operator) GETSTRUCT(tup);
|
||||||
|
if (!optup->oprcanhash || !func_strict(optup->oprcode))
|
||||||
|
{
|
||||||
|
ReleaseSysCache(tup);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ReleaseSysCache(tup);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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,
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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,
|
|||||||
* 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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
* 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,
|
|||||||
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,
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* 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,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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:
|
|||||||
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
|
|||||||
{
|
{
|
||||||
/* 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
|
|||||||
%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
|
|||||||
%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; }
|
|||||||
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; }
|
|||||||
{
|
{
|
||||||
/* 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; }
|
|||||||
| 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; }
|
|||||||
| 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
|
|||||||
{
|
{
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
* 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)
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
" 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 @@
|
|||||||
* 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);
|
|||||||
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,
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
* 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 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200301091
|
#define CATALOG_VERSION_NO 200301101
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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
|
|||||||
* 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 @@
|
|||||||
* 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
|
|||||||
* 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
|
|
||||||
* rewriter.
|
|
||||||
*
|
*
|
||||||
* In EXISTS and EXPR SubLinks, both lefthand and oper are unused and are
|
* In EXISTS and EXPR SubLinks, lefthand, operName, and operOids are unused
|
||||||
* always NIL. useOr is not significant either for these sublink types.
|
* 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
|
|||||||
{
|
{
|
||||||
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
|
|||||||
*
|
*
|
||||||
* 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
|
|||||||
* 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
|
|||||||
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
|
|||||||
* 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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user