/* ---------------------------------------------------------------- * CteScanNext * * This is a workhorse for ExecCteScan * ---------------------------------------------------------------- */ static TupleTableSlot * CteScanNext(CteScanState *node) { EState *estate; ScanDirection dir; bool forward; Tuplestorestate *tuplestorestate; bool eof_tuplestore; TupleTableSlot *slot; /* * get state info from node */ estate = node->ss.ps.state; dir = estate->es_direction; forward = ScanDirectionIsForward(dir); tuplestorestate = node->leader->cte_table; tuplestore_select_read_pointer(tuplestorestate, node->readptr); slot = node->ss.ss_ScanTupleSlot; /* * If we are not at the end of the tuplestore, or are going backwards, try * to fetch a tuple from tuplestore. */ eof_tuplestore = tuplestore_ateof(tuplestorestate); if (!forward && eof_tuplestore) { if (!node->leader->eof_cte) { /* * When reversing direction at tuplestore EOF, the first * gettupleslot call will fetch the last-added tuple; but we want * to return the one before that, if possible. So do an extra * fetch. */ if (!tuplestore_advance(tuplestorestate, forward)) return NULL; /* the tuplestore must be empty */ } eof_tuplestore = false; } /* * If we can fetch another tuple from the tuplestore, return it. * * Note: we have to use copy=true in the tuplestore_gettupleslot call, * because we are sharing the tuplestore with other nodes that might write * into the tuplestore before we get called again. */ if (!eof_tuplestore) { if (tuplestore_gettupleslot(tuplestorestate, forward, true, slot)) return slot; if (forward) eof_tuplestore = true; } /* * If necessary, try to fetch another row from the CTE query. * * Note: the eof_cte state variable exists to short-circuit further calls * of the CTE plan. It's not optional, unfortunately, because some plan * node types are not robust about being called again when they've already * returned NULL. */ if (eof_tuplestore && !node->leader->eof_cte) { TupleTableSlot *cteslot; /* * We can only get here with forward==true, so no need to worry about * which direction the subplan will go. */ cteslot = ExecProcNode(node->cteplanstate); if (TupIsNull(cteslot)) { node->leader->eof_cte = true; return NULL; } /* * There are corner cases where the subplan could change which * tuplestore read pointer is active, so be sure to reselect ours * before storing the tuple we got. */ tuplestore_select_read_pointer(tuplestorestate, node->readptr); /* * Append a copy of the returned tuple to tuplestore. NOTE: because * our read pointer is certainly in EOF state, its read position will * move forward over the added tuple. This is what we want. Also, * any other readers will *not* move past the new tuple, which is what * they want. */ tuplestore_puttupleslot(tuplestorestate, cteslot); /* * We MUST copy the CTE query's output tuple into our own slot. This * is because other CteScan nodes might advance the CTE query before * we are called again, and our output tuple must stay stable over * that. */ return ExecCopySlot(slot, cteslot); } /* * Nothing left ... */ return ExecClearTuple(slot); }
/* ---------------------------------------------------------------- * ExecMaterial * * As long as we are at the end of the data collected in the tuplestore, * we collect one new row from the subplan on each call, and stash it * aside in the tuplestore before returning it. The tuplestore is * only read if we are asked to scan backwards, rescan, or mark/restore. * * ---------------------------------------------------------------- */ TupleTableSlot * /* result tuple from subplan */ ExecMaterial(MaterialState *node) { EState *estate; ScanDirection dir; bool forward; Tuplestorestate *tuplestorestate; HeapTuple heapTuple = NULL; bool should_free = false; bool eof_tuplestore; TupleTableSlot *slot; /* * get state info from node */ estate = node->ss.ps.state; dir = estate->es_direction; forward = ScanDirectionIsForward(dir); tuplestorestate = (Tuplestorestate *) node->tuplestorestate; /* * If first time through, and we need a tuplestore, initialize it. */ if (tuplestorestate == NULL && node->randomAccess) { tuplestorestate = tuplestore_begin_heap(true, false, work_mem); node->tuplestorestate = (void *) tuplestorestate; } /* * If we are not at the end of the tuplestore, or are going backwards, try * to fetch a tuple from tuplestore. */ eof_tuplestore = (tuplestorestate == NULL) || tuplestore_ateof(tuplestorestate); if (!forward && eof_tuplestore) { if (!node->eof_underlying) { /* * When reversing direction at tuplestore EOF, the first * getheaptuple call will fetch the last-added tuple; but we want * to return the one before that, if possible. So do an extra * fetch. */ heapTuple = tuplestore_getheaptuple(tuplestorestate, forward, &should_free); if (heapTuple == NULL) return NULL; /* the tuplestore must be empty */ if (should_free) heap_freetuple(heapTuple); } eof_tuplestore = false; } if (!eof_tuplestore) { heapTuple = tuplestore_getheaptuple(tuplestorestate, forward, &should_free); if (heapTuple == NULL && forward) eof_tuplestore = true; } /* * If necessary, try to fetch another row from the subplan. * * Note: the eof_underlying state variable exists to short-circuit further * subplan calls. It's not optional, unfortunately, because some plan * node types are not robust about being called again when they've already * returned NULL. */ if (eof_tuplestore && !node->eof_underlying) { PlanState *outerNode; TupleTableSlot *outerslot; /* * We can only get here with forward==true, so no need to worry about * which direction the subplan will go. */ outerNode = outerPlanState(node); outerslot = ExecProcNode(outerNode); if (TupIsNull(outerslot)) { node->eof_underlying = true; return NULL; } heapTuple = ExecFetchSlotTuple(outerslot); should_free = false; /* * Append returned tuple to tuplestore, too. NOTE: because the * tuplestore is certainly in EOF state, its read position will move * forward over the added tuple. This is what we want. */ if (tuplestorestate) tuplestore_puttuple(tuplestorestate, (void *) heapTuple); } /* * Return the obtained tuple, if any. */ slot = (TupleTableSlot *) node->ss.ps.ps_ResultTupleSlot; if (heapTuple) return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free); else return ExecClearTuple(slot); }
/* ---------------------------------------------------------------- * ExecMaterial * * As long as we are at the end of the data collected in the tuplestore, * we collect one new row from the subplan on each call, and stash it * aside in the tuplestore before returning it. The tuplestore is * only read if we are asked to scan backwards, rescan, or mark/restore. * * ---------------------------------------------------------------- */ TupleTableSlot * /* result tuple from subplan */ ExecMaterial(MaterialState *node) { EState *estate; ScanDirection dir; bool forward; Tuplestorestate *tuplestorestate; bool eof_tuplestore; TupleTableSlot *slot; /* * get state info from node */ estate = node->ss.ps.state; dir = estate->es_direction; forward = ScanDirectionIsForward(dir); tuplestorestate = node->tuplestorestate; /* * If first time through, and we need a tuplestore, initialize it. */ if (tuplestorestate == NULL && node->eflags != 0) { tuplestorestate = tuplestore_begin_heap(true, false, work_mem); tuplestore_set_eflags(tuplestorestate, node->eflags); if (node->eflags & EXEC_FLAG_MARK) { /* * Allocate a second read pointer to serve as the mark. We know it * must have index 1, so needn't store that. */ int ptrno PG_USED_FOR_ASSERTS_ONLY; ptrno = tuplestore_alloc_read_pointer(tuplestorestate, node->eflags); Assert(ptrno == 1); } node->tuplestorestate = tuplestorestate; } /* * If we are not at the end of the tuplestore, or are going backwards, try * to fetch a tuple from tuplestore. */ eof_tuplestore = (tuplestorestate == NULL) || tuplestore_ateof(tuplestorestate); if (!forward && eof_tuplestore) { if (!node->eof_underlying) { /* * When reversing direction at tuplestore EOF, the first * gettupleslot call will fetch the last-added tuple; but we want * to return the one before that, if possible. So do an extra * fetch. */ if (!tuplestore_advance(tuplestorestate, forward)) return NULL; /* the tuplestore must be empty */ } eof_tuplestore = false; } /* * If we can fetch another tuple from the tuplestore, return it. */ slot = node->ss.ps.ps_ResultTupleSlot; if (!eof_tuplestore) { if (tuplestore_gettupleslot(tuplestorestate, forward, false, slot)) return slot; if (forward) eof_tuplestore = true; } /* * If necessary, try to fetch another row from the subplan. * * Note: the eof_underlying state variable exists to short-circuit further * subplan calls. It's not optional, unfortunately, because some plan * node types are not robust about being called again when they've already * returned NULL. */ if (eof_tuplestore && !node->eof_underlying) { PlanState *outerNode; TupleTableSlot *outerslot; /* * We can only get here with forward==true, so no need to worry about * which direction the subplan will go. */ outerNode = outerPlanState(node); outerslot = ExecProcNode(outerNode); if (TupIsNull(outerslot)) { node->eof_underlying = true; return NULL; } /* * Append a copy of the returned tuple to tuplestore. NOTE: because * the tuplestore is certainly in EOF state, its read position will * move forward over the added tuple. This is what we want. */ if (tuplestorestate) tuplestore_puttupleslot(tuplestorestate, outerslot); /* * We can just return the subplan's returned tuple, without copying. */ return outerslot; } /* * Nothing left ... */ return ExecClearTuple(slot); }