LCOV - code coverage report
Current view: top level - contrib/pgrowlocks - pgrowlocks.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 0 120 0.0 %
Date: 2020-05-25 06:06:29 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             : #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           0 : pgrowlocks(PG_FUNCTION_ARGS)
      66             : {
      67           0 :     text       *relname = PG_GETARG_TEXT_PP(0);
      68           0 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
      69             :     bool        randomAccess;
      70             :     TupleDesc   tupdesc;
      71             :     Tuplestorestate *tupstore;
      72             :     AttInMetadata *attinmeta;
      73             :     Relation    rel;
      74             :     RangeVar   *relrv;
      75             :     TableScanDesc scan;
      76             :     HeapScanDesc hscan;
      77             :     HeapTuple   tuple;
      78             :     MemoryContext oldcontext;
      79             :     AclResult   aclresult;
      80             :     char      **values;
      81             : 
      82             :     /* check to see if caller supports us returning a tuplestore */
      83           0 :     if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
      84           0 :         ereport(ERROR,
      85             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
      86             :                  errmsg("set-valued function called in context that cannot accept a set")));
      87           0 :     if (!(rsinfo->allowedModes & SFRM_Materialize))
      88           0 :         ereport(ERROR,
      89             :                 (errcode(ERRCODE_SYNTAX_ERROR),
      90             :                  errmsg("materialize mode required, but it is not allowed in this context")));
      91             : 
      92             :     /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
      93           0 :     oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
      94             : 
      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 :     randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
      99           0 :     tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
     100           0 :     rsinfo->returnMode = SFRM_Materialize;
     101           0 :     rsinfo->setResult = tupstore;
     102           0 :     rsinfo->setDesc = tupdesc;
     103             : 
     104           0 :     MemoryContextSwitchTo(oldcontext);
     105             : 
     106             :     /* Access the table */
     107           0 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
     108           0 :     rel = relation_openrv(relrv, AccessShareLock);
     109             : 
     110           0 :     if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
     111           0 :         ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     112             :                         errmsg("only heap AM is supported")));
     113             : 
     114           0 :     if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
     115           0 :         ereport(ERROR,
     116             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     117             :                  errmsg("\"%s\" is a partitioned table",
     118             :                         RelationGetRelationName(rel)),
     119             :                  errdetail("Partitioned tables do not contain rows.")));
     120           0 :     else if (rel->rd_rel->relkind != RELKIND_RELATION)
     121           0 :         ereport(ERROR,
     122             :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
     123             :                  errmsg("\"%s\" is not a table",
     124             :                         RelationGetRelationName(rel))));
     125             : 
     126             :     /*
     127             :      * check permissions: must have SELECT on table or be in
     128             :      * pg_stat_scan_tables
     129             :      */
     130           0 :     aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
     131             :                                   ACL_SELECT);
     132           0 :     if (aclresult != ACLCHECK_OK)
     133           0 :         aclresult = is_member_of_role(GetUserId(), DEFAULT_ROLE_STAT_SCAN_TABLES) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
     134             : 
     135           0 :     if (aclresult != ACLCHECK_OK)
     136           0 :         aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
     137           0 :                        RelationGetRelationName(rel));
     138             : 
     139             :     /* Scan the relation */
     140           0 :     scan = table_beginscan(rel, GetActiveSnapshot(), 0, NULL);
     141           0 :     hscan = (HeapScanDesc) scan;
     142             : 
     143           0 :     attinmeta = TupleDescGetAttInMetadata(tupdesc);
     144             : 
     145           0 :     values = (char **) palloc(tupdesc->natts * sizeof(char *));
     146             : 
     147           0 :     while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
     148             :     {
     149             :         TM_Result   htsu;
     150             :         TransactionId xmax;
     151             :         uint16      infomask;
     152             : 
     153             :         /* must hold a buffer lock to call HeapTupleSatisfiesUpdate */
     154           0 :         LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
     155             : 
     156           0 :         htsu = HeapTupleSatisfiesUpdate(tuple,
     157             :                                         GetCurrentCommandId(false),
     158             :                                         hscan->rs_cbuf);
     159           0 :         xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
     160           0 :         infomask = tuple->t_data->t_infomask;
     161             : 
     162             :         /*
     163             :          * A tuple is locked if HTSU returns BeingModified.
     164             :          */
     165           0 :         if (htsu == TM_BeingModified)
     166             :         {
     167           0 :             values[Atnum_tid] = (char *) DirectFunctionCall1(tidout,
     168             :                                                              PointerGetDatum(&tuple->t_self));
     169             : 
     170           0 :             values[Atnum_xmax] = palloc(NCHARS * sizeof(char));
     171           0 :             snprintf(values[Atnum_xmax], NCHARS, "%d", xmax);
     172           0 :             if (infomask & HEAP_XMAX_IS_MULTI)
     173             :             {
     174             :                 MultiXactMember *members;
     175             :                 int         nmembers;
     176           0 :                 bool        first = true;
     177             :                 bool        allow_old;
     178             : 
     179           0 :                 values[Atnum_ismulti] = pstrdup("true");
     180             : 
     181           0 :                 allow_old = HEAP_LOCKED_UPGRADED(infomask);
     182           0 :                 nmembers = GetMultiXactIdMembers(xmax, &members, allow_old,
     183             :                                                  false);
     184           0 :                 if (nmembers == -1)
     185             :                 {
     186           0 :                     values[Atnum_xids] = "{0}";
     187           0 :                     values[Atnum_modes] = "{transient upgrade status}";
     188           0 :                     values[Atnum_pids] = "{0}";
     189             :                 }
     190             :                 else
     191             :                 {
     192             :                     int         j;
     193             : 
     194           0 :                     values[Atnum_xids] = palloc(NCHARS * nmembers);
     195           0 :                     values[Atnum_modes] = palloc(NCHARS * nmembers);
     196           0 :                     values[Atnum_pids] = palloc(NCHARS * nmembers);
     197             : 
     198           0 :                     strcpy(values[Atnum_xids], "{");
     199           0 :                     strcpy(values[Atnum_modes], "{");
     200           0 :                     strcpy(values[Atnum_pids], "{");
     201             : 
     202           0 :                     for (j = 0; j < nmembers; j++)
     203             :                     {
     204             :                         char        buf[NCHARS];
     205             : 
     206           0 :                         if (!first)
     207             :                         {
     208           0 :                             strcat(values[Atnum_xids], ",");
     209           0 :                             strcat(values[Atnum_modes], ",");
     210           0 :                             strcat(values[Atnum_pids], ",");
     211             :                         }
     212           0 :                         snprintf(buf, NCHARS, "%d", members[j].xid);
     213           0 :                         strcat(values[Atnum_xids], buf);
     214           0 :                         switch (members[j].status)
     215             :                         {
     216           0 :                             case MultiXactStatusUpdate:
     217           0 :                                 snprintf(buf, NCHARS, "Update");
     218           0 :                                 break;
     219           0 :                             case MultiXactStatusNoKeyUpdate:
     220           0 :                                 snprintf(buf, NCHARS, "No Key Update");
     221           0 :                                 break;
     222           0 :                             case MultiXactStatusForUpdate:
     223           0 :                                 snprintf(buf, NCHARS, "For Update");
     224           0 :                                 break;
     225           0 :                             case MultiXactStatusForNoKeyUpdate:
     226           0 :                                 snprintf(buf, NCHARS, "For No Key Update");
     227           0 :                                 break;
     228           0 :                             case MultiXactStatusForShare:
     229           0 :                                 snprintf(buf, NCHARS, "Share");
     230           0 :                                 break;
     231           0 :                             case MultiXactStatusForKeyShare:
     232           0 :                                 snprintf(buf, NCHARS, "Key Share");
     233           0 :                                 break;
     234             :                         }
     235           0 :                         strcat(values[Atnum_modes], buf);
     236           0 :                         snprintf(buf, NCHARS, "%d",
     237           0 :                                  BackendXidGetPid(members[j].xid));
     238           0 :                         strcat(values[Atnum_pids], buf);
     239             : 
     240           0 :                         first = false;
     241             :                     }
     242             : 
     243           0 :                     strcat(values[Atnum_xids], "}");
     244           0 :                     strcat(values[Atnum_modes], "}");
     245           0 :                     strcat(values[Atnum_pids], "}");
     246             :                 }
     247             :             }
     248             :             else
     249             :             {
     250           0 :                 values[Atnum_ismulti] = pstrdup("false");
     251             : 
     252           0 :                 values[Atnum_xids] = palloc(NCHARS * sizeof(char));
     253           0 :                 snprintf(values[Atnum_xids], NCHARS, "{%d}", xmax);
     254             : 
     255           0 :                 values[Atnum_modes] = palloc(NCHARS);
     256           0 :                 if (infomask & HEAP_XMAX_LOCK_ONLY)
     257             :                 {
     258           0 :                     if (HEAP_XMAX_IS_SHR_LOCKED(infomask))
     259           0 :                         snprintf(values[Atnum_modes], NCHARS, "{For Share}");
     260           0 :                     else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
     261           0 :                         snprintf(values[Atnum_modes], NCHARS, "{For Key Share}");
     262           0 :                     else if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
     263             :                     {
     264           0 :                         if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     265           0 :                             snprintf(values[Atnum_modes], NCHARS, "{For Update}");
     266             :                         else
     267           0 :                             snprintf(values[Atnum_modes], NCHARS, "{For No Key Update}");
     268             :                     }
     269             :                     else
     270             :                         /* neither keyshare nor exclusive bit it set */
     271           0 :                         snprintf(values[Atnum_modes], NCHARS,
     272             :                                  "{transient upgrade status}");
     273             :                 }
     274             :                 else
     275             :                 {
     276           0 :                     if (tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED)
     277           0 :                         snprintf(values[Atnum_modes], NCHARS, "{Update}");
     278             :                     else
     279           0 :                         snprintf(values[Atnum_modes], NCHARS, "{No Key Update}");
     280             :                 }
     281             : 
     282           0 :                 values[Atnum_pids] = palloc(NCHARS * sizeof(char));
     283           0 :                 snprintf(values[Atnum_pids], NCHARS, "{%d}",
     284             :                          BackendXidGetPid(xmax));
     285             :             }
     286             : 
     287           0 :             LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     288             : 
     289             :             /* build a tuple */
     290           0 :             tuple = BuildTupleFromCStrings(attinmeta, values);
     291           0 :             tuplestore_puttuple(tupstore, tuple);
     292             :         }
     293             :         else
     294             :         {
     295           0 :             LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_UNLOCK);
     296             :         }
     297             :     }
     298             : 
     299           0 :     table_endscan(scan);
     300           0 :     table_close(rel, AccessShareLock);
     301           0 :     return (Datum) 0;
     302             : }

Generated by: LCOV version 1.13