From e64861c79bda659ee384bc253f651401f953dadc Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 13 Nov 2017 15:24:12 -0500 Subject: [PATCH] Track in the plan the types associated with PARAM_EXEC parameters. Up until now, we only tracked the number of parameters, which was sufficient to allocate an array of Datums of the appropriate size, but not sufficient to, for example, know how to serialize a Datum stored in one of those slots. An upcoming patch wants to do that, so add this tracking to make it possible. Patch by me, reviewed by Tom Lane and Amit Kapila. Discussion: http://postgr.es/m/CA+TgmoYqpxDKn8koHdW8BEKk8FMUL0=e8m2Qe=M+r0UBjr3tuQ@mail.gmail.com --- src/backend/executor/execMain.c | 20 ++++++++++----- src/backend/executor/execParallel.c | 2 +- src/backend/nodes/copyfuncs.c | 2 +- src/backend/nodes/outfuncs.c | 4 +-- src/backend/nodes/readfuncs.c | 2 +- src/backend/optimizer/plan/planner.c | 6 ++--- src/backend/optimizer/plan/subselect.c | 35 +++++++++++++++++++------- src/backend/optimizer/util/clauses.c | 2 +- src/include/nodes/plannodes.h | 2 +- src/include/nodes/relation.h | 6 ++--- 10 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 493ff82775f..47f21316429 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -195,9 +195,14 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags) */ estate->es_param_list_info = queryDesc->params; - if (queryDesc->plannedstmt->nParamExec > 0) + if (queryDesc->plannedstmt->paramExecTypes != NIL) + { + int nParamExec; + + nParamExec = list_length(queryDesc->plannedstmt->paramExecTypes); estate->es_param_exec_vals = (ParamExecData *) - palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData)); + palloc0(nParamExec * sizeof(ParamExecData)); + } estate->es_sourceText = queryDesc->sourceText; @@ -3032,9 +3037,11 @@ EvalPlanQualBegin(EPQState *epqstate, EState *parentestate) MemSet(estate->es_epqScanDone, 0, rtsize * sizeof(bool)); /* Recopy current values of parent parameters */ - if (parentestate->es_plannedstmt->nParamExec > 0) + if (parentestate->es_plannedstmt->paramExecTypes != NIL) { - int i = parentestate->es_plannedstmt->nParamExec; + int i; + + i = list_length(parentestate->es_plannedstmt->paramExecTypes); while (--i >= 0) { @@ -3122,10 +3129,11 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree) * already set from other parts of the parent's plan tree. */ estate->es_param_list_info = parentestate->es_param_list_info; - if (parentestate->es_plannedstmt->nParamExec > 0) + if (parentestate->es_plannedstmt->paramExecTypes != NIL) { - int i = parentestate->es_plannedstmt->nParamExec; + int i; + i = list_length(parentestate->es_plannedstmt->paramExecTypes); estate->es_param_exec_vals = (ParamExecData *) palloc0(i * sizeof(ParamExecData)); while (--i >= 0) diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index 1b477baecb8..fd7e7cbf3d3 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -195,7 +195,7 @@ ExecSerializePlan(Plan *plan, EState *estate) pstmt->rowMarks = NIL; pstmt->relationOids = NIL; pstmt->invalItems = NIL; /* workers can't replan anyway... */ - pstmt->nParamExec = estate->es_plannedstmt->nParamExec; + pstmt->paramExecTypes = estate->es_plannedstmt->paramExecTypes; pstmt->utilityStmt = NULL; pstmt->stmt_location = -1; pstmt->stmt_len = -1; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index cadd253ef17..76e75459b46 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -97,7 +97,7 @@ _copyPlannedStmt(const PlannedStmt *from) COPY_NODE_FIELD(rowMarks); COPY_NODE_FIELD(relationOids); COPY_NODE_FIELD(invalItems); - COPY_SCALAR_FIELD(nParamExec); + COPY_NODE_FIELD(paramExecTypes); COPY_NODE_FIELD(utilityStmt); COPY_LOCATION_FIELD(stmt_location); COPY_LOCATION_FIELD(stmt_len); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 291d1eeb46f..dc35df9e4fe 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -282,7 +282,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node) WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(relationOids); WRITE_NODE_FIELD(invalItems); - WRITE_INT_FIELD(nParamExec); + WRITE_NODE_FIELD(paramExecTypes); WRITE_NODE_FIELD(utilityStmt); WRITE_LOCATION_FIELD(stmt_location); WRITE_LOCATION_FIELD(stmt_len); @@ -2181,7 +2181,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node) WRITE_NODE_FIELD(rootResultRelations); WRITE_NODE_FIELD(relationOids); WRITE_NODE_FIELD(invalItems); - WRITE_INT_FIELD(nParamExec); + WRITE_NODE_FIELD(paramExecTypes); WRITE_UINT_FIELD(lastPHId); WRITE_UINT_FIELD(lastRowMarkId); WRITE_INT_FIELD(lastPlanNodeId); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 42c595dc039..593658dd8a8 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1480,7 +1480,7 @@ _readPlannedStmt(void) READ_NODE_FIELD(rowMarks); READ_NODE_FIELD(relationOids); READ_NODE_FIELD(invalItems); - READ_INT_FIELD(nParamExec); + READ_NODE_FIELD(paramExecTypes); READ_NODE_FIELD(utilityStmt); READ_LOCATION_FIELD(stmt_location); READ_LOCATION_FIELD(stmt_len); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 9b7a8fd82c4..607f7cd2518 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -243,7 +243,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->rootResultRelations = NIL; glob->relationOids = NIL; glob->invalItems = NIL; - glob->nParamExec = 0; + glob->paramExecTypes = NIL; glob->lastPHId = 0; glob->lastRowMarkId = 0; glob->lastPlanNodeId = 0; @@ -415,7 +415,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) * set_plan_references' tree traversal, but for now it has to be separate * because we need to visit subplans before not after main plan. */ - if (glob->nParamExec > 0) + if (glob->paramExecTypes != NIL) { Assert(list_length(glob->subplans) == list_length(glob->subroots)); forboth(lp, glob->subplans, lr, glob->subroots) @@ -466,7 +466,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->rowMarks = glob->finalrowmarks; result->relationOids = glob->relationOids; result->invalItems = glob->invalItems; - result->nParamExec = glob->nParamExec; + result->paramExecTypes = glob->paramExecTypes; /* utilityStmt should be null, but we might as well copy it */ result->utilityStmt = parse->utilityStmt; result->stmt_location = parse->stmt_location; diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 8f75fa98edc..2e3abeea3d0 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -131,7 +131,9 @@ assign_param_for_var(PlannerInfo *root, Var *var) pitem = makeNode(PlannerParamItem); pitem->item = (Node *) var; - pitem->paramId = root->glob->nParamExec++; + pitem->paramId = list_length(root->glob->paramExecTypes); + root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, + var->vartype); root->plan_params = lappend(root->plan_params, pitem); @@ -234,7 +236,9 @@ assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) pitem = makeNode(PlannerParamItem); pitem->item = (Node *) phv; - pitem->paramId = root->glob->nParamExec++; + pitem->paramId = list_length(root->glob->paramExecTypes); + root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, + exprType((Node *) phv->phexpr)); root->plan_params = lappend(root->plan_params, pitem); @@ -323,7 +327,9 @@ replace_outer_agg(PlannerInfo *root, Aggref *agg) pitem = makeNode(PlannerParamItem); pitem->item = (Node *) agg; - pitem->paramId = root->glob->nParamExec++; + pitem->paramId = list_length(root->glob->paramExecTypes); + root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, + agg->aggtype); root->plan_params = lappend(root->plan_params, pitem); @@ -348,6 +354,7 @@ replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp) Param *retval; PlannerParamItem *pitem; Index levelsup; + Oid ptype; Assert(grp->agglevelsup > 0 && grp->agglevelsup < root->query_level); @@ -362,17 +369,20 @@ replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp) grp = copyObject(grp); IncrementVarSublevelsUp((Node *) grp, -((int) grp->agglevelsup), 0); Assert(grp->agglevelsup == 0); + ptype = exprType((Node *) grp); pitem = makeNode(PlannerParamItem); pitem->item = (Node *) grp; - pitem->paramId = root->glob->nParamExec++; + pitem->paramId = list_length(root->glob->paramExecTypes); + root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, + ptype); root->plan_params = lappend(root->plan_params, pitem); retval = makeNode(Param); retval->paramkind = PARAM_EXEC; retval->paramid = pitem->paramId; - retval->paramtype = exprType((Node *) grp); + retval->paramtype = ptype; retval->paramtypmod = -1; retval->paramcollid = InvalidOid; retval->location = grp->location; @@ -385,7 +395,8 @@ replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp) * * This is used to create Params representing subplan outputs. * We don't need to build a PlannerParamItem for such a Param, but we do - * need to record the PARAM_EXEC slot number as being allocated. + * need to make sure we record the type in paramExecTypes (otherwise, + * there won't be a slot allocated for it). */ static Param * generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, @@ -395,7 +406,9 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, retval = makeNode(Param); retval->paramkind = PARAM_EXEC; - retval->paramid = root->glob->nParamExec++; + retval->paramid = list_length(root->glob->paramExecTypes); + root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, + paramtype); retval->paramtype = paramtype; retval->paramtypmod = paramtypmod; retval->paramcollid = paramcollation; @@ -415,7 +428,11 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod, int SS_assign_special_param(PlannerInfo *root) { - return root->glob->nParamExec++; + int paramId = list_length(root->glob->paramExecTypes); + + root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes, + InvalidOid); + return paramId; } /* @@ -2098,7 +2115,7 @@ SS_identify_outer_params(PlannerInfo *root) * If no parameters have been assigned anywhere in the tree, we certainly * don't need to do anything here. */ - if (root->glob->nParamExec == 0) + if (root->glob->paramExecTypes == NIL) return; /* diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 30cdd3da4c5..66e098f488a 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1095,7 +1095,7 @@ is_parallel_safe(PlannerInfo *root, Node *node) * in this expression. But otherwise we don't need to look. */ if (root->glob->maxParallelHazard == PROPARALLEL_SAFE && - root->glob->nParamExec == 0) + root->glob->paramExecTypes == NIL) return true; /* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */ context.max_hazard = PROPARALLEL_SAFE; diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index dd74efa9a41..a127682b0e7 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -89,7 +89,7 @@ typedef struct PlannedStmt List *invalItems; /* other dependencies, as PlanInvalItems */ - int nParamExec; /* number of PARAM_EXEC Params used */ + List *paramExecTypes; /* type OIDs for PARAM_EXEC Params */ Node *utilityStmt; /* non-null if this is utility stmt */ diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 05fc9a3f485..9e68e65cc63 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -114,7 +114,7 @@ typedef struct PlannerGlobal List *invalItems; /* other dependencies, as PlanInvalItems */ - int nParamExec; /* number of PARAM_EXEC Params used */ + List *paramExecTypes; /* type OIDs for PARAM_EXEC Params */ Index lastPHId; /* highest PlaceHolderVar ID assigned */ @@ -2219,8 +2219,8 @@ typedef struct MinMaxAggInfo * from subplans (values that are setParam items for those subplans). These * IDs need not be tracked via PlannerParamItems, since we do not need any * duplicate-elimination nor later processing of the represented expressions. - * Instead, we just record the assignment of the slot number by incrementing - * root->glob->nParamExec. + * Instead, we just record the assignment of the slot number by appending to + * root->glob->paramExecTypes. */ typedef struct PlannerParamItem {