diff -durpN postgresql.1/doc/src/sgml/config.sgml postgresql.2/doc/src/sgml/config.sgml
--- postgresql.1/doc/src/sgml/config.sgml	2012-07-02 19:22:42.141166647 +0200
+++ postgresql.2/doc/src/sgml/config.sgml	2012-07-04 19:22:27.698055231 +0200
@@ -4983,7 +4983,10 @@ COPY postgres_log FROM '/full/path/to/lo
         milliseconds, starting from the time the command arrives at the server
         from the client.  If <varname>log_min_error_statement</> is set to
         <literal>ERROR</> or lower, the statement that timed out will also be
-        logged.  A value of zero (the default) turns this off.
+        logged.  The timeout may happen any time, i.e. while waiting for locks
+        on database objects or in case of a large result set, during data
+        retrieval from the server after all locks were successfully acquired.
+        A value of zero (the default) turns this off.
        </para>
 
        <para>
@@ -4994,6 +4997,60 @@ COPY postgres_log FROM '/full/path/to/lo
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-lock-timeout" xreflabel="lock_timeout">
+      <term><varname>lock_timeout</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>lock_timeout</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Abort any statement that tries to acquire a heavy-weight lock on rows,
+        pages, tables, indices or other objects and the lock(s) has to wait
+        more than the specified number of milliseconds. As opposed to
+        <varname>statement_timeout</>, this timeout (and the error) may only
+        occur while waiting for locks. If <varname>log_min_error_statement</>
+        is set to <literal>ERROR</> or lower, the statement that timed out will
+        also be logged. A value of zero (the default) turns this off.
+       </para>
+
+       <para>
+        Setting <varname>lock_timeout</> in
+        <filename>postgresql.conf</> is not recommended because it
+        affects all sessions.
+       </para>      
+      </listitem>   
+     </varlistentry>
+
+     <varlistentry id="guc-lock-timeout-option" xreflabel="lock_timeout_option">
+      <term><varname>lock_timeout_option</varname> (<type>enum</type>)</term>
+      <indexterm>
+       <primary><varname>lock_timeout_option</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Control the behaviour of <varname>lock_timeout</>. Possible values are
+        'per_lock' and 'per_statement'.
+       </para>
+
+       <para>
+        With 'per_lock' in effect and if the statement involves more than one
+        lock, the timeout applies to every one of them individually, starting
+        from the time the server attempts to lock an object. This makes the
+        statement possibly wait for up to N * <varname>lock_timeout</> time in
+        the worst case where N is the number of locks attempted. This is the
+        default.
+       </para>
+
+       <para>
+        With 'per_statement' in effect, <varname>lock_timeout</> behaves like
+        <varname>statement_timeout</>: the specified timeout applies to all
+        the locks in a cumulative way, starting from the time the command
+        arrives at the server from the client.
+       </para>
+
+      </listitem>   
+     </varlistentry>
+
      <varlistentry id="guc-vacuum-freeze-table-age" xreflabel="vacuum_freeze_table_age">
       <term><varname>vacuum_freeze_table_age</varname> (<type>integer</type>)</term>
       <indexterm>
diff -durpN postgresql.1/doc/src/sgml/ref/lock.sgml postgresql.2/doc/src/sgml/ref/lock.sgml
--- postgresql.1/doc/src/sgml/ref/lock.sgml	2012-04-16 19:57:22.229913063 +0200
+++ postgresql.2/doc/src/sgml/ref/lock.sgml	2012-07-04 19:22:27.699055239 +0200
@@ -39,8 +39,11 @@ LOCK [ TABLE ] [ ONLY ] <replaceable cla
    <literal>NOWAIT</literal> is specified, <command>LOCK
    TABLE</command> does not wait to acquire the desired lock: if it
    cannot be acquired immediately, the command is aborted and an
-   error is emitted.  Once obtained, the lock is held for the
-   remainder of the current transaction.  (There is no <command>UNLOCK
+   error is emitted. If <varname>lock_timeout</varname> is set to a value
+   higher than 0, and the lock cannot be acquired under the specified
+   timeout value in milliseconds, the command is aborted and an error
+   is emitted. Once obtained, the lock is held for the remainder of  
+   the current transaction.  (There is no <command>UNLOCK
    TABLE</command> command; locks are always released at transaction
    end.)
   </para>
diff -durpN postgresql.1/doc/src/sgml/ref/select.sgml postgresql.2/doc/src/sgml/ref/select.sgml
--- postgresql.1/doc/src/sgml/ref/select.sgml	2012-04-16 19:57:22.233913109 +0200
+++ postgresql.2/doc/src/sgml/ref/select.sgml	2012-07-04 19:22:27.701055253 +0200
@@ -1199,6 +1199,14 @@ FOR SHARE [ OF <replaceable class="param
    </para>
 
    <para>
+    If <literal>NOWAIT</> option is not specified and <varname>lock_timeout</varname>
+    is set to a value higher than 0, and the lock or statement (depending on
+    <varname>lock_timeout_option</varname>) needs to wait more than
+    the specified value in milliseconds, the command reports an error after
+    timing out, rather than waiting indefinitely.
+   </para>
+
+   <para>
     If specific tables are named in <literal>FOR UPDATE</literal>
     or <literal>FOR SHARE</literal>,
     then only rows coming from those tables are locked; any other
diff -durpN postgresql.1/src/backend/port/posix_sema.c postgresql.2/src/backend/port/posix_sema.c
--- postgresql.1/src/backend/port/posix_sema.c	2012-04-16 19:57:22.438915489 +0200
+++ postgresql.2/src/backend/port/posix_sema.c	2012-07-04 19:58:32.007070683 +0200
@@ -313,3 +313,32 @@ PGSemaphoreTryLock(PGSemaphore sema)
 
 	return true;
 }
+
+/*
+ * PGSemaphoreTimedLock
+ *
+ * Lock a semaphore (decrement count), blocking if count would be < 0
+ * Return if lock_timeout expired
+ */
+bool
+PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+					TimeoutCondition condition)
+{
+	int			errStatus;
+	bool			timeout;
+
+	do
+	{
+		ImmediateInterruptOK = interruptOK;
+		CHECK_FOR_INTERRUPTS();
+		errStatus = sem_wait(PG_SEM_REF(sema));
+		ImmediateInterruptOK = false;
+		timeout = condition();
+	} while (errStatus < 0 && errno == EINTR && !timeout);
+
+	if (timeout)
+		return false;
+	if (errStatus < 0)
+		elog(FATAL, "sem_wait failed: %m");
+	return true;
+}
diff -durpN postgresql.1/src/backend/port/sysv_sema.c postgresql.2/src/backend/port/sysv_sema.c
--- postgresql.1/src/backend/port/sysv_sema.c	2012-05-14 08:20:56.284830580 +0200
+++ postgresql.2/src/backend/port/sysv_sema.c	2012-07-04 19:58:52.096201131 +0200
@@ -492,3 +492,37 @@ PGSemaphoreTryLock(PGSemaphore sema)
 
 	return true;
 }
+
+/*
+ * PGSemaphoreTimedLock
+ *
+ * Lock a semaphore (decrement count), blocking if count would be < 0
+ * Return if lock_timeout expired
+ */
+bool
+PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+					TimeoutCondition condition)
+{
+	int			errStatus;
+	bool			timeout;
+	struct sembuf sops;
+
+	sops.sem_op = -1;			/* decrement */
+	sops.sem_flg = 0;
+	sops.sem_num = sema->semNum;
+
+	do
+	{
+		ImmediateInterruptOK = interruptOK;
+		CHECK_FOR_INTERRUPTS();
+		errStatus = semop(sema->semId, &sops, 1);
+		ImmediateInterruptOK = false;
+		timeout = condition();
+	} while (errStatus < 0 && errno == EINTR && !timeout);
+
+	if (timeout)
+		return false;
+	if (errStatus < 0)
+		elog(FATAL, "semop(id=%d) failed: %m", sema->semId);
+	return true;
+}
diff -durpN postgresql.1/src/backend/port/win32_sema.c postgresql.2/src/backend/port/win32_sema.c
--- postgresql.1/src/backend/port/win32_sema.c	2012-06-11 06:22:48.137921483 +0200
+++ postgresql.2/src/backend/port/win32_sema.c	2012-07-04 19:59:03.247273158 +0200
@@ -209,3 +209,66 @@ PGSemaphoreTryLock(PGSemaphore sema)
 	/* keep compiler quiet */
 	return false;
 }
+
+/*
+ * PGSemaphoreTimedLock
+ *
+ * Lock a semaphore (decrement count), blocking if count would be < 0.
+ * Serve the interrupt if interruptOK is true.
+ * Return if lock_timeout expired.
+ */
+bool
+PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+					TimeoutCondition condition)
+{
+	DWORD		ret;
+	HANDLE		wh[2];
+	bool		timeout;
+
+	/*
+	 * Note: pgwin32_signal_event should be first to ensure that it will be
+	 * reported when multiple events are set.  We want to guarantee that
+	 * pending signals are serviced.
+	 */
+	wh[0] = pgwin32_signal_event;
+	wh[1] = *sema;
+
+	/*
+	 * As in other implementations of PGSemaphoreLock, we need to check for
+	 * cancel/die interrupts each time through the loop.  But here, there is
+	 * no hidden magic about whether the syscall will internally service a
+	 * signal --- we do that ourselves.
+	 */
+	do
+	{
+		ImmediateInterruptOK = interruptOK;
+		CHECK_FOR_INTERRUPTS();
+
+		ret = WaitForMultipleObjectsEx(2, wh, FALSE, INFINITE, TRUE);
+
+		if (ret == WAIT_OBJECT_0)
+		{
+			/* Signal event is set - we have a signal to deliver */
+			pgwin32_dispatch_queued_signals();
+			errno = EINTR;
+		}
+		else if (ret == WAIT_OBJECT_0 + 1)
+		{
+			/* We got it! */
+			return;
+		}
+		else
+			/* Otherwise we are in trouble */
+			errno = EIDRM;
+
+		ImmediateInterruptOK = false;
+		timeout = condition();
+	} while (errno == EINTR && !timeout);
+
+	if (timeout)
+		return false;
+	if (errno != 0)
+		ereport(FATAL,
+				(errmsg("could not lock semaphore: error code %d", (int) GetLastError())));
+	return true;
+}
diff -durpN postgresql.1/src/backend/postmaster/postmaster.c postgresql.2/src/backend/postmaster/postmaster.c
--- postgresql.1/src/backend/postmaster/postmaster.c	2012-07-04 19:13:03.431407389 +0200
+++ postgresql.2/src/backend/postmaster/postmaster.c	2012-07-04 19:33:56.079492755 +0200
@@ -3371,7 +3371,7 @@ report_fork_failure_to_client(Port *port
  * Do nothing -- just to break out of a sleeping system call.
  * The timeout indicator is set by the signal handler.
  */
-static void
+void
 DummyTimeoutFunction(void)
 {
 	return;
diff -durpN postgresql.1/src/backend/storage/lmgr/lmgr.c postgresql.2/src/backend/storage/lmgr/lmgr.c
--- postgresql.1/src/backend/storage/lmgr/lmgr.c	2012-04-16 19:57:22.459915733 +0200
+++ postgresql.2/src/backend/storage/lmgr/lmgr.c	2012-07-04 19:22:27.704055270 +0200
@@ -19,8 +19,11 @@
 #include "access/transam.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
+#include "catalog/pg_database.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
+#include "utils/lsyscache.h"
+#include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/inval.h"
 
@@ -78,6 +81,21 @@ LockRelationOid(Oid relid, LOCKMODE lock
 
 	res = LockAcquire(&tag, lockmode, false, false);
 
+	if (res == LOCKACQUIRE_NOT_AVAIL)
+	{
+		char	   *relname = get_rel_name(relid);
+		if (relname)
+			ereport(ERROR,
+					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						errmsg("could not obtain lock on relation \"%s\"",
+						relname)));
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						errmsg("could not obtain lock on relation with OID %u",
+						relid)));
+	}
+
 	/*
 	 * Now that we have the lock, check for invalidation messages, so that we
 	 * will update or flush any stale relcache entry before we try to use it.
@@ -174,6 +192,12 @@ LockRelation(Relation relation, LOCKMODE
 
 	res = LockAcquire(&tag, lockmode, false, false);
 
+	if (res == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on relation \"%s\"",
+				RelationGetRelationName(relation))));
+
 	/*
 	 * Now that we have the lock, check for invalidation messages; see notes
 	 * in LockRelationOid.
@@ -251,7 +275,20 @@ LockRelationIdForSession(LockRelId *reli
 
 	SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
 
-	(void) LockAcquire(&tag, lockmode, true, false);
+	if (LockAcquire(&tag, lockmode, true, false) == LOCKACQUIRE_NOT_AVAIL)
+	{
+		char	   *relname = get_rel_name(relid->relId);
+		if (relname)
+			ereport(ERROR,
+					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						errmsg("could not obtain lock on relation \"%s\"",
+						relname)));
+		else
+			ereport(ERROR,
+					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						errmsg("could not obtain lock on relation with OID %u",
+						relid->relId)));
+	}
 }
 
 /*
@@ -286,7 +323,11 @@ LockRelationForExtension(Relation relati
 								relation->rd_lockInfo.lockRelId.dbId,
 								relation->rd_lockInfo.lockRelId.relId);
 
-	(void) LockAcquire(&tag, lockmode, false, false);
+	if (LockAcquire(&tag, lockmode, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on index \"%s\"",
+				RelationGetRelationName(relation))));
 }
 
 /*
@@ -320,7 +361,11 @@ LockPage(Relation relation, BlockNumber
 					 relation->rd_lockInfo.lockRelId.relId,
 					 blkno);
 
-	(void) LockAcquire(&tag, lockmode, false, false);
+	if (LockAcquire(&tag, lockmode, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on page %u of relation \"%s\"",
+				blkno, RelationGetRelationName(relation))));
 }
 
 /*
@@ -376,7 +421,11 @@ LockTuple(Relation relation, ItemPointer
 					  ItemPointerGetBlockNumber(tid),
 					  ItemPointerGetOffsetNumber(tid));
 
-	(void) LockAcquire(&tag, lockmode, false, false);
+	if (LockAcquire(&tag, lockmode, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on row in relation \"%s\"",
+				RelationGetRelationName(relation))));
 }
 
 /*
@@ -430,7 +479,10 @@ XactLockTableInsert(TransactionId xid)
 
 	SET_LOCKTAG_TRANSACTION(tag, xid);
 
-	(void) LockAcquire(&tag, ExclusiveLock, false, false);
+	if (LockAcquire(&tag, ExclusiveLock, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on transaction with ID %u", xid)));
 }
 
 /*
@@ -474,7 +526,10 @@ XactLockTableWait(TransactionId xid)
 
 		SET_LOCKTAG_TRANSACTION(tag, xid);
 
-		(void) LockAcquire(&tag, ShareLock, false, false);
+		if (LockAcquire(&tag, ShareLock, false, false) == LOCKACQUIRE_NOT_AVAIL)
+			ereport(ERROR,
+					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						errmsg("could not obtain lock on transaction with ID %u", xid)));
 
 		LockRelease(&tag, ShareLock, false);
 
@@ -535,7 +590,11 @@ LockDatabaseObject(Oid classid, Oid obji
 					   objid,
 					   objsubid);
 
-	(void) LockAcquire(&tag, lockmode, false, false);
+	if (LockAcquire(&tag, lockmode, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on class:object: %u:%u",
+				classid, objid)));
 
 	/* Make sure syscaches are up-to-date with any changes we waited for */
 	AcceptInvalidationMessages();
@@ -576,7 +635,11 @@ LockSharedObject(Oid classid, Oid objid,
 					   objid,
 					   objsubid);
 
-	(void) LockAcquire(&tag, lockmode, false, false);
+	if (LockAcquire(&tag, lockmode, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on class:object: %u:%u",
+				classid, objid)));
 
 	/* Make sure syscaches are up-to-date with any changes we waited for */
 	AcceptInvalidationMessages();
@@ -618,7 +681,22 @@ LockSharedObjectForSession(Oid classid,
 					   objid,
 					   objsubid);
 
-	(void) LockAcquire(&tag, lockmode, true, false);
+	if (LockAcquire(&tag, lockmode, true, false) == LOCKACQUIRE_NOT_AVAIL)
+		switch(classid)
+		{
+		case DatabaseRelationId:
+			ereport(ERROR,
+					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						errmsg("could not obtain lock on database with ID %u",
+					objid)));
+			break;
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						errmsg("could not obtain lock on class:object: %u:%u",
+					classid, objid)));
+			break;
+		}
 }
 
 /*
diff -durpN postgresql.1/src/backend/storage/lmgr/lock.c postgresql.2/src/backend/storage/lmgr/lock.c
--- postgresql.1/src/backend/storage/lmgr/lock.c	2012-06-26 09:10:21.280759421 +0200
+++ postgresql.2/src/backend/storage/lmgr/lock.c	2012-07-04 19:22:27.707055290 +0200
@@ -344,7 +344,7 @@ static PROCLOCK *SetupLockInTable(LockMe
 static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
 static void BeginStrongLockAcquire(LOCALLOCK *locallock, uint32 fasthashcode);
 static void FinishStrongLockAcquire(void);
-static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
+static int WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
 static void ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock);
 static void LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent);
 static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
@@ -551,7 +551,7 @@ ProcLockHashCode(const PROCLOCKTAG *proc
  *	dontWait: if true, don't wait to acquire lock
  *
  * Returns one of:
- *		LOCKACQUIRE_NOT_AVAIL		lock not available, and dontWait=true
+ *		LOCKACQUIRE_NOT_AVAIL		lock not available, either dontWait=true or timeout
  *		LOCKACQUIRE_OK				lock successfully acquired
  *		LOCKACQUIRE_ALREADY_HELD	incremented count for lock already held
  *
@@ -865,7 +865,7 @@ LockAcquireExtended(const LOCKTAG *lockt
 										 locktag->locktag_type,
 										 lockmode);
 
-		WaitOnLock(locallock, owner);
+		status = WaitOnLock(locallock, owner);
 
 		TRACE_POSTGRESQL_LOCK_WAIT_DONE(locktag->locktag_field1,
 										locktag->locktag_field2,
@@ -880,28 +880,51 @@ LockAcquireExtended(const LOCKTAG *lockt
 		 * done when the lock was granted to us --- see notes in WaitOnLock.
 		 */
 
-		/*
-		 * Check the proclock entry status, in case something in the ipc
-		 * communication doesn't work correctly.
-		 */
-		if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
+		switch (status)
 		{
-			AbortStrongLockAcquire();
-			PROCLOCK_PRINT("LockAcquire: INCONSISTENT", proclock);
-			LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
-			/* Should we retry ? */
-			LWLockRelease(partitionLock);
-			elog(ERROR, "LockAcquire failed");
+		case STATUS_OK:
+			/*
+			 * Check the proclock entry status, in case something in the ipc
+			 * communication doesn't work correctly.
+			 */
+			if (!(proclock->holdMask & LOCKBIT_ON(lockmode)))
+			{
+				AbortStrongLockAcquire();
+				PROCLOCK_PRINT("LockAcquire: INCONSISTENT", proclock);
+				LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
+				/* Should we retry ? */
+				LWLockRelease(partitionLock);
+				elog(ERROR, "LockAcquire failed");
+			}
+			PROCLOCK_PRINT("LockAcquire: granted", proclock);
+			LOCK_PRINT("LockAcquire: granted", lock, lockmode);
+			break;
+		case STATUS_WAITING:
+			PROCLOCK_PRINT("LockAcquire: timed out", proclock);
+			LOCK_PRINT("LockAcquire: timed out", lock, lockmode);
+			break;
+		default:
+			elog(ERROR, "LockAcquire invalid status");
+			break;
 		}
-		PROCLOCK_PRINT("LockAcquire: granted", proclock);
-		LOCK_PRINT("LockAcquire: granted", lock, lockmode);
 	}
 
-	/*
-	 * Lock state is fully up-to-date now; if we error out after this, no
-	 * special error cleanup is required.
-	 */
-	FinishStrongLockAcquire();
+	if (status == STATUS_WAITING)
+	{
+		/*
+		 * lock_timeout was set and WaitOnLock() indicated
+		 * we timed out. Clean up manually.
+		 */
+		AbortStrongLockAcquire();
+	}
+	else
+	{
+		/*
+		 * Lock state is fully up-to-date now; if we error out after this, no
+		 * special error cleanup is required.
+		 */
+		FinishStrongLockAcquire();
+	}
 
 	LWLockRelease(partitionLock);
 
@@ -920,7 +943,7 @@ LockAcquireExtended(const LOCKTAG *lockt
 							   locktag->locktag_field2);
 	}
 
-	return LOCKACQUIRE_OK;
+	return (status == STATUS_OK ? LOCKACQUIRE_OK : LOCKACQUIRE_NOT_AVAIL);
 }
 
 /*
@@ -1450,14 +1473,20 @@ GrantAwaitedLock(void)
  * Caller must have set MyProc->heldLocks to reflect locks already held
  * on the lockable object by this process.
  *
+ * Result: returns value of ProcSleep()
+ *	STATUS_OK if we acquired the lock
+ *	STATUS_ERROR if not (deadlock)
+ *	STATUS_WAITING if not (timeout)
+ *
  * The appropriate partition lock must be held at entry.
  */
-static void
+static int
 WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
 {
 	LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
 	LockMethod	lockMethodTable = LockMethods[lockmethodid];
 	char	   *volatile new_status = NULL;
+	int		wait_status;
 
 	LOCK_PRINT("WaitOnLock: sleeping on lock",
 			   locallock->lock, locallock->tag.mode);
@@ -1499,8 +1528,13 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
 	 */
 	PG_TRY();
 	{
-		if (ProcSleep(locallock, lockMethodTable) != STATUS_OK)
+		wait_status = ProcSleep(locallock, lockMethodTable);
+		switch (wait_status)
 		{
+		case STATUS_OK:
+		case STATUS_WAITING:
+			break;
+		default:
 			/*
 			 * We failed as a result of a deadlock, see CheckDeadLock(). Quit
 			 * now.
@@ -1545,8 +1579,14 @@ WaitOnLock(LOCALLOCK *locallock, Resourc
 		pfree(new_status);
 	}
 
-	LOCK_PRINT("WaitOnLock: wakeup on lock",
+	if (wait_status == STATUS_OK)
+		LOCK_PRINT("WaitOnLock: wakeup on lock",
+			   locallock->lock, locallock->tag.mode);
+	else if (wait_status == STATUS_WAITING)
+		LOCK_PRINT("WaitOnLock: timeout on lock",
 			   locallock->lock, locallock->tag.mode);
+
+	return wait_status;
 }
 
 /*
@@ -3910,7 +3950,11 @@ VirtualXactLock(VirtualTransactionId vxi
 	LWLockRelease(proc->backendLock);
 
 	/* Time to wait. */
-	(void) LockAcquire(&tag, ShareLock, false, false);
+	if (LockAcquire(&tag, ShareLock, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain lock on virtual transaction with ID %u",
+				vxid.localTransactionId)));
 
 	LockRelease(&tag, ShareLock, false);
 	return true;
diff -durpN postgresql.1/src/backend/storage/lmgr/proc.c postgresql.2/src/backend/storage/lmgr/proc.c
--- postgresql.1/src/backend/storage/lmgr/proc.c	2012-07-04 11:01:15.338090598 +0200
+++ postgresql.2/src/backend/storage/lmgr/proc.c	2012-07-04 20:27:00.930150003 +0200
@@ -55,6 +55,8 @@
 /* GUC variables */
 int			DeadlockTimeout = 1000;
 int			StatementTimeout = 0;
+int			LockTimeout = 0;
+int			LockTimeoutOption = LOCK_TIMEOUT_PER_LOCK;
 bool		log_lock_waits = false;
 
 /* Pointer to this process's PGPROC and PGXACT structs, if any */
@@ -638,8 +640,12 @@ LockErrorCleanup(void)
 	if (lockAwaited == NULL)
 		return;
 
-	/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
+	/*
+	 * Turn off the deadlock and lock timeout timers,
+	 * if they are still running (see ProcSleep)
+	 */
 	disable_timeout(DEADLOCK_TIMEOUT, false);
+	disable_timeout(LOCK_TIMEOUT, false);
 
 	/* Unlink myself from the wait queue, if on it (might not be anymore!) */
 	partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
@@ -865,6 +871,14 @@ ProcQueueInit(PROC_QUEUE *queue)
 	queue->size = 0;
 }
 
+/*
+ * LockTimeoutIndicator -- passed to PGSemaphoreTimedLock()
+ */
+static bool
+LockTimeoutIndicator(void)
+{
+	return get_timeout_indicator(LOCK_TIMEOUT);
+}
 
 /*
  * ProcSleep -- put a process to sleep on the specified lock
@@ -875,7 +889,10 @@ ProcQueueInit(PROC_QUEUE *queue)
  * The lock table's partition lock must be held at entry, and will be held
  * at exit.
  *
- * Result: STATUS_OK if we acquired the lock, STATUS_ERROR if not (deadlock).
+ * Result:
+ *	STATUS_OK if we acquired the lock
+ *	STATUS_ERROR if not (deadlock)
+ *	STATUS_WAITING if not (timeout)
  *
  * ASSUME: that no one will fiddle with the queue until after
  *		we release the partition lock.
@@ -897,6 +914,7 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	LOCKMASK	myHeldLocks = MyProc->heldLocks;
 	bool		early_deadlock = false;
 	bool		allow_autovacuum_cancel = true;
+	bool		timeout_detected = false;
 	int			myWaitStatus;
 	PGPROC	   *proc;
 	int			i;
@@ -1037,8 +1055,13 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	enable_timeout(DEADLOCK_TIMEOUT, DeadlockTimeout);
 
 	/*
-	 * If someone wakes us between LWLockRelease and PGSemaphoreLock,
-	 * PGSemaphoreLock will not block.	The wakeup is "saved" by the semaphore
+	 * Queue the timer for lock timeout, too.
+	 */
+	enable_timeout(LOCK_TIMEOUT, LockTimeout);
+
+	/*
+	 * If someone wakes us between LWLockRelease and PGSemaphoreTimedLock,
+	 * PGSemaphoreTimedLock will not block.	The wakeup is "saved" by the semaphore
 	 * implementation.	While this is normally good, there are cases where a
 	 * saved wakeup might be leftover from a previous operation (for example,
 	 * we aborted ProcWaitForSignal just before someone did ProcSendSignal).
@@ -1055,7 +1078,11 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	 */
 	do
 	{
-		PGSemaphoreLock(&MyProc->sem, true);
+		/* Check and keep the lock timeout indicator for later checks */
+		timeout_detected = !PGSemaphoreTimedLock(&MyProc->sem, true,
+								LockTimeoutIndicator);
+		if (timeout_detected)
+			break;
 
 		/*
 		 * waitStatus could change from STATUS_WAITING to something else
@@ -1184,9 +1211,10 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	} while (myWaitStatus == STATUS_WAITING);
 
 	/*
-	 * Disable the timer, if it's still running
+	 * Disable the timers, if they are still running
 	 */
 	disable_timeout(DEADLOCK_TIMEOUT, false);
+	disable_timeout(LOCK_TIMEOUT, false);
 
 	/*
 	 * Re-acquire the lock table's partition lock.  We have to do this to hold
@@ -1196,6 +1224,15 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
 	/*
+	 * If we're in timeout, so:
+	 *	1. we're not waiting anymore and
+	 *	2. we're not the one that the lock will be granted to,
+	 * remove ourselves from the wait queue.
+	 */
+	if (timeout_detected)
+		RemoveFromWaitQueue(MyProc, hashcode);
+
+	/*
 	 * We no longer want LockErrorCleanup to do anything.
 	 */
 	lockAwaited = NULL;
@@ -1209,8 +1246,10 @@ ProcSleep(LOCALLOCK *locallock, LockMeth
 	/*
 	 * We don't have to do anything else, because the awaker did all the
 	 * necessary update of the lock table and MyProc.
+	 * RemoveFromWaitQueue() have set MyProc->waitStatus = STATUS_ERROR,
+	 * we need to distinguish this case.
 	 */
-	return MyProc->waitStatus;
+	return (timeout_detected ? STATUS_WAITING : MyProc->waitStatus);
 }
 
 
diff -durpN postgresql.1/src/backend/tcop/postgres.c postgresql.2/src/backend/tcop/postgres.c
--- postgresql.1/src/backend/tcop/postgres.c	2012-07-04 19:14:55.314126731 +0200
+++ postgresql.2/src/backend/tcop/postgres.c	2012-07-04 19:28:08.972258779 +0200
@@ -3497,6 +3497,29 @@ process_postgres_switches(int argc, char
 	return dbname;
 }
 
+/*
+ * GetLockTimeoutStart
+ *
+ * Depending on lock_timeout_option, return either the current time
+ * ('per_lock') or the statement start time ('per_statement').
+ */
+static TimestampTz GetLockTimeoutStart(void)
+{
+	switch (LockTimeoutOption)
+	{
+		case LOCK_TIMEOUT_PER_LOCK:
+			return GetCurrentTimestamp();
+		case LOCK_TIMEOUT_PER_STMT:
+			return GetCurrentStatementStartTimestamp();
+		default:
+			elog(ERROR, "unhandled lock_timeout_option value: \"%s\"",
+						GetConfigOptionByName("lock_timeout_option", NULL));
+			break;
+	}
+	/* Silence possible warnings. */
+	return 0;
+}
+
 
 /* ----------------------------------------------------------------
  * PostgresMain
@@ -3610,6 +3633,9 @@ PostgresMain(int argc, char *argv[], con
 		InitializeTimeouts();
 		RegisterTimeout(DEADLOCK_TIMEOUT, true,
 						CheckDeadLock, GetCurrentTimestamp);
+		RegisterTimeout(LOCK_TIMEOUT, false,
+						DummyTimeoutFunction,
+						GetLockTimeoutStart);
 		RegisterTimeout(STATEMENT_TIMEOUT, false,
 						StatementTimeoutHandler,
 						GetCurrentStatementStartTimestamp);
diff -durpN postgresql.1/src/backend/utils/adt/lockfuncs.c postgresql.2/src/backend/utils/adt/lockfuncs.c
--- postgresql.1/src/backend/utils/adt/lockfuncs.c	2012-06-11 06:22:48.162921604 +0200
+++ postgresql.2/src/backend/utils/adt/lockfuncs.c	2012-07-04 19:22:27.710055311 +0200
@@ -421,7 +421,11 @@ pg_advisory_lock_int8(PG_FUNCTION_ARGS)
 
 	SET_LOCKTAG_INT64(tag, key);
 
-	(void) LockAcquire(&tag, ExclusiveLock, true, false);
+	if (LockAcquire(&tag, ExclusiveLock, true, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain exclusive advisory lock on value %llu",
+								(long long)key)));
 
 	PG_RETURN_VOID();
 }
@@ -438,7 +442,11 @@ pg_advisory_xact_lock_int8(PG_FUNCTION_A
 
 	SET_LOCKTAG_INT64(tag, key);
 
-	(void) LockAcquire(&tag, ExclusiveLock, false, false);
+	if (LockAcquire(&tag, ExclusiveLock, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain exclusive advisory lock on value %llu",
+								(long long)key)));
 
 	PG_RETURN_VOID();
 }
@@ -454,7 +462,11 @@ pg_advisory_lock_shared_int8(PG_FUNCTION
 
 	SET_LOCKTAG_INT64(tag, key);
 
-	(void) LockAcquire(&tag, ShareLock, true, false);
+	if (LockAcquire(&tag, ShareLock, true, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain shared advisory lock on value %llu",
+								(long long)key)));
 
 	PG_RETURN_VOID();
 }
@@ -471,7 +483,11 @@ pg_advisory_xact_lock_shared_int8(PG_FUN
 
 	SET_LOCKTAG_INT64(tag, key);
 
-	(void) LockAcquire(&tag, ShareLock, false, false);
+	if (LockAcquire(&tag, ShareLock, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain shared advisory lock on value %llu",
+								(long long)key)));
 
 	PG_RETURN_VOID();
 }
@@ -604,7 +620,11 @@ pg_advisory_lock_int4(PG_FUNCTION_ARGS)
 
 	SET_LOCKTAG_INT32(tag, key1, key2);
 
-	(void) LockAcquire(&tag, ExclusiveLock, true, false);
+	if (LockAcquire(&tag, ExclusiveLock, true, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain exclusive advisory lock on values %u:%u",
+								key1, key2)));
 
 	PG_RETURN_VOID();
 }
@@ -622,7 +642,11 @@ pg_advisory_xact_lock_int4(PG_FUNCTION_A
 
 	SET_LOCKTAG_INT32(tag, key1, key2);
 
-	(void) LockAcquire(&tag, ExclusiveLock, false, false);
+	if (LockAcquire(&tag, ExclusiveLock, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain exclusive advisory lock on values %u:%u",
+								key1, key2)));
 
 	PG_RETURN_VOID();
 }
@@ -639,7 +663,11 @@ pg_advisory_lock_shared_int4(PG_FUNCTION
 
 	SET_LOCKTAG_INT32(tag, key1, key2);
 
-	(void) LockAcquire(&tag, ShareLock, true, false);
+	if (LockAcquire(&tag, ShareLock, true, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain shared advisory lock on values %u:%u",
+								key1, key2)));
 
 	PG_RETURN_VOID();
 }
@@ -657,7 +685,11 @@ pg_advisory_xact_lock_shared_int4(PG_FUN
 
 	SET_LOCKTAG_INT32(tag, key1, key2);
 
-	(void) LockAcquire(&tag, ShareLock, false, false);
+	if (LockAcquire(&tag, ShareLock, false, false) == LOCKACQUIRE_NOT_AVAIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					errmsg("could not obtain shared advisory lock on values %u:%u",
+								key1, key2)));
 
 	PG_RETURN_VOID();
 }
diff -durpN postgresql.1/src/backend/utils/misc/guc.c postgresql.2/src/backend/utils/misc/guc.c
--- postgresql.1/src/backend/utils/misc/guc.c	2012-07-03 13:50:11.725151648 +0200
+++ postgresql.2/src/backend/utils/misc/guc.c	2012-07-04 19:22:27.715055342 +0200
@@ -389,6 +389,17 @@ static const struct config_enum_entry sy
 };
 
 /*
+ * Control behaviour of lock_timeout:
+ * - timeout applied per lock from the time the lock is attempted to be taken
+ * - timeout applied per statement from the time the statements has started
+ */
+static const struct config_enum_entry lock_timeout_options[] = {
+	{"per_lock", LOCK_TIMEOUT_PER_LOCK, false},
+	{"per_statement", LOCK_TIMEOUT_PER_STMT, false},
+	{NULL, 0, false}
+};
+
+/*
  * Options for enum values stored in other modules
  */
 extern const struct config_enum_entry wal_level_options[];
@@ -1861,6 +1872,17 @@ static struct config_int ConfigureNamesI
 	},
 
 	{
+		{"lock_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("Sets the maximum allowed timeout for any lock taken by a statement."),
+			gettext_noop("A value of 0 turns off the timeout."),
+			GUC_UNIT_MS
+		},
+		&LockTimeout,
+		0, 0, INT_MAX,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
 			gettext_noop("Minimum age at which VACUUM should freeze a table row."),
 			NULL
@@ -3141,6 +3163,16 @@ static struct config_enum ConfigureNames
 		NULL, NULL, NULL
 	},
 
+	{
+		{"lock_timeout_option", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("Sets the lock_timeout behaviour."),
+			NULL
+		},
+		&LockTimeoutOption,
+		LOCK_TIMEOUT_PER_LOCK, lock_timeout_options,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"log_error_verbosity", PGC_SUSET, LOGGING_WHAT,
 			gettext_noop("Sets the verbosity of logged messages."),
diff -durpN postgresql.1/src/backend/utils/misc/postgresql.conf.sample postgresql.2/src/backend/utils/misc/postgresql.conf.sample
--- postgresql.1/src/backend/utils/misc/postgresql.conf.sample	2012-05-14 08:20:56.298830662 +0200
+++ postgresql.2/src/backend/utils/misc/postgresql.conf.sample	2012-07-04 19:22:27.716055349 +0200
@@ -528,6 +528,11 @@
 #------------------------------------------------------------------------------
 
 #deadlock_timeout = 1s
+#lock_timeout = 0			# timeout value for heavy-weight locks
+					# taken by statements. 0 disables timeout
+					# unit in milliseconds, default is 0
+#lock_timeout_option = 'per_lock'	# behaviour of lock_timeout. possible
+					# values are: 'per_lock' or 'per_statement'
 #max_locks_per_transaction = 64		# min 10
 					# (change requires restart)
 # Note:  Each lock table slot uses ~270 bytes of shared memory, and there are
diff -durpN postgresql.1/src/include/postmaster/postmaster.h postgresql.2/src/include/postmaster/postmaster.h
--- postgresql.1/src/include/postmaster/postmaster.h	2012-06-26 09:10:21.315759713 +0200
+++ postgresql.2/src/include/postmaster/postmaster.h	2012-07-04 19:32:47.765054159 +0200
@@ -51,6 +51,8 @@ extern void ClosePostmasterPorts(bool am
 
 extern int	MaxLivePostmasterChildren(void);
 
+extern void	DummyTimeoutFunction(void);
+
 #ifdef EXEC_BACKEND
 extern pid_t postmaster_forkexec(int argc, char *argv[]);
 extern void	SubPostmasterMain(int argc, char *argv[]) __attribute__((noreturn));
diff -durpN postgresql.1/src/include/storage/pg_sema.h postgresql.2/src/include/storage/pg_sema.h
--- postgresql.1/src/include/storage/pg_sema.h	2012-04-16 19:57:22.672918205 +0200
+++ postgresql.2/src/include/storage/pg_sema.h	2012-07-04 19:38:46.001352598 +0200
@@ -61,6 +61,7 @@ typedef HANDLE PGSemaphoreData;
 
 typedef PGSemaphoreData *PGSemaphore;
 
+typedef bool (*TimeoutCondition)(void);
 
 /* Module initialization (called during postmaster start or shmem reinit) */
 extern void PGReserveSemaphores(int maxSemas, int port);
@@ -80,4 +81,11 @@ extern void PGSemaphoreUnlock(PGSemaphor
 /* Lock a semaphore only if able to do so without blocking */
 extern bool PGSemaphoreTryLock(PGSemaphore sema);
 
+/*
+ * Lock a semaphore (decrement count), blocking for at most
+ * "lock_timeout" milliseconds if count would be < 0
+ */
+extern bool PGSemaphoreTimedLock(PGSemaphore sema, bool interruptOK,
+						TimeoutCondition condition);
+
 #endif   /* PG_SEMA_H */
diff -durpN postgresql.1/src/include/storage/proc.h postgresql.2/src/include/storage/proc.h
--- postgresql.1/src/include/storage/proc.h	2012-07-04 11:01:15.344090637 +0200
+++ postgresql.2/src/include/storage/proc.h	2012-07-04 19:22:27.717055355 +0200
@@ -220,8 +220,15 @@ extern PGPROC *PreparedXactProcs;
 /* configurable options */
 extern int	DeadlockTimeout;
 extern int	StatementTimeout;
+extern int	LockTimeout;
+extern int	LockTimeoutOption;
 extern bool log_lock_waits;
 
+typedef enum LockTimeoutOptions {
+	LOCK_TIMEOUT_PER_LOCK,
+	LOCK_TIMEOUT_PER_STMT
+} LockTimeoutOptions;
+
 /*
  * Function Prototypes
  */
diff -durpN postgresql.1/src/include/storage/timeout.h postgresql.2/src/include/storage/timeout.h
--- postgresql.1/src/include/storage/timeout.h	2012-07-04 11:01:15.344090637 +0200
+++ postgresql.2/src/include/storage/timeout.h	2012-07-04 19:22:27.718055361 +0200
@@ -20,6 +20,7 @@ typedef enum TimeoutName
 {
 	AUTHENTICATION_TIMEOUT,
 	DEADLOCK_TIMEOUT,
+	LOCK_TIMEOUT,
 	STATEMENT_TIMEOUT,
 	STANDBY_DEADLOCK_TIMEOUT,
 	STANDBY_TIMEOUT,
diff -durpN postgresql.1/src/test/regress/expected/prepared_xacts.out postgresql.2/src/test/regress/expected/prepared_xacts.out
--- postgresql.1/src/test/regress/expected/prepared_xacts.out	2012-04-16 19:57:22.776919413 +0200
+++ postgresql.2/src/test/regress/expected/prepared_xacts.out	2012-07-04 19:22:27.718055361 +0200
@@ -198,6 +198,26 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 ERROR:  canceling statement due to statement timeout
 reset statement_timeout;
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+ERROR:  could not obtain lock on relation "pxtest3"
+LINE 1: SELECT * FROM pxtest3;
+                      ^
+reset lock_timeout;
+-- Test lock_timeout_option = 'per_statement' and see that lock_timeout
+-- triggers instead of statement_timeout if both are set.
+-- pxtest3 should be locked because of the pending DROP
+set statement_timeout to 2000;
+set lock_timeout to 2000;
+set lock_timeout_option to 'per_statement';
+SELECT * FROM pxtest3;
+ERROR:  could not obtain lock on relation "pxtest3"
+LINE 1: SELECT * FROM pxtest3;
+                      ^
+reset lock_timeout;
+reset statement_timeout;
+reset lock_timeout_option;
 -- Disconnect, we will continue testing in a different backend
 \c -
 -- There should still be two prepared transactions
@@ -213,6 +233,13 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 ERROR:  canceling statement due to statement timeout
 reset statement_timeout;
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+ERROR:  could not obtain lock on relation "pxtest3"
+LINE 1: SELECT * FROM pxtest3;
+                      ^
+reset lock_timeout;
 -- Commit table creation
 COMMIT PREPARED 'regress-one';
 \d pxtest2
diff -durpN postgresql.1/src/test/regress/sql/prepared_xacts.sql postgresql.2/src/test/regress/sql/prepared_xacts.sql
--- postgresql.1/src/test/regress/sql/prepared_xacts.sql	2012-04-16 19:57:22.796919644 +0200
+++ postgresql.2/src/test/regress/sql/prepared_xacts.sql	2012-07-04 19:22:27.719055368 +0200
@@ -126,6 +126,22 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 reset statement_timeout;
 
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+reset lock_timeout;
+
+-- Test lock_timeout_option = 'per_statement' and see that lock_timeout
+-- triggers instead of statement_timeout if both are set.
+-- pxtest3 should be locked because of the pending DROP
+set statement_timeout to 2000;
+set lock_timeout to 2000;
+set lock_timeout_option to 'per_statement';
+SELECT * FROM pxtest3;
+reset lock_timeout;
+reset statement_timeout;
+reset lock_timeout_option;
+
 -- Disconnect, we will continue testing in a different backend
 \c -
 
@@ -137,6 +153,11 @@ set statement_timeout to 2000;
 SELECT * FROM pxtest3;
 reset statement_timeout;
 
+-- pxtest3 should be locked because of the pending DROP
+set lock_timeout to 2000;
+SELECT * FROM pxtest3;
+reset lock_timeout;
+
 -- Commit table creation
 COMMIT PREPARED 'regress-one';
 \d pxtest2
