diff options
Diffstat (limited to 'src/backend/commands/comment.c')
-rw-r--r-- | src/backend/commands/comment.c | 233 |
1 files changed, 215 insertions, 18 deletions
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); } /* |