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 : }
|