⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 utility.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * utility.c *	  Contains functions which control the execution of the POSTGRES utility *	  commands.  At one time acted as an interface between the Lisp and C *	  systems. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.245 2005/10/15 02:49:27 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/twophase.h"#include "catalog/catalog.h"#include "catalog/namespace.h"#include "commands/alter.h"#include "commands/async.h"#include "commands/cluster.h"#include "commands/comment.h"#include "commands/copy.h"#include "commands/conversioncmds.h"#include "commands/dbcommands.h"#include "commands/defrem.h"#include "commands/explain.h"#include "commands/lockcmds.h"#include "commands/portalcmds.h"#include "commands/prepare.h"#include "commands/proclang.h"#include "commands/schemacmds.h"#include "commands/sequence.h"#include "commands/tablecmds.h"#include "commands/tablespace.h"#include "commands/trigger.h"#include "commands/typecmds.h"#include "commands/user.h"#include "commands/vacuum.h"#include "commands/view.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "parser/parse_expr.h"#include "parser/parse_type.h"#include "postmaster/bgwriter.h"#include "rewrite/rewriteDefine.h"#include "rewrite/rewriteRemove.h"#include "storage/fd.h"#include "tcop/pquery.h"#include "tcop/utility.h"#include "utils/acl.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* * Error-checking support for DROP commands */struct msgstrings{	char		kind;	int			nonexistent_code;	const char *nonexistent_msg;	const char *nota_msg;	const char *drophint_msg;};static const struct msgstrings msgstringarray[] = {	{RELKIND_RELATION,		ERRCODE_UNDEFINED_TABLE,		gettext_noop("table \"%s\" does not exist"),		gettext_noop("\"%s\" is not a table"),	gettext_noop("Use DROP TABLE to remove a table.")},	{RELKIND_SEQUENCE,		ERRCODE_UNDEFINED_TABLE,		gettext_noop("sequence \"%s\" does not exist"),		gettext_noop("\"%s\" is not a sequence"),	gettext_noop("Use DROP SEQUENCE to remove a sequence.")},	{RELKIND_VIEW,		ERRCODE_UNDEFINED_TABLE,		gettext_noop("view \"%s\" does not exist"),		gettext_noop("\"%s\" is not a view"),	gettext_noop("Use DROP VIEW to remove a view.")},	{RELKIND_INDEX,		ERRCODE_UNDEFINED_OBJECT,		gettext_noop("index \"%s\" does not exist"),		gettext_noop("\"%s\" is not an index"),	gettext_noop("Use DROP INDEX to remove an index.")},	{RELKIND_COMPOSITE_TYPE,		ERRCODE_UNDEFINED_OBJECT,		gettext_noop("type \"%s\" does not exist"),		gettext_noop("\"%s\" is not a type"),	gettext_noop("Use DROP TYPE to remove a type.")},	{'\0', 0, NULL, NULL, NULL}};/* * Emit the right error message for a "DROP" command issued on a * relation of the wrong type */static voidDropErrorMsgWrongType(char *relname, char wrongkind, char rightkind){	const struct msgstrings *rentry;	const struct msgstrings *wentry;	for (rentry = msgstringarray; rentry->kind != '\0'; rentry++)		if (rentry->kind == rightkind)			break;	Assert(rentry->kind != '\0');	for (wentry = msgstringarray; wentry->kind != '\0'; wentry++)		if (wentry->kind == wrongkind)			break;	/* wrongkind could be something we don't have in our table... */	ereport(ERROR,			(errcode(ERRCODE_WRONG_OBJECT_TYPE),			 errmsg(rentry->nota_msg, relname),			 (wentry->kind != '\0') ? errhint(wentry->drophint_msg) : 0));}/* * Emit the right error message for a "DROP" command issued on a * non-existent relation */static voidDropErrorMsgNonExistent(RangeVar *rel, char rightkind){	const struct msgstrings *rentry;	for (rentry = msgstringarray; rentry->kind != '\0'; rentry++)	{		if (rentry->kind == rightkind)			ereport(ERROR,					(errcode(rentry->nonexistent_code),					 errmsg(rentry->nonexistent_msg, rel->relname)));	}	Assert(false);				/* Should be impossible */}static voidCheckDropPermissions(RangeVar *rel, char rightkind){	Oid			relOid;	HeapTuple	tuple;	Form_pg_class classform;	relOid = RangeVarGetRelid(rel, true);	if (!OidIsValid(relOid))		DropErrorMsgNonExistent(rel, rightkind);	tuple = SearchSysCache(RELOID,						   ObjectIdGetDatum(relOid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for relation %u", relOid);	classform = (Form_pg_class) GETSTRUCT(tuple);	if (classform->relkind != rightkind)		DropErrorMsgWrongType(rel->relname, classform->relkind,							  rightkind);	/* Allow DROP to either table owner or schema owner */	if (!pg_class_ownercheck(relOid, GetUserId()) &&		!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,					   rel->relname);	if (!allowSystemTableMods && IsSystemClass(classform))		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),				 errmsg("permission denied: \"%s\" is a system catalog",						rel->relname)));	ReleaseSysCache(tuple);}/* * Verify user has ownership of specified relation, else ereport. * * If noCatalogs is true then we also deny access to system catalogs, * except when allowSystemTableMods is true. */voidCheckRelationOwnership(RangeVar *rel, bool noCatalogs){	Oid			relOid;	HeapTuple	tuple;	relOid = RangeVarGetRelid(rel, false);	tuple = SearchSysCache(RELOID,						   ObjectIdGetDatum(relOid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		/* should not happen */		elog(ERROR, "cache lookup failed for relation %u", relOid);	if (!pg_class_ownercheck(relOid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,					   rel->relname);	if (noCatalogs)	{		if (!allowSystemTableMods &&			IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))			ereport(ERROR,					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),					 errmsg("permission denied: \"%s\" is a system catalog",							rel->relname)));	}	ReleaseSysCache(tuple);}/* * QueryIsReadOnly: is an analyzed/rewritten query read-only? * * This is a much stricter test than we apply for XactReadOnly mode; * the query must be *in truth* read-only, because the caller wishes * not to do CommandCounterIncrement for it. */boolQueryIsReadOnly(Query *parsetree){	switch (parsetree->commandType)	{		case CMD_SELECT:			if (parsetree->into != NULL)				return false;	/* SELECT INTO */			else if (parsetree->rowMarks != NIL)				return false;	/* SELECT FOR UPDATE/SHARE */			else				return true;		case CMD_UPDATE:		case CMD_INSERT:		case CMD_DELETE:			return false;		case CMD_UTILITY:			/* For now, treat all utility commands as read/write */			return false;		default:			elog(WARNING, "unrecognized commandType: %d",				 (int) parsetree->commandType);			break;	}	return false;}/* * check_xact_readonly: is a utility command read-only? * * Here we use the loose rules of XactReadOnly mode: no permanent effects * on the database are allowed. */static voidcheck_xact_readonly(Node *parsetree){	if (!XactReadOnly)		return;	/*	 * Note: Commands that need to do more complicated checking are handled	 * elsewhere.	 */	switch (nodeTag(parsetree))	{		case T_AlterDatabaseStmt:		case T_AlterDatabaseSetStmt:		case T_AlterDomainStmt:		case T_AlterFunctionStmt:		case T_AlterRoleStmt:		case T_AlterRoleSetStmt:		case T_AlterObjectSchemaStmt:		case T_AlterOwnerStmt:		case T_AlterSeqStmt:		case T_AlterTableStmt:		case T_RenameStmt:		case T_CommentStmt:		case T_DefineStmt:		case T_CreateCastStmt:		case T_CreateConversionStmt:		case T_CreatedbStmt:		case T_CreateDomainStmt:		case T_CreateFunctionStmt:		case T_CreateRoleStmt:		case T_IndexStmt:		case T_CreatePLangStmt:		case T_CreateOpClassStmt:		case T_RuleStmt:		case T_CreateSchemaStmt:		case T_CreateSeqStmt:		case T_CreateStmt:		case T_CreateTableSpaceStmt:		case T_CreateTrigStmt:		case T_CompositeTypeStmt:		case T_ViewStmt:		case T_RemoveAggrStmt:		case T_DropCastStmt:		case T_DropStmt:		case T_DropdbStmt:		case T_DropTableSpaceStmt:		case T_RemoveFuncStmt:		case T_DropRoleStmt:		case T_DropPLangStmt:		case T_RemoveOperStmt:		case T_RemoveOpClassStmt:		case T_DropPropertyStmt:		case T_GrantStmt:		case T_GrantRoleStmt:		case T_TruncateStmt:			ereport(ERROR,					(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),					 errmsg("transaction is read-only")));			break;		default:			/* do nothing */			break;	}}/* * ProcessUtility *		general utility function invoker * *	parsetree: the parse tree for the utility statement *	params: parameters to use during execution (currently only used by DECLARE) *	dest: where to send results *	completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE *		in which to store a command completion status string. * * completionTag is only set nonempty if we want to return a nondefault status. * * completionTag may be NULL if caller doesn't want a status string. */voidProcessUtility(Node *parsetree,			   ParamListInfo params,			   DestReceiver *dest,			   char *completionTag){	check_xact_readonly(parsetree);	if (completionTag)		completionTag[0] = '\0';	switch (nodeTag(parsetree))	{			/*			 * ******************** transactions ********************			 */		case T_TransactionStmt:			{				TransactionStmt *stmt = (TransactionStmt *) parsetree;				switch (stmt->kind)				{						/*						 * START TRANSACTION, as defined by SQL99: Identical						 * to BEGIN.  Same code for both.						 */					case TRANS_STMT_BEGIN:					case TRANS_STMT_START:						{							ListCell   *lc;							BeginTransactionBlock();							foreach(lc, stmt->options)							{								DefElem    *item = (DefElem *) lfirst(lc);								if (strcmp(item->defname, "transaction_isolation") == 0)									SetPGVariable("transaction_isolation",												  list_make1(item->arg),												  true);								else if (strcmp(item->defname, "transaction_read_only") == 0)									SetPGVariable("transaction_read_only",												  list_make1(item->arg),												  true);							}						}						break;					case TRANS_STMT_COMMIT:						if (!EndTransactionBlock())						{							/* report unsuccessful commit in completionTag */							if (completionTag)								strcpy(completionTag, "ROLLBACK");						}						break;					case TRANS_STMT_PREPARE:						if (!PrepareTransactionBlock(stmt->gid))						{							/* report unsuccessful commit in completionTag */							if (completionTag)								strcpy(completionTag, "ROLLBACK");						}						break;					case TRANS_STMT_COMMIT_PREPARED:						PreventTransactionChain(stmt, "COMMIT PREPARED");						FinishPreparedTransaction(stmt->gid, true);						break;					case TRANS_STMT_ROLLBACK_PREPARED:						PreventTransactionChain(stmt, "ROLLBACK PREPARED");						FinishPreparedTransaction(stmt->gid, false);						break;					case TRANS_STMT_ROLLBACK:						UserAbortTransactionBlock();						break;					case TRANS_STMT_SAVEPOINT:						{							ListCell   *cell;							char	   *name = NULL;							RequireTransactionChain((void *) stmt, "SAVEPOINT");							foreach(cell, stmt->options)							{								DefElem    *elem = lfirst(cell);								if (strcmp(elem->defname, "savepoint_name") == 0)									name = strVal(elem->arg);							}							Assert(PointerIsValid(name));							DefineSavepoint(name);						}						break;					case TRANS_STMT_RELEASE:						RequireTransactionChain((void *) stmt, "RELEASE SAVEPOINT");						ReleaseSavepoint(stmt->options);						break;					case TRANS_STMT_ROLLBACK_TO:						RequireTransactionChain((void *) stmt, "ROLLBACK TO SAVEPOINT");						RollbackToSavepoint(stmt->options);						/*						 * CommitTransactionCommand is in charge of						 * re-defining the savepoint again						 */						break;				}			}			break;			/*			 * Portal (cursor) manipulation			 */		case T_DeclareCursorStmt:			PerformCursorOpen((DeclareCursorStmt *) parsetree, params);			break;		case T_ClosePortalStmt:			{				ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;				PerformPortalClose(stmt->portalname);			}			break;		case T_FetchStmt:			PerformPortalFetch((FetchStmt *) parsetree, dest,							   completionTag);			break;			/*			 * relation and attribute manipulation			 */		case T_CreateSchemaStmt:			CreateSchemaCommand((CreateSchemaStmt *) parsetree);			break;		case T_CreateStmt:			{				Oid			relOid;				relOid = DefineRelation((CreateStmt *) parsetree,										RELKIND_RELATION);				/*				 * Let AlterTableCreateToastTable decide if this one needs a				 * secondary relation too.				 */				CommandCounterIncrement();				AlterTableCreateToastTable(relOid, true);			}			break;		case T_CreateTableSpaceStmt:			CreateTableSpace((CreateTableSpaceStmt *) parsetree);			break;		case T_DropTableSpaceStmt:			DropTableSpace((DropTableSpaceStmt *) parsetree);			break;		case T_DropStmt:			{				DropStmt   *stmt = (DropStmt *) parsetree;				ListCell   *arg;				foreach(arg, stmt->objects)				{					List	   *names = (List *) lfirst(arg);					RangeVar   *rel;					switch (stmt->removeType)					{						case OBJECT_TABLE:							rel = makeRangeVarFromNameList(names);							CheckDropPermissions(rel, RELKIND_RELATION);							RemoveRelation(rel, stmt->behavior);							break;						case OBJECT_SEQUENCE:							rel = makeRangeVarFromNameList(names);							CheckDropPermissions(rel, RELKIND_SEQUENCE);							RemoveRelation(rel, stmt->behavior);							break;						case OBJECT_VIEW:							rel = makeRangeVarFromNameList(names);							CheckDropPermissions(rel, RELKIND_VIEW);							RemoveView(rel, stmt->behavior);							break;						case OBJECT_INDEX:							rel = makeRangeVarFromNameList(names);							CheckDropPermissions(rel, RELKIND_INDEX);							RemoveIndex(rel, stmt->behavior);							break;						case OBJECT_TYPE:							/* RemoveType does its own permissions checks */							RemoveType(names, stmt->behavior);							break;						case OBJECT_DOMAIN:							/*							 * RemoveDomain does its own permissions checks							 */							RemoveDomain(names, stmt->behavior);							break;						case OBJECT_CONVERSION:							DropConversionCommand(names, stmt->behavior);							break;						case OBJECT_SCHEMA:							/*							 * RemoveSchema does its own permissions checks							 */							RemoveSchema(names, stmt->behavior);							break;						default:							elog(ERROR, "unrecognized drop object type: %d",								 (int) stmt->removeType);							break;					}					/*					 * We used to need to do CommandCounterIncrement() here,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -