1 : /*-------------------------------------------------------------------------
2 : *
3 : * genam.c
4 : * general index access method routines
5 : *
6 : * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.63 2007/09/20 17:56:30 tgl Exp $
12 : *
13 : * NOTES
14 : * many of the old access method routines have been turned into
15 : * macros and moved to genam.h -cim 4/30/91
16 : *
17 : *-------------------------------------------------------------------------
18 : */
19 :
20 : #include "postgres.h"
21 :
22 : #include "access/genam.h"
23 : #include "access/heapam.h"
24 : #include "access/transam.h"
25 : #include "miscadmin.h"
26 : #include "pgstat.h"
27 :
28 :
29 : /* ----------------------------------------------------------------
30 : * general access method routines
31 : *
32 : * All indexed access methods use an identical scan structure.
33 : * We don't know how the various AMs do locking, however, so we don't
34 : * do anything about that here.
35 : *
36 : * The intent is that an AM implementor will define a beginscan routine
37 : * that calls RelationGetIndexScan, to fill in the scan, and then does
38 : * whatever kind of locking he wants.
39 : *
40 : * At the end of a scan, the AM's endscan routine undoes the locking,
41 : * but does *not* call IndexScanEnd --- the higher-level index_endscan
42 : * routine does that. (We can't do it in the AM because index_endscan
43 : * still needs to touch the IndexScanDesc after calling the AM.)
44 : *
45 : * Because of this, the AM does not have a choice whether to call
46 : * RelationGetIndexScan or not; its beginscan routine must return an
47 : * object made by RelationGetIndexScan. This is kinda ugly but not
48 : * worth cleaning up now.
49 : * ----------------------------------------------------------------
50 : */
51 :
52 : /* ----------------
53 : * RelationGetIndexScan -- Create and fill an IndexScanDesc.
54 : *
55 : * This routine creates an index scan structure and sets its contents
56 : * up correctly. This routine calls AMrescan to set up the scan with
57 : * the passed key.
58 : *
59 : * Parameters:
60 : * indexRelation -- index relation for scan.
61 : * nkeys -- count of scan keys.
62 : * key -- array of scan keys to restrict the index scan.
63 : *
64 : * Returns:
65 : * An initialized IndexScanDesc.
66 : * ----------------
67 : */
68 : IndexScanDesc
69 : RelationGetIndexScan(Relation indexRelation,
70 : int nkeys, ScanKey key)
71 118528 : {
72 : IndexScanDesc scan;
73 :
74 118528 : scan = (IndexScanDesc) palloc(sizeof(IndexScanDescData));
75 :
76 118528 : scan->heapRelation = NULL; /* may be set later */
77 118528 : scan->indexRelation = indexRelation;
78 118528 : scan->xs_snapshot = SnapshotNow; /* may be set later */
79 118528 : scan->numberOfKeys = nkeys;
80 :
81 : /*
82 : * We allocate the key space here, but the AM is responsible for actually
83 : * filling it from the passed key array.
84 : */
85 118528 : if (nkeys > 0)
86 118488 : scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
87 : else
88 40 : scan->keyData = NULL;
89 :
90 118528 : scan->is_multiscan = false; /* caller may change this */
91 118528 : scan->kill_prior_tuple = false;
92 118528 : scan->ignore_killed_tuples = true; /* default setting */
93 :
94 118528 : scan->opaque = NULL;
95 :
96 118528 : ItemPointerSetInvalid(&scan->xs_ctup.t_self);
97 118528 : scan->xs_ctup.t_data = NULL;
98 118528 : scan->xs_cbuf = InvalidBuffer;
99 118528 : scan->xs_prev_xmax = InvalidTransactionId;
100 118528 : scan->xs_next_hot = InvalidOffsetNumber;
101 118528 : scan->xs_hot_dead = false;
102 :
103 : /*
104 : * Let the AM fill in the key and any opaque data it wants.
105 : */
106 118528 : index_rescan(scan, key);
107 :
108 118528 : return scan;
109 : }
110 :
111 : /* ----------------
112 : * IndexScanEnd -- End an index scan.
113 : *
114 : * This routine just releases the storage acquired by
115 : * RelationGetIndexScan(). Any AM-level resources are
116 : * assumed to already have been released by the AM's
117 : * endscan routine.
118 : *
119 : * Returns:
120 : * None.
121 : * ----------------
122 : */
123 : void
124 : IndexScanEnd(IndexScanDesc scan)
125 118502 : {
126 118502 : if (scan->keyData != NULL)
127 118464 : pfree(scan->keyData);
128 :
129 118502 : pfree(scan);
130 118502 : }
131 :
132 :
133 : /* ----------------------------------------------------------------
134 : * heap-or-index-scan access to system catalogs
135 : *
136 : * These functions support system catalog accesses that normally use
137 : * an index but need to be capable of being switched to heap scans
138 : * if the system indexes are unavailable.
139 : *
140 : * The specified scan keys must be compatible with the named index.
141 : * Generally this means that they must constrain either all columns
142 : * of the index, or the first K columns of an N-column index.
143 : *
144 : * These routines could work with non-system tables, actually,
145 : * but they're only useful when there is a known index to use with
146 : * the given scan keys; so in practice they're only good for
147 : * predetermined types of scans of system catalogs.
148 : * ----------------------------------------------------------------
149 : */
150 :
151 : /*
152 : * systable_beginscan --- set up for heap-or-index scan
153 : *
154 : * rel: catalog to scan, already opened and suitably locked
155 : * indexId: OID of index to conditionally use
156 : * indexOK: if false, forces a heap scan (see notes below)
157 : * snapshot: time qual to use (usually should be SnapshotNow)
158 : * nkeys, key: scan keys
159 : *
160 : * The attribute numbers in the scan key should be set for the heap case.
161 : * If we choose to index, we reset them to 1..n to reference the index
162 : * columns. Note this means there must be one scankey qualification per
163 : * index column! This is checked by the Asserts in the normal, index-using
164 : * case, but won't be checked if the heapscan path is taken.
165 : *
166 : * The routine checks the normal cases for whether an indexscan is safe,
167 : * but caller can make additional checks and pass indexOK=false if needed.
168 : * In standard case indexOK can simply be constant TRUE.
169 : */
170 : SysScanDesc
171 : systable_beginscan(Relation heapRelation,
172 : Oid indexId,
173 : bool indexOK,
174 : Snapshot snapshot,
175 : int nkeys, ScanKey key)
176 114256 : {
177 : SysScanDesc sysscan;
178 : Relation irel;
179 :
180 222987 : if (indexOK &&
181 : !IgnoreSystemIndexes &&
182 : !ReindexIsProcessingIndex(indexId))
183 108731 : irel = index_open(indexId, AccessShareLock);
184 : else
185 5525 : irel = NULL;
186 :
187 114256 : sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
188 :
189 114256 : sysscan->heap_rel = heapRelation;
190 114256 : sysscan->irel = irel;
191 :
192 114256 : if (irel)
193 : {
194 : int i;
195 :
196 : /*
197 : * Change attribute numbers to be index column numbers.
198 : *
199 : * This code could be generalized to search for the index key numbers
200 : * to substitute, but for now there's no need.
201 : */
202 293440 : for (i = 0; i < nkeys; i++)
203 : {
204 : Assert(key[i].sk_attno == irel->rd_index->indkey.values[i]);
205 184709 : key[i].sk_attno = i + 1;
206 : }
207 :
208 108731 : sysscan->iscan = index_beginscan(heapRelation, irel,
209 : snapshot, nkeys, key);
210 108731 : sysscan->scan = NULL;
211 : }
212 : else
213 : {
214 5525 : sysscan->scan = heap_beginscan(heapRelation, snapshot, nkeys, key);
215 5525 : sysscan->iscan = NULL;
216 : }
217 :
218 114256 : return sysscan;
219 : }
220 :
221 : /*
222 : * systable_getnext --- get next tuple in a heap-or-index scan
223 : *
224 : * Returns NULL if no more tuples available.
225 : *
226 : * Note that returned tuple is a reference to data in a disk buffer;
227 : * it must not be modified, and should be presumed inaccessible after
228 : * next getnext() or endscan() call.
229 : */
230 : HeapTuple
231 : systable_getnext(SysScanDesc sysscan)
232 196364 : {
233 : HeapTuple htup;
234 :
235 196364 : if (sysscan->irel)
236 179663 : htup = index_getnext(sysscan->iscan, ForwardScanDirection);
237 : else
238 16701 : htup = heap_getnext(sysscan->scan, ForwardScanDirection);
239 :
240 196364 : return htup;
241 : }
242 :
243 : /*
244 : * systable_endscan --- close scan, release resources
245 : *
246 : * Note that it's still up to the caller to close the heap relation.
247 : */
248 : void
249 : systable_endscan(SysScanDesc sysscan)
250 114246 : {
251 114246 : if (sysscan->irel)
252 : {
253 108721 : index_endscan(sysscan->iscan);
254 108721 : index_close(sysscan->irel, AccessShareLock);
255 : }
256 : else
257 5525 : heap_endscan(sysscan->scan);
258 :
259 114246 : pfree(sysscan);
260 114246 : }
|