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