]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/lockfuncs.c
33c5b64f50ac9b8f05a64f4e3a985d4cee2ceaca
[postgresql] / src / backend / utils / adt / lockfuncs.c
1 /*-------------------------------------------------------------------------
2  *
3  * lockfuncs.c
4  *              Functions for SQL access to various lock-manager capabilities.
5  *
6  * Copyright (c) 2002-2012, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  *              src/backend/utils/adt/lockfuncs.c
10  *
11  *-------------------------------------------------------------------------
12  */
13 #include "postgres.h"
14
15 #include "catalog/pg_type.h"
16 #include "funcapi.h"
17 #include "miscadmin.h"
18 #include "storage/predicate_internals.h"
19 #include "utils/builtins.h"
20
21
22 /* This must match enum LockTagType! */
23 static const char *const LockTagTypeNames[] = {
24         "relation",
25         "extend",
26         "page",
27         "tuple",
28         "transactionid",
29         "virtualxid",
30         "object",
31         "userlock",
32         "advisory"
33 };
34
35 /* This must match enum PredicateLockTargetType (predicate_internals.h) */
36 static const char *const PredicateLockTagTypeNames[] = {
37         "relation",
38         "page",
39         "tuple"
40 };
41
42 /* Working status for pg_lock_status */
43 typedef struct
44 {
45         LockData   *lockData;           /* state data from lmgr */
46         int                     currIdx;                /* current PROCLOCK index */
47         PredicateLockData *predLockData;        /* state data for pred locks */
48         int                     predLockIdx;    /* current index for pred lock */
49 } PG_Lock_Status;
50
51 /* Number of columns in pg_locks output */
52 #define NUM_LOCK_STATUS_COLUMNS         15
53
54 /*
55  * VXIDGetDatum - Construct a text representation of a VXID
56  *
57  * This is currently only used in pg_lock_status, so we put it here.
58  */
59 static Datum
60 VXIDGetDatum(BackendId bid, LocalTransactionId lxid)
61 {
62         /*
63          * The representation is "<bid>/<lxid>", decimal and unsigned decimal
64          * respectively.  Note that elog.c also knows how to format a vxid.
65          */
66         char            vxidstr[32];
67
68         snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
69
70         return CStringGetTextDatum(vxidstr);
71 }
72
73
74 /*
75  * pg_lock_status - produce a view with one row per held or awaited lock mode
76  */
77 Datum
78 pg_lock_status(PG_FUNCTION_ARGS)
79 {
80         FuncCallContext *funcctx;
81         PG_Lock_Status *mystatus;
82         LockData   *lockData;
83         PredicateLockData *predLockData;
84
85         if (SRF_IS_FIRSTCALL())
86         {
87                 TupleDesc       tupdesc;
88                 MemoryContext oldcontext;
89
90                 /* create a function context for cross-call persistence */
91                 funcctx = SRF_FIRSTCALL_INIT();
92
93                 /*
94                  * switch to memory context appropriate for multiple function calls
95                  */
96                 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
97
98                 /* build tupdesc for result tuples */
99                 /* this had better match pg_locks view in system_views.sql */
100                 tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS, false);
101                 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
102                                                    TEXTOID, -1, 0);
103                 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
104                                                    OIDOID, -1, 0);
105                 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
106                                                    OIDOID, -1, 0);
107                 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
108                                                    INT4OID, -1, 0);
109                 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
110                                                    INT2OID, -1, 0);
111                 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
112                                                    TEXTOID, -1, 0);
113                 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
114                                                    XIDOID, -1, 0);
115                 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
116                                                    OIDOID, -1, 0);
117                 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
118                                                    OIDOID, -1, 0);
119                 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
120                                                    INT2OID, -1, 0);
121                 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
122                                                    TEXTOID, -1, 0);
123                 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
124                                                    INT4OID, -1, 0);
125                 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
126                                                    TEXTOID, -1, 0);
127                 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
128                                                    BOOLOID, -1, 0);
129                 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
130                                                    BOOLOID, -1, 0);
131
132                 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
133
134                 /*
135                  * Collect all the locking information that we will format and send
136                  * out as a result set.
137                  */
138                 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
139                 funcctx->user_fctx = (void *) mystatus;
140
141                 mystatus->lockData = GetLockStatusData();
142                 mystatus->currIdx = 0;
143                 mystatus->predLockData = GetPredicateLockStatusData();
144                 mystatus->predLockIdx = 0;
145
146                 MemoryContextSwitchTo(oldcontext);
147         }
148
149         funcctx = SRF_PERCALL_SETUP();
150         mystatus = (PG_Lock_Status *) funcctx->user_fctx;
151         lockData = mystatus->lockData;
152
153         while (mystatus->currIdx < lockData->nelements)
154         {
155                 bool            granted;
156                 LOCKMODE        mode = 0;
157                 const char *locktypename;
158                 char            tnbuf[32];
159                 Datum           values[NUM_LOCK_STATUS_COLUMNS];
160                 bool            nulls[NUM_LOCK_STATUS_COLUMNS];
161                 HeapTuple       tuple;
162                 Datum           result;
163                 LockInstanceData *instance;
164
165                 instance = &(lockData->locks[mystatus->currIdx]);
166
167                 /*
168                  * Look to see if there are any held lock modes in this PROCLOCK. If
169                  * so, report, and destructively modify lockData so we don't report
170                  * again.
171                  */
172                 granted = false;
173                 if (instance->holdMask)
174                 {
175                         for (mode = 0; mode < MAX_LOCKMODES; mode++)
176                         {
177                                 if (instance->holdMask & LOCKBIT_ON(mode))
178                                 {
179                                         granted = true;
180                                         instance->holdMask &= LOCKBIT_OFF(mode);
181                                         break;
182                                 }
183                         }
184                 }
185
186                 /*
187                  * If no (more) held modes to report, see if PROC is waiting for a
188                  * lock on this lock.
189                  */
190                 if (!granted)
191                 {
192                         if (instance->waitLockMode != NoLock)
193                         {
194                                 /* Yes, so report it with proper mode */
195                                 mode = instance->waitLockMode;
196
197                                 /*
198                                  * We are now done with this PROCLOCK, so advance pointer to
199                                  * continue with next one on next call.
200                                  */
201                                 mystatus->currIdx++;
202                         }
203                         else
204                         {
205                                 /*
206                                  * Okay, we've displayed all the locks associated with this
207                                  * PROCLOCK, proceed to the next one.
208                                  */
209                                 mystatus->currIdx++;
210                                 continue;
211                         }
212                 }
213
214                 /*
215                  * Form tuple with appropriate data.
216                  */
217                 MemSet(values, 0, sizeof(values));
218                 MemSet(nulls, false, sizeof(nulls));
219
220                 if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
221                         locktypename = LockTagTypeNames[instance->locktag.locktag_type];
222                 else
223                 {
224                         snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
225                                          (int) instance->locktag.locktag_type);
226                         locktypename = tnbuf;
227                 }
228                 values[0] = CStringGetTextDatum(locktypename);
229
230                 switch ((LockTagType) instance->locktag.locktag_type)
231                 {
232                         case LOCKTAG_RELATION:
233                         case LOCKTAG_RELATION_EXTEND:
234                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
235                                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
236                                 nulls[3] = true;
237                                 nulls[4] = true;
238                                 nulls[5] = true;
239                                 nulls[6] = true;
240                                 nulls[7] = true;
241                                 nulls[8] = true;
242                                 nulls[9] = true;
243                                 break;
244                         case LOCKTAG_PAGE:
245                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
246                                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
247                                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
248                                 nulls[4] = true;
249                                 nulls[5] = true;
250                                 nulls[6] = true;
251                                 nulls[7] = true;
252                                 nulls[8] = true;
253                                 nulls[9] = true;
254                                 break;
255                         case LOCKTAG_TUPLE:
256                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
257                                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
258                                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
259                                 values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
260                                 nulls[5] = true;
261                                 nulls[6] = true;
262                                 nulls[7] = true;
263                                 nulls[8] = true;
264                                 nulls[9] = true;
265                                 break;
266                         case LOCKTAG_TRANSACTION:
267                                 values[6] =
268                                         TransactionIdGetDatum(instance->locktag.locktag_field1);
269                                 nulls[1] = true;
270                                 nulls[2] = true;
271                                 nulls[3] = true;
272                                 nulls[4] = true;
273                                 nulls[5] = true;
274                                 nulls[7] = true;
275                                 nulls[8] = true;
276                                 nulls[9] = true;
277                                 break;
278                         case LOCKTAG_VIRTUALTRANSACTION:
279                                 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
280                                                                                  instance->locktag.locktag_field2);
281                                 nulls[1] = true;
282                                 nulls[2] = true;
283                                 nulls[3] = true;
284                                 nulls[4] = true;
285                                 nulls[6] = true;
286                                 nulls[7] = true;
287                                 nulls[8] = true;
288                                 nulls[9] = true;
289                                 break;
290                         case LOCKTAG_OBJECT:
291                         case LOCKTAG_USERLOCK:
292                         case LOCKTAG_ADVISORY:
293                         default:                        /* treat unknown locktags like OBJECT */
294                                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
295                                 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
296                                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
297                                 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
298                                 nulls[2] = true;
299                                 nulls[3] = true;
300                                 nulls[4] = true;
301                                 nulls[5] = true;
302                                 nulls[6] = true;
303                                 break;
304                 }
305
306                 values[10] = VXIDGetDatum(instance->backend, instance->lxid);
307                 if (instance->pid != 0)
308                         values[11] = Int32GetDatum(instance->pid);
309                 else
310                         nulls[11] = true;
311                 values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
312                 values[13] = BoolGetDatum(granted);
313                 values[14] = BoolGetDatum(instance->fastpath);
314
315                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
316                 result = HeapTupleGetDatum(tuple);
317                 SRF_RETURN_NEXT(funcctx, result);
318         }
319
320         /*
321          * Have returned all regular locks. Now start on the SIREAD predicate
322          * locks.
323          */
324         predLockData = mystatus->predLockData;
325         if (mystatus->predLockIdx < predLockData->nelements)
326         {
327                 PredicateLockTargetType lockType;
328
329                 PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
330                 SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
331                 Datum           values[NUM_LOCK_STATUS_COLUMNS];
332                 bool            nulls[NUM_LOCK_STATUS_COLUMNS];
333                 HeapTuple       tuple;
334                 Datum           result;
335
336                 mystatus->predLockIdx++;
337
338                 /*
339                  * Form tuple with appropriate data.
340                  */
341                 MemSet(values, 0, sizeof(values));
342                 MemSet(nulls, false, sizeof(nulls));
343
344                 /* lock type */
345                 lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
346
347                 values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
348
349                 /* lock target */
350                 values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
351                 values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
352                 if (lockType == PREDLOCKTAG_TUPLE)
353                         values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
354                 else
355                         nulls[4] = true;
356                 if ((lockType == PREDLOCKTAG_TUPLE) ||
357                         (lockType == PREDLOCKTAG_PAGE))
358                         values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
359                 else
360                         nulls[3] = true;
361
362                 /* these fields are targets for other types of locks */
363                 nulls[5] = true;                /* virtualxid */
364                 nulls[6] = true;                /* transactionid */
365                 nulls[7] = true;                /* classid */
366                 nulls[8] = true;                /* objid */
367                 nulls[9] = true;                /* objsubid */
368
369                 /* lock holder */
370                 values[10] = VXIDGetDatum(xact->vxid.backendId,
371                                                                   xact->vxid.localTransactionId);
372                 if (xact->pid != 0)
373                         values[11] = Int32GetDatum(xact->pid);
374                 else
375                         nulls[11] = true;
376
377                 /*
378                  * Lock mode. Currently all predicate locks are SIReadLocks, which are
379                  * always held (never waiting) and have no fast path
380                  */
381                 values[12] = CStringGetTextDatum("SIReadLock");
382                 values[13] = BoolGetDatum(true);
383                 values[14] = BoolGetDatum(false);
384
385                 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
386                 result = HeapTupleGetDatum(tuple);
387                 SRF_RETURN_NEXT(funcctx, result);
388         }
389
390         SRF_RETURN_DONE(funcctx);
391 }
392
393
394 /*
395  * Functions for manipulating advisory locks
396  *
397  * We make use of the locktag fields as follows:
398  *
399  *      field1: MyDatabaseId ... ensures locks are local to each database
400  *      field2: first of 2 int4 keys, or high-order half of an int8 key
401  *      field3: second of 2 int4 keys, or low-order half of an int8 key
402  *      field4: 1 if using an int8 key, 2 if using 2 int4 keys
403  */
404 #define SET_LOCKTAG_INT64(tag, key64) \
405         SET_LOCKTAG_ADVISORY(tag, \
406                                                  MyDatabaseId, \
407                                                  (uint32) ((key64) >> 32), \
408                                                  (uint32) (key64), \
409                                                  1)
410 #define SET_LOCKTAG_INT32(tag, key1, key2) \
411         SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
412
413 /*
414  * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
415  */
416 Datum
417 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
418 {
419         int64           key = PG_GETARG_INT64(0);
420         LOCKTAG         tag;
421
422         SET_LOCKTAG_INT64(tag, key);
423
424         (void) LockAcquire(&tag, ExclusiveLock, true, false);
425
426         PG_RETURN_VOID();
427 }
428
429 /*
430  * pg_advisory_xact_lock(int8) - acquire xact scoped
431  * exclusive lock on an int8 key
432  */
433 Datum
434 pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
435 {
436         int64           key = PG_GETARG_INT64(0);
437         LOCKTAG         tag;
438
439         SET_LOCKTAG_INT64(tag, key);
440
441         (void) LockAcquire(&tag, ExclusiveLock, false, false);
442
443         PG_RETURN_VOID();
444 }
445
446 /*
447  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
448  */
449 Datum
450 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
451 {
452         int64           key = PG_GETARG_INT64(0);
453         LOCKTAG         tag;
454
455         SET_LOCKTAG_INT64(tag, key);
456
457         (void) LockAcquire(&tag, ShareLock, true, false);
458
459         PG_RETURN_VOID();
460 }
461
462 /*
463  * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
464  * share lock on an int8 key
465  */
466 Datum
467 pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
468 {
469         int64           key = PG_GETARG_INT64(0);
470         LOCKTAG         tag;
471
472         SET_LOCKTAG_INT64(tag, key);
473
474         (void) LockAcquire(&tag, ShareLock, false, false);
475
476         PG_RETURN_VOID();
477 }
478
479 /*
480  * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
481  *
482  * Returns true if successful, false if lock not available
483  */
484 Datum
485 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
486 {
487         int64           key = PG_GETARG_INT64(0);
488         LOCKTAG         tag;
489         LockAcquireResult res;
490
491         SET_LOCKTAG_INT64(tag, key);
492
493         res = LockAcquire(&tag, ExclusiveLock, true, true);
494
495         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
496 }
497
498 /*
499  * pg_try_advisory_xact_lock(int8) - acquire xact scoped
500  * exclusive lock on an int8 key, no wait
501  *
502  * Returns true if successful, false if lock not available
503  */
504 Datum
505 pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
506 {
507         int64           key = PG_GETARG_INT64(0);
508         LOCKTAG         tag;
509         LockAcquireResult res;
510
511         SET_LOCKTAG_INT64(tag, key);
512
513         res = LockAcquire(&tag, ExclusiveLock, false, true);
514
515         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
516 }
517
518 /*
519  * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
520  *
521  * Returns true if successful, false if lock not available
522  */
523 Datum
524 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
525 {
526         int64           key = PG_GETARG_INT64(0);
527         LOCKTAG         tag;
528         LockAcquireResult res;
529
530         SET_LOCKTAG_INT64(tag, key);
531
532         res = LockAcquire(&tag, ShareLock, true, true);
533
534         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
535 }
536
537 /*
538  * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
539  * share lock on an int8 key, no wait
540  *
541  * Returns true if successful, false if lock not available
542  */
543 Datum
544 pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
545 {
546         int64           key = PG_GETARG_INT64(0);
547         LOCKTAG         tag;
548         LockAcquireResult res;
549
550         SET_LOCKTAG_INT64(tag, key);
551
552         res = LockAcquire(&tag, ShareLock, false, true);
553
554         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
555 }
556
557 /*
558  * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
559  *
560  * Returns true if successful, false if lock was not held
561 */
562 Datum
563 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
564 {
565         int64           key = PG_GETARG_INT64(0);
566         LOCKTAG         tag;
567         bool            res;
568
569         SET_LOCKTAG_INT64(tag, key);
570
571         res = LockRelease(&tag, ExclusiveLock, true);
572
573         PG_RETURN_BOOL(res);
574 }
575
576 /*
577  * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
578  *
579  * Returns true if successful, false if lock was not held
580  */
581 Datum
582 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
583 {
584         int64           key = PG_GETARG_INT64(0);
585         LOCKTAG         tag;
586         bool            res;
587
588         SET_LOCKTAG_INT64(tag, key);
589
590         res = LockRelease(&tag, ShareLock, true);
591
592         PG_RETURN_BOOL(res);
593 }
594
595 /*
596  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
597  */
598 Datum
599 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
600 {
601         int32           key1 = PG_GETARG_INT32(0);
602         int32           key2 = PG_GETARG_INT32(1);
603         LOCKTAG         tag;
604
605         SET_LOCKTAG_INT32(tag, key1, key2);
606
607         (void) LockAcquire(&tag, ExclusiveLock, true, false);
608
609         PG_RETURN_VOID();
610 }
611
612 /*
613  * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
614  * exclusive lock on 2 int4 keys
615  */
616 Datum
617 pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
618 {
619         int32           key1 = PG_GETARG_INT32(0);
620         int32           key2 = PG_GETARG_INT32(1);
621         LOCKTAG         tag;
622
623         SET_LOCKTAG_INT32(tag, key1, key2);
624
625         (void) LockAcquire(&tag, ExclusiveLock, false, false);
626
627         PG_RETURN_VOID();
628 }
629
630 /*
631  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
632  */
633 Datum
634 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
635 {
636         int32           key1 = PG_GETARG_INT32(0);
637         int32           key2 = PG_GETARG_INT32(1);
638         LOCKTAG         tag;
639
640         SET_LOCKTAG_INT32(tag, key1, key2);
641
642         (void) LockAcquire(&tag, ShareLock, true, false);
643
644         PG_RETURN_VOID();
645 }
646
647 /*
648  * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
649  * share lock on 2 int4 keys
650  */
651 Datum
652 pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
653 {
654         int32           key1 = PG_GETARG_INT32(0);
655         int32           key2 = PG_GETARG_INT32(1);
656         LOCKTAG         tag;
657
658         SET_LOCKTAG_INT32(tag, key1, key2);
659
660         (void) LockAcquire(&tag, ShareLock, false, false);
661
662         PG_RETURN_VOID();
663 }
664
665 /*
666  * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
667  *
668  * Returns true if successful, false if lock not available
669  */
670 Datum
671 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
672 {
673         int32           key1 = PG_GETARG_INT32(0);
674         int32           key2 = PG_GETARG_INT32(1);
675         LOCKTAG         tag;
676         LockAcquireResult res;
677
678         SET_LOCKTAG_INT32(tag, key1, key2);
679
680         res = LockAcquire(&tag, ExclusiveLock, true, true);
681
682         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
683 }
684
685 /*
686  * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
687  * exclusive lock on 2 int4 keys, no wait
688  *
689  * Returns true if successful, false if lock not available
690  */
691 Datum
692 pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
693 {
694         int32           key1 = PG_GETARG_INT32(0);
695         int32           key2 = PG_GETARG_INT32(1);
696         LOCKTAG         tag;
697         LockAcquireResult res;
698
699         SET_LOCKTAG_INT32(tag, key1, key2);
700
701         res = LockAcquire(&tag, ExclusiveLock, false, true);
702
703         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
704 }
705
706 /*
707  * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
708  *
709  * Returns true if successful, false if lock not available
710  */
711 Datum
712 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
713 {
714         int32           key1 = PG_GETARG_INT32(0);
715         int32           key2 = PG_GETARG_INT32(1);
716         LOCKTAG         tag;
717         LockAcquireResult res;
718
719         SET_LOCKTAG_INT32(tag, key1, key2);
720
721         res = LockAcquire(&tag, ShareLock, true, true);
722
723         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
724 }
725
726 /*
727  * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
728  * share lock on 2 int4 keys, no wait
729  *
730  * Returns true if successful, false if lock not available
731  */
732 Datum
733 pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
734 {
735         int32           key1 = PG_GETARG_INT32(0);
736         int32           key2 = PG_GETARG_INT32(1);
737         LOCKTAG         tag;
738         LockAcquireResult res;
739
740         SET_LOCKTAG_INT32(tag, key1, key2);
741
742         res = LockAcquire(&tag, ShareLock, false, true);
743
744         PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
745 }
746
747 /*
748  * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
749  *
750  * Returns true if successful, false if lock was not held
751 */
752 Datum
753 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
754 {
755         int32           key1 = PG_GETARG_INT32(0);
756         int32           key2 = PG_GETARG_INT32(1);
757         LOCKTAG         tag;
758         bool            res;
759
760         SET_LOCKTAG_INT32(tag, key1, key2);
761
762         res = LockRelease(&tag, ExclusiveLock, true);
763
764         PG_RETURN_BOOL(res);
765 }
766
767 /*
768  * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
769  *
770  * Returns true if successful, false if lock was not held
771  */
772 Datum
773 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
774 {
775         int32           key1 = PG_GETARG_INT32(0);
776         int32           key2 = PG_GETARG_INT32(1);
777         LOCKTAG         tag;
778         bool            res;
779
780         SET_LOCKTAG_INT32(tag, key1, key2);
781
782         res = LockRelease(&tag, ShareLock, true);
783
784         PG_RETURN_BOOL(res);
785 }
786
787 /*
788  * pg_advisory_unlock_all() - release all advisory locks
789  */
790 Datum
791 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
792 {
793         LockReleaseSession(USER_LOCKMETHOD);
794
795         PG_RETURN_VOID();
796 }