OSDN Git Service

Update copyright for the year 2010.
[pg-rex/syncrep.git] / 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-2010, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/catalog/pg_largeobject.c,v 1.36 2010/01/02 16:57:36 momjian Exp $
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
193                          * LARGE OBJECT ... OWNER did not exist at all prior to
194                          * PostgreSQL 8.5.
195                          *
196                          * We must be the owner of the existing object.
197                          */
198                         if (!pg_largeobject_ownercheck(loid, GetUserId()))
199                                 ereport(ERROR,
200                                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
201                                                  errmsg("must be owner of large object %u", loid)));
202
203                         /* Must be able to become new owner */
204                         check_is_member_of_role(GetUserId(), newOwnerId);
205                 }
206
207                 memset(values, 0, sizeof(values));
208                 memset(nulls, false, sizeof(nulls));
209                 memset(replaces, false, sizeof(nulls));
210
211                 values[Anum_pg_largeobject_metadata_lomowner - 1]
212                         = ObjectIdGetDatum(newOwnerId);
213                 replaces[Anum_pg_largeobject_metadata_lomowner - 1] = true;
214
215                 /*
216                  * Determine the modified ACL for the new owner.
217                  * This is only necessary when the ACL is non-null.
218                  */
219                 aclDatum = heap_getattr(oldtup,
220                                                                 Anum_pg_largeobject_metadata_lomacl,
221                                                                 RelationGetDescr(pg_lo_meta), &isnull);
222                 if (!isnull)
223                 {
224                         newAcl = aclnewowner(DatumGetAclP(aclDatum),
225                                                                  form_lo_meta->lomowner, newOwnerId);
226                         values[Anum_pg_largeobject_metadata_lomacl - 1]
227                                 = PointerGetDatum(newAcl);
228                         replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
229                 }
230
231                 newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_lo_meta),
232                                                                    values, nulls, replaces);
233
234                 simple_heap_update(pg_lo_meta, &newtup->t_self, newtup);
235                 CatalogUpdateIndexes(pg_lo_meta, newtup);
236
237                 heap_freetuple(newtup);
238
239                 /* Update owner dependency reference */
240                 changeDependencyOnOwner(LargeObjectRelationId,
241                                                                 loid, newOwnerId);
242         }
243         systable_endscan(scan);
244
245         heap_close(pg_lo_meta, RowExclusiveLock);
246 }
247
248 /*
249  * LargeObjectExists
250  *
251  * We don't use the system cache to for large object metadata, for fear of
252  * using too much local memory.
253  *
254  * Note that LargeObjectExists always scans the system catalog
255  * with SnapshotNow, so it is unavailable to use to check
256  * existence in read-only accesses.
257  */
258 bool
259 LargeObjectExists(Oid loid)
260 {
261         Relation        pg_lo_meta;
262         ScanKeyData     skey[1];
263         SysScanDesc     sd;
264         HeapTuple       tuple;
265         bool            retval = false;
266
267         ScanKeyInit(&skey[0],
268                                 ObjectIdAttributeNumber,
269                                 BTEqualStrategyNumber, F_OIDEQ,
270                                 ObjectIdGetDatum(loid));
271
272         pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
273                                                    AccessShareLock);
274
275         sd = systable_beginscan(pg_lo_meta,
276                                                         LargeObjectMetadataOidIndexId, true,
277                                                         SnapshotNow, 1, skey);
278
279         tuple = systable_getnext(sd);
280         if (HeapTupleIsValid(tuple))
281                 retval = true;
282
283         systable_endscan(sd);
284
285         heap_close(pg_lo_meta, AccessShareLock);
286
287         return retval;
288 }