comment.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 916 行 · 第 1/2 页
C
916 行
/*------------------------------------------------------------------------- * * comment.c * * PostgreSQL object comments utility code. * * Copyright (c) 1996-2003, PostgreSQL Global Development Group * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.71 2003/09/25 06:57:58 petere Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "catalog/catname.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_constraint.h"#include "catalog/pg_description.h"#include "catalog/pg_operator.h"#include "catalog/pg_rewrite.h"#include "catalog/pg_trigger.h"#include "catalog/pg_type.h"#include "commands/comment.h"#include "commands/dbcommands.h"#include "miscadmin.h"#include "parser/parse_func.h"#include "parser/parse_oper.h"#include "parser/parse_type.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* * Static Function Prototypes -- * * The following protoypes are declared static so as not to conflict * with any other routines outside this module. These routines are * called by the public function CommentObject() routine to create * the appropriate comment for the specific object type. */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);static void CommentProc(List *function, List *arguments, char *comment);static void CommentOperator(List *opername, List *arguments, char *comment);static void CommentTrigger(List *qualname, char *comment);static void CommentConstraint(List *qualname, char *comment);/* * CommentObject -- * * This routine is used to add the associated comment into * pg_description for the object specified by the given SQL command. */voidCommentObject(CommentStmt *stmt){ switch (stmt->objtype) { case OBJECT_INDEX: case OBJECT_SEQUENCE: case OBJECT_TABLE: case OBJECT_VIEW: CommentRelation(stmt->objtype, stmt->objname, stmt->comment); break; case OBJECT_COLUMN: CommentAttribute(stmt->objname, stmt->comment); break; case OBJECT_DATABASE: CommentDatabase(stmt->objname, stmt->comment); break; case OBJECT_RULE: CommentRule(stmt->objname, stmt->comment); break; case OBJECT_TYPE: CommentType(stmt->objname, stmt->comment); break; case OBJECT_AGGREGATE: CommentAggregate(stmt->objname, stmt->objargs, stmt->comment); break; case OBJECT_FUNCTION: CommentProc(stmt->objname, stmt->objargs, stmt->comment); break; case OBJECT_OPERATOR: CommentOperator(stmt->objname, stmt->objargs, stmt->comment); break; case OBJECT_TRIGGER: CommentTrigger(stmt->objname, stmt->comment); break; case OBJECT_SCHEMA: CommentNamespace(stmt->objname, stmt->comment); break; case OBJECT_CONSTRAINT: CommentConstraint(stmt->objname, stmt->comment); break; default: elog(ERROR, "unrecognized object type: %d", (int) stmt->objtype); }}/* * CreateComments -- * * Create a comment for the specified object descriptor. Inserts a new * pg_description 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. */voidCreateComments(Oid oid, Oid classoid, int32 subid, char *comment){ Relation description; ScanKeyData skey[3]; SysScanDesc sd; HeapTuple oldtuple; HeapTuple newtuple = NULL; Datum values[Natts_pg_description]; char nulls[Natts_pg_description]; char replaces[Natts_pg_description]; 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_description; i++) { nulls[i] = ' '; replaces[i] = 'r'; } i = 0; values[i++] = ObjectIdGetDatum(oid); values[i++] = ObjectIdGetDatum(classoid); values[i++] = Int32GetDatum(subid); values[i++] = DirectFunctionCall1(textin, CStringGetDatum(comment)); } /* Use the index to search for a matching old tuple */ ScanKeyEntryInitialize(&skey[0], (bits16) 0x0, (AttrNumber) 1, (RegProcedure) F_OIDEQ, ObjectIdGetDatum(oid)); ScanKeyEntryInitialize(&skey[1], (bits16) 0x0, (AttrNumber) 2, (RegProcedure) F_OIDEQ, ObjectIdGetDatum(classoid)); ScanKeyEntryInitialize(&skey[2], (bits16) 0x0, (AttrNumber) 3, (RegProcedure) F_INT4EQ, Int32GetDatum(subid)); description = heap_openr(DescriptionRelationName, RowExclusiveLock); sd = systable_beginscan(description, DescriptionObjIndex, true, SnapshotNow, 3, skey); while ((oldtuple = systable_getnext(sd)) != NULL) { /* Found the old tuple, so delete or update it */ if (comment == NULL) simple_heap_delete(description, &oldtuple->t_self); else { newtuple = heap_modifytuple(oldtuple, description, values, nulls, replaces); simple_heap_update(description, &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(description), values, nulls); simple_heap_insert(description, newtuple); } /* Update indexes, if necessary */ if (newtuple != NULL) { CatalogUpdateIndexes(description, newtuple); heap_freetuple(newtuple); } /* Done */ heap_close(description, NoLock);}/* * DeleteComments -- remove comments for an object * * If subid is nonzero then only comments matching it will be removed. * If subid is zero, all comments matching the oid/classoid will be removed * (this corresponds to deleting a whole object). */voidDeleteComments(Oid oid, Oid classoid, int32 subid){ Relation description; ScanKeyData skey[3]; int nkeys; SysScanDesc sd; HeapTuple oldtuple; /* Use the index to search for all matching old tuples */ ScanKeyEntryInitialize(&skey[0], 0x0, Anum_pg_description_objoid, F_OIDEQ, ObjectIdGetDatum(oid)); ScanKeyEntryInitialize(&skey[1], 0x0, Anum_pg_description_classoid, F_OIDEQ, ObjectIdGetDatum(classoid)); if (subid != 0) { ScanKeyEntryInitialize(&skey[2], 0x0, Anum_pg_description_objsubid, F_INT4EQ, Int32GetDatum(subid)); nkeys = 3; } else nkeys = 2; description = heap_openr(DescriptionRelationName, RowExclusiveLock); sd = systable_beginscan(description, DescriptionObjIndex, true, SnapshotNow, nkeys, skey); while ((oldtuple = systable_getnext(sd)) != NULL) simple_heap_delete(description, &oldtuple->t_self); /* Done */ systable_endscan(sd); heap_close(description, RowExclusiveLock);}/* * CommentRelation -- * * This routine is used to add/drop a comment from a relation, where * a relation is a TABLE, SEQUENCE, VIEW or INDEX. The routine simply * finds the relation name by searching the system cache, locating * the appropriate tuple, and inserting a comment using that * tuple's oid. Its parameters are the relation name and comments. */static voidCommentRelation(int objtype, List *relname, char *comment){ Relation relation; RangeVar *tgtrel; tgtrel = makeRangeVarFromNameList(relname); /* * Open the relation. We do this mainly to acquire a lock that * ensures no one else drops the relation before we commit. (If they * did, they'd fail to remove the entry we are about to make in * pg_description.) */ relation = relation_openrv(tgtrel, AccessShareLock); /* Check object security */ if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(relation)); /* Next, verify that the relation type matches the intent */ switch (objtype) { case OBJECT_INDEX: if (relation->rd_rel->relkind != RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not an index", RelationGetRelationName(relation)))); break; case OBJECT_SEQUENCE: if (relation->rd_rel->relkind != RELKIND_SEQUENCE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a sequence", RelationGetRelationName(relation)))); break; case OBJECT_TABLE: if (relation->rd_rel->relkind != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", RelationGetRelationName(relation)))); break; case OBJECT_VIEW: if (relation->rd_rel->relkind != RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a view", RelationGetRelationName(relation)))); break; } /* Create the comment using the relation's oid */ CreateComments(RelationGetRelid(relation), RelOid_pg_class, 0, comment); /* Done, but hold lock until commit */ relation_close(relation, NoLock);}/* * CommentAttribute -- * * This routine is used to add/drop a comment from an attribute * such as a table's column. The routine will check security * restrictions and then attempt to look up the specified * attribute. If successful, a comment is added/dropped, else an * ereport() exception is thrown. The parameters are the relation * and attribute names, and the comment */static voidCommentAttribute(List *qualname, char *comment){ int nnames; List *relname; char *attrname; RangeVar *rel; Relation relation; AttrNumber attnum; /* Separate relname and attr name */ nnames = length(qualname); if (nnames < 2) /* parser messed up */ elog(ERROR, "must specify relation and attribute"); relname = ltruncate(nnames - 1, listCopy(qualname)); attrname = strVal(llast(qualname)); /* Open the containing relation to ensure it won't go away meanwhile */ rel = makeRangeVarFromNameList(relname); relation = relation_openrv(rel, AccessShareLock); /* Check object security */ if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(relation)); /* Now, fetch the attribute number from the system cache */ attnum = get_attnum(RelationGetRelid(relation), attrname); if (attnum == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", attrname, RelationGetRelationName(relation)))); /* Create the comment using the relation's oid */ CreateComments(RelationGetRelid(relation), RelOid_pg_class, (int32) attnum, comment); /* Done, but hold lock until commit */ relation_close(relation, NoLock);}/* * CommentDatabase -- * * This routine is used to add/drop any user-comments a user might * 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. */static voidCommentDatabase(List *qualname, char *comment){ char *database; Oid oid; if (length(qualname) != 1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("database name may not be qualified"))); database = strVal(lfirst(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 the problem here). Consensus is that the best fix is * to treat wrong database name as a WARNING not an ERROR. */ /* First get the database OID */ oid = get_database_oid(database); if (!OidIsValid(oid)) { ereport(WARNING, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", database))); return; } /* Only allow comments on the current database */ if (oid != MyDatabaseId) { ereport(WARNING, (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); /* Create the comment with the pg_database oid */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?