1 /*-------------------------------------------------------------------------
4 * general index access method routines
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.27 2001/06/09 18:16:56 tgl Exp $
14 * many of the old access method routines have been turned into
15 * macros and moved to genam.h -cim 4/30/91
17 *-------------------------------------------------------------------------
21 * Scans are implemented as follows:
23 * `0' represents an invalid item pointer.
24 * `-' represents an unknown item pointer.
25 * `X' represents a known item pointers.
26 * `+' represents known or invalid item pointers.
27 * `*' represents any item pointers.
29 * State is represented by a triple of these symbols in the order of
30 * previous, current, next. Note that the case of reverse scans works
34 * (1) + + - + 0 0 (if the next item pointer is invalid)
35 * (2) + X - (otherwise)
36 * (3) * 0 0 * 0 0 (no change)
37 * (4) + X 0 X 0 0 (shift)
38 * (5) * + X + X - (shift, add unknown)
40 * All other states cannot occur.
43 * It would be possible to cache the status of the previous and
44 * next item pointer using the flags.
45 * ----------------------------------------------------------------
49 #include "access/genam.h"
52 /* ----------------------------------------------------------------
53 * general access method routines
55 * All indexed access methods use an identical scan structure.
56 * We don't know how the various AMs do locking, however, so we don't
57 * do anything about that here.
59 * The intent is that an AM implementor will define a beginscan routine
60 * that calls RelationGetIndexScan, to fill in the scan, and then does
61 * whatever kind of locking he wants.
63 * At the end of a scan, the AM's endscan routine undoes the locking,
64 * but does *not* call IndexScanEnd --- the higher-level index_endscan
65 * routine does that. (We can't do it in the AM because index_endscan
66 * still needs to touch the IndexScanDesc after calling the AM.)
68 * Because of this, the AM does not have a choice whether to call
69 * RelationGetIndexScan or not; its beginscan routine must return an
70 * object made by RelationGetIndexScan. This is kinda ugly but not
71 * worth cleaning up now.
72 * ----------------------------------------------------------------
76 * RelationGetIndexScan -- Create and fill an IndexScanDesc.
78 * This routine creates an index scan structure and sets its contents
79 * up correctly. This routine calls AMrescan to set up the scan with
83 * relation -- index relation for scan.
84 * scanFromEnd -- if true, begin scan at one of the index's
86 * numberOfKeys -- count of scan keys.
87 * key -- the ScanKey for the starting position of the scan.
90 * An initialized IndexScanDesc.
94 RelationGetIndexScan(Relation relation,
101 if (!RelationIsValid(relation))
102 elog(ERROR, "RelationGetIndexScan: relation invalid");
104 scan = (IndexScanDesc) palloc(sizeof(IndexScanDescData));
106 scan->relation = relation;
108 scan->numberOfKeys = numberOfKeys;
110 ItemPointerSetInvalid(&scan->currentItemData);
111 ItemPointerSetInvalid(&scan->currentMarkData);
114 * mark cached function lookup data invalid; it will be set on first
117 scan->fn_getnext.fn_oid = InvalidOid;
119 if (numberOfKeys > 0)
120 scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * numberOfKeys);
122 scan->keyData = NULL;
124 index_rescan(scan, scanFromEnd, key);
130 * IndexScanEnd -- End an index scan.
132 * This routine just releases the storage acquired by
133 * RelationGetIndexScan(). Any AM-level resources are
134 * assumed to already have been released by the AM's
142 IndexScanEnd(IndexScanDesc scan)
144 if (!IndexScanIsValid(scan))
145 elog(ERROR, "IndexScanEnd: invalid scan");
147 if (scan->keyData != NULL)
148 pfree(scan->keyData);
155 * IndexScanRestart -- Restart an index scan.
157 * This routine isn't used by any existing access method. It's
158 * appropriate if relation level locks are what you want.
168 IndexScanRestart(IndexScanDesc scan,
172 if (!IndexScanIsValid(scan))
173 elog(ERROR, "IndexScanRestart: invalid scan");
175 ItemPointerSetInvalid(&scan->currentItemData);
177 if (RelationGetNumberOfBlocks(scan->relation) == 0)
178 scan->flags = ScanUnmarked;
179 else if (scanFromEnd)
180 scan->flags = ScanUnmarked | ScanUncheckedPrevious;
182 scan->flags = ScanUnmarked | ScanUncheckedNext;
184 scan->scanFromEnd = (bool) scanFromEnd;
186 if (scan->numberOfKeys > 0)
187 memmove(scan->keyData,
189 scan->numberOfKeys * sizeof(ScanKeyData));
193 * IndexScanMarkPosition -- Mark current position in a scan.
195 * This routine isn't used by any existing access method, but is the
196 * one that AM implementors should use, if they don't want to do any
197 * special locking. If relation-level locking is sufficient, this is
198 * the routine for you.
208 IndexScanMarkPosition(IndexScanDesc scan)
210 scan->currentMarkData = scan->currentItemData;
212 scan->flags = 0x0; /* XXX should have a symbolic name */
216 * IndexScanRestorePosition -- Restore position on a marked scan.
218 * This routine isn't used by any existing access method, but is the
219 * one that AM implementors should use if they don't want to do any
220 * special locking. If relation-level locking is sufficient, then
221 * this is the one you want.
231 IndexScanRestorePosition(IndexScanDesc scan)
233 if (scan->flags & ScanUnmarked)
234 elog(ERROR, "IndexScanRestorePosition: no mark to restore");
236 scan->currentItemData = scan->currentMarkData;
238 scan->flags = 0x0; /* XXX should have a symbolic name */