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

📄 indexcmds.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	 * error checks)	 */	if (isconstraint && !quiet)		ereport(NOTICE,		  (errmsg("%s %s will create implicit index \"%s\" for table \"%s\"",				  is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",				  primary ? "PRIMARY KEY" : "UNIQUE",				  indexRelationName, RelationGetRelationName(rel))));	index_create(relationId, indexRelationName, indexRelationId,				 indexInfo, accessMethodId, tablespaceId, classObjectId,				 primary, isconstraint,				 allowSystemTableMods, skip_build);	/*	 * We update the relation's pg_class tuple even if it already has	 * relhasindex = true.	This is needed to cause a shared-cache-inval	 * message to be sent for the pg_class tuple, which will cause other	 * backends to flush their relcache entries and in particular their cached	 * lists of the indexes for this relation.	 */	setRelhasindex(relationId, true, primary, InvalidOid);}/* * CheckPredicate *		Checks that the given partial-index predicate is valid. * * This used to also constrain the form of the predicate to forms that * indxpath.c could do something with.	However, that seems overly * restrictive.  One useful application of partial indexes is to apply * a UNIQUE constraint across a subset of a table, and in that scenario * any evaluatable predicate will work.  So accept any predicate here * (except ones requiring a plan), and let indxpath.c fend for itself. */static voidCheckPredicate(Expr *predicate){	/*	 * We don't currently support generation of an actual query plan for a	 * predicate, only simple scalar expressions; hence these restrictions.	 */	if (contain_subplans((Node *) predicate))		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("cannot use subquery in index predicate")));	if (contain_agg_clause((Node *) predicate))		ereport(ERROR,				(errcode(ERRCODE_GROUPING_ERROR),				 errmsg("cannot use aggregate in index predicate")));	/*	 * A predicate using mutable functions is probably wrong, for the same	 * reasons that we don't allow an index expression to use one.	 */	if (contain_mutable_functions((Node *) predicate))		ereport(ERROR,				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),		   errmsg("functions in index predicate must be marked IMMUTABLE")));}static voidComputeIndexAttrs(IndexInfo *indexInfo,				  Oid *classOidP,				  List *attList,	/* list of IndexElem's */				  Oid relId,				  char *accessMethodName,				  Oid accessMethodId,				  bool isconstraint){	ListCell   *rest;	int			attn = 0;	/*	 * process attributeList	 */	foreach(rest, attList)	{		IndexElem  *attribute = (IndexElem *) lfirst(rest);		Oid			atttype;		if (attribute->name != NULL)		{			/* Simple index attribute */			HeapTuple	atttuple;			Form_pg_attribute attform;			Assert(attribute->expr == NULL);			atttuple = SearchSysCacheAttName(relId, attribute->name);			if (!HeapTupleIsValid(atttuple))			{				/* difference in error message spellings is historical */				if (isconstraint)					ereport(ERROR,							(errcode(ERRCODE_UNDEFINED_COLUMN),						  errmsg("column \"%s\" named in key does not exist",								 attribute->name)));				else					ereport(ERROR,							(errcode(ERRCODE_UNDEFINED_COLUMN),							 errmsg("column \"%s\" does not exist",									attribute->name)));			}			attform = (Form_pg_attribute) GETSTRUCT(atttuple);			indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;			atttype = attform->atttypid;			ReleaseSysCache(atttuple);		}		else if (attribute->expr && IsA(attribute->expr, Var))		{			/* Tricky tricky, he wrote (column) ... treat as simple attr */			Var		   *var = (Var *) attribute->expr;			indexInfo->ii_KeyAttrNumbers[attn] = var->varattno;			atttype = get_atttype(relId, var->varattno);		}		else		{			/* Index expression */			Assert(attribute->expr != NULL);			indexInfo->ii_KeyAttrNumbers[attn] = 0;		/* marks expression */			indexInfo->ii_Expressions = lappend(indexInfo->ii_Expressions,												attribute->expr);			atttype = exprType(attribute->expr);			/*			 * We don't currently support generation of an actual query plan			 * for an index expression, only simple scalar expressions; hence			 * these restrictions.			 */			if (contain_subplans(attribute->expr))				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("cannot use subquery in index expression")));			if (contain_agg_clause(attribute->expr))				ereport(ERROR,						(errcode(ERRCODE_GROUPING_ERROR),				errmsg("cannot use aggregate function in index expression")));			/*			 * A expression using mutable functions is probably wrong, since			 * if you aren't going to get the same result for the same data			 * every time, it's not clear what the index entries mean at all.			 */			if (contain_mutable_functions(attribute->expr))				ereport(ERROR,						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),						 errmsg("functions in index expression must be marked IMMUTABLE")));		}		classOidP[attn] = GetIndexOpClass(attribute->opclass,										  atttype,										  accessMethodName,										  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	 *	 * Release 8.0 removes bigbox_ops (which was dead code for a long while	 * anyway).  tgl 2003/11/11	 */	if (list_length(opclass) == 1)	{		char	   *claname = strVal(linitial(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 ||			strcmp(claname, "bigbox_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;}/* * GetDefaultOpClass * * Given the OIDs of a datatype and an access method, find the default * operator class, if any.	Returns InvalidOid if there is none. */OidGetDefaultOpClass(Oid type_id, Oid am_id){	int			nexact = 0;	int			ncompatible = 0;	Oid			exactOid = InvalidOid;	Oid			compatibleOid = InvalidOid;	Relation	rel;	ScanKeyData skey[1];	SysScanDesc scan;	HeapTuple	tup;	/* If it's a domain, look at the base type instead */	type_id = getBaseType(type_id);	/*	 * 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.	 */	rel = heap_open(OperatorClassRelationId, AccessShareLock);	ScanKeyInit(&skey[0],				Anum_pg_opclass_opcamid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(am_id));	scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,							  SnapshotNow, 1, skey);	while (HeapTupleIsValid(tup = systable_getnext(scan)))	{		Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);		if (opclass->opcdefault)		{			if (opclass->opcintype == type_id)			{				nexact++;				exactOid = HeapTupleGetOid(tup);			}			else if (IsBinaryCoercible(type_id, opclass->opcintype))			{				ncompatible++;				compatibleOid = HeapTupleGetOid(tup);			}		}	}	systable_endscan(scan);	heap_close(rel, AccessShareLock);	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(type_id))));	if (ncompatible == 1)		return compatibleOid;	return InvalidOid;}/* *	makeObjectName() * *	Create a name for an implicitly created index, sequence, constraint, etc. * *	The parameters are typically: the original table name, the original field *	name, and a "type" string (such as "seq" or "pkey").	The field name *	and/or type can be NULL if not relevant. * *	The result is a palloc'd string. * *	The basic result we want is "name1_name2_label", omitting "_name2" or *	"_label" when those parameters are NULL.  However, we must generate *	a name with less than NAMEDATALEN characters!  So, we truncate one or *	both names if necessary to make a short-enough string.	The label part *	is never truncated (so it had better be reasonably short). * *	The caller is responsible for checking uniqueness of the generated *	name and retrying as needed; retrying will be done by altering the *	"label" string (which is why we never truncate that part). */char *makeObjectName(const char *name1, const char *name2, const char *label){	char	   *name;

⌨️ 快捷键说明

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