LCOV - code coverage report
Current view: top level - src/backend/utils/adt - lockfuncs.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 59.5 % 464 276
Test Date: 2026-01-26 10:56:24 Functions: 60.0 % 25 15
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 37.0 % 92 34

             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                 :        2359 : 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                 :        2359 :         char            vxidstr[32];
      82                 :             : 
      83                 :        2359 :         snprintf(vxidstr, sizeof(vxidstr), "%d/%u", procNumber, lxid);
      84                 :             : 
      85                 :        4718 :         return CStringGetTextDatum(vxidstr);
      86                 :        2359 : }
      87                 :             : 
      88                 :             : 
      89                 :             : /*
      90                 :             :  * pg_lock_status - produce a view with one row per held or awaited lock mode
      91                 :             :  */
      92                 :             : Datum
      93                 :        2093 : pg_lock_status(PG_FUNCTION_ARGS)
      94                 :             : {
      95                 :        2093 :         FuncCallContext *funcctx;
      96                 :        2093 :         PG_Lock_Status *mystatus;
      97                 :        2093 :         LockData   *lockData;
      98                 :        2093 :         PredicateLockData *predLockData;
      99                 :             : 
     100         [ +  + ]:        2093 :         if (SRF_IS_FIRSTCALL())
     101                 :             :         {
     102                 :          70 :                 TupleDesc       tupdesc;
     103                 :          70 :                 MemoryContext oldcontext;
     104                 :             : 
     105                 :             :                 /* create a function context for cross-call persistence */
     106                 :          70 :                 funcctx = SRF_FIRSTCALL_INIT();
     107                 :             : 
     108                 :             :                 /*
     109                 :             :                  * switch to memory context appropriate for multiple function calls
     110                 :             :                  */
     111                 :          70 :                 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                 :          70 :                 tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
     116                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
     117                 :             :                                                    TEXTOID, -1, 0);
     118                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
     119                 :             :                                                    OIDOID, -1, 0);
     120                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
     121                 :             :                                                    OIDOID, -1, 0);
     122                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
     123                 :             :                                                    INT4OID, -1, 0);
     124                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
     125                 :             :                                                    INT2OID, -1, 0);
     126                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
     127                 :             :                                                    TEXTOID, -1, 0);
     128                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
     129                 :             :                                                    XIDOID, -1, 0);
     130                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
     131                 :             :                                                    OIDOID, -1, 0);
     132                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
     133                 :             :                                                    OIDOID, -1, 0);
     134                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
     135                 :             :                                                    INT2OID, -1, 0);
     136                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
     137                 :             :                                                    TEXTOID, -1, 0);
     138                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
     139                 :             :                                                    INT4OID, -1, 0);
     140                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
     141                 :             :                                                    TEXTOID, -1, 0);
     142                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
     143                 :             :                                                    BOOLOID, -1, 0);
     144                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
     145                 :             :                                                    BOOLOID, -1, 0);
     146                 :          70 :                 TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
     147                 :             :                                                    TIMESTAMPTZOID, -1, 0);
     148                 :             : 
     149                 :          70 :                 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
     150                 :             : 
     151                 :             :                 /*
     152                 :             :                  * Collect all the locking information that we will format and send
     153                 :             :                  * out as a result set.
     154                 :             :                  */
     155                 :          70 :                 mystatus = palloc_object(PG_Lock_Status);
     156                 :          70 :                 funcctx->user_fctx = mystatus;
     157                 :             : 
     158                 :          70 :                 mystatus->lockData = GetLockStatusData();
     159                 :          70 :                 mystatus->currIdx = 0;
     160                 :          70 :                 mystatus->predLockData = GetPredicateLockStatusData();
     161                 :          70 :                 mystatus->predLockIdx = 0;
     162                 :             : 
     163                 :          70 :                 MemoryContextSwitchTo(oldcontext);
     164                 :          70 :         }
     165                 :             : 
     166                 :        2093 :         funcctx = SRF_PERCALL_SETUP();
     167                 :        2093 :         mystatus = (PG_Lock_Status *) funcctx->user_fctx;
     168                 :        2093 :         lockData = mystatus->lockData;
     169                 :             : 
     170         [ +  + ]:        4019 :         while (mystatus->currIdx < lockData->nelements)
     171                 :             :         {
     172                 :        3948 :                 bool            granted;
     173                 :        3948 :                 LOCKMODE        mode = 0;
     174                 :        3948 :                 const char *locktypename;
     175                 :        3948 :                 char            tnbuf[32];
     176                 :        3948 :                 Datum           values[NUM_LOCK_STATUS_COLUMNS] = {0};
     177                 :        3948 :                 bool            nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     178                 :        3948 :                 HeapTuple       tuple;
     179                 :        3948 :                 Datum           result;
     180                 :        3948 :                 LockInstanceData *instance;
     181                 :             : 
     182                 :        3948 :                 instance = &(lockData->locks[mystatus->currIdx]);
     183                 :             : 
     184                 :             :                 /*
     185                 :             :                  * Look to see if there are any held lock modes in this PROCLOCK. If
     186                 :             :                  * so, report, and destructively modify lockData so we don't report
     187                 :             :                  * again.
     188                 :             :                  */
     189                 :        3948 :                 granted = false;
     190         [ +  + ]:        3948 :                 if (instance->holdMask)
     191                 :             :                 {
     192         [ -  + ]:        9932 :                         for (mode = 0; mode < MAX_LOCKMODES; mode++)
     193                 :             :                         {
     194         [ +  + ]:        9932 :                                 if (instance->holdMask & LOCKBIT_ON(mode))
     195                 :             :                                 {
     196                 :        2020 :                                         granted = true;
     197                 :        2020 :                                         instance->holdMask &= LOCKBIT_OFF(mode);
     198                 :        2020 :                                         break;
     199                 :             :                                 }
     200                 :        7912 :                         }
     201                 :        2020 :                 }
     202                 :             : 
     203                 :             :                 /*
     204                 :             :                  * If no (more) held modes to report, see if PROC is waiting for a
     205                 :             :                  * lock on this lock.
     206                 :             :                  */
     207         [ +  + ]:        3948 :                 if (!granted)
     208                 :             :                 {
     209         [ +  + ]:        1928 :                         if (instance->waitLockMode != NoLock)
     210                 :             :                         {
     211                 :             :                                 /* Yes, so report it with proper mode */
     212                 :           2 :                                 mode = instance->waitLockMode;
     213                 :             : 
     214                 :             :                                 /*
     215                 :             :                                  * We are now done with this PROCLOCK, so advance pointer to
     216                 :             :                                  * continue with next one on next call.
     217                 :             :                                  */
     218                 :           2 :                                 mystatus->currIdx++;
     219                 :           2 :                         }
     220                 :             :                         else
     221                 :             :                         {
     222                 :             :                                 /*
     223                 :             :                                  * Okay, we've displayed all the locks associated with this
     224                 :             :                                  * PROCLOCK, proceed to the next one.
     225                 :             :                                  */
     226                 :        1926 :                                 mystatus->currIdx++;
     227                 :        1926 :                                 continue;
     228                 :             :                         }
     229                 :           2 :                 }
     230                 :             : 
     231                 :             :                 /*
     232                 :             :                  * Form tuple with appropriate data.
     233                 :             :                  */
     234                 :             : 
     235         [ +  - ]:        2022 :                 if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
     236                 :        2022 :                         locktypename = LockTagTypeNames[instance->locktag.locktag_type];
     237                 :             :                 else
     238                 :             :                 {
     239                 :           0 :                         snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
     240                 :           0 :                                          (int) instance->locktag.locktag_type);
     241                 :           0 :                         locktypename = tnbuf;
     242                 :             :                 }
     243                 :        2022 :                 values[0] = CStringGetTextDatum(locktypename);
     244                 :             : 
     245   [ -  +  +  -  :        2022 :                 switch ((LockTagType) instance->locktag.locktag_type)
          -  +  +  +  -  
                      - ]
     246                 :             :                 {
     247                 :             :                         case LOCKTAG_RELATION:
     248                 :             :                         case LOCKTAG_RELATION_EXTEND:
     249                 :        1383 :                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     250                 :        1383 :                                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     251                 :        1383 :                                 nulls[3] = true;
     252                 :        1383 :                                 nulls[4] = true;
     253                 :        1383 :                                 nulls[5] = true;
     254                 :        1383 :                                 nulls[6] = true;
     255                 :        1383 :                                 nulls[7] = true;
     256                 :        1383 :                                 nulls[8] = true;
     257                 :        1383 :                                 nulls[9] = true;
     258                 :        1383 :                                 break;
     259                 :             :                         case LOCKTAG_DATABASE_FROZEN_IDS:
     260                 :           0 :                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     261                 :           0 :                                 nulls[2] = true;
     262                 :           0 :                                 nulls[3] = true;
     263                 :           0 :                                 nulls[4] = true;
     264                 :           0 :                                 nulls[5] = true;
     265                 :           0 :                                 nulls[6] = true;
     266                 :           0 :                                 nulls[7] = true;
     267                 :           0 :                                 nulls[8] = true;
     268                 :           0 :                                 nulls[9] = true;
     269                 :           0 :                                 break;
     270                 :             :                         case LOCKTAG_PAGE:
     271                 :           0 :                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     272                 :           0 :                                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     273                 :           0 :                                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     274                 :           0 :                                 nulls[4] = true;
     275                 :           0 :                                 nulls[5] = true;
     276                 :           0 :                                 nulls[6] = true;
     277                 :           0 :                                 nulls[7] = true;
     278                 :           0 :                                 nulls[8] = true;
     279                 :           0 :                                 nulls[9] = true;
     280                 :           0 :                                 break;
     281                 :             :                         case LOCKTAG_TUPLE:
     282                 :           2 :                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     283                 :           2 :                                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     284                 :           2 :                                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     285                 :           2 :                                 values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
     286                 :           2 :                                 nulls[5] = true;
     287                 :           2 :                                 nulls[6] = true;
     288                 :           2 :                                 nulls[7] = true;
     289                 :           2 :                                 nulls[8] = true;
     290                 :           2 :                                 nulls[9] = true;
     291                 :           2 :                                 break;
     292                 :             :                         case LOCKTAG_TRANSACTION:
     293                 :         187 :                                 values[6] =
     294                 :         187 :                                         TransactionIdGetDatum(instance->locktag.locktag_field1);
     295                 :         187 :                                 nulls[1] = true;
     296                 :         187 :                                 nulls[2] = true;
     297                 :         187 :                                 nulls[3] = true;
     298                 :         187 :                                 nulls[4] = true;
     299                 :         187 :                                 nulls[5] = true;
     300                 :         187 :                                 nulls[7] = true;
     301                 :         187 :                                 nulls[8] = true;
     302                 :         187 :                                 nulls[9] = true;
     303                 :         187 :                                 break;
     304                 :             :                         case LOCKTAG_VIRTUALTRANSACTION:
     305                 :         672 :                                 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
     306                 :         336 :                                                                                  instance->locktag.locktag_field2);
     307                 :         336 :                                 nulls[1] = true;
     308                 :         336 :                                 nulls[2] = true;
     309                 :         336 :                                 nulls[3] = true;
     310                 :         336 :                                 nulls[4] = true;
     311                 :         336 :                                 nulls[6] = true;
     312                 :         336 :                                 nulls[7] = true;
     313                 :         336 :                                 nulls[8] = true;
     314                 :         336 :                                 nulls[9] = true;
     315                 :         336 :                                 break;
     316                 :             :                         case LOCKTAG_SPECULATIVE_TOKEN:
     317                 :           0 :                                 values[6] =
     318                 :           0 :                                         TransactionIdGetDatum(instance->locktag.locktag_field1);
     319                 :           0 :                                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     320                 :           0 :                                 nulls[1] = true;
     321                 :           0 :                                 nulls[2] = true;
     322                 :           0 :                                 nulls[3] = true;
     323                 :           0 :                                 nulls[4] = true;
     324                 :           0 :                                 nulls[5] = true;
     325                 :           0 :                                 nulls[7] = true;
     326                 :           0 :                                 nulls[9] = true;
     327                 :           0 :                                 break;
     328                 :             :                         case LOCKTAG_APPLY_TRANSACTION:
     329                 :           0 :                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     330                 :           0 :                                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     331                 :           0 :                                 values[6] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     332                 :           0 :                                 values[9] = UInt16GetDatum(instance->locktag.locktag_field4);
     333                 :           0 :                                 nulls[2] = true;
     334                 :           0 :                                 nulls[3] = true;
     335                 :           0 :                                 nulls[4] = true;
     336                 :           0 :                                 nulls[5] = true;
     337                 :           0 :                                 nulls[7] = true;
     338                 :           0 :                                 break;
     339                 :             :                         case LOCKTAG_OBJECT:
     340                 :             :                         case LOCKTAG_USERLOCK:
     341                 :         114 :                         case LOCKTAG_ADVISORY:
     342                 :             :                         default:                        /* treat unknown locktags like OBJECT */
     343                 :         114 :                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     344                 :         114 :                                 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     345                 :         114 :                                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     346                 :         114 :                                 values[9] = UInt16GetDatum(instance->locktag.locktag_field4);
     347                 :         114 :                                 nulls[2] = true;
     348                 :         114 :                                 nulls[3] = true;
     349                 :         114 :                                 nulls[4] = true;
     350                 :         114 :                                 nulls[5] = true;
     351                 :         114 :                                 nulls[6] = true;
     352                 :         114 :                                 break;
     353                 :             :                 }
     354                 :             : 
     355                 :        2022 :                 values[10] = VXIDGetDatum(instance->vxid.procNumber, instance->vxid.localTransactionId);
     356         [ +  - ]:        2022 :                 if (instance->pid != 0)
     357                 :        2022 :                         values[11] = Int32GetDatum(instance->pid);
     358                 :             :                 else
     359                 :           0 :                         nulls[11] = true;
     360                 :        2022 :                 values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
     361                 :        2022 :                 values[13] = BoolGetDatum(granted);
     362                 :        2022 :                 values[14] = BoolGetDatum(instance->fastpath);
     363   [ +  +  +  - ]:        2022 :                 if (!granted && instance->waitStart != 0)
     364                 :           2 :                         values[15] = TimestampTzGetDatum(instance->waitStart);
     365                 :             :                 else
     366                 :        2020 :                         nulls[15] = true;
     367                 :             : 
     368                 :        2022 :                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     369                 :        2022 :                 result = HeapTupleGetDatum(tuple);
     370                 :        2022 :                 SRF_RETURN_NEXT(funcctx, result);
     371      [ +  +  - ]:        3948 :         }
     372                 :             : 
     373                 :             :         /*
     374                 :             :          * Have returned all regular locks. Now start on the SIREAD predicate
     375                 :             :          * locks.
     376                 :             :          */
     377                 :          71 :         predLockData = mystatus->predLockData;
     378         [ +  + ]:          71 :         if (mystatus->predLockIdx < predLockData->nelements)
     379                 :             :         {
     380                 :           1 :                 PredicateLockTargetType lockType;
     381                 :             : 
     382                 :           1 :                 PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
     383                 :           1 :                 SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
     384                 :           1 :                 Datum           values[NUM_LOCK_STATUS_COLUMNS] = {0};
     385                 :           1 :                 bool            nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     386                 :           1 :                 HeapTuple       tuple;
     387                 :           1 :                 Datum           result;
     388                 :             : 
     389                 :           1 :                 mystatus->predLockIdx++;
     390                 :             : 
     391                 :             :                 /*
     392                 :             :                  * Form tuple with appropriate data.
     393                 :             :                  */
     394                 :             : 
     395                 :             :                 /* lock type */
     396         [ +  - ]:           1 :                 lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
     397                 :             : 
     398                 :           1 :                 values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
     399                 :             : 
     400                 :             :                 /* lock target */
     401                 :           1 :                 values[1] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_DB(*predTag));
     402                 :           1 :                 values[2] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_RELATION(*predTag));
     403         [ +  - ]:           1 :                 if (lockType == PREDLOCKTAG_TUPLE)
     404                 :           1 :                         values[4] = UInt16GetDatum(GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag));
     405                 :             :                 else
     406                 :           0 :                         nulls[4] = true;
     407   [ -  +  #  # ]:           1 :                 if ((lockType == PREDLOCKTAG_TUPLE) ||
     408                 :           0 :                         (lockType == PREDLOCKTAG_PAGE))
     409                 :           1 :                         values[3] = UInt32GetDatum(GET_PREDICATELOCKTARGETTAG_PAGE(*predTag));
     410                 :             :                 else
     411                 :           0 :                         nulls[3] = true;
     412                 :             : 
     413                 :             :                 /* these fields are targets for other types of locks */
     414                 :           1 :                 nulls[5] = true;                /* virtualxid */
     415                 :           1 :                 nulls[6] = true;                /* transactionid */
     416                 :           1 :                 nulls[7] = true;                /* classid */
     417                 :           1 :                 nulls[8] = true;                /* objid */
     418                 :           1 :                 nulls[9] = true;                /* objsubid */
     419                 :             : 
     420                 :             :                 /* lock holder */
     421                 :           2 :                 values[10] = VXIDGetDatum(xact->vxid.procNumber,
     422                 :           1 :                                                                   xact->vxid.localTransactionId);
     423         [ +  - ]:           1 :                 if (xact->pid != 0)
     424                 :           1 :                         values[11] = Int32GetDatum(xact->pid);
     425                 :             :                 else
     426                 :           0 :                         nulls[11] = true;
     427                 :             : 
     428                 :             :                 /*
     429                 :             :                  * Lock mode. Currently all predicate locks are SIReadLocks, which are
     430                 :             :                  * always held (never waiting) and have no fast path
     431                 :             :                  */
     432                 :           1 :                 values[12] = CStringGetTextDatum("SIReadLock");
     433                 :           1 :                 values[13] = BoolGetDatum(true);
     434                 :           1 :                 values[14] = BoolGetDatum(false);
     435                 :           1 :                 nulls[15] = true;
     436                 :             : 
     437                 :           1 :                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     438                 :           1 :                 result = HeapTupleGetDatum(tuple);
     439                 :           1 :                 SRF_RETURN_NEXT(funcctx, result);
     440         [ +  - ]:           1 :         }
     441                 :             : 
     442         [ +  - ]:          70 :         SRF_RETURN_DONE(funcctx);
     443         [ -  + ]:        2093 : }
     444                 :             : 
     445                 :             : 
     446                 :             : /*
     447                 :             :  * pg_blocking_pids - produce an array of the PIDs blocking given PID
     448                 :             :  *
     449                 :             :  * The reported PIDs are those that hold a lock conflicting with blocked_pid's
     450                 :             :  * current request (hard block), or are requesting such a lock and are ahead
     451                 :             :  * of blocked_pid in the lock's wait queue (soft block).
     452                 :             :  *
     453                 :             :  * In parallel-query cases, we report all PIDs blocking any member of the
     454                 :             :  * given PID's lock group, and the reported PIDs are those of the blocking
     455                 :             :  * PIDs' lock group leaders.  This allows callers to compare the result to
     456                 :             :  * lists of clients' pg_backend_pid() results even during a parallel query.
     457                 :             :  *
     458                 :             :  * Parallel query makes it possible for there to be duplicate PIDs in the
     459                 :             :  * result (either because multiple waiters are blocked by same PID, or
     460                 :             :  * because multiple blockers have same group leader PID).  We do not bother
     461                 :             :  * to eliminate such duplicates from the result.
     462                 :             :  *
     463                 :             :  * We need not consider predicate locks here, since those don't block anything.
     464                 :             :  */
     465                 :             : Datum
     466                 :           0 : pg_blocking_pids(PG_FUNCTION_ARGS)
     467                 :             : {
     468                 :           0 :         int                     blocked_pid = PG_GETARG_INT32(0);
     469                 :           0 :         Datum      *arrayelems;
     470                 :           0 :         int                     narrayelems;
     471                 :           0 :         BlockedProcsData *lockData; /* state data from lmgr */
     472                 :           0 :         int                     i,
     473                 :             :                                 j;
     474                 :             : 
     475                 :             :         /* Collect a snapshot of lock manager state */
     476                 :           0 :         lockData = GetBlockerStatusData(blocked_pid);
     477                 :             : 
     478                 :             :         /* We can't need more output entries than there are reported PROCLOCKs */
     479                 :           0 :         arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
     480                 :           0 :         narrayelems = 0;
     481                 :             : 
     482                 :             :         /* For each blocked proc in the lock group ... */
     483         [ #  # ]:           0 :         for (i = 0; i < lockData->nprocs; i++)
     484                 :             :         {
     485                 :           0 :                 BlockedProcData *bproc = &lockData->procs[i];
     486                 :           0 :                 LockInstanceData *instances = &lockData->locks[bproc->first_lock];
     487                 :           0 :                 int                *preceding_waiters = &lockData->waiter_pids[bproc->first_waiter];
     488                 :           0 :                 LockInstanceData *blocked_instance;
     489                 :           0 :                 LockMethod      lockMethodTable;
     490                 :           0 :                 int                     conflictMask;
     491                 :             : 
     492                 :             :                 /*
     493                 :             :                  * Locate the blocked proc's own entry in the LockInstanceData array.
     494                 :             :                  * There should be exactly one matching entry.
     495                 :             :                  */
     496                 :           0 :                 blocked_instance = NULL;
     497         [ #  # ]:           0 :                 for (j = 0; j < bproc->num_locks; j++)
     498                 :             :                 {
     499                 :           0 :                         LockInstanceData *instance = &(instances[j]);
     500                 :             : 
     501         [ #  # ]:           0 :                         if (instance->pid == bproc->pid)
     502                 :             :                         {
     503         [ #  # ]:           0 :                                 Assert(blocked_instance == NULL);
     504                 :           0 :                                 blocked_instance = instance;
     505                 :           0 :                         }
     506                 :           0 :                 }
     507         [ #  # ]:           0 :                 Assert(blocked_instance != NULL);
     508                 :             : 
     509                 :           0 :                 lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
     510                 :           0 :                 conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
     511                 :             : 
     512                 :             :                 /* Now scan the PROCLOCK data for conflicting procs */
     513         [ #  # ]:           0 :                 for (j = 0; j < bproc->num_locks; j++)
     514                 :             :                 {
     515                 :           0 :                         LockInstanceData *instance = &(instances[j]);
     516                 :             : 
     517                 :             :                         /* A proc never blocks itself, so ignore that entry */
     518         [ #  # ]:           0 :                         if (instance == blocked_instance)
     519                 :           0 :                                 continue;
     520                 :             :                         /* Members of same lock group never block each other, either */
     521         [ #  # ]:           0 :                         if (instance->leaderPid == blocked_instance->leaderPid)
     522                 :           0 :                                 continue;
     523                 :             : 
     524         [ #  # ]:           0 :                         if (conflictMask & instance->holdMask)
     525                 :             :                         {
     526                 :             :                                 /* hard block: blocked by lock already held by this entry */
     527                 :           0 :                         }
     528   [ #  #  #  # ]:           0 :                         else if (instance->waitLockMode != NoLock &&
     529                 :           0 :                                          (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
     530                 :             :                         {
     531                 :             :                                 /* conflict in lock requests; who's in front in wait queue? */
     532                 :           0 :                                 bool            ahead = false;
     533                 :           0 :                                 int                     k;
     534                 :             : 
     535         [ #  # ]:           0 :                                 for (k = 0; k < bproc->num_waiters; k++)
     536                 :             :                                 {
     537         [ #  # ]:           0 :                                         if (preceding_waiters[k] == instance->pid)
     538                 :             :                                         {
     539                 :             :                                                 /* soft block: this entry is ahead of blocked proc */
     540                 :           0 :                                                 ahead = true;
     541                 :           0 :                                                 break;
     542                 :             :                                         }
     543                 :           0 :                                 }
     544         [ #  # ]:           0 :                                 if (!ahead)
     545                 :           0 :                                         continue;       /* not blocked by this entry */
     546         [ #  # ]:           0 :                         }
     547                 :             :                         else
     548                 :             :                         {
     549                 :             :                                 /* not blocked by this entry */
     550                 :           0 :                                 continue;
     551                 :             :                         }
     552                 :             : 
     553                 :             :                         /* blocked by this entry, so emit a record */
     554                 :           0 :                         arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
     555      [ #  #  # ]:           0 :                 }
     556                 :           0 :         }
     557                 :             : 
     558                 :             :         /* Assert we didn't overrun arrayelems[] */
     559         [ #  # ]:           0 :         Assert(narrayelems <= lockData->nlocks);
     560                 :             : 
     561                 :           0 :         PG_RETURN_ARRAYTYPE_P(construct_array_builtin(arrayelems, narrayelems, INT4OID));
     562                 :           0 : }
     563                 :             : 
     564                 :             : 
     565                 :             : /*
     566                 :             :  * pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
     567                 :             :  * given PID from getting a safe snapshot
     568                 :             :  *
     569                 :             :  * XXX this does not consider parallel-query cases; not clear how big a
     570                 :             :  * problem that is in practice
     571                 :             :  */
     572                 :             : Datum
     573                 :           0 : pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
     574                 :             : {
     575                 :           0 :         int                     blocked_pid = PG_GETARG_INT32(0);
     576                 :           0 :         int                *blockers;
     577                 :           0 :         int                     num_blockers;
     578                 :           0 :         Datum      *blocker_datums;
     579                 :             : 
     580                 :             :         /* A buffer big enough for any possible blocker list without truncation */
     581                 :           0 :         blockers = (int *) palloc(MaxBackends * sizeof(int));
     582                 :             : 
     583                 :             :         /* Collect a snapshot of processes waited for by GetSafeSnapshot */
     584                 :           0 :         num_blockers =
     585                 :           0 :                 GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
     586                 :             : 
     587                 :             :         /* Convert int array to Datum array */
     588         [ #  # ]:           0 :         if (num_blockers > 0)
     589                 :             :         {
     590                 :           0 :                 int                     i;
     591                 :             : 
     592                 :           0 :                 blocker_datums = (Datum *) palloc(num_blockers * sizeof(Datum));
     593         [ #  # ]:           0 :                 for (i = 0; i < num_blockers; ++i)
     594                 :           0 :                         blocker_datums[i] = Int32GetDatum(blockers[i]);
     595                 :           0 :         }
     596                 :             :         else
     597                 :           0 :                 blocker_datums = NULL;
     598                 :             : 
     599                 :           0 :         PG_RETURN_ARRAYTYPE_P(construct_array_builtin(blocker_datums, num_blockers, INT4OID));
     600                 :           0 : }
     601                 :             : 
     602                 :             : 
     603                 :             : /*
     604                 :             :  * Functions for manipulating advisory locks
     605                 :             :  *
     606                 :             :  * We make use of the locktag fields as follows:
     607                 :             :  *
     608                 :             :  *      field1: MyDatabaseId ... ensures locks are local to each database
     609                 :             :  *      field2: first of 2 int4 keys, or high-order half of an int8 key
     610                 :             :  *      field3: second of 2 int4 keys, or low-order half of an int8 key
     611                 :             :  *      field4: 1 if using an int8 key, 2 if using 2 int4 keys
     612                 :             :  */
     613                 :             : #define SET_LOCKTAG_INT64(tag, key64) \
     614                 :             :         SET_LOCKTAG_ADVISORY(tag, \
     615                 :             :                                                  MyDatabaseId, \
     616                 :             :                                                  (uint32) ((key64) >> 32), \
     617                 :             :                                                  (uint32) (key64), \
     618                 :             :                                                  1)
     619                 :             : #define SET_LOCKTAG_INT32(tag, key1, key2) \
     620                 :             :         SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
     621                 :             : 
     622                 :             : /*
     623                 :             :  * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
     624                 :             :  */
     625                 :             : Datum
     626                 :           7 : pg_advisory_lock_int8(PG_FUNCTION_ARGS)
     627                 :             : {
     628                 :           7 :         int64           key = PG_GETARG_INT64(0);
     629                 :           7 :         LOCKTAG         tag;
     630                 :             : 
     631                 :           7 :         SET_LOCKTAG_INT64(tag, key);
     632                 :             : 
     633                 :           7 :         (void) LockAcquire(&tag, ExclusiveLock, true, false);
     634                 :             : 
     635                 :           7 :         PG_RETURN_VOID();
     636                 :           7 : }
     637                 :             : 
     638                 :             : /*
     639                 :             :  * pg_advisory_xact_lock(int8) - acquire xact scoped
     640                 :             :  * exclusive lock on an int8 key
     641                 :             :  */
     642                 :             : Datum
     643                 :           5 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     644                 :             : {
     645                 :           5 :         int64           key = PG_GETARG_INT64(0);
     646                 :           5 :         LOCKTAG         tag;
     647                 :             : 
     648                 :           5 :         SET_LOCKTAG_INT64(tag, key);
     649                 :             : 
     650                 :           5 :         (void) LockAcquire(&tag, ExclusiveLock, false, false);
     651                 :             : 
     652                 :           5 :         PG_RETURN_VOID();
     653                 :           5 : }
     654                 :             : 
     655                 :             : /*
     656                 :             :  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
     657                 :             :  */
     658                 :             : Datum
     659                 :           6 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     660                 :             : {
     661                 :           6 :         int64           key = PG_GETARG_INT64(0);
     662                 :           6 :         LOCKTAG         tag;
     663                 :             : 
     664                 :           6 :         SET_LOCKTAG_INT64(tag, key);
     665                 :             : 
     666                 :           6 :         (void) LockAcquire(&tag, ShareLock, true, false);
     667                 :             : 
     668                 :           6 :         PG_RETURN_VOID();
     669                 :           6 : }
     670                 :             : 
     671                 :             : /*
     672                 :             :  * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
     673                 :             :  * share lock on an int8 key
     674                 :             :  */
     675                 :             : Datum
     676                 :           6 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     677                 :             : {
     678                 :           6 :         int64           key = PG_GETARG_INT64(0);
     679                 :           6 :         LOCKTAG         tag;
     680                 :             : 
     681                 :           6 :         SET_LOCKTAG_INT64(tag, key);
     682                 :             : 
     683                 :           6 :         (void) LockAcquire(&tag, ShareLock, false, false);
     684                 :             : 
     685                 :           6 :         PG_RETURN_VOID();
     686                 :           6 : }
     687                 :             : 
     688                 :             : /*
     689                 :             :  * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
     690                 :             :  *
     691                 :             :  * Returns true if successful, false if lock not available
     692                 :             :  */
     693                 :             : Datum
     694                 :           0 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
     695                 :             : {
     696                 :           0 :         int64           key = PG_GETARG_INT64(0);
     697                 :           0 :         LOCKTAG         tag;
     698                 :           0 :         LockAcquireResult res;
     699                 :             : 
     700                 :           0 :         SET_LOCKTAG_INT64(tag, key);
     701                 :             : 
     702                 :           0 :         res = LockAcquire(&tag, ExclusiveLock, true, true);
     703                 :             : 
     704                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     705                 :           0 : }
     706                 :             : 
     707                 :             : /*
     708                 :             :  * pg_try_advisory_xact_lock(int8) - acquire xact scoped
     709                 :             :  * exclusive lock on an int8 key, no wait
     710                 :             :  *
     711                 :             :  * Returns true if successful, false if lock not available
     712                 :             :  */
     713                 :             : Datum
     714                 :           0 : pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     715                 :             : {
     716                 :           0 :         int64           key = PG_GETARG_INT64(0);
     717                 :           0 :         LOCKTAG         tag;
     718                 :           0 :         LockAcquireResult res;
     719                 :             : 
     720                 :           0 :         SET_LOCKTAG_INT64(tag, key);
     721                 :             : 
     722                 :           0 :         res = LockAcquire(&tag, ExclusiveLock, false, true);
     723                 :             : 
     724                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     725                 :           0 : }
     726                 :             : 
     727                 :             : /*
     728                 :             :  * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
     729                 :             :  *
     730                 :             :  * Returns true if successful, false if lock not available
     731                 :             :  */
     732                 :             : Datum
     733                 :           0 : pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     734                 :             : {
     735                 :           0 :         int64           key = PG_GETARG_INT64(0);
     736                 :           0 :         LOCKTAG         tag;
     737                 :           0 :         LockAcquireResult res;
     738                 :             : 
     739                 :           0 :         SET_LOCKTAG_INT64(tag, key);
     740                 :             : 
     741                 :           0 :         res = LockAcquire(&tag, ShareLock, true, true);
     742                 :             : 
     743                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     744                 :           0 : }
     745                 :             : 
     746                 :             : /*
     747                 :             :  * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
     748                 :             :  * share lock on an int8 key, no wait
     749                 :             :  *
     750                 :             :  * Returns true if successful, false if lock not available
     751                 :             :  */
     752                 :             : Datum
     753                 :           0 : pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     754                 :             : {
     755                 :           0 :         int64           key = PG_GETARG_INT64(0);
     756                 :           0 :         LOCKTAG         tag;
     757                 :           0 :         LockAcquireResult res;
     758                 :             : 
     759                 :           0 :         SET_LOCKTAG_INT64(tag, key);
     760                 :             : 
     761                 :           0 :         res = LockAcquire(&tag, ShareLock, false, true);
     762                 :             : 
     763                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     764                 :           0 : }
     765                 :             : 
     766                 :             : /*
     767                 :             :  * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
     768                 :             :  *
     769                 :             :  * Returns true if successful, false if lock was not held
     770                 :             : */
     771                 :             : Datum
     772                 :           5 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
     773                 :             : {
     774                 :           5 :         int64           key = PG_GETARG_INT64(0);
     775                 :           5 :         LOCKTAG         tag;
     776                 :           5 :         bool            res;
     777                 :             : 
     778                 :           5 :         SET_LOCKTAG_INT64(tag, key);
     779                 :             : 
     780                 :           5 :         res = LockRelease(&tag, ExclusiveLock, true);
     781                 :             : 
     782                 :          10 :         PG_RETURN_BOOL(res);
     783                 :           5 : }
     784                 :             : 
     785                 :             : /*
     786                 :             :  * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
     787                 :             :  *
     788                 :             :  * Returns true if successful, false if lock was not held
     789                 :             :  */
     790                 :             : Datum
     791                 :           5 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
     792                 :             : {
     793                 :           5 :         int64           key = PG_GETARG_INT64(0);
     794                 :           5 :         LOCKTAG         tag;
     795                 :           5 :         bool            res;
     796                 :             : 
     797                 :           5 :         SET_LOCKTAG_INT64(tag, key);
     798                 :             : 
     799                 :           5 :         res = LockRelease(&tag, ShareLock, true);
     800                 :             : 
     801                 :          10 :         PG_RETURN_BOOL(res);
     802                 :           5 : }
     803                 :             : 
     804                 :             : /*
     805                 :             :  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
     806                 :             :  */
     807                 :             : Datum
     808                 :           6 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
     809                 :             : {
     810                 :           6 :         int32           key1 = PG_GETARG_INT32(0);
     811                 :           6 :         int32           key2 = PG_GETARG_INT32(1);
     812                 :           6 :         LOCKTAG         tag;
     813                 :             : 
     814                 :           6 :         SET_LOCKTAG_INT32(tag, key1, key2);
     815                 :             : 
     816                 :           6 :         (void) LockAcquire(&tag, ExclusiveLock, true, false);
     817                 :             : 
     818                 :           6 :         PG_RETURN_VOID();
     819                 :           6 : }
     820                 :             : 
     821                 :             : /*
     822                 :             :  * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
     823                 :             :  * exclusive lock on 2 int4 keys
     824                 :             :  */
     825                 :             : Datum
     826                 :           5 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     827                 :             : {
     828                 :           5 :         int32           key1 = PG_GETARG_INT32(0);
     829                 :           5 :         int32           key2 = PG_GETARG_INT32(1);
     830                 :           5 :         LOCKTAG         tag;
     831                 :             : 
     832                 :           5 :         SET_LOCKTAG_INT32(tag, key1, key2);
     833                 :             : 
     834                 :           5 :         (void) LockAcquire(&tag, ExclusiveLock, false, false);
     835                 :             : 
     836                 :           5 :         PG_RETURN_VOID();
     837                 :           5 : }
     838                 :             : 
     839                 :             : /*
     840                 :             :  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
     841                 :             :  */
     842                 :             : Datum
     843                 :           6 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     844                 :             : {
     845                 :           6 :         int32           key1 = PG_GETARG_INT32(0);
     846                 :           6 :         int32           key2 = PG_GETARG_INT32(1);
     847                 :           6 :         LOCKTAG         tag;
     848                 :             : 
     849                 :           6 :         SET_LOCKTAG_INT32(tag, key1, key2);
     850                 :             : 
     851                 :           6 :         (void) LockAcquire(&tag, ShareLock, true, false);
     852                 :             : 
     853                 :           6 :         PG_RETURN_VOID();
     854                 :           6 : }
     855                 :             : 
     856                 :             : /*
     857                 :             :  * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     858                 :             :  * share lock on 2 int4 keys
     859                 :             :  */
     860                 :             : Datum
     861                 :           5 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     862                 :             : {
     863                 :           5 :         int32           key1 = PG_GETARG_INT32(0);
     864                 :           5 :         int32           key2 = PG_GETARG_INT32(1);
     865                 :           5 :         LOCKTAG         tag;
     866                 :             : 
     867                 :           5 :         SET_LOCKTAG_INT32(tag, key1, key2);
     868                 :             : 
     869                 :           5 :         (void) LockAcquire(&tag, ShareLock, false, false);
     870                 :             : 
     871                 :           5 :         PG_RETURN_VOID();
     872                 :           5 : }
     873                 :             : 
     874                 :             : /*
     875                 :             :  * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
     876                 :             :  *
     877                 :             :  * Returns true if successful, false if lock not available
     878                 :             :  */
     879                 :             : Datum
     880                 :           0 : pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
     881                 :             : {
     882                 :           0 :         int32           key1 = PG_GETARG_INT32(0);
     883                 :           0 :         int32           key2 = PG_GETARG_INT32(1);
     884                 :           0 :         LOCKTAG         tag;
     885                 :           0 :         LockAcquireResult res;
     886                 :             : 
     887                 :           0 :         SET_LOCKTAG_INT32(tag, key1, key2);
     888                 :             : 
     889                 :           0 :         res = LockAcquire(&tag, ExclusiveLock, true, true);
     890                 :             : 
     891                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     892                 :           0 : }
     893                 :             : 
     894                 :             : /*
     895                 :             :  * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
     896                 :             :  * exclusive lock on 2 int4 keys, no wait
     897                 :             :  *
     898                 :             :  * Returns true if successful, false if lock not available
     899                 :             :  */
     900                 :             : Datum
     901                 :           0 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     902                 :             : {
     903                 :           0 :         int32           key1 = PG_GETARG_INT32(0);
     904                 :           0 :         int32           key2 = PG_GETARG_INT32(1);
     905                 :           0 :         LOCKTAG         tag;
     906                 :           0 :         LockAcquireResult res;
     907                 :             : 
     908                 :           0 :         SET_LOCKTAG_INT32(tag, key1, key2);
     909                 :             : 
     910                 :           0 :         res = LockAcquire(&tag, ExclusiveLock, false, true);
     911                 :             : 
     912                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     913                 :           0 : }
     914                 :             : 
     915                 :             : /*
     916                 :             :  * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
     917                 :             :  *
     918                 :             :  * Returns true if successful, false if lock not available
     919                 :             :  */
     920                 :             : Datum
     921                 :           0 : pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     922                 :             : {
     923                 :           0 :         int32           key1 = PG_GETARG_INT32(0);
     924                 :           0 :         int32           key2 = PG_GETARG_INT32(1);
     925                 :           0 :         LOCKTAG         tag;
     926                 :           0 :         LockAcquireResult res;
     927                 :             : 
     928                 :           0 :         SET_LOCKTAG_INT32(tag, key1, key2);
     929                 :             : 
     930                 :           0 :         res = LockAcquire(&tag, ShareLock, true, true);
     931                 :             : 
     932                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     933                 :           0 : }
     934                 :             : 
     935                 :             : /*
     936                 :             :  * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     937                 :             :  * share lock on 2 int4 keys, no wait
     938                 :             :  *
     939                 :             :  * Returns true if successful, false if lock not available
     940                 :             :  */
     941                 :             : Datum
     942                 :           0 : pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     943                 :             : {
     944                 :           0 :         int32           key1 = PG_GETARG_INT32(0);
     945                 :           0 :         int32           key2 = PG_GETARG_INT32(1);
     946                 :           0 :         LOCKTAG         tag;
     947                 :           0 :         LockAcquireResult res;
     948                 :             : 
     949                 :           0 :         SET_LOCKTAG_INT32(tag, key1, key2);
     950                 :             : 
     951                 :           0 :         res = LockAcquire(&tag, ShareLock, false, true);
     952                 :             : 
     953                 :           0 :         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     954                 :           0 : }
     955                 :             : 
     956                 :             : /*
     957                 :             :  * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
     958                 :             :  *
     959                 :             :  * Returns true if successful, false if lock was not held
     960                 :             : */
     961                 :             : Datum
     962                 :           5 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
     963                 :             : {
     964                 :           5 :         int32           key1 = PG_GETARG_INT32(0);
     965                 :           5 :         int32           key2 = PG_GETARG_INT32(1);
     966                 :           5 :         LOCKTAG         tag;
     967                 :           5 :         bool            res;
     968                 :             : 
     969                 :           5 :         SET_LOCKTAG_INT32(tag, key1, key2);
     970                 :             : 
     971                 :           5 :         res = LockRelease(&tag, ExclusiveLock, true);
     972                 :             : 
     973                 :          10 :         PG_RETURN_BOOL(res);
     974                 :           5 : }
     975                 :             : 
     976                 :             : /*
     977                 :             :  * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
     978                 :             :  *
     979                 :             :  * Returns true if successful, false if lock was not held
     980                 :             :  */
     981                 :             : Datum
     982                 :           5 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
     983                 :             : {
     984                 :           5 :         int32           key1 = PG_GETARG_INT32(0);
     985                 :           5 :         int32           key2 = PG_GETARG_INT32(1);
     986                 :           5 :         LOCKTAG         tag;
     987                 :           5 :         bool            res;
     988                 :             : 
     989                 :           5 :         SET_LOCKTAG_INT32(tag, key1, key2);
     990                 :             : 
     991                 :           5 :         res = LockRelease(&tag, ShareLock, true);
     992                 :             : 
     993                 :          10 :         PG_RETURN_BOOL(res);
     994                 :           5 : }
     995                 :             : 
     996                 :             : /*
     997                 :             :  * pg_advisory_unlock_all() - release all advisory locks
     998                 :             :  */
     999                 :             : Datum
    1000                 :           3 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
    1001                 :             : {
    1002                 :           3 :         LockReleaseSession(USER_LOCKMETHOD);
    1003                 :             : 
    1004                 :           3 :         PG_RETURN_VOID();
    1005                 :             : }
        

Generated by: LCOV version 2.3.2-1