LCOV - code coverage report
Current view: top level - src/backend/utils/adt - lockfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 300 384 78.1 %
Date: 2024-04-26 08:11:58 Functions: 19 26 73.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * lockfuncs.c
       4             :  *      Functions for SQL access to various lock-manager capabilities.
       5             :  *
       6             :  * Copyright (c) 2002-2024, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *      src/backend/utils/adt/lockfuncs.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include "access/htup_details.h"
      16             : #include "catalog/pg_type.h"
      17             : #include "funcapi.h"
      18             : #include "miscadmin.h"
      19             : #include "storage/predicate_internals.h"
      20             : #include "utils/array.h"
      21             : #include "utils/builtins.h"
      22             : 
      23             : 
      24             : /*
      25             :  * This must match enum LockTagType!  Also, be sure to document any changes
      26             :  * in the docs for the pg_locks view and update the WaitEventLOCK section in
      27             :  * src/backend/utils/activity/wait_event_names.txt.
      28             :  */
      29             : const char *const LockTagTypeNames[] = {
      30             :     "relation",
      31             :     "extend",
      32             :     "frozenid",
      33             :     "page",
      34             :     "tuple",
      35             :     "transactionid",
      36             :     "virtualxid",
      37             :     "spectoken",
      38             :     "object",
      39             :     "userlock",
      40             :     "advisory",
      41             :     "applytransaction"
      42             : };
      43             : 
      44             : StaticAssertDecl(lengthof(LockTagTypeNames) == (LOCKTAG_LAST_TYPE + 1),
      45             :                  "array length mismatch");
      46             : 
      47             : /* This must match enum PredicateLockTargetType (predicate_internals.h) */
      48             : static const char *const PredicateLockTagTypeNames[] = {
      49             :     "relation",
      50             :     "page",
      51             :     "tuple"
      52             : };
      53             : 
      54             : StaticAssertDecl(lengthof(PredicateLockTagTypeNames) == (PREDLOCKTAG_TUPLE + 1),
      55             :                  "array length mismatch");
      56             : 
      57             : /* Working status for pg_lock_status */
      58             : typedef struct
      59             : {
      60             :     LockData   *lockData;       /* state data from lmgr */
      61             :     int         currIdx;        /* current PROCLOCK index */
      62             :     PredicateLockData *predLockData;    /* state data for pred locks */
      63             :     int         predLockIdx;    /* current index for pred lock */
      64             : } PG_Lock_Status;
      65             : 
      66             : /* Number of columns in pg_locks output */
      67             : #define NUM_LOCK_STATUS_COLUMNS     16
      68             : 
      69             : /*
      70             :  * VXIDGetDatum - Construct a text representation of a VXID
      71             :  *
      72             :  * This is currently only used in pg_lock_status, so we put it here.
      73             :  */
      74             : static Datum
      75       13630 : VXIDGetDatum(ProcNumber procNumber, LocalTransactionId lxid)
      76             : {
      77             :     /*
      78             :      * The representation is "<procNumber>/<lxid>", decimal and unsigned
      79             :      * decimal respectively.  Note that elog.c also knows how to format a
      80             :      * vxid.
      81             :      */
      82             :     char        vxidstr[32];
      83             : 
      84       13630 :     snprintf(vxidstr, sizeof(vxidstr), "%d/%u", procNumber, lxid);
      85             : 
      86       13630 :     return CStringGetTextDatum(vxidstr);
      87             : }
      88             : 
      89             : 
      90             : /*
      91             :  * pg_lock_status - produce a view with one row per held or awaited lock mode
      92             :  */
      93             : Datum
      94       12476 : pg_lock_status(PG_FUNCTION_ARGS)
      95             : {
      96             :     FuncCallContext *funcctx;
      97             :     PG_Lock_Status *mystatus;
      98             :     LockData   *lockData;
      99             :     PredicateLockData *predLockData;
     100             : 
     101       12476 :     if (SRF_IS_FIRSTCALL())
     102             :     {
     103             :         TupleDesc   tupdesc;
     104             :         MemoryContext oldcontext;
     105             : 
     106             :         /* create a function context for cross-call persistence */
     107         592 :         funcctx = SRF_FIRSTCALL_INIT();
     108             : 
     109             :         /*
     110             :          * switch to memory context appropriate for multiple function calls
     111             :          */
     112         592 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     113             : 
     114             :         /* build tupdesc for result tuples */
     115             :         /* this had better match function's declaration in pg_proc.h */
     116         592 :         tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
     117         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
     118             :                            TEXTOID, -1, 0);
     119         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
     120             :                            OIDOID, -1, 0);
     121         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
     122             :                            OIDOID, -1, 0);
     123         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
     124             :                            INT4OID, -1, 0);
     125         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
     126             :                            INT2OID, -1, 0);
     127         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
     128             :                            TEXTOID, -1, 0);
     129         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
     130             :                            XIDOID, -1, 0);
     131         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
     132             :                            OIDOID, -1, 0);
     133         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
     134             :                            OIDOID, -1, 0);
     135         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
     136             :                            INT2OID, -1, 0);
     137         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
     138             :                            TEXTOID, -1, 0);
     139         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
     140             :                            INT4OID, -1, 0);
     141         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
     142             :                            TEXTOID, -1, 0);
     143         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
     144             :                            BOOLOID, -1, 0);
     145         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
     146             :                            BOOLOID, -1, 0);
     147         592 :         TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
     148             :                            TIMESTAMPTZOID, -1, 0);
     149             : 
     150         592 :         funcctx->tuple_desc = BlessTupleDesc(tupdesc);
     151             : 
     152             :         /*
     153             :          * Collect all the locking information that we will format and send
     154             :          * out as a result set.
     155             :          */
     156         592 :         mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
     157         592 :         funcctx->user_fctx = (void *) mystatus;
     158             : 
     159         592 :         mystatus->lockData = GetLockStatusData();
     160         592 :         mystatus->currIdx = 0;
     161         592 :         mystatus->predLockData = GetPredicateLockStatusData();
     162         592 :         mystatus->predLockIdx = 0;
     163             : 
     164         592 :         MemoryContextSwitchTo(oldcontext);
     165             :     }
     166             : 
     167       12476 :     funcctx = SRF_PERCALL_SETUP();
     168       12476 :     mystatus = (PG_Lock_Status *) funcctx->user_fctx;
     169       12476 :     lockData = mystatus->lockData;
     170             : 
     171       23912 :     while (mystatus->currIdx < lockData->nelements)
     172             :     {
     173             :         bool        granted;
     174       23314 :         LOCKMODE    mode = 0;
     175             :         const char *locktypename;
     176             :         char        tnbuf[32];
     177       23314 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     178       23314 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     179             :         HeapTuple   tuple;
     180             :         Datum       result;
     181             :         LockInstanceData *instance;
     182             : 
     183       23314 :         instance = &(lockData->locks[mystatus->currIdx]);
     184             : 
     185             :         /*
     186             :          * Look to see if there are any held lock modes in this PROCLOCK. If
     187             :          * so, report, and destructively modify lockData so we don't report
     188             :          * again.
     189             :          */
     190       23314 :         granted = false;
     191       23314 :         if (instance->holdMask)
     192             :         {
     193       63370 :             for (mode = 0; mode < MAX_LOCKMODES; mode++)
     194             :             {
     195       63370 :                 if (instance->holdMask & LOCKBIT_ON(mode))
     196             :                 {
     197       11860 :                     granted = true;
     198       11860 :                     instance->holdMask &= LOCKBIT_OFF(mode);
     199       11860 :                     break;
     200             :                 }
     201             :             }
     202             :         }
     203             : 
     204             :         /*
     205             :          * If no (more) held modes to report, see if PROC is waiting for a
     206             :          * lock on this lock.
     207             :          */
     208       23314 :         if (!granted)
     209             :         {
     210       11454 :             if (instance->waitLockMode != NoLock)
     211             :             {
     212             :                 /* Yes, so report it with proper mode */
     213          18 :                 mode = instance->waitLockMode;
     214             : 
     215             :                 /*
     216             :                  * We are now done with this PROCLOCK, so advance pointer to
     217             :                  * continue with next one on next call.
     218             :                  */
     219          18 :                 mystatus->currIdx++;
     220             :             }
     221             :             else
     222             :             {
     223             :                 /*
     224             :                  * Okay, we've displayed all the locks associated with this
     225             :                  * PROCLOCK, proceed to the next one.
     226             :                  */
     227       11436 :                 mystatus->currIdx++;
     228       11436 :                 continue;
     229             :             }
     230             :         }
     231             : 
     232             :         /*
     233             :          * Form tuple with appropriate data.
     234             :          */
     235             : 
     236       11878 :         if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
     237       11878 :             locktypename = LockTagTypeNames[instance->locktag.locktag_type];
     238             :         else
     239             :         {
     240           0 :             snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
     241           0 :                      (int) instance->locktag.locktag_type);
     242           0 :             locktypename = tnbuf;
     243             :         }
     244       11878 :         values[0] = CStringGetTextDatum(locktypename);
     245             : 
     246       11878 :         switch ((LockTagType) instance->locktag.locktag_type)
     247             :         {
     248        7260 :             case LOCKTAG_RELATION:
     249             :             case LOCKTAG_RELATION_EXTEND:
     250        7260 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     251        7260 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     252        7260 :                 nulls[3] = true;
     253        7260 :                 nulls[4] = true;
     254        7260 :                 nulls[5] = true;
     255        7260 :                 nulls[6] = true;
     256        7260 :                 nulls[7] = true;
     257        7260 :                 nulls[8] = true;
     258        7260 :                 nulls[9] = true;
     259        7260 :                 break;
     260           0 :             case LOCKTAG_DATABASE_FROZEN_IDS:
     261           0 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     262           0 :                 nulls[2] = true;
     263           0 :                 nulls[3] = true;
     264           0 :                 nulls[4] = true;
     265           0 :                 nulls[5] = true;
     266           0 :                 nulls[6] = true;
     267           0 :                 nulls[7] = true;
     268           0 :                 nulls[8] = true;
     269           0 :                 nulls[9] = true;
     270           0 :                 break;
     271          10 :             case LOCKTAG_PAGE:
     272          10 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     273          10 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     274          10 :                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     275          10 :                 nulls[4] = true;
     276          10 :                 nulls[5] = true;
     277          10 :                 nulls[6] = true;
     278          10 :                 nulls[7] = true;
     279          10 :                 nulls[8] = true;
     280          10 :                 nulls[9] = true;
     281          10 :                 break;
     282           0 :             case LOCKTAG_TUPLE:
     283           0 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     284           0 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     285           0 :                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     286           0 :                 values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
     287           0 :                 nulls[5] = true;
     288           0 :                 nulls[6] = true;
     289           0 :                 nulls[7] = true;
     290           0 :                 nulls[8] = true;
     291           0 :                 nulls[9] = true;
     292           0 :                 break;
     293        1004 :             case LOCKTAG_TRANSACTION:
     294        1004 :                 values[6] =
     295        1004 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     296        1004 :                 nulls[1] = true;
     297        1004 :                 nulls[2] = true;
     298        1004 :                 nulls[3] = true;
     299        1004 :                 nulls[4] = true;
     300        1004 :                 nulls[5] = true;
     301        1004 :                 nulls[7] = true;
     302        1004 :                 nulls[8] = true;
     303        1004 :                 nulls[9] = true;
     304        1004 :                 break;
     305        1746 :             case LOCKTAG_VIRTUALTRANSACTION:
     306        1746 :                 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
     307             :                                          instance->locktag.locktag_field2);
     308        1746 :                 nulls[1] = true;
     309        1746 :                 nulls[2] = true;
     310        1746 :                 nulls[3] = true;
     311        1746 :                 nulls[4] = true;
     312        1746 :                 nulls[6] = true;
     313        1746 :                 nulls[7] = true;
     314        1746 :                 nulls[8] = true;
     315        1746 :                 nulls[9] = true;
     316        1746 :                 break;
     317           4 :             case LOCKTAG_SPECULATIVE_TOKEN:
     318           4 :                 values[6] =
     319           4 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     320           4 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     321           4 :                 nulls[1] = true;
     322           4 :                 nulls[2] = true;
     323           4 :                 nulls[3] = true;
     324           4 :                 nulls[4] = true;
     325           4 :                 nulls[5] = true;
     326           4 :                 nulls[7] = true;
     327           4 :                 nulls[9] = true;
     328           4 :                 break;
     329           0 :             case LOCKTAG_APPLY_TRANSACTION:
     330           0 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     331           0 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     332           0 :                 values[6] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     333           0 :                 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
     334           0 :                 nulls[2] = true;
     335           0 :                 nulls[3] = true;
     336           0 :                 nulls[4] = true;
     337           0 :                 nulls[5] = true;
     338           0 :                 nulls[7] = true;
     339           0 :                 break;
     340        1854 :             case LOCKTAG_OBJECT:
     341             :             case LOCKTAG_USERLOCK:
     342             :             case LOCKTAG_ADVISORY:
     343             :             default:            /* treat unknown locktags like OBJECT */
     344        1854 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     345        1854 :                 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     346        1854 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     347        1854 :                 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
     348        1854 :                 nulls[2] = true;
     349        1854 :                 nulls[3] = true;
     350        1854 :                 nulls[4] = true;
     351        1854 :                 nulls[5] = true;
     352        1854 :                 nulls[6] = true;
     353        1854 :                 break;
     354             :         }
     355             : 
     356       11878 :         values[10] = VXIDGetDatum(instance->vxid.procNumber, instance->vxid.localTransactionId);
     357       11878 :         if (instance->pid != 0)
     358       11836 :             values[11] = Int32GetDatum(instance->pid);
     359             :         else
     360          42 :             nulls[11] = true;
     361       11878 :         values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
     362       11878 :         values[13] = BoolGetDatum(granted);
     363       11878 :         values[14] = BoolGetDatum(instance->fastpath);
     364       11878 :         if (!granted && instance->waitStart != 0)
     365          18 :             values[15] = TimestampTzGetDatum(instance->waitStart);
     366             :         else
     367       11860 :             nulls[15] = true;
     368             : 
     369       11878 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     370       11878 :         result = HeapTupleGetDatum(tuple);
     371       11878 :         SRF_RETURN_NEXT(funcctx, result);
     372             :     }
     373             : 
     374             :     /*
     375             :      * Have returned all regular locks. Now start on the SIREAD predicate
     376             :      * locks.
     377             :      */
     378         598 :     predLockData = mystatus->predLockData;
     379         598 :     if (mystatus->predLockIdx < predLockData->nelements)
     380             :     {
     381             :         PredicateLockTargetType lockType;
     382             : 
     383           6 :         PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
     384           6 :         SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
     385           6 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     386           6 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     387             :         HeapTuple   tuple;
     388             :         Datum       result;
     389             : 
     390           6 :         mystatus->predLockIdx++;
     391             : 
     392             :         /*
     393             :          * Form tuple with appropriate data.
     394             :          */
     395             : 
     396             :         /* lock type */
     397           6 :         lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
     398             : 
     399           6 :         values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
     400             : 
     401             :         /* lock target */
     402           6 :         values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
     403           6 :         values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
     404           6 :         if (lockType == PREDLOCKTAG_TUPLE)
     405           6 :             values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
     406             :         else
     407           0 :             nulls[4] = true;
     408           6 :         if ((lockType == PREDLOCKTAG_TUPLE) ||
     409             :             (lockType == PREDLOCKTAG_PAGE))
     410           6 :             values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
     411             :         else
     412           0 :             nulls[3] = true;
     413             : 
     414             :         /* these fields are targets for other types of locks */
     415           6 :         nulls[5] = true;        /* virtualxid */
     416           6 :         nulls[6] = true;        /* transactionid */
     417           6 :         nulls[7] = true;        /* classid */
     418           6 :         nulls[8] = true;        /* objid */
     419           6 :         nulls[9] = true;        /* objsubid */
     420             : 
     421             :         /* lock holder */
     422           6 :         values[10] = VXIDGetDatum(xact->vxid.procNumber,
     423             :                                   xact->vxid.localTransactionId);
     424           6 :         if (xact->pid != 0)
     425           6 :             values[11] = Int32GetDatum(xact->pid);
     426             :         else
     427           0 :             nulls[11] = true;
     428             : 
     429             :         /*
     430             :          * Lock mode. Currently all predicate locks are SIReadLocks, which are
     431             :          * always held (never waiting) and have no fast path
     432             :          */
     433           6 :         values[12] = CStringGetTextDatum("SIReadLock");
     434           6 :         values[13] = BoolGetDatum(true);
     435           6 :         values[14] = BoolGetDatum(false);
     436           6 :         nulls[15] = true;
     437             : 
     438           6 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     439           6 :         result = HeapTupleGetDatum(tuple);
     440           6 :         SRF_RETURN_NEXT(funcctx, result);
     441             :     }
     442             : 
     443         592 :     SRF_RETURN_DONE(funcctx);
     444             : }
     445             : 
     446             : 
     447             : /*
     448             :  * pg_blocking_pids - produce an array of the PIDs blocking given PID
     449             :  *
     450             :  * The reported PIDs are those that hold a lock conflicting with blocked_pid's
     451             :  * current request (hard block), or are requesting such a lock and are ahead
     452             :  * of blocked_pid in the lock's wait queue (soft block).
     453             :  *
     454             :  * In parallel-query cases, we report all PIDs blocking any member of the
     455             :  * given PID's lock group, and the reported PIDs are those of the blocking
     456             :  * PIDs' lock group leaders.  This allows callers to compare the result to
     457             :  * lists of clients' pg_backend_pid() results even during a parallel query.
     458             :  *
     459             :  * Parallel query makes it possible for there to be duplicate PIDs in the
     460             :  * result (either because multiple waiters are blocked by same PID, or
     461             :  * because multiple blockers have same group leader PID).  We do not bother
     462             :  * to eliminate such duplicates from the result.
     463             :  *
     464             :  * We need not consider predicate locks here, since those don't block anything.
     465             :  */
     466             : Datum
     467        3010 : pg_blocking_pids(PG_FUNCTION_ARGS)
     468             : {
     469        3010 :     int         blocked_pid = PG_GETARG_INT32(0);
     470             :     Datum      *arrayelems;
     471             :     int         narrayelems;
     472             :     BlockedProcsData *lockData; /* state data from lmgr */
     473             :     int         i,
     474             :                 j;
     475             : 
     476             :     /* Collect a snapshot of lock manager state */
     477        3010 :     lockData = GetBlockerStatusData(blocked_pid);
     478             : 
     479             :     /* We can't need more output entries than there are reported PROCLOCKs */
     480        3010 :     arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
     481        3010 :     narrayelems = 0;
     482             : 
     483             :     /* For each blocked proc in the lock group ... */
     484        5244 :     for (i = 0; i < lockData->nprocs; i++)
     485             :     {
     486        2234 :         BlockedProcData *bproc = &lockData->procs[i];
     487        2234 :         LockInstanceData *instances = &lockData->locks[bproc->first_lock];
     488        2234 :         int        *preceding_waiters = &lockData->waiter_pids[bproc->first_waiter];
     489             :         LockInstanceData *blocked_instance;
     490             :         LockMethod  lockMethodTable;
     491             :         int         conflictMask;
     492             : 
     493             :         /*
     494             :          * Locate the blocked proc's own entry in the LockInstanceData array.
     495             :          * There should be exactly one matching entry.
     496             :          */
     497        2234 :         blocked_instance = NULL;
     498        6790 :         for (j = 0; j < bproc->num_locks; j++)
     499             :         {
     500        4556 :             LockInstanceData *instance = &(instances[j]);
     501             : 
     502        4556 :             if (instance->pid == bproc->pid)
     503             :             {
     504             :                 Assert(blocked_instance == NULL);
     505        2234 :                 blocked_instance = instance;
     506             :             }
     507             :         }
     508             :         Assert(blocked_instance != NULL);
     509             : 
     510        2234 :         lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
     511        2234 :         conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
     512             : 
     513             :         /* Now scan the PROCLOCK data for conflicting procs */
     514        6790 :         for (j = 0; j < bproc->num_locks; j++)
     515             :         {
     516        4556 :             LockInstanceData *instance = &(instances[j]);
     517             : 
     518             :             /* A proc never blocks itself, so ignore that entry */
     519        4556 :             if (instance == blocked_instance)
     520        2234 :                 continue;
     521             :             /* Members of same lock group never block each other, either */
     522        2322 :             if (instance->leaderPid == blocked_instance->leaderPid)
     523           0 :                 continue;
     524             : 
     525        2322 :             if (conflictMask & instance->holdMask)
     526             :             {
     527             :                 /* hard block: blocked by lock already held by this entry */
     528             :             }
     529          86 :             else if (instance->waitLockMode != NoLock &&
     530          78 :                      (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
     531          16 :             {
     532             :                 /* conflict in lock requests; who's in front in wait queue? */
     533          38 :                 bool        ahead = false;
     534             :                 int         k;
     535             : 
     536          38 :                 for (k = 0; k < bproc->num_waiters; k++)
     537             :                 {
     538          16 :                     if (preceding_waiters[k] == instance->pid)
     539             :                     {
     540             :                         /* soft block: this entry is ahead of blocked proc */
     541          16 :                         ahead = true;
     542          16 :                         break;
     543             :                     }
     544             :                 }
     545          38 :                 if (!ahead)
     546          22 :                     continue;   /* not blocked by this entry */
     547             :             }
     548             :             else
     549             :             {
     550             :                 /* not blocked by this entry */
     551          48 :                 continue;
     552             :             }
     553             : 
     554             :             /* blocked by this entry, so emit a record */
     555        2252 :             arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
     556             :         }
     557             :     }
     558             : 
     559             :     /* Assert we didn't overrun arrayelems[] */
     560             :     Assert(narrayelems <= lockData->nlocks);
     561             : 
     562        3010 :     PG_RETURN_ARRAYTYPE_P(construct_array_builtin(arrayelems, narrayelems, INT4OID));
     563             : }
     564             : 
     565             : 
     566             : /*
     567             :  * pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
     568             :  * given PID from getting a safe snapshot
     569             :  *
     570             :  * XXX this does not consider parallel-query cases; not clear how big a
     571             :  * problem that is in practice
     572             :  */
     573             : Datum
     574           0 : pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
     575             : {
     576           0 :     int         blocked_pid = PG_GETARG_INT32(0);
     577             :     int        *blockers;
     578             :     int         num_blockers;
     579             :     Datum      *blocker_datums;
     580             : 
     581             :     /* A buffer big enough for any possible blocker list without truncation */
     582           0 :     blockers = (int *) palloc(MaxBackends * sizeof(int));
     583             : 
     584             :     /* Collect a snapshot of processes waited for by GetSafeSnapshot */
     585             :     num_blockers =
     586           0 :         GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
     587             : 
     588             :     /* Convert int array to Datum array */
     589           0 :     if (num_blockers > 0)
     590             :     {
     591             :         int         i;
     592             : 
     593           0 :         blocker_datums = (Datum *) palloc(num_blockers * sizeof(Datum));
     594           0 :         for (i = 0; i < num_blockers; ++i)
     595           0 :             blocker_datums[i] = Int32GetDatum(blockers[i]);
     596             :     }
     597             :     else
     598           0 :         blocker_datums = NULL;
     599             : 
     600           0 :     PG_RETURN_ARRAYTYPE_P(construct_array_builtin(blocker_datums, num_blockers, INT4OID));
     601             : }
     602             : 
     603             : 
     604             : /*
     605             :  * pg_isolation_test_session_is_blocked - support function for isolationtester
     606             :  *
     607             :  * Check if specified PID is blocked by any of the PIDs listed in the second
     608             :  * argument.  Currently, this looks for blocking caused by waiting for
     609             :  * heavyweight locks or safe snapshots.  We ignore blockage caused by PIDs
     610             :  * not directly under the isolationtester's control, eg autovacuum.
     611             :  *
     612             :  * This is an undocumented function intended for use by the isolation tester,
     613             :  * and may change in future releases as required for testing purposes.
     614             :  */
     615             : Datum
     616        3010 : pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
     617             : {
     618        3010 :     int         blocked_pid = PG_GETARG_INT32(0);
     619        3010 :     ArrayType  *interesting_pids_a = PG_GETARG_ARRAYTYPE_P(1);
     620             :     ArrayType  *blocking_pids_a;
     621             :     int32      *interesting_pids;
     622             :     int32      *blocking_pids;
     623             :     int         num_interesting_pids;
     624             :     int         num_blocking_pids;
     625             :     int         dummy;
     626             :     int         i,
     627             :                 j;
     628             : 
     629             :     /* Validate the passed-in array */
     630             :     Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID);
     631        3010 :     if (array_contains_nulls(interesting_pids_a))
     632           0 :         elog(ERROR, "array must not contain nulls");
     633        3010 :     interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
     634        3010 :     num_interesting_pids = ArrayGetNItems(ARR_NDIM(interesting_pids_a),
     635             :                                           ARR_DIMS(interesting_pids_a));
     636             : 
     637             :     /*
     638             :      * Get the PIDs of all sessions blocking the given session's attempt to
     639             :      * acquire heavyweight locks.
     640             :      */
     641             :     blocking_pids_a =
     642        3010 :         DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids, blocked_pid));
     643             : 
     644             :     Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
     645             :     Assert(!array_contains_nulls(blocking_pids_a));
     646        3010 :     blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
     647        3010 :     num_blocking_pids = ArrayGetNItems(ARR_NDIM(blocking_pids_a),
     648             :                                        ARR_DIMS(blocking_pids_a));
     649             : 
     650             :     /*
     651             :      * Check if any of these are in the list of interesting PIDs, that being
     652             :      * the sessions that the isolation tester is running.  We don't use
     653             :      * "arrayoverlaps" here, because it would lead to cache lookups and one of
     654             :      * our goals is to run quickly with debug_discard_caches > 0.  We expect
     655             :      * blocking_pids to be usually empty and otherwise a very small number in
     656             :      * isolation tester cases, so make that the outer loop of a naive search
     657             :      * for a match.
     658             :      */
     659        3010 :     for (i = 0; i < num_blocking_pids; i++)
     660        3376 :         for (j = 0; j < num_interesting_pids; j++)
     661             :         {
     662        3376 :             if (blocking_pids[i] == interesting_pids[j])
     663        2234 :                 PG_RETURN_BOOL(true);
     664             :         }
     665             : 
     666             :     /*
     667             :      * Check if blocked_pid is waiting for a safe snapshot.  We could in
     668             :      * theory check the resulting array of blocker PIDs against the
     669             :      * interesting PIDs list, but since there is no danger of autovacuum
     670             :      * blocking GetSafeSnapshot there seems to be no point in expending cycles
     671             :      * on allocating a buffer and searching for overlap; so it's presently
     672             :      * sufficient for the isolation tester's purposes to use a single element
     673             :      * buffer and check if the number of safe snapshot blockers is non-zero.
     674             :      */
     675         776 :     if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
     676           4 :         PG_RETURN_BOOL(true);
     677             : 
     678         772 :     PG_RETURN_BOOL(false);
     679             : }
     680             : 
     681             : 
     682             : /*
     683             :  * Functions for manipulating advisory locks
     684             :  *
     685             :  * We make use of the locktag fields as follows:
     686             :  *
     687             :  *  field1: MyDatabaseId ... ensures locks are local to each database
     688             :  *  field2: first of 2 int4 keys, or high-order half of an int8 key
     689             :  *  field3: second of 2 int4 keys, or low-order half of an int8 key
     690             :  *  field4: 1 if using an int8 key, 2 if using 2 int4 keys
     691             :  */
     692             : #define SET_LOCKTAG_INT64(tag, key64) \
     693             :     SET_LOCKTAG_ADVISORY(tag, \
     694             :                          MyDatabaseId, \
     695             :                          (uint32) ((key64) >> 32), \
     696             :                          (uint32) (key64), \
     697             :                          1)
     698             : #define SET_LOCKTAG_INT32(tag, key1, key2) \
     699             :     SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
     700             : 
     701             : /*
     702             :  * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
     703             :  */
     704             : Datum
     705         424 : pg_advisory_lock_int8(PG_FUNCTION_ARGS)
     706             : {
     707         424 :     int64       key = PG_GETARG_INT64(0);
     708             :     LOCKTAG     tag;
     709             : 
     710         424 :     SET_LOCKTAG_INT64(tag, key);
     711             : 
     712         424 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     713             : 
     714         422 :     PG_RETURN_VOID();
     715             : }
     716             : 
     717             : /*
     718             :  * pg_advisory_xact_lock(int8) - acquire xact scoped
     719             :  * exclusive lock on an int8 key
     720             :  */
     721             : Datum
     722          60 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     723             : {
     724          60 :     int64       key = PG_GETARG_INT64(0);
     725             :     LOCKTAG     tag;
     726             : 
     727          60 :     SET_LOCKTAG_INT64(tag, key);
     728             : 
     729          60 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     730             : 
     731          60 :     PG_RETURN_VOID();
     732             : }
     733             : 
     734             : /*
     735             :  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
     736             :  */
     737             : Datum
     738          56 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     739             : {
     740          56 :     int64       key = PG_GETARG_INT64(0);
     741             :     LOCKTAG     tag;
     742             : 
     743          56 :     SET_LOCKTAG_INT64(tag, key);
     744             : 
     745          56 :     (void) LockAcquire(&tag, ShareLock, true, false);
     746             : 
     747          56 :     PG_RETURN_VOID();
     748             : }
     749             : 
     750             : /*
     751             :  * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
     752             :  * share lock on an int8 key
     753             :  */
     754             : Datum
     755       40042 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     756             : {
     757       40042 :     int64       key = PG_GETARG_INT64(0);
     758             :     LOCKTAG     tag;
     759             : 
     760       40042 :     SET_LOCKTAG_INT64(tag, key);
     761             : 
     762       40042 :     (void) LockAcquire(&tag, ShareLock, false, false);
     763             : 
     764       40042 :     PG_RETURN_VOID();
     765             : }
     766             : 
     767             : /*
     768             :  * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
     769             :  *
     770             :  * Returns true if successful, false if lock not available
     771             :  */
     772             : Datum
     773         848 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
     774             : {
     775         848 :     int64       key = PG_GETARG_INT64(0);
     776             :     LOCKTAG     tag;
     777             :     LockAcquireResult res;
     778             : 
     779         848 :     SET_LOCKTAG_INT64(tag, key);
     780             : 
     781         848 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     782             : 
     783         848 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     784             : }
     785             : 
     786             : /*
     787             :  * pg_try_advisory_xact_lock(int8) - acquire xact scoped
     788             :  * exclusive lock on an int8 key, no wait
     789             :  *
     790             :  * Returns true if successful, false if lock not available
     791             :  */
     792             : Datum
     793           0 : pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     794             : {
     795           0 :     int64       key = PG_GETARG_INT64(0);
     796             :     LOCKTAG     tag;
     797             :     LockAcquireResult res;
     798             : 
     799           0 :     SET_LOCKTAG_INT64(tag, key);
     800             : 
     801           0 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     802             : 
     803           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     804             : }
     805             : 
     806             : /*
     807             :  * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
     808             :  *
     809             :  * Returns true if successful, false if lock not available
     810             :  */
     811             : Datum
     812           0 : pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     813             : {
     814           0 :     int64       key = PG_GETARG_INT64(0);
     815             :     LOCKTAG     tag;
     816             :     LockAcquireResult res;
     817             : 
     818           0 :     SET_LOCKTAG_INT64(tag, key);
     819             : 
     820           0 :     res = LockAcquire(&tag, ShareLock, true, true);
     821             : 
     822           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     823             : }
     824             : 
     825             : /*
     826             :  * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
     827             :  * share lock on an int8 key, no wait
     828             :  *
     829             :  * Returns true if successful, false if lock not available
     830             :  */
     831             : Datum
     832           0 : pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     833             : {
     834           0 :     int64       key = PG_GETARG_INT64(0);
     835             :     LOCKTAG     tag;
     836             :     LockAcquireResult res;
     837             : 
     838           0 :     SET_LOCKTAG_INT64(tag, key);
     839             : 
     840           0 :     res = LockAcquire(&tag, ShareLock, false, true);
     841             : 
     842           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     843             : }
     844             : 
     845             : /*
     846             :  * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
     847             :  *
     848             :  * Returns true if successful, false if lock was not held
     849             : */
     850             : Datum
     851         304 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
     852             : {
     853         304 :     int64       key = PG_GETARG_INT64(0);
     854             :     LOCKTAG     tag;
     855             :     bool        res;
     856             : 
     857         304 :     SET_LOCKTAG_INT64(tag, key);
     858             : 
     859         304 :     res = LockRelease(&tag, ExclusiveLock, true);
     860             : 
     861         304 :     PG_RETURN_BOOL(res);
     862             : }
     863             : 
     864             : /*
     865             :  * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
     866             :  *
     867             :  * Returns true if successful, false if lock was not held
     868             :  */
     869             : Datum
     870          30 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
     871             : {
     872          30 :     int64       key = PG_GETARG_INT64(0);
     873             :     LOCKTAG     tag;
     874             :     bool        res;
     875             : 
     876          30 :     SET_LOCKTAG_INT64(tag, key);
     877             : 
     878          30 :     res = LockRelease(&tag, ShareLock, true);
     879             : 
     880          30 :     PG_RETURN_BOOL(res);
     881             : }
     882             : 
     883             : /*
     884             :  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
     885             :  */
     886             : Datum
     887          98 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
     888             : {
     889          98 :     int32       key1 = PG_GETARG_INT32(0);
     890          98 :     int32       key2 = PG_GETARG_INT32(1);
     891             :     LOCKTAG     tag;
     892             : 
     893          98 :     SET_LOCKTAG_INT32(tag, key1, key2);
     894             : 
     895          98 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     896             : 
     897          98 :     PG_RETURN_VOID();
     898             : }
     899             : 
     900             : /*
     901             :  * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
     902             :  * exclusive lock on 2 int4 keys
     903             :  */
     904             : Datum
     905         100 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     906             : {
     907         100 :     int32       key1 = PG_GETARG_INT32(0);
     908         100 :     int32       key2 = PG_GETARG_INT32(1);
     909             :     LOCKTAG     tag;
     910             : 
     911         100 :     SET_LOCKTAG_INT32(tag, key1, key2);
     912             : 
     913         100 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     914             : 
     915         100 :     PG_RETURN_VOID();
     916             : }
     917             : 
     918             : /*
     919             :  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
     920             :  */
     921             : Datum
     922          36 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     923             : {
     924          36 :     int32       key1 = PG_GETARG_INT32(0);
     925          36 :     int32       key2 = PG_GETARG_INT32(1);
     926             :     LOCKTAG     tag;
     927             : 
     928          36 :     SET_LOCKTAG_INT32(tag, key1, key2);
     929             : 
     930          36 :     (void) LockAcquire(&tag, ShareLock, true, false);
     931             : 
     932          36 :     PG_RETURN_VOID();
     933             : }
     934             : 
     935             : /*
     936             :  * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     937             :  * share lock on 2 int4 keys
     938             :  */
     939             : Datum
     940          30 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     941             : {
     942          30 :     int32       key1 = PG_GETARG_INT32(0);
     943          30 :     int32       key2 = PG_GETARG_INT32(1);
     944             :     LOCKTAG     tag;
     945             : 
     946          30 :     SET_LOCKTAG_INT32(tag, key1, key2);
     947             : 
     948          30 :     (void) LockAcquire(&tag, ShareLock, false, false);
     949             : 
     950          30 :     PG_RETURN_VOID();
     951             : }
     952             : 
     953             : /*
     954             :  * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
     955             :  *
     956             :  * Returns true if successful, false if lock not available
     957             :  */
     958             : Datum
     959           0 : pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
     960             : {
     961           0 :     int32       key1 = PG_GETARG_INT32(0);
     962           0 :     int32       key2 = PG_GETARG_INT32(1);
     963             :     LOCKTAG     tag;
     964             :     LockAcquireResult res;
     965             : 
     966           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     967             : 
     968           0 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     969             : 
     970           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     971             : }
     972             : 
     973             : /*
     974             :  * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
     975             :  * exclusive lock on 2 int4 keys, no wait
     976             :  *
     977             :  * Returns true if successful, false if lock not available
     978             :  */
     979             : Datum
     980          66 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     981             : {
     982          66 :     int32       key1 = PG_GETARG_INT32(0);
     983          66 :     int32       key2 = PG_GETARG_INT32(1);
     984             :     LOCKTAG     tag;
     985             :     LockAcquireResult res;
     986             : 
     987          66 :     SET_LOCKTAG_INT32(tag, key1, key2);
     988             : 
     989          66 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     990             : 
     991          66 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     992             : }
     993             : 
     994             : /*
     995             :  * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
     996             :  *
     997             :  * Returns true if successful, false if lock not available
     998             :  */
     999             : Datum
    1000           0 : pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
    1001             : {
    1002           0 :     int32       key1 = PG_GETARG_INT32(0);
    1003           0 :     int32       key2 = PG_GETARG_INT32(1);
    1004             :     LOCKTAG     tag;
    1005             :     LockAcquireResult res;
    1006             : 
    1007           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
    1008             : 
    1009           0 :     res = LockAcquire(&tag, ShareLock, true, true);
    1010             : 
    1011           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
    1012             : }
    1013             : 
    1014             : /*
    1015             :  * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
    1016             :  * share lock on 2 int4 keys, no wait
    1017             :  *
    1018             :  * Returns true if successful, false if lock not available
    1019             :  */
    1020             : Datum
    1021           0 : pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
    1022             : {
    1023           0 :     int32       key1 = PG_GETARG_INT32(0);
    1024           0 :     int32       key2 = PG_GETARG_INT32(1);
    1025             :     LOCKTAG     tag;
    1026             :     LockAcquireResult res;
    1027             : 
    1028           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
    1029             : 
    1030           0 :     res = LockAcquire(&tag, ShareLock, false, true);
    1031             : 
    1032           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
    1033             : }
    1034             : 
    1035             : /*
    1036             :  * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
    1037             :  *
    1038             :  * Returns true if successful, false if lock was not held
    1039             : */
    1040             : Datum
    1041          94 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
    1042             : {
    1043          94 :     int32       key1 = PG_GETARG_INT32(0);
    1044          94 :     int32       key2 = PG_GETARG_INT32(1);
    1045             :     LOCKTAG     tag;
    1046             :     bool        res;
    1047             : 
    1048          94 :     SET_LOCKTAG_INT32(tag, key1, key2);
    1049             : 
    1050          94 :     res = LockRelease(&tag, ExclusiveLock, true);
    1051             : 
    1052          94 :     PG_RETURN_BOOL(res);
    1053             : }
    1054             : 
    1055             : /*
    1056             :  * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
    1057             :  *
    1058             :  * Returns true if successful, false if lock was not held
    1059             :  */
    1060             : Datum
    1061          30 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
    1062             : {
    1063          30 :     int32       key1 = PG_GETARG_INT32(0);
    1064          30 :     int32       key2 = PG_GETARG_INT32(1);
    1065             :     LOCKTAG     tag;
    1066             :     bool        res;
    1067             : 
    1068          30 :     SET_LOCKTAG_INT32(tag, key1, key2);
    1069             : 
    1070          30 :     res = LockRelease(&tag, ShareLock, true);
    1071             : 
    1072          30 :     PG_RETURN_BOOL(res);
    1073             : }
    1074             : 
    1075             : /*
    1076             :  * pg_advisory_unlock_all() - release all advisory locks
    1077             :  */
    1078             : Datum
    1079         238 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
    1080             : {
    1081         238 :     LockReleaseSession(USER_LOCKMETHOD);
    1082             : 
    1083         238 :     PG_RETURN_VOID();
    1084             : }

Generated by: LCOV version 1.14