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:
parent
ac47950238
commit
ea0b5c8569
src
backend
commands
executor
optimizer
parser
utils/adt
include/nodes
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.182 2002/11/25 21:29:34 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.183 2002/11/26 03:01:57 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -749,7 +749,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
FmgrInfo *in_functions;
|
FmgrInfo *in_functions;
|
||||||
Oid *elements;
|
Oid *elements;
|
||||||
Node **constraintexprs;
|
Node **constraintexprs;
|
||||||
Const **constraintconsts;
|
|
||||||
bool hasConstraints = false;
|
bool hasConstraints = false;
|
||||||
int i;
|
int i;
|
||||||
List *cur;
|
List *cur;
|
||||||
@ -805,7 +804,6 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
defmap = (int *) palloc(num_phys_attrs * sizeof(int));
|
defmap = (int *) palloc(num_phys_attrs * sizeof(int));
|
||||||
defexprs = (Node **) palloc(num_phys_attrs * sizeof(Node *));
|
defexprs = (Node **) palloc(num_phys_attrs * sizeof(Node *));
|
||||||
constraintexprs = (Node **) palloc0(num_phys_attrs * sizeof(Node *));
|
constraintexprs = (Node **) palloc0(num_phys_attrs * sizeof(Node *));
|
||||||
constraintconsts = (Const **) palloc(num_phys_attrs * sizeof(Const *));
|
|
||||||
|
|
||||||
for (i = 0; i < num_phys_attrs; i++)
|
for (i = 0; i < num_phys_attrs; i++)
|
||||||
{
|
{
|
||||||
@ -840,7 +838,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
/* If it's a domain type, get info on domain constraints */
|
/* If it's a domain type, get info on domain constraints */
|
||||||
if (get_typtype(attr[i]->atttypid) == 'd')
|
if (get_typtype(attr[i]->atttypid) == 'd')
|
||||||
{
|
{
|
||||||
Const *con;
|
Param *prm;
|
||||||
Node *node;
|
Node *node;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -848,28 +846,21 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
* an expression that checks the constraints. (At present,
|
* an expression that checks the constraints. (At present,
|
||||||
* the expression might contain a length-coercion-function call
|
* the expression might contain a length-coercion-function call
|
||||||
* and/or ConstraintTest nodes.) The bottom of the expression
|
* and/or ConstraintTest nodes.) The bottom of the expression
|
||||||
* is a Const node that we fill in with the actual datum during
|
* is a Param node so that we can fill in the actual datum during
|
||||||
* the data input loop.
|
* the data input loop.
|
||||||
*
|
|
||||||
* XXX to prevent premature constant folding in parse_coerce,
|
|
||||||
* pass in a NULL constant to start with. See the comments in
|
|
||||||
* coerce_type; this should be changed someday to use some sort
|
|
||||||
* of Param node instead of a Const.
|
|
||||||
*/
|
*/
|
||||||
con = makeConst(attr[i]->atttypid,
|
prm = makeNode(Param);
|
||||||
attr[i]->attlen,
|
prm->paramkind = PARAM_EXEC;
|
||||||
(Datum) 0,
|
prm->paramid = 0;
|
||||||
true, /* is null */
|
prm->paramtype = attr[i]->atttypid;
|
||||||
attr[i]->attbyval);
|
|
||||||
|
|
||||||
node = coerce_type_constraints((Node *) con, attr[i]->atttypid,
|
node = coerce_type_constraints((Node *) prm, attr[i]->atttypid,
|
||||||
COERCE_IMPLICIT_CAST);
|
COERCE_IMPLICIT_CAST);
|
||||||
|
|
||||||
/* check whether any constraints actually found */
|
/* check whether any constraints actually found */
|
||||||
if (node != (Node *) con)
|
if (node != (Node *) prm)
|
||||||
{
|
{
|
||||||
constraintexprs[i] = node;
|
constraintexprs[i] = node;
|
||||||
constraintconsts[i] = con;
|
|
||||||
hasConstraints = true;
|
hasConstraints = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -931,6 +922,11 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
|
|
||||||
econtext = GetPerTupleExprContext(estate);
|
econtext = GetPerTupleExprContext(estate);
|
||||||
|
|
||||||
|
/* Make room for a PARAM_EXEC value for domain constraint checks */
|
||||||
|
if (hasConstraints)
|
||||||
|
econtext->ecxt_param_exec_vals = (ParamExecData *)
|
||||||
|
palloc0(sizeof(ParamExecData));
|
||||||
|
|
||||||
while (!done)
|
while (!done)
|
||||||
{
|
{
|
||||||
bool skip_tuple;
|
bool skip_tuple;
|
||||||
@ -1153,19 +1149,19 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
*/
|
*/
|
||||||
if (hasConstraints)
|
if (hasConstraints)
|
||||||
{
|
{
|
||||||
|
ParamExecData *prmdata = &econtext->ecxt_param_exec_vals[0];
|
||||||
|
|
||||||
for (i = 0; i < num_phys_attrs; i++)
|
for (i = 0; i < num_phys_attrs; i++)
|
||||||
{
|
{
|
||||||
Node *node = constraintexprs[i];
|
Node *node = constraintexprs[i];
|
||||||
Const *con;
|
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
continue; /* no constraint for this attr */
|
continue; /* no constraint for this attr */
|
||||||
|
|
||||||
/* Insert current row's value into the Const node */
|
/* Insert current row's value into the Param value */
|
||||||
con = constraintconsts[i];
|
prmdata->value = values[i];
|
||||||
con->constvalue = values[i];
|
prmdata->isnull = (nulls[i] == 'n');
|
||||||
con->constisnull = (nulls[i] == 'n');
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the constraint expression. Allow the expression
|
* Execute the constraint expression. Allow the expression
|
||||||
|
@ -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.33 2002/06/20 20:29:28 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.34 2002/11/26 03:01:57 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -150,37 +150,44 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
|||||||
foreach(lst, sublink->oper)
|
foreach(lst, sublink->oper)
|
||||||
{
|
{
|
||||||
Expr *expr = (Expr *) lfirst(lst);
|
Expr *expr = (Expr *) lfirst(lst);
|
||||||
Const *con = lsecond(expr->args);
|
Param *prm = lsecond(expr->args);
|
||||||
|
ParamExecData *prmdata;
|
||||||
Datum expresult;
|
Datum expresult;
|
||||||
bool expnull;
|
bool expnull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The righthand side of the expression should be either a
|
* The righthand side of the expression should be either a
|
||||||
* Const or a function call or RelabelType node taking a Const
|
* Param or a function call or RelabelType node taking a Param
|
||||||
* as arg (these nodes represent run-time type coercions
|
* as arg (these nodes represent run-time type coercions
|
||||||
* inserted by the parser to get to the input type needed by
|
* inserted by the parser to get to the input type needed by
|
||||||
* the operator). Find the Const node and insert the actual
|
* the operator). Find the Param node and insert the actual
|
||||||
* righthand-side value into it.
|
* 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(con, Const))
|
if (!IsA(prm, Param))
|
||||||
{
|
{
|
||||||
switch (con->type)
|
switch (nodeTag(prm))
|
||||||
{
|
{
|
||||||
case T_Expr:
|
case T_Expr:
|
||||||
con = lfirst(((Expr *) con)->args);
|
prm = lfirst(((Expr *) prm)->args);
|
||||||
break;
|
break;
|
||||||
case T_RelabelType:
|
case T_RelabelType:
|
||||||
con = (Const *) (((RelabelType *) con)->arg);
|
prm = (Param *) (((RelabelType *) prm)->arg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* will fail below */
|
/* will fail below */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!IsA(con, Const))
|
if (!IsA(prm, Param))
|
||||||
elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result");
|
elog(ERROR, "ExecSubPlan: failed to find placeholder for subplan result");
|
||||||
}
|
}
|
||||||
con->constvalue = heap_getattr(tup, col, tdesc,
|
Assert(prm->paramkind == PARAM_EXEC);
|
||||||
&(con->constisnull));
|
prmdata = &(econtext->ecxt_param_exec_vals[prm->paramid]);
|
||||||
|
Assert(prmdata->execPlan == NULL);
|
||||||
|
prmdata->value = heap_getattr(tup, col, tdesc,
|
||||||
|
&(prmdata->isnull));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we can eval the combining operator for this column.
|
* Now we can eval the combining operator for this column.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* Note that at this point quals have not yet been converted to
|
||||||
* implicit-AND form, so we can apply eval_const_expressions directly.
|
* 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);
|
expr = eval_const_expressions(expr);
|
||||||
|
|
||||||
|
@ -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.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
|
* and update the list elements when we enter or exit a subplan
|
||||||
* recursion level. But we must pay attention not to confuse this
|
* recursion level. But we must pay attention not to confuse this
|
||||||
* meaning with the normal meaning of varlevelsup.
|
* 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.
|
* Create a new entry in the PlannerParamVar list, and return its index.
|
||||||
*
|
*
|
||||||
* var contains the data to be copied, except for varlevelsup which
|
* var contains the data to use, except for varlevelsup which
|
||||||
* is set from the absolute level value given by varlevel.
|
* 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
|
static int
|
||||||
new_param(Var *var, Index varlevel)
|
new_param(Var *var, Index varlevel)
|
||||||
{
|
{
|
||||||
Var *paramVar = (Var *) copyObject(var);
|
var->varlevelsup = varlevel;
|
||||||
|
|
||||||
paramVar->varlevelsup = varlevel;
|
PlannerParamVar = lappend(PlannerParamVar, var);
|
||||||
|
|
||||||
PlannerParamVar = lappend(PlannerParamVar, paramVar);
|
|
||||||
|
|
||||||
return length(PlannerParamVar) - 1;
|
return length(PlannerParamVar) - 1;
|
||||||
}
|
}
|
||||||
@ -107,7 +115,7 @@ replace_var(Var *var)
|
|||||||
if (!ppv)
|
if (!ppv)
|
||||||
{
|
{
|
||||||
/* Nope, so make a new one */
|
/* Nope, so make a new one */
|
||||||
i = new_param(var, varlevel);
|
i = new_param((Var *) copyObject(var), varlevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = makeNode(Param);
|
retval = makeNode(Param);
|
||||||
@ -118,6 +126,22 @@ replace_var(Var *var)
|
|||||||
return retval;
|
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.
|
* 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)
|
if (node->parParam == NIL && slink->subLinkType == EXISTS_SUBLINK)
|
||||||
{
|
{
|
||||||
Var *var = makeVar(0, 0, BOOLOID, -1, 0);
|
Param *prm;
|
||||||
Param *prm = makeNode(Param);
|
|
||||||
|
|
||||||
prm->paramkind = PARAM_EXEC;
|
prm = generate_new_param(BOOLOID, -1);
|
||||||
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
|
|
||||||
prm->paramtype = var->vartype;
|
|
||||||
pfree(var); /* var is only needed for new_param */
|
|
||||||
node->setParam = lappendi(node->setParam, prm->paramid);
|
node->setParam = lappendi(node->setParam, prm->paramid);
|
||||||
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
||||||
result = (Node *) prm;
|
result = (Node *) prm;
|
||||||
@ -230,89 +250,27 @@ make_subplan(SubLink *slink)
|
|||||||
else if (node->parParam == NIL && slink->subLinkType == EXPR_SUBLINK)
|
else if (node->parParam == NIL && slink->subLinkType == EXPR_SUBLINK)
|
||||||
{
|
{
|
||||||
TargetEntry *te = lfirst(plan->targetlist);
|
TargetEntry *te = lfirst(plan->targetlist);
|
||||||
|
Param *prm;
|
||||||
|
|
||||||
/* need a var node just to pass to new_param()... */
|
prm = generate_new_param(te->resdom->restype, te->resdom->restypmod);
|
||||||
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 */
|
|
||||||
node->setParam = lappendi(node->setParam, prm->paramid);
|
node->setParam = lappendi(node->setParam, prm->paramid);
|
||||||
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
||||||
result = (Node *) prm;
|
result = (Node *) prm;
|
||||||
}
|
}
|
||||||
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
|
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
|
||||||
{
|
{
|
||||||
List *newoper = NIL;
|
convert_sublink_opers(slink, plan->targetlist, &node->setParam);
|
||||||
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;
|
|
||||||
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
PlannerInitPlan = lappend(PlannerInitPlan, node);
|
||||||
if (i > 1)
|
if (length(slink->oper) > 1)
|
||||||
result = (Node *) ((slink->useor) ? make_orclause(newoper) :
|
result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
|
||||||
make_andclause(newoper));
|
make_andclause(slink->oper));
|
||||||
else
|
else
|
||||||
result = (Node *) lfirst(newoper);
|
result = (Node *) lfirst(slink->oper);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Expr *expr = makeNode(Expr);
|
Expr *expr = makeNode(Expr);
|
||||||
List *args = NIL;
|
List *args = NIL;
|
||||||
List *newoper = NIL;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types
|
* 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
|
* Make expression of SUBPLAN type
|
||||||
*/
|
*/
|
||||||
@ -405,55 +366,84 @@ make_subplan(SubLink *slink)
|
|||||||
}
|
}
|
||||||
expr->args = args;
|
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;
|
result = (Node *) expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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
|
* finalize_primnode: build lists of subplans and params appearing
|
||||||
* in the given expression tree. NOTE: items are added to lists passed in,
|
* in the given expression tree. NOTE: items are added to lists passed in,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -1135,14 +1135,6 @@ CommuteClause(Expr *clause)
|
|||||||
*
|
*
|
||||||
* We assume that the tree has already been type-checked and contains
|
* We assume that the tree has already been type-checked and contains
|
||||||
* only operators and functions that are reasonable to try to execute.
|
* 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 *
|
Node *
|
||||||
@ -1411,11 +1403,13 @@ eval_const_expressions_mutator(Node *node, void *context)
|
|||||||
case SUBPLAN_EXPR:
|
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
|
* with it. The arglist simplification above was wasted
|
||||||
* work (the list probably only contains Var nodes
|
* work (the list probably only contains Var nodes
|
||||||
* anyway).
|
* anyway).
|
||||||
|
*
|
||||||
|
* XXX should we elog() here instead? Probably this routine
|
||||||
|
* should never be invoked after SubPlan creation.
|
||||||
*/
|
*/
|
||||||
return (Node *) expr;
|
return (Node *) expr;
|
||||||
default:
|
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
|
* Note we take the result type from the Oper or Func node, not the
|
||||||
* pg_proc tuple; probably necessary for binary-compatibility cases.
|
* pg_proc tuple; probably necessary for binary-compatibility cases.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
if (expr->opType == OP_EXPR)
|
if (expr->opType == OP_EXPR)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.87 2002/11/25 21:29:41 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.88 2002/11/26 03:01:58 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -241,14 +241,8 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
|||||||
*
|
*
|
||||||
* Note that no folding will occur if the conversion function is
|
* Note that no folding will occur if the conversion function is
|
||||||
* not marked 'immutable'.
|
* not marked 'immutable'.
|
||||||
*
|
|
||||||
* HACK: if constant is NULL, don't fold it here. This is needed
|
|
||||||
* by make_subplan(), which calls this routine on placeholder
|
|
||||||
* Const nodes that mustn't be collapsed. (It'd be a lot
|
|
||||||
* cleaner to make a separate node type for that purpose...)
|
|
||||||
*/
|
*/
|
||||||
if (IsA(node, Const) &&
|
if (IsA(node, Const))
|
||||||
!((Const *) node)->constisnull)
|
|
||||||
result = eval_const_expressions(result);
|
result = eval_const_expressions(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.130 2002/11/15 02:50:09 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.131 2002/11/26 03:01:58 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -122,7 +122,6 @@ transformExpr(ParseState *pstate, Node *expr, ConstraintTestValue *domVal)
|
|||||||
param = makeNode(Param);
|
param = makeNode(Param);
|
||||||
param->paramkind = PARAM_NUM;
|
param->paramkind = PARAM_NUM;
|
||||||
param->paramid = (AttrNumber) paramno;
|
param->paramid = (AttrNumber) paramno;
|
||||||
param->paramname = "<unnamed>";
|
|
||||||
param->paramtype = paramtyp;
|
param->paramtype = paramtyp;
|
||||||
result = (Node *) param;
|
result = (Node *) param;
|
||||||
/* handle qualification, if any */
|
/* handle qualification, if any */
|
||||||
|
@ -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.126 2002/11/25 21:29:41 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.127 2002/11/26 03:01:58 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -1921,7 +1921,6 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
* same expression tree.
|
* same expression tree.
|
||||||
*
|
*
|
||||||
* There might be some work left here to support additional node types.
|
* There might be some work left here to support additional node types.
|
||||||
* Can we ever see Param nodes here?
|
|
||||||
*/
|
*/
|
||||||
switch (nodeTag(node))
|
switch (nodeTag(node))
|
||||||
{
|
{
|
||||||
|
@ -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.69 2002/11/25 21:29:42 tgl Exp $
|
* $Id: primnodes.h,v 1.70 2002/11/26 03:01:59 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -357,7 +357,7 @@ typedef struct Aggref
|
|||||||
* 3. Finally, the planner converts the oper list to a list of normal Expr
|
* 3. Finally, the planner converts the oper list to a list of normal Expr
|
||||||
* nodes representing the application of the operator(s) to the lefthand
|
* nodes representing the application of the operator(s) to the lefthand
|
||||||
* expressions and values from the inner targetlist. The inner
|
* expressions and values from the inner targetlist. The inner
|
||||||
* targetlist items are represented by placeholder Param or Const nodes.
|
* targetlist items are represented by placeholder Param nodes.
|
||||||
* The lefthand field is set to NIL, since its expressions are now in
|
* The lefthand field is set to NIL, since its expressions are now in
|
||||||
* the Expr list. This representation is passed to the executor.
|
* the Expr list. This representation is passed to the executor.
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user