Cache NO ACTION foreign keys separately from RESTRICT foreign keys
[pgsql.git] / src / backend / utils / adt / lockfuncs.c
blob00e67fb46d07467ff8e4f1c8ab2dab04c009a124
1 /*-------------------------------------------------------------------------
3 * lockfuncs.c
4 * Functions for SQL access to various lock-manager capabilities.
6 * Copyright (c) 2002-2025, PostgreSQL Global Development Group
8 * IDENTIFICATION
9 * src/backend/utils/adt/lockfuncs.c
11 *-------------------------------------------------------------------------
13 #include "postgres.h"
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"
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[] = {
29 "relation",
30 "extend",
31 "frozenid",
32 "page",
33 "tuple",
34 "transactionid",
35 "virtualxid",
36 "spectoken",
37 "object",
38 "userlock",
39 "advisory",
40 "applytransaction"
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[] = {
48 "relation",
49 "page",
50 "tuple"
53 StaticAssertDecl(lengthof(PredicateLockTagTypeNames) == (PREDLOCKTAG_TUPLE + 1),
54 "array length mismatch");
56 /* Working status for pg_lock_status */
57 typedef struct
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;
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.
73 static Datum
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
79 * vxid.
81 char vxidstr[32];
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
92 Datum
93 pg_lock_status(PG_FUNCTION_ARGS)
95 FuncCallContext *funcctx;
96 PG_Lock_Status *mystatus;
97 LockData *lockData;
98 PredicateLockData *predLockData;
100 if (SRF_IS_FIRSTCALL())
102 TupleDesc tupdesc;
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",
117 TEXTOID, -1, 0);
118 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
119 OIDOID, -1, 0);
120 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
121 OIDOID, -1, 0);
122 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
123 INT4OID, -1, 0);
124 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
125 INT2OID, -1, 0);
126 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
127 TEXTOID, -1, 0);
128 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
129 XIDOID, -1, 0);
130 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
131 OIDOID, -1, 0);
132 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
133 OIDOID, -1, 0);
134 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
135 INT2OID, -1, 0);
136 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
137 TEXTOID, -1, 0);
138 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
139 INT4OID, -1, 0);
140 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
141 TEXTOID, -1, 0);
142 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
143 BOOLOID, -1, 0);
144 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
145 BOOLOID, -1, 0);
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)
172 bool granted;
173 LOCKMODE mode = 0;
174 const char *locktypename;
175 char tnbuf[32];
176 Datum values[NUM_LOCK_STATUS_COLUMNS] = {0};
177 bool nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
178 HeapTuple tuple;
179 Datum result;
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
187 * again.
189 granted = false;
190 if (instance->holdMask)
192 for (mode = 0; mode < MAX_LOCKMODES; mode++)
194 if (instance->holdMask & LOCKBIT_ON(mode))
196 granted = true;
197 instance->holdMask &= LOCKBIT_OFF(mode);
198 break;
204 * If no (more) held modes to report, see if PROC is waiting for a
205 * lock on this lock.
207 if (!granted)
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.
218 mystatus->currIdx++;
220 else
223 * Okay, we've displayed all the locks associated with this
224 * PROCLOCK, proceed to the next one.
226 mystatus->currIdx++;
227 continue;
232 * Form tuple with appropriate data.
235 if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
236 locktypename = LockTagTypeNames[instance->locktag.locktag_type];
237 else
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);
251 nulls[3] = true;
252 nulls[4] = true;
253 nulls[5] = true;
254 nulls[6] = true;
255 nulls[7] = true;
256 nulls[8] = true;
257 nulls[9] = true;
258 break;
259 case LOCKTAG_DATABASE_FROZEN_IDS:
260 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
261 nulls[2] = true;
262 nulls[3] = true;
263 nulls[4] = true;
264 nulls[5] = true;
265 nulls[6] = true;
266 nulls[7] = true;
267 nulls[8] = true;
268 nulls[9] = true;
269 break;
270 case LOCKTAG_PAGE:
271 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
272 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
273 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
274 nulls[4] = true;
275 nulls[5] = true;
276 nulls[6] = true;
277 nulls[7] = true;
278 nulls[8] = true;
279 nulls[9] = true;
280 break;
281 case LOCKTAG_TUPLE:
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);
286 nulls[5] = true;
287 nulls[6] = true;
288 nulls[7] = true;
289 nulls[8] = true;
290 nulls[9] = true;
291 break;
292 case LOCKTAG_TRANSACTION:
293 values[6] =
294 TransactionIdGetDatum(instance->locktag.locktag_field1);
295 nulls[1] = true;
296 nulls[2] = true;
297 nulls[3] = true;
298 nulls[4] = true;
299 nulls[5] = true;
300 nulls[7] = true;
301 nulls[8] = true;
302 nulls[9] = true;
303 break;
304 case LOCKTAG_VIRTUALTRANSACTION:
305 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
306 instance->locktag.locktag_field2);
307 nulls[1] = true;
308 nulls[2] = true;
309 nulls[3] = true;
310 nulls[4] = true;
311 nulls[6] = true;
312 nulls[7] = true;
313 nulls[8] = true;
314 nulls[9] = true;
315 break;
316 case LOCKTAG_SPECULATIVE_TOKEN:
317 values[6] =
318 TransactionIdGetDatum(instance->locktag.locktag_field1);
319 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
320 nulls[1] = true;
321 nulls[2] = true;
322 nulls[3] = true;
323 nulls[4] = true;
324 nulls[5] = true;
325 nulls[7] = true;
326 nulls[9] = true;
327 break;
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);
333 nulls[2] = true;
334 nulls[3] = true;
335 nulls[4] = true;
336 nulls[5] = true;
337 nulls[7] = true;
338 break;
339 case LOCKTAG_OBJECT:
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);
347 nulls[2] = true;
348 nulls[3] = true;
349 nulls[4] = true;
350 nulls[5] = true;
351 nulls[6] = true;
352 break;
355 values[10] = VXIDGetDatum(instance->vxid.procNumber, instance->vxid.localTransactionId);
356 if (instance->pid != 0)
357 values[11] = Int32GetDatum(instance->pid);
358 else
359 nulls[11] = true;
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);
365 else
366 nulls[15] = true;
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
375 * locks.
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};
386 HeapTuple tuple;
387 Datum result;
389 mystatus->predLockIdx++;
392 * Form tuple with appropriate data.
395 /* lock type */
396 lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
398 values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
400 /* lock target */
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);
405 else
406 nulls[4] = true;
407 if ((lockType == PREDLOCKTAG_TUPLE) ||
408 (lockType == PREDLOCKTAG_PAGE))
409 values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
410 else
411 nulls[3] = true;
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 */
420 /* lock holder */
421 values[10] = VXIDGetDatum(xact->vxid.procNumber,
422 xact->vxid.localTransactionId);
423 if (xact->pid != 0)
424 values[11] = Int32GetDatum(xact->pid);
425 else
426 nulls[11] = true;
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);
435 nulls[15] = true;
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.
465 Datum
466 pg_blocking_pids(PG_FUNCTION_ARGS)
468 int blocked_pid = PG_GETARG_INT32(0);
469 Datum *arrayelems;
470 int narrayelems;
471 BlockedProcsData *lockData; /* state data from lmgr */
472 int i,
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));
480 narrayelems = 0;
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;
490 int conflictMask;
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)
519 continue;
520 /* Members of same lock group never block each other, either */
521 if (instance->leaderPid == blocked_instance->leaderPid)
522 continue;
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? */
532 bool ahead = false;
533 int k;
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 */
540 ahead = true;
541 break;
544 if (!ahead)
545 continue; /* not blocked by this entry */
547 else
549 /* not blocked by this entry */
550 continue;
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
572 Datum
573 pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
575 int blocked_pid = PG_GETARG_INT32(0);
576 int *blockers;
577 int num_blockers;
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 */
584 num_blockers =
585 GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
587 /* Convert int array to Datum array */
588 if (num_blockers > 0)
590 int i;
592 blocker_datums = (Datum *) palloc(num_blockers * sizeof(Datum));
593 for (i = 0; i < num_blockers; ++i)
594 blocker_datums[i] = Int32GetDatum(blockers[i]);
596 else
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, \
615 MyDatabaseId, \
616 (uint32) ((key64) >> 32), \
617 (uint32) (key64), \
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
625 Datum
626 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
628 int64 key = PG_GETARG_INT64(0);
629 LOCKTAG tag;
631 SET_LOCKTAG_INT64(tag, key);
633 (void) LockAcquire(&tag, ExclusiveLock, true, false);
635 PG_RETURN_VOID();
639 * pg_advisory_xact_lock(int8) - acquire xact scoped
640 * exclusive lock on an int8 key
642 Datum
643 pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
645 int64 key = PG_GETARG_INT64(0);
646 LOCKTAG tag;
648 SET_LOCKTAG_INT64(tag, key);
650 (void) LockAcquire(&tag, ExclusiveLock, false, false);
652 PG_RETURN_VOID();
656 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
658 Datum
659 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
661 int64 key = PG_GETARG_INT64(0);
662 LOCKTAG tag;
664 SET_LOCKTAG_INT64(tag, key);
666 (void) LockAcquire(&tag, ShareLock, true, false);
668 PG_RETURN_VOID();
672 * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
673 * share lock on an int8 key
675 Datum
676 pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
678 int64 key = PG_GETARG_INT64(0);
679 LOCKTAG tag;
681 SET_LOCKTAG_INT64(tag, key);
683 (void) LockAcquire(&tag, ShareLock, false, false);
685 PG_RETURN_VOID();
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
693 Datum
694 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
696 int64 key = PG_GETARG_INT64(0);
697 LOCKTAG tag;
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
713 Datum
714 pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
716 int64 key = PG_GETARG_INT64(0);
717 LOCKTAG tag;
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
732 Datum
733 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
735 int64 key = PG_GETARG_INT64(0);
736 LOCKTAG tag;
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
752 Datum
753 pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
755 int64 key = PG_GETARG_INT64(0);
756 LOCKTAG tag;
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
771 Datum
772 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
774 int64 key = PG_GETARG_INT64(0);
775 LOCKTAG tag;
776 bool res;
778 SET_LOCKTAG_INT64(tag, key);
780 res = LockRelease(&tag, ExclusiveLock, true);
782 PG_RETURN_BOOL(res);
786 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
788 * Returns true if successful, false if lock was not held
790 Datum
791 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
793 int64 key = PG_GETARG_INT64(0);
794 LOCKTAG tag;
795 bool res;
797 SET_LOCKTAG_INT64(tag, key);
799 res = LockRelease(&tag, ShareLock, true);
801 PG_RETURN_BOOL(res);
805 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
807 Datum
808 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
810 int32 key1 = PG_GETARG_INT32(0);
811 int32 key2 = PG_GETARG_INT32(1);
812 LOCKTAG tag;
814 SET_LOCKTAG_INT32(tag, key1, key2);
816 (void) LockAcquire(&tag, ExclusiveLock, true, false);
818 PG_RETURN_VOID();
822 * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
823 * exclusive lock on 2 int4 keys
825 Datum
826 pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
828 int32 key1 = PG_GETARG_INT32(0);
829 int32 key2 = PG_GETARG_INT32(1);
830 LOCKTAG tag;
832 SET_LOCKTAG_INT32(tag, key1, key2);
834 (void) LockAcquire(&tag, ExclusiveLock, false, false);
836 PG_RETURN_VOID();
840 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
842 Datum
843 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
845 int32 key1 = PG_GETARG_INT32(0);
846 int32 key2 = PG_GETARG_INT32(1);
847 LOCKTAG tag;
849 SET_LOCKTAG_INT32(tag, key1, key2);
851 (void) LockAcquire(&tag, ShareLock, true, false);
853 PG_RETURN_VOID();
857 * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
858 * share lock on 2 int4 keys
860 Datum
861 pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
863 int32 key1 = PG_GETARG_INT32(0);
864 int32 key2 = PG_GETARG_INT32(1);
865 LOCKTAG tag;
867 SET_LOCKTAG_INT32(tag, key1, key2);
869 (void) LockAcquire(&tag, ShareLock, false, false);
871 PG_RETURN_VOID();
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
879 Datum
880 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
882 int32 key1 = PG_GETARG_INT32(0);
883 int32 key2 = PG_GETARG_INT32(1);
884 LOCKTAG tag;
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
900 Datum
901 pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
903 int32 key1 = PG_GETARG_INT32(0);
904 int32 key2 = PG_GETARG_INT32(1);
905 LOCKTAG tag;
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
920 Datum
921 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
923 int32 key1 = PG_GETARG_INT32(0);
924 int32 key2 = PG_GETARG_INT32(1);
925 LOCKTAG tag;
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
941 Datum
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);
946 LOCKTAG tag;
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
961 Datum
962 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
964 int32 key1 = PG_GETARG_INT32(0);
965 int32 key2 = PG_GETARG_INT32(1);
966 LOCKTAG tag;
967 bool res;
969 SET_LOCKTAG_INT32(tag, key1, key2);
971 res = LockRelease(&tag, ExclusiveLock, true);
973 PG_RETURN_BOOL(res);
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
981 Datum
982 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
984 int32 key1 = PG_GETARG_INT32(0);
985 int32 key2 = PG_GETARG_INT32(1);
986 LOCKTAG tag;
987 bool res;
989 SET_LOCKTAG_INT32(tag, key1, key2);
991 res = LockRelease(&tag, ShareLock, true);
993 PG_RETURN_BOOL(res);
997 * pg_advisory_unlock_all() - release all advisory locks
999 Datum
1000 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
1002 LockReleaseSession(USER_LOCKMETHOD);
1004 PG_RETURN_VOID();