void ExecReScanAppend(AppendState *node, ExprContext *exprCtxt) { int i; for (i = node->as_firstplan; i <= node->as_lastplan; i++) { PlanState *subnode = node->appendplans[i]; /* * ExecReScan doesn't know about my subplans, so I have to do * changed-parameter signaling myself. */ if (node->ps.chgParam != NULL) UpdateChangedParamSet(subnode, node->ps.chgParam); /* * if chgParam of subnode is not null then plan will be re-scanned * by first ExecProcNode. */ if (subnode->chgParam == NULL) { /* make sure estate is correct for this subnode (needed??) */ node->as_whichplan = i; exec_append_initialize_next(node); ExecReScan(subnode, exprCtxt); } } node->as_whichplan = node->as_firstplan; exec_append_initialize_next(node); }
void ExecReScanAppend(AppendState *node, ExprContext *exprCtxt) { int i; for (i = node->as_firstplan; i <= node->as_lastplan; i++) { PlanState *subnode = node->appendplans[i]; /* * ExecReScan doesn't know about my subplans, so I have to do * changed-parameter signaling myself. */ if (node->ps.chgParam != NULL) UpdateChangedParamSet(subnode, node->ps.chgParam); /* * If chgParam of subnode is not null then plan will be re-scanned by * first ExecProcNode. However, if caller is passing us an exprCtxt * then forcibly rescan all the subnodes now, so that we can pass the * exprCtxt down to the subnodes (needed for appendrel indexscan). */ if (subnode->chgParam == NULL || exprCtxt != NULL) { /* make sure estate is correct for this subnode (needed??) */ node->as_whichplan = i; exec_append_initialize_next(node); ExecReScan(subnode, exprCtxt); } } node->as_whichplan = node->as_firstplan; exec_append_initialize_next(node); }
/* ---------------------------------------------------------------- * ExecAppend * * Handles iteration over multiple subplans. * ---------------------------------------------------------------- */ TupleTableSlot * ExecAppend(AppendState *node) { for (;;) { PlanState *subnode; TupleTableSlot *result; /* * figure out which subplan we are currently processing */ subnode = node->appendplans[node->as_whichplan]; /* * get a tuple from the subplan */ result = ExecProcNode(subnode); if (!TupIsNull(result)) { /* * If the subplan gave us something then return it as-is. We do * NOT make use of the result slot that was set up in * ExecInitAppend, first because there's no reason to and second * because it may have the wrong tuple descriptor in * inherited-UPDATE cases. */ return result; } /* * Go on to the "next" subplan in the appropriate direction. If no * more subplans, return the empty slot set up for us by * ExecInitAppend. */ if (ScanDirectionIsForward(node->ps.state->es_direction)) node->as_whichplan++; else node->as_whichplan--; if (!exec_append_initialize_next(node)) return ExecClearTuple(node->ps.ps_ResultTupleSlot); /* Else loop back and try to get a tuple from the new subplan */ } }
/* ---------------------------------------------------------------- * ExecProcAppend * * Handles the iteration over the multiple scans. * * NOTE: Can't call this ExecAppend, that name is used in execMain. * ---------------------------------------------------------------- */ TupleTableSlot * ExecProcAppend(AppendState *node) { EState *estate; int whichplan; PlanState *subnode; TupleTableSlot *result; TupleTableSlot *result_slot; ScanDirection direction; /* * get information from the node */ estate = node->ps.state; direction = estate->es_direction; whichplan = node->as_whichplan; result_slot = node->ps.ps_ResultTupleSlot; /* * figure out which subplan we are currently processing */ subnode = node->appendplans[whichplan]; /* * get a tuple from the subplan */ result = ExecProcNode(subnode); if (!TupIsNull(result)) { /* * if the subplan gave us something then place a copy of whatever * we get into our result slot and return it. * * Note we rely on the subplan to retain ownership of the tuple for * as long as we need it --- we don't copy it. */ return ExecStoreTuple(result->val, result_slot, InvalidBuffer, false); } else { /* * .. go on to the "next" subplan in the appropriate direction and * try processing again (recursively) */ if (ScanDirectionIsForward(direction)) node->as_whichplan++; else node->as_whichplan--; /* * return something from next node or an empty slot if all of our * subplans have been exhausted. */ if (exec_append_initialize_next(node)) { ExecSetSlotDescriptorIsNew(result_slot, true); return ExecProcAppend(node); } else return ExecClearTuple(result_slot); } }
/* ---------------------------------------------------------------- * ExecInitAppend * * Begin all of the subscans of the append node. * * (This is potentially wasteful, since the entire result of the * append node may not be scanned, but this way all of the * structures get allocated in the executor's top level memory * block instead of that of the call to ExecProcAppend.) * * Special case: during an EvalPlanQual recheck query of an inherited * target relation, we only want to initialize and scan the single * subplan that corresponds to the target relation being checked. * ---------------------------------------------------------------- */ AppendState * ExecInitAppend(Append *node, EState *estate) { AppendState *appendstate = makeNode(AppendState); PlanState **appendplanstates; int nplans; int i; Plan *initNode; CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext); /* * Set up empty vector of subplan states */ nplans = length(node->appendplans); appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *)); /* * create new AppendState for our append node */ appendstate->ps.plan = (Plan *) node; appendstate->ps.state = estate; appendstate->appendplans = appendplanstates; appendstate->as_nplans = nplans; /* * Do we want to scan just one subplan? (Special case for * EvalPlanQual) XXX pretty dirty way of determining that this case * applies ... */ if (node->isTarget && estate->es_evTuple != NULL) { int tplan; tplan = estate->es_result_relation_info - estate->es_result_relations; Assert(tplan >= 0 && tplan < nplans); appendstate->as_firstplan = tplan; appendstate->as_lastplan = tplan; } else { /* normal case, scan all subplans */ appendstate->as_firstplan = 0; appendstate->as_lastplan = nplans - 1; } /* * Miscellaneous initialization * * Append plans don't have expression contexts because they never call * ExecQual or ExecProject. */ #define APPEND_NSLOTS 1 /* * append nodes still have Result slots, which hold pointers to * tuples, so we have to initialize them. */ ExecInitResultTupleSlot(estate, &appendstate->ps); /* * call ExecInitNode on each of the plans to be executed and save the * results into the array "appendplans". Note we *must* set * estate->es_result_relation_info correctly while we initialize each * sub-plan; ExecContextForcesOids depends on that! */ for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++) { appendstate->as_whichplan = i; exec_append_initialize_next(appendstate); initNode = (Plan *) nth(i, node->appendplans); appendplanstates[i] = ExecInitNode(initNode, estate); } /* * initialize tuple type */ ExecAssignResultTypeFromTL(&appendstate->ps); appendstate->ps.ps_ProjInfo = NULL; /* * return the result from the first subplan's initialization */ appendstate->as_whichplan = appendstate->as_firstplan; exec_append_initialize_next(appendstate); return appendstate; }
/* ---------------------------------------------------------------- * ExecInitAppend * * Begin all of the subscans of the append node. * * (This is potentially wasteful, since the entire result of the * append node may not be scanned, but this way all of the * structures get allocated in the executor's top level memory * block instead of that of the call to ExecAppend.) * * Special case: during an EvalPlanQual recheck query of an inherited * target relation, we only want to initialize and scan the single * subplan that corresponds to the target relation being checked. * ---------------------------------------------------------------- */ AppendState * ExecInitAppend(Append *node, EState *estate, int eflags) { AppendState *appendstate = makeNode(AppendState); PlanState **appendplanstates; int nplans; int i; Plan *initNode; /* check for unsupported flags */ Assert(!(eflags & EXEC_FLAG_MARK)); /* * Set up empty vector of subplan states */ nplans = list_length(node->appendplans); appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *)); /* * create new AppendState for our append node */ appendstate->ps.plan = (Plan *) node; appendstate->ps.state = estate; appendstate->appendplans = appendplanstates; appendstate->as_nplans = nplans; /* * Do we want to scan just one subplan? (Special case for EvalPlanQual) * XXX pretty dirty way of determining that this case applies ... */ if (node->isTarget && estate->es_evTuple != NULL) { int tplan; tplan = estate->es_result_relation_info - estate->es_result_relations; Assert(tplan >= 0 && tplan < nplans); appendstate->as_firstplan = tplan; appendstate->as_lastplan = tplan; } else { /* normal case, scan all subplans */ appendstate->as_firstplan = 0; appendstate->as_lastplan = nplans - 1; } /* * Miscellaneous initialization * * Append plans don't have expression contexts because they never call * ExecQual or ExecProject. */ #define APPEND_NSLOTS 1 /* * append nodes still have Result slots, which hold pointers to tuples, so * we have to initialize them. */ ExecInitResultTupleSlot(estate, &appendstate->ps); /* * call ExecInitNode on each of the plans to be executed and save the * results into the array "appendplans". Note we *must* set * estate->es_result_relation_info correctly while we initialize each * sub-plan; ExecContextForcesOids depends on that! */ for (i = appendstate->as_firstplan; i <= appendstate->as_lastplan; i++) { appendstate->as_whichplan = i; exec_append_initialize_next(appendstate); initNode = (Plan *) list_nth(node->appendplans, i); appendplanstates[i] = ExecInitNode(initNode, estate, eflags); } /* * Initialize tuple type. (Note: in an inherited UPDATE situation, the * tuple type computed here corresponds to the parent table, which is * really a lie since tuples returned from child subplans will not all * look the same.) */ ExecAssignResultTypeFromTL(&appendstate->ps); appendstate->ps.ps_ProjInfo = NULL; /* * return the result from the first subplan's initialization */ appendstate->as_whichplan = appendstate->as_firstplan; exec_append_initialize_next(appendstate); return appendstate; }