indexcmds.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 777 行 · 第 1/2 页

C
777
字号
										  accessMethodId);		attn++;	}}/* * Resolve possibly-defaulted operator class specification */static OidGetIndexOpClass(List *opclass, Oid attrType,				char *accessMethodName, Oid accessMethodId){	char	   *schemaname;	char	   *opcname;	HeapTuple	tuple;	Oid			opClassId,				opInputType;	/*	 * Release 7.0 removed network_ops, timespan_ops, and datetime_ops, so	 * we ignore those opclass names so the default *_ops is used.	This	 * can be removed in some later release.  bjm 2000/02/07	 *	 * Release 7.1 removes lztext_ops, so suppress that too for a while.  tgl	 * 2000/07/30	 *	 * Release 7.2 renames timestamp_ops to timestamptz_ops, so suppress that	 * too for awhile.	I'm starting to think we need a better approach.	 * tgl 2000/10/01	 */	if (length(opclass) == 1)	{		char	   *claname = strVal(lfirst(opclass));		if (strcmp(claname, "network_ops") == 0 ||			strcmp(claname, "timespan_ops") == 0 ||			strcmp(claname, "datetime_ops") == 0 ||			strcmp(claname, "lztext_ops") == 0 ||			strcmp(claname, "timestamp_ops") == 0)			opclass = NIL;	}	if (opclass == NIL)	{		/* no operator class specified, so find the default */		opClassId = GetDefaultOpClass(attrType, accessMethodId);		if (!OidIsValid(opClassId))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("data type %s has no default operator class for access method \"%s\"",							format_type_be(attrType), accessMethodName),					 errhint("You must specify an operator class for the index or define a default operator class for the data type.")));		return opClassId;	}	/*	 * Specific opclass name given, so look up the opclass.	 */	/* deconstruct the name list */	DeconstructQualifiedName(opclass, &schemaname, &opcname);	if (schemaname)	{		/* Look in specific schema only */		Oid			namespaceId;		namespaceId = LookupExplicitNamespace(schemaname);		tuple = SearchSysCache(CLAAMNAMENSP,							   ObjectIdGetDatum(accessMethodId),							   PointerGetDatum(opcname),							   ObjectIdGetDatum(namespaceId),							   0);	}	else	{		/* Unqualified opclass name, so search the search path */		opClassId = OpclassnameGetOpcid(accessMethodId, opcname);		if (!OidIsValid(opClassId))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("operator class \"%s\" does not exist for access method \"%s\"",							opcname, accessMethodName)));		tuple = SearchSysCache(CLAOID,							   ObjectIdGetDatum(opClassId),							   0, 0, 0);	}	if (!HeapTupleIsValid(tuple))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("operator class \"%s\" does not exist for access method \"%s\"",						NameListToString(opclass), accessMethodName)));	/*	 * Verify that the index operator class accepts this datatype.	Note	 * we will accept binary compatibility.	 */	opClassId = HeapTupleGetOid(tuple);	opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;	if (!IsBinaryCoercible(attrType, opInputType))		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),			 errmsg("operator class \"%s\" does not accept data type %s",				  NameListToString(opclass), format_type_be(attrType))));	ReleaseSysCache(tuple);	return opClassId;}static OidGetDefaultOpClass(Oid attrType, Oid accessMethodId){	OpclassCandidateList opclass;	int			nexact = 0;	int			ncompatible = 0;	Oid			exactOid = InvalidOid;	Oid			compatibleOid = InvalidOid;	/* If it's a domain, look at the base type instead */	attrType = getBaseType(attrType);	/*	 * We scan through all the opclasses available for the access method,	 * looking for one that is marked default and matches the target type	 * (either exactly or binary-compatibly, but prefer an exact match).	 *	 * We could find more than one binary-compatible match, in which case we	 * require the user to specify which one he wants.	If we find more	 * than one exact match, then someone put bogus entries in pg_opclass.	 *	 * The initial search is done by namespace.c so that we only consider	 * opclasses visible in the current namespace search path.  (See also	 * typcache.c, which applies the same logic, but over all opclasses.)	 */	for (opclass = OpclassGetCandidates(accessMethodId);		 opclass != NULL;		 opclass = opclass->next)	{		if (opclass->opcdefault)		{			if (opclass->opcintype == attrType)			{				nexact++;				exactOid = opclass->oid;			}			else if (IsBinaryCoercible(attrType, opclass->opcintype))			{				ncompatible++;				compatibleOid = opclass->oid;			}		}	}	if (nexact == 1)		return exactOid;	if (nexact != 0)		ereport(ERROR,				(errcode(ERRCODE_DUPLICATE_OBJECT),				 errmsg("there are multiple default operator classes for data type %s",						format_type_be(attrType))));	if (ncompatible == 1)		return compatibleOid;	return InvalidOid;}/* * RemoveIndex *		Deletes an index. */voidRemoveIndex(RangeVar *relation, DropBehavior behavior){	Oid			indOid;	char		relkind;	ObjectAddress object;	indOid = RangeVarGetRelid(relation, false);	relkind = get_rel_relkind(indOid);	if (relkind != RELKIND_INDEX)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is not an index",						relation->relname)));	object.classId = RelOid_pg_class;	object.objectId = indOid;	object.objectSubId = 0;	performDeletion(&object, behavior);}/* * ReindexIndex *		Recreate an index. */voidReindexIndex(RangeVar *indexRelation, bool force /* currently unused */ ){	Oid			indOid;	HeapTuple	tuple;	indOid = RangeVarGetRelid(indexRelation, false);	tuple = SearchSysCache(RELOID,						   ObjectIdGetDatum(indOid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		/* shouldn't happen */		elog(ERROR, "cache lookup failed for relation %u", indOid);	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is not an index",						indexRelation->relname)));	/* Check permissions */	if (!pg_class_ownercheck(indOid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,					   indexRelation->relname);	ReleaseSysCache(tuple);	reindex_index(indOid);}/* * ReindexTable *		Recreate indexes of a table. */voidReindexTable(RangeVar *relation, bool force /* currently unused */ ){	Oid			heapOid;	HeapTuple	tuple;	heapOid = RangeVarGetRelid(relation, false);	tuple = SearchSysCache(RELOID,						   ObjectIdGetDatum(heapOid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		/* shouldn't happen */		elog(ERROR, "cache lookup failed for relation %u", heapOid);	if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_RELATION &&		((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_TOASTVALUE)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("\"%s\" is not a table",						relation->relname)));	/* Check permissions */	if (!pg_class_ownercheck(heapOid, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,					   relation->relname);	/* Can't reindex shared tables except in standalone mode */	if (((Form_pg_class) GETSTRUCT(tuple))->relisshared && IsUnderPostmaster)		ereport(ERROR,				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),				 errmsg("shared table \"%s\" can only be reindexed in stand-alone mode",						relation->relname)));	ReleaseSysCache(tuple);	if (!reindex_relation(heapOid))		ereport(NOTICE,				(errmsg("table \"%s\" has no indexes",						relation->relname)));}/* * ReindexDatabase *		Recreate indexes of a database. * * To reduce the probability of deadlocks, each table is reindexed in a * separate transaction, so we can release the lock on it right away. */voidReindexDatabase(const char *dbname, bool force /* currently unused */,				bool all){	Relation	relationRelation;	HeapScanDesc scan;	HeapTuple	tuple;	MemoryContext private_context;	MemoryContext old;	List	   *relids = NIL;	AssertArg(dbname);	if (strcmp(dbname, get_database_name(MyDatabaseId)) != 0)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("can only reindex the currently open database")));	if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,					   dbname);	/*	 * We cannot run inside a user transaction block; if we were inside a	 * transaction, then our commit- and start-transaction-command calls	 * would not have the intended effect!	 */	PreventTransactionChain((void *) dbname, "REINDEX DATABASE");	/*	 * Create a memory context that will survive forced transaction	 * commits we do below.  Since it is a child of PortalContext, it will	 * go away eventually even if we suffer an error; there's no need for	 * special abort cleanup logic.	 */	private_context = AllocSetContextCreate(PortalContext,											"ReindexDatabase",											ALLOCSET_DEFAULT_MINSIZE,											ALLOCSET_DEFAULT_INITSIZE,											ALLOCSET_DEFAULT_MAXSIZE);	/*	 * We always want to reindex pg_class first.  This ensures that if	 * there is any corruption in pg_class' indexes, they will be fixed	 * before we process any other tables.  This is critical because	 * reindexing itself will try to update pg_class.	 */	old = MemoryContextSwitchTo(private_context);	relids = lappendo(relids, RelOid_pg_class);	MemoryContextSwitchTo(old);	/*	 * Scan pg_class to build a list of the relations we need to reindex.	 *	 * We only consider plain relations here (toast rels will be processed	 * indirectly by reindex_relation).	 */	relationRelation = heap_openr(RelationRelationName, AccessShareLock);	scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)	{		Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);		if (classtuple->relkind != RELKIND_RELATION)			continue;		if (!all)				/* only system tables? */		{			if (!IsSystemClass(classtuple))				continue;		}		if (IsUnderPostmaster)	/* silently ignore shared tables */		{			if (classtuple->relisshared)				continue;		}		if (HeapTupleGetOid(tuple) == RelOid_pg_class)			continue;			/* got it already */		old = MemoryContextSwitchTo(private_context);		relids = lappendo(relids, HeapTupleGetOid(tuple));		MemoryContextSwitchTo(old);	}	heap_endscan(scan);	heap_close(relationRelation, AccessShareLock);	/* Now reindex each rel in a separate transaction */	CommitTransactionCommand();	while (relids)	{		Oid		relid = lfirsto(relids);		StartTransactionCommand();		SetQuerySnapshot();		/* might be needed for functions in								 * indexes */		if (reindex_relation(relid))			ereport(NOTICE,					(errmsg("table \"%s\" was reindexed",							get_rel_name(relid))));		CommitTransactionCommand();		relids = lnext(relids);	}	StartTransactionCommand();	MemoryContextDelete(private_context);}

⌨️ 快捷键说明

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