7
7
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.50 2002/07/12 18:43:15 tgl Exp $
10
+ * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.51 2002/07/14 23:38:13 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
19
19
#include "catalog/catname.h"
20
20
#include "catalog/indexing.h"
21
21
#include "catalog/namespace.h"
22
+ #include "catalog/pg_constraint.h"
22
23
#include "catalog/pg_database.h"
23
24
#include "catalog/pg_description.h"
24
25
#include "catalog/pg_namespace.h"
30
31
#include "parser/parse_func.h"
31
32
#include "parser/parse_oper.h"
32
33
#include "parser/parse_type.h"
33
- #include "parser/parse.h"
34
34
#include "utils/acl.h"
35
35
#include "utils/builtins.h"
36
36
#include "utils/fmgroids.h"
@@ -57,6 +57,7 @@ static void CommentAggregate(List *aggregate, List *arguments, char *comment);
57
57
static void CommentProc (List * function ,List * arguments ,char * comment );
58
58
static void CommentOperator (List * opername ,List * arguments ,char * comment );
59
59
static void CommentTrigger (List * qualname ,char * comment );
60
+ static void CommentConstraint (List * qualname ,char * comment );
60
61
61
62
62
63
/*
@@ -70,39 +71,42 @@ CommentObject(CommentStmt *stmt)
70
71
{
71
72
switch (stmt -> objtype )
72
73
{
73
- case INDEX :
74
- case SEQUENCE :
75
- case TABLE :
76
- case VIEW :
74
+ case COMMENT_ON_INDEX :
75
+ case COMMENT_ON_SEQUENCE :
76
+ case COMMENT_ON_TABLE :
77
+ case COMMENT_ON_VIEW :
77
78
CommentRelation (stmt -> objtype ,stmt -> objname ,stmt -> comment );
78
79
break ;
79
- case COLUMN :
80
+ case COMMENT_ON_COLUMN :
80
81
CommentAttribute (stmt -> objname ,stmt -> comment );
81
82
break ;
82
- case DATABASE :
83
+ case COMMENT_ON_DATABASE :
83
84
CommentDatabase (stmt -> objname ,stmt -> comment );
84
85
break ;
85
- case RULE :
86
+ case COMMENT_ON_RULE :
86
87
CommentRule (stmt -> objname ,stmt -> comment );
87
88
break ;
88
- case TYPE_P :
89
+ case COMMENT_ON_TYPE :
89
90
CommentType (stmt -> objname ,stmt -> comment );
90
91
break ;
91
- case AGGREGATE :
92
+ case COMMENT_ON_AGGREGATE :
92
93
CommentAggregate (stmt -> objname ,stmt -> objargs ,stmt -> comment );
93
94
break ;
94
- case FUNCTION :
95
+ case COMMENT_ON_FUNCTION :
95
96
CommentProc (stmt -> objname ,stmt -> objargs ,stmt -> comment );
96
97
break ;
97
- case OPERATOR :
98
+ case COMMENT_ON_OPERATOR :
98
99
CommentOperator (stmt -> objname ,stmt -> objargs ,stmt -> comment );
99
100
break ;
100
- case TRIGGER :
101
+ case COMMENT_ON_TRIGGER :
101
102
CommentTrigger (stmt -> objname ,stmt -> comment );
102
103
break ;
103
- case SCHEMA :
104
+ case COMMENT_ON_SCHEMA :
104
105
CommentNamespace (stmt -> objname ,stmt -> comment );
105
106
break ;
107
+ case COMMENT_ON_CONSTRAINT :
108
+ CommentConstraint (stmt -> objname ,stmt -> comment );
109
+ break ;
106
110
default :
107
111
elog (ERROR ,"An attempt was made to comment on a unknown type: %d" ,
108
112
stmt -> objtype );
@@ -309,26 +313,26 @@ CommentRelation(int objtype, List *relname, char *comment)
309
313
310
314
switch (objtype )
311
315
{
312
- case INDEX :
316
+ case COMMENT_ON_INDEX :
313
317
if (relation -> rd_rel -> relkind != RELKIND_INDEX )
314
318
elog (ERROR ,"relation \"%s\" is not an index" ,
315
319
RelationGetRelationName (relation ));
316
320
break ;
317
- case TABLE :
321
+ case COMMENT_ON_SEQUENCE :
322
+ if (relation -> rd_rel -> relkind != RELKIND_SEQUENCE )
323
+ elog (ERROR ,"relation \"%s\" is not a sequence" ,
324
+ RelationGetRelationName (relation ));
325
+ break ;
326
+ case COMMENT_ON_TABLE :
318
327
if (relation -> rd_rel -> relkind != RELKIND_RELATION )
319
328
elog (ERROR ,"relation \"%s\" is not a table" ,
320
329
RelationGetRelationName (relation ));
321
330
break ;
322
- case VIEW :
331
+ case COMMENT_ON_VIEW :
323
332
if (relation -> rd_rel -> relkind != RELKIND_VIEW )
324
333
elog (ERROR ,"relation \"%s\" is not a view" ,
325
334
RelationGetRelationName (relation ));
326
335
break ;
327
- case SEQUENCE :
328
- if (relation -> rd_rel -> relkind != RELKIND_SEQUENCE )
329
- elog (ERROR ,"relation \"%s\" is not a sequence" ,
330
- RelationGetRelationName (relation ));
331
- break ;
332
336
}
333
337
334
338
/* Create the comment using the relation's oid */
@@ -439,7 +443,7 @@ CommentDatabase(List *qualname, char *comment)
439
443
elog (ERROR ,"you are not permitted to comment on database \"%s\"" ,
440
444
database );
441
445
442
- /* Create thecomments with the pg_database oid */
446
+ /* Create thecomment with the pg_database oid */
443
447
444
448
CreateComments (oid ,RelOid_pg_database ,0 ,comment );
445
449
@@ -805,7 +809,7 @@ CommentTrigger(List *qualname, char *comment)
805
809
806
810
systable_endscan (scan );
807
811
808
- /* Create thecomments with the pg_trigger oid */
812
+ /* Create thecomment with the pg_trigger oid */
809
813
810
814
CreateComments (oid ,RelationGetRelid (pg_trigger ),0 ,comment );
811
815
@@ -814,3 +818,83 @@ CommentTrigger(List *qualname, char *comment)
814
818
heap_close (pg_trigger ,AccessShareLock );
815
819
heap_close (relation ,NoLock );
816
820
}
821
+
822
+
823
+ /*
824
+ * CommentConstraint --
825
+ *
826
+ * Enable commenting on constraints held within the pg_constraint
827
+ * table. A qualified name is required as constraint names are
828
+ * unique per relation.
829
+ */
830
+ static void
831
+ CommentConstraint (List * qualname ,char * comment )
832
+ {
833
+ int nnames ;
834
+ List * relName ;
835
+ char * conName ;
836
+ RangeVar * rel ;
837
+ Relation pg_constraint ,
838
+ relation ;
839
+ HeapTuple tuple ;
840
+ SysScanDesc scan ;
841
+ ScanKeyData skey [1 ];
842
+ Oid conOid = InvalidOid ;
843
+
844
+ /* Separate relname and constraint name */
845
+ nnames = length (qualname );
846
+ if (nnames < 2 )
847
+ elog (ERROR ,"CommentConstraint: must specify relation and constraint" );
848
+ relName = ltruncate (nnames - 1 ,listCopy (qualname ));
849
+ conName = strVal (nth (nnames - 1 ,qualname ));
850
+
851
+ /* Open the owning relation to ensure it won't go away meanwhile */
852
+ rel = makeRangeVarFromNameList (relName );
853
+ relation = heap_openrv (rel ,AccessShareLock );
854
+
855
+ /* Check object security */
856
+
857
+ if (!pg_class_ownercheck (RelationGetRelid (relation ),GetUserId ()))
858
+ aclcheck_error (ACLCHECK_NOT_OWNER ,RelationGetRelationName (relation ));
859
+
860
+ /*
861
+ * Fetch the constraint tuple from pg_constraint. There may be more than
862
+ * one match, because constraints are not required to have unique names;
863
+ * if so, error out.
864
+ */
865
+ pg_constraint = heap_openr (ConstraintRelationName ,AccessShareLock );
866
+
867
+ ScanKeyEntryInitialize (& skey [0 ],0x0 ,
868
+ Anum_pg_constraint_conrelid ,F_OIDEQ ,
869
+ ObjectIdGetDatum (RelationGetRelid (relation )));
870
+
871
+ scan = systable_beginscan (pg_constraint ,ConstraintRelidIndex , true,
872
+ SnapshotNow ,1 ,skey );
873
+
874
+ while (HeapTupleIsValid (tuple = systable_getnext (scan )))
875
+ {
876
+ Form_pg_constraint con = (Form_pg_constraint )GETSTRUCT (tuple );
877
+
878
+ if (strcmp (NameStr (con -> conname ),conName )== 0 )
879
+ {
880
+ if (OidIsValid (conOid ))
881
+ elog (ERROR ,"Relation \"%s\" has multiple constraints named \"%s\"" ,
882
+ RelationGetRelationName (relation ),conName );
883
+ conOid = tuple -> t_data -> t_oid ;
884
+ }
885
+ }
886
+
887
+ systable_endscan (scan );
888
+
889
+ /* If no constraint exists for the relation specified, notify user */
890
+ if (!OidIsValid (conOid ))
891
+ elog (ERROR ,"constraint \"%s\" for relation \"%s\" does not exist" ,
892
+ conName ,RelationGetRelationName (relation ));
893
+
894
+ /* Create the comment with the pg_constraint oid */
895
+ CreateComments (conOid ,RelationGetRelid (pg_constraint ),0 ,comment );
896
+
897
+ /* Done, but hold lock on relation */
898
+ heap_close (pg_constraint ,AccessShareLock );
899
+ heap_close (relation ,NoLock );
900
+ }