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
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 concurrent
71 * drops. Note that a lock against an already-dropped relation's OID
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 */