diff options
author | Bruce Momjian <bruce@momjian.us> | 2006-02-12 03:22:21 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 2006-02-12 03:22:21 +0000 |
commit | f9a726aa883e1690f66bec535d85b34e1f9ed7e7 (patch) | |
tree | 764d3d849a2614ea5edcd05eaa36496a79f06c87 /src/backend | |
parent | 95dbf9c02f9a37fc171e0b94b37f9f903abc3942 (diff) | |
download | postgresql-f9a726aa883e1690f66bec535d85b34e1f9ed7e7.tar.gz postgresql-f9a726aa883e1690f66bec535d85b34e1f9ed7e7.zip |
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
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/Makefile | 9 | ||||
-rw-r--r-- | src/backend/catalog/genbki.sh | 24 | ||||
-rw-r--r-- | src/backend/commands/comment.c | 233 | ||||
-rw-r--r-- | src/backend/commands/dbcommands.c | 6 | ||||
-rw-r--r-- | src/backend/commands/tablespace.c | 8 | ||||
-rw-r--r-- | src/backend/commands/user.c | 8 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 7 |
7 files changed, 262 insertions, 33 deletions
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 1f520298b25..635b553dca9 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -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' diff --git a/src/backend/catalog/genbki.sh b/src/backend/catalog/genbki.sh index 9d9b75bde58..4f6b6b2ec66 100644 --- a/src/backend/catalog/genbki.sh +++ b/src/backend/catalog/genbki.sh @@ -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 diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index d0385428db0..30b740fca85 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -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); @@ -241,6 +253,100 @@ CreateComments(Oid oid, Oid classoid, int32 subid, char *comment) } /* + * 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 * * If subid is nonzero then only comments matching it will be removed. @@ -293,6 +399,42 @@ DeleteComments(Oid oid, Oid classoid, int32 subid) } /* + * 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 -- * * This routine is used to add/drop a comment from a relation, where @@ -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) + /* Check object security */ + if (!pg_database_ownercheck(oid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, + database); + + /* 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(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"))); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%s\" does not exist", tablespace))); return; } /* Check object security */ - if (!pg_database_ownercheck(oid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - database); + if (!pg_tablespace_ownercheck(oid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespace); - /* Call CreateComments() to create/drop the comments */ - CreateComments(oid, DatabaseRelationId, 0, comment); + /* 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); } /* diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 5be522db860..ea910d7e870 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -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. diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 19955dd81ed..2cca3fafe03 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -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" @@ -429,6 +430,11 @@ DropTableSpace(DropTableSpaceStmt *stmt) heap_endscan(scandesc); /* + * Remove any comments on this tablespace. + */ + DeleteSharedComments(tablespaceoid, TableSpaceRelationId); + + /* * Remove dependency on owner. */ deleteSharedDependencyRecordsFor(TableSpaceRelationId, tablespaceoid); diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index b3aa2ed8295..24a5abdecc1 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -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" @@ -941,6 +942,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, * we are trying to drop both a role and one of its direct members --- diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 19270bcbda6..79e4616be13 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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: |