*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.103 1999/10/07 05:48:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.104 1999/10/15 01:49:39 momjian Exp $
*
*
* INTERFACE ROUTINES
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/pg_attrdef.h"
+#include "catalog/pg_description.h"
#include "catalog/pg_index.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_ipl.h"
Relation new_rel_desc, Oid new_rel_oid, unsigned natts,
char relkind, char *temp_relname);
static void AddToNoNameRelList(Relation r);
+
static void DeleteAttributeTuples(Relation rel);
static void DeleteRelationTuple(Relation rel);
static void DeleteTypeTuple(Relation rel);
* 2) remove inheritance information
* 3) remove indexes
* 4) remove pg_class tuple
- * 5) remove pg_attribute tuples
- * 6) remove pg_type tuples
- * 7) RemoveConstraints ()
- * 8) unlink relation
+ * 5) remove pg_attribute tuples and related descriptions
+ * 6) remove pg_description tuples
+ * 7) remove pg_type tuples
+ * 8) RemoveConstraints ()
+ * 9) unlink relation
*
* old comments
* Except for vital relations, removes relation from
attnum++)
{
if (HeapTupleIsValid(tup = SearchSysCacheTupleCopy(ATTNUM,
- ObjectIdGetDatum(RelationGetRelid(rel)),
- Int16GetDatum(attnum),
+ ObjectIdGetDatum(RelationGetRelid(rel)),
+ Int16GetDatum(attnum),
0, 0)))
{
- heap_delete(pg_attribute_desc, &tup->t_self, NULL);
- pfree(tup);
+ DeleteComments(tup->t_data->t_oid);
+ heap_delete(pg_attribute_desc, &tup->t_self, NULL);
+ pfree(tup);
}
}
heap_close(pg_attribute_desc, RowExclusiveLock);
}
+/* ----------------------------------------------------------
+ * CreateComments
+ *
+ * This routine is handed the oid and the command associated
+ * with that id and will insert, update, or delete (if the
+ * comment is an empty string or a NULL pointer) the associated
+ * comment from the system cataloge, pg_description.
+ *
+ * ----------------------------------------------------------
+ */
+
+void
+CreateComments(Oid oid, char *comment)
+{
+
+ Relation description;
+ TupleDesc tupDesc;
+ HeapScanDesc scan;
+ ScanKeyData entry;
+ HeapTuple desctuple, searchtuple;
+ Datum values[Natts_pg_description];
+ char nulls[Natts_pg_description];
+ char replaces[Natts_pg_description];
+ bool modified = false;
+ int i;
+
+ /*** Open pg_description, form a new tuple, if necessary ***/
+
+ description = heap_openr(DescriptionRelationName, RowExclusiveLock);
+ tupDesc = description->rd_att;
+ if ((comment != NULL) && (strlen(comment) > 0)) {
+ for (i = 0; i < Natts_pg_description; i++) {
+ nulls[i] = ' ';
+ replaces[i] = 'r';
+ values[i] = (Datum) NULL;
+ }
+ i = 0;
+ values[i++] = ObjectIdGetDatum(oid);
+ values[i++] = (Datum) fmgr(F_TEXTIN, comment);
+ }
+
+ /*** Now, open pg_description and attempt to find the old tuple ***/
+
+ ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ,
+ ObjectIdGetDatum(oid));
+ scan = heap_beginscan(description, false, SnapshotNow, 1, &entry);
+ searchtuple = heap_getnext(scan, 0);
+
+ /*** If a previous tuple exists, either delete it or prepare a replacement ***/
+
+ if (HeapTupleIsValid(searchtuple)) {
+
+ /*** If the comment is blank, call heap_delete, else heap_replace ***/
+
+ if ((comment == NULL) || (strlen(comment) == 0)) {
+ heap_delete(description, &searchtuple->t_self, NULL);
+ } else {
+ desctuple = heap_modifytuple(searchtuple, description, values, nulls, replaces);
+ setheapoverride(true);
+ heap_replace(description, &searchtuple->t_self, desctuple, NULL);
+ setheapoverride(false);
+ modified = TRUE;
+ }
+
+ } else {
+ desctuple = heap_formtuple(tupDesc, values, nulls);
+ heap_insert(description, desctuple);
+ modified = TRUE;
+ }
+
+ /*** Complete the scan, update indices, if necessary ***/
+
+ heap_endscan(scan);
+
+ if (modified) {
+ if (RelationGetForm(description)->relhasindex) {
+ Relation idescs[Num_pg_description_indices];
+
+ CatalogOpenIndices(Num_pg_description_indices, Name_pg_description_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_description_indices, description, desctuple);
+ CatalogCloseIndices(Num_pg_description_indices, idescs);
+ }
+ pfree(desctuple);
+
+ }
+
+ heap_close(description, RowExclusiveLock);
+
+}
+
+/* --------------------------------
+ * DeleteComments
+ *
+ * This routine is used to purge any comments
+ * associated with the Oid handed to this routine,
+ * regardless of the actual object type. It is
+ * called, for example, when a relation is destroyed.
+ * --------------------------------
+ */
+
+void
+DeleteComments(Oid oid)
+{
+
+ Relation description;
+ TupleDesc tupDesc;
+ ScanKeyData entry;
+ HeapScanDesc scan;
+ HeapTuple searchtuple;
+
+ description = heap_openr(DescriptionRelationName, RowExclusiveLock);
+ tupDesc = description->rd_att;
+
+ /*** Now, open pg_description and attempt to find the old tuple ***/
+
+ ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ,
+ ObjectIdGetDatum(oid));
+ scan = heap_beginscan(description, false, SnapshotNow, 1, &entry);
+ searchtuple = heap_getnext(scan, 0);
+
+ /*** If a previous tuple exists, delete it ***/
+
+ if (HeapTupleIsValid(searchtuple)) {
+ heap_delete(description, &searchtuple->t_self, NULL);
+ }
+
+ /*** Complete the scan, update indices, if necessary ***/
+
+ heap_endscan(scan);
+ heap_close(description, RowExclusiveLock);
+
+}
+
/* --------------------------------
* DeleteTypeTuple
*
*/
DeleteAttributeTuples(rel);
+ /* ----------------
+ * delete comments
+ * ----------------
+ */
+
+ DeleteComments(RelationGetRelid(rel));
+
if (istemp)
remove_temp_relation(rid);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.47 1999/09/30 10:31:42 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.48 1999/10/15 01:49:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
TriggerConstrNameIndex,
TriggerConstrRelidIndex};
+char *Name_pg_description_indices[Num_pg_description_indices] = {DescriptionObjIndex};
+
+
static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
Relation idesc,
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.48 1999/10/03 23:55:27 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.49 1999/10/15 01:49:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
#include "catalog/catname.h"
+#include "catalog/indexing.h"
#include "catalog/heap.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_ipl.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_description.h"
#include "commands/creatinh.h"
#include "utils/syscache.h"
heap_truncate(name);
}
+/*------------------------------------------------------------------
+ * CommentRelation --
+ * Adds a comment to pg_description for the associated
+ * relation or relation attribute.
+ *
+ * Note:
+ * The comment is dropped on the relation or attribute if
+ * the comment is an empty string.
+ *------------------------------------------------------------------
+ */
+void
+CommentRelation(char *relname, char *attrname, char *comments)
+{
+
+ Relation relation;
+ HeapTuple attrtuple;
+ Oid oid;
+
+ /*** First ensure relname is valid ***/
+
+ relation = heap_openr(relname, AccessShareLock);
+
+ /*** Now, if an attribute was specified, fetch its oid, else use relation's oid ***/
+
+ if (attrname != NULL) {
+ attrtuple = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(relation->rd_id),
+ PointerGetDatum(attrname), 0, 0);
+ if (!HeapTupleIsValid(attrtuple)) {
+ elog(ERROR, "CommentRelation: attribute \"%s\" is not an attribute of relation \"%s\"",
+ attrname, relname);
+ }
+ oid = attrtuple->t_data->t_oid;
+ } else {
+ oid = RelationGetRelid(relation);
+ }
+
+ /*** Call CreateComments() to create/drop the comments ***/
+
+ CreateComments(oid, comments);
+
+ /*** Now, close the heap relation ***/
+
+ heap_close(relation, AccessShareLock);
+
+}
+
/*
* MergeAttributes
* Returns new schema given initial schema and supers.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.108 1999/10/07 04:23:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.109 1999/10/15 01:49:41 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
%type <node> stmt,
AddAttrStmt, ClosePortalStmt,
CopyStmt, CreateStmt, CreateAsStmt, CreateSeqStmt, DefineStmt, DestroyStmt,
- TruncateStmt,
+ TruncateStmt, CommentStmt,
ExtendStmt, FetchStmt, GrantStmt, CreateTrigStmt, DropTrigStmt,
CreatePLangStmt, DropPLangStmt,
IndexStmt, ListenStmt, UnlistenStmt, LockStmt, OptimizableStmt,
*/
%token ABORT_TRANS, ACCESS, AFTER, AGGREGATE, ANALYZE,
BACKWARD, BEFORE, BINARY,
- CACHE, CLUSTER, COPY, CREATEDB, CREATEUSER, CYCLE,
+ CACHE, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
DATABASE, DELIMITERS, DO,
EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND,
FORWARD, FUNCTION, HANDLER,
| DefineStmt
| DestroyStmt
| TruncateStmt
+ | CommentStmt
| DropPLangStmt
| DropTrigStmt
| DropUserStmt
}
;
+/*****************************************************************************
+ *
+ * QUERY:
+ * comment on [ table <relname> | column <relname>.<attribute> ]
+ * is 'text'
+ *
+ *****************************************************************************/
+
+CommentStmt: COMMENT ON COLUMN relation_name '.' attr_name IS Sconst
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->relname = $4;
+ n->attrname = $6;
+ n->comment = $8;
+ $$ = (Node *) n;
+ }
+ | COMMENT ON TABLE relation_name IS Sconst
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->relname = $4;
+ n->attrname = NULL;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
+ ;
+
/*****************************************************************************
*
* QUERY:
| BACKWARD { $$ = "backward"; }
| BEFORE { $$ = "before"; }
| CACHE { $$ = "cache"; }
+ | COMMENT { $$ = "comment"; }
| COMMITTED { $$ = "committed"; }
| CONSTRAINTS { $$ = "constraints"; }
| CREATEDB { $$ = "createdb"; }
| TIMEZONE_HOUR { $$ = "timezone_hour"; }
| TIMEZONE_MINUTE { $$ = "timezone_minute"; }
| TRIGGER { $$ = "trigger"; }
+ | TRUNCATE { $$ = "truncate"; }
| TRUSTED { $$ = "trusted"; }
| TYPE_P { $$ = "type"; }
| VALID { $$ = "valid"; }
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.62 1999/09/29 16:06:08 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.63 1999/10/15 01:49:41 momjian Exp $
*
*-------------------------------------------------------------------------
*/
{"coalesce", COALESCE},
{"collate", COLLATE},
{"column", COLUMN},
+ {"comment", COMMENT},
{"commit", COMMIT},
{"committed", COMMITTED},
{"constraint", CONSTRAINT},
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.69 1999/09/30 01:12:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.70 1999/10/15 01:49:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
}
break;
+ case T_CommentStmt:
+ {
+
+ CommentStmt *statement;
+
+ statement = ((CommentStmt *) parsetree);
+
+ PS_SET_STATUS(commandTag = "COMMENT");
+ CHECK_IF_ABORTED();
+
+#ifndef NO_SECURITY
+ if (!pg_ownercheck(userName, statement->relname, RELNAME))
+ elog(ERROR, "you do not own class \"%s\"", statement->relname);
+#endif
+
+ CommentRelation(statement->relname, statement->attrname,
+ statement->comment);
+ }
+ break;
+
+
+
case T_CopyStmt:
{
CopyStmt *stmt = (CopyStmt *) parsetree;
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: heap.h,v 1.22 1999/10/03 23:55:35 tgl Exp $
+ * $Id: heap.h,v 1.23 1999/10/15 01:49:44 momjian Exp $
*
*-------------------------------------------------------------------------
*/
extern void heap_truncate(char *relname);
extern void heap_destroy(Relation rel);
+extern void CreateComments(Oid object, char *comments);
+extern void DeleteComments(Oid object);
+
extern void AddRelationRawConstraints(Relation rel,
List *rawColDefaults,
List *rawConstraints);
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_description.h,v 1.8 1999/02/13 23:21:09 momjian Exp $
+ * $Id: pg_description.h,v 1.9 1999/10/15 01:49:44 momjian Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
*/
#endif /* PG_DESCRIPTION_H */
+
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: creatinh.h,v 1.10 1999/09/23 17:03:16 momjian Exp $
+ * $Id: creatinh.h,v 1.11 1999/10/15 01:49:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
extern void DefineRelation(CreateStmt *stmt, char relkind);
extern void RemoveRelation(char *name);
extern void TruncateRelation(char *name);
+extern void CommentRelation(char *name, char *attr, char *comment);
#endif /* CREATINH_H */
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.54 1999/10/02 21:33:33 tgl Exp $
+ * $Id: nodes.h,v 1.55 1999/10/15 01:49:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
T_DefineStmt,
T_DestroyStmt,
T_TruncateStmt,
+ T_CommentStmt,
T_ExtendStmt,
T_FetchStmt,
T_IndexStmt,
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.84 1999/10/07 04:23:17 tgl Exp $
+ * $Id: parsenodes.h,v 1.85 1999/10/15 01:49:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
NodeTag type;
char *relName; /* relation to be truncated */
} TruncateStmt;
+
+/* ----------------------
+ * Comment On Statement
+ * ----------------------
+ */
+typedef struct CommentStmt
+{
+ NodeTag type;
+ char *relname; /* relation to create/drop comment */
+ char *attrname; /* attribute to comment on */
+ char *comment; /* the actual comment */
+} CommentStmt;
/* ----------------------
* Extend Index Statement
-TDestReceiver \
-TDestroyStmt \
-TTruncateStmt \
+-TCommentStmt \
-TDestroydbStmt \
-TDisplay \
-TDl_info \