Add COMMENT ON CONSTRAINT facility (from Rod Taylor's pg_constraint patch).
Fix comment.c to not depend on parser token values, per discussion awhile back.
This commit is contained in:
parent
c4fb2b4e9e
commit
d5fa19c6ee
@ -7,7 +7,7 @@
|
|||||||
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.50 2002/07/12 18:43:15 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.51 2002/07/14 23:38:13 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#include "catalog/catname.h"
|
#include "catalog/catname.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
|
#include "catalog/pg_constraint.h"
|
||||||
#include "catalog/pg_database.h"
|
#include "catalog/pg_database.h"
|
||||||
#include "catalog/pg_description.h"
|
#include "catalog/pg_description.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
@ -30,7 +31,6 @@
|
|||||||
#include "parser/parse_func.h"
|
#include "parser/parse_func.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
#include "parser/parse.h"
|
|
||||||
#include "utils/acl.h"
|
#include "utils/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
@ -57,6 +57,7 @@ static void CommentAggregate(List *aggregate, List *arguments, char *comment);
|
|||||||
static void CommentProc(List *function, List *arguments, char *comment);
|
static void CommentProc(List *function, List *arguments, char *comment);
|
||||||
static void CommentOperator(List *opername, List *arguments, char *comment);
|
static void CommentOperator(List *opername, List *arguments, char *comment);
|
||||||
static void CommentTrigger(List *qualname, char *comment);
|
static void CommentTrigger(List *qualname, char *comment);
|
||||||
|
static void CommentConstraint(List *qualname, char *comment);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -70,39 +71,42 @@ CommentObject(CommentStmt *stmt)
|
|||||||
{
|
{
|
||||||
switch (stmt->objtype)
|
switch (stmt->objtype)
|
||||||
{
|
{
|
||||||
case INDEX:
|
case COMMENT_ON_INDEX:
|
||||||
case SEQUENCE:
|
case COMMENT_ON_SEQUENCE:
|
||||||
case TABLE:
|
case COMMENT_ON_TABLE:
|
||||||
case VIEW:
|
case COMMENT_ON_VIEW:
|
||||||
CommentRelation(stmt->objtype, stmt->objname, stmt->comment);
|
CommentRelation(stmt->objtype, stmt->objname, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case COLUMN:
|
case COMMENT_ON_COLUMN:
|
||||||
CommentAttribute(stmt->objname, stmt->comment);
|
CommentAttribute(stmt->objname, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case DATABASE:
|
case COMMENT_ON_DATABASE:
|
||||||
CommentDatabase(stmt->objname, stmt->comment);
|
CommentDatabase(stmt->objname, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case RULE:
|
case COMMENT_ON_RULE:
|
||||||
CommentRule(stmt->objname, stmt->comment);
|
CommentRule(stmt->objname, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case TYPE_P:
|
case COMMENT_ON_TYPE:
|
||||||
CommentType(stmt->objname, stmt->comment);
|
CommentType(stmt->objname, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case AGGREGATE:
|
case COMMENT_ON_AGGREGATE:
|
||||||
CommentAggregate(stmt->objname, stmt->objargs, stmt->comment);
|
CommentAggregate(stmt->objname, stmt->objargs, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case FUNCTION:
|
case COMMENT_ON_FUNCTION:
|
||||||
CommentProc(stmt->objname, stmt->objargs, stmt->comment);
|
CommentProc(stmt->objname, stmt->objargs, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case OPERATOR:
|
case COMMENT_ON_OPERATOR:
|
||||||
CommentOperator(stmt->objname, stmt->objargs, stmt->comment);
|
CommentOperator(stmt->objname, stmt->objargs, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case TRIGGER:
|
case COMMENT_ON_TRIGGER:
|
||||||
CommentTrigger(stmt->objname, stmt->comment);
|
CommentTrigger(stmt->objname, stmt->comment);
|
||||||
break;
|
break;
|
||||||
case SCHEMA:
|
case COMMENT_ON_SCHEMA:
|
||||||
CommentNamespace(stmt->objname, stmt->comment);
|
CommentNamespace(stmt->objname, stmt->comment);
|
||||||
break;
|
break;
|
||||||
|
case COMMENT_ON_CONSTRAINT:
|
||||||
|
CommentConstraint(stmt->objname, stmt->comment);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "An attempt was made to comment on a unknown type: %d",
|
elog(ERROR, "An attempt was made to comment on a unknown type: %d",
|
||||||
stmt->objtype);
|
stmt->objtype);
|
||||||
@ -309,26 +313,26 @@ CommentRelation(int objtype, List *relname, char *comment)
|
|||||||
|
|
||||||
switch (objtype)
|
switch (objtype)
|
||||||
{
|
{
|
||||||
case INDEX:
|
case COMMENT_ON_INDEX:
|
||||||
if (relation->rd_rel->relkind != RELKIND_INDEX)
|
if (relation->rd_rel->relkind != RELKIND_INDEX)
|
||||||
elog(ERROR, "relation \"%s\" is not an index",
|
elog(ERROR, "relation \"%s\" is not an index",
|
||||||
RelationGetRelationName(relation));
|
RelationGetRelationName(relation));
|
||||||
break;
|
break;
|
||||||
case TABLE:
|
case COMMENT_ON_SEQUENCE:
|
||||||
|
if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
|
||||||
|
elog(ERROR, "relation \"%s\" is not a sequence",
|
||||||
|
RelationGetRelationName(relation));
|
||||||
|
break;
|
||||||
|
case COMMENT_ON_TABLE:
|
||||||
if (relation->rd_rel->relkind != RELKIND_RELATION)
|
if (relation->rd_rel->relkind != RELKIND_RELATION)
|
||||||
elog(ERROR, "relation \"%s\" is not a table",
|
elog(ERROR, "relation \"%s\" is not a table",
|
||||||
RelationGetRelationName(relation));
|
RelationGetRelationName(relation));
|
||||||
break;
|
break;
|
||||||
case VIEW:
|
case COMMENT_ON_VIEW:
|
||||||
if (relation->rd_rel->relkind != RELKIND_VIEW)
|
if (relation->rd_rel->relkind != RELKIND_VIEW)
|
||||||
elog(ERROR, "relation \"%s\" is not a view",
|
elog(ERROR, "relation \"%s\" is not a view",
|
||||||
RelationGetRelationName(relation));
|
RelationGetRelationName(relation));
|
||||||
break;
|
break;
|
||||||
case SEQUENCE:
|
|
||||||
if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
|
|
||||||
elog(ERROR, "relation \"%s\" is not a sequence",
|
|
||||||
RelationGetRelationName(relation));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the comment using the relation's oid */
|
/* Create the comment using the relation's oid */
|
||||||
@ -439,7 +443,7 @@ CommentDatabase(List *qualname, char *comment)
|
|||||||
elog(ERROR, "you are not permitted to comment on database \"%s\"",
|
elog(ERROR, "you are not permitted to comment on database \"%s\"",
|
||||||
database);
|
database);
|
||||||
|
|
||||||
/* Create the comments with the pg_database oid */
|
/* Create the comment with the pg_database oid */
|
||||||
|
|
||||||
CreateComments(oid, RelOid_pg_database, 0, comment);
|
CreateComments(oid, RelOid_pg_database, 0, comment);
|
||||||
|
|
||||||
@ -805,7 +809,7 @@ CommentTrigger(List *qualname, char *comment)
|
|||||||
|
|
||||||
systable_endscan(scan);
|
systable_endscan(scan);
|
||||||
|
|
||||||
/* Create the comments with the pg_trigger oid */
|
/* Create the comment with the pg_trigger oid */
|
||||||
|
|
||||||
CreateComments(oid, RelationGetRelid(pg_trigger), 0, comment);
|
CreateComments(oid, RelationGetRelid(pg_trigger), 0, comment);
|
||||||
|
|
||||||
@ -814,3 +818,83 @@ CommentTrigger(List *qualname, char *comment)
|
|||||||
heap_close(pg_trigger, AccessShareLock);
|
heap_close(pg_trigger, AccessShareLock);
|
||||||
heap_close(relation, NoLock);
|
heap_close(relation, NoLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CommentConstraint --
|
||||||
|
*
|
||||||
|
* Enable commenting on constraints held within the pg_constraint
|
||||||
|
* table. A qualified name is required as constraint names are
|
||||||
|
* unique per relation.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
CommentConstraint(List *qualname, char *comment)
|
||||||
|
{
|
||||||
|
int nnames;
|
||||||
|
List *relName;
|
||||||
|
char *conName;
|
||||||
|
RangeVar *rel;
|
||||||
|
Relation pg_constraint,
|
||||||
|
relation;
|
||||||
|
HeapTuple tuple;
|
||||||
|
SysScanDesc scan;
|
||||||
|
ScanKeyData skey[1];
|
||||||
|
Oid conOid = InvalidOid;
|
||||||
|
|
||||||
|
/* Separate relname and constraint name */
|
||||||
|
nnames = length(qualname);
|
||||||
|
if (nnames < 2)
|
||||||
|
elog(ERROR, "CommentConstraint: must specify relation and constraint");
|
||||||
|
relName = ltruncate(nnames-1, listCopy(qualname));
|
||||||
|
conName = strVal(nth(nnames-1, qualname));
|
||||||
|
|
||||||
|
/* Open the owning relation to ensure it won't go away meanwhile */
|
||||||
|
rel = makeRangeVarFromNameList(relName);
|
||||||
|
relation = heap_openrv(rel, AccessShareLock);
|
||||||
|
|
||||||
|
/* Check object security */
|
||||||
|
|
||||||
|
if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
|
||||||
|
aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(relation));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch the constraint tuple from pg_constraint. There may be more than
|
||||||
|
* one match, because constraints are not required to have unique names;
|
||||||
|
* if so, error out.
|
||||||
|
*/
|
||||||
|
pg_constraint = heap_openr(ConstraintRelationName, AccessShareLock);
|
||||||
|
|
||||||
|
ScanKeyEntryInitialize(&skey[0], 0x0,
|
||||||
|
Anum_pg_constraint_conrelid, F_OIDEQ,
|
||||||
|
ObjectIdGetDatum(RelationGetRelid(relation)));
|
||||||
|
|
||||||
|
scan = systable_beginscan(pg_constraint, ConstraintRelidIndex, true,
|
||||||
|
SnapshotNow, 1, skey);
|
||||||
|
|
||||||
|
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
||||||
|
{
|
||||||
|
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
if (strcmp(NameStr(con->conname), conName) == 0)
|
||||||
|
{
|
||||||
|
if (OidIsValid(conOid))
|
||||||
|
elog(ERROR, "Relation \"%s\" has multiple constraints named \"%s\"",
|
||||||
|
RelationGetRelationName(relation), conName);
|
||||||
|
conOid = tuple->t_data->t_oid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
systable_endscan(scan);
|
||||||
|
|
||||||
|
/* If no constraint exists for the relation specified, notify user */
|
||||||
|
if (!OidIsValid(conOid))
|
||||||
|
elog(ERROR, "constraint \"%s\" for relation \"%s\" does not exist",
|
||||||
|
conName, RelationGetRelationName(relation));
|
||||||
|
|
||||||
|
/* Create the comment with the pg_constraint oid */
|
||||||
|
CreateComments(conOid, RelationGetRelid(pg_constraint), 0, comment);
|
||||||
|
|
||||||
|
/* Done, but hold lock on relation */
|
||||||
|
heap_close(pg_constraint, AccessShareLock);
|
||||||
|
heap_close(relation, NoLock);
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.339 2002/07/12 18:43:17 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.340 2002/07/14 23:38:13 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -2364,7 +2364,7 @@ CommentStmt:
|
|||||||
IS comment_text
|
IS comment_text
|
||||||
{
|
{
|
||||||
CommentStmt *n = makeNode(CommentStmt);
|
CommentStmt *n = makeNode(CommentStmt);
|
||||||
n->objtype = AGGREGATE;
|
n->objtype = COMMENT_ON_AGGREGATE;
|
||||||
n->objname = $4;
|
n->objname = $4;
|
||||||
n->objargs = makeList1($6);
|
n->objargs = makeList1($6);
|
||||||
n->comment = $9;
|
n->comment = $9;
|
||||||
@ -2373,7 +2373,7 @@ CommentStmt:
|
|||||||
| COMMENT ON FUNCTION func_name func_args IS comment_text
|
| COMMENT ON FUNCTION func_name func_args IS comment_text
|
||||||
{
|
{
|
||||||
CommentStmt *n = makeNode(CommentStmt);
|
CommentStmt *n = makeNode(CommentStmt);
|
||||||
n->objtype = FUNCTION;
|
n->objtype = COMMENT_ON_FUNCTION;
|
||||||
n->objname = $4;
|
n->objname = $4;
|
||||||
n->objargs = $5;
|
n->objargs = $5;
|
||||||
n->comment = $7;
|
n->comment = $7;
|
||||||
@ -2383,16 +2383,16 @@ CommentStmt:
|
|||||||
IS comment_text
|
IS comment_text
|
||||||
{
|
{
|
||||||
CommentStmt *n = makeNode(CommentStmt);
|
CommentStmt *n = makeNode(CommentStmt);
|
||||||
n->objtype = OPERATOR;
|
n->objtype = COMMENT_ON_OPERATOR;
|
||||||
n->objname = $4;
|
n->objname = $4;
|
||||||
n->objargs = $6;
|
n->objargs = $6;
|
||||||
n->comment = $9;
|
n->comment = $9;
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
| COMMENT ON TRIGGER name ON any_name IS comment_text
|
| COMMENT ON CONSTRAINT name ON any_name IS comment_text
|
||||||
{
|
{
|
||||||
CommentStmt *n = makeNode(CommentStmt);
|
CommentStmt *n = makeNode(CommentStmt);
|
||||||
n->objtype = TRIGGER;
|
n->objtype = COMMENT_ON_CONSTRAINT;
|
||||||
n->objname = lappend($6, makeString($4));
|
n->objname = lappend($6, makeString($4));
|
||||||
n->objargs = NIL;
|
n->objargs = NIL;
|
||||||
n->comment = $8;
|
n->comment = $8;
|
||||||
@ -2401,7 +2401,7 @@ CommentStmt:
|
|||||||
| COMMENT ON RULE name ON any_name IS comment_text
|
| COMMENT ON RULE name ON any_name IS comment_text
|
||||||
{
|
{
|
||||||
CommentStmt *n = makeNode(CommentStmt);
|
CommentStmt *n = makeNode(CommentStmt);
|
||||||
n->objtype = RULE;
|
n->objtype = COMMENT_ON_RULE;
|
||||||
n->objname = lappend($6, makeString($4));
|
n->objname = lappend($6, makeString($4));
|
||||||
n->objargs = NIL;
|
n->objargs = NIL;
|
||||||
n->comment = $8;
|
n->comment = $8;
|
||||||
@ -2411,24 +2411,33 @@ CommentStmt:
|
|||||||
{
|
{
|
||||||
/* Obsolete syntax supported for awhile for compatibility */
|
/* Obsolete syntax supported for awhile for compatibility */
|
||||||
CommentStmt *n = makeNode(CommentStmt);
|
CommentStmt *n = makeNode(CommentStmt);
|
||||||
n->objtype = RULE;
|
n->objtype = COMMENT_ON_RULE;
|
||||||
n->objname = makeList1(makeString($4));
|
n->objname = makeList1(makeString($4));
|
||||||
n->objargs = NIL;
|
n->objargs = NIL;
|
||||||
n->comment = $6;
|
n->comment = $6;
|
||||||
$$ = (Node *) n;
|
$$ = (Node *) n;
|
||||||
}
|
}
|
||||||
|
| COMMENT ON TRIGGER name ON any_name IS comment_text
|
||||||
|
{
|
||||||
|
CommentStmt *n = makeNode(CommentStmt);
|
||||||
|
n->objtype = COMMENT_ON_TRIGGER;
|
||||||
|
n->objname = lappend($6, makeString($4));
|
||||||
|
n->objargs = NIL;
|
||||||
|
n->comment = $8;
|
||||||
|
$$ = (Node *) n;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
comment_type:
|
comment_type:
|
||||||
COLUMN { $$ = COLUMN; }
|
COLUMN { $$ = COMMENT_ON_COLUMN; }
|
||||||
| DATABASE { $$ = DATABASE; }
|
| DATABASE { $$ = COMMENT_ON_DATABASE; }
|
||||||
| SCHEMA { $$ = SCHEMA; }
|
| SCHEMA { $$ = COMMENT_ON_SCHEMA; }
|
||||||
| INDEX { $$ = INDEX; }
|
| INDEX { $$ = COMMENT_ON_INDEX; }
|
||||||
| SEQUENCE { $$ = SEQUENCE; }
|
| SEQUENCE { $$ = COMMENT_ON_SEQUENCE; }
|
||||||
| TABLE { $$ = TABLE; }
|
| TABLE { $$ = COMMENT_ON_TABLE; }
|
||||||
| DOMAIN_P { $$ = TYPE_P; }
|
| DOMAIN_P { $$ = COMMENT_ON_TYPE; }
|
||||||
| TYPE_P { $$ = TYPE_P; }
|
| TYPE_P { $$ = COMMENT_ON_TYPE; }
|
||||||
| VIEW { $$ = VIEW; }
|
| VIEW { $$ = COMMENT_ON_VIEW; }
|
||||||
;
|
;
|
||||||
|
|
||||||
comment_text:
|
comment_text:
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.185 2002/07/12 18:43:19 tgl Exp $
|
* $Id: parsenodes.h,v 1.186 2002/07/14 23:38:13 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1165,10 +1165,25 @@ typedef struct TruncateStmt
|
|||||||
* Comment On Statement
|
* Comment On Statement
|
||||||
* ----------------------
|
* ----------------------
|
||||||
*/
|
*/
|
||||||
|
#define COMMENT_ON_AGGREGATE 100
|
||||||
|
#define COMMENT_ON_COLUMN 101
|
||||||
|
#define COMMENT_ON_CONSTRAINT 102
|
||||||
|
#define COMMENT_ON_DATABASE 103
|
||||||
|
#define COMMENT_ON_FUNCTION 104
|
||||||
|
#define COMMENT_ON_INDEX 105
|
||||||
|
#define COMMENT_ON_OPERATOR 106
|
||||||
|
#define COMMENT_ON_RULE 107
|
||||||
|
#define COMMENT_ON_SCHEMA 108
|
||||||
|
#define COMMENT_ON_SEQUENCE 109
|
||||||
|
#define COMMENT_ON_TABLE 110
|
||||||
|
#define COMMENT_ON_TRIGGER 111
|
||||||
|
#define COMMENT_ON_TYPE 112
|
||||||
|
#define COMMENT_ON_VIEW 113
|
||||||
|
|
||||||
typedef struct CommentStmt
|
typedef struct CommentStmt
|
||||||
{
|
{
|
||||||
NodeTag type;
|
NodeTag type;
|
||||||
int objtype; /* Object's type */
|
int objtype; /* Object's type, see codes above */
|
||||||
List *objname; /* Qualified name of the object */
|
List *objname; /* Qualified name of the object */
|
||||||
List *objargs; /* Arguments if needed (eg, for functions) */
|
List *objargs; /* Arguments if needed (eg, for functions) */
|
||||||
char *comment; /* Comment to insert, or NULL to remove */
|
char *comment; /* Comment to insert, or NULL to remove */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user