PostgreSQL Source Code  git master
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 "parser/parse_clause.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, Oid userid)
 
static AclResult LockTableAclCheck (Oid relid, 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  relid,
LOCKMODE  lockmode,
Oid  userid 
)
static

Definition at line 286 of file lockcmds.c.

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

Referenced by LockTableRecurse(), LockViewRecurse_walker(), and RangeVarCallbackForLockTable().

287 {
288  AclResult aclresult;
290 
291  /* Verify adequate privilege */
292  if (lockmode == AccessShareLock)
293  aclmask = ACL_SELECT;
294  else if (lockmode == RowExclusiveLock)
296  else
297  aclmask = ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
298 
299  aclresult = pg_class_aclcheck(reloid, userid, aclmask);
300 
301  return aclresult;
302 }
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1321
#define AccessShareLock
Definition: lockdefs.h:36
#define ACL_DELETE
Definition: parsenodes.h:77
uint32 AclMode
Definition: parsenodes.h:72
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ACL_UPDATE
Definition: parsenodes.h:76
AclResult
Definition: acl.h:177
#define ACL_SELECT
Definition: parsenodes.h:75
#define ACL_INSERT
Definition: parsenodes.h:74
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4629
#define ACL_TRUNCATE
Definition: parsenodes.h:78

◆ LockTableCommand()

void LockTableCommand ( LockStmt lockstmt)

Definition at line 41 of file lockcmds.c.

References get_rel_relkind(), GetUserId(), RangeVar::inh, lfirst, LockTableRecurse(), LockViewRecurse(), LockStmt::mode, NIL, LockStmt::nowait, RangeVarCallbackForLockTable(), RangeVarGetRelidExtended(), LockStmt::relations, and RVR_NOWAIT.

Referenced by standard_ProcessUtility().

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  (void *) &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, GetUserId());
63  }
64 }
#define NIL
Definition: pg_list.h:65
bool nowait
Definition: parsenodes.h:3316
Oid GetUserId(void)
Definition: miscinit.c:380
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
static void LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, List *ancestor_views)
Definition: lockcmds.c:259
unsigned int Oid
Definition: postgres_ext.h:31
static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, Oid userid)
Definition: lockcmds.c:116
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, uint32 flags, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:228
bool inh
Definition: primnodes.h:69
List * relations
Definition: parsenodes.h:3314
#define lfirst(lc)
Definition: pg_list.h:190
static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: lockcmds.c:71

◆ LockTableRecurse()

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

Definition at line 116 of file lockcmds.c.

References aclcheck_error(), ACLCHECK_OK, ConditionalLockRelationOid(), ereport, errcode(), errmsg(), ERROR, find_inheritance_children(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), lfirst_oid, LockRelationOid(), LockTableAclCheck(), NoLock, ObjectIdGetDatum, relname, RELOID, SearchSysCacheExists1, and UnlockRelationOid().

Referenced by LockTableCommand(), and LockViewRecurse_walker().

117 {
118  List *children;
119  ListCell *lc;
120 
121  children = find_inheritance_children(reloid, NoLock);
122 
123  foreach(lc, children)
124  {
125  Oid childreloid = lfirst_oid(lc);
126  AclResult aclresult;
127 
128  /* Check permissions before acquiring the lock. */
129  aclresult = LockTableAclCheck(childreloid, lockmode, userid);
130  if (aclresult != ACLCHECK_OK)
131  {
132  char *relname = get_rel_name(childreloid);
133 
134  if (!relname)
135  continue; /* child concurrently dropped, just skip it */
136  aclcheck_error(aclresult, get_relkind_objtype(get_rel_relkind(childreloid)), relname);
137  }
138 
139  /* We have enough rights to lock the relation; do so. */
140  if (!nowait)
141  LockRelationOid(childreloid, lockmode);
142  else if (!ConditionalLockRelationOid(childreloid, lockmode))
143  {
144  /* try to throw error by name; relation could be deleted... */
145  char *relname = get_rel_name(childreloid);
146 
147  if (!relname)
148  continue; /* child concurrently dropped, just skip it */
149  ereport(ERROR,
150  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
151  errmsg("could not obtain lock on relation \"%s\"",
152  relname)));
153  }
154 
155  /*
156  * Even if we got the lock, child might have been concurrently
157  * dropped. If so, we can skip it.
158  */
159  if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(childreloid)))
160  {
161  /* Release useless lock */
162  UnlockRelationOid(childreloid, lockmode);
163  continue;
164  }
165 
166  LockTableRecurse(childreloid, lockmode, nowait, userid);
167  }
168 }
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:199
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:608
NameData relname
Definition: pg_class.h:35
unsigned int Oid
Definition: postgres_ext.h:31
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode, Oid userid)
Definition: lockcmds.c:286
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:183
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, Oid userid)
Definition: lockcmds.c:116
#define NoLock
Definition: lockdefs.h:34
#define ereport(elevel, rest)
Definition: elog.h:141
AclResult
Definition: acl.h:177
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
int errmsg(const char *fmt,...)
Definition: elog.c:822
ObjectType get_relkind_objtype(char relkind)
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
Definition: pg_list.h:50
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ LockViewRecurse()

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

Definition at line 259 of file lockcmds.c.

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

Referenced by LockTableCommand(), and LockViewRecurse_walker().

260 {
261  LockViewRecurse_context context;
262 
263  Relation view;
264  Query *viewquery;
265 
266  view = table_open(reloid, NoLock);
267  viewquery = get_view_query(view);
268 
269  context.lockmode = lockmode;
270  context.nowait = nowait;
271  context.viewowner = view->rd_rel->relowner;
272  context.viewoid = reloid;
273  context.ancestor_views = lappend_oid(ancestor_views, reloid);
274 
275  LockViewRecurse_walker((Node *) viewquery, &context);
276 
277  (void) list_delete_last(context.ancestor_views);
278 
279  table_close(view, NoLock);
280 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
static bool LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
Definition: lockcmds.c:187
Definition: nodes.h:525
Form_pg_class rd_rel
Definition: rel.h:84
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
#define NoLock
Definition: lockdefs.h:34
List * list_delete_last(List *list)
Definition: list.c:878
Query * get_view_query(Relation view)
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ LockViewRecurse_walker()

static bool LockViewRecurse_walker ( Node node,
LockViewRecurse_context context 
)
static

Definition at line 187 of file lockcmds.c.

References aclcheck_error(), ACLCHECK_OK, Alias::aliasname, LockViewRecurse_context::ancestor_views, ConditionalLockRelationOid(), RangeTblEntry::eref, ereport, errcode(), errmsg(), ERROR, expression_tree_walker(), get_rel_name(), get_relkind_objtype(), RangeTblEntry::inh, IsA, lfirst, list_member_oid(), LockViewRecurse_context::lockmode, LockRelationOid(), LockTableAclCheck(), LockTableRecurse(), LockViewRecurse(), LockViewRecurse_context::nowait, QTW_IGNORE_JOINALIASES, query_tree_walker(), RangeTblEntry::relid, relkind, RangeTblEntry::relkind, relname, Query::rtable, LockViewRecurse_context::viewoid, and LockViewRecurse_context::viewowner.

Referenced by LockViewRecurse().

188 {
189  if (node == NULL)
190  return false;
191 
192  if (IsA(node, Query))
193  {
194  Query *query = (Query *) node;
195  ListCell *rtable;
196 
197  foreach(rtable, query->rtable)
198  {
199  RangeTblEntry *rte = lfirst(rtable);
200  AclResult aclresult;
201 
202  Oid relid = rte->relid;
203  char relkind = rte->relkind;
204  char *relname = get_rel_name(relid);
205 
206  /*
207  * The OLD and NEW placeholder entries in the view's rtable are
208  * skipped.
209  */
210  if (relid == context->viewoid &&
211  (strcmp(rte->eref->aliasname, "old") == 0 ||
212  strcmp(rte->eref->aliasname, "new") == 0))
213  continue;
214 
215  /* Currently, we only allow plain tables or views to be locked. */
216  if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
217  relkind != RELKIND_VIEW)
218  continue;
219 
220  /* Check infinite recursion in the view definition. */
221  if (list_member_oid(context->ancestor_views, relid))
222  ereport(ERROR,
223  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
224  errmsg("infinite recursion detected in rules for relation \"%s\"",
225  get_rel_name(relid))));
226 
227  /* Check permissions with the view owner's privilege. */
228  aclresult = LockTableAclCheck(relid, context->lockmode, context->viewowner);
229  if (aclresult != ACLCHECK_OK)
230  aclcheck_error(aclresult, get_relkind_objtype(relkind), relname);
231 
232  /* We have enough rights to lock the relation; do so. */
233  if (!context->nowait)
234  LockRelationOid(relid, context->lockmode);
235  else if (!ConditionalLockRelationOid(relid, context->lockmode))
236  ereport(ERROR,
237  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
238  errmsg("could not obtain lock on relation \"%s\"",
239  relname)));
240 
241  if (relkind == RELKIND_VIEW)
242  LockViewRecurse(relid, context->lockmode, context->nowait, context->ancestor_views);
243  else if (rte->inh)
244  LockTableRecurse(relid, context->lockmode, context->nowait, context->viewowner);
245  }
246 
247  return query_tree_walker(query,
249  context,
251  }
252 
253  return expression_tree_walker(node,
255  context);
256 }
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:151
bool query_tree_walker(Query *query, bool(*walker)(), void *context, int flags)
Definition: nodeFuncs.c:2273
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
static bool LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
Definition: lockcmds.c:187
int errcode(int sqlerrcode)
Definition: elog.c:608
static void LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, List *ancestor_views)
Definition: lockcmds.c:259
NameData relname
Definition: pg_class.h:35
unsigned int Oid
Definition: postgres_ext.h:31
char relkind
Definition: pg_class.h:81
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode, Oid userid)
Definition: lockcmds.c:286
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait, Oid userid)
Definition: lockcmds.c:116
#define ereport(elevel, rest)
Definition: elog.h:141
AclResult
Definition: acl.h:177
bool list_member_oid(const List *list, Oid datum)
Definition: list.c:675
#define lfirst(lc)
Definition: pg_list.h:190
char * aliasname
Definition: primnodes.h:42
bool expression_tree_walker(Node *node, bool(*walker)(), void *context)
Definition: nodeFuncs.c:1839
int errmsg(const char *fmt,...)
Definition: elog.c:822
ObjectType get_relkind_objtype(char relkind)
Alias * eref
Definition: parsenodes.h:1113
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:108
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define QTW_IGNORE_JOINALIASES
Definition: nodeFuncs.h:23

◆ RangeVarCallbackForLockTable()

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

Definition at line 71 of file lockcmds.c.

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

Referenced by LockTableCommand().

73 {
74  LOCKMODE lockmode = *(LOCKMODE *) arg;
75  char relkind;
76  char relpersistence;
77  AclResult aclresult;
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  /* Currently, we only allow plain tables or views to be locked */
87  if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
88  relkind != RELKIND_VIEW)
89  ereport(ERROR,
90  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
91  errmsg("\"%s\" is not a table or view",
92  rv->relname)));
93 
94  /*
95  * Make note if a temporary relation has been accessed in this
96  * transaction.
97  */
98  relpersistence = get_rel_persistence(relid);
99  if (relpersistence == RELPERSISTENCE_TEMP)
101 
102  /* Check permissions. */
103  aclresult = LockTableAclCheck(relid, lockmode, GetUserId());
104  if (aclresult != ACLCHECK_OK)
106 }
int LOCKMODE
Definition: lockdefs.h:26
Oid GetUserId(void)
Definition: miscinit.c:380
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
int errcode(int sqlerrcode)
Definition: elog.c:608
#define OidIsValid(objectId)
Definition: c.h:645
char relkind
Definition: pg_class.h:81
char * relname
Definition: primnodes.h:68
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode, Oid userid)
Definition: lockcmds.c:286
#define ERROR
Definition: elog.h:43
char relpersistence
Definition: pg_class.h:78
#define ereport(elevel, rest)
Definition: elog.h:141
int MyXactFlags
Definition: xact.c:118
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:97
AclResult
Definition: acl.h:177
char get_rel_persistence(Oid relid)
Definition: lsyscache.c:1880
int errmsg(const char *fmt,...)
Definition: elog.c:822
ObjectType get_relkind_objtype(char relkind)
void * arg