LCOV - differential code coverage report
Current view: top level - src/backend/commands - lockcmds.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 88.2 % 93 82 11 1 81 1
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 6 6 1 5
Baseline: 16@8cea358b128 Branches: 73.3 % 86 63 23 63
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 1 1 1
(240..) days: 88.0 % 92 81 11 81
Function coverage date bins:
(240..) days: 100.0 % 6 6 1 5
Branch coverage date bins:
(240..) 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-2024, 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
 8035 tgl@sss.pgh.pa.us          41                 :CBC         573 : 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   [ +  -  +  +  :           5783 :     foreach(p, lockstmt->relations)
                                              +  + ]
                                 49                 :                :     {
 4664 rhaas@postgresql.org       50                 :           5248 :         RangeVar   *rv = (RangeVar *) lfirst(p);
 2669 tgl@sss.pgh.pa.us          51                 :           5248 :         bool        recurse = rv->inh;
                                 52                 :                :         Oid         reloid;
                                 53                 :                : 
 2207 andres@anarazel.de         54                 :           5248 :         reloid = RangeVarGetRelidExtended(rv, lockstmt->mode,
                                 55                 :           5248 :                                           lockstmt->nowait ? RVR_NOWAIT : 0,
                                 56                 :                :                                           RangeVarCallbackForLockTable,
 4519 rhaas@postgresql.org       57         [ +  + ]:           5248 :                                           (void *) &lockstmt->mode);
                                 58                 :                : 
 2207 ishii@postgresql.org       59         [ +  + ]:           5213 :         if (get_rel_relkind(reloid) == RELKIND_VIEW)
 2189                            60                 :             33 :             LockViewRecurse(reloid, lockstmt->mode, lockstmt->nowait, NIL);
 2207                            61         [ +  + ]:           5180 :         else if (recurse)
 1517 fujii@postgresql.org       62                 :           5177 :             LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
                                 63                 :                :     }
 5451 tgl@sss.pgh.pa.us          64                 :            535 : }
                                 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
 4519 rhaas@postgresql.org       71                 :           5292 : RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
                                 72                 :                :                              void *arg)
                                 73                 :                : {
 4326 bruce@momjian.us           74                 :           5292 :     LOCKMODE    lockmode = *(LOCKMODE *) arg;
                                 75                 :                :     char        relkind;
                                 76                 :                :     char        relpersistence;
                                 77                 :                :     AclResult   aclresult;
                                 78                 :                : 
 4519 rhaas@postgresql.org       79         [ -  + ]:           5292 :     if (!OidIsValid(relid))
 4326 bruce@momjian.us           80                 :UBC           0 :         return;                 /* doesn't exist, so no permissions check */
 4519 rhaas@postgresql.org       81                 :CBC        5292 :     relkind = get_rel_relkind(relid);
                                 82         [ -  + ]:           5292 :     if (!relkind)
 4326 bruce@momjian.us           83                 :UBC           0 :         return;                 /* woops, concurrently dropped; no permissions
                                 84                 :                :                                  * check */
                                 85                 :                : 
                                 86                 :                :     /* Currently, we only allow plain tables or views to be locked */
 1255 tgl@sss.pgh.pa.us          87   [ +  +  +  +  :CBC        5292 :     if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
                                              -  + ]
                                 88                 :                :         relkind != RELKIND_VIEW)
 1255 tgl@sss.pgh.pa.us          89         [ #  # ]:UBC           0 :         ereport(ERROR,
                                 90                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                 91                 :                :                  errmsg("cannot lock relation \"%s\"",
                                 92                 :                :                         rv->relname),
                                 93                 :                :                  errdetail_relkind_not_supported(relkind)));
                                 94                 :                : 
                                 95                 :                :     /*
                                 96                 :                :      * Make note if a temporary relation has been accessed in this
                                 97                 :                :      * transaction.
                                 98                 :                :      */
 1913 michael@paquier.xyz        99                 :CBC        5292 :     relpersistence = get_rel_persistence(relid);
                                100         [ +  + ]:           5292 :     if (relpersistence == RELPERSISTENCE_TEMP)
 1905                           101                 :              5 :         MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
                                102                 :                : 
                                103                 :                :     /* Check permissions. */
 2207 ishii@postgresql.org      104                 :           5292 :     aclresult = LockTableAclCheck(relid, lockmode, GetUserId());
 4519 rhaas@postgresql.org      105         [ +  + ]:           5292 :     if (aclresult != ACLCHECK_OK)
 2325 peter_e@gmx.net           106                 :             24 :         aclcheck_error(aclresult, get_relkind_objtype(get_rel_relkind(relid)), rv->relname);
                                107                 :                : }
                                108                 :                : 
                                109                 :                : /*
                                110                 :                :  * Apply LOCK TABLE recursively over an inheritance tree
                                111                 :                :  *
                                112                 :                :  * This doesn't check permission to perform LOCK TABLE on the child tables,
                                113                 :                :  * because getting here means that the user has permission to lock the
                                114                 :                :  * parent which is enough.
                                115                 :                :  */
                                116                 :                : static void
 1517 fujii@postgresql.org      117                 :           5213 : LockTableRecurse(Oid reloid, LOCKMODE lockmode, bool nowait)
                                118                 :                : {
                                119                 :                :     List       *children;
                                120                 :                :     ListCell   *lc;
                                121                 :                : 
                                122                 :           5213 :     children = find_all_inheritors(reloid, NoLock, NULL);
                                123                 :                : 
 4519 rhaas@postgresql.org      124   [ +  -  +  +  :          12448 :     foreach(lc, children)
                                              +  + ]
                                125                 :                :     {
                                126                 :           7235 :         Oid         childreloid = lfirst_oid(lc);
                                127                 :                : 
                                128                 :                :         /* Parent already locked. */
 1517 fujii@postgresql.org      129         [ +  + ]:           7235 :         if (childreloid == reloid)
                                130                 :           5213 :             continue;
                                131                 :                : 
 4519 rhaas@postgresql.org      132         [ +  + ]:           2022 :         if (!nowait)
                                133                 :           2010 :             LockRelationOid(childreloid, lockmode);
                                134         [ -  + ]:             12 :         else if (!ConditionalLockRelationOid(childreloid, lockmode))
                                135                 :                :         {
                                136                 :                :             /* try to throw error by name; relation could be deleted... */
 4519 rhaas@postgresql.org      137                 :UBC           0 :             char       *relname = get_rel_name(childreloid);
                                138                 :                : 
                                139         [ #  # ]:              0 :             if (!relname)
 4326 bruce@momjian.us          140                 :              0 :                 continue;       /* child concurrently dropped, just skip it */
 4519 rhaas@postgresql.org      141         [ #  # ]:              0 :             ereport(ERROR,
                                142                 :                :                     (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                143                 :                :                      errmsg("could not obtain lock on relation \"%s\"",
                                144                 :                :                             relname)));
                                145                 :                :         }
                                146                 :                : 
                                147                 :                :         /*
                                148                 :                :          * Even if we got the lock, child might have been concurrently
                                149                 :                :          * dropped. If so, we can skip it.
                                150                 :                :          */
 4519 rhaas@postgresql.org      151         [ -  + ]:CBC        2022 :         if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(childreloid)))
                                152                 :                :         {
                                153                 :                :             /* Release useless lock */
 4519 rhaas@postgresql.org      154                 :UBC           0 :             UnlockRelationOid(childreloid, lockmode);
                                155                 :              0 :             continue;
                                156                 :                :         }
                                157                 :                :     }
 4519 rhaas@postgresql.org      158                 :CBC        5213 : }
                                159                 :                : 
                                160                 :                : /*
                                161                 :                :  * Apply LOCK TABLE recursively over a view
                                162                 :                :  *
                                163                 :                :  * All tables and views appearing in the view definition query are locked
                                164                 :                :  * recursively with the same lock mode.
                                165                 :                :  */
                                166                 :                : 
                                167                 :                : typedef struct
                                168                 :                : {
                                169                 :                :     LOCKMODE    lockmode;       /* lock mode to use */
                                170                 :                :     bool        nowait;         /* no wait mode */
                                171                 :                :     Oid         check_as_user;  /* user for checking the privilege */
                                172                 :                :     Oid         viewoid;        /* OID of the view to be locked */
                                173                 :                :     List       *ancestor_views; /* OIDs of ancestor views */
                                174                 :                : } LockViewRecurse_context;
                                175                 :                : 
                                176                 :                : static bool
 2207 ishii@postgresql.org      177                 :           1050 : LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
                                178                 :                : {
                                179         [ +  + ]:           1050 :     if (node == NULL)
                                180                 :            669 :         return false;
                                181                 :                : 
                                182         [ +  + ]:            381 :     if (IsA(node, Query))
                                183                 :                :     {
 2189                           184                 :             54 :         Query      *query = (Query *) node;
                                185                 :                :         ListCell   *rtable;
                                186                 :                : 
 2207                           187   [ +  -  +  +  :            111 :         foreach(rtable, query->rtable)
                                              +  + ]
                                188                 :                :         {
 2189                           189                 :             60 :             RangeTblEntry *rte = lfirst(rtable);
                                190                 :                :             AclResult   aclresult;
                                191                 :                : 
 1255 tgl@sss.pgh.pa.us         192                 :             60 :             Oid         relid = rte->relid;
                                193                 :             60 :             char        relkind = rte->relkind;
                                194                 :             60 :             char       *relname = get_rel_name(relid);
                                195                 :                : 
                                196                 :                :             /* Currently, we only allow plain tables or views to be locked. */
                                197   [ +  +  +  -  :             60 :             if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
                                              +  + ]
                                198                 :                :                 relkind != RELKIND_VIEW)
                                199                 :              3 :                 continue;
                                200                 :                : 
                                201                 :                :             /*
                                202                 :                :              * We might be dealing with a self-referential view.  If so, we
                                203                 :                :              * can just stop recursing, since we already locked it.
                                204                 :                :              */
 2189 ishii@postgresql.org      205         [ +  + ]:             57 :             if (list_member_oid(context->ancestor_views, relid))
 1256 tgl@sss.pgh.pa.us         206                 :              6 :                 continue;
                                207                 :                : 
                                208                 :                :             /*
                                209                 :                :              * Check permissions as the specified user.  This will either be
                                210                 :                :              * the view owner or the current user.
                                211                 :                :              */
  754 dean.a.rasheed@gmail      212                 :             51 :             aclresult = LockTableAclCheck(relid, context->lockmode,
                                213                 :                :                                           context->check_as_user);
 2207 ishii@postgresql.org      214         [ +  + ]:             51 :             if (aclresult != ACLCHECK_OK)
 1255 tgl@sss.pgh.pa.us         215                 :              3 :                 aclcheck_error(aclresult, get_relkind_objtype(relkind), relname);
                                216                 :                : 
                                217                 :                :             /* We have enough rights to lock the relation; do so. */
 2207 ishii@postgresql.org      218         [ +  - ]:             48 :             if (!context->nowait)
                                219                 :             48 :                 LockRelationOid(relid, context->lockmode);
 2207 ishii@postgresql.org      220         [ #  # ]:UBC           0 :             else if (!ConditionalLockRelationOid(relid, context->lockmode))
                                221         [ #  # ]:              0 :                 ereport(ERROR,
                                222                 :                :                         (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
                                223                 :                :                          errmsg("could not obtain lock on relation \"%s\"",
                                224                 :                :                                 relname)));
                                225                 :                : 
 1255 tgl@sss.pgh.pa.us         226         [ +  + ]:CBC          48 :             if (relkind == RELKIND_VIEW)
 1256                           227                 :             12 :                 LockViewRecurse(relid, context->lockmode, context->nowait,
                                228                 :                :                                 context->ancestor_views);
 2207 ishii@postgresql.org      229         [ +  - ]:             36 :             else if (rte->inh)
 1517 fujii@postgresql.org      230                 :             36 :                 LockTableRecurse(relid, context->lockmode, context->nowait);
                                231                 :                :         }
                                232                 :                : 
 2207 ishii@postgresql.org      233                 :             51 :         return query_tree_walker(query,
                                234                 :                :                                  LockViewRecurse_walker,
                                235                 :                :                                  context,
                                236                 :                :                                  QTW_IGNORE_JOINALIASES);
                                237                 :                :     }
                                238                 :                : 
                                239                 :            327 :     return expression_tree_walker(node,
                                240                 :                :                                   LockViewRecurse_walker,
                                241                 :                :                                   context);
                                242                 :                : }
                                243                 :                : 
                                244                 :                : static void
 1256 tgl@sss.pgh.pa.us         245                 :             45 : LockViewRecurse(Oid reloid, LOCKMODE lockmode, bool nowait,
                                246                 :                :                 List *ancestor_views)
                                247                 :                : {
                                248                 :                :     LockViewRecurse_context context;
                                249                 :                :     Relation    view;
                                250                 :                :     Query      *viewquery;
                                251                 :                : 
                                252                 :                :     /* caller has already locked the view */
 1910 andres@anarazel.de        253                 :             45 :     view = table_open(reloid, NoLock);
 2207 ishii@postgresql.org      254                 :             45 :     viewquery = get_view_query(view);
                                255                 :                : 
                                256                 :                :     /*
                                257                 :                :      * If the view has the security_invoker property set, check permissions as
                                258                 :                :      * the current user.  Otherwise, check permissions as the view owner.
                                259                 :                :      */
                                260                 :             45 :     context.lockmode = lockmode;
                                261                 :             45 :     context.nowait = nowait;
  754 dean.a.rasheed@gmail      262   [ -  +  +  +  :             45 :     if (RelationHasSecurityInvoker(view))
                                              +  - ]
                                263                 :              6 :         context.check_as_user = GetUserId();
                                264                 :                :     else
                                265                 :             39 :         context.check_as_user = view->rd_rel->relowner;
 2207 ishii@postgresql.org      266                 :             45 :     context.viewoid = reloid;
 1733 tgl@sss.pgh.pa.us         267                 :             45 :     context.ancestor_views = lappend_oid(ancestor_views, reloid);
                                268                 :                : 
 2207 ishii@postgresql.org      269                 :             45 :     LockViewRecurse_walker((Node *) viewquery, &context);
                                270                 :                : 
 1275 peter@eisentraut.org      271                 :             42 :     context.ancestor_views = list_delete_last(context.ancestor_views);
                                272                 :                : 
 1910 andres@anarazel.de        273                 :             42 :     table_close(view, NoLock);
 2207 ishii@postgresql.org      274                 :             42 : }
                                275                 :                : 
                                276                 :                : /*
                                277                 :                :  * Check whether the current user is permitted to lock this relation.
                                278                 :                :  */
                                279                 :                : static AclResult
                                280                 :           5343 : LockTableAclCheck(Oid reloid, LOCKMODE lockmode, Oid userid)
                                281                 :                : {
                                282                 :                :     AclResult   aclresult;
                                283                 :                :     AclMode     aclmask;
                                284                 :                : 
                                285                 :                :     /* any of these privileges permit any lock mode */
   32 nathan@postgresql.or      286                 :GNC        5343 :     aclmask = ACL_MAINTAIN | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
                                287                 :                : 
                                288                 :                :     /* SELECT privileges also permit ACCESS SHARE and below */
  457 jdavis@postgresql.or      289         [ +  + ]:CBC        5343 :     if (lockmode <= AccessShareLock)
                                290                 :           4959 :         aclmask |= ACL_SELECT;
                                291                 :                : 
                                292                 :                :     /* INSERT privileges also permit ROW EXCLUSIVE and below */
                                293         [ +  + ]:           5343 :     if (lockmode <= RowExclusiveLock)
                                294                 :           5015 :         aclmask |= ACL_INSERT;
                                295                 :                : 
 2207 ishii@postgresql.org      296                 :           5343 :     aclresult = pg_class_aclcheck(reloid, userid, aclmask);
                                297                 :                : 
 4519 rhaas@postgresql.org      298                 :           5343 :     return aclresult;
                                299                 :                : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622