📄 nodeindexscan.c
字号:
/*------------------------------------------------------------------------- * * nodeIndexscan.c * Routines to support indexed scans of relations * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.104.2.1 2005/11/22 18:23:09 momjian Exp $ * *------------------------------------------------------------------------- *//* * INTERFACE ROUTINES * ExecIndexScan scans a relation using indices * ExecIndexNext using index to retrieve next tuple * ExecInitIndexScan creates and initializes state info. * ExecIndexReScan rescans the indexed relation. * ExecEndIndexScan releases all storage. * ExecIndexMarkPos marks scan position. * ExecIndexRestrPos restores scan position. */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "executor/execdebug.h"#include "executor/nodeIndexscan.h"#include "miscadmin.h"#include "nodes/nodeFuncs.h"#include "optimizer/clauses.h"#include "parser/parsetree.h"#include "utils/memutils.h"static TupleTableSlot *IndexNext(IndexScanState *node);/* ---------------------------------------------------------------- * IndexNext * * Retrieve a tuple from the IndexScan node's currentRelation * using the index specified in the IndexScanState information. * ---------------------------------------------------------------- */static TupleTableSlot *IndexNext(IndexScanState *node){ EState *estate; ExprContext *econtext; ScanDirection direction; IndexScanDesc scandesc; Index scanrelid; HeapTuple tuple; TupleTableSlot *slot; /* * extract necessary information from index scan node */ estate = node->ss.ps.state; direction = estate->es_direction; /* flip direction if this is an overall backward scan */ if (ScanDirectionIsBackward(((IndexScan *) node->ss.ps.plan)->indexorderdir)) { if (ScanDirectionIsForward(direction)) direction = BackwardScanDirection; else if (ScanDirectionIsBackward(direction)) direction = ForwardScanDirection; } scandesc = node->iss_ScanDesc; econtext = node->ss.ps.ps_ExprContext; slot = node->ss.ss_ScanTupleSlot; scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid; /* * Clear any reference to the previously returned tuple. The idea here is * to not have the tuple slot be the last holder of a pin on that tuple's * buffer; if it is, we'll need a separate visit to the bufmgr to release * the buffer. By clearing here, we get to have the release done by * ReleaseAndReadBuffer inside index_getnext. */ ExecClearTuple(slot); /* * 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 IndexScan --> NewNode * switching in Init/ReScan plan... */ if (estate->es_evTuple != NULL && estate->es_evTuple[scanrelid - 1] != NULL) { if (estate->es_evTupleNull[scanrelid - 1]) return slot; /* return empty slot */ ExecStoreTuple(estate->es_evTuple[scanrelid - 1], slot, InvalidBuffer, false); /* Does the tuple meet the indexqual condition? */ econtext->ecxt_scantuple = slot; ResetExprContext(econtext); if (!ExecQual(node->indexqualorig, econtext, false)) ExecClearTuple(slot); /* would not be returned by scan */ /* Flag for the next call that no more tuples */ estate->es_evTupleNull[scanrelid - 1] = true; return slot; } /* * ok, now that we have what we need, fetch the next tuple. */ if ((tuple = index_getnext(scandesc, direction)) != NULL) { /* * Store the scanned tuple in the scan tuple slot of the scan state. * Note: we pass 'false' because tuples returned by amgetnext are * pointers onto disk pages and must not be pfree()'d. */ ExecStoreTuple(tuple, /* tuple to store */ slot, /* slot to store in */ scandesc->xs_cbuf, /* buffer containing tuple */ false); /* don't pfree */ return slot; } /* * if we get here it means the index scan failed so we are at the end of * the scan.. */ return ExecClearTuple(slot);}/* ---------------------------------------------------------------- * ExecIndexScan(node) * ---------------------------------------------------------------- */TupleTableSlot *ExecIndexScan(IndexScanState *node){ /* * If we have runtime keys and they've not already been set up, do it now. */ if (node->iss_RuntimeKeyInfo && !node->iss_RuntimeKeysReady) ExecReScan((PlanState *) node, NULL); /* * use IndexNext as access method */ return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);}/* ---------------------------------------------------------------- * ExecIndexReScan(node) * * Recalculates the value of the scan keys whose value depends on * information known at runtime and rescans the indexed relation. * Updating the scan key was formerly done separately in * ExecUpdateIndexScanKeys. Integrating it into ReScan makes * rescans of indices and relations/general streams more uniform. * ---------------------------------------------------------------- */voidExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt){ EState *estate; ExprContext *econtext; ScanKey scanKeys; ExprState **runtimeKeyInfo; int numScanKeys; Index scanrelid; estate = node->ss.ps.state; econtext = node->iss_RuntimeContext; /* context for runtime keys */ scanKeys = node->iss_ScanKeys; runtimeKeyInfo = node->iss_RuntimeKeyInfo; numScanKeys = node->iss_NumScanKeys; scanrelid = ((IndexScan *) node->ss.ps.plan)->scan.scanrelid; if (econtext) { /* * If we are being passed an outer tuple, save it for runtime key * calc. We also need to link it into the "regular" per-tuple * econtext, so it can be used during indexqualorig evaluations. */ if (exprCtxt != NULL) { ExprContext *stdecontext; econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple; stdecontext = node->ss.ps.ps_ExprContext; stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple; } /* * Reset the runtime-key context so we don't leak memory as each outer * tuple is scanned. Note this assumes that we will recalculate *all* * runtime keys on each call. */ ResetExprContext(econtext); } /* * If we are doing runtime key calculations (ie, the index keys depend on * data from an outer scan), compute the new key values */ if (runtimeKeyInfo) { ExecIndexEvalRuntimeKeys(econtext, runtimeKeyInfo, scanKeys, numScanKeys); node->iss_RuntimeKeysReady = true; } /* If this is re-scanning of PlanQual ... */ if (estate->es_evTuple != NULL && estate->es_evTuple[scanrelid - 1] != NULL) { estate->es_evTupleNull[scanrelid - 1] = false; return; } /* reset index scan */ index_rescan(node->iss_ScanDesc, scanKeys);}/* * ExecIndexEvalRuntimeKeys * Evaluate any runtime key values, and update the scankeys. */voidExecIndexEvalRuntimeKeys(ExprContext *econtext, ExprState **run_keys, ScanKey scan_keys, int n_keys){ int j; for (j = 0; j < n_keys; j++) { /* * If we have a run-time key, then extract the run-time expression and * evaluate it with respect to the current outer tuple. We then stick * the result into the scan key. * * Note: the result of the eval could be a pass-by-ref value that's * stored in the outer scan's tuple, not in * econtext->ecxt_per_tuple_memory. We assume that the outer tuple * will stay put throughout our scan. If this is wrong, we could copy * the result into our context explicitly, but I think that's not * necessary... */ if (run_keys[j] != NULL) { Datum scanvalue; bool isNull; scanvalue = ExecEvalExprSwitchContext(run_keys[j], econtext, &isNull, NULL); scan_keys[j].sk_argument = scanvalue; if (isNull) scan_keys[j].sk_flags |= SK_ISNULL; else scan_keys[j].sk_flags &= ~SK_ISNULL; } }}/* ---------------------------------------------------------------- * ExecEndIndexScan * ---------------------------------------------------------------- */voidExecEndIndexScan(IndexScanState *node){ Relation indexRelationDesc; IndexScanDesc indexScanDesc; Relation relation; /* * extract information from the node */ indexRelationDesc = node->iss_RelationDesc; indexScanDesc = node->iss_ScanDesc; relation = node->ss.ss_currentRelation; /* * Free the exprcontext(s) ... now dead code, see ExecFreeExprContext */#ifdef NOT_USED ExecFreeExprContext(&node->ss.ps); if (node->iss_RuntimeContext) FreeExprContext(node->iss_RuntimeContext);#endif /* * clear out tuple table slots */ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ss_ScanTupleSlot); /* * close the index relation */ index_endscan(indexScanDesc); index_close(indexRelationDesc); /* * close the heap relation. * * Currently, we do not release the AccessShareLock acquired by * ExecInitIndexScan. This lock should be held till end of transaction. * (There is a faction that considers this too much locking, however.) */ heap_close(relation, NoLock);}/* ---------------------------------------------------------------- * ExecIndexMarkPos * ---------------------------------------------------------------- */voidExecIndexMarkPos(IndexScanState *node){ index_markpos(node->iss_ScanDesc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -