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

📄 indexcmds.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * indexcmds.c *	  POSTGRES define and remove index code. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.134.2.2 2006/02/10 19:01:22 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "catalog/dependency.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/indexing.h"#include "catalog/pg_opclass.h"#include "catalog/pg_tablespace.h"#include "commands/dbcommands.h"#include "commands/defrem.h"#include "commands/tablecmds.h"#include "commands/tablespace.h"#include "mb/pg_wchar.h"#include "miscadmin.h"#include "optimizer/clauses.h"#include "parser/parsetree.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/relcache.h"#include "utils/syscache.h"/* non-export function prototypes */static void CheckPredicate(Expr *predicate);static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,				  List *attList,				  Oid relId,				  char *accessMethodName, Oid accessMethodId,				  bool isconstraint);static Oid GetIndexOpClass(List *opclass, Oid attrType,				char *accessMethodName, Oid accessMethodId);static bool relationHasPrimaryKey(Relation rel);/* * DefineIndex *		Creates a new index. * * 'heapRelation': the relation the index will apply to. * 'indexRelationName': the name for the new index, or NULL to indicate *		that a nonconflicting default name should be picked. * 'indexRelationId': normally InvalidOid, but during bootstrap can be *		nonzero to specify a preselected OID for the index. * 'accessMethodName': name of the AM to use. * 'tableSpaceName': name of the tablespace to create the index in. *		NULL specifies using the appropriate default. * 'attributeList': a list of IndexElem specifying columns and expressions *		to index on. * 'predicate': the partial-index condition, or NULL if none. * 'rangetable': needed to interpret the predicate. * 'unique': make the index enforce uniqueness. * 'primary': mark the index as a primary key in the catalogs. * 'isconstraint': index is for a PRIMARY KEY or UNIQUE constraint, *		so build a pg_constraint entry for it. * 'is_alter_table': this is due to an ALTER rather than a CREATE operation. * 'check_rights': check for CREATE rights in the namespace.  (This should *		be true except when ALTER is deleting/recreating an index.) * 'skip_build': make the catalog entries but leave the index file empty; *		it will be filled later. * 'quiet': suppress the NOTICE chatter ordinarily provided for constraints. */voidDefineIndex(RangeVar *heapRelation,			char *indexRelationName,			Oid indexRelationId,			char *accessMethodName,			char *tableSpaceName,			List *attributeList,			Expr *predicate,			List *rangetable,			bool unique,			bool primary,			bool isconstraint,			bool is_alter_table,			bool check_rights,			bool skip_build,			bool quiet){	Oid		   *classObjectId;	Oid			accessMethodId;	Oid			relationId;	Oid			namespaceId;	Oid			tablespaceId;	Relation	rel;	HeapTuple	tuple;	Form_pg_am	accessMethodForm;	IndexInfo  *indexInfo;	int			numberOfAttributes;	/*	 * count attributes in index	 */	numberOfAttributes = list_length(attributeList);	if (numberOfAttributes <= 0)		ereport(ERROR,				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),				 errmsg("must specify at least one column")));	if (numberOfAttributes > INDEX_MAX_KEYS)		ereport(ERROR,				(errcode(ERRCODE_TOO_MANY_COLUMNS),				 errmsg("cannot use more than %d columns in an index",						INDEX_MAX_KEYS)));	/*	 * Open heap relation, acquire a suitable lock on it, remember its OID	 */	rel = heap_openrv(heapRelation, ShareLock);	/* Note: during bootstrap may see uncataloged relation */	if (rel->rd_rel->relkind != RELKIND_RELATION &&		rel->rd_rel->relkind != RELKIND_UNCATALOGED)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is not a table",						heapRelation->relname)));	relationId = RelationGetRelid(rel);	namespaceId = RelationGetNamespace(rel);	/*	 * Verify we (still) have CREATE rights in the rel's namespace.	 * (Presumably we did when the rel was created, but maybe not anymore.)	 * Skip check if caller doesn't want it.  Also skip check if	 * bootstrapping, since permissions machinery may not be working yet.	 */	if (check_rights && !IsBootstrapProcessingMode())	{		AclResult	aclresult;		aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),										  ACL_CREATE);		if (aclresult != ACLCHECK_OK)			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,						   get_namespace_name(namespaceId));	}	/*	 * Select tablespace to use.  If not specified, use default_tablespace	 * (which may in turn default to database's default).	 */	if (tableSpaceName)	{		tablespaceId = get_tablespace_oid(tableSpaceName);		if (!OidIsValid(tablespaceId))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("tablespace \"%s\" does not exist",							tableSpaceName)));	}	else	{		tablespaceId = GetDefaultTablespace();		/* note InvalidOid is OK in this case */	}	/* Check permissions except when using database's default */	if (OidIsValid(tablespaceId))	{		AclResult	aclresult;		aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),										   ACL_CREATE);		if (aclresult != ACLCHECK_OK)			aclcheck_error(aclresult, ACL_KIND_TABLESPACE,						   get_tablespace_name(tablespaceId));	}	/*	 * Force shared indexes into the pg_global tablespace.	This is a bit of a	 * hack but seems simpler than marking them in the BKI commands.	 */	if (rel->rd_rel->relisshared)		tablespaceId = GLOBALTABLESPACE_OID;	/*	 * Select name for index if caller didn't specify	 */	if (indexRelationName == NULL)	{		if (primary)			indexRelationName = ChooseRelationName(RelationGetRelationName(rel),												   NULL,												   "pkey",												   namespaceId);		else		{			IndexElem  *iparam = (IndexElem *) linitial(attributeList);			indexRelationName = ChooseRelationName(RelationGetRelationName(rel),												   iparam->name,												   "key",												   namespaceId);		}	}	/*	 * look up the access method, verify it can handle the requested features	 */	tuple = SearchSysCache(AMNAME,						   PointerGetDatum(accessMethodName),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("access method \"%s\" does not exist",						accessMethodName)));	accessMethodId = HeapTupleGetOid(tuple);	accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);	if (unique && !accessMethodForm->amcanunique)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),			   errmsg("access method \"%s\" does not support unique indexes",					  accessMethodName)));	if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),		  errmsg("access method \"%s\" does not support multicolumn indexes",				 accessMethodName)));	ReleaseSysCache(tuple);	/*	 * If a range table was created then check that only the base rel is	 * mentioned.	 */	if (rangetable != NIL)	{		if (list_length(rangetable) != 1 || getrelid(1, rangetable) != relationId)			ereport(ERROR,					(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),					 errmsg("index expressions and predicates may refer only to the table being indexed")));	}	/*	 * Validate predicate, if given	 */	if (predicate)		CheckPredicate(predicate);	/*	 * Extra checks when creating a PRIMARY KEY index.	 */	if (primary)	{		List	   *cmds;		ListCell   *keys;		/*		 * If ALTER TABLE, check that there isn't already a PRIMARY KEY. In		 * CREATE TABLE, we have faith that the parser rejected multiple pkey		 * clauses; and CREATE INDEX doesn't have a way to say PRIMARY KEY, so		 * it's no problem either.		 */		if (is_alter_table &&			relationHasPrimaryKey(rel))		{			ereport(ERROR,					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),			 errmsg("multiple primary keys for table \"%s\" are not allowed",					RelationGetRelationName(rel))));		}		/*		 * Check that all of the attributes in a primary key are marked as not		 * null, otherwise attempt to ALTER TABLE .. SET NOT NULL		 */		cmds = NIL;		foreach(keys, attributeList)		{			IndexElem  *key = (IndexElem *) lfirst(keys);			HeapTuple	atttuple;			if (!key->name)				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("primary keys cannot be expressions")));			/* System attributes are never null, so no problem */			if (SystemAttributeByName(key->name, rel->rd_rel->relhasoids))				continue;			atttuple = SearchSysCacheAttName(relationId, key->name);			if (HeapTupleIsValid(atttuple))			{				if (!((Form_pg_attribute) GETSTRUCT(atttuple))->attnotnull)				{					/* Add a subcommand to make this one NOT NULL */					AlterTableCmd *cmd = makeNode(AlterTableCmd);					cmd->subtype = AT_SetNotNull;					cmd->name = key->name;					cmds = lappend(cmds, cmd);				}				ReleaseSysCache(atttuple);			}			else			{				/*				 * This shouldn't happen during CREATE TABLE, but can happen				 * during ALTER TABLE.	Keep message in sync with				 * transformIndexConstraints() in parser/analyze.c.				 */				ereport(ERROR,						(errcode(ERRCODE_UNDEFINED_COLUMN),						 errmsg("column \"%s\" named in key does not exist",								key->name)));			}		}		/*		 * XXX: Shouldn't the ALTER TABLE .. SET NOT NULL cascade to child		 * tables?	Currently, since the PRIMARY KEY itself doesn't cascade,		 * we don't cascade the notnull constraint(s) either; but this is		 * pretty debatable.		 *		 * XXX: possible future improvement: when being called from ALTER		 * TABLE, it would be more efficient to merge this with the outer		 * ALTER TABLE, so as to avoid two scans.  But that seems to		 * complicate DefineIndex's API unduly.		 */		if (cmds)			AlterTableInternal(relationId, cmds, false);	}	/*	 * Prepare arguments for index_create, primarily an IndexInfo structure.	 * Note that ii_Predicate must be in implicit-AND format.	 */	indexInfo = makeNode(IndexInfo);	indexInfo->ii_NumIndexAttrs = numberOfAttributes;	indexInfo->ii_Expressions = NIL;	/* for now */	indexInfo->ii_ExpressionsState = NIL;	indexInfo->ii_Predicate = make_ands_implicit(predicate);	indexInfo->ii_PredicateState = NIL;	indexInfo->ii_Unique = unique;	classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));	ComputeIndexAttrs(indexInfo, classObjectId, attributeList,					  relationId, accessMethodName, accessMethodId,					  isconstraint);	heap_close(rel, NoLock);	/*	 * Report index creation if appropriate (delay this till after most of the

⌨️ 快捷键说明

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