LCOV - code coverage report
Current view: top level - contrib/pgrowlocks - pgrowlocks.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 0 118 0.0 %
Date: 2019-06-19 14:06:47 Functions: 0 3 0.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/builtins.h"
      41             : #include "utils/rel.h"
      42             : #include "utils/snapmgr.h"
      43             : #include "utils/varlena.h"
      44             : 
      45           0 : PG_MODULE_MAGIC;
      46             : 
      47           0 : 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             : typedef struct
      58             : {
      59             :     Relation    rel;
      60             :     TableScanDesc scan;
      61             :     int         ncolumns;
      62             : } MyData;
      63             : 
      64             : #define     Atnum_tid       0
      65             : #define     Atnum_xmax      1
      66             : #define     Atnum_ismulti   2
      67             : #define     Atnum_xids      3
      68             : #define     Atnum_modes     4
      69             : #define     Atnum_pids      5
      70             : 
      71             : Datum
      72           0 : pgrowlocks(PG_FUNCTION_ARGS)
      73             : {
      74             :     FuncCallContext *funcctx;
      75             :     TableScanDesc scan;
      76             :     HeapScanDesc hscan;
      77             :     HeapTuple   tuple;
      78             :     TupleDesc   tupdesc;
      79             :     AttInMetadata *attinmeta;
      80             :     Datum       result;
      81             :     MyData     *mydata;
      82             :     Relation    rel;
      83             : 
      84           0 :     if (SRF_IS_FIRSTCALL())
      85             :     {
      86             :         text       *relname;
      87             :         RangeVar   *relrv;
      88             :         MemoryContext oldcontext;
      89             :         AclResult   aclresult;
      90             : 
      91           0 :         funcctx = SRF_FIRSTCALL_INIT();
      92           0 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
      93             : 
      94             :         /* Build a tuple descriptor for our result type */
      95           0 :         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
      96           0 :             elog(ERROR, "return type must be a row type");
      97             : 
      98           0 :         attinmeta = TupleDescGetAttInMetadata(tupdesc);
      99           0 :         funcctx->attinmeta = attinmeta;
     100             : 
     101           0 :         relname = PG_GETARG_TEXT_PP(0);
     102           0 :         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
     103           0 :         rel = relation_openrv(relrv, AccessShareLock);
     104             : 
     105           0 :         if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
     106           0 :             ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     107             :                             errmsg("only heap AM is supported")));
     108             : 
     109           0 :         if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
     110           0 :             ereport(ERROR,
     111             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     112             :                      errmsg("\"%s\" is a partitioned table",
     113             :                             RelationGetRelationName(rel)),
     114             :                      errdetail("Partitioned tables do not contain rows.")));
     115           0 :         else if (rel->rd_rel->relkind != RELKIND_RELATION)
     116           0 :             ereport(ERROR,
     117             :                     (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     118             :                      errmsg("\"%s\" is not a table",
     119             :                             RelationGetRelationName(rel))));
     120             : 
     121             :         /*
     122             :          * check permissions: must have SELECT on table or be in
     123             :          * pg_stat_scan_tables
     124             :          */
     125           0 :         aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     126             :                                       ACL_SELECT);
     127           0 :         if (aclresult != ACLCHECK_OK)
     128           0 :             aclresult = is_member_of_role(GetUserId(), DEFAULT_ROLE_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
     129             : 
     130           0 :         if (aclresult != ACLCHECK_OK)
     131           0 :             aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
     132           0 :                            RelationGetRelationName(rel));
     133             : 
     134           0 :         scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
     135           0 :         hscan = (HeapScanDesc) scan;
     136           0 :         mydata = palloc(sizeof(*mydata));
     137           0 :         mydata->rel = rel;
     138           0 :         mydata->scan = scan;
     139           0 :         mydata->ncolumns = tupdesc->natts;
     140           0 :         funcctx->user_fctx = mydata;
     141             : 
     142           0 :         MemoryContextSwitchTo(oldcontext);
     143             :     }
     144             : 
     145           0 :     funcctx = SRF_PERCALL_SETUP();
     146           0 :     attinmeta = funcctx->attinmeta;
     147           0 :     mydata = (MyData *) funcctx->user_fctx;
     148           0 :     scan = mydata->scan;
     149           0 :     hscan = (HeapScanDesc) scan;
     150             : 
     151             :     /* scan the relation */
     152           0 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     153             :     {
     154             :         TM_Result   htsu;
     155             :         TransactionId xmax;
     156             :         uint16      infomask;
     157             : 
     158             :         /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
     159           0 :         LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
     160             : 
     161           0 :         htsu = HeapTupleSatisfiesUpdate(tuple,
     162             :                                         GetCurrentCommandId(false),
     163             :                                         hscan->rs_cbuf);
     164           0 :         xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
     165           0 :         infomask = tuple->t_data->t_infomask;
     166             : 
     167             :         /*
     168             :          * A tuple is locked if HTSU returns BeingModified.
     169             :          */
     170           0 :         if (htsu == TM_BeingModified)
     171             :         {
     172             :             char      **values;
     173             : 
     174           0 :             values = (char **) palloc(mydata->ncolumns * sizeof(char *));
     175             : 
     176           0 :             values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
     177             :                                                              PointerGetDatum(&tuple->t_self));
     178             : 
     179           0 :             values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
     180           0 :             snprintf(values[Atnum_xmax], NCHARS, "%d", xmax);
     181           0 :             if (infomask & HEAP_XMAX_IS_MULTI)
     182             :             {
     183             :                 MultiXactMember *members;
     184             :                 int         nmembers;
     185           0 :                 bool        first = true;
     186             :                 bool        allow_old;
     187             : 
     188           0 :                 values[Atnum_ismulti] = pstrdup("true");
     189             : 
     190           0 :                 allow_old = HEAP_LOCKED_UPGRADED(infomask);
     191           0 :                 nmembers = GetMultiXactIdMembers(xmax, &members, allow_old,
     192             :                                                  false);
     193           0 :                 if (nmembers == -1)
     194             :                 {
     195           0 :                     values[Atnum_xids] = "{0}";
     196           0 :                     values[Atnum_modes] = "{transient upgrade status}";
     197           0 :                     values[Atnum_pids] = "{0}";
     198             :                 }
     199             :                 else
     200             :                 {
     201             :                     int         j;
     202             : 
     203           0 :                     values[Atnum_xids] = palloc(NCHARS * nmembers);
     204           0 :                     values[Atnum_modes] = palloc(NCHARS * nmembers);
     205           0 :                     values[Atnum_pids] = palloc(NCHARS * nmembers);
     206             : 
     207           0 :                     strcpy(values[Atnum_xids], "{");
     208           0 :                     strcpy(values[Atnum_modes], "{");
     209           0 :                     strcpy(values[Atnum_pids], "{");
     210             : 
     211           0 :                     for (j = 0; j < nmembers; j++)
     212             :                     {
     213             :                         char        buf[NCHARS];
     214             : 
     215           0 :                         if (!first)
     216             :                         {
     217           0 :                             strcat(values[Atnum_xids], ",");
     218           0 :                             strcat(values[Atnum_modes], ",");
     219           0 :                             strcat(values[Atnum_pids], ",");
     220             :                         }
     221           0 :                         snprintf(buf, NCHARS, "%d", members[j].xid);
     222           0 :                         strcat(values[Atnum_xids], buf);
     223           0 :                         switch (members[j].status)
     224             :                         {
     225             :                             case MultiXactStatusUpdate:
     226           0 :                                 snprintf(buf, NCHARS, "Update");
     227           0 :                                 break;
     228             :                             case MultiXactStatusNoKeyUpdate:
     229           0 :                                 snprintf(buf, NCHARS, "No Key Update");
     230           0 :                                 break;
     231             :                             case MultiXactStatusForUpdate:
     232           0 :                                 snprintf(buf, NCHARS, "For Update");
     233           0 :                                 break;
     234             :                             case MultiXactStatusForNoKeyUpdate:
     235           0 :                                 snprintf(buf, NCHARS, "For No Key Update");
     236           0 :                                 break;
     237             :                             case MultiXactStatusForShare:
     238           0 :                                 snprintf(buf, NCHARS, "Share");
     239           0 :                                 break;
     240             :                             case MultiXactStatusForKeyShare:
     241           0 :                                 snprintf(buf, NCHARS, "Key Share");
     242           0 :                                 break;
     243             :                         }
     244           0 :                         strcat(values[Atnum_modes], buf);
     245           0 :                         snprintf(buf, NCHARS, "%d",
     246           0 :                                  BackendXidGetPid(members[j].xid));
     247           0 :                         strcat(values[Atnum_pids], buf);
     248             : 
     249           0 :                         first = false;
     250             :                     }
     251             : 
     252           0 :                     strcat(values[Atnum_xids], "}");
     253           0 :                     strcat(values[Atnum_modes], "}");
     254           0 :                     strcat(values[Atnum_pids], "}");
     255             :                 }
     256             :             }
     257             :             else
     258             :             {
     259           0 :                 values[Atnum_ismulti] = pstrdup("false");
     260             : 
     261           0 :                 values[Atnum_xids] = palloc(NCHARS * sizeof(char));
     262           0 :                 snprintf(values[Atnum_xids], NCHARS, "{%d}", xmax);
     263             : 
     264           0 :                 values[Atnum_modes] = palloc(NCHARS);
     265           0 :                 if (infomask & HEAP_XMAX_LOCK_ONLY)
     266             :                 {
     267           0 :                     if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
     268           0 :                         snprintf(values[Atnum_modes], NCHARS, "{For Share}");
     269           0 :                     else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
     270           0 :                         snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
     271           0 :                     else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
     272             :                     {
     273           0 :                         if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     274           0 :                             snprintf(values[Atnum_modes], NCHARS, "{For Update}");
     275             :                         else
     276           0 :                             snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
     277             :                     }
     278             :                     else
     279             :                         /* neither keyshare nor exclusive bit it set */
     280           0 :                         snprintf(values[Atnum_modes], NCHARS,
     281             :                                  "{transient upgrade status}");
     282             :                 }
     283             :                 else
     284             :                 {
     285           0 :                     if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     286           0 :                         snprintf(values[Atnum_modes], NCHARS, "{Update}");
     287             :                     else
     288           0 :                         snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
     289             :                 }
     290             : 
     291           0 :                 values[Atnum_pids] = palloc(NCHARS * sizeof(char));
     292           0 :                 snprintf(values[Atnum_pids], NCHARS, "{%d}",
     293             :                          BackendXidGetPid(xmax));
     294             :             }
     295             : 
     296           0 :             LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     297             : 
     298             :             /* build a tuple */
     299           0 :             tuple = BuildTupleFromCStrings(attinmeta, values);
     300             : 
     301             :             /* make the tuple into a datum */
     302           0 :             result = HeapTupleGetDatum(tuple);
     303             : 
     304             :             /*
     305             :              * no need to pfree what we allocated; it's on a short-lived
     306             :              * memory context anyway
     307             :              */
     308             : 
     309           0 :             SRF_RETURN_NEXT(funcctx, result);
     310             :         }
     311             :         else
     312             :         {
     313           0 :             LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     314             :         }
     315             :     }
     316             : 
     317           0 :     table_endscan(scan);
     318           0 :     table_close(mydata->rel, AccessShareLock);
     319             : 
     320           0 :     SRF_RETURN_DONE(funcctx);
     321             : }

Generated by: LCOV version 1.13