LCOV - differential code coverage report
Current view: top level - src/backend/commands - lockcmds.c (source / functions) Coverage Total Hit UNC UBC GNC CBC
Current: 77aeca80249c9e640c811e80633a2e334a9320de vs 38afc3dcb25c45b744d4025029ce0a6c90b7059f Lines: 87.4 % 95 83 1 11 1 82
Current Date: 2026-07-25 19:08:27 +0900 Functions: 100.0 % 6 6 2 4
Baseline: lcov-20260725-baseline Branches: 72.7 % 88 64 1 23 1 63
Baseline Date: 2026-07-25 19:09:19 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 50.0 % 2 1 1 1
(360..) days: 88.2 % 93 82 11 82
Function coverage date bins:
(360..) days: 100.0 % 6 6 2 4
Branch coverage date bins:
(7,30] days: 50.0 % 2 1 1 1
(360..) days: 73.3 % 86 63 23 63

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * lockcmds.c
                                  4                 :                :  *    LOCK command support code
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/backend/commands/lockcmds.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : #include "postgres.h"
                                 16                 :                : 
                                 17                 :                : #include "access/table.h"
                                 18                 :                : #include "access/xact.h"
                                 19                 :                : #include "catalog/namespace.h"
                                 20                 :                : #include "catalog/pg_inherits.h"
                                 21                 :                : #include "commands/lockcmds.h"
                                 22                 :                : #include "miscadmin.h"
                                 23                 :                : #include "nodes/nodeFuncs.h"
                                 24                 :                : #include "rewrite/rewriteHandler.h"
                                 25                 :                : #include "storage/lmgr.h"
                                 26                 :                : #include "utils/acl.h"
                                 27                 :                : #include "utils/lsyscache.h"
                                 28                 :                : #include "utils/syscache.h"
                                 29                 :                : 
                                 30                 :                : static void LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait);
                                 31                 :                : static AclResult LockTableAclCheck(Oid reloid, LOCKMODE lockmode, Oid userid);
                                 32                 :                : static void RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid,
                                 33                 :                :                                          Oid oldrelid, void *arg);
                                 34                 :                : static void LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait,
                                 35                 :                :                             List *ancestor_views);
                                 36                 :                : 
                                 37                 :                : /*
                                 38                 :                :  * LOCK TABLE
                                 39                 :                :  */
                                 40                 :                : void
 8867 tgl@sss.pgh.pa.us          41                 :CBC         591 : LockTableCommand(LockStmt *lockstmt)
                                 42                 :                : {
                                 43                 :                :     ListCell   *p;
                                 44                 :                : 
                                 45                 :                :     /*
                                 46                 :                :      * Iterate over the list and process the named relations one at a time
                                 47                 :                :      */
                                 48   [ +  -  +  +  :           7129 :     foreach(p, lockstmt->relations)
                                              +  + ]
                                 49                 :                :     {
 5496 rhaas@postgresql.org       50                 :           6585 :         RangeVar   *rv = (RangeVar *) lfirst(p);
 3501 tgl@sss.pgh.pa.us          51                 :           6585 :         bool        recurse = rv->inh;
                                 52                 :                :         Oid         reloid;
                                 53                 :                : 
 3039 andres@anarazel.de         54                 :           6585 :         reloid = RangeVarGetRelidExtended(rv, lockstmt->mode,
                                 55                 :           6585 :                                           lockstmt->nowait ? RVR_NOWAIT : 0,
                                 56                 :                :                                           RangeVarCallbackForLockTable,
  604 peter@eisentraut.org       57         [ +  + ]:           6585 :                                           &lockstmt->mode);
                                 58                 :                : 
 3039 ishii@postgresql.org       59         [ +  + ]:           6542 :         if (get_rel_relkind(reloid) == RELKIND_VIEW)
 3021                            60                 :             44 :             LockViewRecurse(reloid, lockstmt->mode, lockstmt->nowait, NIL);
 3039                            61         [ +  + ]:           6498 :         else if (recurse)
 2349 fujii@postgresql.org       62                 :           6494 :             LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
                                 63                 :                :     }
 6283 tgl@sss.pgh.pa.us          64                 :            544 : }
                                 65                 :                : 
                                 66                 :                : /*
                                 67                 :                :  * Before acquiring a table lock on the named table, check whether we have
                                 68                 :                :  * permission to do so.
                                 69                 :                :  */
                                 70                 :                : static void
 5351 rhaas@postgresql.org       71                 :           6665 : RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
                                 72                 :                :                              void *arg)
                                 73                 :                : {
 5158 bruce@momjian.us           74                 :           6665 :     LOCKMODE    lockmode = *(LOCKMODE *) arg;
                                 75                 :                :     char        relkind;
                                 76                 :                :     char        relpersistence;
                                 77                 :                :     AclResult   aclresult;
                                 78                 :                : 
 5351 rhaas@postgresql.org       79         [ -  + ]:           6665 :     if (!OidIsValid(relid))
 5158 bruce@momjian.us           80                 :UBC           0 :         return;                 /* doesn't exist, so no permissions check */
 5351 rhaas@postgresql.org       81                 :CBC        6665 :     relkind = get_rel_relkind(relid);
                                 82         [ -  + ]:           6665 :     if (!relkind)
 5158 bruce@momjian.us           83                 :UBC           0 :         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                 :                :      */
 2087 tgl@sss.pgh.pa.us          99   [ +  +  +  +  :CBC        6665 :     if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
                                              -  + ]
                                100                 :                :         relkind != RELKIND_VIEW)
 2087 tgl@sss.pgh.pa.us         101         [ #  # ]:UBC           0 :         ereport(ERROR,
                                102                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                103                 :                :                  errmsg("cannot lock relation \"%s\"",
                                104                 :                :                         rv->relname),
                                105                 :                :                  errdetail_relkind_not_supported(relkind)));
                                106                 :                : 
                                107                 :                :     /*
                                108                 :                :      * Make note if a temporary relation has been accessed in this
                                109                 :                :      * transaction.
                                110                 :                :      */
 2745 michael@paquier.xyz       111                 :CBC        6665 :     relpersistence = get_rel_persistence(relid);
                                112         [ +  + ]:           6665 :     if (relpersistence == RELPERSISTENCE_TEMP)
 2737                           113                 :              6 :         MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
                                114                 :                : 
                                115                 :                :     /* Check permissions. */
 3039 ishii@postgresql.org      116                 :           6665 :     aclresult = LockTableAclCheck(relid, lockmode, GetUserId());
 5351 rhaas@postgresql.org      117         [ +  + ]:           6665 :     if (aclresult != ACLCHECK_OK)
 3157 peter_e@gmx.net           118                 :             32 :         aclcheck_error(aclresult, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
                                119                 :                : }
                                120                 :                : 
                                121                 :                : /*
                                122                 :                :  * Apply LOCK TABLE recursively over an inheritance tree
                                123                 :                :  *
                                124                 :                :  * This doesn't check permission to perform LOCK TABLE on the child tables,
                                125                 :                :  * because getting here means that the user has permission to lock the
                                126                 :                :  * parent which is enough.
                                127                 :                :  */
                                128                 :                : static void
 2349 fujii@postgresql.org      129                 :           6542 : LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
                                130                 :                : {
                                131                 :                :     List       *children;
                                132                 :                :     ListCell   *lc;
                                133                 :                : 
                                134                 :           6542 :     children = find_all_inheritors(reloid, NoLock, NULL);
                                135                 :                : 
 5351 rhaas@postgresql.org      136   [ +  -  +  +  :          15602 :     foreach(lc, children)
                                              +  + ]
                                137                 :                :     {
                                138                 :           9060 :         Oid         childreloid = lfirst_oid(lc);
                                139                 :                : 
                                140                 :                :         /* Parent already locked. */
 2349 fujii@postgresql.org      141         [ +  + ]:           9060 :         if (childreloid == reloid)
                                142                 :           6542 :             continue;
                                143                 :                : 
 5351 rhaas@postgresql.org      144         [ +  + ]:           2518 :         if (!nowait)
                                145                 :           2510 :             LockRelationOid(childreloid, lockmode);
                                146         [ -  + ]:              8 :         else if (!ConditionalLockRelationOid(childreloid, lockmode))
                                147                 :                :         {
                                148                 :                :             /* try to throw error by name; relation could be deleted... */
 5351 rhaas@postgresql.org      149                 :UBC           0 :             char       *relname = get_rel_name(childreloid);
                                150                 :                : 
                                151         [ #  # ]:              0 :             if (!relname)
 5158 bruce@momjian.us          152                 :              0 :                 continue;       /* child concurrently dropped, just skip it */
 5351 rhaas@postgresql.org      153         [ #  # ]:              0 :             ereport(ERROR,
                                154                 :                :                     (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                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                 :                :          */
 5351 rhaas@postgresql.org      163         [ -  + ]:CBC        2518 :         if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(childreloid)))
                                164                 :                :         {
                                165                 :                :             /* Release useless lock */
 5351 rhaas@postgresql.org      166                 :UBC           0 :             UnlockRelationOid(childreloid, lockmode);
                                167                 :              0 :             continue;
                                168                 :                :         }
                                169                 :                :     }
 5351 rhaas@postgresql.org      170                 :CBC        6542 : }
                                171                 :                : 
                                172                 :                : /*
                                173                 :                :  * Apply LOCK TABLE recursively over a view
                                174                 :                :  *
                                175                 :                :  * All tables and views appearing in the view definition query are locked
                                176                 :                :  * recursively with the same lock mode.
                                177                 :                :  */
                                178                 :                : 
                                179                 :                : typedef struct
                                180                 :                : {
                                181                 :                :     LOCKMODE    lockmode;       /* lock mode to use */
                                182                 :                :     bool        nowait;         /* no wait mode */
                                183                 :                :     Oid         check_as_user;  /* user for checking the privilege */
                                184                 :                :     Oid         viewoid;        /* OID of the view to be locked */
                                185                 :                :     List       *ancestor_views; /* OIDs of ancestor views */
                                186                 :                : } LockViewRecurse_context;
                                187                 :                : 
                                188                 :                : static bool
 3039 ishii@postgresql.org      189                 :           1468 : LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
                                190                 :                : {
                                191         [ +  + ]:           1468 :     if (node == NULL)
                                192                 :            960 :         return false;
                                193                 :                : 
                                194         [ +  + ]:            508 :     if (IsA(node, Query))
                                195                 :                :     {
 3021                           196                 :             72 :         Query      *query = (Query *) node;
                                197                 :                :         ListCell   *rtable;
                                198                 :                : 
 3039                           199   [ +  -  +  +  :            148 :         foreach(rtable, query->rtable)
                                              +  + ]
                                200                 :                :         {
 3021                           201                 :             80 :             RangeTblEntry *rte = lfirst(rtable);
                                202                 :                :             AclResult   aclresult;
                                203                 :                : 
 2087 tgl@sss.pgh.pa.us         204                 :             80 :             Oid         relid = rte->relid;
                                205                 :             80 :             char        relkind = rte->relkind;
                                206                 :             80 :             char       *relname = get_rel_name(relid);
                                207                 :                : 
                                208                 :                :             /* Currently, we only allow plain tables or views to be locked. */
                                209   [ +  +  +  -  :             80 :             if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
                                              +  + ]
                                210                 :                :                 relkind != RELKIND_VIEW)
                                211                 :              4 :                 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                 :                :              */
   23 akapila@postgresql.o      220         [ -  + ]:GNC          76 :             if (IsConflictLogTableNamespace(get_rel_namespace(relid)))
   23 akapila@postgresql.o      221                 :UNC           0 :                 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                 :                :              */
 3021 ishii@postgresql.org      227         [ +  + ]:CBC          76 :             if (list_member_oid(context->ancestor_views, relid))
 2088 tgl@sss.pgh.pa.us         228                 :              8 :                 continue;
                                229                 :                : 
                                230                 :                :             /*
                                231                 :                :              * Check permissions as the specified user.  This will either be
                                232                 :                :              * the view owner or the current user.
                                233                 :                :              */
 1586 dean.a.rasheed@gmail      234                 :             68 :             aclresult = LockTableAclCheck(relid, context->lockmode,
                                235                 :                :                                           context->check_as_user);
 3039 ishii@postgresql.org      236         [ +  + ]:             68 :             if (aclresult != ACLCHECK_OK)
 2087 tgl@sss.pgh.pa.us         237                 :              4 :                 aclcheck_error(aclresult, get_relkind_objtype(relkind), relname);
                                238                 :                : 
                                239                 :                :             /* We have enough rights to lock the relation; do so. */
 3039 ishii@postgresql.org      240         [ +  - ]:             64 :             if (!context->nowait)
                                241                 :             64 :                 LockRelationOid(relid, context->lockmode);
 3039 ishii@postgresql.org      242         [ #  # ]:UBC           0 :             else if (!ConditionalLockRelationOid(relid, context->lockmode))
                                243         [ #  # ]:              0 :                 ereport(ERROR,
                                244                 :                :                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                245                 :                :                          errmsg("could not obtain lock on relation \"%s\"",
                                246                 :                :                                 relname)));
                                247                 :                : 
 2087 tgl@sss.pgh.pa.us         248         [ +  + ]:CBC          64 :             if (relkind == RELKIND_VIEW)
 2088                           249                 :             16 :                 LockViewRecurse(relid, context->lockmode, context->nowait,
                                250                 :                :                                 context->ancestor_views);
 3039 ishii@postgresql.org      251         [ +  - ]:             48 :             else if (rte->inh)
 2349 fujii@postgresql.org      252                 :             48 :                 LockTableRecurse(relid, context->lockmode, context->nowait);
                                253                 :                :         }
                                254                 :                : 
 3039 ishii@postgresql.org      255                 :             68 :         return query_tree_walker(query,
                                256                 :                :                                  LockViewRecurse_walker,
                                257                 :                :                                  context,
                                258                 :                :                                  QTW_IGNORE_JOINALIASES);
                                259                 :                :     }
                                260                 :                : 
                                261                 :            436 :     return expression_tree_walker(node,
                                262                 :                :                                   LockViewRecurse_walker,
                                263                 :                :                                   context);
                                264                 :                : }
                                265                 :                : 
                                266                 :                : static void
 2088 tgl@sss.pgh.pa.us         267                 :             60 : LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait,
                                268                 :                :                 List *ancestor_views)
                                269                 :                : {
                                270                 :                :     LockViewRecurse_context context;
                                271                 :                :     Relation    view;
                                272                 :                :     Query      *viewquery;
                                273                 :                : 
                                274                 :                :     /* caller has already locked the view */
 2742 andres@anarazel.de        275                 :             60 :     view = table_open(reloid, NoLock);
 3039 ishii@postgresql.org      276                 :             60 :     viewquery = get_view_query(view);
                                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                 :             60 :     context.lockmode = lockmode;
                                283                 :             60 :     context.nowait = nowait;
 1586 dean.a.rasheed@gmail      284   [ -  +  +  +  :             60 :     if (RelationHasSecurityInvoker(view))
                                              +  - ]
                                285                 :              8 :         context.check_as_user = GetUserId();
                                286                 :                :     else
                                287                 :             52 :         context.check_as_user = view->rd_rel->relowner;
 3039 ishii@postgresql.org      288                 :             60 :     context.viewoid = reloid;
 2565 tgl@sss.pgh.pa.us         289                 :             60 :     context.ancestor_views = lappend_oid(ancestor_views, reloid);
                                290                 :                : 
 3039 ishii@postgresql.org      291                 :             60 :     LockViewRecurse_walker((Node *) viewquery, &context);
                                292                 :                : 
 2107 peter@eisentraut.org      293                 :             56 :     context.ancestor_views = list_delete_last(context.ancestor_views);
                                294                 :                : 
 2742 andres@anarazel.de        295                 :             56 :     table_close(view, NoLock);
 3039 ishii@postgresql.org      296                 :             56 : }
                                297                 :                : 
                                298                 :                : /*
                                299                 :                :  * Check whether the current user is permitted to lock this relation.
                                300                 :                :  */
                                301                 :                : static AclResult
                                302                 :           6733 : LockTableAclCheck(Oid reloid, LOCKMODE lockmode, Oid userid)
                                303                 :                : {
                                304                 :                :     AclResult   aclresult;
                                305                 :                :     AclMode     aclmask;
                                306                 :                : 
                                307                 :                :     /* any of these privileges permit any lock mode */
  864 nathan@postgresql.or      308                 :           6733 :     aclmask = ACL_MAINTAIN | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
                                309                 :                : 
                                310                 :                :     /* SELECT privileges also permit ACCESS SHARE and below */
 1289 jdavis@postgresql.or      311         [ +  + ]:           6733 :     if (lockmode <= AccessShareLock)
                                312                 :           6240 :         aclmask |= ACL_SELECT;
                                313                 :                : 
                                314                 :                :     /* INSERT privileges also permit ROW EXCLUSIVE and below */
                                315         [ +  + ]:           6733 :     if (lockmode <= RowExclusiveLock)
                                316                 :           6310 :         aclmask |= ACL_INSERT;
                                317                 :                : 
 3039 ishii@postgresql.org      318                 :           6733 :     aclresult = pg_class_aclcheck(reloid, userid, aclmask);
                                319                 :                : 
 5351 rhaas@postgresql.org      320                 :           6733 :     return aclresult;
                                321                 :                : }
        

Generated by: LCOV version 2.0-1