1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-07 19:06:32 +03:00

Use Params, rather than run-time-modified Const nodes, to handle

sublink results and COPY's domain constraint checking.  A Const that
isn't really constant is just a Bad Idea(tm).  Remove hacks in
parse_coerce and other places that were needed because of the former
klugery.
This commit is contained in:
Tom Lane
2002-11-26 03:01:59 +00:00
parent ac47950238
commit ea0b5c8569
9 changed files with 166 additions and 190 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.130 2002/11/21 00:42:19 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.131 2002/11/26 03:01:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -720,8 +720,6 @@ preprocess_expression(Query *parse, Node *expr, int kind)
*
* Note that at this point quals have not yet been converted to
* implicit-AND form, so we can apply eval_const_expressions directly.
* Also note that we need to do this before SS_process_sublinks,
* because that routine inserts bogus "Const" nodes.
*/
expr = eval_const_expressions(expr);

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.55 2002/09/04 20:31:21 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.56 2002/11/26 03:01:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,24 +44,32 @@ int PlannerPlanId = 0; /* to assign unique ID to subquery plans */
* and update the list elements when we enter or exit a subplan
* recursion level. But we must pay attention not to confuse this
* meaning with the normal meaning of varlevelsup.
*
* We also need to create Param slots that don't correspond to any outer Var.
* For these, we set varno = 0 and varlevelsup = 0, so that they can't
* accidentally match an outer Var.
*--------------------
*/
static void convert_sublink_opers(SubLink *slink, List *targetlist,
List **setParams);
/*
* Create a new entry in the PlannerParamVar list, and return its index.
*
* var contains the data to be copied, except for varlevelsup which
* is set from the absolute level value given by varlevel.
* var contains the data to use, except for varlevelsup which
* is set from the absolute level value given by varlevel. NOTE that
* the passed var is scribbled on and placed directly into the list!
* Generally, caller should have just created or copied it.
*/
static int
new_param(Var *var, Index varlevel)
{
Var *paramVar = (Var *) copyObject(var);
var->varlevelsup = varlevel;
paramVar->varlevelsup = varlevel;
PlannerParamVar = lappend(PlannerParamVar, paramVar);
PlannerParamVar = lappend(PlannerParamVar, var);
return length(PlannerParamVar) - 1;
}
@@ -107,7 +115,7 @@ replace_var(Var *var)
if (!ppv)
{
/* Nope, so make a new one */
i = new_param(var, varlevel);
i = new_param((Var *) copyObject(var), varlevel);
}
retval = makeNode(Param);
@@ -118,6 +126,22 @@ replace_var(Var *var)
return retval;
}
/*
* Generate a new Param node that will not conflict with any other.
*/
static Param *
generate_new_param(Oid paramtype, int32 paramtypmod)
{
Var *var = makeVar(0, 0, paramtype, paramtypmod, 0);
Param *retval = makeNode(Param);
retval->paramkind = PARAM_EXEC;
retval->paramid = (AttrNumber) new_param(var, 0);
retval->paramtype = paramtype;
return retval;
}
/*
* Convert a bare SubLink (as created by the parser) into a SubPlan.
*/
@@ -216,13 +240,9 @@ make_subplan(SubLink *slink)
*/
if (node->parParam == NIL && slink->subLinkType == EXISTS_SUBLINK)
{
Var *var = makeVar(0, 0, BOOLOID, -1, 0);
Param *prm = makeNode(Param);
Param *prm;
prm->paramkind = PARAM_EXEC;
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
pfree(var); /* var is only needed for new_param */
prm = generate_new_param(BOOLOID, -1);
node->setParam = lappendi(node->setParam, prm->paramid);
PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm;
@@ -230,89 +250,27 @@ make_subplan(SubLink *slink)
else if (node->parParam == NIL && slink->subLinkType == EXPR_SUBLINK)
{
TargetEntry *te = lfirst(plan->targetlist);
Param *prm;
/* need a var node just to pass to new_param()... */
Var *var = makeVar(0, 0, te->resdom->restype,
te->resdom->restypmod, 0);
Param *prm = makeNode(Param);
prm->paramkind = PARAM_EXEC;
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
pfree(var); /* var is only needed for new_param */
prm = generate_new_param(te->resdom->restype, te->resdom->restypmod);
node->setParam = lappendi(node->setParam, prm->paramid);
PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm;
}
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
{
List *newoper = NIL;
int i = 0;
/*
* Convert oper list of Opers into a list of Exprs, using lefthand
* arguments and Params representing inside results.
*/
foreach(lst, slink->oper)
{
Oper *oper = (Oper *) lfirst(lst);
Node *lefthand = nth(i, slink->lefthand);
TargetEntry *te = nth(i, plan->targetlist);
/* need a var node just to pass to new_param()... */
Var *var = makeVar(0, 0, te->resdom->restype,
te->resdom->restypmod, 0);
Param *prm = makeNode(Param);
Operator tup;
Form_pg_operator opform;
Node *left,
*right;
prm->paramkind = PARAM_EXEC;
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
pfree(var); /* var is only needed for new_param */
Assert(IsA(oper, Oper));
tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(oper->opno),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for operator %u", oper->opno);
opform = (Form_pg_operator) GETSTRUCT(tup);
/*
* Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator!
*/
left = make_operand(lefthand,
exprType(lefthand), opform->oprleft);
right = make_operand((Node *) prm,
prm->paramtype, opform->oprright);
ReleaseSysCache(tup);
newoper = lappend(newoper,
make_opclause(oper,
(Var *) left,
(Var *) right));
node->setParam = lappendi(node->setParam, prm->paramid);
i++;
}
slink->oper = newoper;
slink->lefthand = NIL;
convert_sublink_opers(slink, plan->targetlist, &node->setParam);
PlannerInitPlan = lappend(PlannerInitPlan, node);
if (i > 1)
result = (Node *) ((slink->useor) ? make_orclause(newoper) :
make_andclause(newoper));
if (length(slink->oper) > 1)
result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
make_andclause(slink->oper));
else
result = (Node *) lfirst(newoper);
result = (Node *) lfirst(slink->oper);
}
else
{
Expr *expr = makeNode(Expr);
List *args = NIL;
List *newoper = NIL;
int i = 0;
/*
* We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types
@@ -379,6 +337,9 @@ make_subplan(SubLink *slink)
}
}
/* Fix the SubLink's oper list */
convert_sublink_opers(slink, plan->targetlist, NULL);
/*
* Make expression of SUBPLAN type
*/
@@ -405,55 +366,84 @@ make_subplan(SubLink *slink)
}
expr->args = args;
/*
* Convert oper list of Opers into a list of Exprs, using lefthand
* arguments and Consts representing inside results.
*/
foreach(lst, slink->oper)
{
Oper *oper = (Oper *) lfirst(lst);
Node *lefthand = nth(i, slink->lefthand);
TargetEntry *te = nth(i, plan->targetlist);
Const *con;
Operator tup;
Form_pg_operator opform;
Node *left,
*right;
con = makeNullConst(te->resdom->restype);
Assert(IsA(oper, Oper));
tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(oper->opno),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for operator %u", oper->opno);
opform = (Form_pg_operator) GETSTRUCT(tup);
/*
* Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator!
*/
left = make_operand(lefthand,
exprType(lefthand), opform->oprleft);
right = make_operand((Node *) con,
con->consttype, opform->oprright);
ReleaseSysCache(tup);
newoper = lappend(newoper,
make_opclause(oper,
(Var *) left,
(Var *) right));
i++;
}
slink->oper = newoper;
slink->lefthand = NIL;
result = (Node *) expr;
}
return result;
}
/*
* convert_sublink_opers: convert a SubLink's oper list from the
* parser/rewriter format into the executor's format.
*
* The oper list is initially just a list of Oper nodes. We replace it
* with 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. lefthand is then
* set to NIL.
*
* If setParams is not NULL, the paramids of the Params created are added
* to the *setParams list.
*/
static void
convert_sublink_opers(SubLink *slink, List *targetlist,
List **setParams)
{
List *newoper = NIL;
List *leftlist = slink->lefthand;
List *lst;
foreach(lst, slink->oper)
{
Oper *oper = (Oper *) lfirst(lst);
Node *lefthand = lfirst(leftlist);
TargetEntry *te = lfirst(targetlist);
Param *prm;
Operator tup;
Form_pg_operator opform;
Node *left,
*right;
/* Make the Param node representing the subplan's result */
prm = generate_new_param(te->resdom->restype,
te->resdom->restypmod);
/* Record its ID if needed */
if (setParams)
*setParams = lappendi(*setParams, prm->paramid);
/* Look up the operator to check its declared input types */
Assert(IsA(oper, Oper));
tup = SearchSysCache(OPEROID,
ObjectIdGetDatum(oper->opno),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for operator %u", oper->opno);
opform = (Form_pg_operator) GETSTRUCT(tup);
/*
* Make the expression node.
*
* Note: we use make_operand in case runtime type conversion
* function calls must be inserted for this operator!
*/
left = make_operand(lefthand, exprType(lefthand), opform->oprleft);
right = make_operand((Node *) prm, prm->paramtype, opform->oprright);
newoper = lappend(newoper,
make_opclause(oper,
(Var *) left,
(Var *) right));
ReleaseSysCache(tup);
leftlist = lnext(leftlist);
targetlist = lnext(targetlist);
}
slink->oper = newoper;
slink->lefthand = NIL;
}
/*
* finalize_primnode: build lists of subplans and params appearing
* in the given expression tree. NOTE: items are added to lists passed in,

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.112 2002/11/25 21:29:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.113 2002/11/26 03:01:58 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -1135,14 +1135,6 @@ CommuteClause(Expr *clause)
*
* We assume that the tree has already been type-checked and contains
* only operators and functions that are reasonable to try to execute.
*
* This routine should be invoked before converting sublinks to subplans
* (subselect.c's SS_process_sublinks()). The converted form contains
* bogus "Const" nodes that are actually placeholders where the executor
* will insert values from the inner plan, and obviously we mustn't try
* to reduce the expression as though these were really constants.
* As a safeguard, if we happen to find an already-converted SubPlan node,
* we will return it unchanged rather than recursing into it.
*--------------------
*/
Node *
@@ -1411,11 +1403,13 @@ eval_const_expressions_mutator(Node *node, void *context)
case SUBPLAN_EXPR:
/*
* Safety measure per notes at head of this routine:
* return a SubPlan unchanged. Too late to do anything
* Return a SubPlan unchanged --- too late to do anything
* with it. The arglist simplification above was wasted
* work (the list probably only contains Var nodes
* anyway).
*
* XXX should we elog() here instead? Probably this routine
* should never be invoked after SubPlan creation.
*/
return (Node *) expr;
default:
@@ -1629,7 +1623,6 @@ simplify_op_or_func(Expr *expr, List *args)
*
* Note we take the result type from the Oper or Func node, not the
* pg_proc tuple; probably necessary for binary-compatibility cases.
*
*/
if (expr->opType == OP_EXPR)
{