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 + -
显示快捷键?