LTP GCOV extension - code coverage report
Current view: directory - access/index - indexam.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 162
Code covered: 85.2 % Executed lines: 138
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * indexam.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/indexam.c,v 1.100 2007/11/15 21:14:32 momjian Exp $
      12                 :  *
      13                 :  * INTERFACE ROUTINES
      14                 :  *              index_open              - open an index relation by relation OID
      15                 :  *              index_close             - close an index relation
      16                 :  *              index_beginscan - start a scan of an index with amgettuple
      17                 :  *              index_beginscan_multi - start a scan of an index with amgetmulti
      18                 :  *              index_rescan    - restart a scan of an index
      19                 :  *              index_endscan   - end a scan
      20                 :  *              index_insert    - insert an index tuple into a 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_getmulti  - get multiple tuples from a scan
      25                 :  *              index_bulk_delete       - bulk deletion of index tuples
      26                 :  *              index_vacuum_cleanup    - post-deletion cleanup of an index
      27                 :  *              index_getprocid - get a support procedure OID
      28                 :  *              index_getprocinfo - get a support procedure's lookup info
      29                 :  *
      30                 :  * NOTES
      31                 :  *              This file contains the index_ routines which used
      32                 :  *              to be a scattered collection of stuff in access/genam.
      33                 :  *
      34                 :  *
      35                 :  * old comments
      36                 :  *              Scans are implemented as follows:
      37                 :  *
      38                 :  *              `0' represents an invalid item pointer.
      39                 :  *              `-' represents an unknown item pointer.
      40                 :  *              `X' represents a known item pointers.
      41                 :  *              `+' represents known or invalid item pointers.
      42                 :  *              `*' represents any item pointers.
      43                 :  *
      44                 :  *              State is represented by a triple of these symbols in the order of
      45                 :  *              previous, current, next.  Note that the case of reverse scans works
      46                 :  *              identically.
      47                 :  *
      48                 :  *                              State   Result
      49                 :  *              (1)             + + -   + 0 0                   (if the next item pointer is invalid)
      50                 :  *              (2)                             + X -                   (otherwise)
      51                 :  *              (3)             * 0 0   * 0 0                   (no change)
      52                 :  *              (4)             + X 0   X 0 0                   (shift)
      53                 :  *              (5)             * + X   + X -                   (shift, add unknown)
      54                 :  *
      55                 :  *              All other states cannot occur.
      56                 :  *
      57                 :  *              Note: It would be possible to cache the status of the previous and
      58                 :  *                        next item pointer using the flags.
      59                 :  *
      60                 :  *-------------------------------------------------------------------------
      61                 :  */
      62                 : 
      63                 : #include "postgres.h"
      64                 : 
      65                 : #include "access/genam.h"
      66                 : #include "access/heapam.h"
      67                 : #include "access/transam.h"
      68                 : #include "pgstat.h"
      69                 : #include "utils/relcache.h"
      70                 : 
      71                 : 
      72                 : /* ----------------------------------------------------------------
      73                 :  *                                      macros used in index_ routines
      74                 :  * ----------------------------------------------------------------
      75                 :  */
      76                 : #define RELATION_CHECKS \
      77                 : ( \
      78                 :         AssertMacro(RelationIsValid(indexRelation)), \
      79                 :         AssertMacro(PointerIsValid(indexRelation->rd_am)) \
      80                 : )
      81                 : 
      82                 : #define SCAN_CHECKS \
      83                 : ( \
      84                 :         AssertMacro(IndexScanIsValid(scan)), \
      85                 :         AssertMacro(RelationIsValid(scan->indexRelation)), \
      86                 :         AssertMacro(PointerIsValid(scan->indexRelation->rd_am)) \
      87                 : )
      88                 : 
      89                 : #define GET_REL_PROCEDURE(pname) \
      90                 : do { \
      91                 :         procedure = &indexRelation->rd_aminfo->pname; \
      92                 :         if (!OidIsValid(procedure->fn_oid)) \
      93                 :         { \
      94                 :                 RegProcedure    procOid = indexRelation->rd_am->pname; \
      95                 :                 if (!RegProcedureIsValid(procOid)) \
      96                 :                         elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
      97                 :                 fmgr_info_cxt(procOid, procedure, indexRelation->rd_indexcxt); \
      98                 :         } \
      99                 : } while(0)
     100                 : 
     101                 : #define GET_SCAN_PROCEDURE(pname) \
     102                 : do { \
     103                 :         procedure = &scan->indexRelation->rd_aminfo->pname; \
     104                 :         if (!OidIsValid(procedure->fn_oid)) \
     105                 :         { \
     106                 :                 RegProcedure    procOid = scan->indexRelation->rd_am->pname; \
     107                 :                 if (!RegProcedureIsValid(procOid)) \
     108                 :                         elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
     109                 :                 fmgr_info_cxt(procOid, procedure, scan->indexRelation->rd_indexcxt); \
     110                 :         } \
     111                 : } while(0)
     112                 : 
     113                 : static IndexScanDesc index_beginscan_internal(Relation indexRelation,
     114                 :                                                  int nkeys, ScanKey key);
     115                 : 
     116                 : 
     117                 : /* ----------------------------------------------------------------
     118                 :  *                                 index_ interface functions
     119                 :  * ----------------------------------------------------------------
     120                 :  */
     121                 : 
     122                 : /* ----------------
     123                 :  *              index_open - open an index relation by relation OID
     124                 :  *
     125                 :  *              If lockmode is not "NoLock", the specified kind of lock is
     126                 :  *              obtained on the index.  (Generally, NoLock should only be
     127                 :  *              used if the caller knows it has some appropriate lock on the
     128                 :  *              index already.)
     129                 :  *
     130                 :  *              An error is raised if the index does not exist.
     131                 :  *
     132                 :  *              This is a convenience routine adapted for indexscan use.
     133                 :  *              Some callers may prefer to use relation_open directly.
     134                 :  * ----------------
     135                 :  */
     136                 : Relation
     137                 : index_open(Oid relationId, LOCKMODE lockmode)
     138          155852 : {
     139                 :         Relation        r;
     140                 : 
     141          155852 :         r = relation_open(relationId, lockmode);
     142                 : 
     143          155852 :         if (r->rd_rel->relkind != RELKIND_INDEX)
     144               0 :                 ereport(ERROR,
     145                 :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     146                 :                                  errmsg("\"%s\" is not an index",
     147                 :                                                 RelationGetRelationName(r))));
     148                 : 
     149          155852 :         return r;
     150                 : }
     151                 : 
     152                 : /* ----------------
     153                 :  *              index_close - close an index relation
     154                 :  *
     155                 :  *              If lockmode is not "NoLock", we then release the specified lock.
     156                 :  *
     157                 :  *              Note that it is often sensible to hold a lock beyond index_close;
     158                 :  *              in that case, the lock is released automatically at xact end.
     159                 :  * ----------------
     160                 :  */
     161                 : void
     162                 : index_close(Relation relation, LOCKMODE lockmode)
     163          156299 : {
     164          156299 :         LockRelId       relid = relation->rd_lockInfo.lockRelId;
     165                 : 
     166                 :         Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
     167                 : 
     168                 :         /* The relcache does the real work... */
     169          156299 :         RelationClose(relation);
     170                 : 
     171          156299 :         if (lockmode != NoLock)
     172          147585 :                 UnlockRelationId(&relid, lockmode);
     173          156299 : }
     174                 : 
     175                 : /* ----------------
     176                 :  *              index_insert - insert an index tuple into a relation
     177                 :  * ----------------
     178                 :  */
     179                 : bool
     180                 : index_insert(Relation indexRelation,
     181                 :                          Datum *values,
     182                 :                          bool *isnull,
     183                 :                          ItemPointer heap_t_ctid,
     184                 :                          Relation heapRelation,
     185                 :                          bool check_uniqueness)
     186           70122 : {
     187                 :         FmgrInfo   *procedure;
     188                 : 
     189                 :         RELATION_CHECKS;
     190           70122 :         GET_REL_PROCEDURE(aminsert);
     191                 : 
     192                 :         /*
     193                 :          * have the am's insert proc do all the work.
     194                 :          */
     195           70122 :         return DatumGetBool(FunctionCall6(procedure,
     196                 :                                                                           PointerGetDatum(indexRelation),
     197                 :                                                                           PointerGetDatum(values),
     198                 :                                                                           PointerGetDatum(isnull),
     199                 :                                                                           PointerGetDatum(heap_t_ctid),
     200                 :                                                                           PointerGetDatum(heapRelation),
     201                 :                                                                           BoolGetDatum(check_uniqueness)));
     202                 : }
     203                 : 
     204                 : /*
     205                 :  * index_beginscan - start a scan of an index with amgettuple
     206                 :  *
     207                 :  * Note: heapRelation may be NULL if there is no intention of calling
     208                 :  * index_getnext on this scan; index_getnext_indexitem will not use the
     209                 :  * heapRelation link (nor the snapshot).  However, the caller had better
     210                 :  * be holding some kind of lock on the heap relation in any case, to ensure
     211                 :  * no one deletes it (or the index) out from under us.  Caller must also
     212                 :  * be holding a lock on the index.
     213                 :  */
     214                 : IndexScanDesc
     215                 : index_beginscan(Relation heapRelation,
     216                 :                                 Relation indexRelation,
     217                 :                                 Snapshot snapshot,
     218                 :                                 int nkeys, ScanKey key)
     219          118332 : {
     220                 :         IndexScanDesc scan;
     221                 : 
     222          118332 :         scan = index_beginscan_internal(indexRelation, nkeys, key);
     223                 : 
     224                 :         /*
     225                 :          * Save additional parameters into the scandesc.  Everything else was set
     226                 :          * up by RelationGetIndexScan.
     227                 :          */
     228          118332 :         scan->is_multiscan = false;
     229          118332 :         scan->heapRelation = heapRelation;
     230          118332 :         scan->xs_snapshot = snapshot;
     231                 : 
     232          118332 :         return scan;
     233                 : }
     234                 : 
     235                 : /*
     236                 :  * index_beginscan_multi - start a scan of an index with amgetmulti
     237                 :  *
     238                 :  * As above, caller had better be holding some lock on the parent heap
     239                 :  * relation, even though it's not explicitly mentioned here.
     240                 :  */
     241                 : IndexScanDesc
     242                 : index_beginscan_multi(Relation indexRelation,
     243                 :                                           Snapshot snapshot,
     244                 :                                           int nkeys, ScanKey key)
     245             196 : {
     246                 :         IndexScanDesc scan;
     247                 : 
     248             196 :         scan = index_beginscan_internal(indexRelation, nkeys, key);
     249                 : 
     250                 :         /*
     251                 :          * Save additional parameters into the scandesc.  Everything else was set
     252                 :          * up by RelationGetIndexScan.
     253                 :          */
     254             196 :         scan->is_multiscan = true;
     255             196 :         scan->xs_snapshot = snapshot;
     256                 : 
     257             196 :         return scan;
     258                 : }
     259                 : 
     260                 : /*
     261                 :  * index_beginscan_internal --- common code for index_beginscan variants
     262                 :  */
     263                 : static IndexScanDesc
     264                 : index_beginscan_internal(Relation indexRelation,
     265                 :                                                  int nkeys, ScanKey key)
     266          118528 : {
     267                 :         IndexScanDesc scan;
     268                 :         FmgrInfo   *procedure;
     269                 : 
     270                 :         RELATION_CHECKS;
     271          118528 :         GET_REL_PROCEDURE(ambeginscan);
     272                 : 
     273                 :         /*
     274                 :          * We hold a reference count to the relcache entry throughout the scan.
     275                 :          */
     276          118528 :         RelationIncrementReferenceCount(indexRelation);
     277                 : 
     278                 :         /*
     279                 :          * Tell the AM to open a scan.
     280                 :          */
     281          118528 :         scan = (IndexScanDesc)
     282                 :                 DatumGetPointer(FunctionCall3(procedure,
     283                 :                                                                           PointerGetDatum(indexRelation),
     284                 :                                                                           Int32GetDatum(nkeys),
     285                 :                                                                           PointerGetDatum(key)));
     286                 : 
     287          118528 :         return scan;
     288                 : }
     289                 : 
     290                 : /* ----------------
     291                 :  *              index_rescan  - (re)start a scan of an index
     292                 :  *
     293                 :  * The caller may specify a new set of scankeys (but the number of keys
     294                 :  * cannot change).      To restart the scan without changing keys, pass NULL
     295                 :  * for the key array.
     296                 :  *
     297                 :  * Note that this is also called when first starting an indexscan;
     298                 :  * see RelationGetIndexScan.  Keys *must* be passed in that case,
     299                 :  * unless scan->numberOfKeys is zero.
     300                 :  * ----------------
     301                 :  */
     302                 : void
     303                 : index_rescan(IndexScanDesc scan, ScanKey key)
     304          167861 : {
     305                 :         FmgrInfo   *procedure;
     306                 : 
     307                 :         SCAN_CHECKS;
     308          167861 :         GET_SCAN_PROCEDURE(amrescan);
     309                 : 
     310                 :         /* Release any held pin on a heap page */
     311          167861 :         if (BufferIsValid(scan->xs_cbuf))
     312                 :         {
     313           26340 :                 ReleaseBuffer(scan->xs_cbuf);
     314           26340 :                 scan->xs_cbuf = InvalidBuffer;
     315                 :         }
     316                 : 
     317          167861 :         scan->xs_next_hot = InvalidOffsetNumber;
     318                 : 
     319          167861 :         scan->kill_prior_tuple = false;              /* for safety */
     320                 : 
     321          167861 :         FunctionCall2(procedure,
     322                 :                                   PointerGetDatum(scan),
     323                 :                                   PointerGetDatum(key));
     324          167861 : }
     325                 : 
     326                 : /* ----------------
     327                 :  *              index_endscan - end a scan
     328                 :  * ----------------
     329                 :  */
     330                 : void
     331                 : index_endscan(IndexScanDesc scan)
     332          118502 : {
     333                 :         FmgrInfo   *procedure;
     334                 : 
     335                 :         SCAN_CHECKS;
     336          118502 :         GET_SCAN_PROCEDURE(amendscan);
     337                 : 
     338                 :         /* Release any held pin on a heap page */
     339          118502 :         if (BufferIsValid(scan->xs_cbuf))
     340                 :         {
     341           70075 :                 ReleaseBuffer(scan->xs_cbuf);
     342           70075 :                 scan->xs_cbuf = InvalidBuffer;
     343                 :         }
     344                 : 
     345                 :         /* End the AM's scan */
     346          118502 :         FunctionCall1(procedure, PointerGetDatum(scan));
     347                 : 
     348                 :         /* Release index refcount acquired by index_beginscan */
     349          118502 :         RelationDecrementReferenceCount(scan->indexRelation);
     350                 : 
     351                 :         /* Release the scan data structure itself */
     352          118502 :         IndexScanEnd(scan);
     353          118502 : }
     354                 : 
     355                 : /* ----------------
     356                 :  *              index_markpos  - mark a scan position
     357                 :  * ----------------
     358                 :  */
     359                 : void
     360                 : index_markpos(IndexScanDesc scan)
     361               0 : {
     362                 :         FmgrInfo   *procedure;
     363                 : 
     364                 :         SCAN_CHECKS;
     365               0 :         GET_SCAN_PROCEDURE(ammarkpos);
     366                 : 
     367               0 :         FunctionCall1(procedure, PointerGetDatum(scan));
     368               0 : }
     369                 : 
     370                 : /* ----------------
     371                 :  *              index_restrpos  - restore a scan position
     372                 :  *
     373                 :  * NOTE: this only restores the internal scan state of the index AM.
     374                 :  * The current result tuple (scan->xs_ctup) doesn't change.  See comments
     375                 :  * for ExecRestrPos().
     376                 :  *
     377                 :  * NOTE: in the presence of HOT chains, mark/restore only works correctly
     378                 :  * if the scan's snapshot is MVCC-safe; that ensures that there's at most one
     379                 :  * returnable tuple in each HOT chain, and so restoring the prior state at the
     380                 :  * granularity of the index AM is sufficient.  Since the only current user
     381                 :  * of mark/restore functionality is nodeMergejoin.c, this effectively means
     382                 :  * that merge-join plans only work for MVCC snapshots.  This could be fixed
     383                 :  * if necessary, but for now it seems unimportant.
     384                 :  * ----------------
     385                 :  */
     386                 : void
     387                 : index_restrpos(IndexScanDesc scan)
     388               0 : {
     389                 :         FmgrInfo   *procedure;
     390                 : 
     391                 :         Assert(IsMVCCSnapshot(scan->xs_snapshot));
     392                 : 
     393                 :         SCAN_CHECKS;
     394               0 :         GET_SCAN_PROCEDURE(amrestrpos);
     395                 : 
     396               0 :         scan->xs_next_hot = InvalidOffsetNumber;
     397                 : 
     398               0 :         scan->kill_prior_tuple = false;              /* for safety */
     399                 : 
     400               0 :         FunctionCall1(procedure, PointerGetDatum(scan));
     401               0 : }
     402                 : 
     403                 : /* ----------------
     404                 :  *              index_getnext - get the next heap tuple from a scan
     405                 :  *
     406                 :  * The result is the next heap tuple satisfying the scan keys and the
     407                 :  * snapshot, or NULL if no more matching tuples exist.  On success,
     408                 :  * the buffer containing the heap tuple is pinned (the pin will be dropped
     409                 :  * at the next index_getnext or index_endscan).
     410                 :  * ----------------
     411                 :  */
     412                 : HeapTuple
     413                 : index_getnext(IndexScanDesc scan, ScanDirection direction)
     414          240936 : {
     415          240936 :         HeapTuple       heapTuple = &scan->xs_ctup;
     416          240936 :         ItemPointer tid = &heapTuple->t_self;
     417                 :         FmgrInfo   *procedure;
     418                 : 
     419                 :         SCAN_CHECKS;
     420          240936 :         GET_SCAN_PROCEDURE(amgettuple);
     421                 : 
     422                 :         /*
     423                 :          * We always reset xs_hot_dead; if we are here then either we are just
     424                 :          * starting the scan, or we previously returned a visible tuple, and in
     425                 :          * either case it's inappropriate to kill the prior index entry.
     426                 :          */
     427          240936 :         scan->xs_hot_dead = false;
     428                 : 
     429                 :         for (;;)
     430                 :         {
     431                 :                 OffsetNumber offnum;
     432                 :                 bool            at_chain_start;
     433                 :                 Page            dp;
     434                 : 
     435          248965 :                 if (scan->xs_next_hot != InvalidOffsetNumber)
     436                 :                 {
     437                 :                         /*
     438                 :                          * We are resuming scan of a HOT chain after having returned an
     439                 :                          * earlier member.      Must still hold pin on current heap page.
     440                 :                          */
     441                 :                         Assert(BufferIsValid(scan->xs_cbuf));
     442                 :                         Assert(ItemPointerGetBlockNumber(tid) ==
     443                 :                                    BufferGetBlockNumber(scan->xs_cbuf));
     444                 :                         Assert(TransactionIdIsValid(scan->xs_prev_xmax));
     445               0 :                         offnum = scan->xs_next_hot;
     446               0 :                         at_chain_start = false;
     447               0 :                         scan->xs_next_hot = InvalidOffsetNumber;
     448                 :                 }
     449                 :                 else
     450                 :                 {
     451                 :                         bool            found;
     452                 :                         Buffer          prev_buf;
     453                 : 
     454                 :                         /*
     455                 :                          * If we scanned a whole HOT chain and found only dead tuples,
     456                 :                          * tell index AM to kill its entry for that TID.
     457                 :                          */
     458          248965 :                         scan->kill_prior_tuple = scan->xs_hot_dead;
     459                 : 
     460                 :                         /*
     461                 :                          * The AM's gettuple proc finds the next index entry matching the
     462                 :                          * scan keys, and puts the TID in xs_ctup.t_self (ie, *tid).
     463                 :                          */
     464          248965 :                         found = DatumGetBool(FunctionCall2(procedure,
     465                 :                                                                                            PointerGetDatum(scan),
     466                 :                                                                                            Int32GetDatum(direction)));
     467                 : 
     468                 :                         /* Reset kill flag immediately for safety */
     469          248965 :                         scan->kill_prior_tuple = false;
     470                 : 
     471                 :                         /* If we're out of index entries, break out of outer loop */
     472          248965 :                         if (!found)
     473           66754 :                                 break;
     474                 : 
     475          182211 :                         pgstat_count_index_tuples(scan->indexRelation, 1);
     476                 : 
     477                 :                         /* Switch to correct buffer if we don't have it already */
     478          182211 :                         prev_buf = scan->xs_cbuf;
     479          182211 :                         scan->xs_cbuf = ReleaseAndReadBuffer(scan->xs_cbuf,
     480                 :                                                                                                  scan->heapRelation,
     481                 :                                                                                          ItemPointerGetBlockNumber(tid));
     482                 : 
     483                 :                         /*
     484                 :                          * Prune page, but only if we weren't already on this page
     485                 :                          */
     486          182211 :                         if (prev_buf != scan->xs_cbuf)
     487          121855 :                                 heap_page_prune_opt(scan->heapRelation, scan->xs_cbuf,
     488                 :                                                                         RecentGlobalXmin);
     489                 : 
     490                 :                         /* Prepare to scan HOT chain starting at index-referenced offnum */
     491          182211 :                         offnum = ItemPointerGetOffsetNumber(tid);
     492          182211 :                         at_chain_start = true;
     493                 : 
     494                 :                         /* We don't know what the first tuple's xmin should be */
     495          182211 :                         scan->xs_prev_xmax = InvalidTransactionId;
     496                 : 
     497                 :                         /* Initialize flag to detect if all entries are dead */
     498          182211 :                         scan->xs_hot_dead = true;
     499                 :                 }
     500                 : 
     501                 :                 /* Obtain share-lock on the buffer so we can examine visibility */
     502          182211 :                 LockBuffer(scan->xs_cbuf, BUFFER_LOCK_SHARE);
     503                 : 
     504          182211 :                 dp = (Page) BufferGetPage(scan->xs_cbuf);
     505                 : 
     506                 :                 /* Scan through possible multiple members of HOT-chain */
     507                 :                 for (;;)
     508                 :                 {
     509                 :                         ItemId          lp;
     510                 :                         ItemPointer ctid;
     511                 : 
     512                 :                         /* check for bogus TID */
     513          199396 :                         if (offnum < FirstOffsetNumber ||
     514                 :                                 offnum > PageGetMaxOffsetNumber(dp))
     515                 :                                 break;
     516                 : 
     517          199396 :                         lp = PageGetItemId(dp, offnum);
     518                 : 
     519                 :                         /* check for unused, dead, or redirected items */
     520          199396 :                         if (!ItemIdIsNormal(lp))
     521                 :                         {
     522                 :                                 /* We should only see a redirect at start of chain */
     523            3140 :                                 if (ItemIdIsRedirected(lp) && at_chain_start)
     524                 :                                 {
     525                 :                                         /* Follow the redirect */
     526            2502 :                                         offnum = ItemIdGetRedirect(lp);
     527            2502 :                                         at_chain_start = false;
     528            2502 :                                         continue;
     529                 :                                 }
     530                 :                                 /* else must be end of chain */
     531                 :                                 break;
     532                 :                         }
     533                 : 
     534                 :                         /*
     535                 :                          * We must initialize all of *heapTuple (ie, scan->xs_ctup) since
     536                 :                          * it is returned to the executor on success.
     537                 :                          */
     538          196256 :                         heapTuple->t_data = (HeapTupleHeader) PageGetItem(dp, lp);
     539          196256 :                         heapTuple->t_len = ItemIdGetLength(lp);
     540          196256 :                         ItemPointerSetOffsetNumber(tid, offnum);
     541          196256 :                         heapTuple->t_tableOid = RelationGetRelid(scan->heapRelation);
     542          196256 :                         ctid = &heapTuple->t_data->t_ctid;
     543                 : 
     544                 :                         /*
     545                 :                          * Shouldn't see a HEAP_ONLY tuple at chain start.  (This test
     546                 :                          * should be unnecessary, since the chain root can't be removed
     547                 :                          * while we have pin on the index entry, but let's make it
     548                 :                          * anyway.)
     549                 :                          */
     550          196256 :                         if (at_chain_start && HeapTupleIsHeapOnly(heapTuple))
     551               0 :                                 break;
     552                 : 
     553                 :                         /*
     554                 :                          * The xmin should match the previous xmax value, else chain is
     555                 :                          * broken.      (Note: this test is not optional because it protects
     556                 :                          * us against the case where the prior chain member's xmax aborted
     557                 :                          * since we looked at it.)
     558                 :                          */
     559          196256 :                         if (TransactionIdIsValid(scan->xs_prev_xmax) &&
     560                 :                                 !TransactionIdEquals(scan->xs_prev_xmax,
     561                 :                                                                   HeapTupleHeaderGetXmin(heapTuple->t_data)))
     562               0 :                                 break;
     563                 : 
     564                 :                         /* If it's visible per the snapshot, we must return it */
     565          196256 :                         if (HeapTupleSatisfiesVisibility(heapTuple, scan->xs_snapshot,
     566                 :                                                                                          scan->xs_cbuf))
     567                 :                         {
     568                 :                                 /*
     569                 :                                  * If the snapshot is MVCC, we know that it could accept at
     570                 :                                  * most one member of the HOT chain, so we can skip examining
     571                 :                                  * any more members.  Otherwise, check for continuation of the
     572                 :                                  * HOT-chain, and set state for next time.
     573                 :                                  */
     574          174182 :                                 if (IsMVCCSnapshot(scan->xs_snapshot))
     575           33595 :                                         scan->xs_next_hot = InvalidOffsetNumber;
     576          140588 :                                 else if (HeapTupleIsHotUpdated(heapTuple))
     577                 :                                 {
     578                 :                                         Assert(ItemPointerGetBlockNumber(ctid) ==
     579                 :                                                    ItemPointerGetBlockNumber(tid));
     580               1 :                                         scan->xs_next_hot = ItemPointerGetOffsetNumber(ctid);
     581               1 :                                         scan->xs_prev_xmax = HeapTupleHeaderGetXmax(heapTuple->t_data);
     582                 :                                 }
     583                 :                                 else
     584          140586 :                                         scan->xs_next_hot = InvalidOffsetNumber;
     585                 : 
     586          174182 :                                 LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
     587                 : 
     588          174182 :                                 pgstat_count_heap_fetch(scan->indexRelation);
     589                 : 
     590          174182 :                                 return heapTuple;
     591                 :                         }
     592                 : 
     593                 :                         /*
     594                 :                          * If we can't see it, maybe no one else can either.  Check to see
     595                 :                          * if the tuple is dead to all transactions.  If we find that all
     596                 :                          * the tuples in the HOT chain are dead, we'll signal the index AM
     597                 :                          * to not return that TID on future indexscans.
     598                 :                          */
     599           22074 :                         if (scan->xs_hot_dead &&
     600                 :                                 HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin,
     601                 :                                                                                  scan->xs_cbuf) != HEAPTUPLE_DEAD)
     602           10079 :                                 scan->xs_hot_dead = false;
     603                 : 
     604                 :                         /*
     605                 :                          * Check to see if HOT chain continues past this tuple; if so
     606                 :                          * fetch the next offnum (we don't bother storing it into
     607                 :                          * xs_next_hot, but must store xs_prev_xmax), and loop around.
     608                 :                          */
     609           22074 :                         if (HeapTupleIsHotUpdated(heapTuple))
     610                 :                         {
     611                 :                                 Assert(ItemPointerGetBlockNumber(ctid) ==
     612                 :                                            ItemPointerGetBlockNumber(tid));
     613           14683 :                                 offnum = ItemPointerGetOffsetNumber(ctid);
     614           14683 :                                 at_chain_start = false;
     615           14683 :                                 scan->xs_prev_xmax = HeapTupleHeaderGetXmax(heapTuple->t_data);
     616                 :                         }
     617                 :                         else
     618                 :                                 break;                  /* end of chain */
     619                 :                 }                                               /* loop over a single HOT chain */
     620                 : 
     621            8029 :                 LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
     622                 : 
     623                 :                 /* Loop around to ask index AM for another TID */
     624            8029 :                 scan->xs_next_hot = InvalidOffsetNumber;
     625            8029 :         }
     626                 : 
     627                 :         /* Release any held pin on a heap page */
     628           66754 :         if (BufferIsValid(scan->xs_cbuf))
     629                 :         {
     630           16800 :                 ReleaseBuffer(scan->xs_cbuf);
     631           16800 :                 scan->xs_cbuf = InvalidBuffer;
     632                 :         }
     633                 : 
     634           66754 :         return NULL;                            /* failure exit */
     635                 : }
     636                 : 
     637                 : /* ----------------
     638                 :  *              index_getnext_indexitem - get the next index tuple from a scan
     639                 :  *
     640                 :  * Finds the next index tuple satisfying the scan keys.  Note that the
     641                 :  * corresponding heap tuple is not accessed, and thus no time qual (snapshot)
     642                 :  * check is done, other than the index AM's internal check for killed tuples
     643                 :  * (which most callers of this routine will probably want to suppress by
     644                 :  * setting scan->ignore_killed_tuples = false).
     645                 :  *
     646                 :  * On success (TRUE return), the heap TID of the found index entry is in
     647                 :  * scan->xs_ctup.t_self.  scan->xs_cbuf is untouched.
     648                 :  * ----------------
     649                 :  */
     650                 : bool
     651                 : index_getnext_indexitem(IndexScanDesc scan,
     652                 :                                                 ScanDirection direction)
     653               0 : {
     654                 :         FmgrInfo   *procedure;
     655                 :         bool            found;
     656                 : 
     657                 :         SCAN_CHECKS;
     658               0 :         GET_SCAN_PROCEDURE(amgettuple);
     659                 : 
     660                 :         /* just make sure this is false... */
     661               0 :         scan->kill_prior_tuple = false;
     662                 : 
     663                 :         /*
     664                 :          * have the am's gettuple proc do all the work.
     665                 :          */
     666               0 :         found = DatumGetBool(FunctionCall2(procedure,
     667                 :                                                                            PointerGetDatum(scan),
     668                 :                                                                            Int32GetDatum(direction)));
     669                 : 
     670               0 :         if (found)
     671               0 :                 pgstat_count_index_tuples(scan->indexRelation, 1);
     672                 : 
     673               0 :         return found;
     674                 : }
     675                 : 
     676                 : /* ----------------
     677                 :  *              index_getmulti - get multiple tuples from an index scan
     678                 :  *
     679                 :  * Collects the TIDs of multiple heap tuples satisfying the scan keys.
     680                 :  * Since there's no interlock between the index scan and the eventual heap
     681                 :  * access, this is only safe to use with MVCC-based snapshots: the heap
     682                 :  * item slot could have been replaced by a newer tuple by the time we get
     683                 :  * to it.
     684                 :  *
     685                 :  * A TRUE result indicates more calls should occur; a FALSE result says the
     686                 :  * scan is done.  *returned_tids could be zero or nonzero in either case.
     687                 :  * ----------------
     688                 :  */
     689                 : bool
     690                 : index_getmulti(IndexScanDesc scan,
     691                 :                            ItemPointer tids, int32 max_tids,
     692                 :                            int32 *returned_tids)
     693             353 : {
     694                 :         FmgrInfo   *procedure;
     695                 :         bool            found;
     696                 : 
     697                 :         SCAN_CHECKS;
     698             353 :         GET_SCAN_PROCEDURE(amgetmulti);
     699                 : 
     700                 :         /* just make sure this is false... */
     701             353 :         scan->kill_prior_tuple = false;
     702                 : 
     703                 :         /*
     704                 :          * have the am's getmulti proc do all the work.
     705                 :          */
     706             353 :         found = DatumGetBool(FunctionCall4(procedure,
     707                 :                                                                            PointerGetDatum(scan),
     708                 :                                                                            PointerGetDatum(tids),
     709                 :                                                                            Int32GetDatum(max_tids),
     710                 :                                                                            PointerGetDatum(returned_tids)));
     711                 : 
     712             353 :         pgstat_count_index_tuples(scan->indexRelation, *returned_tids);
     713                 : 
     714             353 :         return found;
     715                 : }
     716                 : 
     717                 : /* ----------------
     718                 :  *              index_bulk_delete - do mass deletion of index entries
     719                 :  *
     720                 :  *              callback routine tells whether a given main-heap tuple is
     721                 :  *              to be deleted
     722                 :  *
     723                 :  *              return value is an optional palloc'd struct of statistics
     724                 :  * ----------------
     725                 :  */
     726                 : IndexBulkDeleteResult *
     727                 : index_bulk_delete(IndexVacuumInfo *info,
     728                 :                                   IndexBulkDeleteResult *stats,
     729                 :                                   IndexBulkDeleteCallback callback,
     730                 :                                   void *callback_state)
     731              70 : {
     732              70 :         Relation        indexRelation = info->index;
     733                 :         FmgrInfo   *procedure;
     734                 :         IndexBulkDeleteResult *result;
     735                 : 
     736                 :         RELATION_CHECKS;
     737              70 :         GET_REL_PROCEDURE(ambulkdelete);
     738                 : 
     739              70 :         result = (IndexBulkDeleteResult *)
     740                 :                 DatumGetPointer(FunctionCall4(procedure,
     741                 :                                                                           PointerGetDatum(info),
     742                 :                                                                           PointerGetDatum(stats),
     743                 :                                                                           PointerGetDatum((Pointer) callback),
     744                 :                                                                           PointerGetDatum(callback_state)));
     745                 : 
     746              70 :         return result;
     747                 : }
     748                 : 
     749                 : /* ----------------
     750                 :  *              index_vacuum_cleanup - do post-deletion cleanup of an index
     751                 :  *
     752                 :  *              return value is an optional palloc'd struct of statistics
     753                 :  * ----------------
     754                 :  */
     755                 : IndexBulkDeleteResult *
     756                 : index_vacuum_cleanup(IndexVacuumInfo *info,
     757                 :                                          IndexBulkDeleteResult *stats)
     758             375 : {
     759             375 :         Relation        indexRelation = info->index;
     760                 :         FmgrInfo   *procedure;
     761                 :         IndexBulkDeleteResult *result;
     762                 : 
     763                 :         RELATION_CHECKS;
     764             375 :         GET_REL_PROCEDURE(amvacuumcleanup);
     765                 : 
     766             375 :         result = (IndexBulkDeleteResult *)
     767                 :                 DatumGetPointer(FunctionCall2(procedure,
     768                 :                                                                           PointerGetDatum(info),
     769                 :                                                                           PointerGetDatum(stats)));
     770                 : 
     771             375 :         return result;
     772                 : }
     773                 : 
     774                 : /* ----------------
     775                 :  *              index_getprocid
     776                 :  *
     777                 :  *              Index access methods typically require support routines that are
     778                 :  *              not directly the implementation of any WHERE-clause query operator
     779                 :  *              and so cannot be kept in pg_amop.  Instead, such routines are kept
     780                 :  *              in pg_amproc.  These registered procedure OIDs are assigned numbers
     781                 :  *              according to a convention established by the access method.
     782                 :  *              The general index code doesn't know anything about the routines
     783                 :  *              involved; it just builds an ordered list of them for
     784                 :  *              each attribute on which an index is defined.
     785                 :  *
     786                 :  *              As of Postgres 8.3, support routines within an operator family
     787                 :  *              are further subdivided by the "left type" and "right type" of the
     788                 :  *              query operator(s) that they support.  The "default" functions for a
     789                 :  *              particular indexed attribute are those with both types equal to
     790                 :  *              the index opclass' opcintype (note that this is subtly different
     791                 :  *              from the indexed attribute's own type: it may be a binary-compatible
     792                 :  *              type instead).  Only the default functions are stored in relcache
     793                 :  *              entries --- access methods can use the syscache to look up non-default
     794                 :  *              functions.
     795                 :  *
     796                 :  *              This routine returns the requested default procedure OID for a
     797                 :  *              particular indexed attribute.
     798                 :  * ----------------
     799                 :  */
     800                 : RegProcedure
     801                 : index_getprocid(Relation irel,
     802                 :                                 AttrNumber attnum,
     803                 :                                 uint16 procnum)
     804               6 : {
     805                 :         RegProcedure *loc;
     806                 :         int                     nproc;
     807                 :         int                     procindex;
     808                 : 
     809               6 :         nproc = irel->rd_am->amsupport;
     810                 : 
     811                 :         Assert(procnum > 0 && procnum <= (uint16) nproc);
     812                 : 
     813               6 :         procindex = (nproc * (attnum - 1)) + (procnum - 1);
     814                 : 
     815               6 :         loc = irel->rd_support;
     816                 : 
     817                 :         Assert(loc != NULL);
     818                 : 
     819               6 :         return loc[procindex];
     820                 : }
     821                 : 
     822                 : /* ----------------
     823                 :  *              index_getprocinfo
     824                 :  *
     825                 :  *              This routine allows index AMs to keep fmgr lookup info for
     826                 :  *              support procs in the relcache.  As above, only the "default"
     827                 :  *              functions for any particular indexed attribute are cached.
     828                 :  *
     829                 :  * Note: the return value points into cached data that will be lost during
     830                 :  * any relcache rebuild!  Therefore, either use the callinfo right away,
     831                 :  * or save it only after having acquired some type of lock on the index rel.
     832                 :  * ----------------
     833                 :  */
     834                 : FmgrInfo *
     835                 : index_getprocinfo(Relation irel,
     836                 :                                   AttrNumber attnum,
     837                 :                                   uint16 procnum)
     838          483790 : {
     839                 :         FmgrInfo   *locinfo;
     840                 :         int                     nproc;
     841                 :         int                     procindex;
     842                 : 
     843          483790 :         nproc = irel->rd_am->amsupport;
     844                 : 
     845                 :         Assert(procnum > 0 && procnum <= (uint16) nproc);
     846                 : 
     847          483790 :         procindex = (nproc * (attnum - 1)) + (procnum - 1);
     848                 : 
     849          483790 :         locinfo = irel->rd_supportinfo;
     850                 : 
     851                 :         Assert(locinfo != NULL);
     852                 : 
     853          483790 :         locinfo += procindex;
     854                 : 
     855                 :         /* Initialize the lookup info if first time through */
     856          483790 :         if (locinfo->fn_oid == InvalidOid)
     857                 :         {
     858            8294 :                 RegProcedure *loc = irel->rd_support;
     859                 :                 RegProcedure procId;
     860                 : 
     861                 :                 Assert(loc != NULL);
     862                 : 
     863            8294 :                 procId = loc[procindex];
     864                 : 
     865                 :                 /*
     866                 :                  * Complain if function was not found during IndexSupportInitialize.
     867                 :                  * This should not happen unless the system tables contain bogus
     868                 :                  * entries for the index opclass.  (If an AM wants to allow a support
     869                 :                  * function to be optional, it can use index_getprocid.)
     870                 :                  */
     871            8294 :                 if (!RegProcedureIsValid(procId))
     872               0 :                         elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
     873                 :                                  procnum, attnum, RelationGetRelationName(irel));
     874                 : 
     875            8294 :                 fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
     876                 :         }
     877                 : 
     878          483790 :         return locinfo;
     879                 : }

Generated by: LTP GCOV extension version 1.5