indxpath.c

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

C
2,156
字号
 * expand_indexqual_conditions().  match_special_index_operator() is * just an auxiliary function for match_clause_to_indexcol(); after * the latter fails to recognize a restriction opclause's operator * as a member of an index's opclass, it asks match_special_index_operator() * whether the clause should be considered an indexqual anyway. * expand_indexqual_conditions() converts a list of lists of RestrictInfo * nodes (with implicit AND semantics across list elements) into * a list of clauses that the executor can actually handle.  For operators * that are members of the index's opclass this transformation is a no-op, * but operators recognized by match_special_index_operator() must be * converted into one or more "regular" indexqual conditions. *---------- *//* * match_special_index_operator *	  Recognize restriction clauses that can be used to generate *	  additional indexscanable qualifications. * * The given clause is already known to be a binary opclause having * the form (indexkey OP pseudoconst) or (pseudoconst OP indexkey), * but the OP proved not to be one of the index's opclass operators. * Return 'true' if we can do something with it anyway. */static boolmatch_special_index_operator(Expr *clause, Oid opclass,							 bool indexkey_on_left){	bool		isIndexable = false;	Node	   *rightop;	Oid			expr_op;	Const	   *patt;	Const	   *prefix = NULL;	Const	   *rest = NULL;	/*	 * Currently, all known special operators require the indexkey on the	 * left, but this test could be pushed into the switch statement if	 * some are added that do not...	 */	if (!indexkey_on_left)		return false;	/* we know these will succeed */	rightop = get_rightop(clause);	expr_op = ((OpExpr *) clause)->opno;	/* again, required for all current special ops: */	if (!IsA(rightop, Const) ||		((Const *) rightop)->constisnull)		return false;	patt = (Const *) rightop;	switch (expr_op)	{		case OID_TEXT_LIKE_OP:		case OID_BPCHAR_LIKE_OP:		case OID_NAME_LIKE_OP:			/* the right-hand const is type text for all of these */			isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like,								  &prefix, &rest) != Pattern_Prefix_None;			break;		case OID_BYTEA_LIKE_OP:			isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like,								  &prefix, &rest) != Pattern_Prefix_None;			break;		case OID_TEXT_ICLIKE_OP:		case OID_BPCHAR_ICLIKE_OP:		case OID_NAME_ICLIKE_OP:			/* the right-hand const is type text for all of these */			isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,								  &prefix, &rest) != Pattern_Prefix_None;			break;		case OID_TEXT_REGEXEQ_OP:		case OID_BPCHAR_REGEXEQ_OP:		case OID_NAME_REGEXEQ_OP:			/* the right-hand const is type text for all of these */			isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex,								  &prefix, &rest) != Pattern_Prefix_None;			break;		case OID_TEXT_ICREGEXEQ_OP:		case OID_BPCHAR_ICREGEXEQ_OP:		case OID_NAME_ICREGEXEQ_OP:			/* the right-hand const is type text for all of these */			isIndexable = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,								  &prefix, &rest) != Pattern_Prefix_None;			break;		case OID_INET_SUB_OP:		case OID_INET_SUBEQ_OP:		case OID_CIDR_SUB_OP:		case OID_CIDR_SUBEQ_OP:			isIndexable = true;			break;	}	if (prefix)	{		pfree(DatumGetPointer(prefix->constvalue));		pfree(prefix);	}	/* done if the expression doesn't look indexable */	if (!isIndexable)		return false;	/*	 * Must also check that index's opclass supports the operators we will	 * want to apply.  (A hash index, for example, will not support ">=".)	 * Currently, only btree supports the operators we need.	 *	 * We insist on the opclass being the specific one we expect, else we'd	 * do the wrong thing if someone were to make a reverse-sort opclass	 * with the same operators.	 */	switch (expr_op)	{		case OID_TEXT_LIKE_OP:		case OID_TEXT_ICLIKE_OP:		case OID_TEXT_REGEXEQ_OP:		case OID_TEXT_ICREGEXEQ_OP:			/* text operators will be used for varchar inputs, too */			isIndexable =				(opclass == TEXT_PATTERN_BTREE_OPS_OID) ||				(opclass == TEXT_BTREE_OPS_OID && lc_collate_is_c()) ||				(opclass == VARCHAR_PATTERN_BTREE_OPS_OID) ||				(opclass == VARCHAR_BTREE_OPS_OID && lc_collate_is_c());			break;		case OID_BPCHAR_LIKE_OP:		case OID_BPCHAR_ICLIKE_OP:		case OID_BPCHAR_REGEXEQ_OP:		case OID_BPCHAR_ICREGEXEQ_OP:			isIndexable =				(opclass == BPCHAR_PATTERN_BTREE_OPS_OID) ||				(opclass == BPCHAR_BTREE_OPS_OID && lc_collate_is_c());			break;		case OID_NAME_LIKE_OP:		case OID_NAME_ICLIKE_OP:		case OID_NAME_REGEXEQ_OP:		case OID_NAME_ICREGEXEQ_OP:			isIndexable =				(opclass == NAME_PATTERN_BTREE_OPS_OID) ||				(opclass == NAME_BTREE_OPS_OID && lc_collate_is_c());			break;		case OID_BYTEA_LIKE_OP:			isIndexable = (opclass == BYTEA_BTREE_OPS_OID);			break;		case OID_INET_SUB_OP:		case OID_INET_SUBEQ_OP:			isIndexable = (opclass == INET_BTREE_OPS_OID);			break;		case OID_CIDR_SUB_OP:		case OID_CIDR_SUBEQ_OP:			isIndexable = (opclass == CIDR_BTREE_OPS_OID);			break;	}	return isIndexable;}/* * expand_indexqual_conditions *	  Given a list of sublists of RestrictInfo nodes, produce a flat list *	  of index qual clauses.  Standard qual clauses (those in the index's *	  opclass) are passed through unchanged.  "Special" index operators *	  are expanded into clauses that the indexscan machinery will know *	  what to do with. * * The input list is ordered by index key, and so the output list is too. * (The latter is not depended on by any part of the planner, so far as I can * tell; but some parts of the executor do assume that the indxqual list * ultimately delivered to the executor is so ordered.	One such place is * _bt_orderkeys() in the btree support.  Perhaps that ought to be fixed * someday --- tgl 7/00) */List *expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups){	FastList	resultquals;	Oid		   *classes = index->classlist;	if (clausegroups == NIL)		return NIL;	FastListInit(&resultquals);	do	{		Oid			curClass = classes[0];		List	   *i;		foreach(i, (List *) lfirst(clausegroups))		{			RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);			FastConc(&resultquals,					 expand_indexqual_condition(rinfo->clause,												curClass));		}		clausegroups = lnext(clausegroups);		classes++;	} while (clausegroups != NIL && !DoneMatchingIndexKeys(classes));	Assert(clausegroups == NIL);	/* else more groups than indexkeys... */	return FastListValue(&resultquals);}/* * expand_indexqual_condition --- expand a single indexqual condition */static List *expand_indexqual_condition(Expr *clause, Oid opclass){	/* we know these will succeed */	Node	   *leftop = get_leftop(clause);	Node	   *rightop = get_rightop(clause);	Oid			expr_op = ((OpExpr *) clause)->opno;	Const	   *patt = (Const *) rightop;	Const	   *prefix = NULL;	Const	   *rest = NULL;	Pattern_Prefix_Status pstatus;	List	   *result;	switch (expr_op)	{			/*			 * LIKE and regex operators are not members of any index			 * opclass, so if we find one in an indexqual list we can			 * assume that it was accepted by			 * match_special_index_operator().			 */		case OID_TEXT_LIKE_OP:		case OID_BPCHAR_LIKE_OP:		case OID_NAME_LIKE_OP:		case OID_BYTEA_LIKE_OP:			pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like,										   &prefix, &rest);			result = prefix_quals(leftop, opclass, prefix, pstatus);			break;		case OID_TEXT_ICLIKE_OP:		case OID_BPCHAR_ICLIKE_OP:		case OID_NAME_ICLIKE_OP:			/* the right-hand const is type text for all of these */			pstatus = pattern_fixed_prefix(patt, Pattern_Type_Like_IC,										   &prefix, &rest);			result = prefix_quals(leftop, opclass, prefix, pstatus);			break;		case OID_TEXT_REGEXEQ_OP:		case OID_BPCHAR_REGEXEQ_OP:		case OID_NAME_REGEXEQ_OP:			/* the right-hand const is type text for all of these */			pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex,										   &prefix, &rest);			result = prefix_quals(leftop, opclass, prefix, pstatus);			break;		case OID_TEXT_ICREGEXEQ_OP:		case OID_BPCHAR_ICREGEXEQ_OP:		case OID_NAME_ICREGEXEQ_OP:			/* the right-hand const is type text for all of these */			pstatus = pattern_fixed_prefix(patt, Pattern_Type_Regex_IC,										   &prefix, &rest);			result = prefix_quals(leftop, opclass, prefix, pstatus);			break;		case OID_INET_SUB_OP:		case OID_INET_SUBEQ_OP:		case OID_CIDR_SUB_OP:		case OID_CIDR_SUBEQ_OP:			result = network_prefix_quals(leftop, expr_op, opclass,										  patt->constvalue);			break;		default:			result = makeList1(clause);			break;	}	return result;}/* * Given a fixed prefix that all the "leftop" values must have, * generate suitable indexqual condition(s).  opclass is the index * operator class; we use it to deduce the appropriate comparison * operators and operand datatypes. */static List *prefix_quals(Node *leftop, Oid opclass,			 Const *prefix_const, Pattern_Prefix_Status pstatus){	List	   *result;	Oid			datatype;	Oid			oproid;	Expr	   *expr;	Const	   *greaterstr;	Assert(pstatus != Pattern_Prefix_None);	switch (opclass)	{		case TEXT_BTREE_OPS_OID:		case TEXT_PATTERN_BTREE_OPS_OID:			datatype = TEXTOID;			break;		case VARCHAR_BTREE_OPS_OID:		case VARCHAR_PATTERN_BTREE_OPS_OID:			datatype = VARCHAROID;			break;		case BPCHAR_BTREE_OPS_OID:		case BPCHAR_PATTERN_BTREE_OPS_OID:			datatype = BPCHAROID;			break;		case NAME_BTREE_OPS_OID:		case NAME_PATTERN_BTREE_OPS_OID:			datatype = NAMEOID;			break;		case BYTEA_BTREE_OPS_OID:			datatype = BYTEAOID;			break;		default:			/* shouldn't get here */			elog(ERROR, "unexpected opclass: %u", opclass);			return NIL;	}	/*	 * If necessary, coerce the prefix constant to the right type. The	 * given prefix constant is either text or bytea type.	 */	if (prefix_const->consttype != datatype)	{		char	   *prefix;		switch (prefix_const->consttype)		{			case TEXTOID:				prefix = DatumGetCString(DirectFunctionCall1(textout,											  prefix_const->constvalue));				break;			case BYTEAOID:				prefix = DatumGetCString(DirectFunctionCall1(byteaout,											  prefix_const->constvalue));				break;			default:				elog(ERROR, "unexpected const type: %u",					 prefix_const->consttype);				return NIL;		}		prefix_const = string_to_const(prefix, datatype);		pfree(prefix);	}	/*	 * If we found an exact-match pattern, generate an "=" indexqual.	 */	if (pstatus == Pattern_Prefix_Exact)	{		oproid = get_opclass_member(opclass, BTEqualStrategyNumber);		if (oproid == InvalidOid)			elog(ERROR, "no = operator for opclass %u", opclass);		expr = make_opclause(oproid, BOOLOID, false,							 (Expr *) leftop, (Expr *) prefix_const);		result = makeList1(expr);		return result;	}	/*	 * Otherwise, we have a nonempty required prefix of the values.	 *	 * We can always say "x >= prefix".	 */	oproid = get_opclass_member(opclass, BTGreaterEqualStrategyNumber);	if (oproid == InvalidOid)		elog(ERROR, "no >= operator for opclass %u", opclass);	expr = make_opclause(oproid, BOOLOID, false,						 (Expr *) leftop, (Expr *) prefix_const);	result = makeList1(expr);	/*-------	 * If we can create a string larger than the prefix, we can say	 * "x < greaterstr".	 *-------	 */	greaterstr = make_greater_string(prefix_const);	if (greaterstr)	{		oproid = get_opclass_member(opclass, BTLessStrategyNumber);		if (oproid == InvalidOid)			elog(ERROR, "no < operator for opclass %u", opclass);		expr = make_opclause(oproid, BOOLOID, false,							 (Expr *) leftop, (Expr *) greaterstr);		result = lappend(result, expr);	}	return result;}/* * Given a leftop and a rightop, and a inet-class sup/sub operator, * generate suitable indexqual condition(s).  expr_op is the original * operator, and opclass is the index opclass. */static List *network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop){	bool		is_eq;	Oid			datatype;	Oid			opr1o

⌨️ 快捷键说明

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