1 /*-------------------------------------------------------------------------
4 * LOCK command support code
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/commands/lockcmds.c,v 1.24 2009/05/12 16:43:32 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "catalog/namespace.h"
19 #include "catalog/pg_inherits_fn.h"
20 #include "commands/lockcmds.h"
21 #include "miscadmin.h"
22 #include "parser/parse_clause.h"
23 #include "storage/lmgr.h"
24 #include "utils/acl.h"
25 #include "utils/lsyscache.h"
27 static void LockTableRecurse(Oid reloid, RangeVar *rv,
28 LOCKMODE lockmode, bool nowait, bool recurse);
35 LockTableCommand(LockStmt *lockstmt)
40 * Iterate over the list and process the named relations one at a time
42 foreach(p, lockstmt->relations)
44 RangeVar *relation = (RangeVar *) lfirst(p);
45 bool recurse = interpretInhOption(relation->inhOpt);
48 reloid = RangeVarGetRelid(relation, false);
50 LockTableRecurse(reloid, relation,
51 lockstmt->mode, lockstmt->nowait, recurse);
56 * Apply LOCK TABLE recursively over an inheritance tree
58 * At top level, "rv" is the original command argument; we use it to throw
59 * an appropriate error message if the relation isn't there. Below top level,
60 * "rv" is NULL and we should just silently ignore any dropped child rel.
63 LockTableRecurse(Oid reloid, RangeVar *rv,
64 LOCKMODE lockmode, bool nowait, bool recurse)
70 * Acquire the lock. We must do this first to protect against
71 * concurrent drops. Note that a lock against an already-dropped
72 * relation's OID won't fail.
76 if (!ConditionalLockRelationOid(reloid, lockmode))
78 /* try to throw error by name; relation could be deleted... */
79 char *relname = rv ? rv->relname : get_rel_name(reloid);
83 (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
84 errmsg("could not obtain lock on relation \"%s\"",
88 (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
89 errmsg("could not obtain lock on relation with OID %u",
94 LockRelationOid(reloid, lockmode);
97 * Now that we have the lock, check to see if the relation really exists
100 rel = try_relation_open(reloid, NoLock);
104 /* Release useless lock */
105 UnlockRelationOid(reloid, lockmode);
107 /* At top level, throw error; otherwise, ignore this child rel */
112 (errcode(ERRCODE_UNDEFINED_TABLE),
113 errmsg("relation \"%s.%s\" does not exist",
114 rv->schemaname, rv->relname)));
117 (errcode(ERRCODE_UNDEFINED_TABLE),
118 errmsg("relation \"%s\" does not exist",
125 /* Verify adequate privilege */
126 if (lockmode == AccessShareLock)
127 aclresult = pg_class_aclcheck(reloid, GetUserId(),
130 aclresult = pg_class_aclcheck(reloid, GetUserId(),
131 ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
132 if (aclresult != ACLCHECK_OK)
133 aclcheck_error(aclresult, ACL_KIND_CLASS,
134 RelationGetRelationName(rel));
136 /* Currently, we only allow plain tables to be locked */
137 if (rel->rd_rel->relkind != RELKIND_RELATION)
139 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
140 errmsg("\"%s\" is not a table",
141 RelationGetRelationName(rel))));
144 * If requested, recurse to children. We use find_inheritance_children
145 * not find_all_inheritors to avoid taking locks far in advance of
146 * checking privileges. This means we'll visit multiply-inheriting
147 * children more than once, but that's no problem.
151 List *children = find_inheritance_children(reloid, NoLock);
154 foreach(lc, children)
156 Oid childreloid = lfirst_oid(lc);
158 LockTableRecurse(childreloid, NULL, lockmode, nowait, recurse);
162 relation_close(rel, NoLock); /* close rel, keep lock */