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