1 /*-------------------------------------------------------------------------
4 * routines to support manipulation of the pg_largeobject relation
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/catalog/pg_largeobject.c
13 *-------------------------------------------------------------------------
17 #include "access/genam.h"
18 #include "access/heapam.h"
19 #include "access/sysattr.h"
20 #include "catalog/catalog.h"
21 #include "catalog/dependency.h"
22 #include "catalog/indexing.h"
23 #include "catalog/pg_authid.h"
24 #include "catalog/pg_largeobject.h"
25 #include "catalog/pg_largeobject_metadata.h"
26 #include "catalog/toasting.h"
27 #include "miscadmin.h"
28 #include "utils/acl.h"
29 #include "utils/bytea.h"
30 #include "utils/fmgroids.h"
31 #include "utils/rel.h"
32 #include "utils/tqual.h"
36 * Create a large object having the given LO identifier.
38 * We create a new large object by inserting an entry into
39 * pg_largeobject_metadata without any data pages, so that the object
40 * will appear to exist with size 0.
43 LargeObjectCreate(Oid loid)
48 Datum values[Natts_pg_largeobject_metadata];
49 bool nulls[Natts_pg_largeobject_metadata];
51 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
55 * Insert metadata of the largeobject
57 memset(values, 0, sizeof(values));
58 memset(nulls, false, sizeof(nulls));
60 values[Anum_pg_largeobject_metadata_lomowner - 1]
61 = ObjectIdGetDatum(GetUserId());
62 nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
64 ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
67 HeapTupleSetOid(ntup, loid);
69 loid_new = simple_heap_insert(pg_lo_meta, ntup);
70 Assert(!OidIsValid(loid) || loid == loid_new);
72 CatalogUpdateIndexes(pg_lo_meta, ntup);
76 heap_close(pg_lo_meta, RowExclusiveLock);
82 * Drop a large object having the given LO identifier. Both the data pages
83 * and metadata must be dropped.
86 LargeObjectDrop(Oid loid)
89 Relation pg_largeobject;
94 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
97 pg_largeobject = heap_open(LargeObjectRelationId,
101 * Delete an entry from pg_largeobject_metadata
103 ScanKeyInit(&skey[0],
104 ObjectIdAttributeNumber,
105 BTEqualStrategyNumber, F_OIDEQ,
106 ObjectIdGetDatum(loid));
108 scan = systable_beginscan(pg_lo_meta,
109 LargeObjectMetadataOidIndexId, true,
110 SnapshotNow, 1, skey);
112 tuple = systable_getnext(scan);
113 if (!HeapTupleIsValid(tuple))
115 (errcode(ERRCODE_UNDEFINED_OBJECT),
116 errmsg("large object %u does not exist", loid)));
118 simple_heap_delete(pg_lo_meta, &tuple->t_self);
120 systable_endscan(scan);
123 * Delete all the associated entries from pg_largeobject
125 ScanKeyInit(&skey[0],
126 Anum_pg_largeobject_loid,
127 BTEqualStrategyNumber, F_OIDEQ,
128 ObjectIdGetDatum(loid));
130 scan = systable_beginscan(pg_largeobject,
131 LargeObjectLOidPNIndexId, true,
132 SnapshotNow, 1, skey);
133 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
135 simple_heap_delete(pg_largeobject, &tuple->t_self);
138 systable_endscan(scan);
140 heap_close(pg_largeobject, RowExclusiveLock);
142 heap_close(pg_lo_meta, RowExclusiveLock);
146 * LargeObjectAlterOwner
148 * Implementation of ALTER LARGE OBJECT statement
151 LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
153 Form_pg_largeobject_metadata form_lo_meta;
160 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
163 ScanKeyInit(&skey[0],
164 ObjectIdAttributeNumber,
165 BTEqualStrategyNumber, F_OIDEQ,
166 ObjectIdGetDatum(loid));
168 scan = systable_beginscan(pg_lo_meta,
169 LargeObjectMetadataOidIndexId, true,
170 SnapshotNow, 1, skey);
172 oldtup = systable_getnext(scan);
173 if (!HeapTupleIsValid(oldtup))
175 (errcode(ERRCODE_UNDEFINED_OBJECT),
176 errmsg("large object %u does not exist", loid)));
178 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(oldtup);
179 if (form_lo_meta->lomowner != newOwnerId)
181 Datum values[Natts_pg_largeobject_metadata];
182 bool nulls[Natts_pg_largeobject_metadata];
183 bool replaces[Natts_pg_largeobject_metadata];
188 /* Superusers can always do it */
192 * lo_compat_privileges is not checked here, because ALTER LARGE
193 * OBJECT ... OWNER did not exist at all prior to PostgreSQL 9.0.
195 * We must be the owner of the existing object.
197 if (!pg_largeobject_ownercheck(loid, GetUserId()))
199 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
200 errmsg("must be owner of large object %u", loid)));
202 /* Must be able to become new owner */
203 check_is_member_of_role(GetUserId(), newOwnerId);
206 memset(values, 0, sizeof(values));
207 memset(nulls, false, sizeof(nulls));
208 memset(replaces, false, sizeof(nulls));
210 values[Anum_pg_largeobject_metadata_lomowner - 1]
211 = ObjectIdGetDatum(newOwnerId);
212 replaces[Anum_pg_largeobject_metadata_lomowner - 1] = true;
215 * Determine the modified ACL for the new owner. This is only
216 * necessary when the ACL is non-null.
218 aclDatum = heap_getattr(oldtup,
219 Anum_pg_largeobject_metadata_lomacl,
220 RelationGetDescr(pg_lo_meta), &isnull);
223 newAcl = aclnewowner(DatumGetAclP(aclDatum),
224 form_lo_meta->lomowner, newOwnerId);
225 values[Anum_pg_largeobject_metadata_lomacl - 1]
226 = PointerGetDatum(newAcl);
227 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
230 newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_lo_meta),
231 values, nulls, replaces);
233 simple_heap_update(pg_lo_meta, &newtup->t_self, newtup);
234 CatalogUpdateIndexes(pg_lo_meta, newtup);
236 heap_freetuple(newtup);
238 /* Update owner dependency reference */
239 changeDependencyOnOwner(LargeObjectRelationId,
242 systable_endscan(scan);
244 heap_close(pg_lo_meta, RowExclusiveLock);
250 * We don't use the system cache for large object metadata, for fear of
251 * using too much local memory.
253 * This function always scans the system catalog using SnapshotNow, so it
254 * should not be used when a large object is opened in read-only mode (because
255 * large objects opened in read only mode are supposed to be viewed relative
256 * to the caller's snapshot, whereas in read-write mode they are relative to
260 LargeObjectExists(Oid loid)
268 ScanKeyInit(&skey[0],
269 ObjectIdAttributeNumber,
270 BTEqualStrategyNumber, F_OIDEQ,
271 ObjectIdGetDatum(loid));
273 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
276 sd = systable_beginscan(pg_lo_meta,
277 LargeObjectMetadataOidIndexId, true,
278 SnapshotNow, 1, skey);
280 tuple = systable_getnext(sd);
281 if (HeapTupleIsValid(tuple))
284 systable_endscan(sd);
286 heap_close(pg_lo_meta, AccessShareLock);