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