📄 comment.c
字号:
/*------------------------------------------------------------------------- * * comment.c * * PostgreSQL object comments utility code. * * Copyright (c) 1996-2005, PostgreSQL Global Development Group * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.84.2.1 2005/11/22 18:23:06 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_cast.h"#include "catalog/pg_constraint.h"#include "catalog/pg_conversion.h"#include "catalog/pg_database.h"#include "catalog/pg_description.h"#include "catalog/pg_language.h"#include "catalog/pg_largeobject.h"#include "catalog/pg_namespace.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.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);static void CommentConversion(List *qualname, char *comment);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);/* * 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; case OBJECT_CONVERSION: CommentConversion(stmt->objname, stmt->comment); break; case OBJECT_LANGUAGE: CommentLanguage(stmt->objname, stmt->comment); break; case OBJECT_OPCLASS: CommentOpClass(stmt->objname, stmt->objargs, stmt->comment); break; case OBJECT_LARGEOBJECT: CommentLargeObject(stmt->objname, stmt->comment); break; case OBJECT_CAST: CommentCast(stmt->objname, stmt->objargs, 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 */ ScanKeyInit(&skey[0], Anum_pg_description_objoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(oid)); ScanKeyInit(&skey[1], Anum_pg_description_classoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classoid)); ScanKeyInit(&skey[2], Anum_pg_description_objsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(subid)); description = heap_open(DescriptionRelationId, RowExclusiveLock); sd = systable_beginscan(description, DescriptionObjIndexId, 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, RelationGetDescr(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 */ ScanKeyInit(&skey[0], Anum_pg_description_objoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(oid)); ScanKeyInit(&skey[1], Anum_pg_description_classoid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classoid)); if (subid != 0) { ScanKeyInit(&skey[2], Anum_pg_description_objsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(subid)); nkeys = 3; } else nkeys = 2; description = heap_open(DescriptionRelationId, RowExclusiveLock); sd = systable_beginscan(description, DescriptionObjIndexId, 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), RelationRelationId, 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 = list_length(qualname); if (nnames < 2) /* parser messed up */ elog(ERROR, "must specify relation and attribute"); relname = list_truncate(list_copy(qualname), nnames - 1); attrname = strVal(lfirst(list_tail(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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -