Header And Logo

PostgreSQL
| The world's most advanced open source database.

indexam.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * indexam.c
00004  *    general index access method routines
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/access/index/indexam.c
00012  *
00013  * INTERFACE ROUTINES
00014  *      index_open      - open an index relation by relation OID
00015  *      index_close     - close an index relation
00016  *      index_beginscan - start a scan of an index with amgettuple
00017  *      index_beginscan_bitmap - start a scan of an index with amgetbitmap
00018  *      index_rescan    - restart a scan of an index
00019  *      index_endscan   - end a scan
00020  *      index_insert    - insert an index tuple into a relation
00021  *      index_markpos   - mark a scan position
00022  *      index_restrpos  - restore a scan position
00023  *      index_getnext_tid   - get the next TID from a scan
00024  *      index_fetch_heap        - get the scan's next heap tuple
00025  *      index_getnext   - get the next heap tuple from a scan
00026  *      index_getbitmap - get all tuples from a scan
00027  *      index_bulk_delete   - bulk deletion of index tuples
00028  *      index_vacuum_cleanup    - post-deletion cleanup of an index
00029  *      index_can_return    - does index support index-only scans?
00030  *      index_getprocid - get a support procedure OID
00031  *      index_getprocinfo - get a support procedure's lookup info
00032  *
00033  * NOTES
00034  *      This file contains the index_ routines which used
00035  *      to be a scattered collection of stuff in access/genam.
00036  *
00037  *
00038  * old comments
00039  *      Scans are implemented as follows:
00040  *
00041  *      `0' represents an invalid item pointer.
00042  *      `-' represents an unknown item pointer.
00043  *      `X' represents a known item pointers.
00044  *      `+' represents known or invalid item pointers.
00045  *      `*' represents any item pointers.
00046  *
00047  *      State is represented by a triple of these symbols in the order of
00048  *      previous, current, next.  Note that the case of reverse scans works
00049  *      identically.
00050  *
00051  *              State   Result
00052  *      (1)     + + -   + 0 0           (if the next item pointer is invalid)
00053  *      (2)             + X -           (otherwise)
00054  *      (3)     * 0 0   * 0 0           (no change)
00055  *      (4)     + X 0   X 0 0           (shift)
00056  *      (5)     * + X   + X -           (shift, add unknown)
00057  *
00058  *      All other states cannot occur.
00059  *
00060  *      Note: It would be possible to cache the status of the previous and
00061  *            next item pointer using the flags.
00062  *
00063  *-------------------------------------------------------------------------
00064  */
00065 
00066 #include "postgres.h"
00067 
00068 #include "access/relscan.h"
00069 #include "access/transam.h"
00070 #include "catalog/index.h"
00071 #include "pgstat.h"
00072 #include "storage/bufmgr.h"
00073 #include "storage/lmgr.h"
00074 #include "storage/predicate.h"
00075 #include "utils/snapmgr.h"
00076 #include "utils/tqual.h"
00077 
00078 
00079 /* ----------------------------------------------------------------
00080  *                  macros used in index_ routines
00081  *
00082  * Note: the ReindexIsProcessingIndex() check in RELATION_CHECKS is there
00083  * to check that we don't try to scan or do retail insertions into an index
00084  * that is currently being rebuilt or pending rebuild.  This helps to catch
00085  * things that don't work when reindexing system catalogs.  The assertion
00086  * doesn't prevent the actual rebuild because we don't use RELATION_CHECKS
00087  * when calling the index AM's ambuild routine, and there is no reason for
00088  * ambuild to call its subsidiary routines through this file.
00089  * ----------------------------------------------------------------
00090  */
00091 #define RELATION_CHECKS \
00092 ( \
00093     AssertMacro(RelationIsValid(indexRelation)), \
00094     AssertMacro(PointerIsValid(indexRelation->rd_am)), \
00095     AssertMacro(!ReindexIsProcessingIndex(RelationGetRelid(indexRelation))) \
00096 )
00097 
00098 #define SCAN_CHECKS \
00099 ( \
00100     AssertMacro(IndexScanIsValid(scan)), \
00101     AssertMacro(RelationIsValid(scan->indexRelation)), \
00102     AssertMacro(PointerIsValid(scan->indexRelation->rd_am)) \
00103 )
00104 
00105 #define GET_REL_PROCEDURE(pname) \
00106 do { \
00107     procedure = &indexRelation->rd_aminfo->pname; \
00108     if (!OidIsValid(procedure->fn_oid)) \
00109     { \
00110         RegProcedure    procOid = indexRelation->rd_am->pname; \
00111         if (!RegProcedureIsValid(procOid)) \
00112             elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
00113         fmgr_info_cxt(procOid, procedure, indexRelation->rd_indexcxt); \
00114     } \
00115 } while(0)
00116 
00117 #define GET_UNCACHED_REL_PROCEDURE(pname) \
00118 do { \
00119     if (!RegProcedureIsValid(indexRelation->rd_am->pname)) \
00120         elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
00121     fmgr_info(indexRelation->rd_am->pname, &procedure); \
00122 } while(0)
00123 
00124 #define GET_SCAN_PROCEDURE(pname) \
00125 do { \
00126     procedure = &scan->indexRelation->rd_aminfo->pname; \
00127     if (!OidIsValid(procedure->fn_oid)) \
00128     { \
00129         RegProcedure    procOid = scan->indexRelation->rd_am->pname; \
00130         if (!RegProcedureIsValid(procOid)) \
00131             elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
00132         fmgr_info_cxt(procOid, procedure, scan->indexRelation->rd_indexcxt); \
00133     } \
00134 } while(0)
00135 
00136 static IndexScanDesc index_beginscan_internal(Relation indexRelation,
00137                          int nkeys, int norderbys, Snapshot snapshot);
00138 
00139 
00140 /* ----------------------------------------------------------------
00141  *                 index_ interface functions
00142  * ----------------------------------------------------------------
00143  */
00144 
00145 /* ----------------
00146  *      index_open - open an index relation by relation OID
00147  *
00148  *      If lockmode is not "NoLock", the specified kind of lock is
00149  *      obtained on the index.  (Generally, NoLock should only be
00150  *      used if the caller knows it has some appropriate lock on the
00151  *      index already.)
00152  *
00153  *      An error is raised if the index does not exist.
00154  *
00155  *      This is a convenience routine adapted for indexscan use.
00156  *      Some callers may prefer to use relation_open directly.
00157  * ----------------
00158  */
00159 Relation
00160 index_open(Oid relationId, LOCKMODE lockmode)
00161 {
00162     Relation    r;
00163 
00164     r = relation_open(relationId, lockmode);
00165 
00166     if (r->rd_rel->relkind != RELKIND_INDEX)
00167         ereport(ERROR,
00168                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00169                  errmsg("\"%s\" is not an index",
00170                         RelationGetRelationName(r))));
00171 
00172     return r;
00173 }
00174 
00175 /* ----------------
00176  *      index_close - close an index relation
00177  *
00178  *      If lockmode is not "NoLock", we then release the specified lock.
00179  *
00180  *      Note that it is often sensible to hold a lock beyond index_close;
00181  *      in that case, the lock is released automatically at xact end.
00182  * ----------------
00183  */
00184 void
00185 index_close(Relation relation, LOCKMODE lockmode)
00186 {
00187     LockRelId   relid = relation->rd_lockInfo.lockRelId;
00188 
00189     Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
00190 
00191     /* The relcache does the real work... */
00192     RelationClose(relation);
00193 
00194     if (lockmode != NoLock)
00195         UnlockRelationId(&relid, lockmode);
00196 }
00197 
00198 /* ----------------
00199  *      index_insert - insert an index tuple into a relation
00200  * ----------------
00201  */
00202 bool
00203 index_insert(Relation indexRelation,
00204              Datum *values,
00205              bool *isnull,
00206              ItemPointer heap_t_ctid,
00207              Relation heapRelation,
00208              IndexUniqueCheck checkUnique)
00209 {
00210     FmgrInfo   *procedure;
00211 
00212     RELATION_CHECKS;
00213     GET_REL_PROCEDURE(aminsert);
00214 
00215     if (!(indexRelation->rd_am->ampredlocks))
00216         CheckForSerializableConflictIn(indexRelation,
00217                                        (HeapTuple) NULL,
00218                                        InvalidBuffer);
00219 
00220     /*
00221      * have the am's insert proc do all the work.
00222      */
00223     return DatumGetBool(FunctionCall6(procedure,
00224                                       PointerGetDatum(indexRelation),
00225                                       PointerGetDatum(values),
00226                                       PointerGetDatum(isnull),
00227                                       PointerGetDatum(heap_t_ctid),
00228                                       PointerGetDatum(heapRelation),
00229                                       Int32GetDatum((int32) checkUnique)));
00230 }
00231 
00232 /*
00233  * index_beginscan - start a scan of an index with amgettuple
00234  *
00235  * Caller must be holding suitable locks on the heap and the index.
00236  */
00237 IndexScanDesc
00238 index_beginscan(Relation heapRelation,
00239                 Relation indexRelation,
00240                 Snapshot snapshot,
00241                 int nkeys, int norderbys)
00242 {
00243     IndexScanDesc scan;
00244 
00245     scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot);
00246 
00247     /*
00248      * Save additional parameters into the scandesc.  Everything else was set
00249      * up by RelationGetIndexScan.
00250      */
00251     scan->heapRelation = heapRelation;
00252     scan->xs_snapshot = snapshot;
00253 
00254     return scan;
00255 }
00256 
00257 /*
00258  * index_beginscan_bitmap - start a scan of an index with amgetbitmap
00259  *
00260  * As above, caller had better be holding some lock on the parent heap
00261  * relation, even though it's not explicitly mentioned here.
00262  */
00263 IndexScanDesc
00264 index_beginscan_bitmap(Relation indexRelation,
00265                        Snapshot snapshot,
00266                        int nkeys)
00267 {
00268     IndexScanDesc scan;
00269 
00270     scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot);
00271 
00272     /*
00273      * Save additional parameters into the scandesc.  Everything else was set
00274      * up by RelationGetIndexScan.
00275      */
00276     scan->xs_snapshot = snapshot;
00277 
00278     return scan;
00279 }
00280 
00281 /*
00282  * index_beginscan_internal --- common code for index_beginscan variants
00283  */
00284 static IndexScanDesc
00285 index_beginscan_internal(Relation indexRelation,
00286                          int nkeys, int norderbys, Snapshot snapshot)
00287 {
00288     IndexScanDesc scan;
00289     FmgrInfo   *procedure;
00290 
00291     RELATION_CHECKS;
00292     GET_REL_PROCEDURE(ambeginscan);
00293 
00294     if (!(indexRelation->rd_am->ampredlocks))
00295         PredicateLockRelation(indexRelation, snapshot);
00296 
00297     /*
00298      * We hold a reference count to the relcache entry throughout the scan.
00299      */
00300     RelationIncrementReferenceCount(indexRelation);
00301 
00302     /*
00303      * Tell the AM to open a scan.
00304      */
00305     scan = (IndexScanDesc)
00306         DatumGetPointer(FunctionCall3(procedure,
00307                                       PointerGetDatum(indexRelation),
00308                                       Int32GetDatum(nkeys),
00309                                       Int32GetDatum(norderbys)));
00310 
00311     return scan;
00312 }
00313 
00314 /* ----------------
00315  *      index_rescan  - (re)start a scan of an index
00316  *
00317  * During a restart, the caller may specify a new set of scankeys and/or
00318  * orderbykeys; but the number of keys cannot differ from what index_beginscan
00319  * was told.  (Later we might relax that to "must not exceed", but currently
00320  * the index AMs tend to assume that scan->numberOfKeys is what to believe.)
00321  * To restart the scan without changing keys, pass NULL for the key arrays.
00322  * (Of course, keys *must* be passed on the first call, unless
00323  * scan->numberOfKeys is zero.)
00324  * ----------------
00325  */
00326 void
00327 index_rescan(IndexScanDesc scan,
00328              ScanKey keys, int nkeys,
00329              ScanKey orderbys, int norderbys)
00330 {
00331     FmgrInfo   *procedure;
00332 
00333     SCAN_CHECKS;
00334     GET_SCAN_PROCEDURE(amrescan);
00335 
00336     Assert(nkeys == scan->numberOfKeys);
00337     Assert(norderbys == scan->numberOfOrderBys);
00338 
00339     /* Release any held pin on a heap page */
00340     if (BufferIsValid(scan->xs_cbuf))
00341     {
00342         ReleaseBuffer(scan->xs_cbuf);
00343         scan->xs_cbuf = InvalidBuffer;
00344     }
00345 
00346     scan->xs_continue_hot = false;
00347 
00348     scan->kill_prior_tuple = false;     /* for safety */
00349 
00350     FunctionCall5(procedure,
00351                   PointerGetDatum(scan),
00352                   PointerGetDatum(keys),
00353                   Int32GetDatum(nkeys),
00354                   PointerGetDatum(orderbys),
00355                   Int32GetDatum(norderbys));
00356 }
00357 
00358 /* ----------------
00359  *      index_endscan - end a scan
00360  * ----------------
00361  */
00362 void
00363 index_endscan(IndexScanDesc scan)
00364 {
00365     FmgrInfo   *procedure;
00366 
00367     SCAN_CHECKS;
00368     GET_SCAN_PROCEDURE(amendscan);
00369 
00370     /* Release any held pin on a heap page */
00371     if (BufferIsValid(scan->xs_cbuf))
00372     {
00373         ReleaseBuffer(scan->xs_cbuf);
00374         scan->xs_cbuf = InvalidBuffer;
00375     }
00376 
00377     /* End the AM's scan */
00378     FunctionCall1(procedure, PointerGetDatum(scan));
00379 
00380     /* Release index refcount acquired by index_beginscan */
00381     RelationDecrementReferenceCount(scan->indexRelation);
00382 
00383     /* Release the scan data structure itself */
00384     IndexScanEnd(scan);
00385 }
00386 
00387 /* ----------------
00388  *      index_markpos  - mark a scan position
00389  * ----------------
00390  */
00391 void
00392 index_markpos(IndexScanDesc scan)
00393 {
00394     FmgrInfo   *procedure;
00395 
00396     SCAN_CHECKS;
00397     GET_SCAN_PROCEDURE(ammarkpos);
00398 
00399     FunctionCall1(procedure, PointerGetDatum(scan));
00400 }
00401 
00402 /* ----------------
00403  *      index_restrpos  - restore a scan position
00404  *
00405  * NOTE: this only restores the internal scan state of the index AM.
00406  * The current result tuple (scan->xs_ctup) doesn't change.  See comments
00407  * for ExecRestrPos().
00408  *
00409  * NOTE: in the presence of HOT chains, mark/restore only works correctly
00410  * if the scan's snapshot is MVCC-safe; that ensures that there's at most one
00411  * returnable tuple in each HOT chain, and so restoring the prior state at the
00412  * granularity of the index AM is sufficient.  Since the only current user
00413  * of mark/restore functionality is nodeMergejoin.c, this effectively means
00414  * that merge-join plans only work for MVCC snapshots.  This could be fixed
00415  * if necessary, but for now it seems unimportant.
00416  * ----------------
00417  */
00418 void
00419 index_restrpos(IndexScanDesc scan)
00420 {
00421     FmgrInfo   *procedure;
00422 
00423     Assert(IsMVCCSnapshot(scan->xs_snapshot));
00424 
00425     SCAN_CHECKS;
00426     GET_SCAN_PROCEDURE(amrestrpos);
00427 
00428     scan->xs_continue_hot = false;
00429 
00430     scan->kill_prior_tuple = false;     /* for safety */
00431 
00432     FunctionCall1(procedure, PointerGetDatum(scan));
00433 }
00434 
00435 /* ----------------
00436  * index_getnext_tid - get the next TID from a scan
00437  *
00438  * The result is the next TID satisfying the scan keys,
00439  * or NULL if no more matching tuples exist.
00440  * ----------------
00441  */
00442 ItemPointer
00443 index_getnext_tid(IndexScanDesc scan, ScanDirection direction)
00444 {
00445     FmgrInfo   *procedure;
00446     bool        found;
00447 
00448     SCAN_CHECKS;
00449     GET_SCAN_PROCEDURE(amgettuple);
00450 
00451     Assert(TransactionIdIsValid(RecentGlobalXmin));
00452 
00453     /*
00454      * The AM's amgettuple proc finds the next index entry matching the scan
00455      * keys, and puts the TID into scan->xs_ctup.t_self.  It should also set
00456      * scan->xs_recheck and possibly scan->xs_itup, though we pay no attention
00457      * to those fields here.
00458      */
00459     found = DatumGetBool(FunctionCall2(procedure,
00460                                        PointerGetDatum(scan),
00461                                        Int32GetDatum(direction)));
00462 
00463     /* Reset kill flag immediately for safety */
00464     scan->kill_prior_tuple = false;
00465 
00466     /* If we're out of index entries, we're done */
00467     if (!found)
00468     {
00469         /* ... but first, release any held pin on a heap page */
00470         if (BufferIsValid(scan->xs_cbuf))
00471         {
00472             ReleaseBuffer(scan->xs_cbuf);
00473             scan->xs_cbuf = InvalidBuffer;
00474         }
00475         return NULL;
00476     }
00477 
00478     pgstat_count_index_tuples(scan->indexRelation, 1);
00479 
00480     /* Return the TID of the tuple we found. */
00481     return &scan->xs_ctup.t_self;
00482 }
00483 
00484 /* ----------------
00485  *      index_fetch_heap - get the scan's next heap tuple
00486  *
00487  * The result is a visible heap tuple associated with the index TID most
00488  * recently fetched by index_getnext_tid, or NULL if no more matching tuples
00489  * exist.  (There can be more than one matching tuple because of HOT chains,
00490  * although when using an MVCC snapshot it should be impossible for more than
00491  * one such tuple to exist.)
00492  *
00493  * On success, the buffer containing the heap tup is pinned (the pin will be
00494  * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
00495  * call).
00496  *
00497  * Note: caller must check scan->xs_recheck, and perform rechecking of the
00498  * scan keys if required.  We do not do that here because we don't have
00499  * enough information to do it efficiently in the general case.
00500  * ----------------
00501  */
00502 HeapTuple
00503 index_fetch_heap(IndexScanDesc scan)
00504 {
00505     ItemPointer tid = &scan->xs_ctup.t_self;
00506     bool        all_dead = false;
00507     bool        got_heap_tuple;
00508 
00509     /* We can skip the buffer-switching logic if we're in mid-HOT chain. */
00510     if (!scan->xs_continue_hot)
00511     {
00512         /* Switch to correct buffer if we don't have it already */
00513         Buffer      prev_buf = scan->xs_cbuf;
00514 
00515         scan->xs_cbuf = ReleaseAndReadBuffer(scan->xs_cbuf,
00516                                              scan->heapRelation,
00517                                              ItemPointerGetBlockNumber(tid));
00518 
00519         /*
00520          * Prune page, but only if we weren't already on this page
00521          */
00522         if (prev_buf != scan->xs_cbuf)
00523             heap_page_prune_opt(scan->heapRelation, scan->xs_cbuf,
00524                                 RecentGlobalXmin);
00525     }
00526 
00527     /* Obtain share-lock on the buffer so we can examine visibility */
00528     LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE);
00529     got_heap_tuple = heap_hot_search_buffer(tid, scan->heapRelation,
00530                                             scan->xs_cbuf,
00531                                             scan->xs_snapshot,
00532                                             &scan->xs_ctup,
00533                                             &all_dead,
00534                                             !scan->xs_continue_hot);
00535     LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
00536 
00537     if (got_heap_tuple)
00538     {
00539         /*
00540          * Only in a non-MVCC snapshot can more than one member of the HOT
00541          * chain be visible.
00542          */
00543         scan->xs_continue_hot = !IsMVCCSnapshot(scan->xs_snapshot);
00544         pgstat_count_heap_fetch(scan->indexRelation);
00545         return &scan->xs_ctup;
00546     }
00547 
00548     /* We've reached the end of the HOT chain. */
00549     scan->xs_continue_hot = false;
00550 
00551     /*
00552      * If we scanned a whole HOT chain and found only dead tuples, tell index
00553      * AM to kill its entry for that TID (this will take effect in the next
00554      * amgettuple call, in index_getnext_tid).  We do not do this when in
00555      * recovery because it may violate MVCC to do so.  See comments in
00556      * RelationGetIndexScan().
00557      */
00558     if (!scan->xactStartedInRecovery)
00559         scan->kill_prior_tuple = all_dead;
00560 
00561     return NULL;
00562 }
00563 
00564 /* ----------------
00565  *      index_getnext - get the next heap tuple from a scan
00566  *
00567  * The result is the next heap tuple satisfying the scan keys and the
00568  * snapshot, or NULL if no more matching tuples exist.
00569  *
00570  * On success, the buffer containing the heap tup is pinned (the pin will be
00571  * dropped in a future index_getnext_tid, index_fetch_heap or index_endscan
00572  * call).
00573  *
00574  * Note: caller must check scan->xs_recheck, and perform rechecking of the
00575  * scan keys if required.  We do not do that here because we don't have
00576  * enough information to do it efficiently in the general case.
00577  * ----------------
00578  */
00579 HeapTuple
00580 index_getnext(IndexScanDesc scan, ScanDirection direction)
00581 {
00582     HeapTuple   heapTuple;
00583     ItemPointer tid;
00584 
00585     for (;;)
00586     {
00587         if (scan->xs_continue_hot)
00588         {
00589             /*
00590              * We are resuming scan of a HOT chain after having returned an
00591              * earlier member.  Must still hold pin on current heap page.
00592              */
00593             Assert(BufferIsValid(scan->xs_cbuf));
00594             Assert(ItemPointerGetBlockNumber(&scan->xs_ctup.t_self) ==
00595                    BufferGetBlockNumber(scan->xs_cbuf));
00596         }
00597         else
00598         {
00599             /* Time to fetch the next TID from the index */
00600             tid = index_getnext_tid(scan, direction);
00601 
00602             /* If we're out of index entries, we're done */
00603             if (tid == NULL)
00604                 break;
00605         }
00606 
00607         /*
00608          * Fetch the next (or only) visible heap tuple for this index entry.
00609          * If we don't find anything, loop around and grab the next TID from
00610          * the index.
00611          */
00612         heapTuple = index_fetch_heap(scan);
00613         if (heapTuple != NULL)
00614             return heapTuple;
00615     }
00616 
00617     return NULL;                /* failure exit */
00618 }
00619 
00620 /* ----------------
00621  *      index_getbitmap - get all tuples at once from an index scan
00622  *
00623  * Adds the TIDs of all heap tuples satisfying the scan keys to a bitmap.
00624  * Since there's no interlock between the index scan and the eventual heap
00625  * access, this is only safe to use with MVCC-based snapshots: the heap
00626  * item slot could have been replaced by a newer tuple by the time we get
00627  * to it.
00628  *
00629  * Returns the number of matching tuples found.  (Note: this might be only
00630  * approximate, so it should only be used for statistical purposes.)
00631  * ----------------
00632  */
00633 int64
00634 index_getbitmap(IndexScanDesc scan, TIDBitmap *bitmap)
00635 {
00636     FmgrInfo   *procedure;
00637     int64       ntids;
00638     Datum       d;
00639 
00640     SCAN_CHECKS;
00641     GET_SCAN_PROCEDURE(amgetbitmap);
00642 
00643     /* just make sure this is false... */
00644     scan->kill_prior_tuple = false;
00645 
00646     /*
00647      * have the am's getbitmap proc do all the work.
00648      */
00649     d = FunctionCall2(procedure,
00650                       PointerGetDatum(scan),
00651                       PointerGetDatum(bitmap));
00652 
00653     ntids = DatumGetInt64(d);
00654 
00655     /* If int8 is pass-by-ref, must free the result to avoid memory leak */
00656 #ifndef USE_FLOAT8_BYVAL
00657     pfree(DatumGetPointer(d));
00658 #endif
00659 
00660     pgstat_count_index_tuples(scan->indexRelation, ntids);
00661 
00662     return ntids;
00663 }
00664 
00665 /* ----------------
00666  *      index_bulk_delete - do mass deletion of index entries
00667  *
00668  *      callback routine tells whether a given main-heap tuple is
00669  *      to be deleted
00670  *
00671  *      return value is an optional palloc'd struct of statistics
00672  * ----------------
00673  */
00674 IndexBulkDeleteResult *
00675 index_bulk_delete(IndexVacuumInfo *info,
00676                   IndexBulkDeleteResult *stats,
00677                   IndexBulkDeleteCallback callback,
00678                   void *callback_state)
00679 {
00680     Relation    indexRelation = info->index;
00681     FmgrInfo    procedure;
00682     IndexBulkDeleteResult *result;
00683 
00684     RELATION_CHECKS;
00685     GET_UNCACHED_REL_PROCEDURE(ambulkdelete);
00686 
00687     result = (IndexBulkDeleteResult *)
00688         DatumGetPointer(FunctionCall4(&procedure,
00689                                       PointerGetDatum(info),
00690                                       PointerGetDatum(stats),
00691                                       PointerGetDatum((Pointer) callback),
00692                                       PointerGetDatum(callback_state)));
00693 
00694     return result;
00695 }
00696 
00697 /* ----------------
00698  *      index_vacuum_cleanup - do post-deletion cleanup of an index
00699  *
00700  *      return value is an optional palloc'd struct of statistics
00701  * ----------------
00702  */
00703 IndexBulkDeleteResult *
00704 index_vacuum_cleanup(IndexVacuumInfo *info,
00705                      IndexBulkDeleteResult *stats)
00706 {
00707     Relation    indexRelation = info->index;
00708     FmgrInfo    procedure;
00709     IndexBulkDeleteResult *result;
00710 
00711     RELATION_CHECKS;
00712     GET_UNCACHED_REL_PROCEDURE(amvacuumcleanup);
00713 
00714     result = (IndexBulkDeleteResult *)
00715         DatumGetPointer(FunctionCall2(&procedure,
00716                                       PointerGetDatum(info),
00717                                       PointerGetDatum(stats)));
00718 
00719     return result;
00720 }
00721 
00722 /* ----------------
00723  *      index_can_return - does index support index-only scans?
00724  * ----------------
00725  */
00726 bool
00727 index_can_return(Relation indexRelation)
00728 {
00729     FmgrInfo   *procedure;
00730 
00731     RELATION_CHECKS;
00732 
00733     /* amcanreturn is optional; assume FALSE if not provided by AM */
00734     if (!RegProcedureIsValid(indexRelation->rd_am->amcanreturn))
00735         return false;
00736 
00737     GET_REL_PROCEDURE(amcanreturn);
00738 
00739     return DatumGetBool(FunctionCall1(procedure,
00740                                       PointerGetDatum(indexRelation)));
00741 }
00742 
00743 /* ----------------
00744  *      index_getprocid
00745  *
00746  *      Index access methods typically require support routines that are
00747  *      not directly the implementation of any WHERE-clause query operator
00748  *      and so cannot be kept in pg_amop.  Instead, such routines are kept
00749  *      in pg_amproc.  These registered procedure OIDs are assigned numbers
00750  *      according to a convention established by the access method.
00751  *      The general index code doesn't know anything about the routines
00752  *      involved; it just builds an ordered list of them for
00753  *      each attribute on which an index is defined.
00754  *
00755  *      As of Postgres 8.3, support routines within an operator family
00756  *      are further subdivided by the "left type" and "right type" of the
00757  *      query operator(s) that they support.  The "default" functions for a
00758  *      particular indexed attribute are those with both types equal to
00759  *      the index opclass' opcintype (note that this is subtly different
00760  *      from the indexed attribute's own type: it may be a binary-compatible
00761  *      type instead).  Only the default functions are stored in relcache
00762  *      entries --- access methods can use the syscache to look up non-default
00763  *      functions.
00764  *
00765  *      This routine returns the requested default procedure OID for a
00766  *      particular indexed attribute.
00767  * ----------------
00768  */
00769 RegProcedure
00770 index_getprocid(Relation irel,
00771                 AttrNumber attnum,
00772                 uint16 procnum)
00773 {
00774     RegProcedure *loc;
00775     int         nproc;
00776     int         procindex;
00777 
00778     nproc = irel->rd_am->amsupport;
00779 
00780     Assert(procnum > 0 && procnum <= (uint16) nproc);
00781 
00782     procindex = (nproc * (attnum - 1)) + (procnum - 1);
00783 
00784     loc = irel->rd_support;
00785 
00786     Assert(loc != NULL);
00787 
00788     return loc[procindex];
00789 }
00790 
00791 /* ----------------
00792  *      index_getprocinfo
00793  *
00794  *      This routine allows index AMs to keep fmgr lookup info for
00795  *      support procs in the relcache.  As above, only the "default"
00796  *      functions for any particular indexed attribute are cached.
00797  *
00798  * Note: the return value points into cached data that will be lost during
00799  * any relcache rebuild!  Therefore, either use the callinfo right away,
00800  * or save it only after having acquired some type of lock on the index rel.
00801  * ----------------
00802  */
00803 FmgrInfo *
00804 index_getprocinfo(Relation irel,
00805                   AttrNumber attnum,
00806                   uint16 procnum)
00807 {
00808     FmgrInfo   *locinfo;
00809     int         nproc;
00810     int         procindex;
00811 
00812     nproc = irel->rd_am->amsupport;
00813 
00814     Assert(procnum > 0 && procnum <= (uint16) nproc);
00815 
00816     procindex = (nproc * (attnum - 1)) + (procnum - 1);
00817 
00818     locinfo = irel->rd_supportinfo;
00819 
00820     Assert(locinfo != NULL);
00821 
00822     locinfo += procindex;
00823 
00824     /* Initialize the lookup info if first time through */
00825     if (locinfo->fn_oid == InvalidOid)
00826     {
00827         RegProcedure *loc = irel->rd_support;
00828         RegProcedure procId;
00829 
00830         Assert(loc != NULL);
00831 
00832         procId = loc[procindex];
00833 
00834         /*
00835          * Complain if function was not found during IndexSupportInitialize.
00836          * This should not happen unless the system tables contain bogus
00837          * entries for the index opclass.  (If an AM wants to allow a support
00838          * function to be optional, it can use index_getprocid.)
00839          */
00840         if (!RegProcedureIsValid(procId))
00841             elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
00842                  procnum, attnum, RelationGetRelationName(irel));
00843 
00844         fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
00845     }
00846 
00847     return locinfo;
00848 }