LCOV - differential code coverage report
Current view: top level - contrib/pgrowlocks - pgrowlocks.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 90.7 % 108 98 10 98
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 3 3 3
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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/builtins.h"
      41                 : #include "utils/rel.h"
      42                 : #include "utils/snapmgr.h"
      43                 : #include "utils/varlena.h"
      44                 : 
      45 CBC           2 : PG_MODULE_MAGIC;
      46                 : 
      47               2 : PG_FUNCTION_INFO_V1(pgrowlocks);
      48                 : 
      49                 : /* ----------
      50                 :  * pgrowlocks:
      51                 :  * returns tids of rows being locked
      52                 :  * ----------
      53                 :  */
      54                 : 
      55                 : #define NCHARS 32
      56                 : 
      57                 : #define     Atnum_tid       0
      58                 : #define     Atnum_xmax      1
      59                 : #define     Atnum_ismulti   2
      60                 : #define     Atnum_xids      3
      61                 : #define     Atnum_modes     4
      62                 : #define     Atnum_pids      5
      63                 : 
      64                 : Datum
      65              12 : pgrowlocks(PG_FUNCTION_ARGS)
      66                 : {
      67              12 :     text       *relname = PG_GETARG_TEXT_PP(0);
      68              12 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
      69                 :     AttInMetadata *attinmeta;
      70                 :     Relation    rel;
      71                 :     RangeVar   *relrv;
      72                 :     TableScanDesc scan;
      73                 :     HeapScanDesc hscan;
      74                 :     HeapTuple   tuple;
      75                 :     AclResult   aclresult;
      76                 :     char      **values;
      77                 : 
      78              12 :     InitMaterializedSRF(fcinfo, 0);
      79                 : 
      80                 :     /* Access the table */
      81              12 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
      82              12 :     rel = relation_openrv(relrv, AccessShareLock);
      83                 : 
      84              12 :     if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
      85 UBC           0 :         ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      86                 :                         errmsg("only heap AM is supported")));
      87                 : 
      88 CBC          12 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
      89 UBC           0 :         ereport(ERROR,
      90                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
      91                 :                  errmsg("\"%s\" is a partitioned table",
      92                 :                         RelationGetRelationName(rel)),
      93                 :                  errdetail("Partitioned tables do not contain rows.")));
      94 CBC          12 :     else if (rel->rd_rel->relkind != RELKIND_RELATION)
      95 UBC           0 :         ereport(ERROR,
      96                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
      97                 :                  errmsg("\"%s\" is not a table",
      98                 :                         RelationGetRelationName(rel))));
      99                 : 
     100                 :     /*
     101                 :      * check permissions: must have SELECT on table or be in
     102                 :      * pg_stat_scan_tables
     103                 :      */
     104 CBC          12 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     105                 :                                   ACL_SELECT);
     106              12 :     if (aclresult != ACLCHECK_OK)
     107 UBC           0 :         aclresult = has_privs_of_role(GetUserId(), ROLE_PG_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
     108                 : 
     109 CBC          12 :     if (aclresult != ACLCHECK_OK)
     110 UBC           0 :         aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
     111               0 :                        RelationGetRelationName(rel));
     112                 : 
     113                 :     /* Scan the relation */
     114 CBC          12 :     scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
     115              12 :     hscan = (HeapScanDesc) scan;
     116                 : 
     117              12 :     attinmeta = TupleDescGetAttInMetadata(rsinfo->setDesc);
     118                 : 
     119              12 :     values = (char **) palloc(rsinfo->setDesc->natts * sizeof(char *));
     120                 : 
     121              36 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     122                 :     {
     123                 :         TM_Result   htsu;
     124                 :         TransactionId xmax;
     125                 :         uint16      infomask;
     126                 : 
     127                 :         /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
     128              24 :         LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
     129                 : 
     130              24 :         htsu = HeapTupleSatisfiesUpdate(tuple,
     131                 :                                         GetCurrentCommandId(false),
     132                 :                                         hscan->rs_cbuf);
     133              24 :         xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
     134              24 :         infomask = tuple->t_data->t_infomask;
     135                 : 
     136                 :         /*
     137                 :          * A tuple is locked if HTSU returns BeingModified.
     138                 :          */
     139              24 :         if (htsu == TM_BeingModified)
     140                 :         {
     141              22 :             values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
     142                 :                                                              PointerGetDatum(&tuple->t_self));
     143                 : 
     144              22 :             values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
     145              22 :             snprintf(values[Atnum_xmax], NCHARS, "%u", xmax);
     146              22 :             if (infomask & HEAP_XMAX_IS_MULTI)
     147                 :             {
     148                 :                 MultiXactMember *members;
     149                 :                 int         nmembers;
     150               8 :                 bool        first = true;
     151                 :                 bool        allow_old;
     152                 : 
     153               8 :                 values[Atnum_ismulti] = pstrdup("true");
     154                 : 
     155               8 :                 allow_old = HEAP_LOCKED_UPGRADED(infomask);
     156               8 :                 nmembers = GetMultiXactIdMembers(xmax, &members, allow_old,
     157                 :                                                  false);
     158               8 :                 if (nmembers == -1)
     159                 :                 {
     160 UBC           0 :                     values[Atnum_xids] = "{0}";
     161               0 :                     values[Atnum_modes] = "{transient upgrade status}";
     162               0 :                     values[Atnum_pids] = "{0}";
     163                 :                 }
     164                 :                 else
     165                 :                 {
     166                 :                     int         j;
     167                 : 
     168 CBC           8 :                     values[Atnum_xids] = palloc(NCHARS * nmembers);
     169               8 :                     values[Atnum_modes] = palloc(NCHARS * nmembers);
     170               8 :                     values[Atnum_pids] = palloc(NCHARS * nmembers);
     171                 : 
     172               8 :                     strcpy(values[Atnum_xids], "{");
     173               8 :                     strcpy(values[Atnum_modes], "{");
     174               8 :                     strcpy(values[Atnum_pids], "{");
     175                 : 
     176              24 :                     for (j = 0; j < nmembers; j++)
     177                 :                     {
     178                 :                         char        buf[NCHARS];
     179                 : 
     180              16 :                         if (!first)
     181                 :                         {
     182               8 :                             strcat(values[Atnum_xids], ",");
     183               8 :                             strcat(values[Atnum_modes], ",");
     184               8 :                             strcat(values[Atnum_pids], ",");
     185                 :                         }
     186              16 :                         snprintf(buf, NCHARS, "%u", members[j].xid);
     187              16 :                         strcat(values[Atnum_xids], buf);
     188              16 :                         switch (members[j].status)
     189                 :                         {
     190               1 :                             case MultiXactStatusUpdate:
     191               1 :                                 snprintf(buf, NCHARS, "Update");
     192               1 :                                 break;
     193               1 :                             case MultiXactStatusNoKeyUpdate:
     194               1 :                                 snprintf(buf, NCHARS, "No Key Update");
     195               1 :                                 break;
     196               2 :                             case MultiXactStatusForUpdate:
     197               2 :                                 snprintf(buf, NCHARS, "For Update");
     198               2 :                                 break;
     199               2 :                             case MultiXactStatusForNoKeyUpdate:
     200               2 :                                 snprintf(buf, NCHARS, "For No Key Update");
     201               2 :                                 break;
     202               2 :                             case MultiXactStatusForShare:
     203               2 :                                 snprintf(buf, NCHARS, "Share");
     204               2 :                                 break;
     205               8 :                             case MultiXactStatusForKeyShare:
     206               8 :                                 snprintf(buf, NCHARS, "Key Share");
     207               8 :                                 break;
     208                 :                         }
     209              16 :                         strcat(values[Atnum_modes], buf);
     210              16 :                         snprintf(buf, NCHARS, "%d",
     211              16 :                                  BackendXidGetPid(members[j].xid));
     212              16 :                         strcat(values[Atnum_pids], buf);
     213                 : 
     214              16 :                         first = false;
     215                 :                     }
     216                 : 
     217               8 :                     strcat(values[Atnum_xids], "}");
     218               8 :                     strcat(values[Atnum_modes], "}");
     219               8 :                     strcat(values[Atnum_pids], "}");
     220                 :                 }
     221                 :             }
     222                 :             else
     223                 :             {
     224              14 :                 values[Atnum_ismulti] = pstrdup("false");
     225                 : 
     226              14 :                 values[Atnum_xids] = palloc(NCHARS * sizeof(char));
     227              14 :                 snprintf(values[Atnum_xids], NCHARS, "{%u}", xmax);
     228                 : 
     229              14 :                 values[Atnum_modes] = palloc(NCHARS);
     230              14 :                 if (infomask & HEAP_XMAX_LOCK_ONLY)
     231                 :                 {
     232              12 :                     if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
     233               2 :                         snprintf(values[Atnum_modes], NCHARS, "{For Share}");
     234              10 :                     else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
     235               6 :                         snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
     236               4 :                     else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
     237                 :                     {
     238               4 :                         if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     239               2 :                             snprintf(values[Atnum_modes], NCHARS, "{For Update}");
     240                 :                         else
     241               2 :                             snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
     242                 :                     }
     243                 :                     else
     244                 :                         /* neither keyshare nor exclusive bit it set */
     245 UBC           0 :                         snprintf(values[Atnum_modes], NCHARS,
     246                 :                                  "{transient upgrade status}");
     247                 :                 }
     248                 :                 else
     249                 :                 {
     250 CBC           2 :                     if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     251               1 :                         snprintf(values[Atnum_modes], NCHARS, "{Update}");
     252                 :                     else
     253               1 :                         snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
     254                 :                 }
     255                 : 
     256              14 :                 values[Atnum_pids] = palloc(NCHARS * sizeof(char));
     257              14 :                 snprintf(values[Atnum_pids], NCHARS, "{%d}",
     258                 :                          BackendXidGetPid(xmax));
     259                 :             }
     260                 : 
     261              22 :             LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     262                 : 
     263                 :             /* build a tuple */
     264              22 :             tuple = BuildTupleFromCStrings(attinmeta, values);
     265              22 :             tuplestore_puttuple(rsinfo->setResult, tuple);
     266                 :         }
     267                 :         else
     268                 :         {
     269               2 :             LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     270                 :         }
     271                 :     }
     272                 : 
     273              12 :     table_endscan(scan);
     274              12 :     table_close(rel, AccessShareLock);
     275              12 :     return (Datum) 0;
     276                 : }
        

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