diff options
author | Bruce Momjian <bruce@momjian.us> | 1999-11-23 20:07:06 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1999-11-23 20:07:06 +0000 |
commit | 6f9ff92cc0ff6a07d2fe38abe044286ee98d44a0 (patch) | |
tree | 797395e647f1e8a741214d5eaafb9ee66a64c462 /src/backend/executor | |
parent | 54ffd4677aaf56e928af9e3f689297d6c06d1fe9 (diff) | |
download | postgresql-6f9ff92cc0ff6a07d2fe38abe044286ee98d44a0.tar.gz postgresql-6f9ff92cc0ff6a07d2fe38abe044286ee98d44a0.zip |
Tid access method feature from Hiroshi Inoue, Inoue@tpf.co.jp
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/Makefile | 5 | ||||
-rw-r--r-- | src/backend/executor/execAmi.c | 17 | ||||
-rw-r--r-- | src/backend/executor/execProcnode.c | 18 | ||||
-rw-r--r-- | src/backend/executor/execTuples.c | 9 | ||||
-rw-r--r-- | src/backend/executor/nodeTidscan.c | 550 |
5 files changed, 593 insertions, 6 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile index 4f8c1341c83..ea0b20e9b48 100644 --- a/src/backend/executor/Makefile +++ b/src/backend/executor/Makefile @@ -4,7 +4,7 @@ # Makefile for executor # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.8 1999/03/23 16:50:46 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.9 1999/11/23 20:06:49 momjian Exp $ # #------------------------------------------------------------------------- @@ -18,7 +18,8 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \ execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \ nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \ nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSort.o \ - nodeUnique.o nodeGroup.o spi.o nodeSubplan.o + nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \ + nodeTidscan.o all: SUBSYS.o diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index dc69953e210..0d7801bcd8a 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: execAmi.c,v 1.43 1999/11/04 08:00:57 inoue Exp $ + * $Id: execAmi.c,v 1.44 1999/11/23 20:06:50 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -40,6 +40,7 @@ #include "executor/nodeHash.h" #include "executor/nodeHashjoin.h" #include "executor/nodeIndexscan.h" +#include "executor/nodeTidscan.h" #include "executor/nodeMaterial.h" #include "executor/nodeMergejoin.h" #include "executor/nodeNestloop.h" @@ -217,6 +218,10 @@ ExecCloseR(Plan *node) state = &(((Agg *) node)->aggstate->csstate); break; + case T_TidScan: + state = ((TidScan *) node)->scan.scanstate; + break; + default: elog(DEBUG, "ExecCloseR: not a scan, material, or sort node!"); return; @@ -367,6 +372,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent) ExecReScanAppend((Append *) node, exprCtxt, parent); break; + case T_TidScan: + ExecTidReScan((TidScan *) node, exprCtxt, parent); + break; + default: elog(ERROR, "ExecReScan: node type %u not supported", nodeTag(node)); return; @@ -413,7 +422,7 @@ ExecMarkPos(Plan *node) { switch (nodeTag(node)) { - case T_SeqScan: + case T_SeqScan: ExecSeqMarkPos((SeqScan *) node); break; @@ -425,6 +434,10 @@ ExecMarkPos(Plan *node) ExecSortMarkPos((Sort *) node); break; + case T_TidScan: + ExecTidMarkPos((TidScan *) node); + break; + default: elog(DEBUG, "ExecMarkPos: node type %u not supported", nodeTag(node)); break; diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 1b6d2bd8421..d4527be23ba 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.15 1999/07/16 04:58:46 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.16 1999/11/23 20:06:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -81,6 +81,7 @@ #include "executor/nodeHash.h" #include "executor/nodeHashjoin.h" #include "executor/nodeIndexscan.h" +#include "executor/nodeTidscan.h" #include "executor/nodeMaterial.h" #include "executor/nodeMergejoin.h" #include "executor/nodeNestloop.h" @@ -195,6 +196,10 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent) result = ExecInitHashJoin((HashJoin *) node, estate, parent); break; + case T_TidScan: + result = ExecInitTidScan((TidScan *) node, estate, parent); + break; + default: elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node)); result = FALSE; @@ -310,6 +315,10 @@ ExecProcNode(Plan *node, Plan *parent) result = ExecHashJoin((HashJoin *) node); break; + case T_TidScan: + result = ExecTidScan((TidScan *) node); + break; + default: elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node)); result = NULL; @@ -381,6 +390,9 @@ ExecCountSlotsNode(Plan *node) case T_HashJoin: return ExecCountSlotsHashJoin((HashJoin *) node); + case T_TidScan: + return ExecCountSlotsTidScan((TidScan *) node); + default: elog(ERROR, "ExecCountSlotsNode: node not yet supported: %d", nodeTag(node)); @@ -497,6 +509,10 @@ ExecEndNode(Plan *node, Plan *parent) ExecEndHashJoin((HashJoin *) node); break; + case T_TidScan: + ExecEndTidScan((TidScan *) node); + break; + default: elog(ERROR, "ExecEndNode: node %d unsupported", nodeTag(node)); break; diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 53edd555ad8..f1f6d15f1b0 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.31 1999/11/07 23:08:06 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.32 1999/11/23 20:06:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -771,6 +771,13 @@ NodeGetResultTupleSlot(Plan *node) } break; + case T_TidScan: + { + CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate; + slot = scanstate->cstate.cs_ResultTupleSlot; + } + break; + default: /* ---------------- * should never get here diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c new file mode 100644 index 00000000000..8d6481bf8ad --- /dev/null +++ b/src/backend/executor/nodeTidscan.c @@ -0,0 +1,550 @@ +/*------------------------------------------------------------------------- + * + * nodeTidscan.c + * Routines to support direct tid scans of relations + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.1 1999/11/23 20:06:51 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +/* + * INTERFACE ROUTINES + * + * ExecTidScan scans a relation using tids + * ExecInitTidScan creates and initializes state info. + * ExecTidReScan rescans the tid relation. + * ExecEndTidScan releases all storage. + * ExecTidMarkPos marks scan position. + * ExecTidRestrPos restores scan position. + * + */ +#include "postgres.h" + +#include "executor/executor.h" +#include "executor/execdebug.h" +#include "executor/nodeTidscan.h" +#include "optimizer/clauses.h" /* for get_op, get_leftop, get_rightop */ +#include "access/heapam.h" +#include "parser/parsetree.h" + +static int TidListCreate(List *, ExprContext *, ItemPointer *); +static TupleTableSlot *TidNext(TidScan *node); + +static int +TidListCreate(List *evalList, ExprContext *econtext, ItemPointer *tidList) +{ + List *lst; + ItemPointer itemptr; + bool isNull; + int numTids = 0; + + foreach (lst, evalList) + { + itemptr = (ItemPointer)ExecEvalExpr(lfirst(lst), econtext, + &isNull, (bool *)0); + if (itemptr && ItemPointerIsValid(itemptr)) + { + tidList[numTids] = itemptr; + numTids++; + } + } + return numTids; +} + +/* ---------------------------------------------------------------- + * TidNext + * + * Retrieve a tuple from the TidScan node's currentRelation + * using the tids in the TidScanState information. + * + * ---------------------------------------------------------------- + */ +static TupleTableSlot * +TidNext(TidScan *node) +{ + EState *estate; + CommonScanState *scanstate; + TidScanState *tidstate; + ScanDirection direction; + Snapshot snapshot; + Relation heapRelation; + HeapTuple tuple; + TupleTableSlot *slot; + Buffer buffer = InvalidBuffer; + int numTids; + + bool bBackward; + int tidNumber; + ItemPointer *tidList, itemptr; + + /* ---------------- + * extract necessary information from tid scan node + * ---------------- + */ + estate = node->scan.plan.state; + direction = estate->es_direction; + snapshot = estate->es_snapshot; + scanstate = node->scan.scanstate; + tidstate = node->tidstate; + heapRelation = scanstate->css_currentRelation; + numTids = tidstate->tss_NumTids; + tidList = tidstate->tss_TidList; + slot = scanstate->css_ScanTupleSlot; + + /* + * Check if we are evaluating PlanQual for tuple of this relation. + * Additional checking is not good, but no other way for now. We could + * introduce new nodes for this case and handle TidScan --> NewNode + * switching in Init/ReScan plan... + */ + if (estate->es_evTuple != NULL && + estate->es_evTuple[node->scan.scanrelid - 1] != NULL) + { + int iptr, numQuals; + + ExecClearTuple(slot); + if (estate->es_evTupleNull[node->scan.scanrelid - 1]) + return slot; /* return empty slot */ + + slot->val = estate->es_evTuple[node->scan.scanrelid - 1]; + slot->ttc_shouldFree = false; + /* Flag for the next call that no more tuples */ + estate->es_evTupleNull[node->scan.scanrelid - 1] = true; + return (slot); + } + + tuple = &(tidstate->tss_htup); + + /* ---------------- + * ok, now that we have what we need, fetch an tid tuple. + * if scanning this tid succeeded then return the + * appropriate heap tuple.. else return NULL. + * ---------------- + */ + bBackward = ScanDirectionIsBackward(direction); + if (bBackward) + { + tidNumber = numTids - tidstate->tss_TidPtr - 1; + if (tidNumber < 0) + { + tidNumber = 0; + tidstate->tss_TidPtr = numTids - 1; + } + } + else + { + if ((tidNumber = tidstate->tss_TidPtr) < 0) + { + tidNumber = 0; + tidstate->tss_TidPtr = 0; + } + } + while (tidNumber < numTids) + { + bool slot_is_valid = false; + + itemptr = tidList[tidstate->tss_TidPtr]; + tuple->t_data = NULL; + if (itemptr) + { + tuple->t_self = *(itemptr); + heap_fetch(heapRelation, snapshot, tuple, &buffer); + } + if (tuple->t_data != NULL) + { + bool prev_matches = false; + int prev_tid; + + /* ---------------- + * store the scanned tuple in the scan tuple slot of + * the scan state. Eventually we will only do this and not + * return a tuple. Note: we pass 'false' because tuples + * returned by amgetnext are pointers onto disk pages and + * were not created with palloc() and so should not be pfree()'d. + * ---------------- + */ + ExecStoreTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + buffer, /* buffer associated with tuple */ + false); /* don't pfree */ + + /* + * At this point we have an extra pin on the buffer, + * because ExecStoreTuple incremented the pin count. + * Drop our local pin. + */ + ReleaseBuffer(buffer); + /* + * We must check to see if the current tuple would have + * been matched by an earlier tid, so we don't double + * report it. We do this by passing the tuple through + * ExecQual and look for failure with all previous + * qualifications. + */ + for (prev_tid = 0; prev_tid < tidstate->tss_TidPtr; + prev_tid++) + { + if (ItemPointerEquals(tidList[prev_tid], &tuple->t_self)) + { + prev_matches = true; + break; + } + } + if (!prev_matches) + slot_is_valid = true; + else + ExecClearTuple(slot); + } + else if (BufferIsValid(buffer)) + ReleaseBuffer(buffer); + tidNumber++; + if (bBackward) + tidstate->tss_TidPtr--; + else + tidstate->tss_TidPtr++; + if (slot_is_valid) + return slot; + } + /* ---------------- + * if we get here it means the tid scan failed so we + * are at the end of the scan.. + * ---------------- + */ + return ExecClearTuple(slot); +} + +/* ---------------------------------------------------------------- + * ExecTidScan(node) + * + * Scans the relation using tids and returns + * the next qualifying tuple in the direction specified. + * It calls ExecScan() and passes it the access methods which returns + * the next tuple using the tids. + * + * Conditions: + * -- the "cursor" maintained by the AMI is positioned at the tuple + * returned previously. + * + * Initial States: + * -- the relation indicated is opened for scanning so that the + * "cursor" is positioned before the first qualifying tuple. + * -- tidPtr points to the first tid. + * -- state variable ruleFlag = nil. + * ---------------------------------------------------------------- + */ +TupleTableSlot * +ExecTidScan(TidScan *node) +{ + /* ---------------- + * use TidNext as access method + * ---------------- + */ + return ExecScan(&node->scan, TidNext); +} + +/* ---------------------------------------------------------------- + * ExecTidReScan(node) + * ---------------------------------------------------------------- + */ +void +ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent) +{ + EState *estate; + TidScanState *tidstate; + Plan *outerPlan; + ItemPointer *tidList; + + tidstate = node->tidstate; + estate = node->scan.plan.state; + tidstate->tss_TidPtr = -1; + tidList = tidstate->tss_TidList; + + if ((outerPlan = outerPlan((Plan *) node)) != NULL) + { + /* we are scanning a subplan */ + outerPlan = outerPlan((Plan *) node); + ExecReScan(outerPlan, exprCtxt, parent); + } + else + /* otherwise, we are scanning a relation */ + { + /* If this is re-scanning of PlanQual ... */ + if (estate->es_evTuple != NULL && + estate->es_evTuple[node->scan.scanrelid - 1] != NULL) + { + estate->es_evTupleNull[node->scan.scanrelid - 1] = false; + return; + } + + /* it's possible in subselects */ + if (exprCtxt == NULL) + exprCtxt = node->scan.scanstate->cstate.cs_ExprContext; + + node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple = exprCtxt->ecxt_outertuple; + tidstate->tss_NumTids = TidListCreate(node->tideval, exprCtxt, tidList); + } + + /* ---------------- + * perhaps return something meaningful + * ---------------- + */ + return; +} + +/* ---------------------------------------------------------------- + * ExecEndTidScan + * + * Releases any storage allocated through C routines. + * Returns nothing. + * ---------------------------------------------------------------- + */ +void +ExecEndTidScan(TidScan *node) +{ + CommonScanState *scanstate; + TidScanState *tidstate; + + scanstate = node->scan.scanstate; + tidstate = node->tidstate; + if (tidstate && tidstate->tss_TidList) + pfree(tidstate->tss_TidList); + + /* ---------------- + * extract information from the node + * ---------------- + */ + + /* ---------------- + * Free the projection info and the scan attribute info + * + * Note: we don't ExecFreeResultType(scanstate) + * because the rule manager depends on the tupType + * returned by ExecMain(). So for now, this + * is freed at end-transaction time. -cim 6/2/91 + * ---------------- + */ + ExecFreeProjectionInfo(&scanstate->cstate); + + /* ---------------- + * close the heap and tid relations + * ---------------- + */ + ExecCloseR((Plan *) node); + + /* ---------------- + * clear out tuple table slots + * ---------------- + */ + ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot); + ExecClearTuple(scanstate->css_ScanTupleSlot); +/* ExecClearTuple(scanstate->css_RawTupleSlot); */ +} + +/* ---------------------------------------------------------------- + * ExecTidMarkPos + * + * Marks scan position by marking the current tid. + * Returns nothing. + * ---------------------------------------------------------------- + */ +void +ExecTidMarkPos(TidScan *node) +{ + TidScanState *tidstate; + + tidstate = node->tidstate; + tidstate->tss_MarkTidPtr = tidstate->tss_TidPtr; +} + +/* ---------------------------------------------------------------- + * ExecTidRestrPos + * + * Restores scan position by restoring the current tid. + * Returns nothing. + * + * XXX Assumes previously marked scan position belongs to current tid + * ---------------------------------------------------------------- + */ +void +ExecTidRestrPos(TidScan *node) +{ + TidScanState *tidstate; + + tidstate = node->tidstate; + tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr; +} + +/* ---------------------------------------------------------------- + * ExecInitTidScan + * + * Initializes the tid scan's state information, creates + * scan keys, and opens the base and tid relations. + * + * Parameters: + * node: TidNode node produced by the planner. + * estate: the execution state initialized in InitPlan. + * ---------------------------------------------------------------- + */ +bool +ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) +{ + TidScanState *tidstate; + CommonScanState *scanstate; + ItemPointer *tidList; + int numTids; + int tidPtr; + List *rangeTable; + RangeTblEntry *rtentry; + Oid relid; + Oid reloid; + + Relation currentRelation; + int baseid; + + List *execParam = NULL; + + /* ---------------- + * assign execution state to node + * ---------------- + */ + node->scan.plan.state = estate; + + /* -------------------------------- + * Part 1) initialize scan state + * + * create new CommonScanState for node + * -------------------------------- + */ + scanstate = makeNode(CommonScanState); +/* + scanstate->ss_ProcOuterFlag = false; + scanstate->ss_OldRelId = 0; +*/ + + node->scan.scanstate = scanstate; + + /* ---------------- + * assign node's base_id .. we don't use AssignNodeBaseid() because + * the increment is done later on after we assign the tid scan's + * scanstate. see below. + * ---------------- + */ + baseid = estate->es_BaseId; +/* scanstate->csstate.cstate.bnode.base_id = baseid; */ + scanstate->cstate.cs_base_id = baseid; + + /* ---------------- + * create expression context for node + * ---------------- + */ + ExecAssignExprContext(estate, &scanstate->cstate); + +#define TIDSCAN_NSLOTS 3 + /* ---------------- + * tuple table initialization + * ---------------- + */ + ExecInitResultTupleSlot(estate, &scanstate->cstate); + ExecInitScanTupleSlot(estate, scanstate); +/* ExecInitRawTupleSlot(estate, scanstate); */ + + /* ---------------- + * initialize projection info. result type comes from scan desc + * below.. + * ---------------- + */ + ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate); + + /* -------------------------------- + * Part 2) initialize tid scan state + * + * create new TidScanState for node + * -------------------------------- + */ + tidstate = makeNode(TidScanState); + node->tidstate = tidstate; + + /* ---------------- + * assign base id to tid scan state also + * ---------------- + */ + tidstate->cstate.cs_base_id = baseid; + baseid++; + estate->es_BaseId = baseid; + + /* ---------------- + * get the tid node information + * ---------------- + */ + tidList = (ItemPointer *)palloc(length(node->tideval) * sizeof(ItemPointer)); + numTids = 0; + if (!node->needRescan) + numTids = TidListCreate(node->tideval, scanstate->cstate.cs_ExprContext, tidList); + tidPtr = -1; + + CXT1_printf("ExecInitTidScan: context is %d\n", CurrentMemoryContext); + + tidstate->tss_NumTids = numTids; + tidstate->tss_TidPtr = tidPtr; + tidstate->tss_TidList = tidList; + + /* ---------------- + * get the range table and direction information + * from the execution state (these are needed to + * open the relations). + * ---------------- + */ + rangeTable = estate->es_range_table; + + /* ---------------- + * open the base relation + * ---------------- + */ + relid = node->scan.scanrelid; + rtentry = rt_fetch(relid, rangeTable); + reloid = rtentry->relid; + + currentRelation = heap_open(reloid, AccessShareLock); + if (currentRelation == NULL) + elog(ERROR, "ExecInitTidScan heap_open failed."); + scanstate->css_currentRelation = currentRelation; + scanstate->css_currentScanDesc = 0; + + /* ---------------- + * get the scan type from the relation descriptor. + * ---------------- + */ + ExecAssignScanType(scanstate, RelationGetDescr(currentRelation)); + ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate); + + /* ---------------- + * tid scans don't have subtrees.. + * ---------------- + */ +/* scanstate->ss_ProcOuterFlag = false; */ + + tidstate->cstate.cs_TupFromTlist = false; + + /* + * if there are some PARAM_EXEC in skankeys then force tid rescan on + * first scan. + */ + ((Plan *) node)->chgParam = execParam; + + /* ---------------- + * all done. + * ---------------- + */ + return TRUE; +} + +int +ExecCountSlotsTidScan(TidScan *node) +{ + return ExecCountSlotsNode(outerPlan((Plan *) node)) + + ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS; +} |