PostgreSQL Source Code git master
Loading...
Searching...
No Matches
lockcmds.c File Reference
#include "postgres.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_inherits.h"
#include "commands/lockcmds.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "rewrite/rewriteHandler.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Include dependency graph for lockcmds.c:

Go to the source code of this file.

Data Structures

struct  LockViewRecurse_context
 

Functions

static void LockTableRecurse (Oid reloid, LOCKMODE lockmode, bool nowait)
 
static AclResult LockTableAclCheck (Oid reloid, LOCKMODE lockmode, Oid userid)
 
static void RangeVarCallbackForLockTable (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
static void LockViewRecurse (Oid reloid, LOCKMODE lockmode, bool nowait, List *ancestor_views)
 
void LockTableCommand (LockStmt *lockstmt)
 
static bool LockViewRecurse_walker (Node *node, LockViewRecurse_context *context)
 

Function Documentation

◆ LockTableAclCheck()

static AclResult LockTableAclCheck ( Oid  reloid,
LOCKMODE  lockmode,
Oid  userid 
)
static

Definition at line 302 of file lockcmds.c.

303{
306
307 /* any of these privileges permit any lock mode */
309
310 /* SELECT privileges also permit ACCESS SHARE and below */
311 if (lockmode <= AccessShareLock)
313
314 /* INSERT privileges also permit ROW EXCLUSIVE and below */
315 if (lockmode <= RowExclusiveLock)
317
318 aclresult = pg_class_aclcheck(reloid, userid, aclmask);
319
320 return aclresult;
321}
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition acl.c:1416
AclResult
Definition acl.h:183
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4105
#define AccessShareLock
Definition lockdefs.h:36
#define RowExclusiveLock
Definition lockdefs.h:38
#define ACL_DELETE
Definition parsenodes.h:79
uint64 AclMode
Definition parsenodes.h:74
#define ACL_MAINTAIN
Definition parsenodes.h:90
#define ACL_INSERT
Definition parsenodes.h:76
#define ACL_UPDATE
Definition parsenodes.h:78
#define ACL_SELECT
Definition parsenodes.h:77
#define ACL_TRUNCATE
Definition parsenodes.h:80
static int fb(int x)

References AccessShareLock, ACL_DELETE, ACL_INSERT, ACL_MAINTAIN, ACL_SELECT, ACL_TRUNCATE, ACL_UPDATE, aclmask(), fb(), pg_class_aclcheck(), and RowExclusiveLock.

Referenced by LockViewRecurse_walker(), and RangeVarCallbackForLockTable().

◆ LockTableCommand()

void LockTableCommand ( LockStmt lockstmt)

Definition at line 41 of file lockcmds.c.

42{
43 ListCell *p;
44
45 /*
46 * Iterate over the list and process the named relations one at a time
47 */
48 foreach(p, lockstmt->relations)
49 {
50 RangeVar *rv = (RangeVar *) lfirst(p);
51 bool recurse = rv->inh;
52 Oid reloid;
53
54 reloid = RangeVarGetRelidExtended(rv, lockstmt->mode,
55 lockstmt->nowait ? RVR_NOWAIT : 0,
57 &lockstmt->mode);
58
59 if (get_rel_relkind(reloid) == RELKIND_VIEW)
60 LockViewRecurse(reloid, lockstmt->mode, lockstmt->nowait, NIL);
61 else if (recurse)
62 LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
63 }
64}
static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition lockcmds.c:71
static void LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, List *ancestor_views)
Definition lockcmds.c:267
static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
Definition lockcmds.c:129
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2317
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition namespace.c:442
@ RVR_NOWAIT
Definition namespace.h:91
static PgChecksumMode mode
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
unsigned int Oid
bool inh
Definition primnodes.h:87

References fb(), get_rel_relkind(), RangeVar::inh, lfirst, LockTableRecurse(), LockViewRecurse(), NIL, RangeVarCallbackForLockTable(), RangeVarGetRelidExtended(), and RVR_NOWAIT.

Referenced by standard_ProcessUtility().

◆ LockTableRecurse()

static void LockTableRecurse ( Oid  reloid,
LOCKMODE  lockmode,
bool  nowait 
)
static

Definition at line 129 of file lockcmds.c.

130{
131 List *children;
132 ListCell *lc;
133
134 children = find_all_inheritors(reloid, NoLock, NULL);
135
136 foreach(lc, children)
137 {
139
140 /* Parent already locked. */
141 if (childreloid == reloid)
142 continue;
143
144 if (!nowait)
145 LockRelationOid(childreloid, lockmode);
146 else if (!ConditionalLockRelationOid(childreloid, lockmode))
147 {
148 /* try to throw error by name; relation could be deleted... */
150
151 if (!relname)
152 continue; /* child concurrently dropped, just skip it */
155 errmsg("could not obtain lock on relation \"%s\"",
156 relname)));
157 }
158
159 /*
160 * Even if we got the lock, child might have been concurrently
161 * dropped. If so, we can skip it.
162 */
164 {
165 /* Release useless lock */
167 continue;
168 }
169 }
170}
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:151
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:229
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition lmgr.c:107
#define NoLock
Definition lockdefs.h:34
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
static char * errmsg
NameData relname
Definition pg_class.h:40
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
#define lfirst_oid(lc)
Definition pg_list.h:174
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
Definition pg_list.h:54
#define SearchSysCacheExists1(cacheId, key1)
Definition syscache.h:100

References ConditionalLockRelationOid(), ereport, errcode(), errmsg, ERROR, fb(), find_all_inheritors(), get_rel_name(), lfirst_oid, LockRelationOid(), NoLock, ObjectIdGetDatum(), relname, SearchSysCacheExists1, and UnlockRelationOid().

Referenced by LockTableCommand(), and LockViewRecurse_walker().

◆ LockViewRecurse()

static void LockViewRecurse ( Oid  reloid,
LOCKMODE  lockmode,
bool  nowait,
List ancestor_views 
)
static

Definition at line 267 of file lockcmds.c.

269{
271 Relation view;
273
274 /* caller has already locked the view */
275 view = table_open(reloid, NoLock);
277
278 /*
279 * If the view has the security_invoker property set, check permissions as
280 * the current user. Otherwise, check permissions as the view owner.
281 */
282 context.lockmode = lockmode;
283 context.nowait = nowait;
285 context.check_as_user = GetUserId();
286 else
287 context.check_as_user = view->rd_rel->relowner;
288 context.viewoid = reloid;
289 context.ancestor_views = lappend_oid(ancestor_views, reloid);
290
292
294
295 table_close(view, NoLock);
296}
List * lappend_oid(List *list, Oid datum)
Definition list.c:375
List * list_delete_last(List *list)
Definition list.c:957
static bool LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
Definition lockcmds.c:189
Oid GetUserId(void)
Definition miscinit.c:470
#define RelationHasSecurityInvoker(relation)
Definition rel.h:449
Query * get_view_query(Relation view)
Definition nodes.h:133
Form_pg_class rd_rel
Definition rel.h:111
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References LockViewRecurse_context::ancestor_views, LockViewRecurse_context::check_as_user, fb(), get_view_query(), GetUserId(), lappend_oid(), list_delete_last(), LockViewRecurse_context::lockmode, LockViewRecurse_walker(), NoLock, LockViewRecurse_context::nowait, RelationData::rd_rel, RelationHasSecurityInvoker, table_close(), table_open(), and LockViewRecurse_context::viewoid.

Referenced by LockTableCommand(), and LockViewRecurse_walker().

◆ LockViewRecurse_walker()

static bool LockViewRecurse_walker ( Node node,
LockViewRecurse_context context 
)
static

Definition at line 189 of file lockcmds.c.

190{
191 if (node == NULL)
192 return false;
193
194 if (IsA(node, Query))
195 {
196 Query *query = (Query *) node;
197 ListCell *rtable;
198
199 foreach(rtable, query->rtable)
200 {
201 RangeTblEntry *rte = lfirst(rtable);
203
204 Oid relid = rte->relid;
205 char relkind = rte->relkind;
206 char *relname = get_rel_name(relid);
207
208 /* Currently, we only allow plain tables or views to be locked. */
209 if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
210 relkind != RELKIND_VIEW)
211 continue;
212
213 /*
214 * Conflict log tables only support SELECT, DELETE, and TRUNCATE.
215 * A direct LOCK on them is permitted solely so that pg_dump can
216 * lock them during a binary upgrade; locking one indirectly by
217 * locking a view over it is not needed for that, so skip it here
218 * rather than locking it.
219 */
221 continue;
222
223 /*
224 * We might be dealing with a self-referential view. If so, we
225 * can just stop recursing, since we already locked it.
226 */
227 if (list_member_oid(context->ancestor_views, relid))
228 continue;
229
230 /*
231 * Check permissions as the specified user. This will either be
232 * the view owner or the current user.
233 */
234 aclresult = LockTableAclCheck(relid, context->lockmode,
235 context->check_as_user);
236 if (aclresult != ACLCHECK_OK)
238
239 /* We have enough rights to lock the relation; do so. */
240 if (!context->nowait)
241 LockRelationOid(relid, context->lockmode);
242 else if (!ConditionalLockRelationOid(relid, context->lockmode))
245 errmsg("could not obtain lock on relation \"%s\"",
246 relname)));
247
248 if (relkind == RELKIND_VIEW)
249 LockViewRecurse(relid, context->lockmode, context->nowait,
250 context->ancestor_views);
251 else if (rte->inh)
252 LockTableRecurse(relid, context->lockmode, context->nowait);
253 }
254
255 return query_tree_walker(query,
257 context,
259 }
260
261 return expression_tree_walker(node,
263 context);
264}
@ ACLCHECK_OK
Definition acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
bool IsConflictLogTableNamespace(Oid namespaceId)
Definition catalog.c:290
bool list_member_oid(const List *list, Oid datum)
Definition list.c:722
static AclResult LockTableAclCheck(Oid reloid, LOCKMODE lockmode, Oid userid)
Definition lockcmds.c:302
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2266
#define query_tree_walker(q, w, c, f)
Definition nodeFuncs.h:158
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153
#define QTW_IGNORE_JOINALIASES
Definition nodeFuncs.h:25
#define IsA(nodeptr, _type_)
Definition nodes.h:162
ObjectType get_relkind_objtype(char relkind)
List * rtable
Definition parsenodes.h:180

References aclcheck_error(), ACLCHECK_OK, LockViewRecurse_context::ancestor_views, LockViewRecurse_context::check_as_user, ConditionalLockRelationOid(), ereport, errcode(), errmsg, ERROR, expression_tree_walker, fb(), get_rel_name(), get_rel_namespace(), get_relkind_objtype(), IsA, IsConflictLogTableNamespace(), lfirst, list_member_oid(), LockViewRecurse_context::lockmode, LockRelationOid(), LockTableAclCheck(), LockTableRecurse(), LockViewRecurse(), LockViewRecurse_walker(), LockViewRecurse_context::nowait, QTW_IGNORE_JOINALIASES, query_tree_walker, relname, and Query::rtable.

Referenced by LockViewRecurse(), and LockViewRecurse_walker().

◆ RangeVarCallbackForLockTable()

static void RangeVarCallbackForLockTable ( const RangeVar rv,
Oid  relid,
Oid  oldrelid,
void arg 
)
static

Definition at line 71 of file lockcmds.c.

73{
74 LOCKMODE lockmode = *(LOCKMODE *) arg;
75 char relkind;
76 char relpersistence;
78
79 if (!OidIsValid(relid))
80 return; /* doesn't exist, so no permissions check */
81 relkind = get_rel_relkind(relid);
82 if (!relkind)
83 return; /* woops, concurrently dropped; no permissions
84 * check */
85
86 /*
87 * Note: Conflict log tables are deliberately NOT blocked here, even
88 * though other direct DDL on them is rejected elsewhere. pg_dump relies
89 * on being able to take an ACCESS SHARE lock on these tables to safely
90 * dump their definitions during a binary upgrade, so we permit LOCK
91 * commands on them and treat them like ordinary tables here. It's true
92 * that a strong lock (ShareLock or above) on such a table would conflict
93 * with the RowExclusiveLock taken by the apply worker's inserts and could
94 * stall conflict logging as well as the apply worker for as long as it is
95 * held. But locking a system-managed conflict log table is an unusual
96 * thing to do, and it doesn't seem worth the trouble of filtering by lock
97 * mode here.
98 */
99 if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
100 relkind != RELKIND_VIEW)
103 errmsg("cannot lock relation \"%s\"",
104 rv->relname),
106
107 /*
108 * Make note if a temporary relation has been accessed in this
109 * transaction.
110 */
111 relpersistence = get_rel_persistence(relid);
112 if (relpersistence == RELPERSISTENCE_TEMP)
114
115 /* Check permissions. */
116 aclresult = LockTableAclCheck(relid, lockmode, GetUserId());
117 if (aclresult != ACLCHECK_OK)
119}
#define OidIsValid(objectId)
Definition c.h:917
Datum arg
Definition elog.c:1323
int LOCKMODE
Definition lockdefs.h:26
char get_rel_persistence(Oid relid)
Definition lsyscache.c:2392
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
char * relname
Definition primnodes.h:84
int MyXactFlags
Definition xact.c:138
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition xact.h:103

References aclcheck_error(), ACLCHECK_OK, arg, ereport, errcode(), errdetail_relkind_not_supported(), errmsg, ERROR, fb(), get_rel_persistence(), get_rel_relkind(), get_relkind_objtype(), GetUserId(), LockTableAclCheck(), MyXactFlags, OidIsValid, RangeVar::relname, and XACT_FLAGS_ACCESSEDTEMPNAMESPACE.

Referenced by LockTableCommand().