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