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/dependency.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 #include "utils/tqual.h"
32 * Create a large object having the given LO identifier.
34 * We create a new large object by inserting an entry into
35 * pg_largeobject_metadata without any data pages, so that the object
36 * will appear to exist with size 0.
39 LargeObjectCreate(Oid loid)
44 Datum values[Natts_pg_largeobject_metadata];
45 bool nulls[Natts_pg_largeobject_metadata];
47 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
51 * Insert metadata of the largeobject
53 memset(values, 0, sizeof(values));
54 memset(nulls, false, sizeof(nulls));
56 values[Anum_pg_largeobject_metadata_lomowner - 1]
57 = ObjectIdGetDatum(GetUserId());
58 nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
60 ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
63 HeapTupleSetOid(ntup, loid);
65 loid_new = simple_heap_insert(pg_lo_meta, ntup);
66 Assert(!OidIsValid(loid) || loid == loid_new);
68 CatalogUpdateIndexes(pg_lo_meta, ntup);
72 heap_close(pg_lo_meta, RowExclusiveLock);
78 * Drop a large object having the given LO identifier. Both the data pages
79 * and metadata must be dropped.
82 LargeObjectDrop(Oid loid)
85 Relation pg_largeobject;
90 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
93 pg_largeobject = heap_open(LargeObjectRelationId,
97 * Delete an entry from pg_largeobject_metadata
100 ObjectIdAttributeNumber,
101 BTEqualStrategyNumber, F_OIDEQ,
102 ObjectIdGetDatum(loid));
104 scan = systable_beginscan(pg_lo_meta,
105 LargeObjectMetadataOidIndexId, true,
106 SnapshotNow, 1, skey);
108 tuple = systable_getnext(scan);
109 if (!HeapTupleIsValid(tuple))
111 (errcode(ERRCODE_UNDEFINED_OBJECT),
112 errmsg("large object %u does not exist", loid)));
114 simple_heap_delete(pg_lo_meta, &tuple->t_self);
116 systable_endscan(scan);
119 * Delete all the associated entries from pg_largeobject
121 ScanKeyInit(&skey[0],
122 Anum_pg_largeobject_loid,
123 BTEqualStrategyNumber, F_OIDEQ,
124 ObjectIdGetDatum(loid));
126 scan = systable_beginscan(pg_largeobject,
127 LargeObjectLOidPNIndexId, true,
128 SnapshotNow, 1, skey);
129 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
131 simple_heap_delete(pg_largeobject, &tuple->t_self);
134 systable_endscan(scan);
136 heap_close(pg_largeobject, RowExclusiveLock);
138 heap_close(pg_lo_meta, RowExclusiveLock);
142 * LargeObjectAlterOwner
144 * Implementation of ALTER LARGE OBJECT statement
147 LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
149 Form_pg_largeobject_metadata form_lo_meta;
156 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
159 ScanKeyInit(&skey[0],
160 ObjectIdAttributeNumber,
161 BTEqualStrategyNumber, F_OIDEQ,
162 ObjectIdGetDatum(loid));
164 scan = systable_beginscan(pg_lo_meta,
165 LargeObjectMetadataOidIndexId, true,
166 SnapshotNow, 1, skey);
168 oldtup = systable_getnext(scan);
169 if (!HeapTupleIsValid(oldtup))
171 (errcode(ERRCODE_UNDEFINED_OBJECT),
172 errmsg("large object %u does not exist", loid)));
174 form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(oldtup);
175 if (form_lo_meta->lomowner != newOwnerId)
177 Datum values[Natts_pg_largeobject_metadata];
178 bool nulls[Natts_pg_largeobject_metadata];
179 bool replaces[Natts_pg_largeobject_metadata];
184 /* Superusers can always do it */
188 * lo_compat_privileges is not checked here, because ALTER LARGE
189 * OBJECT ... OWNER did not exist at all prior to PostgreSQL 9.0.
191 * We must be the owner of the existing object.
193 if (!pg_largeobject_ownercheck(loid, GetUserId()))
195 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
196 errmsg("must be owner of large object %u", loid)));
198 /* Must be able to become new owner */
199 check_is_member_of_role(GetUserId(), newOwnerId);
202 memset(values, 0, sizeof(values));
203 memset(nulls, false, sizeof(nulls));
204 memset(replaces, false, sizeof(nulls));
206 values[Anum_pg_largeobject_metadata_lomowner - 1]
207 = ObjectIdGetDatum(newOwnerId);
208 replaces[Anum_pg_largeobject_metadata_lomowner - 1] = true;
211 * Determine the modified ACL for the new owner. This is only
212 * necessary when the ACL is non-null.
214 aclDatum = heap_getattr(oldtup,
215 Anum_pg_largeobject_metadata_lomacl,
216 RelationGetDescr(pg_lo_meta), &isnull);
219 newAcl = aclnewowner(DatumGetAclP(aclDatum),
220 form_lo_meta->lomowner, newOwnerId);
221 values[Anum_pg_largeobject_metadata_lomacl - 1]
222 = PointerGetDatum(newAcl);
223 replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
226 newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_lo_meta),
227 values, nulls, replaces);
229 simple_heap_update(pg_lo_meta, &newtup->t_self, newtup);
230 CatalogUpdateIndexes(pg_lo_meta, newtup);
232 heap_freetuple(newtup);
234 /* Update owner dependency reference */
235 changeDependencyOnOwner(LargeObjectRelationId,
238 systable_endscan(scan);
240 heap_close(pg_lo_meta, RowExclusiveLock);
246 * We don't use the system cache for large object metadata, for fear of
247 * using too much local memory.
249 * This function always scans the system catalog using SnapshotNow, so it
250 * should not be used when a large object is opened in read-only mode (because
251 * large objects opened in read only mode are supposed to be viewed relative
252 * to the caller's snapshot, whereas in read-write mode they are relative to
256 LargeObjectExists(Oid loid)
264 ScanKeyInit(&skey[0],
265 ObjectIdAttributeNumber,
266 BTEqualStrategyNumber, F_OIDEQ,
267 ObjectIdGetDatum(loid));
269 pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
272 sd = systable_beginscan(pg_lo_meta,
273 LargeObjectMetadataOidIndexId, true,
274 SnapshotNow, 1, skey);
276 tuple = systable_getnext(sd);
277 if (HeapTupleIsValid(tuple))
280 systable_endscan(sd);
282 heap_close(pg_lo_meta, AccessShareLock);