]> granicus.if.org Git - postgresql/blob - src/backend/catalog/pg_largeobject.c
Stamp copyrights for year 2011.
[postgresql] / src / backend / catalog / pg_largeobject.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_largeobject.c
4  *        routines to support manipulation of the pg_largeobject relation
5  *
6  * Portions Copyright (c) 1996-2011, 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/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"
33
34
35 /*
36  * Create a large object having the given LO identifier.
37  *
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.
41  */
42 Oid
43 LargeObjectCreate(Oid loid)
44 {
45         Relation        pg_lo_meta;
46         HeapTuple       ntup;
47         Oid                     loid_new;
48         Datum           values[Natts_pg_largeobject_metadata];
49         bool            nulls[Natts_pg_largeobject_metadata];
50
51         pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
52                                                    RowExclusiveLock);
53
54         /*
55          * Insert metadata of the largeobject
56          */
57         memset(values, 0, sizeof(values));
58         memset(nulls, false, sizeof(nulls));
59
60         values[Anum_pg_largeobject_metadata_lomowner - 1]
61                 = ObjectIdGetDatum(GetUserId());
62         nulls[Anum_pg_largeobject_metadata_lomacl - 1] = true;
63
64         ntup = heap_form_tuple(RelationGetDescr(pg_lo_meta),
65                                                    values, nulls);
66         if (OidIsValid(loid))
67                 HeapTupleSetOid(ntup, loid);
68
69         loid_new = simple_heap_insert(pg_lo_meta, ntup);
70         Assert(!OidIsValid(loid) || loid == loid_new);
71
72         CatalogUpdateIndexes(pg_lo_meta, ntup);
73
74         heap_freetuple(ntup);
75
76         heap_close(pg_lo_meta, RowExclusiveLock);
77
78         return loid_new;
79 }
80
81 /*
82  * Drop a large object having the given LO identifier.  Both the data pages
83  * and metadata must be dropped.
84  */
85 void
86 LargeObjectDrop(Oid loid)
87 {
88         Relation        pg_lo_meta;
89         Relation        pg_largeobject;
90         ScanKeyData skey[1];
91         SysScanDesc scan;
92         HeapTuple       tuple;
93
94         pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
95                                                    RowExclusiveLock);
96
97         pg_largeobject = heap_open(LargeObjectRelationId,
98                                                            RowExclusiveLock);
99
100         /*
101          * Delete an entry from pg_largeobject_metadata
102          */
103         ScanKeyInit(&skey[0],
104                                 ObjectIdAttributeNumber,
105                                 BTEqualStrategyNumber, F_OIDEQ,
106                                 ObjectIdGetDatum(loid));
107
108         scan = systable_beginscan(pg_lo_meta,
109                                                           LargeObjectMetadataOidIndexId, true,
110                                                           SnapshotNow, 1, skey);
111
112         tuple = systable_getnext(scan);
113         if (!HeapTupleIsValid(tuple))
114                 ereport(ERROR,
115                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
116                                  errmsg("large object %u does not exist", loid)));
117
118         simple_heap_delete(pg_lo_meta, &tuple->t_self);
119
120         systable_endscan(scan);
121
122         /*
123          * Delete all the associated entries from pg_largeobject
124          */
125         ScanKeyInit(&skey[0],
126                                 Anum_pg_largeobject_loid,
127                                 BTEqualStrategyNumber, F_OIDEQ,
128                                 ObjectIdGetDatum(loid));
129
130         scan = systable_beginscan(pg_largeobject,
131                                                           LargeObjectLOidPNIndexId, true,
132                                                           SnapshotNow, 1, skey);
133         while (HeapTupleIsValid(tuple = systable_getnext(scan)))
134         {
135                 simple_heap_delete(pg_largeobject, &tuple->t_self);
136         }
137
138         systable_endscan(scan);
139
140         heap_close(pg_largeobject, RowExclusiveLock);
141
142         heap_close(pg_lo_meta, RowExclusiveLock);
143 }
144
145 /*
146  * LargeObjectAlterOwner
147  *
148  * Implementation of ALTER LARGE OBJECT statement
149  */
150 void
151 LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
152 {
153         Form_pg_largeobject_metadata form_lo_meta;
154         Relation        pg_lo_meta;
155         ScanKeyData skey[1];
156         SysScanDesc scan;
157         HeapTuple       oldtup;
158         HeapTuple       newtup;
159
160         pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
161                                                    RowExclusiveLock);
162
163         ScanKeyInit(&skey[0],
164                                 ObjectIdAttributeNumber,
165                                 BTEqualStrategyNumber, F_OIDEQ,
166                                 ObjectIdGetDatum(loid));
167
168         scan = systable_beginscan(pg_lo_meta,
169                                                           LargeObjectMetadataOidIndexId, true,
170                                                           SnapshotNow, 1, skey);
171
172         oldtup = systable_getnext(scan);
173         if (!HeapTupleIsValid(oldtup))
174                 ereport(ERROR,
175                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
176                                  errmsg("large object %u does not exist", loid)));
177
178         form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(oldtup);
179         if (form_lo_meta->lomowner != newOwnerId)
180         {
181                 Datum           values[Natts_pg_largeobject_metadata];
182                 bool            nulls[Natts_pg_largeobject_metadata];
183                 bool            replaces[Natts_pg_largeobject_metadata];
184                 Acl                *newAcl;
185                 Datum           aclDatum;
186                 bool            isnull;
187
188                 /* Superusers can always do it */
189                 if (!superuser())
190                 {
191                         /*
192                          * lo_compat_privileges is not checked here, because ALTER LARGE
193                          * OBJECT ... OWNER did not exist at all prior to PostgreSQL 9.0.
194                          *
195                          * We must be the owner of the existing object.
196                          */
197                         if (!pg_largeobject_ownercheck(loid, GetUserId()))
198                                 ereport(ERROR,
199                                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
200                                                  errmsg("must be owner of large object %u", loid)));
201
202                         /* Must be able to become new owner */
203                         check_is_member_of_role(GetUserId(), newOwnerId);
204                 }
205
206                 memset(values, 0, sizeof(values));
207                 memset(nulls, false, sizeof(nulls));
208                 memset(replaces, false, sizeof(nulls));
209
210                 values[Anum_pg_largeobject_metadata_lomowner - 1]
211                         = ObjectIdGetDatum(newOwnerId);
212                 replaces[Anum_pg_largeobject_metadata_lomowner - 1] = true;
213
214                 /*
215                  * Determine the modified ACL for the new owner. This is only
216                  * necessary when the ACL is non-null.
217                  */
218                 aclDatum = heap_getattr(oldtup,
219                                                                 Anum_pg_largeobject_metadata_lomacl,
220                                                                 RelationGetDescr(pg_lo_meta), &isnull);
221                 if (!isnull)
222                 {
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;
228                 }
229
230                 newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_lo_meta),
231                                                                    values, nulls, replaces);
232
233                 simple_heap_update(pg_lo_meta, &newtup->t_self, newtup);
234                 CatalogUpdateIndexes(pg_lo_meta, newtup);
235
236                 heap_freetuple(newtup);
237
238                 /* Update owner dependency reference */
239                 changeDependencyOnOwner(LargeObjectRelationId,
240                                                                 loid, newOwnerId);
241         }
242         systable_endscan(scan);
243
244         heap_close(pg_lo_meta, RowExclusiveLock);
245 }
246
247 /*
248  * LargeObjectExists
249  *
250  * We don't use the system cache for large object metadata, for fear of
251  * using too much local memory.
252  *
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
257  * SnapshotNow).
258  */
259 bool
260 LargeObjectExists(Oid loid)
261 {
262         Relation        pg_lo_meta;
263         ScanKeyData skey[1];
264         SysScanDesc sd;
265         HeapTuple       tuple;
266         bool            retval = false;
267
268         ScanKeyInit(&skey[0],
269                                 ObjectIdAttributeNumber,
270                                 BTEqualStrategyNumber, F_OIDEQ,
271                                 ObjectIdGetDatum(loid));
272
273         pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
274                                                    AccessShareLock);
275
276         sd = systable_beginscan(pg_lo_meta,
277                                                         LargeObjectMetadataOidIndexId, true,
278                                                         SnapshotNow, 1, skey);
279
280         tuple = systable_getnext(sd);
281         if (HeapTupleIsValid(tuple))
282                 retval = true;
283
284         systable_endscan(sd);
285
286         heap_close(pg_lo_meta, AccessShareLock);
287
288         return retval;
289 }