LCOV - code coverage report
Current view: top level - src/backend/utils/adt - lockfuncs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 83.7 % 368 308
Test Date: 2026-07-22 12:15:41 Functions: 72.0 % 25 18
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 78.9 % 71 56

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * lockfuncs.c
       4                 :             :  *      Functions for SQL access to various lock-manager capabilities.
       5                 :             :  *
       6                 :             :  * Copyright (c) 2002-2026, 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 "funcapi.h"
      17                 :             : #include "miscadmin.h"
      18                 :             : #include "storage/predicate_internals.h"
      19                 :             : #include "utils/array.h"
      20                 :             : #include "utils/builtins.h"
      21                 :             : 
      22                 :             : 
      23                 :             : /*
      24                 :             :  * This must match enum LockTagType!  Also, be sure to document any changes
      25                 :             :  * in the docs for the pg_locks view and update the WaitEventLOCK section in
      26                 :             :  * src/backend/utils/activity/wait_event_names.txt.
      27                 :             :  */
      28                 :             : const char *const LockTagTypeNames[] = {
      29                 :             :     "relation",
      30                 :             :     "extend",
      31                 :             :     "frozenid",
      32                 :             :     "page",
      33                 :             :     "tuple",
      34                 :             :     "transactionid",
      35                 :             :     "virtualxid",
      36                 :             :     "spectoken",
      37                 :             :     "object",
      38                 :             :     "userlock",
      39                 :             :     "advisory",
      40                 :             :     "applytransaction"
      41                 :             : };
      42                 :             : 
      43                 :             : StaticAssertDecl(lengthof(LockTagTypeNames) == (LOCKTAG_LAST_TYPE + 1),
      44                 :             :                  "array length mismatch");
      45                 :             : 
      46                 :             : /* This must match enum PredicateLockTargetType (predicate_internals.h) */
      47                 :             : static const char *const PredicateLockTagTypeNames[] = {
      48                 :             :     "relation",
      49                 :             :     "page",
      50                 :             :     "tuple"
      51                 :             : };
      52                 :             : 
      53                 :             : StaticAssertDecl(lengthof(PredicateLockTagTypeNames) == (PREDLOCKTAG_TUPLE + 1),
      54                 :             :                  "array length mismatch");
      55                 :             : 
      56                 :             : /* Working status for pg_lock_status */
      57                 :             : typedef struct
      58                 :             : {
      59                 :             :     LockData   *lockData;       /* state data from lmgr */
      60                 :             :     int         currIdx;        /* current PROCLOCK index */
      61                 :             :     PredicateLockData *predLockData;    /* state data for pred locks */
      62                 :             :     int         predLockIdx;    /* current index for pred lock */
      63                 :             : } PG_Lock_Status;
      64                 :             : 
      65                 :             : /* Number of columns in pg_locks output */
      66                 :             : #define NUM_LOCK_STATUS_COLUMNS     16
      67                 :             : 
      68                 :             : /*
      69                 :             :  * VXIDGetDatum - Construct a text representation of a VXID
      70                 :             :  *
      71                 :             :  * This is currently only used in pg_lock_status, so we put it here.
      72                 :             :  */
      73                 :             : static Datum
      74                 :       11169 : VXIDGetDatum(ProcNumber procNumber, LocalTransactionId lxid)
      75                 :             : {
      76                 :             :     /*
      77                 :             :      * The representation is "<procNumber>/<lxid>", decimal and unsigned
      78                 :             :      * decimal respectively.  Note that elog.c also knows how to format a
      79                 :             :      * vxid.
      80                 :             :      */
      81                 :             :     char        vxidstr[32];
      82                 :             : 
      83                 :       11169 :     snprintf(vxidstr, sizeof(vxidstr), "%d/%u", procNumber, lxid);
      84                 :             : 
      85                 :       11169 :     return CStringGetTextDatum(vxidstr);
      86                 :             : }
      87                 :             : 
      88                 :             : 
      89                 :             : /*
      90                 :             :  * pg_lock_status - produce a view with one row per held or awaited lock mode
      91                 :             :  */
      92                 :             : Datum
      93                 :       10119 : pg_lock_status(PG_FUNCTION_ARGS)
      94                 :             : {
      95                 :             :     FuncCallContext *funcctx;
      96                 :             :     PG_Lock_Status *mystatus;
      97                 :             :     LockData   *lockData;
      98                 :             :     PredicateLockData *predLockData;
      99                 :             : 
     100         [ +  + ]:       10119 :     if (SRF_IS_FIRSTCALL())
     101                 :             :     {
     102                 :             :         TupleDesc   tupdesc;
     103                 :             :         MemoryContext oldcontext;
     104                 :             : 
     105                 :             :         /* create a function context for cross-call persistence */
     106                 :         376 :         funcctx = SRF_FIRSTCALL_INIT();
     107                 :             : 
     108                 :             :         /*
     109                 :             :          * switch to memory context appropriate for multiple function calls
     110                 :             :          */
     111                 :         376 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     112                 :             : 
     113                 :             :         /* build tupdesc for result tuples */
     114                 :             :         /* this had better match function's declaration in pg_proc.h */
     115                 :         376 :         tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
     116                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
     117                 :             :                            TEXTOID, -1, 0);
     118                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
     119                 :             :                            OIDOID, -1, 0);
     120                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
     121                 :             :                            OIDOID, -1, 0);
     122                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
     123                 :             :                            INT4OID, -1, 0);
     124                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
     125                 :             :                            INT2OID, -1, 0);
     126                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
     127                 :             :                            TEXTOID, -1, 0);
     128                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
     129                 :             :                            XIDOID, -1, 0);
     130                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
     131                 :             :                            OIDOID, -1, 0);
     132                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
     133                 :             :                            OIDOID, -1, 0);
     134                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
     135                 :             :                            INT2OID, -1, 0);
     136                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
     137                 :             :                            TEXTOID, -1, 0);
     138                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
     139                 :             :                            INT4OID, -1, 0);
     140                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
     141                 :             :                            TEXTOID, -1, 0);
     142                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
     143                 :             :                            BOOLOID, -1, 0);
     144                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
     145                 :             :                            BOOLOID, -1, 0);
     146                 :         376 :         TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
     147                 :             :                            TIMESTAMPTZOID, -1, 0);
     148                 :             : 
     149                 :         376 :         TupleDescFinalize(tupdesc);
     150                 :         376 :         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                 :         376 :         mystatus = palloc_object(PG_Lock_Status);
     157                 :         376 :         funcctx->user_fctx = mystatus;
     158                 :             : 
     159                 :         376 :         mystatus->lockData = GetLockStatusData();
     160                 :         376 :         mystatus->currIdx = 0;
     161                 :         376 :         mystatus->predLockData = GetPredicateLockStatusData();
     162                 :         376 :         mystatus->predLockIdx = 0;
     163                 :             : 
     164                 :         376 :         MemoryContextSwitchTo(oldcontext);
     165                 :             :     }
     166                 :             : 
     167                 :       10119 :     funcctx = SRF_PERCALL_SETUP();
     168                 :       10119 :     mystatus = (PG_Lock_Status *) funcctx->user_fctx;
     169                 :       10119 :     lockData = mystatus->lockData;
     170                 :             : 
     171         [ +  + ]:       19479 :     while (mystatus->currIdx < lockData->nelements)
     172                 :             :     {
     173                 :             :         bool        granted;
     174                 :       19099 :         LOCKMODE    mode = 0;
     175                 :             :         const char *locktypename;
     176                 :             :         char        tnbuf[32];
     177                 :       19099 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     178                 :       19099 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     179                 :             :         HeapTuple   tuple;
     180                 :             :         Datum       result;
     181                 :             :         LockInstanceData *instance;
     182                 :             : 
     183                 :       19099 :         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                 :       19099 :         granted = false;
     191         [ +  + ]:       19099 :         if (instance->holdMask)
     192                 :             :         {
     193         [ +  - ]:       44431 :             for (mode = 0; mode < MAX_LOCKMODES; mode++)
     194                 :             :             {
     195         [ +  + ]:       44431 :                 if (instance->holdMask & LOCKBIT_ON(mode))
     196                 :             :                 {
     197                 :        9728 :                     granted = true;
     198                 :        9728 :                     instance->holdMask &= LOCKBIT_OFF(mode);
     199                 :        9728 :                     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         [ +  + ]:       19099 :         if (!granted)
     209                 :             :         {
     210         [ +  + ]:        9371 :             if (instance->waitLockMode != NoLock)
     211                 :             :             {
     212                 :             :                 /* Yes, so report it with proper mode */
     213                 :          11 :                 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                 :          11 :                 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                 :        9360 :                 mystatus->currIdx++;
     228                 :        9360 :                 continue;
     229                 :             :             }
     230                 :             :         }
     231                 :             : 
     232                 :             :         /*
     233                 :             :          * Form tuple with appropriate data.
     234                 :             :          */
     235                 :             : 
     236         [ +  - ]:        9739 :         if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
     237                 :        9739 :             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                 :        9739 :         values[0] = CStringGetTextDatum(locktypename);
     245                 :             : 
     246   [ +  +  +  +  :        9739 :         switch ((LockTagType) instance->locktag.locktag_type)
             +  +  +  -  
                      + ]
     247                 :             :         {
     248                 :        6354 :             case LOCKTAG_RELATION:
     249                 :             :             case LOCKTAG_RELATION_EXTEND:
     250                 :        6354 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     251                 :        6354 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     252                 :        6354 :                 nulls[3] = true;
     253                 :        6354 :                 nulls[4] = true;
     254                 :        6354 :                 nulls[5] = true;
     255                 :        6354 :                 nulls[6] = true;
     256                 :        6354 :                 nulls[7] = true;
     257                 :        6354 :                 nulls[8] = true;
     258                 :        6354 :                 nulls[9] = true;
     259                 :        6354 :                 break;
     260                 :           2 :             case LOCKTAG_DATABASE_FROZEN_IDS:
     261                 :           2 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     262                 :           2 :                 nulls[2] = true;
     263                 :           2 :                 nulls[3] = true;
     264                 :           2 :                 nulls[4] = true;
     265                 :           2 :                 nulls[5] = true;
     266                 :           2 :                 nulls[6] = true;
     267                 :           2 :                 nulls[7] = true;
     268                 :           2 :                 nulls[8] = true;
     269                 :           2 :                 nulls[9] = true;
     270                 :           2 :                 break;
     271                 :           2 :             case LOCKTAG_PAGE:
     272                 :           2 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     273                 :           2 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     274                 :           2 :                 values[3] = Int32GetDatum(instance->locktag.locktag_field3);
     275                 :           2 :                 nulls[4] = true;
     276                 :           2 :                 nulls[5] = true;
     277                 :           2 :                 nulls[6] = true;
     278                 :           2 :                 nulls[7] = true;
     279                 :           2 :                 nulls[8] = true;
     280                 :           2 :                 nulls[9] = true;
     281                 :           2 :                 break;
     282                 :           4 :             case LOCKTAG_TUPLE:
     283                 :           4 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     284                 :           4 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     285                 :           4 :                 values[3] = Int32GetDatum(instance->locktag.locktag_field3);
     286                 :           4 :                 values[4] = Int16GetDatum(instance->locktag.locktag_field4);
     287                 :           4 :                 nulls[5] = true;
     288                 :           4 :                 nulls[6] = true;
     289                 :           4 :                 nulls[7] = true;
     290                 :           4 :                 nulls[8] = true;
     291                 :           4 :                 nulls[9] = true;
     292                 :           4 :                 break;
     293                 :         729 :             case LOCKTAG_TRANSACTION:
     294                 :         729 :                 values[6] =
     295                 :         729 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     296                 :         729 :                 nulls[1] = true;
     297                 :         729 :                 nulls[2] = true;
     298                 :         729 :                 nulls[3] = true;
     299                 :         729 :                 nulls[4] = true;
     300                 :         729 :                 nulls[5] = true;
     301                 :         729 :                 nulls[7] = true;
     302                 :         729 :                 nulls[8] = true;
     303                 :         729 :                 nulls[9] = true;
     304                 :         729 :                 break;
     305                 :        1426 :             case LOCKTAG_VIRTUALTRANSACTION:
     306                 :        1426 :                 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
     307                 :             :                                          instance->locktag.locktag_field2);
     308                 :        1426 :                 nulls[1] = true;
     309                 :        1426 :                 nulls[2] = true;
     310                 :        1426 :                 nulls[3] = true;
     311                 :        1426 :                 nulls[4] = true;
     312                 :        1426 :                 nulls[6] = true;
     313                 :        1426 :                 nulls[7] = true;
     314                 :        1426 :                 nulls[8] = true;
     315                 :        1426 :                 nulls[9] = true;
     316                 :        1426 :                 break;
     317                 :           2 :             case LOCKTAG_SPECULATIVE_TOKEN:
     318                 :           2 :                 values[6] =
     319                 :           2 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     320                 :           2 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     321                 :           2 :                 nulls[1] = true;
     322                 :           2 :                 nulls[2] = true;
     323                 :           2 :                 nulls[3] = true;
     324                 :           2 :                 nulls[4] = true;
     325                 :           2 :                 nulls[5] = true;
     326                 :           2 :                 nulls[7] = true;
     327                 :           2 :                 nulls[9] = true;
     328                 :           2 :                 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                 :        1220 :             case LOCKTAG_OBJECT:
     341                 :             :             case LOCKTAG_USERLOCK:
     342                 :             :             case LOCKTAG_ADVISORY:
     343                 :             :             default:            /* treat unknown locktags like OBJECT */
     344                 :        1220 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     345                 :        1220 :                 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     346                 :        1220 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     347                 :        1220 :                 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
     348                 :        1220 :                 nulls[2] = true;
     349                 :        1220 :                 nulls[3] = true;
     350                 :        1220 :                 nulls[4] = true;
     351                 :        1220 :                 nulls[5] = true;
     352                 :        1220 :                 nulls[6] = true;
     353                 :        1220 :                 break;
     354                 :             :         }
     355                 :             : 
     356                 :        9739 :         values[10] = VXIDGetDatum(instance->vxid.procNumber, instance->vxid.localTransactionId);
     357         [ +  + ]:        9739 :         if (instance->pid != 0)
     358                 :        9715 :             values[11] = Int32GetDatum(instance->pid);
     359                 :             :         else
     360                 :          24 :             nulls[11] = true;
     361                 :        9739 :         values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
     362                 :        9739 :         values[13] = BoolGetDatum(granted);
     363                 :        9739 :         values[14] = BoolGetDatum(instance->fastpath);
     364   [ +  +  +  - ]:        9739 :         if (!granted && instance->waitStart != 0)
     365                 :          11 :             values[15] = TimestampTzGetDatum(instance->waitStart);
     366                 :             :         else
     367                 :        9728 :             nulls[15] = true;
     368                 :             : 
     369                 :        9739 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     370                 :        9739 :         result = HeapTupleGetDatum(tuple);
     371                 :        9739 :         SRF_RETURN_NEXT(funcctx, result);
     372                 :             :     }
     373                 :             : 
     374                 :             :     /*
     375                 :             :      * Have returned all regular locks. Now start on the SIREAD predicate
     376                 :             :      * locks.
     377                 :             :      */
     378                 :         380 :     predLockData = mystatus->predLockData;
     379         [ +  + ]:         380 :     if (mystatus->predLockIdx < predLockData->nelements)
     380                 :             :     {
     381                 :             :         PredicateLockTargetType lockType;
     382                 :             : 
     383                 :           4 :         PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
     384                 :           4 :         SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
     385                 :           4 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     386                 :           4 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     387                 :             :         HeapTuple   tuple;
     388                 :             :         Datum       result;
     389                 :             : 
     390                 :           4 :         mystatus->predLockIdx++;
     391                 :             : 
     392                 :             :         /*
     393                 :             :          * Form tuple with appropriate data.
     394                 :             :          */
     395                 :             : 
     396                 :             :         /* lock type */
     397         [ -  + ]:           4 :         lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
     398                 :             : 
     399                 :           4 :         values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
     400                 :             : 
     401                 :             :         /* lock target */
     402                 :           4 :         values[1] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_DB(*predTag));
     403                 :           4 :         values[2] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_RELATION(*predTag));
     404         [ +  - ]:           4 :         if (lockType == PREDLOCKTAG_TUPLE)
     405                 :           4 :             values[4] = Int16GetDatum(GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag));
     406                 :             :         else
     407                 :           0 :             nulls[4] = true;
     408   [ -  +  -  - ]:           4 :         if ((lockType == PREDLOCKTAG_TUPLE) ||
     409                 :             :             (lockType == PREDLOCKTAG_PAGE))
     410                 :           4 :             values[3] = Int32GetDatum(GET_PREDICATELOCKTARGETTAG_PAGE(*predTag));
     411                 :             :         else
     412                 :           0 :             nulls[3] = true;
     413                 :             : 
     414                 :             :         /* these fields are targets for other types of locks */
     415                 :           4 :         nulls[5] = true;        /* virtualxid */
     416                 :           4 :         nulls[6] = true;        /* transactionid */
     417                 :           4 :         nulls[7] = true;        /* classid */
     418                 :           4 :         nulls[8] = true;        /* objid */
     419                 :           4 :         nulls[9] = true;        /* objsubid */
     420                 :             : 
     421                 :             :         /* lock holder */
     422                 :           4 :         values[10] = VXIDGetDatum(xact->vxid.procNumber,
     423                 :             :                                   xact->vxid.localTransactionId);
     424         [ +  - ]:           4 :         if (xact->pid != 0)
     425                 :           4 :             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                 :           4 :         values[12] = CStringGetTextDatum("SIReadLock");
     434                 :           4 :         values[13] = BoolGetDatum(true);
     435                 :           4 :         values[14] = BoolGetDatum(false);
     436                 :           4 :         nulls[15] = true;
     437                 :             : 
     438                 :           4 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     439                 :           4 :         result = HeapTupleGetDatum(tuple);
     440                 :           4 :         SRF_RETURN_NEXT(funcctx, result);
     441                 :             :     }
     442                 :             : 
     443                 :         376 :     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                 :        1745 : pg_blocking_pids(PG_FUNCTION_ARGS)
     468                 :             : {
     469                 :        1745 :     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                 :        1745 :     lockData = GetBlockerStatusData(blocked_pid);
     478                 :             : 
     479                 :             :     /* We can't need more output entries than there are reported PROCLOCKs */
     480                 :        1745 :     arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
     481                 :        1745 :     narrayelems = 0;
     482                 :             : 
     483                 :             :     /* For each blocked proc in the lock group ... */
     484         [ +  + ]:        3032 :     for (i = 0; i < lockData->nprocs; i++)
     485                 :             :     {
     486                 :        1287 :         BlockedProcData *bproc = &lockData->procs[i];
     487                 :        1287 :         LockInstanceData *instances = &lockData->locks[bproc->first_lock];
     488                 :        1287 :         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                 :        1287 :         blocked_instance = NULL;
     498         [ +  + ]:        3916 :         for (j = 0; j < bproc->num_locks; j++)
     499                 :             :         {
     500                 :        2629 :             LockInstanceData *instance = &(instances[j]);
     501                 :             : 
     502         [ +  + ]:        2629 :             if (instance->pid == bproc->pid)
     503                 :             :             {
     504                 :             :                 Assert(blocked_instance == NULL);
     505                 :        1287 :                 blocked_instance = instance;
     506                 :             :             }
     507                 :             :         }
     508                 :             :         Assert(blocked_instance != NULL);
     509                 :             : 
     510                 :        1287 :         lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
     511                 :        1287 :         conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
     512                 :             : 
     513                 :             :         /* Now scan the PROCLOCK data for conflicting procs */
     514         [ +  + ]:        3916 :         for (j = 0; j < bproc->num_locks; j++)
     515                 :             :         {
     516                 :        2629 :             LockInstanceData *instance = &(instances[j]);
     517                 :             : 
     518                 :             :             /* A proc never blocks itself, so ignore that entry */
     519         [ +  + ]:        2629 :             if (instance == blocked_instance)
     520                 :        1287 :                 continue;
     521                 :             :             /* Members of same lock group never block each other, either */
     522         [ +  + ]:        1342 :             if (instance->leaderPid == blocked_instance->leaderPid)
     523                 :           8 :                 continue;
     524                 :             : 
     525         [ +  + ]:        1334 :             if (conflictMask & instance->holdMask)
     526                 :             :             {
     527                 :             :                 /* hard block: blocked by lock already held by this entry */
     528                 :             :             }
     529         [ +  + ]:          49 :             else if (instance->waitLockMode != NoLock &&
     530         [ +  + ]:          42 :                      (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
     531                 :          11 :             {
     532                 :             :                 /* conflict in lock requests; who's in front in wait queue? */
     533                 :          22 :                 bool        ahead = false;
     534                 :             :                 int         k;
     535                 :             : 
     536         [ +  + ]:          22 :                 for (k = 0; k < bproc->num_waiters; k++)
     537                 :             :                 {
     538         [ +  - ]:          11 :                     if (preceding_waiters[k] == instance->pid)
     539                 :             :                     {
     540                 :             :                         /* soft block: this entry is ahead of blocked proc */
     541                 :          11 :                         ahead = true;
     542                 :          11 :                         break;
     543                 :             :                     }
     544                 :             :                 }
     545         [ +  + ]:          22 :                 if (!ahead)
     546                 :          11 :                     continue;   /* not blocked by this entry */
     547                 :             :             }
     548                 :             :             else
     549                 :             :             {
     550                 :             :                 /* not blocked by this entry */
     551                 :          27 :                 continue;
     552                 :             :             }
     553                 :             : 
     554                 :             :             /* blocked by this entry, so emit a record */
     555                 :        1296 :             arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
     556                 :             :         }
     557                 :             :     }
     558                 :             : 
     559                 :             :     /* Assert we didn't overrun arrayelems[] */
     560                 :             :     Assert(narrayelems <= lockData->nlocks);
     561                 :             : 
     562                 :        1745 :     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                 :             :  * Functions for manipulating advisory locks
     606                 :             :  *
     607                 :             :  * We make use of the locktag fields as follows:
     608                 :             :  *
     609                 :             :  *  field1: MyDatabaseId ... ensures locks are local to each database
     610                 :             :  *  field2: first of 2 int4 keys, or high-order half of an int8 key
     611                 :             :  *  field3: second of 2 int4 keys, or low-order half of an int8 key
     612                 :             :  *  field4: 1 if using an int8 key, 2 if using 2 int4 keys
     613                 :             :  */
     614                 :             : #define SET_LOCKTAG_INT64(tag, key64) \
     615                 :             :     SET_LOCKTAG_ADVISORY(tag, \
     616                 :             :                          MyDatabaseId, \
     617                 :             :                          (uint32) ((key64) >> 32), \
     618                 :             :                          (uint32) (key64), \
     619                 :             :                          1)
     620                 :             : #define SET_LOCKTAG_INT32(tag, key1, key2) \
     621                 :             :     SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
     622                 :             : 
     623                 :             : /*
     624                 :             :  * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
     625                 :             :  */
     626                 :             : Datum
     627                 :         221 : pg_advisory_lock_int8(PG_FUNCTION_ARGS)
     628                 :             : {
     629                 :         221 :     int64       key = PG_GETARG_INT64(0);
     630                 :             :     LOCKTAG     tag;
     631                 :             : 
     632                 :         221 :     SET_LOCKTAG_INT64(tag, key);
     633                 :             : 
     634                 :         221 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     635                 :             : 
     636                 :         220 :     PG_RETURN_VOID();
     637                 :             : }
     638                 :             : 
     639                 :             : /*
     640                 :             :  * pg_advisory_xact_lock(int8) - acquire xact scoped
     641                 :             :  * exclusive lock on an int8 key
     642                 :             :  */
     643                 :             : Datum
     644                 :         253 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     645                 :             : {
     646                 :         253 :     int64       key = PG_GETARG_INT64(0);
     647                 :             :     LOCKTAG     tag;
     648                 :             : 
     649                 :         253 :     SET_LOCKTAG_INT64(tag, key);
     650                 :             : 
     651                 :         253 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     652                 :             : 
     653                 :         253 :     PG_RETURN_VOID();
     654                 :             : }
     655                 :             : 
     656                 :             : /*
     657                 :             :  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
     658                 :             :  */
     659                 :             : Datum
     660                 :          34 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     661                 :             : {
     662                 :          34 :     int64       key = PG_GETARG_INT64(0);
     663                 :             :     LOCKTAG     tag;
     664                 :             : 
     665                 :          34 :     SET_LOCKTAG_INT64(tag, key);
     666                 :             : 
     667                 :          34 :     (void) LockAcquire(&tag, ShareLock, true, false);
     668                 :             : 
     669                 :          34 :     PG_RETURN_VOID();
     670                 :             : }
     671                 :             : 
     672                 :             : /*
     673                 :             :  * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
     674                 :             :  * share lock on an int8 key
     675                 :             :  */
     676                 :             : Datum
     677                 :       20025 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     678                 :             : {
     679                 :       20025 :     int64       key = PG_GETARG_INT64(0);
     680                 :             :     LOCKTAG     tag;
     681                 :             : 
     682                 :       20025 :     SET_LOCKTAG_INT64(tag, key);
     683                 :             : 
     684                 :       20025 :     (void) LockAcquire(&tag, ShareLock, false, false);
     685                 :             : 
     686                 :       20025 :     PG_RETURN_VOID();
     687                 :             : }
     688                 :             : 
     689                 :             : /*
     690                 :             :  * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
     691                 :             :  *
     692                 :             :  * Returns true if successful, false if lock not available
     693                 :             :  */
     694                 :             : Datum
     695                 :         469 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
     696                 :             : {
     697                 :         469 :     int64       key = PG_GETARG_INT64(0);
     698                 :             :     LOCKTAG     tag;
     699                 :             :     LockAcquireResult res;
     700                 :             : 
     701                 :         469 :     SET_LOCKTAG_INT64(tag, key);
     702                 :             : 
     703                 :         469 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     704                 :             : 
     705                 :         469 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     706                 :             : }
     707                 :             : 
     708                 :             : /*
     709                 :             :  * pg_try_advisory_xact_lock(int8) - acquire xact scoped
     710                 :             :  * exclusive lock on an int8 key, no wait
     711                 :             :  *
     712                 :             :  * Returns true if successful, false if lock not available
     713                 :             :  */
     714                 :             : Datum
     715                 :           0 : pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     716                 :             : {
     717                 :           0 :     int64       key = PG_GETARG_INT64(0);
     718                 :             :     LOCKTAG     tag;
     719                 :             :     LockAcquireResult res;
     720                 :             : 
     721                 :           0 :     SET_LOCKTAG_INT64(tag, key);
     722                 :             : 
     723                 :           0 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     724                 :             : 
     725                 :           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     726                 :             : }
     727                 :             : 
     728                 :             : /*
     729                 :             :  * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
     730                 :             :  *
     731                 :             :  * Returns true if successful, false if lock not available
     732                 :             :  */
     733                 :             : Datum
     734                 :           0 : pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     735                 :             : {
     736                 :           0 :     int64       key = PG_GETARG_INT64(0);
     737                 :             :     LOCKTAG     tag;
     738                 :             :     LockAcquireResult res;
     739                 :             : 
     740                 :           0 :     SET_LOCKTAG_INT64(tag, key);
     741                 :             : 
     742                 :           0 :     res = LockAcquire(&tag, ShareLock, true, true);
     743                 :             : 
     744                 :           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     745                 :             : }
     746                 :             : 
     747                 :             : /*
     748                 :             :  * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
     749                 :             :  * share lock on an int8 key, no wait
     750                 :             :  *
     751                 :             :  * Returns true if successful, false if lock not available
     752                 :             :  */
     753                 :             : Datum
     754                 :           0 : pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     755                 :             : {
     756                 :           0 :     int64       key = PG_GETARG_INT64(0);
     757                 :             :     LOCKTAG     tag;
     758                 :             :     LockAcquireResult res;
     759                 :             : 
     760                 :           0 :     SET_LOCKTAG_INT64(tag, key);
     761                 :             : 
     762                 :           0 :     res = LockAcquire(&tag, ShareLock, false, true);
     763                 :             : 
     764                 :           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     765                 :             : }
     766                 :             : 
     767                 :             : /*
     768                 :             :  * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
     769                 :             :  *
     770                 :             :  * Returns true if successful, false if lock was not held
     771                 :             :  */
     772                 :             : Datum
     773                 :         160 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
     774                 :             : {
     775                 :         160 :     int64       key = PG_GETARG_INT64(0);
     776                 :             :     LOCKTAG     tag;
     777                 :             :     bool        res;
     778                 :             : 
     779                 :         160 :     SET_LOCKTAG_INT64(tag, key);
     780                 :             : 
     781                 :         160 :     res = LockRelease(&tag, ExclusiveLock, true);
     782                 :             : 
     783                 :         160 :     PG_RETURN_BOOL(res);
     784                 :             : }
     785                 :             : 
     786                 :             : /*
     787                 :             :  * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
     788                 :             :  *
     789                 :             :  * Returns true if successful, false if lock was not held
     790                 :             :  */
     791                 :             : Datum
     792                 :          20 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
     793                 :             : {
     794                 :          20 :     int64       key = PG_GETARG_INT64(0);
     795                 :             :     LOCKTAG     tag;
     796                 :             :     bool        res;
     797                 :             : 
     798                 :          20 :     SET_LOCKTAG_INT64(tag, key);
     799                 :             : 
     800                 :          20 :     res = LockRelease(&tag, ShareLock, true);
     801                 :             : 
     802                 :          20 :     PG_RETURN_BOOL(res);
     803                 :             : }
     804                 :             : 
     805                 :             : /*
     806                 :             :  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
     807                 :             :  */
     808                 :             : Datum
     809                 :          55 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
     810                 :             : {
     811                 :          55 :     int32       key1 = PG_GETARG_INT32(0);
     812                 :          55 :     int32       key2 = PG_GETARG_INT32(1);
     813                 :             :     LOCKTAG     tag;
     814                 :             : 
     815                 :          55 :     SET_LOCKTAG_INT32(tag, key1, key2);
     816                 :             : 
     817                 :          55 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     818                 :             : 
     819                 :          55 :     PG_RETURN_VOID();
     820                 :             : }
     821                 :             : 
     822                 :             : /*
     823                 :             :  * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
     824                 :             :  * exclusive lock on 2 int4 keys
     825                 :             :  */
     826                 :             : Datum
     827                 :          55 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     828                 :             : {
     829                 :          55 :     int32       key1 = PG_GETARG_INT32(0);
     830                 :          55 :     int32       key2 = PG_GETARG_INT32(1);
     831                 :             :     LOCKTAG     tag;
     832                 :             : 
     833                 :          55 :     SET_LOCKTAG_INT32(tag, key1, key2);
     834                 :             : 
     835                 :          55 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     836                 :             : 
     837                 :          55 :     PG_RETURN_VOID();
     838                 :             : }
     839                 :             : 
     840                 :             : /*
     841                 :             :  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
     842                 :             :  */
     843                 :             : Datum
     844                 :          24 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     845                 :             : {
     846                 :          24 :     int32       key1 = PG_GETARG_INT32(0);
     847                 :          24 :     int32       key2 = PG_GETARG_INT32(1);
     848                 :             :     LOCKTAG     tag;
     849                 :             : 
     850                 :          24 :     SET_LOCKTAG_INT32(tag, key1, key2);
     851                 :             : 
     852                 :          24 :     (void) LockAcquire(&tag, ShareLock, true, false);
     853                 :             : 
     854                 :          24 :     PG_RETURN_VOID();
     855                 :             : }
     856                 :             : 
     857                 :             : /*
     858                 :             :  * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     859                 :             :  * share lock on 2 int4 keys
     860                 :             :  */
     861                 :             : Datum
     862                 :          20 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     863                 :             : {
     864                 :          20 :     int32       key1 = PG_GETARG_INT32(0);
     865                 :          20 :     int32       key2 = PG_GETARG_INT32(1);
     866                 :             :     LOCKTAG     tag;
     867                 :             : 
     868                 :          20 :     SET_LOCKTAG_INT32(tag, key1, key2);
     869                 :             : 
     870                 :          20 :     (void) LockAcquire(&tag, ShareLock, false, false);
     871                 :             : 
     872                 :          20 :     PG_RETURN_VOID();
     873                 :             : }
     874                 :             : 
     875                 :             : /*
     876                 :             :  * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
     877                 :             :  *
     878                 :             :  * Returns true if successful, false if lock not available
     879                 :             :  */
     880                 :             : Datum
     881                 :           0 : pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
     882                 :             : {
     883                 :           0 :     int32       key1 = PG_GETARG_INT32(0);
     884                 :           0 :     int32       key2 = PG_GETARG_INT32(1);
     885                 :             :     LOCKTAG     tag;
     886                 :             :     LockAcquireResult res;
     887                 :             : 
     888                 :           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     889                 :             : 
     890                 :           0 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     891                 :             : 
     892                 :           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     893                 :             : }
     894                 :             : 
     895                 :             : /*
     896                 :             :  * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
     897                 :             :  * exclusive lock on 2 int4 keys, no wait
     898                 :             :  *
     899                 :             :  * Returns true if successful, false if lock not available
     900                 :             :  */
     901                 :             : Datum
     902                 :          33 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     903                 :             : {
     904                 :          33 :     int32       key1 = PG_GETARG_INT32(0);
     905                 :          33 :     int32       key2 = PG_GETARG_INT32(1);
     906                 :             :     LOCKTAG     tag;
     907                 :             :     LockAcquireResult res;
     908                 :             : 
     909                 :          33 :     SET_LOCKTAG_INT32(tag, key1, key2);
     910                 :             : 
     911                 :          33 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     912                 :             : 
     913                 :          33 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     914                 :             : }
     915                 :             : 
     916                 :             : /*
     917                 :             :  * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
     918                 :             :  *
     919                 :             :  * Returns true if successful, false if lock not available
     920                 :             :  */
     921                 :             : Datum
     922                 :           0 : pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     923                 :             : {
     924                 :           0 :     int32       key1 = PG_GETARG_INT32(0);
     925                 :           0 :     int32       key2 = PG_GETARG_INT32(1);
     926                 :             :     LOCKTAG     tag;
     927                 :             :     LockAcquireResult res;
     928                 :             : 
     929                 :           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     930                 :             : 
     931                 :           0 :     res = LockAcquire(&tag, ShareLock, true, true);
     932                 :             : 
     933                 :           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     934                 :             : }
     935                 :             : 
     936                 :             : /*
     937                 :             :  * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     938                 :             :  * share lock on 2 int4 keys, no wait
     939                 :             :  *
     940                 :             :  * Returns true if successful, false if lock not available
     941                 :             :  */
     942                 :             : Datum
     943                 :           0 : pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     944                 :             : {
     945                 :           0 :     int32       key1 = PG_GETARG_INT32(0);
     946                 :           0 :     int32       key2 = PG_GETARG_INT32(1);
     947                 :             :     LOCKTAG     tag;
     948                 :             :     LockAcquireResult res;
     949                 :             : 
     950                 :           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     951                 :             : 
     952                 :           0 :     res = LockAcquire(&tag, ShareLock, false, true);
     953                 :             : 
     954                 :           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     955                 :             : }
     956                 :             : 
     957                 :             : /*
     958                 :             :  * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
     959                 :             :  *
     960                 :             :  * Returns true if successful, false if lock was not held
     961                 :             :  */
     962                 :             : Datum
     963                 :          52 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
     964                 :             : {
     965                 :          52 :     int32       key1 = PG_GETARG_INT32(0);
     966                 :          52 :     int32       key2 = PG_GETARG_INT32(1);
     967                 :             :     LOCKTAG     tag;
     968                 :             :     bool        res;
     969                 :             : 
     970                 :          52 :     SET_LOCKTAG_INT32(tag, key1, key2);
     971                 :             : 
     972                 :          52 :     res = LockRelease(&tag, ExclusiveLock, true);
     973                 :             : 
     974                 :          52 :     PG_RETURN_BOOL(res);
     975                 :             : }
     976                 :             : 
     977                 :             : /*
     978                 :             :  * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
     979                 :             :  *
     980                 :             :  * Returns true if successful, false if lock was not held
     981                 :             :  */
     982                 :             : Datum
     983                 :          20 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
     984                 :             : {
     985                 :          20 :     int32       key1 = PG_GETARG_INT32(0);
     986                 :          20 :     int32       key2 = PG_GETARG_INT32(1);
     987                 :             :     LOCKTAG     tag;
     988                 :             :     bool        res;
     989                 :             : 
     990                 :          20 :     SET_LOCKTAG_INT32(tag, key1, key2);
     991                 :             : 
     992                 :          20 :     res = LockRelease(&tag, ShareLock, true);
     993                 :             : 
     994                 :          20 :     PG_RETURN_BOOL(res);
     995                 :             : }
     996                 :             : 
     997                 :             : /*
     998                 :             :  * pg_advisory_unlock_all() - release all advisory locks
     999                 :             :  */
    1000                 :             : Datum
    1001                 :         122 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
    1002                 :             : {
    1003                 :         122 :     LockReleaseSession(USER_LOCKMETHOD);
    1004                 :             : 
    1005                 :         122 :     PG_RETURN_VOID();
    1006                 :             : }
        

Generated by: LCOV version 2.0-1