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