PostgreSQL Source Code  git master
comment.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/table.h"
#include "catalog/indexing.h"
#include "catalog/objectaddress.h"
#include "catalog/pg_description.h"
#include "catalog/pg_shdescription.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
Include dependency graph for comment.c:

Go to the source code of this file.

Functions

ObjectAddress CommentObject (CommentStmt *stmt)
 
void CreateComments (Oid oid, Oid classoid, int32 subid, const char *comment)
 
void CreateSharedComments (Oid oid, Oid classoid, const char *comment)
 
void DeleteComments (Oid oid, Oid classoid, int32 subid)
 
void DeleteSharedComments (Oid oid, Oid classoid)
 
char * GetComment (Oid oid, Oid classoid, int32 subid)
 

Function Documentation

◆ CommentObject()

ObjectAddress CommentObject ( CommentStmt stmt)

Definition at line 40 of file comment.c.

41 {
42  Relation relation;
44 
45  /*
46  * When loading a dump, we may see a COMMENT ON DATABASE for the old name
47  * of the database. Erroring out would prevent pg_restore from completing
48  * (which is really pg_restore's fault, but for now we will work around
49  * the problem here). Consensus is that the best fix is to treat wrong
50  * database name as a WARNING not an ERROR; hence, the following special
51  * case.
52  */
53  if (stmt->objtype == OBJECT_DATABASE)
54  {
55  char *database = strVal(stmt->object);
56 
57  if (!OidIsValid(get_database_oid(database, true)))
58  {
60  (errcode(ERRCODE_UNDEFINED_DATABASE),
61  errmsg("database \"%s\" does not exist", database)));
62  return address;
63  }
64  }
65 
66  /*
67  * Translate the parser representation that identifies this object into an
68  * ObjectAddress. get_object_address() will throw an error if the object
69  * does not exist, and will also acquire a lock on the target to guard
70  * against concurrent DROP operations.
71  */
72  address = get_object_address(stmt->objtype, stmt->object,
73  &relation, ShareUpdateExclusiveLock, false);
74 
75  /* Require ownership of the target object. */
76  check_object_ownership(GetUserId(), stmt->objtype, address,
77  stmt->object, relation);
78 
79  /* Perform other integrity checks as needed. */
80  switch (stmt->objtype)
81  {
82  case OBJECT_COLUMN:
83 
84  /*
85  * Allow comments only on columns of tables, views, materialized
86  * views, composite types, and foreign tables (which are the only
87  * relkinds for which pg_dump will dump per-column comments). In
88  * particular we wish to disallow comments on index columns,
89  * because the naming of an index's columns may change across PG
90  * versions, so dumping per-column comments could create reload
91  * failures.
92  */
93  if (relation->rd_rel->relkind != RELKIND_RELATION &&
94  relation->rd_rel->relkind != RELKIND_VIEW &&
95  relation->rd_rel->relkind != RELKIND_MATVIEW &&
96  relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
97  relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
98  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
99  ereport(ERROR,
100  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
101  errmsg("cannot set comment on relation \"%s\"",
102  RelationGetRelationName(relation)),
103  errdetail_relkind_not_supported(relation->rd_rel->relkind)));
104  break;
105  default:
106  break;
107  }
108 
109  /*
110  * Databases, tablespaces, and roles are cluster-wide objects, so any
111  * comments on those objects are recorded in the shared pg_shdescription
112  * catalog. Comments on all other objects are recorded in pg_description.
113  */
114  if (stmt->objtype == OBJECT_DATABASE || stmt->objtype == OBJECT_TABLESPACE
115  || stmt->objtype == OBJECT_ROLE)
116  CreateSharedComments(address.objectId, address.classId, stmt->comment);
117  else
118  CreateComments(address.objectId, address.classId, address.objectSubId,
119  stmt->comment);
120 
121  /*
122  * If get_object_address() opened the relation for us, we close it to keep
123  * the reference count correct - but we retain any locks acquired by
124  * get_object_address() until commit time, to guard against concurrent
125  * activity.
126  */
127  if (relation != NULL)
128  relation_close(relation, NoLock);
129 
130  return address;
131 }
#define OidIsValid(objectId)
Definition: c.h:762
void CreateSharedComments(Oid oid, Oid classoid, const char *comment)
Definition: comment.c:238
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:143
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3106
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define stmt
Definition: indent_codes.h:59
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
Oid GetUserId(void)
Definition: miscinit.c:514
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
const ObjectAddress InvalidObjectAddress
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
@ OBJECT_COLUMN
Definition: parsenodes.h:2115
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2151
@ OBJECT_ROLE
Definition: parsenodes.h:2142
@ OBJECT_DATABASE
Definition: parsenodes.h:2118
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define RelationGetRelationName(relation)
Definition: rel.h:539
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Form_pg_class rd_rel
Definition: rel.h:111
#define strVal(v)
Definition: value.h:82

References check_object_ownership(), ObjectAddress::classId, CreateComments(), CreateSharedComments(), ereport, errcode(), errdetail_relkind_not_supported(), errmsg(), ERROR, get_database_oid(), get_object_address(), GetUserId(), InvalidObjectAddress, NoLock, OBJECT_COLUMN, OBJECT_DATABASE, OBJECT_ROLE, OBJECT_TABLESPACE, ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, RelationData::rd_rel, relation_close(), RelationGetRelationName, ShareUpdateExclusiveLock, stmt, strVal, and WARNING.

Referenced by ATExecCmd(), ProcessUtilitySlow(), and standard_ProcessUtility().

◆ CreateComments()

void CreateComments ( Oid  oid,
Oid  classoid,
int32  subid,
const char *  comment 
)

Definition at line 143 of file comment.c.

144 {
146  ScanKeyData skey[3];
147  SysScanDesc sd;
148  HeapTuple oldtuple;
149  HeapTuple newtuple = NULL;
150  Datum values[Natts_pg_description];
151  bool nulls[Natts_pg_description];
152  bool replaces[Natts_pg_description];
153  int i;
154 
155  /* Reduce empty-string to NULL case */
156  if (comment != NULL && strlen(comment) == 0)
157  comment = NULL;
158 
159  /* Prepare to form or update a tuple, if necessary */
160  if (comment != NULL)
161  {
162  for (i = 0; i < Natts_pg_description; i++)
163  {
164  nulls[i] = false;
165  replaces[i] = true;
166  }
167  values[Anum_pg_description_objoid - 1] = ObjectIdGetDatum(oid);
168  values[Anum_pg_description_classoid - 1] = ObjectIdGetDatum(classoid);
169  values[Anum_pg_description_objsubid - 1] = Int32GetDatum(subid);
170  values[Anum_pg_description_description - 1] = CStringGetTextDatum(comment);
171  }
172 
173  /* Use the index to search for a matching old tuple */
174 
175  ScanKeyInit(&skey[0],
176  Anum_pg_description_objoid,
177  BTEqualStrategyNumber, F_OIDEQ,
178  ObjectIdGetDatum(oid));
179  ScanKeyInit(&skey[1],
180  Anum_pg_description_classoid,
181  BTEqualStrategyNumber, F_OIDEQ,
182  ObjectIdGetDatum(classoid));
183  ScanKeyInit(&skey[2],
184  Anum_pg_description_objsubid,
185  BTEqualStrategyNumber, F_INT4EQ,
186  Int32GetDatum(subid));
187 
188  description = table_open(DescriptionRelationId, RowExclusiveLock);
189 
190  sd = systable_beginscan(description, DescriptionObjIndexId, true,
191  NULL, 3, skey);
192 
193  while ((oldtuple = systable_getnext(sd)) != NULL)
194  {
195  /* Found the old tuple, so delete or update it */
196 
197  if (comment == NULL)
199  else
200  {
201  newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(description), values,
202  nulls, replaces);
203  CatalogTupleUpdate(description, &oldtuple->t_self, newtuple);
204  }
205 
206  break; /* Assume there can be only one match */
207  }
208 
209  systable_endscan(sd);
210 
211  /* If we didn't find an old tuple, insert a new one */
212 
213  if (newtuple == NULL && comment != NULL)
214  {
216  values, nulls);
217  CatalogTupleInsert(description, newtuple);
218  }
219 
220  if (newtuple != NULL)
221  heap_freetuple(newtuple);
222 
223  /* Done */
224 
226 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:596
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:503
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:384
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define comment
Definition: indent_codes.h:49
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
int i
Definition: isn.c:73
#define RowExclusiveLock
Definition: lockdefs.h:38
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define RelationGetDescr(relation)
Definition: rel.h:531
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
const char * description

References BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleInsert(), CatalogTupleUpdate(), comment, CStringGetTextDatum, description, heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), i, Int32GetDatum(), NoLock, ObjectIdGetDatum(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by CommentObject(), CreateExtensionInternal(), CreateStatistics(), DefineIndex(), and pg_import_system_collations().

◆ CreateSharedComments()

void CreateSharedComments ( Oid  oid,
Oid  classoid,
const char *  comment 
)

Definition at line 238 of file comment.c.

239 {
240  Relation shdescription;
241  ScanKeyData skey[2];
242  SysScanDesc sd;
243  HeapTuple oldtuple;
244  HeapTuple newtuple = NULL;
245  Datum values[Natts_pg_shdescription];
246  bool nulls[Natts_pg_shdescription];
247  bool replaces[Natts_pg_shdescription];
248  int i;
249 
250  /* Reduce empty-string to NULL case */
251  if (comment != NULL && strlen(comment) == 0)
252  comment = NULL;
253 
254  /* Prepare to form or update a tuple, if necessary */
255  if (comment != NULL)
256  {
257  for (i = 0; i < Natts_pg_shdescription; i++)
258  {
259  nulls[i] = false;
260  replaces[i] = true;
261  }
262  values[Anum_pg_shdescription_objoid - 1] = ObjectIdGetDatum(oid);
263  values[Anum_pg_shdescription_classoid - 1] = ObjectIdGetDatum(classoid);
264  values[Anum_pg_shdescription_description - 1] = CStringGetTextDatum(comment);
265  }
266 
267  /* Use the index to search for a matching old tuple */
268 
269  ScanKeyInit(&skey[0],
270  Anum_pg_shdescription_objoid,
271  BTEqualStrategyNumber, F_OIDEQ,
272  ObjectIdGetDatum(oid));
273  ScanKeyInit(&skey[1],
274  Anum_pg_shdescription_classoid,
275  BTEqualStrategyNumber, F_OIDEQ,
276  ObjectIdGetDatum(classoid));
277 
278  shdescription = table_open(SharedDescriptionRelationId, RowExclusiveLock);
279 
280  sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
281  NULL, 2, skey);
282 
283  while ((oldtuple = systable_getnext(sd)) != NULL)
284  {
285  /* Found the old tuple, so delete or update it */
286 
287  if (comment == NULL)
288  CatalogTupleDelete(shdescription, &oldtuple->t_self);
289  else
290  {
291  newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(shdescription),
292  values, nulls, replaces);
293  CatalogTupleUpdate(shdescription, &oldtuple->t_self, newtuple);
294  }
295 
296  break; /* Assume there can be only one match */
297  }
298 
299  systable_endscan(sd);
300 
301  /* If we didn't find an old tuple, insert a new one */
302 
303  if (newtuple == NULL && comment != NULL)
304  {
305  newtuple = heap_form_tuple(RelationGetDescr(shdescription),
306  values, nulls);
307  CatalogTupleInsert(shdescription, newtuple);
308  }
309 
310  if (newtuple != NULL)
311  heap_freetuple(newtuple);
312 
313  /* Done */
314 
315  table_close(shdescription, NoLock);
316 }

References BTEqualStrategyNumber, CatalogTupleDelete(), CatalogTupleInsert(), CatalogTupleUpdate(), comment, CStringGetTextDatum, heap_form_tuple(), heap_freetuple(), heap_modify_tuple(), i, NoLock, ObjectIdGetDatum(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by CommentObject().

◆ DeleteComments()

void DeleteComments ( Oid  oid,
Oid  classoid,
int32  subid 
)

Definition at line 326 of file comment.c.

327 {
329  ScanKeyData skey[3];
330  int nkeys;
331  SysScanDesc sd;
332  HeapTuple oldtuple;
333 
334  /* Use the index to search for all matching old tuples */
335 
336  ScanKeyInit(&skey[0],
337  Anum_pg_description_objoid,
338  BTEqualStrategyNumber, F_OIDEQ,
339  ObjectIdGetDatum(oid));
340  ScanKeyInit(&skey[1],
341  Anum_pg_description_classoid,
342  BTEqualStrategyNumber, F_OIDEQ,
343  ObjectIdGetDatum(classoid));
344 
345  if (subid != 0)
346  {
347  ScanKeyInit(&skey[2],
348  Anum_pg_description_objsubid,
349  BTEqualStrategyNumber, F_INT4EQ,
350  Int32GetDatum(subid));
351  nkeys = 3;
352  }
353  else
354  nkeys = 2;
355 
356  description = table_open(DescriptionRelationId, RowExclusiveLock);
357 
358  sd = systable_beginscan(description, DescriptionObjIndexId, true,
359  NULL, nkeys, skey);
360 
361  while ((oldtuple = systable_getnext(sd)) != NULL)
363 
364  /* Done */
365 
366  systable_endscan(sd);
368 }

References BTEqualStrategyNumber, CatalogTupleDelete(), description, Int32GetDatum(), ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by deleteOneObject().

◆ DeleteSharedComments()

void DeleteSharedComments ( Oid  oid,
Oid  classoid 
)

Definition at line 374 of file comment.c.

375 {
376  Relation shdescription;
377  ScanKeyData skey[2];
378  SysScanDesc sd;
379  HeapTuple oldtuple;
380 
381  /* Use the index to search for all matching old tuples */
382 
383  ScanKeyInit(&skey[0],
384  Anum_pg_shdescription_objoid,
385  BTEqualStrategyNumber, F_OIDEQ,
386  ObjectIdGetDatum(oid));
387  ScanKeyInit(&skey[1],
388  Anum_pg_shdescription_classoid,
389  BTEqualStrategyNumber, F_OIDEQ,
390  ObjectIdGetDatum(classoid));
391 
392  shdescription = table_open(SharedDescriptionRelationId, RowExclusiveLock);
393 
394  sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
395  NULL, 2, skey);
396 
397  while ((oldtuple = systable_getnext(sd)) != NULL)
398  CatalogTupleDelete(shdescription, &oldtuple->t_self);
399 
400  /* Done */
401 
402  systable_endscan(sd);
403  table_close(shdescription, RowExclusiveLock);
404 }

References BTEqualStrategyNumber, CatalogTupleDelete(), ObjectIdGetDatum(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by dropdb(), DropRole(), and DropTableSpace().

◆ GetComment()

char* GetComment ( Oid  oid,
Oid  classoid,
int32  subid 
)

Definition at line 410 of file comment.c.

411 {
413  ScanKeyData skey[3];
414  SysScanDesc sd;
415  TupleDesc tupdesc;
416  HeapTuple tuple;
417  char *comment;
418 
419  /* Use the index to search for a matching old tuple */
420 
421  ScanKeyInit(&skey[0],
422  Anum_pg_description_objoid,
423  BTEqualStrategyNumber, F_OIDEQ,
424  ObjectIdGetDatum(oid));
425  ScanKeyInit(&skey[1],
426  Anum_pg_description_classoid,
427  BTEqualStrategyNumber, F_OIDEQ,
428  ObjectIdGetDatum(classoid));
429  ScanKeyInit(&skey[2],
430  Anum_pg_description_objsubid,
431  BTEqualStrategyNumber, F_INT4EQ,
432  Int32GetDatum(subid));
433 
434  description = table_open(DescriptionRelationId, AccessShareLock);
435  tupdesc = RelationGetDescr(description);
436 
437  sd = systable_beginscan(description, DescriptionObjIndexId, true,
438  NULL, 3, skey);
439 
440  comment = NULL;
441  while ((tuple = systable_getnext(sd)) != NULL)
442  {
443  Datum value;
444  bool isnull;
445 
446  /* Found the tuple, get description field */
447  value = heap_getattr(tuple, Anum_pg_description_description, tupdesc, &isnull);
448  if (!isnull)
450  break; /* Assume there can be only one match */
451  }
452 
453  systable_endscan(sd);
454 
455  /* Done */
457 
458  return comment;
459 }
#define TextDatumGetCString(d)
Definition: builtins.h:98
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:792
static struct @150 value
#define AccessShareLock
Definition: lockdefs.h:36

References AccessShareLock, BTEqualStrategyNumber, comment, description, heap_getattr(), Int32GetDatum(), ObjectIdGetDatum(), RelationGetDescr, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, and value.

Referenced by ATPostAlterTypeParse(), expandTableLikeClause(), RebuildConstraintComment(), and transformTableLikeClause().