Branch data 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 : 20 : LargeObjectCreate(Oid loid)
39 : : {
40 : 20 : Relation pg_lo_meta;
41 : 20 : HeapTuple ntup;
42 : 20 : Oid loid_new;
43 : 20 : Datum values[Natts_pg_largeobject_metadata];
44 : 20 : bool nulls[Natts_pg_largeobject_metadata];
45 : 20 : Oid ownerId;
46 : 20 : Acl *lomacl;
47 : :
48 : 20 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
49 : : RowExclusiveLock);
50 : :
51 : : /*
52 : : * Insert metadata of the largeobject
53 : : */
54 : 20 : memset(values, 0, sizeof(values));
55 : 20 : memset(nulls, false, sizeof(nulls));
56 : :
57 [ + + ]: 20 : if (OidIsValid(loid))
58 : 13 : loid_new = loid;
59 : : else
60 : 7 : loid_new = GetNewOidWithIndex(pg_lo_meta,
61 : : LargeObjectMetadataOidIndexId,
62 : : Anum_pg_largeobject_metadata_oid);
63 : 20 : ownerId = GetUserId();
64 : 20 : lomacl = get_user_default_acl(OBJECT_LARGEOBJECT, ownerId, InvalidOid);
65 : :
66 : 20 : values[Anum_pg_largeobject_metadata_oid - 1] = ObjectIdGetDatum(loid_new);
67 : 20 : values[Anum_pg_largeobject_metadata_lomowner - 1]
68 : 40 : = ObjectIdGetDatum(ownerId);
69 : :
70 [ + + ]: 20 : if (lomacl != NULL)
71 : 6 : values[Anum_pg_largeobject_metadata_lomacl - 1]
72 : 6 : = PointerGetDatum(lomacl);
73 : : else
74 : 17 : nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
75 : :
76 : 40 : ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
77 : 20 : values, nulls);
78 : :
79 : 20 : CatalogTupleInsert(pg_lo_meta, ntup);
80 : :
81 : 20 : heap_freetuple(ntup);
82 : :
83 : 20 : table_close(pg_lo_meta, RowExclusiveLock);
84 : :
85 : : /* dependencies on roles mentioned in default ACL */
86 : 40 : recordDependencyOnNewAcl(LargeObjectRelationId, loid_new, 0,
87 : 20 : ownerId, lomacl);
88 : :
89 : 40 : return loid_new;
90 : 20 : }
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 : 14 : LargeObjectDrop(Oid loid)
98 : : {
99 : 14 : Relation pg_lo_meta;
100 : 14 : Relation pg_largeobject;
101 : 14 : ScanKeyData skey[1];
102 : 14 : SysScanDesc scan;
103 : 14 : HeapTuple tuple;
104 : :
105 : 14 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
106 : : RowExclusiveLock);
107 : :
108 : 14 : pg_largeobject = table_open(LargeObjectRelationId,
109 : : RowExclusiveLock);
110 : :
111 : : /*
112 : : * Delete an entry from pg_largeobject_metadata
113 : : */
114 : 28 : ScanKeyInit(&skey[0],
115 : : Anum_pg_largeobject_metadata_oid,
116 : : BTEqualStrategyNumber, F_OIDEQ,
117 : 14 : ObjectIdGetDatum(loid));
118 : :
119 : 28 : scan = systable_beginscan(pg_lo_meta,
120 : : LargeObjectMetadataOidIndexId, true,
121 : 14 : NULL, 1, skey);
122 : :
123 : 14 : tuple = systable_getnext(scan);
124 [ + - ]: 14 : if (!HeapTupleIsValid(tuple))
125 [ # # # # ]: 0 : ereport(ERROR,
126 : : (errcode(ERRCODE_UNDEFINED_OBJECT),
127 : : errmsg("large object %u does not exist", loid)));
128 : :
129 : 14 : CatalogTupleDelete(pg_lo_meta, &tuple->t_self);
130 : :
131 : 14 : systable_endscan(scan);
132 : :
133 : : /*
134 : : * Delete all the associated entries from pg_largeobject
135 : : */
136 : 28 : ScanKeyInit(&skey[0],
137 : : Anum_pg_largeobject_loid,
138 : : BTEqualStrategyNumber, F_OIDEQ,
139 : 14 : ObjectIdGetDatum(loid));
140 : :
141 : 28 : scan = systable_beginscan(pg_largeobject,
142 : : LargeObjectLOidPNIndexId, true,
143 : 14 : NULL, 1, skey);
144 [ + + ]: 1335 : while (HeapTupleIsValid(tuple = systable_getnext(scan)))
145 : : {
146 : 1321 : CatalogTupleDelete(pg_largeobject, &tuple->t_self);
147 : : }
148 : :
149 : 14 : systable_endscan(scan);
150 : :
151 : 14 : table_close(pg_largeobject, RowExclusiveLock);
152 : :
153 : 14 : table_close(pg_lo_meta, RowExclusiveLock);
154 : 14 : }
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 : 37 : LargeObjectExists(Oid loid)
170 : : {
171 : 37 : return LargeObjectExistsWithSnapshot(loid, NULL);
172 : : }
173 : :
174 : : /*
175 : : * Same as LargeObjectExists(), except snapshot to read with can be specified.
176 : : */
177 : : bool
178 : 122 : LargeObjectExistsWithSnapshot(Oid loid, Snapshot snapshot)
179 : : {
180 : 122 : Relation pg_lo_meta;
181 : 122 : ScanKeyData skey[1];
182 : 122 : SysScanDesc sd;
183 : 122 : HeapTuple tuple;
184 : 122 : bool retval = false;
185 : :
186 : 244 : ScanKeyInit(&skey[0],
187 : : Anum_pg_largeobject_metadata_oid,
188 : : BTEqualStrategyNumber, F_OIDEQ,
189 : 122 : ObjectIdGetDatum(loid));
190 : :
191 : 122 : pg_lo_meta = table_open(LargeObjectMetadataRelationId,
192 : : AccessShareLock);
193 : :
194 : 244 : sd = systable_beginscan(pg_lo_meta,
195 : : LargeObjectMetadataOidIndexId, true,
196 : 122 : snapshot, 1, skey);
197 : :
198 : 122 : tuple = systable_getnext(sd);
199 [ + + ]: 122 : if (HeapTupleIsValid(tuple))
200 : 115 : retval = true;
201 : :
202 : 122 : systable_endscan(sd);
203 : :
204 : 122 : table_close(pg_lo_meta, AccessShareLock);
205 : :
206 : 244 : return retval;
207 : 122 : }
|