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