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