diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/executor/nodeTee.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/executor/nodeTee.c')
-rw-r--r-- | src/backend/executor/nodeTee.c | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/src/backend/executor/nodeTee.c b/src/backend/executor/nodeTee.c new file mode 100644 index 00000000000..5be700b9ae7 --- /dev/null +++ b/src/backend/executor/nodeTee.c @@ -0,0 +1,503 @@ +/*------------------------------------------------------------------------- + * + * nodeTee.c-- + * + * + * Copyright (c) 1994, Regents of the University of California + * + * DESCRIPTION + * This code provides support for a tee node, which allows multiple + * parent in a megaplan. + * + * INTERFACE ROUTINES + * ExecTee + * ExecInitTee + * ExecEndTee + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/executor/Attic/nodeTee.c,v 1.1.1.1 1996/07/09 06:21:27 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + +#include <sys/file.h> +#include "utils/palloc.h" +#include "utils/relcache.h" +#include "storage/bufmgr.h" /* for IncrBufferRefCount */ +#include "optimizer/internal.h" +#include "executor/executor.h" +#include "executor/nodeTee.h" +#include "catalog/catalog.h" +#include "tcop/pquery.h" + +/* ------------------------------------------------------------------ + * ExecInitTee + * + * Create tee state + * + * ------------------------------------------------------------------ + */ +bool +ExecInitTee(Tee* node, EState *currentEstate, Plan * parent) +{ + TeeState *teeState; + Plan *outerPlan; + int len; + Relation bufferRel; + TupleDesc tupType; + EState *estate; + + /* it is possible that the Tee has already been initialized + since it can be reached by multiple parents. + If it is already initialized, simply return and do + not initialize the children nodes again + */ + if (node->plan.state) + return TRUE; + + /* ---------------- + * assign the node's execution state + * ---------------- + */ + /* make a new executor state, because we have a different + es_range_table */ + +/* node->plan.state = estate;*/ + + estate = CreateExecutorState(); + estate->es_direction = currentEstate->es_direction; + estate->es_BaseId = currentEstate->es_BaseId; + estate->es_BaseId = currentEstate->es_BaseId; + estate->es_tupleTable = currentEstate->es_tupleTable; + estate->es_refcount = currentEstate->es_refcount; + estate->es_junkFilter = currentEstate->es_junkFilter; + + /* use the range table for Tee subplan since the range tables + for the two parents may be different */ + if (node->rtentries) + estate->es_range_table = node->rtentries; + else + estate->es_range_table = currentEstate->es_range_table; + + node->plan.state = estate; + + + /* ---------------- + * create teeState structure + * ---------------- + */ + teeState = makeNode(TeeState); + teeState->tee_leftPlace = 0; + teeState->tee_rightPlace = 0; + teeState->tee_lastPlace = 0; + teeState->tee_bufferRel = NULL; + teeState->tee_leftScanDesc = NULL; + teeState->tee_rightScanDesc = NULL; + + + node->teestate = teeState; + + /* ---------------- + * Miscellanious initialization + * + * + assign node's base_id + * + assign debugging hooks and + * + create expression context for node + * ---------------- + */ + ExecAssignNodeBaseInfo(estate, &(teeState->cstate), parent); + ExecAssignExprContext(estate, &(teeState->cstate)); + +#define TEE_NSLOTS 2 + /* ---------------- + * initialize tuple slots + * ---------------- + */ + ExecInitResultTupleSlot(estate, &(teeState->cstate)); + + /* initialize child nodes */ + outerPlan = outerPlan((Plan*) node); + ExecInitNode(outerPlan, estate, (Plan*) node); + + /* ---------------- + * the tuple type info is from the outer plan of this node + * the result type is also the same as the outerplan + */ + ExecAssignResultTypeFromOuterPlan((Plan*) node, &(teeState->cstate)); + ExecAssignProjectionInfo((Plan*)node, &teeState->cstate); + + /* --------------------------------------- + initialize temporary relation to buffer tuples + */ + tupType = ExecGetResultType(&(teeState->cstate)); + len = ExecTargetListLength(((Plan*)node)->targetlist); + +/* bufferRel = ExecCreatR(len, tupType, _TEMP_RELATION_ID_); */ + + /* create a catalogued relation even though this is a temporary relation */ + /* cleanup of catalogued relations is easier to do */ + + if (node->teeTableName[0] != '\0') { + Relation r; + + teeState->tee_bufferRelname = pstrdup(node->teeTableName); + + /* we are given an tee table name, + if a relation by that name exists, then we open it, + else we create it and then open it */ + r = RelationNameGetRelation(teeState->tee_bufferRelname); + + if (RelationIsValid(r)) + bufferRel = heap_openr(teeState->tee_bufferRelname); + else + bufferRel = heap_open(heap_create(teeState->tee_bufferRelname, +/*FIX */ NULL, + 'n', + DEFAULT_SMGR, + tupType)); + } + else { + sprintf(teeState->tee_bufferRelname, + "ttemp_%d", /* 'ttemp' for 'tee' temporary*/ + newoid()); +/* bufferRel = ExecCreatR(len, tupType, _TEMP_RELATION_ID); */ + bufferRel = heap_open(heap_create(teeState->tee_bufferRelname, + NULL, /*XXX */ + 'n', + DEFAULT_SMGR, + tupType)); + } + + teeState->tee_bufferRel = bufferRel; + + /*initialize a memory context for allocating thing like scan descriptors */ + /* we do this so that on cleanup of the tee, we can free things. + if we didn't have our own memory context, we would be in the memory + context of the portal that we happen to be using at the moment */ + + teeState->tee_mcxt = (MemoryContext)CreateGlobalMemory(teeState->tee_bufferRelname); + + /* don't initialize the scan descriptors here + because it's not good to initialize scan descriptors on empty + rels. Wait until the scan descriptors are needed + before initializing them. */ + + teeState->tee_leftScanDesc = NULL; + teeState->tee_rightScanDesc = NULL; + + return TRUE; +} + +int +ExecCountSlotsTee(Tee *node) +{ + /* Tee nodes can't have innerPlans */ + return ExecCountSlotsNode(outerPlan(node)) + TEE_NSLOTS; +} + +/* ---------------------------------------------------------------- + initTeeScanDescs + initializes the left and right scandescs on the temporary + relation of a Tee node + + must open two separate scan descriptors, + because the left and right scans may be at different points +* ---------------------------------------------------------------- +*/ +void +initTeeScanDescs(Tee* node) +{ + TeeState *teeState; + Relation bufferRel; + ScanDirection dir; + MemoryContext orig; + + teeState = node->teestate; + if (teeState->tee_leftScanDesc && teeState->tee_rightScanDesc) + return; + + orig = CurrentMemoryContext; + MemoryContextSwitchTo(teeState->tee_mcxt); + + bufferRel = teeState->tee_bufferRel; + dir = ((Plan*)node)->state->es_direction; /* backwards not handled yet XXX */ + + if (teeState->tee_leftScanDesc == NULL) + { + teeState->tee_leftScanDesc = heap_beginscan(bufferRel, + ScanDirectionIsBackward(dir), + NowTimeQual, /* time qual */ + 0, /* num scan keys */ + NULL /* scan keys */ + ); + } + if (teeState->tee_rightScanDesc == NULL) + { + teeState->tee_rightScanDesc = heap_beginscan(bufferRel, + ScanDirectionIsBackward(dir), + NowTimeQual, /* time qual */ + 0, /* num scan keys */ + NULL /* scan keys */ + ); + } + + MemoryContextSwitchTo(orig); +} + +/* ---------------------------------------------------------------- + * ExecTee(node) + * + * + * A Tee serves to connect a subplan to multiple parents. + * the subplan is always the outplan of the Tee node. + * + * The Tee gets requests from either leftParent or rightParent, + * fetches the result tuple from the child, and then + * stored the result into a temporary relation (serving as a queue). + * leftPlace and rightPlace keep track of where the left and rightParents + * are. + * If a parent requests a tuple and that parent is not at the end + * of the temporary relation, then the request is satisfied from + * the queue instead of by executing the child plan + * + * ---------------------------------------------------------------- + */ + +TupleTableSlot* +ExecTee(Tee *node, Plan *parent) +{ + EState *estate; + TeeState *teeState; + int leftPlace, rightPlace, lastPlace; + int branch; + TupleTableSlot* result; + TupleTableSlot* slot; + Plan *childNode; + ScanDirection dir; + HeapTuple heapTuple; + Relation bufferRel; + HeapScanDesc scanDesc; + Buffer buffer; + + estate = ((Plan*)node)->state; + teeState = node->teestate; + leftPlace = teeState->tee_leftPlace; + rightPlace = teeState->tee_rightPlace; + lastPlace = teeState->tee_lastPlace; + bufferRel = teeState->tee_bufferRel; + + childNode = outerPlan(node); + + dir = estate->es_direction; + + /* XXX doesn't handle backwards direction yet */ + + if (parent == node->leftParent) { + branch = leftPlace; + } + else + if ( (parent == node->rightParent) || (parent == (Plan*) node)) + /* the tee node could be the root node of the plan, + in which case, we treat it like a right-parent pull*/ + { + branch = rightPlace; + } + else + { + elog(WARN,"A Tee node can only be executed from its left or right parent\n"); + return NULL; + } + + if (branch == lastPlace) + { /* we're at the end of the queue already, + - get a new tuple from the child plan, + - store it in the queue, + - increment lastPlace, + - increment leftPlace or rightPlace as appropriate, + - and return result + */ + slot = ExecProcNode(childNode, (Plan*)node); + if (!TupIsNull(slot)) + { + heapTuple = slot->val; + + /* insert into temporary relation */ + heap_insert(bufferRel, heapTuple); + + /* once there is data in the temporary relation, + ensure that the left and right scandescs are initialized */ + initTeeScanDescs(node); + + scanDesc = (parent == node->leftParent) ? + teeState->tee_leftScanDesc : teeState->tee_rightScanDesc; + + { + /* move the scandesc forward so we don't re-read this tuple later */ + HeapTuple throwAway; + /* Buffer buffer;*/ + throwAway = heap_getnext(scanDesc, + ScanDirectionIsBackward(dir), + /* &buffer */ + (Buffer*)NULL); + } + + /* set the shouldFree field of the child's slot so that + when the child's slot is free'd, this tuple isn't free'd also */ + /* does this mean this tuple has to be garbage collected later??*/ + slot->ttc_shouldFree = false; + + teeState->tee_lastPlace = lastPlace + 1; + } + result = slot; + } + else + {/* the desired data already exists in the temporary relation */ + scanDesc = (parent == node->leftParent) ? + teeState->tee_leftScanDesc : teeState->tee_rightScanDesc; + + heapTuple = heap_getnext(scanDesc, + ScanDirectionIsBackward(dir), + &buffer); + + /* Increase the pin count on the buffer page, because the + tuple stored in the slot also points to it (as well as + the scan descriptor). If we don't, ExecStoreTuple will + decrease the pin count on the next iteration. */ + + if (buffer != InvalidBuffer) + IncrBufferRefCount(buffer); + + slot = teeState->cstate.cs_ResultTupleSlot; + slot->ttc_tupleDescriptor = RelationGetTupleDescriptor(bufferRel); + + result = ExecStoreTuple(heapTuple,/* tuple to store */ + slot, /* slot to store in */ + buffer,/* this tuple's buffer */ + false); /* don't free stuff from heap_getnext */ + + } + + if (parent == node->leftParent) + { + teeState->tee_leftPlace = leftPlace+1; + } + else + { + teeState->tee_rightPlace = rightPlace+1; + } + + return result; +} + +/* ---------------------------------------------------------------- + * ExecTeeReScan(node) + * + * Rescans the relation. + * ---------------------------------------------------------------- + */ +void +ExecTeeReScan(Tee *node, ExprContext *exprCtxt, Plan *parent) +{ + + EState *estate; + TeeState *teeState; + ScanDirection dir; + + estate = ((Plan*)node)->state; + teeState = node->teestate; + + dir = estate->es_direction; + + /* XXX doesn't handle backwards direction yet */ + + if (parent == node->leftParent) { + if (teeState->tee_leftScanDesc) + { + heap_rescan(teeState->tee_leftScanDesc, + ScanDirectionIsBackward(dir), + NULL); + teeState->tee_leftPlace = 0; + } + } + else + { + if (teeState->tee_rightScanDesc) + { + heap_rescan(teeState->tee_leftScanDesc, + ScanDirectionIsBackward(dir), + NULL); + teeState->tee_rightPlace = 0; + } + } +} + + +/* --------------------------------------------------------------------- + * ExecEndTee + * + * End the Tee node, and free up any storage + * since a Tee node can be downstream of multiple parent nodes, + * only free when both parents are done + * -------------------------------------------------------------------- + */ + +void +ExecEndTee(Tee* node, Plan* parent) +{ + EState *estate; + TeeState *teeState; + int leftPlace, rightPlace, lastPlace; + Relation bufferRel; + MemoryContext orig; + + estate = ((Plan*)node)->state; + teeState = node->teestate; + leftPlace = teeState->tee_leftPlace; + rightPlace = teeState->tee_rightPlace; + lastPlace = teeState->tee_lastPlace; + + if (!node->leftParent || parent == node->leftParent) + leftPlace = -1; + + if (!node->rightParent || parent == node->rightParent) + rightPlace = -1; + + if (parent == (Plan*)node) + rightPlace = leftPlace = -1; + + teeState->tee_leftPlace = leftPlace; + teeState->tee_rightPlace = rightPlace; + if ( (leftPlace == -1) && (rightPlace == -1) ) + { + /* remove the temporary relations */ + /* and close the scan descriptors */ + + bufferRel = teeState->tee_bufferRel; + if (bufferRel) { + heap_destroyr(bufferRel); + teeState->tee_bufferRel = NULL; + if (teeState->tee_mcxt) { + orig = CurrentMemoryContext; + MemoryContextSwitchTo(teeState->tee_mcxt); + } + + if (teeState->tee_leftScanDesc) + { + heap_endscan(teeState->tee_leftScanDesc); + teeState->tee_leftScanDesc = NULL; + } + if (teeState->tee_rightScanDesc) + { + heap_endscan(teeState->tee_rightScanDesc); + teeState->tee_rightScanDesc = NULL; + } + + if (teeState->tee_mcxt) { + MemoryContextSwitchTo(orig); + teeState->tee_mcxt = NULL; + } + } + } + +} + |