LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_largeobject.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 50 51 98.0 %
Date: 2026-01-20 23:17:14 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_largeobject.c
       4             :  *    routines to support manipulation of the pg_largeobject relation
       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/catalog/pg_largeobject.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "access/genam.h"
      18             : #include "access/htup_details.h"
      19             : #include "access/table.h"
      20             : #include "catalog/catalog.h"
      21             : #include "catalog/indexing.h"
      22             : #include "catalog/pg_largeobject.h"
      23             : #include "catalog/pg_largeobject_metadata.h"
      24             : #include "miscadmin.h"
      25             : #include "utils/acl.h"
      26             : #include "utils/fmgroids.h"
      27             : #include "utils/rel.h"
      28             : 
      29             : 
      30             : /*
      31             :  * Create a large object having the given LO identifier.
      32             :  *
      33             :  * We create a new large object by inserting an entry into
      34             :  * pg_largeobject_metadata without any data pages, so that the object
      35             :  * will appear to exist with size 0.
      36             :  */
      37             : Oid
      38         168 : LargeObjectCreate(Oid loid)
      39             : {
      40             :     Relation    pg_lo_meta;
      41             :     HeapTuple   ntup;
      42             :     Oid         loid_new;
      43             :     Datum       values[Natts_pg_largeobject_metadata];
      44             :     bool        nulls[Natts_pg_largeobject_metadata];
      45             :     Oid         ownerId;
      46             :     Acl        *lomacl;
      47             : 
      48         168 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
      49             :                             RowExclusiveLock);
      50             : 
      51             :     /*
      52             :      * Insert metadata of the largeobject
      53             :      */
      54         168 :     memset(values, 0, sizeof(values));
      55         168 :     memset(nulls, false, sizeof(nulls));
      56             : 
      57         168 :     if (OidIsValid(loid))
      58         118 :         loid_new = loid;
      59             :     else
      60          50 :         loid_new = GetNewOidWithIndex(pg_lo_meta,
      61             :                                       LargeObjectMetadataOidIndexId,
      62             :                                       Anum_pg_largeobject_metadata_oid);
      63         168 :     ownerId = GetUserId();
      64         168 :     lomacl = get_user_default_acl(OBJECT_LARGEOBJECT, ownerId, InvalidOid);
      65             : 
      66         168 :     values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new);
      67             :     values[Anum_pg_largeobject_metadata_lomowner - 1]
      68         168 :         = ObjectIdGetDatum(ownerId);
      69             : 
      70         168 :     if (lomacl != NULL)
      71             :         values[Anum_pg_largeobject_metadata_lomacl - 1]
      72          18 :             = PointerGetDatum(lomacl);
      73             :     else
      74         150 :         nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
      75             : 
      76         168 :     ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
      77             :                            values, nulls);
      78             : 
      79         168 :     CatalogTupleInsert(pg_lo_meta, ntup);
      80             : 
      81         168 :     heap_freetuple(ntup);
      82             : 
      83         168 :     table_close(pg_lo_meta, RowExclusiveLock);
      84             : 
      85             :     /* dependencies on roles mentioned in default ACL */
      86         168 :     recordDependencyOnNewAcl(LargeObjectRelationId, loid_new, 0,
      87             :                              ownerId, lomacl);
      88             : 
      89         168 :     return loid_new;
      90             : }
      91             : 
      92             : /*
      93             :  * Drop a large object having the given LO identifier.  Both the data pages
      94             :  * and metadata must be dropped.
      95             :  */
      96             : void
      97          94 : LargeObjectDrop(Oid loid)
      98             : {
      99             :     Relation    pg_lo_meta;
     100             :     Relation    pg_largeobject;
     101             :     ScanKeyData skey[1];
     102             :     SysScanDesc scan;
     103             :     HeapTuple   tuple;
     104             : 
     105          94 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
     106             :                             RowExclusiveLock);
     107             : 
     108          94 :     pg_largeobject = table_open(LargeObjectRelationId,
     109             :                                 RowExclusiveLock);
     110             : 
     111             :     /*
     112             :      * Delete an entry from pg_largeobject_metadata
     113             :      */
     114          94 :     ScanKeyInit(&skey[0],
     115             :                 Anum_pg_largeobject_metadata_oid,
     116             :                 BTEqualStrategyNumber, F_OIDEQ,
     117             :                 ObjectIdGetDatum(loid));
     118             : 
     119          94 :     scan = systable_beginscan(pg_lo_meta,
     120             :                               LargeObjectMetadataOidIndexId, true,
     121             :                               NULL, 1, skey);
     122             : 
     123          94 :     tuple = systable_getnext(scan);
     124          94 :     if (!HeapTupleIsValid(tuple))
     125           0 :         ereport(ERROR,
     126             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     127             :                  errmsg("large object %u does not exist", loid)));
     128             : 
     129          94 :     CatalogTupleDelete(pg_lo_meta, &tuple->t_self);
     130             : 
     131          94 :     systable_endscan(scan);
     132             : 
     133             :     /*
     134             :      * Delete all the associated entries from pg_largeobject
     135             :      */
     136          94 :     ScanKeyInit(&skey[0],
     137             :                 Anum_pg_largeobject_loid,
     138             :                 BTEqualStrategyNumber, F_OIDEQ,
     139             :                 ObjectIdGetDatum(loid));
     140             : 
     141          94 :     scan = systable_beginscan(pg_largeobject,
     142             :                               LargeObjectLOidPNIndexId, true,
     143             :                               NULL, 1, skey);
     144        8020 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
     145             :     {
     146        7926 :         CatalogTupleDelete(pg_largeobject, &tuple->t_self);
     147             :     }
     148             : 
     149          94 :     systable_endscan(scan);
     150             : 
     151          94 :     table_close(pg_largeobject, RowExclusiveLock);
     152             : 
     153          94 :     table_close(pg_lo_meta, RowExclusiveLock);
     154          94 : }
     155             : 
     156             : /*
     157             :  * LargeObjectExists
     158             :  *
     159             :  * We don't use the system cache for large object metadata, for fear of
     160             :  * using too much local memory.
     161             :  *
     162             :  * This function always scans the system catalog using an up-to-date snapshot,
     163             :  * so it should not be used when a large object is opened in read-only mode
     164             :  * (because large objects opened in read only mode are supposed to be viewed
     165             :  * relative to the caller's snapshot, whereas in read-write mode they are
     166             :  * relative to a current snapshot).
     167             :  */
     168             : bool
     169         298 : LargeObjectExists(Oid loid)
     170             : {
     171         298 :     return LargeObjectExistsWithSnapshot(loid, NULL);
     172             : }
     173             : 
     174             : /*
     175             :  * Same as LargeObjectExists(), except snapshot to read with can be specified.
     176             :  */
     177             : bool
     178        1058 : LargeObjectExistsWithSnapshot(Oid loid, Snapshot snapshot)
     179             : {
     180             :     Relation    pg_lo_meta;
     181             :     ScanKeyData skey[1];
     182             :     SysScanDesc sd;
     183             :     HeapTuple   tuple;
     184        1058 :     bool        retval = false;
     185             : 
     186        1058 :     ScanKeyInit(&skey[0],
     187             :                 Anum_pg_largeobject_metadata_oid,
     188             :                 BTEqualStrategyNumber, F_OIDEQ,
     189             :                 ObjectIdGetDatum(loid));
     190             : 
     191        1058 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
     192             :                             AccessShareLock);
     193             : 
     194        1058 :     sd = systable_beginscan(pg_lo_meta,
     195             :                             LargeObjectMetadataOidIndexId, true,
     196             :                             snapshot, 1, skey);
     197             : 
     198        1058 :     tuple = systable_getnext(sd);
     199        1058 :     if (HeapTupleIsValid(tuple))
     200        1006 :         retval = true;
     201             : 
     202        1058 :     systable_endscan(sd);
     203             : 
     204        1058 :     table_close(pg_lo_meta, AccessShareLock);
     205             : 
     206        1058 :     return retval;
     207             : }

Generated by: LCOV version 1.16