]> granicus.if.org Git - postgresql/blob - src/backend/access/index/indexam.c
New NameStr macro to convert Name to Str. No need for var.data anymore.
[postgresql] / src / backend / access / index / indexam.c
1 /*-------------------------------------------------------------------------
2  *
3  * indexam.c
4  *        general index access method routines
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.37 1999/11/07 23:07:54 momjian Exp $
11  *
12  * INTERFACE ROUTINES
13  *              index_open              - open an index relation by relationId
14  *              index_openr             - open a index relation by name
15  *              index_close             - close a index relation
16  *              index_beginscan - start a scan of an index
17  *              index_rescan    - restart a scan of an index
18  *              index_endscan   - end a scan
19  *              index_insert    - insert an index tuple into a relation
20  *              index_delete    - delete an item from an index relation
21  *              index_markpos   - mark a scan position
22  *              index_restrpos  - restore a scan position
23  *              index_getnext   - get the next tuple from a scan
24  * **   index_fetch             - retrieve tuple with tid
25  * **   index_replace   - replace a tuple
26  * **   index_getattr   - get an attribute from an index tuple
27  *              index_getprocid - get a support procedure id from the rel tuple
28  *
29  *              IndexScanIsValid - check index scan
30  *
31  * NOTES
32  *              This file contains the index_ routines which used
33  *              to be a scattered collection of stuff in access/genam.
34  *
35  *              The ** routines: index_fetch, index_replace, and index_getattr
36  *              have not yet been implemented.  They may not be needed.
37  *
38  * old comments
39  *              Scans are implemented as follows:
40  *
41  *              `0' represents an invalid item pointer.
42  *              `-' represents an unknown item pointer.
43  *              `X' represents a known item pointers.
44  *              `+' represents known or invalid item pointers.
45  *              `*' represents any item pointers.
46  *
47  *              State is represented by a triple of these symbols in the order of
48  *              previous, current, next.  Note that the case of reverse scans works
49  *              identically.
50  *
51  *                              State   Result
52  *              (1)             + + -   + 0 0                   (if the next item pointer is invalid)
53  *              (2)                             + X -                   (otherwise)
54  *              (3)             * 0 0   * 0 0                   (no change)
55  *              (4)             + X 0   X 0 0                   (shift)
56  *              (5)             * + X   + X -                   (shift, add unknown)
57  *
58  *              All other states cannot occur.
59  *
60  *              Note: It would be possible to cache the status of the previous and
61  *                        next item pointer using the flags.
62  *
63  *-------------------------------------------------------------------------
64  */
65
66 #include "postgres.h"
67
68 #include "access/genam.h"
69 #include "access/heapam.h"
70 #include "utils/relcache.h"
71
72 /* ----------------
73  *       undefine macros we aren't going to use that would otherwise
74  *       get in our way..  delete is defined in c.h and the am's are
75  *       defined in heapam.h
76  * ----------------
77  */
78 #undef delete
79 #undef aminsert
80 #undef amdelete
81 #undef ambeginscan
82 #undef amrescan
83 #undef amendscan
84 #undef ammarkpos
85 #undef amrestrpos
86 #undef amgettuple
87
88 /* ----------------------------------------------------------------
89  *                                      macros used in index_ routines
90  * ----------------------------------------------------------------
91  */
92 #define RELATION_CHECKS \
93 ( \
94         AssertMacro(RelationIsValid(relation)), \
95         AssertMacro(PointerIsValid(relation->rd_am)) \
96 )
97
98 #define SCAN_CHECKS \
99 ( \
100         AssertMacro(IndexScanIsValid(scan)), \
101         AssertMacro(RelationIsValid(scan->relation)), \
102         AssertMacro(PointerIsValid(scan->relation->rd_am)) \
103 )
104
105 #define GET_REL_PROCEDURE(x,y) \
106 ( \
107         procedure = relation->rd_am->y, \
108         (!RegProcedureIsValid(procedure)) ? \
109                 elog(ERROR, "index_%s: invalid %s regproc", \
110                         CppAsString(x), CppAsString(y)) \
111         : (void)NULL \
112 )
113
114 #define GET_SCAN_PROCEDURE(x,y) \
115 ( \
116         procedure = scan->relation->rd_am->y, \
117         (!RegProcedureIsValid(procedure)) ? \
118                 elog(ERROR, "index_%s: invalid %s regproc", \
119                         CppAsString(x), CppAsString(y)) \
120         : (void)NULL \
121 )
122
123
124 /* ----------------------------------------------------------------
125  *                                 index_ interface functions
126  * ----------------------------------------------------------------
127  */
128 /* ----------------
129  *              index_open - open an index relation by relationId
130  *
131  *              presently the relcache routines do all the work we need
132  *              to open/close index relations.  However, callers of index_open
133  *              expect it to succeed, so we need to check for a failure return.
134  *
135  *              Note: we acquire no lock on the index.  An AccessShareLock is
136  *              acquired by index_beginscan (and released by index_endscan).
137  * ----------------
138  */
139 Relation
140 index_open(Oid relationId)
141 {
142         Relation        r;
143
144         r = RelationIdGetRelation(relationId);
145
146         if (! RelationIsValid(r))
147                 elog(ERROR, "Index %u does not exist", relationId);
148
149         if (r->rd_rel->relkind != RELKIND_INDEX)
150                 elog(ERROR, "%s is not an index relation", RelationGetRelationName(r));
151
152         return r;
153 }
154
155 /* ----------------
156  *              index_openr - open a index relation by name
157  *
158  *              As above, but lookup by name instead of OID.
159  * ----------------
160  */
161 Relation
162 index_openr(char *relationName)
163 {
164         Relation        r;
165
166         r = RelationNameGetRelation(relationName);
167
168         if (! RelationIsValid(r))
169                 elog(ERROR, "Index '%s' does not exist", relationName);
170
171         if (r->rd_rel->relkind != RELKIND_INDEX)
172                 elog(ERROR, "%s is not an index relation", RelationGetRelationName(r));
173
174         return r;
175 }
176
177 /* ----------------
178  *              index_close - close a index relation
179  *
180  *              presently the relcache routines do all the work we need
181  *              to open/close index relations.
182  * ----------------
183  */
184 void
185 index_close(Relation relation)
186 {
187         RelationClose(relation);
188 }
189
190 /* ----------------
191  *              index_insert - insert an index tuple into a relation
192  * ----------------
193  */
194 InsertIndexResult
195 index_insert(Relation relation,
196                          Datum *datum,
197                          char *nulls,
198                          ItemPointer heap_t_ctid,
199                          Relation heapRel)
200 {
201         RegProcedure procedure;
202         InsertIndexResult specificResult;
203
204         RELATION_CHECKS;
205         GET_REL_PROCEDURE(insert, aminsert);
206
207         /* ----------------
208          *      have the am's insert proc do all the work.
209          * ----------------
210          */
211         specificResult = (InsertIndexResult)
212                 fmgr(procedure, relation, datum, nulls, heap_t_ctid, heapRel, NULL);
213
214         /* must be pfree'ed */
215         return specificResult;
216 }
217
218 /* ----------------
219  *              index_delete - delete an item from an index relation
220  * ----------------
221  */
222 void
223 index_delete(Relation relation, ItemPointer indexItem)
224 {
225         RegProcedure procedure;
226
227         RELATION_CHECKS;
228         GET_REL_PROCEDURE(delete, amdelete);
229
230         fmgr(procedure, relation, indexItem);
231 }
232
233 /* ----------------
234  *              index_beginscan - start a scan of an index
235  * ----------------
236  */
237 IndexScanDesc
238 index_beginscan(Relation relation,
239                                 bool scanFromEnd,
240                                 uint16 numberOfKeys,
241                                 ScanKey key)
242 {
243         IndexScanDesc scandesc;
244         RegProcedure procedure;
245
246         RELATION_CHECKS;
247         GET_REL_PROCEDURE(beginscan, ambeginscan);
248
249         RelationIncrementReferenceCount(relation);
250
251         /* ----------------
252          *      Acquire AccessShareLock for the duration of the scan
253          *
254          *      Note: we could get an SI inval message here and consequently have
255          *      to rebuild the relcache entry.  The refcount increment above
256          *      ensures that we will rebuild it and not just flush it...
257          * ----------------
258          */
259         LockRelation(relation, AccessShareLock);
260
261         scandesc = (IndexScanDesc)
262                 fmgr(procedure, relation, scanFromEnd, numberOfKeys, key);
263
264         return scandesc;
265 }
266
267 /* ----------------
268  *              index_rescan  - restart a scan of an index
269  * ----------------
270  */
271 void
272 index_rescan(IndexScanDesc scan, bool scanFromEnd, ScanKey key)
273 {
274         RegProcedure procedure;
275
276         SCAN_CHECKS;
277         GET_SCAN_PROCEDURE(rescan, amrescan);
278
279         fmgr(procedure, scan, scanFromEnd, key);
280 }
281
282 /* ----------------
283  *              index_endscan - end a scan
284  * ----------------
285  */
286 void
287 index_endscan(IndexScanDesc scan)
288 {
289         RegProcedure procedure;
290
291         SCAN_CHECKS;
292         GET_SCAN_PROCEDURE(endscan, amendscan);
293
294         fmgr(procedure, scan);
295
296         /* Release lock and refcount acquired by index_beginscan */
297
298         UnlockRelation(scan->relation, AccessShareLock);
299
300         RelationDecrementReferenceCount(scan->relation);
301 }
302
303 /* ----------------
304  *              index_markpos  - mark a scan position
305  * ----------------
306  */
307 void
308 index_markpos(IndexScanDesc scan)
309 {
310         RegProcedure procedure;
311
312         SCAN_CHECKS;
313         GET_SCAN_PROCEDURE(markpos, ammarkpos);
314
315         fmgr(procedure, scan);
316 }
317
318 /* ----------------
319  *              index_restrpos  - restore a scan position
320  * ----------------
321  */
322 void
323 index_restrpos(IndexScanDesc scan)
324 {
325         RegProcedure procedure;
326
327         SCAN_CHECKS;
328         GET_SCAN_PROCEDURE(restrpos, amrestrpos);
329
330         fmgr(procedure, scan);
331 }
332
333 /* ----------------
334  *              index_getnext - get the next tuple from a scan
335  *
336  *              A RetrieveIndexResult is a index tuple/heap tuple pair
337  * ----------------
338  */
339 RetrieveIndexResult
340 index_getnext(IndexScanDesc scan,
341                           ScanDirection direction)
342 {
343         RegProcedure procedure;
344         RetrieveIndexResult result;
345
346         SCAN_CHECKS;
347         GET_SCAN_PROCEDURE(getnext, amgettuple);
348
349         /* ----------------
350          *      have the am's gettuple proc do all the work.
351          * ----------------
352          */
353         result = (RetrieveIndexResult) fmgr(procedure, scan, direction);
354
355         return result;
356 }
357
358 /* ----------------
359  *              index_getprocid
360  *
361  *              Some indexed access methods may require support routines that are
362  *              not in the operator class/operator model imposed by pg_am.      These
363  *              access methods may store the OIDs of registered procedures they
364  *              need in pg_amproc.      These registered procedure OIDs are ordered in
365  *              a way that makes sense to the access method, and used only by the
366  *              access method.  The general index code doesn't know anything about
367  *              the routines involved; it just builds an ordered list of them for
368  *              each attribute on which an index is defined.
369  *
370  *              This routine returns the requested procedure OID for a particular
371  *              indexed attribute.
372  * ----------------
373  */
374 RegProcedure
375 index_getprocid(Relation irel,
376                                 AttrNumber attnum,
377                                 uint16 procnum)
378 {
379         RegProcedure *loc;
380         int                     natts;
381
382         natts = irel->rd_rel->relnatts;
383
384         loc = irel->rd_support;
385
386         Assert(loc != NULL);
387
388         return loc[(natts * (procnum - 1)) + (attnum - 1)];
389 }
390
391 Datum
392 GetIndexValue(HeapTuple tuple,
393                           TupleDesc hTupDesc,
394                           int attOff,
395                           AttrNumber *attrNums,
396                           FuncIndexInfo *fInfo,
397                           bool *attNull)
398 {
399         Datum           returnVal;
400         bool            isNull = FALSE;
401
402         if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid)
403         {
404                 int                     i;
405                 Datum      *attData = (Datum *) palloc(FIgetnArgs(fInfo) * sizeof(Datum));
406
407                 for (i = 0; i < FIgetnArgs(fInfo); i++)
408                 {
409                         attData[i] = heap_getattr(tuple,
410                                                                           attrNums[i],
411                                                                           hTupDesc,
412                                                                           attNull);
413                         if (*attNull)
414                                 isNull = TRUE;
415                 }
416                 returnVal = (Datum) fmgr_array_args(FIgetProcOid(fInfo),
417                                                                                         FIgetnArgs(fInfo),
418                                                                                         (char **) attData,
419                                                                                         &isNull);
420                 pfree(attData);
421                 *attNull = isNull;
422         }
423         else
424                 returnVal = heap_getattr(tuple, attrNums[attOff], hTupDesc, attNull);
425
426         return returnVal;
427 }