1 /*-------------------------------------------------------------------------
4 * Functions for SQL access to various lock-manager capabilities.
6 * Copyright (c) 2002-2025, PostgreSQL Global Development Group
9 * src/backend/utils/adt/lockfuncs.c
11 *-------------------------------------------------------------------------
15 #include "access/htup_details.h"
17 #include "miscadmin.h"
18 #include "storage/predicate_internals.h"
19 #include "utils/array.h"
20 #include "utils/builtins.h"
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.
28 const char *const LockTagTypeNames
[] = {
43 StaticAssertDecl(lengthof(LockTagTypeNames
) == (LOCKTAG_LAST_TYPE
+ 1),
44 "array length mismatch");
46 /* This must match enum PredicateLockTargetType (predicate_internals.h) */
47 static const char *const PredicateLockTagTypeNames
[] = {
53 StaticAssertDecl(lengthof(PredicateLockTagTypeNames
) == (PREDLOCKTAG_TUPLE
+ 1),
54 "array length mismatch");
56 /* Working status for pg_lock_status */
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 */
65 /* Number of columns in pg_locks output */
66 #define NUM_LOCK_STATUS_COLUMNS 16
69 * VXIDGetDatum - Construct a text representation of a VXID
71 * This is currently only used in pg_lock_status, so we put it here.
74 VXIDGetDatum(ProcNumber procNumber
, LocalTransactionId lxid
)
77 * The representation is "<procNumber>/<lxid>", decimal and unsigned
78 * decimal respectively. Note that elog.c also knows how to format a
83 snprintf(vxidstr
, sizeof(vxidstr
), "%d/%u", procNumber
, lxid
);
85 return CStringGetTextDatum(vxidstr
);
90 * pg_lock_status - produce a view with one row per held or awaited lock mode
93 pg_lock_status(PG_FUNCTION_ARGS
)
95 FuncCallContext
*funcctx
;
96 PG_Lock_Status
*mystatus
;
98 PredicateLockData
*predLockData
;
100 if (SRF_IS_FIRSTCALL())
103 MemoryContext oldcontext
;
105 /* create a function context for cross-call persistence */
106 funcctx
= SRF_FIRSTCALL_INIT();
109 * switch to memory context appropriate for multiple function calls
111 oldcontext
= MemoryContextSwitchTo(funcctx
->multi_call_memory_ctx
);
113 /* build tupdesc for result tuples */
114 /* this had better match function's declaration in pg_proc.h */
115 tupdesc
= CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS
);
116 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "locktype",
118 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "database",
120 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "relation",
122 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "page",
124 TupleDescInitEntry(tupdesc
, (AttrNumber
) 5, "tuple",
126 TupleDescInitEntry(tupdesc
, (AttrNumber
) 6, "virtualxid",
128 TupleDescInitEntry(tupdesc
, (AttrNumber
) 7, "transactionid",
130 TupleDescInitEntry(tupdesc
, (AttrNumber
) 8, "classid",
132 TupleDescInitEntry(tupdesc
, (AttrNumber
) 9, "objid",
134 TupleDescInitEntry(tupdesc
, (AttrNumber
) 10, "objsubid",
136 TupleDescInitEntry(tupdesc
, (AttrNumber
) 11, "virtualtransaction",
138 TupleDescInitEntry(tupdesc
, (AttrNumber
) 12, "pid",
140 TupleDescInitEntry(tupdesc
, (AttrNumber
) 13, "mode",
142 TupleDescInitEntry(tupdesc
, (AttrNumber
) 14, "granted",
144 TupleDescInitEntry(tupdesc
, (AttrNumber
) 15, "fastpath",
146 TupleDescInitEntry(tupdesc
, (AttrNumber
) 16, "waitstart",
147 TIMESTAMPTZOID
, -1, 0);
149 funcctx
->tuple_desc
= BlessTupleDesc(tupdesc
);
152 * Collect all the locking information that we will format and send
153 * out as a result set.
155 mystatus
= (PG_Lock_Status
*) palloc(sizeof(PG_Lock_Status
));
156 funcctx
->user_fctx
= mystatus
;
158 mystatus
->lockData
= GetLockStatusData();
159 mystatus
->currIdx
= 0;
160 mystatus
->predLockData
= GetPredicateLockStatusData();
161 mystatus
->predLockIdx
= 0;
163 MemoryContextSwitchTo(oldcontext
);
166 funcctx
= SRF_PERCALL_SETUP();
167 mystatus
= (PG_Lock_Status
*) funcctx
->user_fctx
;
168 lockData
= mystatus
->lockData
;
170 while (mystatus
->currIdx
< lockData
->nelements
)
174 const char *locktypename
;
176 Datum values
[NUM_LOCK_STATUS_COLUMNS
] = {0};
177 bool nulls
[NUM_LOCK_STATUS_COLUMNS
] = {0};
180 LockInstanceData
*instance
;
182 instance
= &(lockData
->locks
[mystatus
->currIdx
]);
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
190 if (instance
->holdMask
)
192 for (mode
= 0; mode
< MAX_LOCKMODES
; mode
++)
194 if (instance
->holdMask
& LOCKBIT_ON(mode
))
197 instance
->holdMask
&= LOCKBIT_OFF(mode
);
204 * If no (more) held modes to report, see if PROC is waiting for a
209 if (instance
->waitLockMode
!= NoLock
)
211 /* Yes, so report it with proper mode */
212 mode
= instance
->waitLockMode
;
215 * We are now done with this PROCLOCK, so advance pointer to
216 * continue with next one on next call.
223 * Okay, we've displayed all the locks associated with this
224 * PROCLOCK, proceed to the next one.
232 * Form tuple with appropriate data.
235 if (instance
->locktag
.locktag_type
<= LOCKTAG_LAST_TYPE
)
236 locktypename
= LockTagTypeNames
[instance
->locktag
.locktag_type
];
239 snprintf(tnbuf
, sizeof(tnbuf
), "unknown %d",
240 (int) instance
->locktag
.locktag_type
);
241 locktypename
= tnbuf
;
243 values
[0] = CStringGetTextDatum(locktypename
);
245 switch ((LockTagType
) instance
->locktag
.locktag_type
)
247 case LOCKTAG_RELATION
:
248 case LOCKTAG_RELATION_EXTEND
:
249 values
[1] = ObjectIdGetDatum(instance
->locktag
.locktag_field1
);
250 values
[2] = ObjectIdGetDatum(instance
->locktag
.locktag_field2
);
259 case LOCKTAG_DATABASE_FROZEN_IDS
:
260 values
[1] = ObjectIdGetDatum(instance
->locktag
.locktag_field1
);
271 values
[1] = ObjectIdGetDatum(instance
->locktag
.locktag_field1
);
272 values
[2] = ObjectIdGetDatum(instance
->locktag
.locktag_field2
);
273 values
[3] = UInt32GetDatum(instance
->locktag
.locktag_field3
);
282 values
[1] = ObjectIdGetDatum(instance
->locktag
.locktag_field1
);
283 values
[2] = ObjectIdGetDatum(instance
->locktag
.locktag_field2
);
284 values
[3] = UInt32GetDatum(instance
->locktag
.locktag_field3
);
285 values
[4] = UInt16GetDatum(instance
->locktag
.locktag_field4
);
292 case LOCKTAG_TRANSACTION
:
294 TransactionIdGetDatum(instance
->locktag
.locktag_field1
);
304 case LOCKTAG_VIRTUALTRANSACTION
:
305 values
[5] = VXIDGetDatum(instance
->locktag
.locktag_field1
,
306 instance
->locktag
.locktag_field2
);
316 case LOCKTAG_SPECULATIVE_TOKEN
:
318 TransactionIdGetDatum(instance
->locktag
.locktag_field1
);
319 values
[8] = ObjectIdGetDatum(instance
->locktag
.locktag_field2
);
328 case LOCKTAG_APPLY_TRANSACTION
:
329 values
[1] = ObjectIdGetDatum(instance
->locktag
.locktag_field1
);
330 values
[8] = ObjectIdGetDatum(instance
->locktag
.locktag_field2
);
331 values
[6] = ObjectIdGetDatum(instance
->locktag
.locktag_field3
);
332 values
[9] = Int16GetDatum(instance
->locktag
.locktag_field4
);
340 case LOCKTAG_USERLOCK
:
341 case LOCKTAG_ADVISORY
:
342 default: /* treat unknown locktags like OBJECT */
343 values
[1] = ObjectIdGetDatum(instance
->locktag
.locktag_field1
);
344 values
[7] = ObjectIdGetDatum(instance
->locktag
.locktag_field2
);
345 values
[8] = ObjectIdGetDatum(instance
->locktag
.locktag_field3
);
346 values
[9] = Int16GetDatum(instance
->locktag
.locktag_field4
);
355 values
[10] = VXIDGetDatum(instance
->vxid
.procNumber
, instance
->vxid
.localTransactionId
);
356 if (instance
->pid
!= 0)
357 values
[11] = Int32GetDatum(instance
->pid
);
360 values
[12] = CStringGetTextDatum(GetLockmodeName(instance
->locktag
.locktag_lockmethodid
, mode
));
361 values
[13] = BoolGetDatum(granted
);
362 values
[14] = BoolGetDatum(instance
->fastpath
);
363 if (!granted
&& instance
->waitStart
!= 0)
364 values
[15] = TimestampTzGetDatum(instance
->waitStart
);
368 tuple
= heap_form_tuple(funcctx
->tuple_desc
, values
, nulls
);
369 result
= HeapTupleGetDatum(tuple
);
370 SRF_RETURN_NEXT(funcctx
, result
);
374 * Have returned all regular locks. Now start on the SIREAD predicate
377 predLockData
= mystatus
->predLockData
;
378 if (mystatus
->predLockIdx
< predLockData
->nelements
)
380 PredicateLockTargetType lockType
;
382 PREDICATELOCKTARGETTAG
*predTag
= &(predLockData
->locktags
[mystatus
->predLockIdx
]);
383 SERIALIZABLEXACT
*xact
= &(predLockData
->xacts
[mystatus
->predLockIdx
]);
384 Datum values
[NUM_LOCK_STATUS_COLUMNS
] = {0};
385 bool nulls
[NUM_LOCK_STATUS_COLUMNS
] = {0};
389 mystatus
->predLockIdx
++;
392 * Form tuple with appropriate data.
396 lockType
= GET_PREDICATELOCKTARGETTAG_TYPE(*predTag
);
398 values
[0] = CStringGetTextDatum(PredicateLockTagTypeNames
[lockType
]);
401 values
[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag
);
402 values
[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag
);
403 if (lockType
== PREDLOCKTAG_TUPLE
)
404 values
[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag
);
407 if ((lockType
== PREDLOCKTAG_TUPLE
) ||
408 (lockType
== PREDLOCKTAG_PAGE
))
409 values
[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag
);
413 /* these fields are targets for other types of locks */
414 nulls
[5] = true; /* virtualxid */
415 nulls
[6] = true; /* transactionid */
416 nulls
[7] = true; /* classid */
417 nulls
[8] = true; /* objid */
418 nulls
[9] = true; /* objsubid */
421 values
[10] = VXIDGetDatum(xact
->vxid
.procNumber
,
422 xact
->vxid
.localTransactionId
);
424 values
[11] = Int32GetDatum(xact
->pid
);
429 * Lock mode. Currently all predicate locks are SIReadLocks, which are
430 * always held (never waiting) and have no fast path
432 values
[12] = CStringGetTextDatum("SIReadLock");
433 values
[13] = BoolGetDatum(true);
434 values
[14] = BoolGetDatum(false);
437 tuple
= heap_form_tuple(funcctx
->tuple_desc
, values
, nulls
);
438 result
= HeapTupleGetDatum(tuple
);
439 SRF_RETURN_NEXT(funcctx
, result
);
442 SRF_RETURN_DONE(funcctx
);
447 * pg_blocking_pids - produce an array of the PIDs blocking given PID
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).
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.
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.
463 * We need not consider predicate locks here, since those don't block anything.
466 pg_blocking_pids(PG_FUNCTION_ARGS
)
468 int blocked_pid
= PG_GETARG_INT32(0);
471 BlockedProcsData
*lockData
; /* state data from lmgr */
475 /* Collect a snapshot of lock manager state */
476 lockData
= GetBlockerStatusData(blocked_pid
);
478 /* We can't need more output entries than there are reported PROCLOCKs */
479 arrayelems
= (Datum
*) palloc(lockData
->nlocks
* sizeof(Datum
));
482 /* For each blocked proc in the lock group ... */
483 for (i
= 0; i
< lockData
->nprocs
; i
++)
485 BlockedProcData
*bproc
= &lockData
->procs
[i
];
486 LockInstanceData
*instances
= &lockData
->locks
[bproc
->first_lock
];
487 int *preceding_waiters
= &lockData
->waiter_pids
[bproc
->first_waiter
];
488 LockInstanceData
*blocked_instance
;
489 LockMethod lockMethodTable
;
493 * Locate the blocked proc's own entry in the LockInstanceData array.
494 * There should be exactly one matching entry.
496 blocked_instance
= NULL
;
497 for (j
= 0; j
< bproc
->num_locks
; j
++)
499 LockInstanceData
*instance
= &(instances
[j
]);
501 if (instance
->pid
== bproc
->pid
)
503 Assert(blocked_instance
== NULL
);
504 blocked_instance
= instance
;
507 Assert(blocked_instance
!= NULL
);
509 lockMethodTable
= GetLockTagsMethodTable(&(blocked_instance
->locktag
));
510 conflictMask
= lockMethodTable
->conflictTab
[blocked_instance
->waitLockMode
];
512 /* Now scan the PROCLOCK data for conflicting procs */
513 for (j
= 0; j
< bproc
->num_locks
; j
++)
515 LockInstanceData
*instance
= &(instances
[j
]);
517 /* A proc never blocks itself, so ignore that entry */
518 if (instance
== blocked_instance
)
520 /* Members of same lock group never block each other, either */
521 if (instance
->leaderPid
== blocked_instance
->leaderPid
)
524 if (conflictMask
& instance
->holdMask
)
526 /* hard block: blocked by lock already held by this entry */
528 else if (instance
->waitLockMode
!= NoLock
&&
529 (conflictMask
& LOCKBIT_ON(instance
->waitLockMode
)))
531 /* conflict in lock requests; who's in front in wait queue? */
535 for (k
= 0; k
< bproc
->num_waiters
; k
++)
537 if (preceding_waiters
[k
] == instance
->pid
)
539 /* soft block: this entry is ahead of blocked proc */
545 continue; /* not blocked by this entry */
549 /* not blocked by this entry */
553 /* blocked by this entry, so emit a record */
554 arrayelems
[narrayelems
++] = Int32GetDatum(instance
->leaderPid
);
558 /* Assert we didn't overrun arrayelems[] */
559 Assert(narrayelems
<= lockData
->nlocks
);
561 PG_RETURN_ARRAYTYPE_P(construct_array_builtin(arrayelems
, narrayelems
, INT4OID
));
566 * pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
567 * given PID from getting a safe snapshot
569 * XXX this does not consider parallel-query cases; not clear how big a
570 * problem that is in practice
573 pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS
)
575 int blocked_pid
= PG_GETARG_INT32(0);
578 Datum
*blocker_datums
;
580 /* A buffer big enough for any possible blocker list without truncation */
581 blockers
= (int *) palloc(MaxBackends
* sizeof(int));
583 /* Collect a snapshot of processes waited for by GetSafeSnapshot */
585 GetSafeSnapshotBlockingPids(blocked_pid
, blockers
, MaxBackends
);
587 /* Convert int array to Datum array */
588 if (num_blockers
> 0)
592 blocker_datums
= (Datum
*) palloc(num_blockers
* sizeof(Datum
));
593 for (i
= 0; i
< num_blockers
; ++i
)
594 blocker_datums
[i
] = Int32GetDatum(blockers
[i
]);
597 blocker_datums
= NULL
;
599 PG_RETURN_ARRAYTYPE_P(construct_array_builtin(blocker_datums
, num_blockers
, INT4OID
));
604 * Functions for manipulating advisory locks
606 * We make use of the locktag fields as follows:
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
613 #define SET_LOCKTAG_INT64(tag, key64) \
614 SET_LOCKTAG_ADVISORY(tag, \
616 (uint32) ((key64) >> 32), \
619 #define SET_LOCKTAG_INT32(tag, key1, key2) \
620 SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
623 * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
626 pg_advisory_lock_int8(PG_FUNCTION_ARGS
)
628 int64 key
= PG_GETARG_INT64(0);
631 SET_LOCKTAG_INT64(tag
, key
);
633 (void) LockAcquire(&tag
, ExclusiveLock
, true, false);
639 * pg_advisory_xact_lock(int8) - acquire xact scoped
640 * exclusive lock on an int8 key
643 pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS
)
645 int64 key
= PG_GETARG_INT64(0);
648 SET_LOCKTAG_INT64(tag
, key
);
650 (void) LockAcquire(&tag
, ExclusiveLock
, false, false);
656 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
659 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS
)
661 int64 key
= PG_GETARG_INT64(0);
664 SET_LOCKTAG_INT64(tag
, key
);
666 (void) LockAcquire(&tag
, ShareLock
, true, false);
672 * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
673 * share lock on an int8 key
676 pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS
)
678 int64 key
= PG_GETARG_INT64(0);
681 SET_LOCKTAG_INT64(tag
, key
);
683 (void) LockAcquire(&tag
, ShareLock
, false, false);
689 * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
691 * Returns true if successful, false if lock not available
694 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS
)
696 int64 key
= PG_GETARG_INT64(0);
698 LockAcquireResult res
;
700 SET_LOCKTAG_INT64(tag
, key
);
702 res
= LockAcquire(&tag
, ExclusiveLock
, true, true);
704 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
708 * pg_try_advisory_xact_lock(int8) - acquire xact scoped
709 * exclusive lock on an int8 key, no wait
711 * Returns true if successful, false if lock not available
714 pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS
)
716 int64 key
= PG_GETARG_INT64(0);
718 LockAcquireResult res
;
720 SET_LOCKTAG_INT64(tag
, key
);
722 res
= LockAcquire(&tag
, ExclusiveLock
, false, true);
724 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
728 * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
730 * Returns true if successful, false if lock not available
733 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS
)
735 int64 key
= PG_GETARG_INT64(0);
737 LockAcquireResult res
;
739 SET_LOCKTAG_INT64(tag
, key
);
741 res
= LockAcquire(&tag
, ShareLock
, true, true);
743 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
747 * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
748 * share lock on an int8 key, no wait
750 * Returns true if successful, false if lock not available
753 pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS
)
755 int64 key
= PG_GETARG_INT64(0);
757 LockAcquireResult res
;
759 SET_LOCKTAG_INT64(tag
, key
);
761 res
= LockAcquire(&tag
, ShareLock
, false, true);
763 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
767 * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
769 * Returns true if successful, false if lock was not held
772 pg_advisory_unlock_int8(PG_FUNCTION_ARGS
)
774 int64 key
= PG_GETARG_INT64(0);
778 SET_LOCKTAG_INT64(tag
, key
);
780 res
= LockRelease(&tag
, ExclusiveLock
, true);
786 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
788 * Returns true if successful, false if lock was not held
791 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS
)
793 int64 key
= PG_GETARG_INT64(0);
797 SET_LOCKTAG_INT64(tag
, key
);
799 res
= LockRelease(&tag
, ShareLock
, true);
805 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
808 pg_advisory_lock_int4(PG_FUNCTION_ARGS
)
810 int32 key1
= PG_GETARG_INT32(0);
811 int32 key2
= PG_GETARG_INT32(1);
814 SET_LOCKTAG_INT32(tag
, key1
, key2
);
816 (void) LockAcquire(&tag
, ExclusiveLock
, true, false);
822 * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
823 * exclusive lock on 2 int4 keys
826 pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS
)
828 int32 key1
= PG_GETARG_INT32(0);
829 int32 key2
= PG_GETARG_INT32(1);
832 SET_LOCKTAG_INT32(tag
, key1
, key2
);
834 (void) LockAcquire(&tag
, ExclusiveLock
, false, false);
840 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
843 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS
)
845 int32 key1
= PG_GETARG_INT32(0);
846 int32 key2
= PG_GETARG_INT32(1);
849 SET_LOCKTAG_INT32(tag
, key1
, key2
);
851 (void) LockAcquire(&tag
, ShareLock
, true, false);
857 * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
858 * share lock on 2 int4 keys
861 pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS
)
863 int32 key1
= PG_GETARG_INT32(0);
864 int32 key2
= PG_GETARG_INT32(1);
867 SET_LOCKTAG_INT32(tag
, key1
, key2
);
869 (void) LockAcquire(&tag
, ShareLock
, false, false);
875 * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
877 * Returns true if successful, false if lock not available
880 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS
)
882 int32 key1
= PG_GETARG_INT32(0);
883 int32 key2
= PG_GETARG_INT32(1);
885 LockAcquireResult res
;
887 SET_LOCKTAG_INT32(tag
, key1
, key2
);
889 res
= LockAcquire(&tag
, ExclusiveLock
, true, true);
891 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
895 * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
896 * exclusive lock on 2 int4 keys, no wait
898 * Returns true if successful, false if lock not available
901 pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS
)
903 int32 key1
= PG_GETARG_INT32(0);
904 int32 key2
= PG_GETARG_INT32(1);
906 LockAcquireResult res
;
908 SET_LOCKTAG_INT32(tag
, key1
, key2
);
910 res
= LockAcquire(&tag
, ExclusiveLock
, false, true);
912 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
916 * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
918 * Returns true if successful, false if lock not available
921 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS
)
923 int32 key1
= PG_GETARG_INT32(0);
924 int32 key2
= PG_GETARG_INT32(1);
926 LockAcquireResult res
;
928 SET_LOCKTAG_INT32(tag
, key1
, key2
);
930 res
= LockAcquire(&tag
, ShareLock
, true, true);
932 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
936 * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
937 * share lock on 2 int4 keys, no wait
939 * Returns true if successful, false if lock not available
942 pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS
)
944 int32 key1
= PG_GETARG_INT32(0);
945 int32 key2
= PG_GETARG_INT32(1);
947 LockAcquireResult res
;
949 SET_LOCKTAG_INT32(tag
, key1
, key2
);
951 res
= LockAcquire(&tag
, ShareLock
, false, true);
953 PG_RETURN_BOOL(res
!= LOCKACQUIRE_NOT_AVAIL
);
957 * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
959 * Returns true if successful, false if lock was not held
962 pg_advisory_unlock_int4(PG_FUNCTION_ARGS
)
964 int32 key1
= PG_GETARG_INT32(0);
965 int32 key2
= PG_GETARG_INT32(1);
969 SET_LOCKTAG_INT32(tag
, key1
, key2
);
971 res
= LockRelease(&tag
, ExclusiveLock
, true);
977 * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
979 * Returns true if successful, false if lock was not held
982 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS
)
984 int32 key1
= PG_GETARG_INT32(0);
985 int32 key2
= PG_GETARG_INT32(1);
989 SET_LOCKTAG_INT32(tag
, key1
, key2
);
991 res
= LockRelease(&tag
, ShareLock
, true);
997 * pg_advisory_unlock_all() - release all advisory locks
1000 pg_advisory_unlock_all(PG_FUNCTION_ARGS
)
1002 LockReleaseSession(USER_LOCKMETHOD
);