Track in the plan the types associated with PARAM_EXEC parameters.
authorRobert Haas <rhaas@postgresql.org>
Mon, 13 Nov 2017 20:24:12 +0000 (15:24 -0500)
committerRobert Haas <rhaas@postgresql.org>
Mon, 13 Nov 2017 20:24:12 +0000 (15:24 -0500)
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
src/backend/executor/execParallel.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/util/clauses.c
src/include/nodes/plannodes.h
src/include/nodes/relation.h

index 493ff82775fde41df9a39984ff23e097d629c22a..47f21316429543cd73300cff4adf1bc698b558f2 100644 (file)
@@ -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)
index 1b477baecb89e1b891ffca4287f94596292b135e..fd7e7cbf3d3516412aeea3906eeaa79176ea87a6 100644 (file)
@@ -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;
index cadd253ef17ea23834a47d3f01be7e676494e4ab..76e75459b46a781aa423e53baae62391cce29edd 100644 (file)
@@ -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);
index 291d1eeb46f0f9ee4dd450c453575e9d7833b5cf..dc35df9e4fe11a4d26cf92e48a57f9d654424a4e 100644 (file)
@@ -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);
index 42c595dc039d630daef22eee8d935ef1174753dc..593658dd8a8910841bfbe5febf83569cd49ea3e4 100644 (file)
@@ -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);
index 9b7a8fd82c45ce5b9963339c6ec27ba7d5a96532..607f7cd25187ae29999a0658199c201864d76158 100644 (file)
@@ -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;
index 8f75fa98edc560f1f81a223bd920c4cca64f792a..2e3abeea3d0938c4e2a308d25afddfaa7a5bae1b 100644 (file)
@@ -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;
 
        /*
index 30cdd3da4c5268051e6df25b1564c0b2c00a647e..66e098f488a2007b950bbc98d06b956d21ea0369 100644 (file)
@@ -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;
index dd74efa9a4138330c2e10785ba9526b0e43b35c7..a127682b0e7827277f09e571929f7c3423ea0628 100644 (file)
@@ -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 */
 
index 05fc9a3f485c427e5f9b67d3229e3cc0ca2ceda3..9e68e65cc6305c1e3268c1877267cc1b727acb18 100644 (file)
@@ -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
 {