PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
lockcmds.c File Reference
#include "postgres.h"
#include "catalog/namespace.h"
#include "catalog/pg_inherits_fn.h"
#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/syscache.h"
Include dependency graph for lockcmds.c:

Go to the source code of this file.

Functions

static void LockTableRecurse (Oid reloid, LOCKMODE lockmode, bool nowait)
 
static AclResult LockTableAclCheck (Oid relid, LOCKMODE lockmode)
 
static void RangeVarCallbackForLockTable (const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
 
void LockTableCommand (LockStmt *lockstmt)
 

Function Documentation

static AclResult LockTableAclCheck ( Oid  relid,
LOCKMODE  lockmode 
)
static

Definition at line 168 of file lockcmds.c.

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

Referenced by LockTableRecurse(), and RangeVarCallbackForLockTable().

169 {
170  AclResult aclresult;
172 
173  /* Verify adequate privilege */
174  if (lockmode == AccessShareLock)
175  aclmask = ACL_SELECT;
176  else if (lockmode == RowExclusiveLock)
178  else
179  aclmask = ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
180 
181  aclresult = pg_class_aclcheck(reloid, GetUserId(), aclmask);
182 
183  return aclresult;
184 }
Oid GetUserId(void)
Definition: miscinit.c:283
AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how)
Definition: acl.c:1305
#define AccessShareLock
Definition: lockdefs.h:36
#define ACL_DELETE
Definition: parsenodes.h:68
uint32 AclMode
Definition: parsenodes.h:63
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ACL_UPDATE
Definition: parsenodes.h:67
AclResult
Definition: acl.h:170
#define ACL_SELECT
Definition: parsenodes.h:66
#define ACL_INSERT
Definition: parsenodes.h:65
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4397
#define ACL_TRUNCATE
Definition: parsenodes.h:69
void LockTableCommand ( LockStmt lockstmt)

Definition at line 36 of file lockcmds.c.

References RangeVar::inh, lfirst, LockTableRecurse(), LockStmt::mode, LockStmt::nowait, PreventCommandDuringRecovery(), RangeVarCallbackForLockTable(), RangeVarGetRelidExtended(), LockStmt::relations, and RowExclusiveLock.

Referenced by standard_ProcessUtility().

37 {
38  ListCell *p;
39 
40  /*---------
41  * During recovery we only accept these variations:
42  * LOCK TABLE foo IN ACCESS SHARE MODE
43  * LOCK TABLE foo IN ROW SHARE MODE
44  * LOCK TABLE foo IN ROW EXCLUSIVE MODE
45  * This test must match the restrictions defined in LockAcquireExtended()
46  *---------
47  */
48  if (lockstmt->mode > RowExclusiveLock)
49  PreventCommandDuringRecovery("LOCK TABLE");
50 
51  /*
52  * Iterate over the list and process the named relations one at a time
53  */
54  foreach(p, lockstmt->relations)
55  {
56  RangeVar *rv = (RangeVar *) lfirst(p);
57  bool recurse = rv->inh;
58  Oid reloid;
59 
60  reloid = RangeVarGetRelidExtended(rv, lockstmt->mode, false,
61  lockstmt->nowait,
63  (void *) &lockstmt->mode);
64 
65  if (recurse)
66  LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
67  }
68 }
bool nowait
Definition: parsenodes.h:3076
Oid RangeVarGetRelidExtended(const RangeVar *relation, LOCKMODE lockmode, bool missing_ok, bool nowait, RangeVarGetRelidCallback callback, void *callback_arg)
Definition: namespace.c:217
unsigned int Oid
Definition: postgres_ext.h:31
void PreventCommandDuringRecovery(const char *cmdname)
Definition: utility.c:272
#define RowExclusiveLock
Definition: lockdefs.h:38
bool inh
Definition: primnodes.h:68
static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
Definition: lockcmds.c:110
List * relations
Definition: parsenodes.h:3074
#define lfirst(lc)
Definition: pg_list.h:106
static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid, void *arg)
Definition: lockcmds.c:75
static void LockTableRecurse ( Oid  reloid,
LOCKMODE  lockmode,
bool  nowait 
)
static

Definition at line 110 of file lockcmds.c.

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

Referenced by LockTableCommand().

111 {
112  List *children;
113  ListCell *lc;
114 
115  children = find_inheritance_children(reloid, NoLock);
116 
117  foreach(lc, children)
118  {
119  Oid childreloid = lfirst_oid(lc);
120  AclResult aclresult;
121 
122  /* Check permissions before acquiring the lock. */
123  aclresult = LockTableAclCheck(childreloid, lockmode);
124  if (aclresult != ACLCHECK_OK)
125  {
126  char *relname = get_rel_name(childreloid);
127 
128  if (!relname)
129  continue; /* child concurrently dropped, just skip it */
130  aclcheck_error(aclresult, ACL_KIND_CLASS, relname);
131  }
132 
133  /* We have enough rights to lock the relation; do so. */
134  if (!nowait)
135  LockRelationOid(childreloid, lockmode);
136  else if (!ConditionalLockRelationOid(childreloid, lockmode))
137  {
138  /* try to throw error by name; relation could be deleted... */
139  char *relname = get_rel_name(childreloid);
140 
141  if (!relname)
142  continue; /* child concurrently dropped, just skip it */
143  ereport(ERROR,
144  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
145  errmsg("could not obtain lock on relation \"%s\"",
146  relname)));
147  }
148 
149  /*
150  * Even if we got the lock, child might have been concurrently
151  * dropped. If so, we can skip it.
152  */
153  if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(childreloid)))
154  {
155  /* Release useless lock */
156  UnlockRelationOid(childreloid, lockmode);
157  continue;
158  }
159 
160  LockTableRecurse(childreloid, lockmode, nowait);
161  }
162 }
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:138
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:182
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:167
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3378
#define ereport(elevel, rest)
Definition: elog.h:122
static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
Definition: lockcmds.c:110
AclResult
Definition: acl.h:170
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:49
int errmsg(const char *fmt,...)
Definition: elog.c:797
static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode)
Definition: lockcmds.c:168
void LockRelationOid(Oid relid, LOCKMODE lockmode)
Definition: lmgr.c:105
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
#define lfirst_oid(lc)
Definition: pg_list.h:108
static void RangeVarCallbackForLockTable ( const RangeVar rv,
Oid  relid,
Oid  oldrelid,
void *  arg 
)
static

Definition at line 75 of file lockcmds.c.

References ACL_KIND_CLASS, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, get_rel_relkind(), LockTableAclCheck(), OidIsValid, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, and RangeVar::relname.

Referenced by LockTableCommand().

77 {
78  LOCKMODE lockmode = *(LOCKMODE *) arg;
79  char relkind;
80  AclResult aclresult;
81 
82  if (!OidIsValid(relid))
83  return; /* doesn't exist, so no permissions check */
84  relkind = get_rel_relkind(relid);
85  if (!relkind)
86  return; /* woops, concurrently dropped; no permissions
87  * check */
88 
89  /* Currently, we only allow plain tables to be locked */
90  if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
91  ereport(ERROR,
92  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
93  errmsg("\"%s\" is not a table",
94  rv->relname)));
95 
96  /* Check permissions. */
97  aclresult = LockTableAclCheck(relid, lockmode);
98  if (aclresult != ACLCHECK_OK)
99  aclcheck_error(aclresult, ACL_KIND_CLASS, rv->relname);
100 }
int LOCKMODE
Definition: lockdefs.h:26
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1769
int errcode(int sqlerrcode)
Definition: elog.c:575
#define OidIsValid(objectId)
Definition: c.h:534
char * relname
Definition: primnodes.h:67
#define ERROR
Definition: elog.h:43
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3378
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
AclResult
Definition: acl.h:170
int errmsg(const char *fmt,...)
Definition: elog.c:797
static AclResult LockTableAclCheck(Oid relid, LOCKMODE lockmode)
Definition: lockcmds.c:168
void * arg
#define RELKIND_RELATION
Definition: pg_class.h:160