]> granicus.if.org Git - postgresql/commitdiff
This patch implements ORACLE's COMMENT SQL command.
authorBruce Momjian <bruce@momjian.us>
Fri, 15 Oct 1999 01:49:49 +0000 (01:49 +0000)
committerBruce Momjian <bruce@momjian.us>
Fri, 15 Oct 1999 01:49:49 +0000 (01:49 +0000)
>From the ORACLE 7 SQL Language Reference Manual:
-----------------------------------------------------
COMMENT

Purpose:

To add a comment about a table, view, snapshot, or
column into the data dictionary.

Prerequisites:

The table, view, or snapshot must be in your own
schema
or you must have COMMENT ANY TABLE system privilege.

Syntax:

COMMENT ON [ TABLE table ] |
           [ COLUMN table.column] IS 'text'

You can effectively drop a comment from the database
by setting it to the empty string ''.
-----------------------------------------------------

Example:

COMMENT ON TABLE workorders IS
   'Maintains base records for workorder information';

COMMENT ON COLUMN workorders.hours IS
   'Number of hours the engineer worked on the task';

to drop a comment:

COMMENT ON COLUMN workorders.hours IS '';

The current patch will simply perform the insert into
pg_description, as per the TODO. And, of course, when
the table is dropped, any comments relating to it
or any of its attributes are also dropped. I haven't
looked at the ODBC source yet, but I do know from
an ODBC client standpoint that the standard does
support the notion of table and column comments.
Hopefully the ODBC driver is already fetching these
values from pg_description, but if not, it should be
trivial.

Hope this makes the grade,

Mike Mascari
(mascarim@yahoo.com)

12 files changed:
src/backend/catalog/heap.c
src/backend/catalog/indexing.c
src/backend/commands/creatinh.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/tcop/utility.c
src/include/catalog/heap.h
src/include/catalog/pg_description.h
src/include/commands/creatinh.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/tools/pgindent/pgindent

index 0f3044b9a6a07ba50f3f32306c195140e52a1f57..bd0a8668d0fe97a0f126672736ea2c64df6f7d07 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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
@@ -38,6 +38,7 @@
 #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"
@@ -67,6 +68,7 @@ static void AddNewRelationTuple(Relation pg_class_desc,
                                  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);
@@ -861,10 +863,11 @@ heap_create_with_catalog(char *relname,
  *             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
@@ -1269,18 +1272,152 @@ DeleteAttributeTuples(Relation rel)
                 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
  *
@@ -1471,6 +1608,13 @@ heap_destroy_with_catalog(char *relname)
         */
        DeleteAttributeTuples(rel);
 
+       /* ----------------
+        *      delete comments
+         * ----------------
+         */
+
+       DeleteComments(RelationGetRelid(rel));
+
        if (istemp)
                remove_temp_relation(rid);
 
index 1e5c6252a4bad335cb4c2c1cca748f7bd96636b4..2caffcbcf5cac67af4bed656c1511e97bcb39c1e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,6 +55,9 @@ char     *Name_pg_trigger_indices[Num_pg_trigger_indices] = {TriggerRelidIndex,
        TriggerConstrNameIndex,
        TriggerConstrRelidIndex};
 
+char       *Name_pg_description_indices[Num_pg_description_indices] = {DescriptionObjIndex};
+
+
 
 static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
                                           Relation idesc,
index 0b2d2360b3c685f66ea696bbe99055fc8e492fb5..9463d55a6a16be2bb64081d660bf97a5cdc90ed0 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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"
 
@@ -232,6 +234,52 @@ TruncateRelation(char *name)
        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.
index a88b66c970732259c5d83c0fe6630b8c7cb00d77..16a4efa2baa49fdeb6babe428db091e2cda13e76 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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
@@ -118,7 +118,7 @@ Oid param_type(int t); /* used in parse_expr.c */
 %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,
@@ -314,7 +314,7 @@ Oid param_type(int t); /* used in parse_expr.c */
  */
 %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,
@@ -402,6 +402,7 @@ stmt :        AddAttrStmt
                | DefineStmt
                | DestroyStmt           
                | TruncateStmt
+               | CommentStmt
                | DropPLangStmt
                | DropTrigStmt
                | DropUserStmt
@@ -1539,6 +1540,32 @@ TruncateStmt:  TRUNCATE TABLE relation_name
                                }
                        ;
 
+/*****************************************************************************
+ *
+ *             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:
@@ -5011,6 +5038,7 @@ ColId:  IDENT                                                     { $$ = $1; }
                | BACKWARD                                              { $$ = "backward"; }
                | BEFORE                                                { $$ = "before"; }
                | CACHE                                                 { $$ = "cache"; }
+               | COMMENT                                               { $$ = "comment"; }
                | COMMITTED                                             { $$ = "committed"; }
                | CONSTRAINTS                                   { $$ = "constraints"; }
                | CREATEDB                                              { $$ = "createdb"; }
@@ -5081,6 +5109,7 @@ ColId:  IDENT                                                     { $$ = $1; }
                | TIMEZONE_HOUR                                 { $$ = "timezone_hour"; }
                | TIMEZONE_MINUTE                               { $$ = "timezone_minute"; }
                | TRIGGER                                               { $$ = "trigger"; }
+               | TRUNCATE                                              { $$ = "truncate"; }
                | TRUSTED                                               { $$ = "trusted"; }
                | TYPE_P                                                { $$ = "type"; }
                | VALID                                                 { $$ = "valid"; }
index 3e30a47d12a9b12085f839700f09e064979fb980..392e7509c8ee39cf7fac5aa7faee6bc5ffb47587 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,6 +60,7 @@ static ScanKeyword ScanKeywords[] = {
        {"coalesce", COALESCE},
        {"collate", COLLATE},
        {"column", COLUMN},
+       {"comment", COMMENT},
        {"commit", COMMIT},
        {"committed", COMMITTED},
        {"constraint", CONSTRAINT},
index 0b8d1efcdde034244edb48828b9c0af37ddaee9b..ec617d753692251b224e358014d3e504aab31ee0 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -233,6 +233,28 @@ ProcessUtility(Node *parsetree,
                        }
                        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;
index faa708ff24bb803c8d96c71455689e69b8901808..4720013160486ad5f28023fac2d2cd19e817d8f7 100644 (file)
@@ -6,7 +6,7 @@
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,6 +32,9 @@ extern void heap_destroy_with_catalog(char *relname);
 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);
index d50da53d92b18977964a0389031ebfeb31a04428..5db9204669b27779aae8c62d03ddd81bb0147c47 100644 (file)
@@ -6,7 +6,7 @@
  *
  * 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
@@ -65,3 +65,4 @@ typedef FormData_pg_description *Form_pg_description;
  */
 
 #endif  /* PG_DESCRIPTION_H */
+
index ffb111937a0e5e6cfd76d4d487065cec5ca45f42..11d5fdb7a0d41602c310cf8ff043f8ee6947dba0 100644 (file)
@@ -6,7 +6,7 @@
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,5 +18,6 @@
 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 */
index 08705ea9f6ebfcc5cce71595f0e00687ea3755ee..09f60466f4399d5877df0a98bebe66b25b859194 100644 (file)
@@ -6,7 +6,7 @@
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -152,6 +152,7 @@ typedef enum NodeTag
        T_DefineStmt,
        T_DestroyStmt,
        T_TruncateStmt,
+       T_CommentStmt,
        T_ExtendStmt,
        T_FetchStmt,
        T_IndexStmt,
index 1556bf38693e8aa162ac1defa8b01f114cf801c3..208b31d740da7ac5b67b28b8be0d33f098514903 100644 (file)
@@ -6,7 +6,7 @@
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -309,6 +309,18 @@ typedef struct TruncateStmt
         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
index ddffb937b6c80bfce3f14f21ede1d664ec2e1b1b..4b7a3ad17526313770f3d1c4ae1137947bbbe24c 100755 (executable)
@@ -164,6 +164,7 @@ do
 -TDestReceiver \
 -TDestroyStmt \
 -TTruncateStmt \
+-TCommentStmt \
 -TDestroydbStmt \
 -TDisplay \
 -TDl_info \