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 = tupdesc->attrs[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; }
/* ---------------- * ExecAssignResultTypeFromTL * ---------------- */ void ExecAssignResultTypeFromTL(plan_state_n *planstate) { bool hasoid; struct tuple* tupDesc; if (ExecContextForcesOids(planstate, &hasoid)) { /* context forces OID choice; hasoid is now set correctly */ } else { /* given free choice, don't leave space for OIDs in result tuples */ hasoid = false; } /* * exec_type_from_tgtlist needs the parse-time representation of the tlist, not a * list of ExprStates. This is good because some plan nodes don't bother * to set up planstate->targetlist ... */ tupDesc = exec_type_from_tgtlist(planstate->plan->targetlist, hasoid); ExecAssignResultType(planstate, tupDesc); }
/* ---------------------------------------------------------------- * ExecInitGather * ---------------------------------------------------------------- */ GatherState * ExecInitGather(Gather *node, EState *estate, int eflags) { GatherState *gatherstate; Plan *outerNode; bool hasoid; TupleDesc tupDesc; /* Gather node doesn't have innerPlan node. */ Assert(innerPlan(node) == NULL); /* * create state structure */ gatherstate = makeNode(GatherState); gatherstate->ps.plan = (Plan *) node; gatherstate->ps.state = estate; gatherstate->need_to_scan_locally = !node->single_copy; /* * Miscellaneous initialization * * create expression context for node */ ExecAssignExprContext(estate, &gatherstate->ps); /* * initialize child expressions */ gatherstate->ps.targetlist = (List *) ExecInitExpr((Expr *) node->plan.targetlist, (PlanState *) gatherstate); gatherstate->ps.qual = (List *) ExecInitExpr((Expr *) node->plan.qual, (PlanState *) gatherstate); /* * tuple table initialization */ gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate); ExecInitResultTupleSlot(estate, &gatherstate->ps); /* * now initialize outer plan */ outerNode = outerPlan(node); outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); gatherstate->ps.ps_TupFromTlist = false; /* * 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(&gatherstate->ps, &hasoid)) hasoid = false; tupDesc = ExecTypeFromTL(outerNode->targetlist, hasoid); ExecSetSlotDescriptor(gatherstate->funnel_slot, tupDesc); return gatherstate; }
/* ------------------------------------------------------------------ * ExecInitShareInputScan * ------------------------------------------------------------------ */ ShareInputScanState * ExecInitShareInputScan(ShareInputScan *node, EState *estate, int eflags) { ShareInputScanState *sisstate; Plan *outerPlan; TupleDesc tupDesc; Assert(innerPlan(node) == NULL); /* create state data structure */ sisstate = makeNode(ShareInputScanState); sisstate->ss.ps.plan = (Plan *) node; sisstate->ss.ps.state = estate; sisstate->ts_state = NULL; sisstate->ts_pos = NULL; sisstate->ts_markpos = NULL; sisstate->share_lk_ctxt = NULL; sisstate->freed = false; /* * init child node. * if outerPlan is NULL, this is no-op (so that the ShareInput node will be * only init-ed once). */ outerPlan = outerPlan(node); outerPlanState(sisstate) = ExecInitNode(outerPlan, estate, eflags); sisstate->ss.ps.targetlist = (List *) ExecInitExpr((Expr *) node->plan.targetlist, (PlanState *) sisstate); Assert(node->plan.qual == NULL); sisstate->ss.ps.qual = NULL; /* Misc initialization * * Create expression context */ ExecAssignExprContext(estate, &sisstate->ss.ps); /* tuple table init */ ExecInitResultTupleSlot(estate, &sisstate->ss.ps); sisstate->ss.ss_ScanTupleSlot = ExecInitExtraTupleSlot(estate); /* * init tuple type. */ ExecAssignResultTypeFromTL(&sisstate->ss.ps); { bool hasoid; if (!ExecContextForcesOids(&sisstate->ss.ps, &hasoid)) hasoid = false; tupDesc = ExecTypeFromTL(node->plan.targetlist, hasoid); } ExecAssignScanType(&sisstate->ss, tupDesc); sisstate->ss.ps.ps_ProjInfo = NULL; /* * If this is an intra-slice share node, increment reference count to * tell the underlying node not to be freed before this node is ready to * be freed. fCreate flag to ExecGetShareNodeEntry is true because * at this point we don't have the entry which will be initialized in * the underlying node initialization later. */ if (node->share_type == SHARE_MATERIAL || node->share_type == SHARE_SORT) { ShareNodeEntry *snEntry = ExecGetShareNodeEntry(estate, node->share_id, true); snEntry->refcount++; } initGpmonPktForShareInputScan((Plan *)node, &sisstate->ss.ps.gpmon_pkt, estate); return sisstate; }
/* ---------------------------------------------------------------- * ExecInitGather * ---------------------------------------------------------------- */ GatherState * ExecInitGather(Gather *node, EState *estate, int eflags) { GatherState *gatherstate; Plan *outerNode; bool hasoid; TupleDesc tupDesc; /* Gather node doesn't have innerPlan node. */ Assert(innerPlan(node) == NULL); /* * create state structure */ gatherstate = makeNode(GatherState); gatherstate->ps.plan = (Plan *) node; gatherstate->ps.state = estate; gatherstate->ps.ExecProcNode = ExecGather; gatherstate->initialized = false; gatherstate->need_to_scan_locally = !node->single_copy && parallel_leader_participation; gatherstate->tuples_needed = -1; /* * Miscellaneous initialization * * create expression context for node */ ExecAssignExprContext(estate, &gatherstate->ps); /* * Gather doesn't support checking a qual (it's always more efficient to * do it in the child node). */ Assert(!node->plan.qual); /* * tuple table initialization */ gatherstate->funnel_slot = ExecInitExtraTupleSlot(estate); ExecInitResultTupleSlot(estate, &gatherstate->ps); /* * now initialize outer plan */ outerNode = outerPlan(node); outerPlanState(gatherstate) = ExecInitNode(outerNode, estate, eflags); /* * Initialize funnel slot to same tuple descriptor as outer plan. */ if (!ExecContextForcesOids(outerPlanState(gatherstate), &hasoid)) hasoid = false; 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; }
/* ---------------------------------------------------------------- * ExecInitGather * ---------------------------------------------------------------- */ GatherMergeState * ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags) { GatherMergeState *gm_state; Plan *outerNode; bool hasoid; TupleDesc tupDesc; /* Gather merge node doesn't have innerPlan node. */ Assert(innerPlan(node) == NULL); /* * create state structure */ gm_state = makeNode(GatherMergeState); gm_state->ps.plan = (Plan *) node; gm_state->ps.state = estate; gm_state->ps.ExecProcNode = ExecGatherMerge; /* * Miscellaneous initialization * * create expression context for node */ ExecAssignExprContext(estate, &gm_state->ps); /* * initialize child expressions */ gm_state->ps.qual = ExecInitQual(node->plan.qual, &gm_state->ps); /* * tuple table initialization */ ExecInitResultTupleSlot(estate, &gm_state->ps); /* * now initialize outer plan */ outerNode = outerPlan(node); outerPlanState(gm_state) = ExecInitNode(outerNode, estate, eflags); /* * Initialize result tuple type and projection info. */ ExecAssignResultTypeFromTL(&gm_state->ps); ExecAssignProjectionInfo(&gm_state->ps, NULL); gm_state->gm_initialized = false; /* * initialize sort-key information */ if (node->numCols) { int i; gm_state->gm_nkeys = node->numCols; gm_state->gm_sortkeys = palloc0(sizeof(SortSupportData) * node->numCols); for (i = 0; i < node->numCols; i++) { SortSupport sortKey = gm_state->gm_sortkeys + i; sortKey->ssup_cxt = CurrentMemoryContext; sortKey->ssup_collation = node->collations[i]; sortKey->ssup_nulls_first = node->nullsFirst[i]; sortKey->ssup_attno = node->sortColIdx[i]; /* * We don't perform abbreviated key conversion here, for the same * reasons that it isn't used in MergeAppend */ sortKey->abbreviate = false; PrepareSortSupportFromOrderingOp(node->sortOperators[i], sortKey); } } /* * store the tuple descriptor into gather merge state, so we can use it * later while initializing the gather merge slots. */ if (!ExecContextForcesOids(&gm_state->ps, &hasoid)) hasoid = false; tupDesc = ExecTypeFromTL(outerNode->targetlist, hasoid); gm_state->tupDesc = tupDesc; return gm_state; }