aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/storage/lmgr/README11
-rw-r--r--src/backend/storage/lmgr/lock.c101
-rw-r--r--src/backend/storage/lmgr/proc.c5
-rw-r--r--src/backend/utils/adt/lockfuncs.c154
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.h16
-rw-r--r--src/include/storage/lock.h1
-rw-r--r--src/include/utils/builtins.h8
-rw-r--r--src/test/regress/expected/advisory_lock.out275
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/advisory_lock.sql146
12 files changed, 681 insertions, 41 deletions
diff --git a/src/backend/storage/lmgr/README b/src/backend/storage/lmgr/README
index 40779d2e359..87fd312e314 100644
--- a/src/backend/storage/lmgr/README
+++ b/src/backend/storage/lmgr/README
@@ -505,7 +505,7 @@ User Locks
----------
User locks are handled totally on the application side as long term
-cooperative locks which extend beyond the normal transaction boundaries.
+cooperative locks which may extend beyond the normal transaction boundaries.
Their purpose is to indicate to an application that someone is `working'
on an item. So it is possible to put an user lock on a tuple's oid,
retrieve the tuple, work on it for an hour and then update it and remove
@@ -516,9 +516,12 @@ level by someone.
User locks and normal locks are completely orthogonal and they don't
interfere with each other.
-User locks are always held as session locks, so that they are not released at
-transaction end. They must be released explicitly by the application --- but
-they are released automatically when a backend terminates.
+There are two types of user locks: session level and transaction level.
+Session level user locks are not released at transaction end. They must
+be released explicitly by the application --- but they are released
+automatically when a backend terminates. On the other hand, transaction
+level user locks are released automatically at the end of the transaction
+as like as other normal locks.
Locking during Hot Standby
--------------------------
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index cea5096c778..ed0ea1205f4 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -130,7 +130,7 @@ static const LockMethodData default_lockmethod = {
static const LockMethodData user_lockmethod = {
AccessExclusiveLock, /* highest valid lock mode number */
- false,
+ true,
LockConflicts,
lock_mode_names,
#ifdef LOCK_DEBUG
@@ -256,6 +256,7 @@ static uint32 proclock_hash(const void *key, Size keysize);
static void RemoveLocalLock(LOCALLOCK *locallock);
static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
+static void ReleaseLockForOwner(LOCALLOCK *locallock, ResourceOwner owner);
static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
PROCLOCK *proclock, LockMethod lockMethodTable);
static void CleanUpLock(LOCK *lock, PROCLOCK *proclock,
@@ -1484,6 +1485,31 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
}
/*
+ * LockReleaseSession -- Release all session locks of the specified lock method
+ * that are held by the current process.
+ */
+void
+LockReleaseSession(LOCKMETHODID lockmethodid)
+{
+ HASH_SEQ_STATUS status;
+ LOCALLOCK *locallock;
+
+ if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
+ elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+
+ hash_seq_init(&status, LockMethodLocalHash);
+
+ while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
+ {
+ /* Ignore items that are not of the specified lock method */
+ if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
+ continue;
+
+ ReleaseLockForOwner(locallock, NULL);
+ }
+}
+
+/*
* LockReleaseAll -- Release all locks of the specified lock method that
* are held by the current process.
*
@@ -1679,8 +1705,6 @@ LockReleaseCurrentOwner(void)
{
HASH_SEQ_STATUS status;
LOCALLOCK *locallock;
- LOCALLOCKOWNER *lockOwners;
- int i;
hash_seq_init(&status, LockMethodLocalHash);
@@ -1690,38 +1714,51 @@ LockReleaseCurrentOwner(void)
if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
- /* Scan to see if there are any locks belonging to current owner */
- lockOwners = locallock->lockOwners;
- for (i = locallock->numLockOwners - 1; i >= 0; i--)
+ ReleaseLockForOwner(locallock, CurrentResourceOwner);
+ }
+}
+
+/*
+ * Subroutine to release a lock belonging to the 'owner' if found.
+ * 'owner' can be NULL to release a session lock.
+ */
+static void
+ReleaseLockForOwner(LOCALLOCK *locallock, ResourceOwner owner)
+{
+ int i;
+ LOCALLOCKOWNER *lockOwners;
+
+ /* Scan to see if there are any locks belonging to the owner */
+ lockOwners = locallock->lockOwners;
+ for (i = locallock->numLockOwners - 1; i >= 0; i--)
+ {
+ if (lockOwners[i].owner == owner)
{
- if (lockOwners[i].owner == CurrentResourceOwner)
+ Assert(lockOwners[i].nLocks > 0);
+ if (lockOwners[i].nLocks < locallock->nLocks)
{
- Assert(lockOwners[i].nLocks > 0);
- if (lockOwners[i].nLocks < locallock->nLocks)
- {
- /*
- * We will still hold this lock after forgetting this
- * ResourceOwner.
- */
- locallock->nLocks -= lockOwners[i].nLocks;
- /* compact out unused slot */
- locallock->numLockOwners--;
- if (i < locallock->numLockOwners)
- lockOwners[i] = lockOwners[locallock->numLockOwners];
- }
- else
- {
- Assert(lockOwners[i].nLocks == locallock->nLocks);
- /* We want to call LockRelease just once */
- lockOwners[i].nLocks = 1;
- locallock->nLocks = 1;
- if (!LockRelease(&locallock->tag.lock,
- locallock->tag.mode,
- false))
- elog(WARNING, "LockReleaseCurrentOwner: failed??");
- }
- break;
+ /*
+ * We will still hold this lock after forgetting this
+ * ResourceOwner.
+ */
+ locallock->nLocks -= lockOwners[i].nLocks;
+ /* compact out unused slot */
+ locallock->numLockOwners--;
+ if (i < locallock->numLockOwners)
+ lockOwners[i] = lockOwners[locallock->numLockOwners];
+ }
+ else
+ {
+ Assert(lockOwners[i].nLocks == locallock->nLocks);
+ /* We want to call LockRelease just once */
+ lockOwners[i].nLocks = 1;
+ locallock->nLocks = 1;
+ if (!LockRelease(&locallock->tag.lock,
+ locallock->tag.mode,
+ owner == NULL))
+ elog(WARNING, "ReleaseLockForOwner: failed??");
}
+ break;
}
}
}
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index be577bcd5fd..afaf5995f00 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -629,8 +629,6 @@ LockWaitCancel(void)
* At subtransaction abort, we release all locks held by the subtransaction;
* this is implemented by retail releasing of the locks under control of
* the ResourceOwner mechanism.
- *
- * Note that user locks are not released in any case.
*/
void
ProcReleaseLocks(bool isCommit)
@@ -641,6 +639,9 @@ ProcReleaseLocks(bool isCommit)
LockWaitCancel();
/* Release locks */
LockReleaseAll(DEFAULT_LOCKMETHOD, !isCommit);
+
+ /* Release transaction level advisory locks */
+ LockReleaseAll(USER_LOCKMETHOD, false);
}
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 8e369826cec..c6c948ce5e7 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -422,6 +422,23 @@ pg_advisory_lock_int8(PG_FUNCTION_ARGS)
}
/*
+ * pg_advisory_xact_lock(int8) - acquire xact scoped
+ * exclusive lock on an int8 key
+ */
+Datum
+pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ (void) LockAcquire(&tag, ExclusiveLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
+/*
* pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
*/
Datum
@@ -438,6 +455,23 @@ pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
}
/*
+ * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
+ * share lock on an int8 key
+ */
+Datum
+pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ (void) LockAcquire(&tag, ShareLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
+/*
* pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
*
* Returns true if successful, false if lock not available
@@ -457,6 +491,26 @@ pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
}
/*
+ * pg_try_advisory_xact_lock(int8) - acquire xact scoped
+ * exclusive lock on an int8 key, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ res = LockAcquire(&tag, ExclusiveLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
+/*
* pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
*
* Returns true if successful, false if lock not available
@@ -476,6 +530,26 @@ pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
}
/*
+ * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
+ * share lock on an int8 key, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ res = LockAcquire(&tag, ShareLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
+/*
* pg_advisory_unlock(int8) - release exclusive lock on an int8 key
*
* Returns true if successful, false if lock was not held
@@ -531,6 +605,24 @@ pg_advisory_lock_int4(PG_FUNCTION_ARGS)
}
/*
+ * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
+ * exclusive lock on 2 int4 keys
+ */
+Datum
+pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ (void) LockAcquire(&tag, ExclusiveLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
+/*
* pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
*/
Datum
@@ -548,6 +640,24 @@ pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
}
/*
+ * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
+ * share lock on 2 int4 keys
+ */
+Datum
+pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ (void) LockAcquire(&tag, ShareLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
+/*
* pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
*
* Returns true if successful, false if lock not available
@@ -568,6 +678,27 @@ pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
}
/*
+ * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
+ * exclusive lock on 2 int4 keys, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ res = LockAcquire(&tag, ExclusiveLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
+/*
* pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
*
* Returns true if successful, false if lock not available
@@ -588,6 +719,27 @@ pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
}
/*
+ * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
+ * share lock on 2 int4 keys, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ res = LockAcquire(&tag, ShareLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
+/*
* pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
*
* Returns true if successful, false if lock was not held
@@ -633,7 +785,7 @@ pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
Datum
pg_advisory_unlock_all(PG_FUNCTION_ARGS)
{
- LockReleaseAll(USER_LOCKMETHOD, true);
+ LockReleaseSession(USER_LOCKMETHOD);
PG_RETURN_VOID();
}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 7fb33f09e33..1a7be47fab8 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201102171
+#define CATALOG_VERSION_NO 201102181
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 60a2e623f23..b3458ed56eb 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4420,25 +4420,41 @@ DESCR("is contained by");
/* userlock replacements */
DATA(insert OID = 2880 ( pg_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_lock_int8 _null_ _null_ _null_ ));
+DESCR("obtain exclusive a4dvisory lock");
+DATA(insert OID = 3089 ( pg_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_int8 _null_ _null_ _null_ ));
DESCR("obtain exclusive advisory lock");
DATA(insert OID = 2881 ( pg_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_lock_shared_int8 _null_ _null_ _null_ ));
DESCR("obtain shared advisory lock");
+DATA(insert OID = 3090 ( pg_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_shared_int8 _null_ _null_ _null_ ));
+DESCR("obtain shared advisory lock");
DATA(insert OID = 2882 ( pg_try_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_lock_int8 _null_ _null_ _null_ ));
DESCR("obtain exclusive advisory lock if available");
+DATA(insert OID = 3091 ( pg_try_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_int8 _null_ _null_ _null_ ));
+DESCR("obtain exclusive advisory lock if available");
DATA(insert OID = 2883 ( pg_try_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_lock_shared_int8 _null_ _null_ _null_ ));
DESCR("obtain shared advisory lock if available");
+DATA(insert OID = 3092 ( pg_try_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_shared_int8 _null_ _null_ _null_ ));
+DESCR("obtain shared advisory lock if available");
DATA(insert OID = 2884 ( pg_advisory_unlock PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_advisory_unlock_int8 _null_ _null_ _null_ ));
DESCR("release exclusive advisory lock");
DATA(insert OID = 2885 ( pg_advisory_unlock_shared PGNSP PGUID 12 1 0 0 f f f t f v 1 0 16 "20" _null_ _null_ _null_ _null_ pg_advisory_unlock_shared_int8 _null_ _null_ _null_ ));
DESCR("release shared advisory lock");
DATA(insert OID = 2886 ( pg_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_lock_int4 _null_ _null_ _null_ ));
DESCR("obtain exclusive advisory lock");
+DATA(insert OID = 3093 ( pg_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_int4 _null_ _null_ _null_ ));
+DESCR("obtain exclusive advisory lock");
DATA(insert OID = 2887 ( pg_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_lock_shared_int4 _null_ _null_ _null_ ));
DESCR("obtain shared advisory lock");
+DATA(insert OID = 3094 ( pg_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2278 "23 23" _null_ _null_ _null_ _null_ pg_advisory_xact_lock_shared_int4 _null_ _null_ _null_ ));
+DESCR("obtain shared advisory lock");
DATA(insert OID = 2888 ( pg_try_advisory_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_lock_int4 _null_ _null_ _null_ ));
DESCR("obtain exclusive advisory lock if available");
+DATA(insert OID = 3095 ( pg_try_advisory_xact_lock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_int4 _null_ _null_ _null_ ));
+DESCR("obtain exclusive advisory lock if available");
DATA(insert OID = 2889 ( pg_try_advisory_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_lock_shared_int4 _null_ _null_ _null_ ));
DESCR("obtain shared advisory lock if available");
+DATA(insert OID = 3096 ( pg_try_advisory_xact_lock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_try_advisory_xact_lock_shared_int4 _null_ _null_ _null_ ));
+DESCR("obtain shared advisory lock if available");
DATA(insert OID = 2890 ( pg_advisory_unlock PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_advisory_unlock_int4 _null_ _null_ _null_ ));
DESCR("release exclusive advisory lock");
DATA(insert OID = 2891 ( pg_advisory_unlock_shared PGNSP PGUID 12 1 0 0 f f f t f v 2 0 16 "23 23" _null_ _null_ _null_ _null_ pg_advisory_unlock_shared_int4 _null_ _null_ _null_ ));
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 7b52d2e6d16..7ec961f4430 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -484,6 +484,7 @@ extern LockAcquireResult LockAcquireExtended(const LOCKTAG *locktag,
bool report_memory_error);
extern bool LockRelease(const LOCKTAG *locktag,
LOCKMODE lockmode, bool sessionLock);
+extern void LockReleaseSession(LOCKMETHODID lockmethodid);
extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
extern void LockReleaseCurrentOwner(void);
extern void LockReassignCurrentOwner(void);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 4341025d06a..277aec414c3 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -995,15 +995,23 @@ extern Datum show_all_settings(PG_FUNCTION_ARGS);
/* lockfuncs.c */
extern Datum pg_lock_status(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_int8(PG_FUNCTION_ARGS);
+extern Datum pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS);
+extern Datum pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_int8(PG_FUNCTION_ARGS);
+extern Datum pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS);
+extern Datum pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_int4(PG_FUNCTION_ARGS);
+extern Datum pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS);
+extern Datum pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_int4(PG_FUNCTION_ARGS);
+extern Datum pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS);
extern Datum pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS);
+extern Datum pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS);
extern Datum pg_advisory_unlock_all(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/advisory_lock.out b/src/test/regress/expected/advisory_lock.out
new file mode 100644
index 00000000000..2a2df6f7e4b
--- /dev/null
+++ b/src/test/regress/expected/advisory_lock.out
@@ -0,0 +1,275 @@
+--
+-- ADVISORY LOCKS
+--
+BEGIN;
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2);
+ pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock_shared
+-----------------------+------------------------------+-----------------------+------------------------------
+ | | |
+(1 row)
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+-- pg_advisory_unlock_all() shouldn't release xact locks
+SELECT pg_advisory_unlock_all();
+ pg_advisory_unlock_all
+------------------------
+
+(1 row)
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+ count
+-------
+ 4
+(1 row)
+
+-- can't unlock xact locks
+SELECT
+ pg_advisory_unlock(1), pg_advisory_unlock_shared(2),
+ pg_advisory_unlock(1, 1), pg_advisory_unlock_shared(2, 2);
+WARNING: you don't own a lock of type ExclusiveLock
+WARNING: you don't own a lock of type ShareLock
+WARNING: you don't own a lock of type ExclusiveLock
+WARNING: you don't own a lock of type ShareLock
+ pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock | pg_advisory_unlock_shared
+--------------------+---------------------------+--------------------+---------------------------
+ f | f | f | f
+(1 row)
+
+-- automatically release xact locks at commit
+COMMIT;
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+ count
+-------
+ 0
+(1 row)
+
+BEGIN;
+-- holding both session and xact locks on the same objects, xact first
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2);
+ pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock_shared
+-----------------------+------------------------------+-----------------------+------------------------------
+ | | |
+(1 row)
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2);
+ pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock_shared
+------------------+-------------------------+------------------+-------------------------
+ | | |
+(1 row)
+
+ROLLBACK;
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+-- unlocking session locks
+SELECT
+ pg_advisory_unlock(1), pg_advisory_unlock(1),
+ pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2),
+ pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1),
+ pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2);
+WARNING: you don't own a lock of type ExclusiveLock
+WARNING: you don't own a lock of type ShareLock
+WARNING: you don't own a lock of type ExclusiveLock
+WARNING: you don't own a lock of type ShareLock
+ pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared | pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared
+--------------------+--------------------+---------------------------+---------------------------+--------------------+--------------------+---------------------------+---------------------------
+ t | f | t | f | t | f | t | f
+(1 row)
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+ count
+-------
+ 0
+(1 row)
+
+BEGIN;
+-- holding both session and xact locks on the same objects, session first
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2);
+ pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock_shared
+------------------+-------------------------+------------------+-------------------------
+ | | |
+(1 row)
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2);
+ pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock_shared
+-----------------------+------------------------------+-----------------------+------------------------------
+ | | |
+(1 row)
+
+ROLLBACK;
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+-- releasing all session locks
+SELECT pg_advisory_unlock_all();
+ pg_advisory_unlock_all
+------------------------
+
+(1 row)
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+ count
+-------
+ 0
+(1 row)
+
+BEGIN;
+-- grabbing txn locks multiple times
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock(1),
+ pg_advisory_xact_lock_shared(2), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock(1, 1),
+ pg_advisory_xact_lock_shared(2, 2), pg_advisory_xact_lock_shared(2, 2);
+ pg_advisory_xact_lock | pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock_shared | pg_advisory_xact_lock | pg_advisory_xact_lock | pg_advisory_xact_lock_shared | pg_advisory_xact_lock_shared
+-----------------------+-----------------------+------------------------------+------------------------------+-----------------------+-----------------------+------------------------------+------------------------------
+ | | | | | | |
+(1 row)
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+COMMIT;
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+ count
+-------
+ 0
+(1 row)
+
+-- grabbing session locks multiple times
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock(1),
+ pg_advisory_lock_shared(2), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock(1, 1),
+ pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2);
+ pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared
+------------------+------------------+-------------------------+-------------------------+------------------+------------------+-------------------------+-------------------------
+ | | | | | | |
+(1 row)
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+SELECT
+ pg_advisory_unlock(1), pg_advisory_unlock(1),
+ pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2),
+ pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1),
+ pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2);
+ pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared | pg_advisory_unlock | pg_advisory_unlock | pg_advisory_unlock_shared | pg_advisory_unlock_shared
+--------------------+--------------------+---------------------------+---------------------------+--------------------+--------------------+---------------------------+---------------------------
+ t | t | t | t | t | t | t | t
+(1 row)
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+ count
+-------
+ 0
+(1 row)
+
+-- .. and releasing them all at once
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock(1),
+ pg_advisory_lock_shared(2), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock(1, 1),
+ pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2);
+ pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared | pg_advisory_lock | pg_advisory_lock | pg_advisory_lock_shared | pg_advisory_lock_shared
+------------------+------------------+-------------------------+-------------------------+------------------+------------------+-------------------------+-------------------------
+ | | | | | | |
+(1 row)
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+ locktype | classid | objid | objsubid | mode | granted
+----------+---------+-------+----------+---------------+---------
+ advisory | 0 | 1 | 1 | ExclusiveLock | t
+ advisory | 0 | 2 | 1 | ShareLock | t
+ advisory | 1 | 1 | 2 | ExclusiveLock | t
+ advisory | 2 | 2 | 2 | ShareLock | t
+(4 rows)
+
+SELECT pg_advisory_unlock_all();
+ pg_advisory_unlock_all
+------------------------
+
+(1 row)
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+ count
+-------
+ 0
+(1 row)
+
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 3b99e867efe..aa6f6d2ddd8 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -84,7 +84,7 @@ test: rules
# ----------
# Another group of parallel tests
# ----------
-test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps
+test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock
# ----------
# Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index b348f0e1a94..b76b1877a7e 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -105,6 +105,7 @@ test: foreign_data
test: window
test: xmlmap
test: functional_deps
+test: advisory_lock
test: plancache
test: limit
test: plpgsql
diff --git a/src/test/regress/sql/advisory_lock.sql b/src/test/regress/sql/advisory_lock.sql
new file mode 100644
index 00000000000..57c47c0faca
--- /dev/null
+++ b/src/test/regress/sql/advisory_lock.sql
@@ -0,0 +1,146 @@
+--
+-- ADVISORY LOCKS
+--
+
+BEGIN;
+
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2);
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+
+-- pg_advisory_unlock_all() shouldn't release xact locks
+SELECT pg_advisory_unlock_all();
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+
+
+-- can't unlock xact locks
+SELECT
+ pg_advisory_unlock(1), pg_advisory_unlock_shared(2),
+ pg_advisory_unlock(1, 1), pg_advisory_unlock_shared(2, 2);
+
+
+-- automatically release xact locks at commit
+COMMIT;
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+
+
+BEGIN;
+
+-- holding both session and xact locks on the same objects, xact first
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2);
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2);
+
+ROLLBACK;
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+
+-- unlocking session locks
+SELECT
+ pg_advisory_unlock(1), pg_advisory_unlock(1),
+ pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2),
+ pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1),
+ pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2);
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+
+
+BEGIN;
+
+-- holding both session and xact locks on the same objects, session first
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock_shared(2, 2);
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock_shared(2, 2);
+
+ROLLBACK;
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+
+-- releasing all session locks
+SELECT pg_advisory_unlock_all();
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+
+
+BEGIN;
+
+-- grabbing txn locks multiple times
+
+SELECT
+ pg_advisory_xact_lock(1), pg_advisory_xact_lock(1),
+ pg_advisory_xact_lock_shared(2), pg_advisory_xact_lock_shared(2),
+ pg_advisory_xact_lock(1, 1), pg_advisory_xact_lock(1, 1),
+ pg_advisory_xact_lock_shared(2, 2), pg_advisory_xact_lock_shared(2, 2);
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+COMMIT;
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+
+-- grabbing session locks multiple times
+
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock(1),
+ pg_advisory_lock_shared(2), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock(1, 1),
+ pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2);
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+SELECT
+ pg_advisory_unlock(1), pg_advisory_unlock(1),
+ pg_advisory_unlock_shared(2), pg_advisory_unlock_shared(2),
+ pg_advisory_unlock(1, 1), pg_advisory_unlock(1, 1),
+ pg_advisory_unlock_shared(2, 2), pg_advisory_unlock_shared(2, 2);
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';
+
+-- .. and releasing them all at once
+
+SELECT
+ pg_advisory_lock(1), pg_advisory_lock(1),
+ pg_advisory_lock_shared(2), pg_advisory_lock_shared(2),
+ pg_advisory_lock(1, 1), pg_advisory_lock(1, 1),
+ pg_advisory_lock_shared(2, 2), pg_advisory_lock_shared(2, 2);
+
+SELECT locktype, classid, objid, objsubid, mode, granted
+ FROM pg_locks WHERE locktype = 'advisory'
+ ORDER BY classid, objid, objsubid;
+
+SELECT pg_advisory_unlock_all();
+
+SELECT count(*) FROM pg_locks WHERE locktype = 'advisory';