diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 43af0c7e04875c02a8f8fb70da0864c2a12e9be2..272fb32c58f232456878e20b0a53ed6779b95a21 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.274 2009/01/20 18:59:36 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.275 2009/05/12 16:43:32 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -947,56 +947,6 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
 	return r;
 }
 
-/* ----------------
- *		relation_open_nowait - open but don't wait for lock
- *
- *		Same as relation_open, except throw an error instead of waiting
- *		when the requested lock is not immediately obtainable.
- * ----------------
- */
-Relation
-relation_open_nowait(Oid relationId, LOCKMODE lockmode)
-{
-	Relation	r;
-
-	Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
-
-	/* Get the lock before trying to open the relcache entry */
-	if (lockmode != NoLock)
-	{
-		if (!ConditionalLockRelationOid(relationId, lockmode))
-		{
-			/* try to throw error by name; relation could be deleted... */
-			char	   *relname = get_rel_name(relationId);
-
-			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",
-							 relationId)));
-		}
-	}
-
-	/* The relcache does all the real work... */
-	r = RelationIdGetRelation(relationId);
-
-	if (!RelationIsValid(r))
-		elog(ERROR, "could not open relation with OID %u", relationId);
-
-	/* Make note that we've accessed a temporary relation */
-	if (r->rd_istemp)
-		MyXactAccessedTempRel = true;
-
-	pgstat_initstats(r);
-
-	return r;
-}
-
 /* ----------------
  *		relation_openrv - open any relation specified by a RangeVar
  *
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index 84b152a20075851e212b61b7608bcc13d7db6d5b..1e9b5dd961a110e271289487292f63b6acaa34a0 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -1,14 +1,14 @@
 /*-------------------------------------------------------------------------
  *
  * lockcmds.c
- *	  Lock command support code
+ *	  LOCK command support code
  *
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.23 2009/05/12 03:11:01 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.24 2009/05/12 16:43:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,9 +20,12 @@
 #include "commands/lockcmds.h"
 #include "miscadmin.h"
 #include "parser/parse_clause.h"
+#include "storage/lmgr.h"
 #include "utils/acl.h"
 #include "utils/lsyscache.h"
-#include "utils/rel.h"
+
+static void LockTableRecurse(Oid reloid, RangeVar *rv,
+							 LOCKMODE lockmode, bool nowait, bool recurse);
 
 
 /*
@@ -34,57 +37,127 @@ LockTableCommand(LockStmt *lockstmt)
 	ListCell   *p;
 
 	/*
-	 * Iterate over the list and open, lock, and close the relations one at a
-	 * time
+	 * Iterate over the list and process the named relations one at a time
 	 */
-
 	foreach(p, lockstmt->relations)
 	{
-		RangeVar   *relation = lfirst(p);
-		Oid			reloid;
+		RangeVar   *relation = (RangeVar *) lfirst(p);
 		bool		recurse = interpretInhOption(relation->inhOpt);
-		List	   *children_and_self;
-		ListCell   *child;
+		Oid			reloid;
 
 		reloid = RangeVarGetRelid(relation, false);
 
-		/* XXX NoLock here is not really a good idea */
-		if (recurse)
-			children_and_self = find_all_inheritors(reloid, NoLock);
-		else
-			children_and_self = list_make1_oid(reloid);
+		LockTableRecurse(reloid, relation,
+						 lockstmt->mode, lockstmt->nowait, recurse);
+	}
+}
 
-		foreach(child, children_and_self)
+/*
+ * Apply LOCK TABLE recursively over an inheritance tree
+ *
+ * At top level, "rv" is the original command argument; we use it to throw
+ * an appropriate error message if the relation isn't there.  Below top level,
+ * "rv" is NULL and we should just silently ignore any dropped child rel.
+ */
+static void
+LockTableRecurse(Oid reloid, RangeVar *rv,
+				 LOCKMODE lockmode, bool nowait, bool recurse)
+{
+	Relation	rel;
+	AclResult	aclresult;
+
+	/*
+	 * Acquire the lock.  We must do this first to protect against
+	 * concurrent drops.  Note that a lock against an already-dropped
+	 * relation's OID won't fail.
+	 */
+	if (nowait)
+	{
+		if (!ConditionalLockRelationOid(reloid, lockmode))
 		{
-			Oid			childreloid = lfirst_oid(child);
-			Relation	rel;
-			AclResult	aclresult;
-
-			/* We don't want to open the relation until we've checked privilege. */
-			if (lockstmt->mode == AccessShareLock)
-				aclresult = pg_class_aclcheck(childreloid, GetUserId(),
-											  ACL_SELECT);
+			/* try to throw error by name; relation could be deleted... */
+			char	   *relname = rv ? rv->relname : get_rel_name(reloid);
+
+			if (relname)
+				ereport(ERROR,
+						(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+						 errmsg("could not obtain lock on relation \"%s\"",
+								relname)));
 			else
-				aclresult = pg_class_aclcheck(childreloid, GetUserId(),
-											  ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
+				ereport(ERROR,
+						(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
+					  errmsg("could not obtain lock on relation with OID %u",
+							 reloid)));
+		}
+	}
+	else
+		LockRelationOid(reloid, lockmode);
 
-			if (aclresult != ACLCHECK_OK)
-				aclcheck_error(aclresult, ACL_KIND_CLASS,
-							   get_rel_name(childreloid));
+	/*
+	 * Now that we have the lock, check to see if the relation really exists
+	 * or not.
+	 */
+	rel = try_relation_open(reloid, NoLock);
 
-			if (lockstmt->nowait)
-				rel = relation_open_nowait(childreloid, lockstmt->mode);
-			else
-				rel = relation_open(childreloid, lockstmt->mode);
+	if (!rel)
+	{
+		/* Release useless lock */
+		UnlockRelationOid(reloid, lockmode);
 
-			/* Currently, we only allow plain tables to be locked */
-			if (rel->rd_rel->relkind != RELKIND_RELATION)
+		/* At top level, throw error; otherwise, ignore this child rel */
+		if (rv)
+		{
+			if (rv->schemaname)
 				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table",
-								get_rel_name(childreloid))));
+						(errcode(ERRCODE_UNDEFINED_TABLE),
+						 errmsg("relation \"%s.%s\" does not exist",
+								rv->schemaname, rv->relname)));
+			else
+				ereport(ERROR,
+						(errcode(ERRCODE_UNDEFINED_TABLE),
+						 errmsg("relation \"%s\" does not exist",
+								rv->relname)));
+		}
+
+		return;
+	}
 
-			relation_close(rel, NoLock);	/* close rel, keep lock */
+	/* Verify adequate privilege */
+	if (lockmode == AccessShareLock)
+		aclresult = pg_class_aclcheck(reloid, GetUserId(),
+									  ACL_SELECT);
+	else
+		aclresult = pg_class_aclcheck(reloid, GetUserId(),
+									  ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
+	if (aclresult != ACLCHECK_OK)
+		aclcheck_error(aclresult, ACL_KIND_CLASS,
+					   RelationGetRelationName(rel));
+
+	/* Currently, we only allow plain tables to be locked */
+	if (rel->rd_rel->relkind != RELKIND_RELATION)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("\"%s\" is not a table",
+						RelationGetRelationName(rel))));
+
+	/*
+	 * If requested, recurse to children.  We use find_inheritance_children
+	 * not find_all_inheritors to avoid taking locks far in advance of
+	 * checking privileges.  This means we'll visit multiply-inheriting
+	 * children more than once, but that's no problem.
+	 */
+	if (recurse)
+	{
+		List   *children = find_inheritance_children(reloid, NoLock);
+		ListCell *lc;
+
+		foreach(lc, children)
+		{
+			Oid			childreloid = lfirst_oid(lc);
+
+			LockTableRecurse(childreloid, NULL, lockmode, nowait, recurse);
 		}
 	}
+
+	relation_close(rel, NoLock);	/* close rel, keep lock */
 }
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index d773652d0d5f60f51f7b5ad8856fada5ef9baa25..ec49192cacc09c7135d501a710bd9b7c1e9df281 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.141 2009/01/01 17:23:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.142 2009/05/12 16:43:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,7 +49,6 @@ typedef enum
 /* in heap/heapam.c */
 extern Relation relation_open(Oid relationId, LOCKMODE lockmode);
 extern Relation try_relation_open(Oid relationId, LOCKMODE lockmode);
-extern Relation relation_open_nowait(Oid relationId, LOCKMODE lockmode);
 extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
 extern Relation try_relation_openrv(const RangeVar *relation, LOCKMODE lockmode);
 extern void relation_close(Relation relation, LOCKMODE lockmode);