LCOV - code coverage report
Current view: top level - src/backend/catalog - pg_largeobject.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 98.0 % 51 50
Test Date: 2026-03-14 03:14:36 Functions: 100.0 % 4 4
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           84 : 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           84 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
      49              :                             RowExclusiveLock);
      50              : 
      51              :     /*
      52              :      * Insert metadata of the largeobject
      53              :      */
      54           84 :     memset(values, 0, sizeof(values));
      55           84 :     memset(nulls, false, sizeof(nulls));
      56              : 
      57           84 :     if (OidIsValid(loid))
      58           59 :         loid_new = loid;
      59              :     else
      60           25 :         loid_new = GetNewOidWithIndex(pg_lo_meta,
      61              :                                       LargeObjectMetadataOidIndexId,
      62              :                                       Anum_pg_largeobject_metadata_oid);
      63           84 :     ownerId = GetUserId();
      64           84 :     lomacl = get_user_default_acl(OBJECT_LARGEOBJECT, ownerId, InvalidOid);
      65              : 
      66           84 :     values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new);
      67              :     values[Anum_pg_largeobject_metadata_lomowner - 1]
      68           84 :         = ObjectIdGetDatum(ownerId);
      69              : 
      70           84 :     if (lomacl != NULL)
      71              :         values[Anum_pg_largeobject_metadata_lomacl - 1]
      72            9 :             = PointerGetDatum(lomacl);
      73              :     else
      74           75 :         nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
      75              : 
      76           84 :     ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
      77              :                            values, nulls);
      78              : 
      79           84 :     CatalogTupleInsert(pg_lo_meta, ntup);
      80              : 
      81           84 :     heap_freetuple(ntup);
      82              : 
      83           84 :     table_close(pg_lo_meta, RowExclusiveLock);
      84              : 
      85              :     /* dependencies on roles mentioned in default ACL */
      86           84 :     recordDependencyOnNewAcl(LargeObjectRelationId, loid_new, 0,
      87              :                              ownerId, lomacl);
      88              : 
      89           84 :     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           47 : 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           47 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
     106              :                             RowExclusiveLock);
     107              : 
     108           47 :     pg_largeobject = table_open(LargeObjectRelationId,
     109              :                                 RowExclusiveLock);
     110              : 
     111              :     /*
     112              :      * Delete an entry from pg_largeobject_metadata
     113              :      */
     114           47 :     ScanKeyInit(&skey[0],
     115              :                 Anum_pg_largeobject_metadata_oid,
     116              :                 BTEqualStrategyNumber, F_OIDEQ,
     117              :                 ObjectIdGetDatum(loid));
     118              : 
     119           47 :     scan = systable_beginscan(pg_lo_meta,
     120              :                               LargeObjectMetadataOidIndexId, true,
     121              :                               NULL, 1, skey);
     122              : 
     123           47 :     tuple = systable_getnext(scan);
     124           47 :     if (!HeapTupleIsValid(tuple))
     125            0 :         ereport(ERROR,
     126              :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     127              :                  errmsg("large object %u does not exist", loid)));
     128              : 
     129           47 :     CatalogTupleDelete(pg_lo_meta, &tuple->t_self);
     130              : 
     131           47 :     systable_endscan(scan);
     132              : 
     133              :     /*
     134              :      * Delete all the associated entries from pg_largeobject
     135              :      */
     136           47 :     ScanKeyInit(&skey[0],
     137              :                 Anum_pg_largeobject_loid,
     138              :                 BTEqualStrategyNumber, F_OIDEQ,
     139              :                 ObjectIdGetDatum(loid));
     140              : 
     141           47 :     scan = systable_beginscan(pg_largeobject,
     142              :                               LargeObjectLOidPNIndexId, true,
     143              :                               NULL, 1, skey);
     144         4010 :     while (HeapTupleIsValid(tuple = systable_getnext(scan)))
     145              :     {
     146         3963 :         CatalogTupleDelete(pg_largeobject, &tuple->t_self);
     147              :     }
     148              : 
     149           47 :     systable_endscan(scan);
     150              : 
     151           47 :     table_close(pg_largeobject, RowExclusiveLock);
     152              : 
     153           47 :     table_close(pg_lo_meta, RowExclusiveLock);
     154           47 : }
     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          157 : LargeObjectExists(Oid loid)
     170              : {
     171          157 :     return LargeObjectExistsWithSnapshot(loid, NULL);
     172              : }
     173              : 
     174              : /*
     175              :  * Same as LargeObjectExists(), except snapshot to read with can be specified.
     176              :  */
     177              : bool
     178          561 : LargeObjectExistsWithSnapshot(Oid loid, Snapshot snapshot)
     179              : {
     180              :     Relation    pg_lo_meta;
     181              :     ScanKeyData skey[1];
     182              :     SysScanDesc sd;
     183              :     HeapTuple   tuple;
     184          561 :     bool        retval = false;
     185              : 
     186          561 :     ScanKeyInit(&skey[0],
     187              :                 Anum_pg_largeobject_metadata_oid,
     188              :                 BTEqualStrategyNumber, F_OIDEQ,
     189              :                 ObjectIdGetDatum(loid));
     190              : 
     191          561 :     pg_lo_meta = table_open(LargeObjectMetadataRelationId,
     192              :                             AccessShareLock);
     193              : 
     194          561 :     sd = systable_beginscan(pg_lo_meta,
     195              :                             LargeObjectMetadataOidIndexId, true,
     196              :                             snapshot, 1, skey);
     197              : 
     198          561 :     tuple = systable_getnext(sd);
     199          561 :     if (HeapTupleIsValid(tuple))
     200          525 :         retval = true;
     201              : 
     202          561 :     systable_endscan(sd);
     203              : 
     204          561 :     table_close(pg_lo_meta, AccessShareLock);
     205              : 
     206          561 :     return retval;
     207              : }
        

Generated by: LCOV version 2.0-1