<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.18 2002/04/23 02:07:15 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/comment.sgml,v 1.19 2002/05/13 17:45:30 tgl Exp $
PostgreSQL documentation
-->
<synopsis>
COMMENT ON
[
- [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW ] <replaceable class="PARAMETER">object_name</replaceable> |
+ TABLE <replaceable class="PARAMETER">object_name</replaceable> |
COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
AGGREGATE <replaceable class="PARAMETER">agg_name</replaceable> (<replaceable class="PARAMETER">agg_type</replaceable>) |
- FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1</replaceable>, <replaceable class="PARAMETER">arg2</replaceable>, ...) |
- OPERATOR <replaceable class="PARAMETER">op</replaceable> (<replaceable class="PARAMETER">leftoperand_type</replaceable> <replaceable class="PARAMETER">rightoperand_type</replaceable>) |
+ DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
+ DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
+ FUNCTION <replaceable class="PARAMETER">func_name</replaceable> (<replaceable class="PARAMETER">arg1_type</replaceable>, <replaceable class="PARAMETER">arg2_type</replaceable>, ...) |
+ INDEX <replaceable class="PARAMETER">object_name</replaceable> |
+ OPERATOR <replaceable class="PARAMETER">op</replaceable> (<replaceable class="PARAMETER">leftoperand_type</replaceable>, <replaceable class="PARAMETER">rightoperand_type</replaceable>) |
RULE <replaceable class="PARAMETER">rule_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
- TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable>
+ SCHEMA <replaceable class="PARAMETER">object_name</replaceable> |
+ SEQUENCE <replaceable class="PARAMETER">object_name</replaceable> |
+ TRIGGER <replaceable class="PARAMETER">trigger_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
+ TYPE <replaceable class="PARAMETER">object_name</replaceable> |
+ VIEW <replaceable class="PARAMETER">object_name</replaceable>
] IS <replaceable class="PARAMETER">'text'</replaceable>
</synopsis>
<listitem>
<para>
The name of the object to be be commented. Names of tables,
- indexes, sequences, views, types, domains, functions, aggregates,
- and operators may be schema-qualified.
+ aggregates, domains, functions, indexes, operators, sequences, types,
+ and views
+ may be schema-qualified.
</para>
</listitem>
</varlistentry>
Comments are automatically dropped when the object is dropped.
</para>
+ <note>
<para>
- It should be noted that there is presently no security mechanism
+ There is presently no security mechanism
for comments: any user connected to a database can see all the comments
for objects in that database (although only superusers can change
comments for objects that they don't own). Therefore, don't put
security-critical information in comments.
</para>
+ </note>
</refsect1>
<refsect1 id="R1-SQL-COMMENT-2">
Usage
</title>
<para>
- Comment the table <literal>mytable</literal>:
+ Attach a comment to the table <literal>mytable</literal>:
<programlisting>
-COMMENT ON mytable IS 'This is my table.';
+COMMENT ON TABLE mytable IS 'This is my table.';
+ </programlisting>
+
+ Remove it again:
+
+ <programlisting>
+COMMENT ON TABLE mytable IS NULL;
</programlisting>
</para>
Some more examples:
<programlisting>
+COMMENT ON AGGREGATE my_aggregate (double precision) IS 'Computes sample variance';
+COMMENT ON COLUMN my_table.my_field IS 'Employee ID number';
COMMENT ON DATABASE my_database IS 'Development Database';
COMMENT ON DOMAIN my_domain IS 'Email Address Domain';
-COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee id';
-COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
-COMMENT ON TABLE my_table IS 'Employee Information';
-COMMENT ON TYPE my_type IS 'Complex Number support';
-COMMENT ON VIEW my_view IS 'View of departmental costs';
-COMMENT ON COLUMN my_table.my_field IS 'Employee ID number';
-COMMENT ON AGGREGATE my_aggregate (double precision) IS 'Computes sample variance';
COMMENT ON FUNCTION my_function (timestamp) IS 'Returns Roman Numeral';
-COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two text';
+COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee id';
+COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two texts';
+COMMENT ON OPERATOR ^ (NONE, text) IS 'This is a prefix operator on text';
COMMENT ON RULE my_rule ON my_table IS 'Logs UPDATES of employee records';
+COMMENT ON SCHEMA my_schema IS 'Departmental data';
+COMMENT ON SEQUENCE my_sequence IS 'Used to generate primary keys';
+COMMENT ON TABLE my_schema.my_table IS 'Employee Information';
COMMENT ON TRIGGER my_trigger ON my_table IS 'Used for R.I.';
+COMMENT ON TYPE complex IS 'Complex Number datatype';
+COMMENT ON VIEW my_view IS 'View of departmental costs';
</programlisting>
</para>
</refsect1>
* Copyright (c) 1999-2001, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.45 2002/04/27 03:45:00 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.46 2002/05/13 17:45:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static void CommentRelation(int objtype, List *relname, char *comment);
static void CommentAttribute(List *qualname, char *comment);
static void CommentDatabase(List *qualname, char *comment);
+static void CommentNamespace(List *qualname, char *comment);
static void CommentRule(List *qualname, char *comment);
static void CommentType(List *typename, char *comment);
static void CommentAggregate(List *aggregate, List *arguments, char *comment);
case TRIGGER:
CommentTrigger(stmt->objname, stmt->comment);
break;
+ case SCHEMA:
+ CommentNamespace(stmt->objname, stmt->comment);
+ break;
default:
elog(ERROR, "An attempt was made to comment on a unknown type: %d",
stmt->objtype);
{
case 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));
break;
case TABLE:
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));
break;
case 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));
break;
case SEQUENCE:
if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
- elog(ERROR, "relation '%s' is not a sequence",
+ elog(ERROR, "relation \"%s\" is not a sequence",
RelationGetRelationName(relation));
break;
}
attnum = get_attnum(RelationGetRelid(relation), attrname);
if (attnum == InvalidAttrNumber)
- elog(ERROR, "'%s' is not an attribute of class '%s'",
+ elog(ERROR, "\"%s\" is not an attribute of class \"%s\"",
attrname, RelationGetRelationName(relation));
/* Create the comment using the relation's oid */
/* Validate database exists, and fetch the db oid */
if (!HeapTupleIsValid(dbtuple))
- elog(ERROR, "database '%s' does not exist", database);
+ elog(ERROR, "database \"%s\" does not exist", database);
oid = dbtuple->t_data->t_oid;
/* Allow if the user matches the database dba or is a superuser */
if (!(superuser() || is_dbadmin(oid)))
- elog(ERROR, "you are not permitted to comment on database '%s'",
+ elog(ERROR, "you are not permitted to comment on database \"%s\"",
database);
/* Create the comments with the pg_database oid */
heap_close(pg_database, AccessShareLock);
}
+/*
+ * CommentNamespace --
+ *
+ * This routine is used to add/drop any user-comments a user might
+ * have regarding the specified namespace. The routine will check
+ * security for owner permissions, and, if succesful, will then
+ * attempt to find the oid of the namespace specified. Once found,
+ * a comment is added/dropped using the CreateComments() routine.
+ */
+static void
+CommentNamespace(List *qualname, char *comment)
+{
+ Oid oid;
+ Oid classoid;
+ HeapTuple tp;
+ char *namespace;
+
+ if (length(qualname) != 1)
+ elog(ERROR, "CommentSchema: schema name may not be qualified");
+ namespace = strVal(lfirst(qualname));
+
+ tp = SearchSysCache(NAMESPACENAME,
+ CStringGetDatum(namespace),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "CommentSchema: Schema \"%s\" could not be found",
+ namespace);
+
+ oid = tp->t_data->t_oid;
+
+ /* Check object security */
+ if (!pg_namespace_ownercheck(oid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, namespace);
+
+ /* pg_namespace doesn't have a hard-coded OID, so must look it up */
+ classoid = get_relname_relid(NamespaceRelationName, PG_CATALOG_NAMESPACE);
+ Assert(OidIsValid(classoid));
+
+ /* Call CreateComments() to create/drop the comments */
+ CreateComments(oid, classoid, 0, comment);
+
+ /* Cleanup */
+ ReleaseSysCache(tp);
+}
+
/*
* CommentRule --
*
}
else
{
- elog(ERROR, "rule '%s' does not exist", rulename);
+ elog(ERROR, "rule \"%s\" does not exist", rulename);
reloid = ruleoid = 0; /* keep compiler quiet */
}
if (HeapTupleIsValid(tuple = heap_getnext(scanDesc, 0)))
- elog(ERROR, "There are multiple rules '%s'"
+ elog(ERROR, "There are multiple rules \"%s\""
"\n\tPlease specify a relation name as well as a rule name",
rulename);
PointerGetDatum(rulename),
0, 0);
if (!HeapTupleIsValid(tuple))
- elog(ERROR, "rule '%s' does not exist", rulename);
+ elog(ERROR, "rule \"%s\" does not exist", rulename);
Assert(reloid == ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class);
ruleoid = tuple->t_data->t_oid;
ReleaseSysCache(tuple);
aclcheck_error(aclcheck, rulename);
/* pg_rewrite doesn't have a hard-coded OID, so must look it up */
-
classoid = get_relname_relid(RewriteRelationName, PG_CATALOG_NAMESPACE);
Assert(OidIsValid(classoid));
* its name and its argument list which defines the left and right
* hand types the operator will operate on. The argument list is
* expected to be a couple of parse nodes pointed to be a List
- * object. If the comments string is empty, the associated comment
- * is dropped.
- *
- * NOTE: we actually attach the comment to the procedure that underlies
- * the operator. This is a feature, not a bug: we want the same comment
- * to be visible for both operator and function.
+ * object.
*/
static void
CommentOperator(List *opername, List *arguments, char *comment)
TypeName *typenode1 = (TypeName *) lfirst(arguments);
TypeName *typenode2 = (TypeName *) lsecond(arguments);
Oid oid;
+ Oid classoid;
/* Look up the operator */
-
oid = LookupOperNameTypeNames(opername, typenode1, typenode2,
"CommentOperator");
/* Valid user's ability to comment on this operator */
-
if (!pg_oper_ownercheck(oid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(opername));
- /* Get the procedure associated with the operator */
-
- oid = get_opcode(oid);
- if (oid == InvalidOid)
- elog(ERROR, "operator '%s' does not have an underlying function",
- NameListToString(opername));
+ /* pg_operator doesn't have a hard-coded OID, so must look it up */
+ classoid = get_relname_relid(OperatorRelationName, PG_CATALOG_NAMESPACE);
+ Assert(OidIsValid(classoid));
/* Call CreateComments() to create/drop the comments */
-
- CreateComments(oid, RelOid_pg_proc, 0, comment);
+ CreateComments(oid, classoid, 0, comment);
}
/*
/* If no trigger exists for the relation specified, notify user */
if (!HeapTupleIsValid(triggertuple))
- elog(ERROR, "trigger '%s' for relation '%s' does not exist",
+ elog(ERROR, "trigger \"%s\" for relation \"%s\" does not exist",
trigname, RelationGetRelationName(relation));
oid = triggertuple->t_data->t_oid;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.259 2002/05/10 22:36:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.260 2002/05/13 17:45:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
nsinfo[i].usename, "SCHEMA", NULL,
q->data, delq->data, NULL, NULL, NULL);
-#ifdef NOTYET /* suppress till COMMENT ON SCHEMA works */
/*** Dump Schema Comments ***/
resetPQExpBuffer(q);
appendPQExpBuffer(q, "SCHEMA %s",
dumpComment(fout, q->data,
NULL, nsinfo[i].usename,
nsinfo[i].oid, "pg_namespace", 0, NULL);
-#endif
}
destroyPQExpBuffer(q);
/*** Dump Function Comments ***/
resetPQExpBuffer(q);
- appendPQExpBuffer(q, "FUNCTION %s ", fn->data);
+ appendPQExpBuffer(q, "FUNCTION %s", fn->data);
dumpComment(fout, q->data,
finfo->pronamespace->nspname, finfo->usename,
finfo->oid, "pg_proc", 0, NULL);
q->data, delq->data,
NULL, NULL, NULL);
- /*
- * Note: no need to dump operator comment; we expect that the comment
- * is attached to the underlying function instead. (If the function
- * isn't getting dumped ... you lose.)
- */
+ /*** Dump Operator Comments ***/
+
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
+ dumpComment(fout, q->data,
+ oprinfo->oprnamespace->nspname, oprinfo->usename,
+ oprinfo->oid, "pg_operator", 0, NULL);
PQclear(res);