LCOV - differential code coverage report
Current view: top level - src/backend/access/index - genam.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GIC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 83.1 % 201 167 3 6 11 14 76 91 20 70
Current Date: 2023-04-08 17:13:01 Functions: 91.7 % 12 11 1 8 3 1 8
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 0.0 % 3 0 3
Legend: Lines: hit not hit (240..) days: 84.3 % 198 167 6 11 14 76 91 20 69
Function coverage date bins:
(240..) days: 52.4 % 21 11 1 8 3 1 8

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * genam.c
                                  4                 :  *    general index access method routines
                                  5                 :  *
                                  6                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                  7                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :  *
                                  9                 :  *
                                 10                 :  * IDENTIFICATION
                                 11                 :  *    src/backend/access/index/genam.c
                                 12                 :  *
                                 13                 :  * NOTES
                                 14                 :  *    many of the old access method routines have been turned into
                                 15                 :  *    macros and moved to genam.h -cim 4/30/91
                                 16                 :  *
                                 17                 :  *-------------------------------------------------------------------------
                                 18                 :  */
                                 19                 : 
                                 20                 : #include "postgres.h"
                                 21                 : 
                                 22                 : #include "access/genam.h"
                                 23                 : #include "access/heapam.h"
                                 24                 : #include "access/relscan.h"
                                 25                 : #include "access/tableam.h"
                                 26                 : #include "access/transam.h"
                                 27                 : #include "catalog/index.h"
                                 28                 : #include "lib/stringinfo.h"
                                 29                 : #include "miscadmin.h"
                                 30                 : #include "storage/bufmgr.h"
                                 31                 : #include "storage/procarray.h"
                                 32                 : #include "utils/acl.h"
                                 33                 : #include "utils/builtins.h"
                                 34                 : #include "utils/lsyscache.h"
                                 35                 : #include "utils/rel.h"
                                 36                 : #include "utils/rls.h"
                                 37                 : #include "utils/ruleutils.h"
                                 38                 : #include "utils/snapmgr.h"
                                 39                 : #include "utils/syscache.h"
                                 40                 : 
                                 41                 : 
                                 42                 : /* ----------------------------------------------------------------
                                 43                 :  *      general access method routines
                                 44                 :  *
                                 45                 :  *      All indexed access methods use an identical scan structure.
                                 46                 :  *      We don't know how the various AMs do locking, however, so we don't
                                 47                 :  *      do anything about that here.
                                 48                 :  *
                                 49                 :  *      The intent is that an AM implementor will define a beginscan routine
                                 50                 :  *      that calls RelationGetIndexScan, to fill in the scan, and then does
                                 51                 :  *      whatever kind of locking he wants.
                                 52                 :  *
                                 53                 :  *      At the end of a scan, the AM's endscan routine undoes the locking,
                                 54                 :  *      but does *not* call IndexScanEnd --- the higher-level index_endscan
                                 55                 :  *      routine does that.  (We can't do it in the AM because index_endscan
                                 56                 :  *      still needs to touch the IndexScanDesc after calling the AM.)
                                 57                 :  *
                                 58                 :  *      Because of this, the AM does not have a choice whether to call
                                 59                 :  *      RelationGetIndexScan or not; its beginscan routine must return an
                                 60                 :  *      object made by RelationGetIndexScan.  This is kinda ugly but not
                                 61                 :  *      worth cleaning up now.
                                 62                 :  * ----------------------------------------------------------------
                                 63                 :  */
                                 64                 : 
                                 65                 : /* ----------------
                                 66                 :  *  RelationGetIndexScan -- Create and fill an IndexScanDesc.
                                 67                 :  *
                                 68                 :  *      This routine creates an index scan structure and sets up initial
                                 69                 :  *      contents for it.
                                 70                 :  *
                                 71                 :  *      Parameters:
                                 72                 :  *              indexRelation -- index relation for scan.
                                 73                 :  *              nkeys -- count of scan keys (index qual conditions).
                                 74                 :  *              norderbys -- count of index order-by operators.
                                 75                 :  *
                                 76                 :  *      Returns:
                                 77                 :  *              An initialized IndexScanDesc.
                                 78                 :  * ----------------
                                 79                 :  */
                                 80                 : IndexScanDesc
 4511 tgl                        81 CBC     8905358 : RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
                                 82                 : {
                                 83                 :     IndexScanDesc scan;
                                 84                 : 
 9345 bruce                      85         8905358 :     scan = (IndexScanDesc) palloc(sizeof(IndexScanDescData));
                                 86                 : 
 7629 tgl                        87         8905358 :     scan->heapRelation = NULL;   /* may be set later */
 1490 andres                     88         8905358 :     scan->xs_heapfetch = NULL;
 7629 tgl                        89         8905358 :     scan->indexRelation = indexRelation;
 2118                            90         8905358 :     scan->xs_snapshot = InvalidSnapshot; /* caller must initialize this */
 7629                            91         8905358 :     scan->numberOfKeys = nkeys;
 4511                            92         8905358 :     scan->numberOfOrderBys = norderbys;
                                 93                 : 
                                 94                 :     /*
                                 95                 :      * We allocate key workspace here, but it won't get filled until amrescan.
                                 96                 :      */
 7629                            97         8905358 :     if (nkeys > 0)
                                 98         8900408 :         scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
                                 99                 :     else
                                100            4950 :         scan->keyData = NULL;
 4511                           101         8905358 :     if (norderbys > 0)
                                102              96 :         scan->orderByData = (ScanKey) palloc(sizeof(ScanKeyData) * norderbys);
                                103                 :     else
                                104         8905262 :         scan->orderByData = NULL;
                                105                 : 
 3955 bruce                     106         8905358 :     scan->xs_want_itup = false; /* may be set later */
                                107                 : 
                                108                 :     /*
                                109                 :      * During recovery we ignore killed tuples and don't bother to kill them
                                110                 :      * either. We do this because the xmin on the primary node could easily be
                                111                 :      * later than the xmin on the standby node, so that what the primary
                                112                 :      * thinks is killed is supposed to be visible on standby. So for correct
                                113                 :      * MVCC for queries during recovery we must ignore these hints and check
                                114                 :      * all tuples. Do *not* set ignore_killed_tuples to true when running in a
                                115                 :      * transaction that was started during recovery. xactStartedInRecovery
                                116                 :      * should not be altered by index AMs.
                                117                 :      */
 7625 tgl                       118         8905358 :     scan->kill_prior_tuple = false;
 4859 simon                     119         8905358 :     scan->xactStartedInRecovery = TransactionStartedDuringRecovery();
                                120         8905358 :     scan->ignore_killed_tuples = !scan->xactStartedInRecovery;
                                121                 : 
 9345 bruce                     122         8905358 :     scan->opaque = NULL;
                                123                 : 
 4202 tgl                       124         8905358 :     scan->xs_itup = NULL;
 4193                           125         8905358 :     scan->xs_itupdesc = NULL;
 2232                           126         8905358 :     scan->xs_hitup = NULL;
                                127         8905358 :     scan->xs_hitupdesc = NULL;
                                128                 : 
 8986 bruce                     129         8905358 :     return scan;
                                130                 : }
                                131                 : 
                                132                 : /* ----------------
                                133                 :  *  IndexScanEnd -- End an index scan.
                                134                 :  *
                                135                 :  *      This routine just releases the storage acquired by
                                136                 :  *      RelationGetIndexScan().  Any AM-level resources are
                                137                 :  *      assumed to already have been released by the AM's
                                138                 :  *      endscan routine.
                                139                 :  *
                                140                 :  *  Returns:
                                141                 :  *      None.
                                142                 :  * ----------------
                                143                 :  */
                                144                 : void
 8501 tgl                       145         8904646 : IndexScanEnd(IndexScanDesc scan)
                                146                 : {
                                147         8904646 :     if (scan->keyData != NULL)
                                148         8899758 :         pfree(scan->keyData);
 4511                           149         8904646 :     if (scan->orderByData != NULL)
                                150              93 :         pfree(scan->orderByData);
                                151                 : 
 8501                           152         8904646 :     pfree(scan);
                                153         8904646 : }
                                154                 : 
                                155                 : /*
                                156                 :  * BuildIndexValueDescription
                                157                 :  *
                                158                 :  * Construct a string describing the contents of an index entry, in the
                                159                 :  * form "(key_name, ...)=(key_value, ...)".  This is currently used
                                160                 :  * for building unique-constraint and exclusion-constraint error messages,
                                161                 :  * so only key columns of the index are checked and printed.
                                162                 :  *
                                163                 :  * Note that if the user does not have permissions to view all of the
                                164                 :  * columns involved then a NULL is returned.  Returning a partial key seems
                                165                 :  * unlikely to be useful and we have no way to know which of the columns the
                                166                 :  * user provided (unlike in ExecBuildSlotValueDescription).
                                167                 :  *
                                168                 :  * The passed-in values/nulls arrays are the "raw" input to the index AM,
                                169                 :  * e.g. results of FormIndexDatum --- this is not necessarily what is stored
                                170                 :  * in the index, but it's what the user perceives to be stored.
                                171                 :  *
                                172                 :  * Note: if you change anything here, check whether
                                173                 :  * ExecBuildSlotPartitionKeyDescription() in execMain.c needs a similar
                                174                 :  * change.
                                175                 :  */
                                176                 : char *
 4999                           177             562 : BuildIndexValueDescription(Relation indexRelation,
                                178                 :                            Datum *values, bool *isnull)
                                179                 : {
                                180                 :     StringInfoData buf;
                                181                 :     Form_pg_index idxrec;
                                182                 :     int         indnkeyatts;
                                183                 :     int         i;
                                184                 :     int         keyno;
 3009 sfrost                    185             562 :     Oid         indexrelid = RelationGetRelid(indexRelation);
                                186                 :     Oid         indrelid;
                                187                 :     AclResult   aclresult;
                                188                 : 
 1828 teodor                    189             562 :     indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
                                190                 : 
                                191                 :     /*
                                192                 :      * Check permissions- if the user does not have access to view all of the
                                193                 :      * key columns then return NULL to avoid leaking data.
                                194                 :      *
                                195                 :      * First check if RLS is enabled for the relation.  If so, return NULL to
                                196                 :      * avoid leaking data.
                                197                 :      *
                                198                 :      * Next we need to check table-level SELECT access and then, if there is
                                199                 :      * no access there, check column-level permissions.
                                200                 :      */
 1728 alvherre                  201             562 :     idxrec = indexRelation->rd_index;
 3009 sfrost                    202             562 :     indrelid = idxrec->indrelid;
                                203             562 :     Assert(indexrelid == idxrec->indexrelid);
                                204                 : 
                                205                 :     /* RLS check- if RLS is enabled then we don't return anything. */
 2812 mail                      206             562 :     if (check_enable_rls(indrelid, InvalidOid, true) == RLS_ENABLED)
 3009 sfrost                    207               6 :         return NULL;
                                208                 : 
                                209                 :     /* Table-level SELECT is enough, if the user has it */
                                210             556 :     aclresult = pg_class_aclcheck(indrelid, GetUserId(), ACL_SELECT);
                                211             556 :     if (aclresult != ACLCHECK_OK)
                                212                 :     {
                                213                 :         /*
                                214                 :          * No table-level access, so step through the columns in the index and
                                215                 :          * make sure the user has SELECT rights on all of them.
                                216                 :          */
 1728 alvherre                  217              12 :         for (keyno = 0; keyno < indnkeyatts; keyno++)
                                218                 :         {
 3009 sfrost                    219              12 :             AttrNumber  attnum = idxrec->indkey.values[keyno];
                                220                 : 
                                221                 :             /*
                                222                 :              * Note that if attnum == InvalidAttrNumber, then this is an index
                                223                 :              * based on an expression and we return no detail rather than try
                                224                 :              * to figure out what column(s) the expression includes and if the
                                225                 :              * user has SELECT rights on them.
                                226                 :              */
 2992                           227              24 :             if (attnum == InvalidAttrNumber ||
                                228              12 :                 pg_attribute_aclcheck(indrelid, attnum, GetUserId(),
                                229                 :                                       ACL_SELECT) != ACLCHECK_OK)
                                230                 :             {
                                231                 :                 /* No access, so clean up and return */
 3009                           232               6 :                 return NULL;
                                233                 :             }
                                234                 :         }
                                235                 :     }
                                236                 : 
 4999 tgl                       237             550 :     initStringInfo(&buf);
                                238             550 :     appendStringInfo(&buf, "(%s)=(",
                                239                 :                      pg_get_indexdef_columns(indexrelid, true));
                                240                 : 
 1828 teodor                    241            1167 :     for (i = 0; i < indnkeyatts; i++)
                                242                 :     {
                                243                 :         char       *val;
                                244                 : 
 4999 tgl                       245             617 :         if (isnull[i])
                                246               9 :             val = "null";
                                247                 :         else
                                248                 :         {
                                249                 :             Oid         foutoid;
                                250                 :             bool        typisvarlena;
                                251                 : 
                                252                 :             /*
                                253                 :              * The provided data is not necessarily of the type stored in the
                                254                 :              * index; rather it is of the index opclass's input type. So look
                                255                 :              * at rd_opcintype not the index tupdesc.
                                256                 :              *
                                257                 :              * Note: this is a bit shaky for opclasses that have pseudotype
                                258                 :              * input types such as ANYARRAY or RECORD.  Currently, the
                                259                 :              * typoutput functions associated with the pseudotypes will work
                                260                 :              * okay, but we might have to try harder in future.
                                261                 :              */
 4871                           262             608 :             getTypeOutputInfo(indexRelation->rd_opcintype[i],
                                263                 :                               &foutoid, &typisvarlena);
 4999                           264             608 :             val = OidOutputFunctionCall(foutoid, values[i]);
                                265                 :         }
                                266                 : 
                                267             617 :         if (i > 0)
                                268              67 :             appendStringInfoString(&buf, ", ");
                                269             617 :         appendStringInfoString(&buf, val);
                                270                 :     }
                                271                 : 
                                272             550 :     appendStringInfoChar(&buf, ')');
                                273                 : 
                                274             550 :     return buf.data;
                                275                 : }
                                276                 : 
                                277                 : /*
                                278                 :  * Get the snapshotConflictHorizon from the table entries pointed to by the
                                279                 :  * index tuples being deleted using an AM-generic approach.
                                280                 :  *
                                281                 :  * This is a table_index_delete_tuples() shim used by index AMs that only need
                                282                 :  * to consult the tableam to get a snapshotConflictHorizon value, and only
                                283                 :  * expect to delete index tuples that are already known deletable (typically
                                284                 :  * due to having LP_DEAD bits set).  When a snapshotConflictHorizon value
                                285                 :  * isn't needed in index AM's deletion WAL record, it is safe for it to skip
                                286                 :  * calling here entirely.
                                287                 :  *
                                288                 :  * We assume that caller index AM uses the standard IndexTuple representation,
                                289                 :  * with table TIDs stored in the t_tid field.  We also expect (and assert)
                                290                 :  * that the line pointers on page for 'itemnos' offsets are already marked
                                291                 :  * LP_DEAD.
                                292                 :  */
                                293                 : TransactionId
 1475 andres                    294 UIC           0 : index_compute_xid_horizon_for_tuples(Relation irel,
 1475 andres                    295 EUB             :                                      Relation hrel,
                                296                 :                                      Buffer ibuf,
                                297                 :                                      OffsetNumber *itemnos,
                                298                 :                                      int nitems)
                                299                 : {
                                300                 :     TM_IndexDeleteOp delstate;
  143 pg                        301 UNC           0 :     TransactionId snapshotConflictHorizon = InvalidTransactionId;
 1475 andres                    302 UBC           0 :     Page        ipage = BufferGetPage(ibuf);
 1475 andres                    303 EUB             :     IndexTuple  itup;
                                304                 : 
  803 pg                        305 UIC           0 :     Assert(nitems > 0);
  803 pg                        306 EUB             : 
  521 pg                        307 UIC           0 :     delstate.irel = irel;
  521 pg                        308 UBC           0 :     delstate.iblknum = BufferGetBlockNumber(ibuf);
  816                           309               0 :     delstate.bottomup = false;
                                310               0 :     delstate.bottomupfreespace = 0;
                                311               0 :     delstate.ndeltids = 0;
                                312               0 :     delstate.deltids = palloc(nitems * sizeof(TM_IndexDelete));
                                313               0 :     delstate.status = palloc(nitems * sizeof(TM_IndexStatus));
  816 pg                        314 EUB             : 
                                315                 :     /* identify what the index tuples about to be deleted point to */
 1475 andres                    316 UIC           0 :     for (int i = 0; i < nitems; i++)
 1475 andres                    317 EUB             :     {
  521 pg                        318 UIC           0 :         OffsetNumber offnum = itemnos[i];
 1475 andres                    319 EUB             :         ItemId      iitemid;
                                320                 : 
  521 pg                        321 UIC           0 :         iitemid = PageGetItemId(ipage, offnum);
 1475 andres                    322 UBC           0 :         itup = (IndexTuple) PageGetItem(ipage, iitemid);
 1475 andres                    323 EUB             : 
  816 pg                        324 UIC           0 :         Assert(ItemIdIsDead(iitemid));
  816 pg                        325 EUB             : 
  816 pg                        326 UIC           0 :         ItemPointerCopy(&itup->t_tid, &delstate.deltids[i].tid);
  816 pg                        327 UBC           0 :         delstate.deltids[i].id = delstate.ndeltids;
  521                           328               0 :         delstate.status[i].idxoffnum = offnum;
  816                           329               0 :         delstate.status[i].knowndeletable = true;   /* LP_DEAD-marked */
                                330               0 :         delstate.status[i].promising = false;   /* unused */
                                331               0 :         delstate.status[i].freespace = 0;   /* unused */
  816 pg                        332 EUB             : 
  816 pg                        333 UIC           0 :         delstate.ndeltids++;
 1475 andres                    334 EUB             :     }
                                335                 : 
                                336                 :     /* determine the actual xid horizon */
  143 pg                        337 UNC           0 :     snapshotConflictHorizon = table_index_delete_tuples(hrel, &delstate);
  816 pg                        338 EUB             : 
                                339                 :     /* assert tableam agrees that all items are deletable */
  816 pg                        340 UIC           0 :     Assert(delstate.ndeltids == nitems);
 1475 andres                    341 EUB             : 
  816 pg                        342 UIC           0 :     pfree(delstate.deltids);
  816 pg                        343 UBC           0 :     pfree(delstate.status);
 1475 andres                    344 EUB             : 
  143 pg                        345 UNC           0 :     return snapshotConflictHorizon;
 1475 andres                    346 EUB             : }
                                347                 : 
                                348                 : 
                                349                 : /* ----------------------------------------------------------------
                                350                 :  *      heap-or-index-scan access to system catalogs
                                351                 :  *
                                352                 :  *      These functions support system catalog accesses that normally use
                                353                 :  *      an index but need to be capable of being switched to heap scans
                                354                 :  *      if the system indexes are unavailable.
                                355                 :  *
                                356                 :  *      The specified scan keys must be compatible with the named index.
                                357                 :  *      Generally this means that they must constrain either all columns
                                358                 :  *      of the index, or the first K columns of an N-column index.
                                359                 :  *
                                360                 :  *      These routines could work with non-system tables, actually,
                                361                 :  *      but they're only useful when there is a known index to use with
                                362                 :  *      the given scan keys; so in practice they're only good for
                                363                 :  *      predetermined types of scans of system catalogs.
                                364                 :  * ----------------------------------------------------------------
                                365                 :  */
                                366                 : 
                                367                 : /*
                                368                 :  * systable_beginscan --- set up for heap-or-index scan
                                369                 :  *
                                370                 :  *  rel: catalog to scan, already opened and suitably locked
                                371                 :  *  indexId: OID of index to conditionally use
                                372                 :  *  indexOK: if false, forces a heap scan (see notes below)
                                373                 :  *  snapshot: time qual to use (NULL for a recent catalog snapshot)
                                374                 :  *  nkeys, key: scan keys
                                375                 :  *
                                376                 :  * The attribute numbers in the scan key should be set for the heap case.
                                377                 :  * If we choose to index, we reset them to 1..n to reference the index
                                378                 :  * columns.  Note this means there must be one scankey qualification per
                                379                 :  * index column!  This is checked by the Asserts in the normal, index-using
                                380                 :  * case, but won't be checked if the heapscan path is taken.
                                381                 :  *
                                382                 :  * The routine checks the normal cases for whether an indexscan is safe,
                                383                 :  * but caller can make additional checks and pass indexOK=false if needed.
                                384                 :  * In standard case indexOK can simply be constant TRUE.
                                385                 :  */
                                386                 : SysScanDesc
 7629 tgl                       387 GIC     9189314 : systable_beginscan(Relation heapRelation,
 6569 tgl                       388 ECB             :                    Oid indexId,
                                389                 :                    bool indexOK,
                                390                 :                    Snapshot snapshot,
                                391                 :                    int nkeys, ScanKey key)
                                392                 : {
                                393                 :     SysScanDesc sysscan;
                                394                 :     Relation    irel;
                                395                 : 
 6569 tgl                       396 GIC     9189314 :     if (indexOK &&
 6303 peter_e                   397 CBC     8947477 :         !IgnoreSystemIndexes &&
 6569 tgl                       398         8667487 :         !ReindexIsProcessingIndex(indexId))
 6096                           399         8663012 :         irel = index_open(indexId, AccessShareLock);
 7137 tgl                       400 ECB             :     else
 7137 tgl                       401 GIC      526302 :         irel = NULL;
 7719 tgl                       402 ECB             : 
 7719 tgl                       403 GIC     9189310 :     sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
 7629 tgl                       404 ECB             : 
 7629 tgl                       405 GIC     9189310 :     sysscan->heap_rel = heapRelation;
 7137 tgl                       406 CBC     9189310 :     sysscan->irel = irel;
 1490 andres                    407         9189310 :     sysscan->slot = table_slot_create(heapRelation, NULL);
 7719 tgl                       408 ECB             : 
 3568 rhaas                     409 GIC     9189310 :     if (snapshot == NULL)
 3568 rhaas                     410 ECB             :     {
 3260 bruce                     411 GIC     8073730 :         Oid         relid = RelationGetRelid(heapRelation);
 3568 rhaas                     412 ECB             : 
 3568 rhaas                     413 GIC     8073730 :         snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
 3568 rhaas                     414 CBC     8073730 :         sysscan->snapshot = snapshot;
 3568 rhaas                     415 ECB             :     }
                                416                 :     else
                                417                 :     {
                                418                 :         /* Caller is responsible for any snapshot. */
 3568 rhaas                     419 GIC     1115580 :         sysscan->snapshot = NULL;
 3568 rhaas                     420 ECB             :     }
                                421                 : 
 7137 tgl                       422 GIC     9189310 :     if (irel)
 7719 tgl                       423 ECB             :     {
                                424                 :         int         i;
                                425                 : 
                                426                 :         /* Change attribute numbers to be index column numbers. */
 7719 tgl                       427 GIC    24125029 :         for (i = 0; i < nkeys; i++)
 7719 tgl                       428 ECB             :         {
                                429                 :             int         j;
                                430                 : 
 1828 teodor                    431 GIC    24247050 :             for (j = 0; j < IndexRelationGetNumberOfAttributes(irel); j++)
 5267 heikki.linnakangas        432 ECB             :             {
 5267 heikki.linnakangas        433 GIC    24247050 :                 if (key[i].sk_attno == irel->rd_index->indkey.values[j])
 5267 heikki.linnakangas        434 ECB             :                 {
 5267 heikki.linnakangas        435 GIC    15462021 :                     key[i].sk_attno = j + 1;
 5267 heikki.linnakangas        436 CBC    15462021 :                     break;
 5267 heikki.linnakangas        437 ECB             :                 }
                                438                 :             }
 1828 teodor                    439 GIC    15462021 :             if (j == IndexRelationGetNumberOfAttributes(irel))
 5267 heikki.linnakangas        440 LBC           0 :                 elog(ERROR, "column is not in index");
 7719 tgl                       441 EUB             :         }
                                442                 : 
 6096 tgl                       443 GIC     8663008 :         sysscan->iscan = index_beginscan(heapRelation, irel,
 4511 tgl                       444 ECB             :                                          snapshot, nkeys, 0);
 4511 tgl                       445 GIC     8663008 :         index_rescan(sysscan->iscan, key, nkeys, NULL, 0);
 7719 tgl                       446 CBC     8663008 :         sysscan->scan = NULL;
 7719 tgl                       447 ECB             :     }
                                448                 :     else
                                449                 :     {
                                450                 :         /*
                                451                 :          * We disallow synchronized scans when forced to use a heapscan on a
                                452                 :          * catalog.  In most cases the desired rows are near the front, so
                                453                 :          * that the unpredictable start point of a syncscan is a serious
                                454                 :          * disadvantage; and there are no compensating advantages, because
                                455                 :          * it's unlikely that such scans will occur in parallel.
                                456                 :          */
 1490 andres                    457 GIC      526302 :         sysscan->scan = table_beginscan_strat(heapRelation, snapshot,
 1490 andres                    458 ECB             :                                               nkeys, key,
                                459                 :                                               true, false);
 7719 tgl                       460 GIC      526302 :         sysscan->iscan = NULL;
 7719 tgl                       461 ECB             :     }
                                462                 : 
                                463                 :     /*
                                464                 :      * If CheckXidAlive is set then set a flag to indicate that system table
                                465                 :      * scan is in-progress.  See detailed comments in xact.c where these
                                466                 :      * variables are declared.
                                467                 :      */
  974 akapila                   468 GIC     9189310 :     if (TransactionIdIsValid(CheckXidAlive))
  974 akapila                   469 CBC         672 :         bsysscan = true;
  974 akapila                   470 ECB             : 
 7719 tgl                       471 GIC     9189310 :     return sysscan;
 7719 tgl                       472 ECB             : }
                                473                 : 
                                474                 : /*
                                475                 :  * HandleConcurrentAbort - Handle concurrent abort of the CheckXidAlive.
                                476                 :  *
                                477                 :  * Error out, if CheckXidAlive is aborted. We can't directly use
                                478                 :  * TransactionIdDidAbort as after crash such transaction might not have been
                                479                 :  * marked as aborted.  See detailed comments in xact.c where the variable
                                480                 :  * is declared.
                                481                 :  */
                                482                 : static inline void
  974 akapila                   483 GIC    19811170 : HandleConcurrentAbort()
  974 akapila                   484 ECB             : {
  974 akapila                   485 GIC    19811170 :     if (TransactionIdIsValid(CheckXidAlive) &&
  974 akapila                   486 CBC         980 :         !TransactionIdIsInProgress(CheckXidAlive) &&
                                487               7 :         !TransactionIdDidCommit(CheckXidAlive))
                                488               7 :         ereport(ERROR,
  974 akapila                   489 ECB             :                 (errcode(ERRCODE_TRANSACTION_ROLLBACK),
                                490                 :                  errmsg("transaction aborted during system catalog scan")));
  974 akapila                   491 GIC    19811163 : }
  974 akapila                   492 ECB             : 
                                493                 : /*
                                494                 :  * systable_getnext --- get next tuple in a heap-or-index scan
                                495                 :  *
                                496                 :  * Returns NULL if no more tuples available.
                                497                 :  *
                                498                 :  * Note that returned tuple is a reference to data in a disk buffer;
                                499                 :  * it must not be modified, and should be presumed inaccessible after
                                500                 :  * next getnext() or endscan() call.
                                501                 :  *
                                502                 :  * XXX: It'd probably make sense to offer a slot based interface, at least
                                503                 :  * optionally.
                                504                 :  */
                                505                 : HeapTuple
 7719 tgl                       506 GIC    19486879 : systable_getnext(SysScanDesc sysscan)
 7719 tgl                       507 ECB             : {
 1490 andres                    508 GIC    19486879 :     HeapTuple   htup = NULL;
 7719 tgl                       509 ECB             : 
 7719 tgl                       510 GIC    19486879 :     if (sysscan->irel)
 5474 tgl                       511 ECB             :     {
 1490 andres                    512 GIC    17708275 :         if (index_getnext_slot(sysscan->iscan, ForwardScanDirection, sysscan->slot))
 1490 andres                    513 ECB             :         {
                                514                 :             bool        shouldFree;
                                515                 : 
 1490 andres                    516 GIC    12749633 :             htup = ExecFetchSlotHeapTuple(sysscan->slot, false, &shouldFree);
 1490 andres                    517 CBC    12749633 :             Assert(!shouldFree);
 1490 andres                    518 ECB             : 
                                519                 :             /*
                                520                 :              * We currently don't need to support lossy index operators for
                                521                 :              * any system catalog scan.  It could be done here, using the scan
                                522                 :              * keys to drive the operator calls, if we arranged to save the
                                523                 :              * heap attnums during systable_beginscan(); this is practical
                                524                 :              * because we still wouldn't need to support indexes on
                                525                 :              * expressions.
                                526                 :              */
 1490 andres                    527 GIC    12749633 :             if (sysscan->iscan->xs_recheck)
 1490 andres                    528 LBC           0 :                 elog(ERROR, "system catalog scans with lossy index conditions are not implemented");
 1490 andres                    529 EUB             :         }
                                530                 :     }
                                531                 :     else
                                532                 :     {
 1490 andres                    533 GIC     1778604 :         if (table_scan_getnextslot(sysscan->scan, ForwardScanDirection, sysscan->slot))
 1490 andres                    534 ECB             :         {
                                535                 :             bool        shouldFree;
                                536                 : 
 1490 andres                    537 GIC     1597300 :             htup = ExecFetchSlotHeapTuple(sysscan->slot, false, &shouldFree);
 1490 andres                    538 CBC     1597300 :             Assert(!shouldFree);
 1490 andres                    539 ECB             :         }
                                540                 :     }
                                541                 : 
                                542                 :     /*
                                543                 :      * Handle the concurrent abort while fetching the catalog tuple during
                                544                 :      * logical streaming of a transaction.
                                545                 :      */
  974 akapila                   546 GIC    19486878 :     HandleConcurrentAbort();
  974 akapila                   547 ECB             : 
 7719 tgl                       548 GIC    19486871 :     return htup;
 7719 tgl                       549 ECB             : }
                                550                 : 
                                551                 : /*
                                552                 :  * systable_recheck_tuple --- recheck visibility of most-recently-fetched tuple
                                553                 :  *
                                554                 :  * In particular, determine if this tuple would be visible to a catalog scan
                                555                 :  * that started now.  We don't handle the case of a non-MVCC scan snapshot,
                                556                 :  * because no caller needs that yet.
                                557                 :  *
                                558                 :  * This is useful to test whether an object was deleted while we waited to
                                559                 :  * acquire lock on it.
                                560                 :  *
                                561                 :  * Note: we don't actually *need* the tuple to be passed in, but it's a
                                562                 :  * good crosscheck that the caller is interested in the right tuple.
                                563                 :  */
                                564                 : bool
 5418 tgl                       565 GIC       89536 : systable_recheck_tuple(SysScanDesc sysscan, HeapTuple tup)
 5418 tgl                       566 ECB             : {
                                567                 :     Snapshot    freshsnap;
                                568                 :     bool        result;
                                569                 : 
 1490 andres                    570 GIC       89536 :     Assert(tup == ExecFetchSlotHeapTuple(sysscan->slot, false, NULL));
 1490 andres                    571 ECB             : 
                                572                 :     /*
                                573                 :      * Trust that table_tuple_satisfies_snapshot() and its subsidiaries
                                574                 :      * (commonly LockBuffer() and HeapTupleSatisfiesMVCC()) do not themselves
                                575                 :      * acquire snapshots, so we need not register the snapshot.  Those
                                576                 :      * facilities are too low-level to have any business scanning tables.
                                577                 :      */
 3554 noah                      578 GIC       89536 :     freshsnap = GetCatalogSnapshot(RelationGetRelid(sysscan->heap_rel));
 3554 noah                      579 ECB             : 
 1490 andres                    580 GIC       89536 :     result = table_tuple_satisfies_snapshot(sysscan->heap_rel,
 1490 andres                    581 CBC       89536 :                                             sysscan->slot,
 1490 andres                    582 ECB             :                                             freshsnap);
                                583                 : 
                                584                 :     /*
                                585                 :      * Handle the concurrent abort while fetching the catalog tuple during
                                586                 :      * logical streaming of a transaction.
                                587                 :      */
  974 akapila                   588 GIC       89536 :     HandleConcurrentAbort();
  974 akapila                   589 ECB             : 
 5418 tgl                       590 GIC       89536 :     return result;
 5418 tgl                       591 ECB             : }
                                592                 : 
                                593                 : /*
                                594                 :  * systable_endscan --- close scan, release resources
                                595                 :  *
                                596                 :  * Note that it's still up to the caller to close the heap relation.
                                597                 :  */
                                598                 : void
 7719 tgl                       599 GIC     9189046 : systable_endscan(SysScanDesc sysscan)
 7719 tgl                       600 ECB             : {
 1490 andres                    601 GIC     9189046 :     if (sysscan->slot)
 1490 andres                    602 ECB             :     {
 1490 andres                    603 GIC     9189046 :         ExecDropSingleTupleTableSlot(sysscan->slot);
 1490 andres                    604 CBC     9189046 :         sysscan->slot = NULL;
 1490 andres                    605 ECB             :     }
                                606                 : 
 7719 tgl                       607 GIC     9189046 :     if (sysscan->irel)
 7719 tgl                       608 ECB             :     {
 7719 tgl                       609 GIC     8662751 :         index_endscan(sysscan->iscan);
 6096 tgl                       610 CBC     8662751 :         index_close(sysscan->irel, AccessShareLock);
 7719 tgl                       611 ECB             :     }
                                612                 :     else
 1490 andres                    613 GIC      526295 :         table_endscan(sysscan->scan);
 7719 tgl                       614 ECB             : 
 3568 rhaas                     615 GIC     9189046 :     if (sysscan->snapshot)
 3568 rhaas                     616 CBC     8073466 :         UnregisterSnapshot(sysscan->snapshot);
 3568 rhaas                     617 ECB             : 
                                618                 :     /*
                                619                 :      * Reset the bsysscan flag at the end of the systable scan.  See detailed
                                620                 :      * comments in xact.c where these variables are declared.
                                621                 :      */
  974 akapila                   622 GIC     9189046 :     if (TransactionIdIsValid(CheckXidAlive))
  974 akapila                   623 CBC         665 :         bsysscan = false;
  974 akapila                   624 ECB             : 
 7719 tgl                       625 GIC     9189046 :     pfree(sysscan);
 7719 tgl                       626 CBC     9189046 : }
 5475 tgl                       627 ECB             : 
                                628                 : 
                                629                 : /*
                                630                 :  * systable_beginscan_ordered --- set up for ordered catalog scan
                                631                 :  *
                                632                 :  * These routines have essentially the same API as systable_beginscan etc,
                                633                 :  * except that they guarantee to return multiple matching tuples in
                                634                 :  * index order.  Also, for largely historical reasons, the index to use
                                635                 :  * is opened and locked by the caller, not here.
                                636                 :  *
                                637                 :  * Currently we do not support non-index-based scans here.  (In principle
                                638                 :  * we could do a heapscan and sort, but the uses are in places that
                                639                 :  * probably don't need to still work with corrupted catalog indexes.)
                                640                 :  * For the moment, therefore, these functions are merely the thinest of
                                641                 :  * wrappers around index_beginscan/index_getnext_slot.  The main reason for
                                642                 :  * their existence is to centralize possible future support of lossy operators
                                643                 :  * in catalog scans.
                                644                 :  */
                                645                 : SysScanDesc
 5475 tgl                       646 GIC       55407 : systable_beginscan_ordered(Relation heapRelation,
 5475 tgl                       647 ECB             :                            Relation indexRelation,
                                648                 :                            Snapshot snapshot,
                                649                 :                            int nkeys, ScanKey key)
                                650                 : {
                                651                 :     SysScanDesc sysscan;
                                652                 :     int         i;
                                653                 : 
                                654                 :     /* REINDEX can probably be a hard error here ... */
 5475 tgl                       655 GIC       55407 :     if (ReindexIsProcessingIndex(RelationGetRelid(indexRelation)))
 4809 tgl                       656 LBC           0 :         elog(ERROR, "cannot do ordered scan on index \"%s\", because it is being reindexed",
 5475 tgl                       657 EUB             :              RelationGetRelationName(indexRelation));
                                658                 :     /* ... but we only throw a warning about violating IgnoreSystemIndexes */
 5475 tgl                       659 GIC       55407 :     if (IgnoreSystemIndexes)
 5475 tgl                       660 LBC           0 :         elog(WARNING, "using index \"%s\" despite IgnoreSystemIndexes",
 5475 tgl                       661 EUB             :              RelationGetRelationName(indexRelation));
                                662                 : 
 5475 tgl                       663 GIC       55407 :     sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData));
 5475 tgl                       664 ECB             : 
 5475 tgl                       665 GIC       55407 :     sysscan->heap_rel = heapRelation;
 5475 tgl                       666 CBC       55407 :     sysscan->irel = indexRelation;
 1490 andres                    667           55407 :     sysscan->slot = table_slot_create(heapRelation, NULL);
 5475 tgl                       668 ECB             : 
 3568 rhaas                     669 GIC       55407 :     if (snapshot == NULL)
 3568 rhaas                     670 ECB             :     {
 3260 bruce                     671 GIC        3799 :         Oid         relid = RelationGetRelid(heapRelation);
 3568 rhaas                     672 ECB             : 
 3568 rhaas                     673 GIC        3799 :         snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
 3568 rhaas                     674 CBC        3799 :         sysscan->snapshot = snapshot;
 3568 rhaas                     675 ECB             :     }
                                676                 :     else
                                677                 :     {
                                678                 :         /* Caller is responsible for any snapshot. */
 3568 rhaas                     679 GIC       51608 :         sysscan->snapshot = NULL;
 3568 rhaas                     680 ECB             :     }
                                681                 : 
                                682                 :     /* Change attribute numbers to be index column numbers. */
 5475 tgl                       683 GIC      109569 :     for (i = 0; i < nkeys; i++)
 5475 tgl                       684 ECB             :     {
                                685                 :         int         j;
                                686                 : 
 1828 teodor                    687 GIC       55786 :         for (j = 0; j < IndexRelationGetNumberOfAttributes(indexRelation); j++)
 5267 heikki.linnakangas        688 ECB             :         {
 5267 heikki.linnakangas        689 GIC       55786 :             if (key[i].sk_attno == indexRelation->rd_index->indkey.values[j])
 5267 heikki.linnakangas        690 ECB             :             {
 5267 heikki.linnakangas        691 GIC       54162 :                 key[i].sk_attno = j + 1;
 5267 heikki.linnakangas        692 CBC       54162 :                 break;
 5267 heikki.linnakangas        693 ECB             :             }
                                694                 :         }
 1828 teodor                    695 GIC       54162 :         if (j == IndexRelationGetNumberOfAttributes(indexRelation))
 5267 heikki.linnakangas        696 LBC           0 :             elog(ERROR, "column is not in index");
 5475 tgl                       697 EUB             :     }
                                698                 : 
 5475 tgl                       699 GIC       55407 :     sysscan->iscan = index_beginscan(heapRelation, indexRelation,
 4511 tgl                       700 ECB             :                                      snapshot, nkeys, 0);
 4511 tgl                       701 GIC       55407 :     index_rescan(sysscan->iscan, key, nkeys, NULL, 0);
 5475 tgl                       702 CBC       55407 :     sysscan->scan = NULL;
 5475 tgl                       703 ECB             : 
 5475 tgl                       704 GIC       55407 :     return sysscan;
 5475 tgl                       705 ECB             : }
                                706                 : 
                                707                 : /*
                                708                 :  * systable_getnext_ordered --- get next tuple in an ordered catalog scan
                                709                 :  */
                                710                 : HeapTuple
 5475 tgl                       711 GIC      234759 : systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
 5475 tgl                       712 ECB             : {
 1490 andres                    713 GIC      234759 :     HeapTuple   htup = NULL;
 5475 tgl                       714 ECB             : 
 5475 tgl                       715 GIC      234759 :     Assert(sysscan->irel);
 1490 andres                    716 CBC      234759 :     if (index_getnext_slot(sysscan->iscan, direction, sysscan->slot))
                                717          179970 :         htup = ExecFetchSlotHeapTuple(sysscan->slot, false, NULL);
 1490 andres                    718 ECB             : 
                                719                 :     /* See notes in systable_getnext */
 5474 tgl                       720 GIC      234756 :     if (htup && sysscan->iscan->xs_recheck)
 5474 tgl                       721 LBC           0 :         elog(ERROR, "system catalog scans with lossy index conditions are not implemented");
 5475 tgl                       722 EUB             : 
                                723                 :     /*
                                724                 :      * Handle the concurrent abort while fetching the catalog tuple during
                                725                 :      * logical streaming of a transaction.
                                726                 :      */
  974 akapila                   727 GIC      234756 :     HandleConcurrentAbort();
  974 akapila                   728 ECB             : 
 5475 tgl                       729 GIC      234756 :     return htup;
 5475 tgl                       730 ECB             : }
                                731                 : 
                                732                 : /*
                                733                 :  * systable_endscan_ordered --- close scan, release resources
                                734                 :  */
                                735                 : void
 5475 tgl                       736 GIC       55395 : systable_endscan_ordered(SysScanDesc sysscan)
 5475 tgl                       737 ECB             : {
 1490 andres                    738 GIC       55395 :     if (sysscan->slot)
 1490 andres                    739 ECB             :     {
 1490 andres                    740 GIC       55395 :         ExecDropSingleTupleTableSlot(sysscan->slot);
 1490 andres                    741 CBC       55395 :         sysscan->slot = NULL;
 1490 andres                    742 ECB             :     }
                                743                 : 
 5475 tgl                       744 GIC       55395 :     Assert(sysscan->irel);
 5475 tgl                       745 CBC       55395 :     index_endscan(sysscan->iscan);
 3568 rhaas                     746           55395 :     if (sysscan->snapshot)
                                747            3790 :         UnregisterSnapshot(sysscan->snapshot);
 5475 tgl                       748           55395 :     pfree(sysscan);
                                749           55395 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a