1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-09 06:21:09 +03:00

I've created a new shared catalog table pg_shdescription to store

comments on cluster global objects like databases, tablespaces, and
roles.

It touches a lot of places, but not much in the way of big changes.  The
only design decision I made was to duplicate the query and manipulation
functions rather than to try and have them handle both shared and local
comments.  I believe this is simpler for the code and not an issue for
callers because they know what type of object they are dealing with.
This has resulted in a shobj_description function analagous to
obj_description and backend functions [Create/Delete]SharedComments
mirroring the existing [Create/Delete]Comments functions.

pg_shdescription.h goes into src/include/catalog/

Kris Jurka
This commit is contained in:
Bruce Momjian
2006-02-12 03:22:21 +00:00
parent 95dbf9c02f
commit f9a726aa88
25 changed files with 617 additions and 82 deletions

View File

@@ -2,7 +2,7 @@
#
# Makefile for backend/catalog
#
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.58 2005/12/09 21:19:35 petere Exp $
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.59 2006/02/12 03:22:17 momjian Exp $
#
#-------------------------------------------------------------------------
@@ -15,7 +15,7 @@ OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
pg_type.o
BKIFILES = postgres.bki postgres.description
BKIFILES = postgres.bki postgres.description postgres.shdescription
all: SUBSYS.o $(BKIFILES)
@@ -34,7 +34,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_depend.h \
pg_database.h pg_tablespace.h pg_pltemplate.h \
pg_authid.h pg_auth_members.h pg_shdepend.h \
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
indexing.h \
)
@@ -43,6 +43,8 @@ pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
# see explanation in ../parser/Makefile
postgres.description: postgres.bki ;
postgres.shdescription: postgres.bki ;
postgres.bki: genbki.sh $(POSTGRES_BKI_SRCS) \
$(top_srcdir)/src/include/postgres_ext.h $(top_builddir)/src/include/pg_config_manual.h
AWK='$(AWK)' $(SHELL) $< $(pg_includes) --set-version=$(VERSION) -o postgres $(POSTGRES_BKI_SRCS)
@@ -51,6 +53,7 @@ postgres.bki: genbki.sh $(POSTGRES_BKI_SRCS) \
install-data: $(BKIFILES) installdirs
$(INSTALL_DATA) postgres.bki '$(DESTDIR)$(datadir)/postgres.bki'
$(INSTALL_DATA) postgres.description '$(DESTDIR)$(datadir)/postgres.description'
$(INSTALL_DATA) postgres.shdescription '$(DESTDIR)$(datadir)/postgres.shdescription'
$(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql'
$(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql'
$(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt'

View File

@@ -11,7 +11,7 @@
#
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.37 2005/06/28 05:08:52 tgl Exp $
# $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.38 2006/02/12 03:22:17 momjian Exp $
#
# NOTES
# non-essential whitespace is removed from the generated file.
@@ -103,7 +103,7 @@ fi
TMPFILE="genbkitmp$$.c"
trap "rm -f $TMPFILE ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.description.$$" 0 1 2 3 15
trap "rm -f $TMPFILE ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.shdescription.$$" 0 1 2 3 15
# Get NAMEDATALEN from postgres_ext.h
@@ -131,6 +131,7 @@ for dir in $INCLUDE_DIRS; do
done
touch ${OUTPUT_PREFIX}.description.$$
touch ${OUTPUT_PREFIX}.shdescription.$$
# ----------------
# Strip comments and other trash from .h
@@ -201,7 +202,7 @@ comment_level > 0 { next; }
# ----------------
# DATA() statements are basically passed right through after
# stripping off the DATA( and the ) on the end.
# Remember the OID for use by DESCR().
# Remember the OID for use by DESCR() and SHDESCR().
# ----------------
/^DATA\(/ {
data = substr($0, 6, length($0) - 6);
@@ -225,6 +226,16 @@ comment_level > 0 { next; }
next;
}
/^SHDESCR\(/ {
if (oid != 0)
{
data = substr($0, 10, length($0) - 11);
if (data != "")
printf "%d\t%s\t%s\n", oid, catalog, data >>shdescriptionfile;
}
next;
}
/^DECLARE_INDEX\(/ {
# ----
# end any prior catalog data insertions before starting a define index
@@ -365,7 +376,7 @@ END {
reln_open = 0;
}
}
' "descriptionfile=${OUTPUT_PREFIX}.description.$$" > $TMPFILE || exit
' "descriptionfile=${OUTPUT_PREFIX}.description.$$" "shdescriptionfile=${OUTPUT_PREFIX}.shdescription.$$" > $TMPFILE || exit
echo "# PostgreSQL $major_version" >${OUTPUT_PREFIX}.bki.$$
@@ -386,10 +397,15 @@ if [ `wc -c < ${OUTPUT_PREFIX}.description.$$` -lt 10000 ]; then
echo "$CMDNAME: something seems to be wrong with the .description file" >&2
exit 1
fi
if [ `wc -c < ${OUTPUT_PREFIX}.shdescription.$$` -lt 10 ]; then
echo "$CMDNAME: something seems to be wrong with the .shdescription file" >&2
exit 1
fi
# Looks good, commit ...
mv ${OUTPUT_PREFIX}.bki.$$ ${OUTPUT_PREFIX}.bki || exit
mv ${OUTPUT_PREFIX}.description.$$ ${OUTPUT_PREFIX}.description || exit
mv ${OUTPUT_PREFIX}.shdescription.$$ ${OUTPUT_PREFIX}.shdescription || exit
exit 0

View File

@@ -7,7 +7,7 @@
* Copyright (c) 1996-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.85 2005/11/22 18:17:08 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.86 2006/02/12 03:22:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
#include "access/heapam.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_conversion.h"
@@ -30,10 +31,13 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_shdescription.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
@@ -70,6 +74,8 @@ static void CommentLanguage(List *qualname, char *comment);
static void CommentOpClass(List *qualname, List *arguments, char *comment);
static void CommentLargeObject(List *qualname, char *comment);
static void CommentCast(List *qualname, List *arguments, char *comment);
static void CommentTablespace(List *qualname, char *comment);
static void CommentRole(List *qualname, char *comment);
/*
@@ -134,6 +140,12 @@ CommentObject(CommentStmt *stmt)
case OBJECT_CAST:
CommentCast(stmt->objname, stmt->objargs, stmt->comment);
break;
case OBJECT_TABLESPACE:
CommentTablespace(stmt->objname, stmt->comment);
break;
case OBJECT_ROLE:
CommentRole(stmt->objname, stmt->comment);
break;
default:
elog(ERROR, "unrecognized object type: %d",
(int) stmt->objtype);
@@ -240,6 +252,100 @@ CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
heap_close(description, NoLock);
}
/*
* CreateSharedComments --
*
* Create a comment for the specified shared object descriptor. Inserts a
* new pg_shdescription tuple, or replaces an existing one with the same key.
*
* If the comment given is null or an empty string, instead delete any
* existing comment for the specified key.
*/
void CreateSharedComments(Oid oid, Oid classoid, char *comment)
{
Relation shdescription;
ScanKeyData skey[2];
SysScanDesc sd;
HeapTuple oldtuple;
HeapTuple newtuple = NULL;
Datum values[Natts_pg_shdescription];
char nulls[Natts_pg_shdescription];
char replaces[Natts_pg_shdescription];
int i;
/* Reduce empty-string to NULL case */
if (comment != NULL && strlen(comment) == 0)
comment = NULL;
/* Prepare to form or update a tuple, if necessary */
if (comment != NULL)
{
for (i = 0; i < Natts_pg_shdescription; i++)
{
nulls[i] = ' ';
replaces[i] = 'r';
}
i = 0;
values[i++] = ObjectIdGetDatum(oid);
values[i++] = ObjectIdGetDatum(classoid);
values[i++] = DirectFunctionCall1(textin, CStringGetDatum(comment));
}
/* Use the index to search for a matching old tuple */
ScanKeyInit(&skey[0],
Anum_pg_shdescription_objoid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(oid));
ScanKeyInit(&skey[1],
Anum_pg_shdescription_classoid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(classoid));
shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
SnapshotNow, 2, skey);
while ((oldtuple = systable_getnext(sd)) != NULL)
{
/* Found the old tuple, so delete or update it */
if (comment == NULL)
simple_heap_delete(shdescription, &oldtuple->t_self);
else
{
newtuple = heap_modifytuple(oldtuple, RelationGetDescr(shdescription),
values, nulls, replaces);
simple_heap_update(shdescription, &oldtuple->t_self, newtuple);
}
break; /* Assume there can be only one match */
}
systable_endscan(sd);
/* If we didn't find an old tuple, insert a new one */
if (newtuple == NULL && comment != NULL)
{
newtuple = heap_formtuple(RelationGetDescr(shdescription),
values, nulls);
simple_heap_insert(shdescription, newtuple);
}
/* Update indexes, if necessary */
if (newtuple != NULL)
{
CatalogUpdateIndexes(shdescription, newtuple);
heap_freetuple(newtuple);
}
/* Done */
heap_close(shdescription, NoLock);
}
/*
* DeleteComments -- remove comments for an object
*
@@ -292,6 +398,42 @@ DeleteComments(Oid oid, Oid classoid, int32 subid)
heap_close(description, RowExclusiveLock);
}
/*
* DeleteSharedComments -- remove comments for a shared object
*/
void
DeleteSharedComments(Oid oid, Oid classoid)
{
Relation shdescription;
ScanKeyData skey[2];
SysScanDesc sd;
HeapTuple oldtuple;
/* Use the index to search for all matching old tuples */
ScanKeyInit(&skey[0],
Anum_pg_shdescription_objoid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(oid));
ScanKeyInit(&skey[1],
Anum_pg_shdescription_classoid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(classoid));
shdescription = heap_open(SharedDescriptionRelationId, RowExclusiveLock);
sd = systable_beginscan(shdescription, SharedDescriptionObjIndexId, true,
SnapshotNow, 2, skey);
while ((oldtuple = systable_getnext(sd)) != NULL)
simple_heap_delete(shdescription, &oldtuple->t_self);
/* Done */
systable_endscan(sd);
heap_close(shdescription, RowExclusiveLock);
}
/*
* CommentRelation --
*
@@ -425,7 +567,7 @@ CommentAttribute(List *qualname, char *comment)
* have regarding the specified database. The routine will check
* security for owner permissions, and, if successful, will then
* attempt to find the oid of the database specified. Once found,
* a comment is added/dropped using the CreateComments() routine.
* a comment is added/dropped using the CreateSharedComments() routine.
*/
static void
CommentDatabase(List *qualname, char *comment)
@@ -440,11 +582,6 @@ CommentDatabase(List *qualname, char *comment)
database = strVal(linitial(qualname));
/*
* We cannot currently support cross-database comments (since other DBs
* cannot see pg_description of this database). So, we reject attempts to
* comment on a database other than the current one. Someday this might be
* improved, but it would take a redesigned infrastructure.
*
* When loading a dump, we may see a COMMENT ON DATABASE for the old name
* of the database. Erroring out would prevent pg_restore from completing
* (which is really pg_restore's fault, but for now we will work around
@@ -462,23 +599,83 @@ CommentDatabase(List *qualname, char *comment)
return;
}
/* Only allow comments on the current database */
if (oid != MyDatabaseId)
{
ereport(WARNING, /* throw just a warning so pg_restore doesn't
* fail */
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("database comments may only be applied to the current database")));
return;
}
/* Check object security */
if (!pg_database_ownercheck(oid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
database);
/* Call CreateComments() to create/drop the comments */
CreateComments(oid, DatabaseRelationId, 0, comment);
/* Call CreateSharedComments() to create/drop the comments */
CreateSharedComments(oid, DatabaseRelationId, comment);
}
/*
* CommentTablespace --
*
* This routine is used to add/drop any user-comments a user might
* have regarding a tablespace. The tablepace is specified by name
* and, if found, and the user has appropriate permissions, a
* comment will be added/dropped using the CreateSharedComments() routine.
*
*/
static void
CommentTablespace(List *qualname, char *comment)
{
char *tablespace;
Oid oid;
if (list_length(qualname) != 1)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("tablespace name may not be qualified")));
tablespace = strVal(linitial(qualname));
oid = get_tablespace_oid(tablespace);
if (!OidIsValid(oid))
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist", tablespace)));
return;
}
/* Check object security */
if (!pg_tablespace_ownercheck(oid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespace);
/* Call CreateSharedComments() to create/drop the comments */
CreateSharedComments(oid, TableSpaceRelationId, comment);
}
/*
* CommentRole --
*
* This routine is used to add/drop any user-comments a user might
* have regarding a role. The role is specified by name
* and, if found, and the user has appropriate permissions, a
* comment will be added/dropped using the CreateSharedComments() routine.
*/
static void
CommentRole(List *qualname, char *comment)
{
char *role;
Oid oid;
if (list_length(qualname) != 1)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("role name may not be qualified")));
role = strVal(linitial(qualname));
oid = get_roleid_checked(role);
/* Check object security */
if (!has_privs_of_role(GetUserId(), oid))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be member of role \"%s\" to comment upon it", role)));
/* Call CreateSharedComments() to create/drop the comments */
CreateSharedComments(oid, AuthIdRelationId, comment);
}
/*

View File

@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.175 2005/11/22 18:17:08 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.176 2006/02/12 03:22:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -658,10 +658,8 @@ dropdb(const char *dbname, bool missing_ok)
/*
* Delete any comments associated with the database
*
* NOTE: this is probably dead code since any such comments should have
* been in that database, not mine.
*/
DeleteComments(db_id, DatabaseRelationId, 0);
DeleteSharedComments(db_id, DatabaseRelationId);
/*
* Remove shared dependency references for the database.

View File

@@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.29 2006/01/19 04:45:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.30 2006/02/12 03:22:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -54,6 +54,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_tablespace.h"
#include "commands/comment.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "storage/fd.h"
@@ -428,6 +429,11 @@ DropTableSpace(DropTableSpaceStmt *stmt)
heap_endscan(scandesc);
/*
* Remove any comments on this tablespace.
*/
DeleteSharedComments(tablespaceoid, TableSpaceRelationId);
/*
* Remove dependency on owner.
*/

View File

@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.168 2006/02/04 19:06:46 adunstan Exp $
* $PostgreSQL: pgsql/src/backend/commands/user.c,v 1.169 2006/02/12 03:22:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,6 +18,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "commands/comment.h"
#include "commands/user.h"
#include "libpq/crypt.h"
#include "miscadmin.h"
@@ -940,6 +941,11 @@ DropRole(DropRoleStmt *stmt)
systable_endscan(sscan);
/*
* Remove any comments on this role.
*/
DeleteSharedComments(roleid, AuthIdRelationId);
/*
* Advance command counter so that later iterations of this loop will
* see the changes already made. This is essential if, for example,

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.527 2006/02/11 22:17:18 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.528 2006/02/12 03:22:17 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2953,11 +2953,12 @@ TruncateStmt:
*
* COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW |
* CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT |
* CAST ] <objname> |
* CAST | COLUMN | SCHEMA | TABLESPACE | ROLE ] <objname> |
* AGGREGATE <aggname> (<aggtype>) |
* FUNCTION <funcname> (arg1, arg2, ...) |
* OPERATOR <op> (leftoperand_typ, rightoperand_typ) |
* TRIGGER <triggername> ON <relname> |
* CONSTRAINT <constraintname> ON <relname> |
* RULE <rulename> ON <relname> ]
* IS 'text'
*
@@ -3088,6 +3089,8 @@ comment_type:
| TYPE_P { $$ = OBJECT_TYPE; }
| VIEW { $$ = OBJECT_VIEW; }
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
| TABLESPACE { $$ = OBJECT_TABLESPACE; }
| ROLE { $$ = OBJECT_ROLE; }
;
comment_text: