LCOV - code coverage report
Current view: top level - contrib/pgrowlocks - pgrowlocks.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 131 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 3 0
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * contrib/pgrowlocks/pgrowlocks.c
       3              :  *
       4              :  * Copyright (c) 2005-2006      Tatsuo Ishii
       5              :  *
       6              :  * Permission to use, copy, modify, and distribute this software and
       7              :  * its documentation for any purpose, without fee, and without a
       8              :  * written agreement is hereby granted, provided that the above
       9              :  * copyright notice and this paragraph and the following two
      10              :  * paragraphs appear in all copies.
      11              :  *
      12              :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
      13              :  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
      14              :  * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
      15              :  * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
      16              :  * OF THE POSSIBILITY OF SUCH DAMAGE.
      17              :  *
      18              :  * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
      19              :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      20              :  * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
      21              :  * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
      22              :  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
      23              :  */
      24              : 
      25              : #include "postgres.h"
      26              : 
      27              : #include "access/heapam.h"
      28              : #include "access/multixact.h"
      29              : #include "access/relscan.h"
      30              : #include "access/tableam.h"
      31              : #include "access/xact.h"
      32              : #include "catalog/namespace.h"
      33              : #include "catalog/pg_am_d.h"
      34              : #include "catalog/pg_authid.h"
      35              : #include "funcapi.h"
      36              : #include "miscadmin.h"
      37              : #include "storage/bufmgr.h"
      38              : #include "storage/procarray.h"
      39              : #include "utils/acl.h"
      40              : #include "utils/fmgrprotos.h"
      41              : #include "utils/rel.h"
      42              : #include "utils/snapmgr.h"
      43              : #include "utils/varlena.h"
      44              : 
      45            0 : PG_MODULE_MAGIC_EXT(
      46              :                                         .name = "pgrowlocks",
      47              :                                         .version = PG_VERSION
      48              : );
      49              : 
      50            0 : PG_FUNCTION_INFO_V1(pgrowlocks);
      51              : 
      52              : /* ----------
      53              :  * pgrowlocks:
      54              :  * returns tids of rows being locked
      55              :  * ----------
      56              :  */
      57              : 
      58              : #define NCHARS 32
      59              : 
      60              : #define         Atnum_tid               0
      61              : #define         Atnum_xmax              1
      62              : #define         Atnum_ismulti   2
      63              : #define         Atnum_xids              3
      64              : #define         Atnum_modes             4
      65              : #define         Atnum_pids              5
      66              : 
      67              : Datum
      68            0 : pgrowlocks(PG_FUNCTION_ARGS)
      69              : {
      70            0 :         text       *relname = PG_GETARG_TEXT_PP(0);
      71            0 :         ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
      72            0 :         AttInMetadata *attinmeta;
      73            0 :         Relation        rel;
      74            0 :         RangeVar   *relrv;
      75            0 :         TableScanDesc scan;
      76            0 :         HeapScanDesc hscan;
      77            0 :         HeapTuple       tuple;
      78            0 :         AclResult       aclresult;
      79            0 :         char      **values;
      80              : 
      81            0 :         InitMaterializedSRF(fcinfo, 0);
      82              : 
      83              :         /* Access the table */
      84            0 :         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
      85            0 :         rel = relation_openrv(relrv, AccessShareLock);
      86              : 
      87            0 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
      88            0 :                 ereport(ERROR,
      89              :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
      90              :                                  errmsg("\"%s\" is a partitioned table",
      91              :                                                 RelationGetRelationName(rel)),
      92              :                                  errdetail("Partitioned tables do not contain rows.")));
      93            0 :         else if (rel->rd_rel->relkind != RELKIND_RELATION)
      94            0 :                 ereport(ERROR,
      95              :                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
      96              :                                  errmsg("\"%s\" is not a table",
      97              :                                                 RelationGetRelationName(rel))));
      98            0 :         else if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
      99            0 :                 ereport(ERROR,
     100              :                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     101              :                                  errmsg("only heap AM is supported")));
     102              : 
     103              :         /*
     104              :          * check permissions: must have SELECT on table or be in
     105              :          * pg_stat_scan_tables
     106              :          */
     107            0 :         aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     108              :                                                                   ACL_SELECT);
     109            0 :         if (aclresult != ACLCHECK_OK)
     110            0 :                 aclresult = has_privs_of_role(GetUserId(), ROLE_PG_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
     111              : 
     112            0 :         if (aclresult != ACLCHECK_OK)
     113            0 :                 aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
     114            0 :                                            RelationGetRelationName(rel));
     115              : 
     116              :         /* Scan the relation */
     117            0 :         scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
     118            0 :         hscan = (HeapScanDesc) scan;
     119              : 
     120            0 :         attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
     121              : 
     122            0 :         values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
     123              : 
     124            0 :         while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     125              :         {
     126            0 :                 TM_Result       htsu;
     127            0 :                 TransactionId xmax;
     128            0 :                 uint16          infomask;
     129              : 
     130              :                 /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
     131            0 :                 LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
     132              : 
     133            0 :                 htsu = HeapTupleSatisfiesUpdate(tuple,
     134            0 :                                                                                 GetCurrentCommandId(false),
     135            0 :                                                                                 hscan->rs_cbuf);
     136            0 :                 xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
     137            0 :                 infomask = tuple->t_data->t_infomask;
     138              : 
     139              :                 /*
     140              :                  * A tuple is locked if HTSU returns BeingModified.
     141              :                  */
     142            0 :                 if (htsu == TM_BeingModified)
     143              :                 {
     144            0 :                         values[Atnum_tid] = DatumGetCString(DirectFunctionCall1(tidout,
     145              :                                                                                                                                         PointerGetDatum(&tuple->t_self)));
     146              : 
     147            0 :                         values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
     148            0 :                         snprintf(values[Atnum_xmax], NCHARS, "%u", xmax);
     149            0 :                         if (infomask & HEAP_XMAX_IS_MULTI)
     150              :                         {
     151            0 :                                 MultiXactMember *members;
     152            0 :                                 int                     nmembers;
     153            0 :                                 bool            first = true;
     154            0 :                                 bool            allow_old;
     155              : 
     156            0 :                                 values[Atnum_ismulti] = pstrdup("true");
     157              : 
     158            0 :                                 allow_old = HEAP_LOCKED_UPGRADED(infomask);
     159            0 :                                 nmembers = GetMultiXactIdMembers(xmax, &members, allow_old,
     160              :                                                                                                  false);
     161            0 :                                 if (nmembers == -1)
     162              :                                 {
     163            0 :                                         values[Atnum_xids] = "{0}";
     164            0 :                                         values[Atnum_modes] = "{transient upgrade status}";
     165            0 :                                         values[Atnum_pids] = "{0}";
     166            0 :                                 }
     167              :                                 else
     168              :                                 {
     169            0 :                                         int                     j;
     170              : 
     171            0 :                                         values[Atnum_xids] = palloc(NCHARS * nmembers);
     172            0 :                                         values[Atnum_modes] = palloc(NCHARS * nmembers);
     173            0 :                                         values[Atnum_pids] = palloc(NCHARS * nmembers);
     174              : 
     175            0 :                                         strcpy(values[Atnum_xids], "{");
     176            0 :                                         strcpy(values[Atnum_modes], "{");
     177            0 :                                         strcpy(values[Atnum_pids], "{");
     178              : 
     179            0 :                                         for (j = 0; j < nmembers; j++)
     180              :                                         {
     181            0 :                                                 char            buf[NCHARS];
     182              : 
     183            0 :                                                 if (!first)
     184              :                                                 {
     185            0 :                                                         strcat(values[Atnum_xids], ",");
     186            0 :                                                         strcat(values[Atnum_modes], ",");
     187            0 :                                                         strcat(values[Atnum_pids], ",");
     188            0 :                                                 }
     189            0 :                                                 snprintf(buf, NCHARS, "%u", members[j].xid);
     190            0 :                                                 strcat(values[Atnum_xids], buf);
     191            0 :                                                 switch (members[j].status)
     192              :                                                 {
     193              :                                                         case MultiXactStatusUpdate:
     194            0 :                                                                 snprintf(buf, NCHARS, "Update");
     195            0 :                                                                 break;
     196              :                                                         case MultiXactStatusNoKeyUpdate:
     197            0 :                                                                 snprintf(buf, NCHARS, "No Key Update");
     198            0 :                                                                 break;
     199              :                                                         case MultiXactStatusForUpdate:
     200            0 :                                                                 snprintf(buf, NCHARS, "For Update");
     201            0 :                                                                 break;
     202              :                                                         case MultiXactStatusForNoKeyUpdate:
     203            0 :                                                                 snprintf(buf, NCHARS, "For No Key Update");
     204            0 :                                                                 break;
     205              :                                                         case MultiXactStatusForShare:
     206            0 :                                                                 snprintf(buf, NCHARS, "For Share");
     207            0 :                                                                 break;
     208              :                                                         case MultiXactStatusForKeyShare:
     209            0 :                                                                 snprintf(buf, NCHARS, "For Key Share");
     210            0 :                                                                 break;
     211              :                                                 }
     212            0 :                                                 strcat(values[Atnum_modes], buf);
     213            0 :                                                 snprintf(buf, NCHARS, "%d",
     214            0 :                                                                  BackendXidGetPid(members[j].xid));
     215            0 :                                                 strcat(values[Atnum_pids], buf);
     216              : 
     217            0 :                                                 first = false;
     218            0 :                                         }
     219              : 
     220            0 :                                         strcat(values[Atnum_xids], "}");
     221            0 :                                         strcat(values[Atnum_modes], "}");
     222            0 :                                         strcat(values[Atnum_pids], "}");
     223            0 :                                 }
     224            0 :                         }
     225              :                         else
     226              :                         {
     227            0 :                                 values[Atnum_ismulti] = pstrdup("false");
     228              : 
     229            0 :                                 values[Atnum_xids] = palloc(NCHARS * sizeof(char));
     230            0 :                                 snprintf(values[Atnum_xids], NCHARS, "{%u}", xmax);
     231              : 
     232            0 :                                 values[Atnum_modes] = palloc(NCHARS);
     233            0 :                                 if (infomask & HEAP_XMAX_LOCK_ONLY)
     234              :                                 {
     235            0 :                                         if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
     236            0 :                                                 snprintf(values[Atnum_modes], NCHARS, "{For Share}");
     237            0 :                                         else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
     238            0 :                                                 snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
     239            0 :                                         else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
     240              :                                         {
     241            0 :                                                 if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     242            0 :                                                         snprintf(values[Atnum_modes], NCHARS, "{For Update}");
     243              :                                                 else
     244            0 :                                                         snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
     245            0 :                                         }
     246              :                                         else
     247              :                                                 /* neither keyshare nor exclusive bit it set */
     248            0 :                                                 snprintf(values[Atnum_modes], NCHARS,
     249              :                                                                  "{transient upgrade status}");
     250            0 :                                 }
     251              :                                 else
     252              :                                 {
     253            0 :                                         if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     254            0 :                                                 snprintf(values[Atnum_modes], NCHARS, "{Update}");
     255              :                                         else
     256            0 :                                                 snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
     257              :                                 }
     258              : 
     259            0 :                                 values[Atnum_pids] = palloc(NCHARS * sizeof(char));
     260            0 :                                 snprintf(values[Atnum_pids], NCHARS, "{%d}",
     261            0 :                                                  BackendXidGetPid(xmax));
     262              :                         }
     263              : 
     264            0 :                         LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     265              : 
     266              :                         /* build a tuple */
     267            0 :                         tuple = BuildTupleFromCStrings(attinmeta, values);
     268            0 :                         tuplestore_puttuple(rsinfo->setResult, tuple);
     269            0 :                 }
     270              :                 else
     271              :                 {
     272            0 :                         LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     273              :                 }
     274            0 :         }
     275              : 
     276            0 :         table_endscan(scan);
     277            0 :         table_close(rel, AccessShareLock);
     278            0 :         return (Datum) 0;
     279            0 : }
        

Generated by: LCOV version 2.3.2-1