Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions

lockcmds.c File Reference

#include "postgres.h"
#include "access/heapam.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 169 of file lockcmds.c.

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

Referenced by LockTableRecurse(), and RangeVarCallbackForLockTable().

{
    AclResult   aclresult;

    /* Verify adequate privilege */
    if (lockmode == AccessShareLock)
        aclresult = pg_class_aclcheck(reloid, GetUserId(),
                                      ACL_SELECT);
    else
        aclresult = pg_class_aclcheck(reloid, GetUserId(),
                                      ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE);
    return aclresult;
}

void LockTableCommand ( LockStmt lockstmt  ) 

Definition at line 37 of file lockcmds.c.

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

Referenced by standard_ProcessUtility().

{
    ListCell   *p;

    /*---------
     * During recovery we only accept these variations:
     * LOCK TABLE foo IN ACCESS SHARE MODE
     * LOCK TABLE foo IN ROW SHARE MODE
     * LOCK TABLE foo IN ROW EXCLUSIVE MODE
     * This test must match the restrictions defined in LockAcquireExtended()
     *---------
     */
    if (lockstmt->mode > RowExclusiveLock)
        PreventCommandDuringRecovery("LOCK TABLE");

    /*
     * Iterate over the list and process the named relations one at a time
     */
    foreach(p, lockstmt->relations)
    {
        RangeVar   *rv = (RangeVar *) lfirst(p);
        bool        recurse = interpretInhOption(rv->inhOpt);
        Oid         reloid;

        reloid = RangeVarGetRelidExtended(rv, lockstmt->mode, false,
                                          lockstmt->nowait,
                                          RangeVarCallbackForLockTable,
                                          (void *) &lockstmt->mode);

        if (recurse)
            LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
    }
}

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

Definition at line 111 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().

{
    List       *children;
    ListCell   *lc;

    children = find_inheritance_children(reloid, NoLock);

    foreach(lc, children)
    {
        Oid         childreloid = lfirst_oid(lc);
        AclResult   aclresult;

        /* Check permissions before acquiring the lock. */
        aclresult = LockTableAclCheck(childreloid, lockmode);
        if (aclresult != ACLCHECK_OK)
        {
            char       *relname = get_rel_name(childreloid);

            if (!relname)
                continue;       /* child concurrently dropped, just skip it */
            aclcheck_error(aclresult, ACL_KIND_CLASS, relname);
        }

        /* We have enough rights to lock the relation; do so. */
        if (!nowait)
            LockRelationOid(childreloid, lockmode);
        else if (!ConditionalLockRelationOid(childreloid, lockmode))
        {
            /* try to throw error by name; relation could be deleted... */
            char       *relname = get_rel_name(childreloid);

            if (!relname)
                continue;       /* child concurrently dropped, just skip it */
            ereport(ERROR,
                    (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                     errmsg("could not obtain lock on relation \"%s\"",
                            relname)));
        }

        /*
         * Even if we got the lock, child might have been concurrently
         * dropped. If so, we can skip it.
         */
        if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(childreloid)))
        {
            /* Release useless lock */
            UnlockRelationOid(childreloid, lockmode);
            continue;
        }

        LockTableRecurse(childreloid, lockmode, nowait);
    }
}

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

Definition at line 76 of file lockcmds.c.

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

Referenced by LockTableCommand().

{
    LOCKMODE    lockmode = *(LOCKMODE *) arg;
    char        relkind;
    AclResult   aclresult;

    if (!OidIsValid(relid))
        return;                 /* doesn't exist, so no permissions check */
    relkind = get_rel_relkind(relid);
    if (!relkind)
        return;                 /* woops, concurrently dropped; no permissions
                                 * check */

    /* Currently, we only allow plain tables to be locked */
    if (relkind != RELKIND_RELATION)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("\"%s\" is not a table",
                        rv->relname)));

    /* Check permissions. */
    aclresult = LockTableAclCheck(relid, lockmode);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_CLASS, rv->relname);
}