diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/executor/execScan.c | 75 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 80 | ||||
-rw-r--r-- | src/backend/executor/nodeGather.c | 16 | ||||
-rw-r--r-- | src/backend/executor/nodeGatherMerge.c | 24 | ||||
-rw-r--r-- | src/include/executor/executor.h | 2 |
5 files changed, 110 insertions, 87 deletions
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index 5dfc49deb95..837abc0f017 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -23,8 +23,6 @@ #include "utils/memutils.h" -static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc); - /* * ExecScanFetch -- check interrupts & fetch next potential tuple @@ -237,8 +235,9 @@ void ExecAssignScanProjectionInfo(ScanState *node) { Scan *scan = (Scan *) node->ps.plan; + TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; - ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid); + ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, scan->scanrelid); } /* @@ -248,75 +247,9 @@ ExecAssignScanProjectionInfo(ScanState *node) void ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno) { - Scan *scan = (Scan *) node->ps.plan; - - if (tlist_matches_tupdesc(&node->ps, - scan->plan.targetlist, - varno, - node->ss_ScanTupleSlot->tts_tupleDescriptor)) - node->ps.ps_ProjInfo = NULL; - else - ExecAssignProjectionInfo(&node->ps, - node->ss_ScanTupleSlot->tts_tupleDescriptor); -} - -static bool -tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc) -{ - int numattrs = tupdesc->natts; - int attrno; - bool hasoid; - ListCell *tlist_item = list_head(tlist); - - /* Check the tlist attributes */ - for (attrno = 1; attrno <= numattrs; attrno++) - { - Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1); - Var *var; - - if (tlist_item == NULL) - return false; /* tlist too short */ - var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr; - if (!var || !IsA(var, Var)) - return false; /* tlist item not a Var */ - /* if these Asserts fail, planner messed up */ - Assert(var->varno == varno); - Assert(var->varlevelsup == 0); - if (var->varattno != attrno) - return false; /* out of order */ - if (att_tup->attisdropped) - return false; /* table contains dropped columns */ - - /* - * Note: usually the Var's type should match the tupdesc exactly, but - * in situations involving unions of columns that have different - * typmods, the Var may have come from above the union and hence have - * typmod -1. This is a legitimate situation since the Var still - * describes the column, just not as exactly as the tupdesc does. We - * could change the planner to prevent it, but it'd then insert - * projection steps just to convert from specific typmod to typmod -1, - * which is pretty silly. - */ - if (var->vartype != att_tup->atttypid || - (var->vartypmod != att_tup->atttypmod && - var->vartypmod != -1)) - return false; /* type mismatch */ - - tlist_item = lnext(tlist_item); - } - - if (tlist_item) - return false; /* tlist too long */ - - /* - * If the plan context requires a particular hasoid setting, then that has - * to match, too. - */ - if (ExecContextForcesOids(ps, &hasoid) && - hasoid != tupdesc->tdhasoid) - return false; + TupleDesc tupdesc = node->ss_ScanTupleSlot->tts_tupleDescriptor; - return true; + ExecConditionalAssignProjectionInfo(&node->ps, tupdesc, varno); } /* diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index e8c06c76056..876439835a3 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -56,6 +56,7 @@ #include "utils/typcache.h" +static bool tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc); static void ShutdownExprContext(ExprContext *econtext, bool isCommit); @@ -504,6 +505,85 @@ ExecAssignProjectionInfo(PlanState *planstate, /* ---------------- + * ExecConditionalAssignProjectionInfo + * + * as ExecAssignProjectionInfo, but store NULL rather than building projection + * info if no projection is required + * ---------------- + */ +void +ExecConditionalAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc, + Index varno) +{ + if (tlist_matches_tupdesc(planstate, + planstate->plan->targetlist, + varno, + inputDesc)) + planstate->ps_ProjInfo = NULL; + else + ExecAssignProjectionInfo(planstate, inputDesc); +} + +static bool +tlist_matches_tupdesc(PlanState *ps, List *tlist, Index varno, TupleDesc tupdesc) +{ + int numattrs = tupdesc->natts; + int attrno; + bool hasoid; + ListCell *tlist_item = list_head(tlist); + + /* Check the tlist attributes */ + for (attrno = 1; attrno <= numattrs; attrno++) + { + Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1); + Var *var; + + if (tlist_item == NULL) + return false; /* tlist too short */ + var = (Var *) ((TargetEntry *) lfirst(tlist_item))->expr; + if (!var || !IsA(var, Var)) + return false; /* tlist item not a Var */ + /* if these Asserts fail, planner messed up */ + Assert(var->varno == varno); + Assert(var->varlevelsup == 0); + if (var->varattno != attrno) + return false; /* out of order */ + if (att_tup->attisdropped) + return false; /* table contains dropped columns */ + + /* + * Note: usually the Var's type should match the tupdesc exactly, but + * in situations involving unions of columns that have different + * typmods, the Var may have come from above the union and hence have + * typmod -1. This is a legitimate situation since the Var still + * describes the column, just not as exactly as the tupdesc does. We + * could change the planner to prevent it, but it'd then insert + * projection steps just to convert from specific typmod to typmod -1, + * which is pretty silly. + */ + if (var->vartype != att_tup->atttypid || + (var->vartypmod != att_tup->atttypmod && + var->vartypmod != -1)) + return false; /* type mismatch */ + + tlist_item = lnext(tlist_item); + } + + if (tlist_item) + return false; /* tlist too long */ + + /* + * If the plan context requires a particular hasoid setting, then that has + * to match, too. + */ + if (ExecContextForcesOids(ps, &hasoid) && + hasoid != tupdesc->tdhasoid) + return false; + + return true; +} + +/* ---------------- * ExecFreeExprContext * * A plan node's ExprContext should be freed explicitly during executor diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c index 30885e6f5c2..212612b5351 100644 --- a/src/backend/executor/nodeGather.c +++ b/src/backend/executor/nodeGather.c @@ -104,12 +104,6 @@ ExecInitGather(Gather *node, EState *estate, int eflags) outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); /* - * Initialize result tuple type and projection info. - */ - ExecAssignResultTypeFromTL(&gatherstate->ps); - ExecAssignProjectionInfo(&gatherstate->ps, NULL); - - /* * Initialize funnel slot to same tuple descriptor as outer plan. */ if (!ExecContextForcesOids(outerPlanState(gatherstate), &hasoid)) @@ -117,6 +111,12 @@ ExecInitGather(Gather *node, EState *estate, int eflags) tupDesc = ExecTypeFromTL(outerNode->targetlist, hasoid); ExecSetSlotDescriptor(gatherstate->funnel_slot, tupDesc); + /* + * Initialize result tuple type and projection info. + */ + ExecAssignResultTypeFromTL(&gatherstate->ps); + ExecConditionalAssignProjectionInfo(&gatherstate->ps, tupDesc, OUTER_VAR); + return gatherstate; } @@ -221,6 +221,10 @@ ExecGather(PlanState *pstate) if (TupIsNull(slot)) return NULL; + /* If no projection is required, we're done. */ + if (node->ps.ps_ProjInfo == NULL) + return slot; + /* * Form the result tuple using ExecProject(), and return it. */ diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c index d81462e72b4..166f2064ff7 100644 --- a/src/backend/executor/nodeGatherMerge.c +++ b/src/backend/executor/nodeGatherMerge.c @@ -116,10 +116,19 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) outerPlanState(gm_state) = ExecInitNode(outerNode, estate, eflags); /* + * Store the tuple descriptor into gather merge state, so we can use it + * while initializing the gather merge slots. + */ + if (!ExecContextForcesOids(outerPlanState(gm_state), &hasoid)) + hasoid = false; + tupDesc = ExecTypeFromTL(outerNode->targetlist, hasoid); + gm_state->tupDesc = tupDesc; + + /* * Initialize result tuple type and projection info. */ ExecAssignResultTypeFromTL(&gm_state->ps); - ExecAssignProjectionInfo(&gm_state->ps, NULL); + ExecConditionalAssignProjectionInfo(&gm_state->ps, tupDesc, OUTER_VAR); /* * initialize sort-key information @@ -151,15 +160,6 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) } } - /* - * Store the tuple descriptor into gather merge state, so we can use it - * while initializing the gather merge slots. - */ - if (!ExecContextForcesOids(outerPlanState(gm_state), &hasoid)) - hasoid = false; - tupDesc = ExecTypeFromTL(outerNode->targetlist, hasoid); - gm_state->tupDesc = tupDesc; - /* Now allocate the workspace for gather merge */ gather_merge_setup(gm_state); @@ -257,6 +257,10 @@ ExecGatherMerge(PlanState *pstate) if (TupIsNull(slot)) return NULL; + /* If no projection is required, we're done. */ + if (node->ps.ps_ProjInfo == NULL) + return slot; + /* * Form the result tuple using ExecProject(), and return it. */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index bee4ebf2693..b5578f5855f 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -485,6 +485,8 @@ extern void ExecAssignResultTypeFromTL(PlanState *planstate); extern TupleDesc ExecGetResultType(PlanState *planstate); extern void ExecAssignProjectionInfo(PlanState *planstate, TupleDesc inputDesc); +extern void ExecConditionalAssignProjectionInfo(PlanState *planstate, + TupleDesc inputDesc, Index varno); extern void ExecFreeExprContext(PlanState *planstate); extern void ExecAssignScanType(ScanState *scanstate, TupleDesc tupDesc); extern void ExecAssignScanTypeFromOuterPlan(ScanState *scanstate); |