~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/commands/comment.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * comment.c
 
4
 *
 
5
 * PostgreSQL object comments utility code.
 
6
 *
 
7
 * Copyright (c) 1996-2011, PostgreSQL Global Development Group
 
8
 *
 
9
 * IDENTIFICATION
 
10
 *        src/backend/commands/comment.c
 
11
 *
 
12
 *-------------------------------------------------------------------------
 
13
 */
 
14
 
 
15
#include "postgres.h"
 
16
 
 
17
#include "access/genam.h"
 
18
#include "access/heapam.h"
 
19
#include "catalog/indexing.h"
 
20
#include "catalog/objectaddress.h"
 
21
#include "catalog/pg_description.h"
 
22
#include "catalog/pg_shdescription.h"
 
23
#include "commands/comment.h"
 
24
#include "commands/dbcommands.h"
 
25
#include "miscadmin.h"
 
26
#include "utils/builtins.h"
 
27
#include "utils/fmgroids.h"
 
28
#include "utils/tqual.h"
 
29
 
 
30
 
 
31
/*
 
32
 * CommentObject --
 
33
 *
 
34
 * This routine is used to add the associated comment into
 
35
 * pg_description for the object specified by the given SQL command.
 
36
 */
 
37
void
 
38
CommentObject(CommentStmt *stmt)
 
39
{
 
40
        ObjectAddress address;
 
41
        Relation        relation;
 
42
 
 
43
        /*
 
44
         * When loading a dump, we may see a COMMENT ON DATABASE for the old name
 
45
         * of the database.  Erroring out would prevent pg_restore from completing
 
46
         * (which is really pg_restore's fault, but for now we will work around
 
47
         * the problem here).  Consensus is that the best fix is to treat wrong
 
48
         * database name as a WARNING not an ERROR; hence, the following special
 
49
         * case.  (If the length of stmt->objname is not 1, get_object_address
 
50
         * will throw an error below; that's OK.)
 
51
         */
 
52
        if (stmt->objtype == OBJECT_DATABASE && list_length(stmt->objname) == 1)
 
53
        {
 
54
                char       *database = strVal(linitial(stmt->objname));
 
55
 
 
56
                if (!OidIsValid(get_database_oid(database, true)))
 
57
                {
 
58
                        ereport(WARNING,
 
59
                                        (errcode(ERRCODE_UNDEFINED_DATABASE),
 
60
                                         errmsg("database \"%s\" does not exist", database)));
 
61
                        return;
 
62
                }
 
63
        }
 
64
 
 
65
        /*
 
66
         * Translate the parser representation that identifies this object into an
 
67
         * ObjectAddress.  get_object_address() will throw an error if the object
 
68
         * does not exist, and will also acquire a lock on the target to guard
 
69
         * against concurrent DROP operations.
 
70
         */
 
71
        address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
 
72
                                                                 &relation, ShareUpdateExclusiveLock);
 
73
 
 
74
        /* Require ownership of the target object. */
 
75
        check_object_ownership(GetUserId(), stmt->objtype, address,
 
76
                                                   stmt->objname, stmt->objargs, relation);
 
77
 
 
78
        /* Perform other integrity checks as needed. */
 
79
        switch (stmt->objtype)
 
80
        {
 
81
                case OBJECT_COLUMN:
 
82
 
 
83
                        /*
 
84
                         * Allow comments only on columns of tables, views, composite
 
85
                         * types, and foreign tables (which are the only relkinds for
 
86
                         * which pg_dump will dump per-column comments).  In particular we
 
87
                         * wish to disallow comments on index columns, because the naming
 
88
                         * of an index's columns may change across PG versions, so dumping
 
89
                         * per-column comments could create reload failures.
 
90
                         */
 
91
                        if (relation->rd_rel->relkind != RELKIND_RELATION &&
 
92
                                relation->rd_rel->relkind != RELKIND_VIEW &&
 
93
                                relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
 
94
                                relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
 
95
                                ereport(ERROR,
 
96
                                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
 
97
                                                 errmsg("\"%s\" is not a table, view, composite type, or foreign table",
 
98
                                                                RelationGetRelationName(relation))));
 
99
                        break;
 
100
                default:
 
101
                        break;
 
102
        }
 
103
 
 
104
        /*
 
105
         * Databases, tablespaces, and roles are cluster-wide objects, so any
 
106
         * comments on those objects are recorded in the shared pg_shdescription
 
107
         * catalog.  Comments on all other objects are recorded in pg_description.
 
108
         */
 
109
        if (stmt->objtype == OBJECT_DATABASE || stmt->objtype == OBJECT_TABLESPACE
 
110
                || stmt->objtype == OBJECT_ROLE)
 
111
                CreateSharedComments(address.objectId, address.classId, stmt->comment);
 
112
        else
 
113
                CreateComments(address.objectId, address.classId, address.objectSubId,
 
114
                                           stmt->comment);
 
115
 
 
116
        /*
 
117
         * If get_object_address() opened the relation for us, we close it to keep
 
118
         * the reference count correct - but we retain any locks acquired by
 
119
         * get_object_address() until commit time, to guard against concurrent
 
120
         * activity.
 
121
         */
 
122
        if (relation != NULL)
 
123
                relation_close(relation, NoLock);
 
124
}
 
125
 
 
126
/*
 
127
 * CreateComments --
 
128
 *
 
129
 * Create a comment for the specified object descriptor.  Inserts a new
 
130
 * pg_description tuple, or replaces an existing one with the same key.
 
131
 *
 
132
 * If the comment given is null or an empty string, instead delete any
 
133
 * existing comment for the specified key.
 
134
 */
 
135
void
 
136
CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
 
137
{
 
138
        Relation        description;
 
139
        ScanKeyData skey[3];
 
140
        SysScanDesc sd;
 
141
        HeapTuple       oldtuple;
 
142
        HeapTuple       newtuple = NULL;
 
143
        Datum           values[Natts_pg_description];
 
144
        bool            nulls[Natts_pg_description];
 
145
        bool            replaces[Natts_pg_description];
 
146
        int                     i;
 
147
 
 
148
        /* Reduce empty-string to NULL case */
 
149
        if (comment != NULL && strlen(comment) == 0)
 
150
                comment = NULL;
 
151
 
 
152
        /* Prepare to form or update a tuple, if necessary */
 
153
        if (comment != NULL)
 
154
        {
 
155
                for (i = 0; i < Natts_pg_description; i++)
 
156
                {
 
157
                        nulls[i] = false;
 
158
                        replaces[i] = true;
 
159
                }
 
160
                i = 0;
 
161
                values[i++] = ObjectIdGetDatum(oid);
 
162
                values[i++] = ObjectIdGetDatum(classoid);
 
163
                values[i++] = Int32GetDatum(subid);
 
164
                values[i++] = CStringGetTextDatum(comment);
 
165
        }
 
166
 
 
167
        /* Use the index to search for a matching old tuple */
 
168
 
 
169
        ScanKeyInit(&skey[0],
 
170
                                Anum_pg_description_objoid,
 
171
                                BTEqualStrategyNumber, F_OIDEQ,
 
172
                                ObjectIdGetDatum(oid));
 
173
        ScanKeyInit(&skey[1],
 
174
                                Anum_pg_description_classoid,
 
175
                                BTEqualStrategyNumber, F_OIDEQ,
 
176
                                ObjectIdGetDatum(classoid));
 
177
        ScanKeyInit(&skey[2],
 
178
                                Anum_pg_description_objsubid,
 
179
                                BTEqualStrategyNumber, F_INT4EQ,
 
180
                                Int32GetDatum(subid));
 
181
 
 
182
        description = heap_open(DescriptionRelationId, RowExclusiveLock);
 
183
 
 
184
        sd = systable_beginscan(description, DescriptionObjIndexId, true,
 
185
                                                        SnapshotNow, 3, skey);
 
186
 
 
187
        while ((oldtuple = systable_getnext(sd)) != NULL)
 
188
        {
 
189
                /* Found the old tuple, so delete or update it */
 
190
 
 
191
                if (comment == NULL)
 
192
                        simple_heap_delete(description, &oldtuple->t_self);
 
193
                else
 
194
                {
 
195
                        newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(description), values,
 
196
                                                                                 nulls, replaces);
 
197
                        simple_heap_update(description, &oldtuple->t_self, newtuple);
 
198
                }
 
199
 
 
200
                break;                                  /* Assume there can be only one match */
 
201
        }
 
202
 
 
203
        systable_endscan(sd);
 
204
 
 
205
        /* If we didn't find an old tuple, insert a new one */
 
206
 
 
207
        if (newtuple == NULL && comment != NULL)
 
208
        {
 
209
                newtuple = heap_form_tuple(RelationGetDescr(description),
 
210
                                                                   values, nulls);
 
211
                simple_heap_insert(description, newtuple);
 
212
        }
 
213
 
 
214
        /* Update indexes, if necessary */
 
215
        if (newtuple != NULL)
 
216
        {
 
217
                CatalogUpdateIndexes(description, newtuple);
 
218
                heap_freetuple(newtuple);
 
219
        }
 
220
 
 
221
        /* Done */
 
222
 
 
223
        heap_close(description, NoLock);
 
224
}
 
225
 
 
226
/*
 
227
 * CreateSharedComments --
 
228
 *
 
229
 * Create a comment for the specified shared object descriptor.  Inserts a
 
230
 * new pg_shdescription tuple, or replaces an existing one with the same key.
 
231
 *
 
232
 * If the comment given is null or an empty string, instead delete any
 
233
 * existing comment for the specified key.
 
234
 */
 
235
void
 
236
CreateSharedComments(Oid oid, Oid classoid, char *comment)
 
237
{
 
238
        Relation        shdescription;
 
239
        ScanKeyData skey[2];
 
240
        SysScanDesc sd;
 
241
        HeapTuple       oldtuple;
 
242
        HeapTuple       newtuple = NULL;
 
243
        Datum           values[Natts_pg_shdescription];
 
244
        bool            nulls[Natts_pg_shdescription];
 
245
        bool            replaces[Natts_pg_shdescription];
 
246
        int                     i;
 
247
 
 
248
        /* Reduce empty-string to NULL case */
 
249
        if (comment != NULL && strlen(comment) == 0)
 
250
                comment = NULL;
 
251
 
 
252
        /* Prepare to form or update a tuple, if necessary */
 
253
        if (comment != NULL)
 
254
        {
 
255
                for (i = 0; i < Natts_pg_shdescription; i++)
 
256
                {
 
257
                        nulls[i] = false;
 
258
                        replaces[i] = true;
 
259
                }
 
260
                i = 0;
 
261
                values[i++] = ObjectIdGetDatum(oid);
 
262
                values[i++] = ObjectIdGetDatum(classoid);
 
263
                values[i++] = CStringGetTextDatum(comment);
 
264
        }
 
265
 
 
266
        /* Use the index to search for a matching old tuple */
 
267
 
 
268
        ScanKeyInit(&skey[0],
 
269
                                Anum_pg_shdescription_objoid,
 
270
                                BTEqualStrategyNumber, F_OIDEQ,
 
271
                                ObjectIdGetDatum(oid));
 
272
        ScanKeyInit(&skey[1],
 
273
                                Anum_pg_shdescription_classoid,
 
274
                                BTEqualStrategyNumber, F_OIDEQ,
 
275
                                ObjectIdGetDatum(classoid));
 
276
 
 
277
        shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
 
278
 
 
279
        sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
 
280
                                                        SnapshotNow, 2, skey);
 
281
 
 
282
        while ((oldtuple = systable_getnext(sd)) != NULL)
 
283
        {
 
284
                /* Found the old tuple, so delete or update it */
 
285
 
 
286
                if (comment == NULL)
 
287
                        simple_heap_delete(shdescription, &oldtuple->t_self);
 
288
                else
 
289
                {
 
290
                        newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(shdescription),
 
291
                                                                                 values, nulls, replaces);
 
292
                        simple_heap_update(shdescription, &oldtuple->t_self, newtuple);
 
293
                }
 
294
 
 
295
                break;                                  /* Assume there can be only one match */
 
296
        }
 
297
 
 
298
        systable_endscan(sd);
 
299
 
 
300
        /* If we didn't find an old tuple, insert a new one */
 
301
 
 
302
        if (newtuple == NULL && comment != NULL)
 
303
        {
 
304
                newtuple = heap_form_tuple(RelationGetDescr(shdescription),
 
305
                                                                   values, nulls);
 
306
                simple_heap_insert(shdescription, newtuple);
 
307
        }
 
308
 
 
309
        /* Update indexes, if necessary */
 
310
        if (newtuple != NULL)
 
311
        {
 
312
                CatalogUpdateIndexes(shdescription, newtuple);
 
313
                heap_freetuple(newtuple);
 
314
        }
 
315
 
 
316
        /* Done */
 
317
 
 
318
        heap_close(shdescription, NoLock);
 
319
}
 
320
 
 
321
/*
 
322
 * DeleteComments -- remove comments for an object
 
323
 *
 
324
 * If subid is nonzero then only comments matching it will be removed.
 
325
 * If subid is zero, all comments matching the oid/classoid will be removed
 
326
 * (this corresponds to deleting a whole object).
 
327
 */
 
328
void
 
329
DeleteComments(Oid oid, Oid classoid, int32 subid)
 
330
{
 
331
        Relation        description;
 
332
        ScanKeyData skey[3];
 
333
        int                     nkeys;
 
334
        SysScanDesc sd;
 
335
        HeapTuple       oldtuple;
 
336
 
 
337
        /* Use the index to search for all matching old tuples */
 
338
 
 
339
        ScanKeyInit(&skey[0],
 
340
                                Anum_pg_description_objoid,
 
341
                                BTEqualStrategyNumber, F_OIDEQ,
 
342
                                ObjectIdGetDatum(oid));
 
343
        ScanKeyInit(&skey[1],
 
344
                                Anum_pg_description_classoid,
 
345
                                BTEqualStrategyNumber, F_OIDEQ,
 
346
                                ObjectIdGetDatum(classoid));
 
347
 
 
348
        if (subid != 0)
 
349
        {
 
350
                ScanKeyInit(&skey[2],
 
351
                                        Anum_pg_description_objsubid,
 
352
                                        BTEqualStrategyNumber, F_INT4EQ,
 
353
                                        Int32GetDatum(subid));
 
354
                nkeys = 3;
 
355
        }
 
356
        else
 
357
                nkeys = 2;
 
358
 
 
359
        description = heap_open(DescriptionRelationId, RowExclusiveLock);
 
360
 
 
361
        sd = systable_beginscan(description, DescriptionObjIndexId, true,
 
362
                                                        SnapshotNow, nkeys, skey);
 
363
 
 
364
        while ((oldtuple = systable_getnext(sd)) != NULL)
 
365
                simple_heap_delete(description, &oldtuple->t_self);
 
366
 
 
367
        /* Done */
 
368
 
 
369
        systable_endscan(sd);
 
370
        heap_close(description, RowExclusiveLock);
 
371
}
 
372
 
 
373
/*
 
374
 * DeleteSharedComments -- remove comments for a shared object
 
375
 */
 
376
void
 
377
DeleteSharedComments(Oid oid, Oid classoid)
 
378
{
 
379
        Relation        shdescription;
 
380
        ScanKeyData skey[2];
 
381
        SysScanDesc sd;
 
382
        HeapTuple       oldtuple;
 
383
 
 
384
        /* Use the index to search for all matching old tuples */
 
385
 
 
386
        ScanKeyInit(&skey[0],
 
387
                                Anum_pg_shdescription_objoid,
 
388
                                BTEqualStrategyNumber, F_OIDEQ,
 
389
                                ObjectIdGetDatum(oid));
 
390
        ScanKeyInit(&skey[1],
 
391
                                Anum_pg_shdescription_classoid,
 
392
                                BTEqualStrategyNumber, F_OIDEQ,
 
393
                                ObjectIdGetDatum(classoid));
 
394
 
 
395
        shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
 
396
 
 
397
        sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
 
398
                                                        SnapshotNow, 2, skey);
 
399
 
 
400
        while ((oldtuple = systable_getnext(sd)) != NULL)
 
401
                simple_heap_delete(shdescription, &oldtuple->t_self);
 
402
 
 
403
        /* Done */
 
404
 
 
405
        systable_endscan(sd);
 
406
        heap_close(shdescription, RowExclusiveLock);
 
407
}
 
408
 
 
409
/*
 
410
 * GetComment -- get the comment for an object, or null if not found.
 
411
 */
 
412
char *
 
413
GetComment(Oid oid, Oid classoid, int32 subid)
 
414
{
 
415
        Relation        description;
 
416
        ScanKeyData skey[3];
 
417
        SysScanDesc sd;
 
418
        TupleDesc       tupdesc;
 
419
        HeapTuple       tuple;
 
420
        char       *comment;
 
421
 
 
422
        /* Use the index to search for a matching old tuple */
 
423
 
 
424
        ScanKeyInit(&skey[0],
 
425
                                Anum_pg_description_objoid,
 
426
                                BTEqualStrategyNumber, F_OIDEQ,
 
427
                                ObjectIdGetDatum(oid));
 
428
        ScanKeyInit(&skey[1],
 
429
                                Anum_pg_description_classoid,
 
430
                                BTEqualStrategyNumber, F_OIDEQ,
 
431
                                ObjectIdGetDatum(classoid));
 
432
        ScanKeyInit(&skey[2],
 
433
                                Anum_pg_description_objsubid,
 
434
                                BTEqualStrategyNumber, F_INT4EQ,
 
435
                                Int32GetDatum(subid));
 
436
 
 
437
        description = heap_open(DescriptionRelationId, AccessShareLock);
 
438
        tupdesc = RelationGetDescr(description);
 
439
 
 
440
        sd = systable_beginscan(description, DescriptionObjIndexId, true,
 
441
                                                        SnapshotNow, 3, skey);
 
442
 
 
443
        comment = NULL;
 
444
        while ((tuple = systable_getnext(sd)) != NULL)
 
445
        {
 
446
                Datum           value;
 
447
                bool            isnull;
 
448
 
 
449
                /* Found the tuple, get description field */
 
450
                value = heap_getattr(tuple, Anum_pg_description_description, tupdesc, &isnull);
 
451
                if (!isnull)
 
452
                        comment = TextDatumGetCString(value);
 
453
                break;                                  /* Assume there can be only one match */
 
454
        }
 
455
 
 
456
        systable_endscan(sd);
 
457
 
 
458
        /* Done */
 
459
        heap_close(description, AccessShareLock);
 
460
 
 
461
        return comment;
 
462
}