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