indxpath.c

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

C
2,156
字号
 *	  Does a binary opclause contain an operator matching the index opclass? * * If the indexkey is on the right, what we actually want to know * is whether the operator has a commutator operator that matches * the index's opclass. * * Returns the OID of the matching operator, or InvalidOid if no match. * (Formerly, this routine might return a binary-compatible operator * rather than the original one, but that kluge is history.) */static Oidindexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left){	Oid			expr_op = ((OpExpr *) clause)->opno;	Oid			commuted_op;	/* Get the commuted operator if necessary */	if (indexkey_on_left)		commuted_op = expr_op;	else		commuted_op = get_commutator(expr_op);	if (commuted_op == InvalidOid)		return InvalidOid;	/* OK if the (commuted) operator is a member of the index's opclass */	if (op_in_opclass(commuted_op, opclass))		return expr_op;	return InvalidOid;}/**************************************************************************** *				----  ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS	---- ****************************************************************************//* * pred_test *	  Does the "predicate inclusion test" for partial indexes. * *	  Recursively checks whether the clauses in restrictinfo_list imply *	  that the given predicate is true. * *	  This routine (together with the routines it calls) iterates over *	  ANDs in the predicate first, then reduces the qualification *	  clauses down to their constituent terms, and iterates over ORs *	  in the predicate last.  This order is important to make the test *	  succeed whenever possible (assuming the predicate has been converted *	  to CNF format). --Nels, Jan '93 */static boolpred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list){	List	   *pred;	/*	 * Note: if Postgres tried to optimize queries by forming equivalence	 * classes over equi-joined attributes (i.e., if it recognized that a	 * qualification such as "where a.b=c.d and a.b=5" could make use of	 * an index on c.d), then we could use that equivalence class info	 * here with joininfo_list to do more complete tests for the usability	 * of a partial index.	For now, the test only uses restriction	 * clauses (those in restrictinfo_list). --Nels, Dec '92	 *	 * XXX as of 7.1, equivalence class info *is* available.  Consider	 * improving this code as foreseen by Nels.	 */	if (predicate_list == NIL)		return true;			/* no predicate: the index is usable */	if (restrictinfo_list == NIL)		return false;			/* no restriction clauses: the test must								 * fail */	foreach(pred, predicate_list)	{		/*		 * if any clause is not implied, the whole predicate is not		 * implied.  Note we assume that any sub-ANDs have been flattened		 * when the predicate was fed through canonicalize_qual().		 */		if (!pred_test_restrict_list(lfirst(pred), restrictinfo_list))			return false;	}	return true;}/* * pred_test_restrict_list *	  Does the "predicate inclusion test" for one conjunct of a predicate *	  expression. */static boolpred_test_restrict_list(Expr *predicate, List *restrictinfo_list){	List	   *item;	foreach(item, restrictinfo_list)	{		RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(item);		/* if any clause implies the predicate, return true */		if (pred_test_recurse_clause(predicate,									 (Node *) restrictinfo->clause))			return true;	}	return false;}/* * pred_test_recurse_clause *	  Does the "predicate inclusion test" for a general restriction-clause *	  expression.  Here we recursively deal with the possibility that the *	  restriction clause is itself an AND or OR structure. */static boolpred_test_recurse_clause(Expr *predicate, Node *clause){	List	   *items,			   *item;	Assert(clause != NULL);	if (or_clause(clause))	{		items = ((BoolExpr *) clause)->args;		foreach(item, items)		{			/* if any OR item doesn't imply the predicate, clause doesn't */			if (!pred_test_recurse_clause(predicate, lfirst(item)))				return false;		}		return true;	}	else if (and_clause(clause))	{		items = ((BoolExpr *) clause)->args;		foreach(item, items)		{			/*			 * if any AND item implies the predicate, the whole clause			 * does			 */			if (pred_test_recurse_clause(predicate, lfirst(item)))				return true;		}		return false;	}	else		return pred_test_recurse_pred(predicate, clause);}/* * pred_test_recurse_pred *	  Does the "predicate inclusion test" for one conjunct of a predicate *	  expression for a simple restriction clause.  Here we recursively deal *	  with the possibility that the predicate conjunct is itself an AND or *	  OR structure. */static boolpred_test_recurse_pred(Expr *predicate, Node *clause){	List	   *items,			   *item;	Assert(predicate != NULL);	if (or_clause((Node *) predicate))	{		items = ((BoolExpr *) predicate)->args;		foreach(item, items)		{			/* if any item is implied, the whole predicate is implied */			if (pred_test_recurse_pred(lfirst(item), clause))				return true;		}		return false;	}	else if (and_clause((Node *) predicate))	{		items = ((BoolExpr *) predicate)->args;		foreach(item, items)		{			/*			 * if any item is not implied, the whole predicate is not			 * implied			 */			if (!pred_test_recurse_pred(lfirst(item), clause))				return false;		}		return true;	}	else		return pred_test_simple_clause(predicate, clause);}/* * Define an "operator implication table" for btree operators ("strategies"). * The "strategy numbers" are:	(1) <	(2) <=	 (3) =	 (4) >=   (5) > * * The interpretation of: * *		test_op = BT_implic_table[given_op-1][target_op-1] * * where test_op, given_op and target_op are strategy numbers (from 1 to 5) * of btree operators, is as follows: * *	 If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you *	 want to determine whether "ATTR target_op CONST2" must also be true, then *	 you can use "CONST1 test_op CONST2" as a test.  If this test returns true, *	 then the target expression must be true; if the test returns false, then *	 the target expression may be false. * * An entry where test_op==0 means the implication cannot be determined, i.e., * this test should always be considered false. */static const StrategyNumber			BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {	{2, 2, 0, 0, 0},	{1, 2, 0, 0, 0},	{1, 2, 3, 4, 5},	{0, 0, 0, 4, 5},	{0, 0, 0, 4, 4}};/* * pred_test_simple_clause *	  Does the "predicate inclusion test" for a "simple clause" predicate *	  and a "simple clause" restriction. * *	  We have two strategies for determining whether one simple clause *	  implies another.	A simple and general way is to see if they are *	  equal(); this works for any kind of expression.  (Actually, there *	  is an implied assumption that the functions in the expression are *	  immutable, ie dependent only on their input arguments --- but this *	  was checked for the predicate by CheckPredicate().) * *	  Our other way works only for (binary boolean) operators that are *	  in some btree operator class.  We use the above operator implication *	  table to be able to derive implications between nonidentical clauses. * *	  Eventually, rtree operators could also be handled by defining an *	  appropriate "RT_implic_table" array. */static boolpred_test_simple_clause(Expr *predicate, Node *clause){	Var		   *pred_var,			   *clause_var;	Const	   *pred_const,			   *clause_const;	Oid			pred_op,				clause_op,				test_op;	Oid			opclass_id = InvalidOid;	bool		found = false;	StrategyNumber pred_strategy = 0,				clause_strategy = 0,				test_strategy;	Expr	   *test_expr;	ExprState  *test_exprstate;	Datum		test_result;	bool		isNull;	CatCList   *catlist;	int			i;	EState	   *estate;	MemoryContext oldcontext;	/* First try the equal() test */	if (equal((Node *) predicate, clause))		return true;	/*	 * Can't do anything more unless they are both binary opclauses with a	 * Var on the left and a Const on the right.  (XXX someday try to	 * commute Const/Var cases?)	 */	if (!is_opclause(predicate))		return false;	pred_var = (Var *) get_leftop(predicate);	pred_const = (Const *) get_rightop(predicate);	if (!is_opclause(clause))		return false;	clause_var = (Var *) get_leftop((Expr *) clause);	clause_const = (Const *) get_rightop((Expr *) clause);	if (!IsA(clause_var, Var) ||		clause_const == NULL ||		!IsA(clause_const, Const) ||		!IsA(pred_var, Var) ||		pred_const == NULL ||		!IsA(pred_const, Const))		return false;	/*	 * The implication can't be determined unless the predicate and the	 * clause refer to the same attribute.	 */	if (clause_var->varno != pred_var->varno ||		clause_var->varattno != pred_var->varattno)		return false;	/* Get the operators for the two clauses we're comparing */	pred_op = ((OpExpr *) predicate)->opno;	clause_op = ((OpExpr *) clause)->opno;	/*	 * 1. Find "btree" strategy numbers for the pred_op and clause_op.	 *	 * We must find a btree opclass that contains both operators, else the	 * implication can't be determined.  If there are multiple such	 * opclasses, assume we can use any one to determine the logical	 * relationship of the two operators and the correct corresponding	 * test operator.  This should work for any logically consistent	 * opclasses.	 */	catlist = SearchSysCacheList(AMOPOPID, 1,								 ObjectIdGetDatum(pred_op),								 0, 0, 0);	for (i = 0; i < catlist->n_members; i++)	{		HeapTuple	pred_tuple = &catlist->members[i]->tuple;		Form_pg_amop pred_form = (Form_pg_amop) GETSTRUCT(pred_tuple);		HeapTuple	clause_tuple;		if (!opclass_is_btree(pred_form->amopclaid))			continue;		/* Get the predicate operator's btree strategy number */		pred_strategy = (StrategyNumber) pred_form->amopstrategy;		Assert(pred_strategy >= 1 && pred_strategy <= 5);		/*		 * Remember which operator class this strategy number came from		 */		opclass_id = pred_form->amopclaid;		/*		 * From the same opclass, find a strategy num for the clause_op,		 * if possible		 */		clause_tuple = SearchSysCache(AMOPOPID,									  ObjectIdGetDatum(clause_op),									  ObjectIdGetDatum(opclass_id),									  0, 0);		if (HeapTupleIsValid(clause_tuple))		{			Form_pg_amop clause_form = (Form_pg_amop) GETSTRUCT(clause_tuple);			/* Get the restriction clause operator's strategy number */			clause_strategy = (StrategyNumber) clause_form->amopstrategy;			Assert(clause_strategy >= 1 && clause_strategy <= 5);			ReleaseSysCache(clause_tuple);			found = true;			break;		}	}	ReleaseSysCacheList(catlist);	if (!found)	{		/* couldn't find a btree opclass to interpret the operators */		return false;	}	/*	 * 2. Look up the "test" strategy number in the implication table	 */	test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];	if (test_strategy == 0)		return false;			/* the implication cannot be determined */	/*	 * 3. From the same opclass, find the operator for the test strategy	 */	test_op = get_opclass_member(opclass_id, test_strategy);	if (!OidIsValid(test_op))	{		/* This should not fail, else pg_amop entry is missing */		elog(ERROR, "missing pg_amop entry for opclass %u strategy %d",			 opclass_id, test_strategy);	}	/*	 * 4. Evaluate the test.  For this we need an EState.	 */	estate = CreateExecutorState();	/* We can use the estate's working context to avoid memory leaks. */	oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);	/* Build expression tree */	test_expr = make_opclause(test_op,							  BOOLOID,							  false,							  (Expr *) clause_const,							  (Expr *) pred_const);	/* Prepare it for execution */	test_exprstate = ExecPrepareExpr(test_expr, estate);	/* And execute it. */	test_result = ExecEvalExprSwitchContext(test_exprstate,										  GetPerTupleExprContext(estate),											&isNull, NULL);	/* Get back to outer memory context */	MemoryContextSwitchTo(oldcontext);	/* Release all the junk we just created */	FreeExecutorState(estate);	if (isNull)	{		/* Treat a null result as false ... but it's a tad fishy ... */		elog(DEBUG2, "null predicate test result");		return false;	}	return DatumGetBool(test_result);}/**************************************************************************** *				----  ROUTINES TO CHECK JOIN CLAUSES  ---- ****************************************************************************/

⌨️ 快捷键说明

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