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

📄 predtest.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
			list_member_strip(((FuncExpr *) clause)->args, isnullarg) &&			func_strict(((FuncExpr *) clause)->funcid))			return true;		/* foo IS NOT NULL refutes foo IS NULL */		if (clause && IsA(clause, NullTest) &&			((NullTest *) clause)->nulltesttype == IS_NOT_NULL &&			equal(((NullTest *) clause)->arg, isnullarg))			return true;		return false;			/* we can't succeed below... */	}	/* Try the clause-IS-NULL case */	if (clause && IsA(clause, NullTest) &&		((NullTest *) clause)->nulltesttype == IS_NULL)	{		Expr	   *isnullarg = ((NullTest *) clause)->arg;		/* row IS NULL does not act in the simple way we have in mind */		if (type_is_rowtype(exprType((Node *) isnullarg)))			return false;		/* foo IS NULL refutes foo IS NOT NULL */		if (predicate && IsA(predicate, NullTest) &&			((NullTest *) predicate)->nulltesttype == IS_NOT_NULL &&			equal(((NullTest *) predicate)->arg, isnullarg))			return true;		return false;			/* we can't succeed below... */	}	/* Else try btree operator knowledge */	return btree_predicate_proof(predicate, clause, true);}/* * If clause asserts the non-truth of a subclause, return that subclause; * otherwise return NULL. */static Node *extract_not_arg(Node *clause){	if (clause == NULL)		return NULL;	if (IsA(clause, BoolExpr))	{		BoolExpr   *bexpr = (BoolExpr *) clause;		if (bexpr->boolop == NOT_EXPR)			return (Node *) linitial(bexpr->args);	}	else if (IsA(clause, BooleanTest))	{		BooleanTest *btest = (BooleanTest *) clause;		if (btest->booltesttype == IS_NOT_TRUE ||			btest->booltesttype == IS_FALSE ||			btest->booltesttype == IS_UNKNOWN)			return (Node *) btest->arg;	}	return NULL;}/* * Check whether an Expr is equal() to any member of a list, ignoring * any top-level RelabelType nodes.  This is legitimate for the purposes * we use it for (matching IS [NOT] NULL arguments to arguments of strict * functions) because RelabelType doesn't change null-ness.  It's helpful * for cases such as a varchar argument of a strict function on text. */static boollist_member_strip(List *list, Expr *datum){	ListCell   *cell;	if (datum && IsA(datum, RelabelType))		datum = ((RelabelType *) datum)->arg;	foreach(cell, list)	{		Expr	   *elem = (Expr *) lfirst(cell);		if (elem && IsA(elem, RelabelType))			elem = ((RelabelType *) elem)->arg;		if (equal(elem, datum))			return true;	}	return false;}/* * Define an "operator implication table" for btree operators ("strategies"), * and a similar table for refutation. * * The strategy numbers defined by btree indexes (see access/skey.h) are: *		(1) <	(2) <=	 (3) =	 (4) >=   (5) > * and in addition we use (6) to represent <>.	<> is not a btree-indexable * operator, but we assume here that if an equality operator of a btree * opfamily has a negator operator, the negator behaves as <> for the opfamily. * * 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 6) * 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 "CONST2 test_op CONST1" 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. * * For example, if clause is "Quantity > 10" and pred is "Quantity > 5" * then we test "5 <= 10" which evals to true, so clause implies pred. * * Similarly, the interpretation of a BT_refute_table entry is: * *	 If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you *	 want to determine whether "ATTR target_op CONST2" must be false, then *	 you can use "CONST2 test_op CONST1" as a test.  If this test returns true, *	 then the target expression must be false; if the test returns false, then *	 the target expression may be true. * * For example, if clause is "Quantity > 10" and pred is "Quantity < 5" * then we test "5 <= 10" which evals to true, so clause refutes pred. * * An entry where test_op == 0 means the implication cannot be determined. */#define BTLT BTLessStrategyNumber#define BTLE BTLessEqualStrategyNumber#define BTEQ BTEqualStrategyNumber#define BTGE BTGreaterEqualStrategyNumber#define BTGT BTGreaterStrategyNumber#define BTNE 6static const StrategyNumber BT_implic_table[6][6] = {/* *			The target operator: * *	 LT    LE	 EQ    GE	 GT    NE */	{BTGE, BTGE, 0, 0, 0, BTGE},	/* LT */	{BTGT, BTGE, 0, 0, 0, BTGT},	/* LE */	{BTGT, BTGE, BTEQ, BTLE, BTLT, BTNE},		/* EQ */	{0, 0, 0, BTLE, BTLT, BTLT},	/* GE */	{0, 0, 0, BTLE, BTLE, BTLE},	/* GT */	{0, 0, 0, 0, 0, BTEQ}		/* NE */};static const StrategyNumber BT_refute_table[6][6] = {/* *			The target operator: * *	 LT    LE	 EQ    GE	 GT    NE */	{0, 0, BTGE, BTGE, BTGE, 0},	/* LT */	{0, 0, BTGT, BTGT, BTGE, 0},	/* LE */	{BTLE, BTLT, BTNE, BTGT, BTGE, BTEQ},		/* EQ */	{BTLE, BTLT, BTLT, 0, 0, 0},	/* GE */	{BTLE, BTLE, BTLE, 0, 0, 0},	/* GT */	{0, 0, BTEQ, 0, 0, 0}		/* NE */};/* * btree_predicate_proof *	  Does the predicate implication or refutation test for a "simple clause" *	  predicate and a "simple clause" restriction, when both are simple *	  operator clauses using related btree operators. * * When refute_it == false, we want to prove the predicate true; * when refute_it == true, we want to prove the predicate false. * (There is enough common code to justify handling these two cases * in one routine.)  We return TRUE if able to make the proof, FALSE * if not able to prove it. * * What we look for here is binary boolean opclauses of the form * "foo op constant", where "foo" is the same in both clauses.	The operators * and constants can be different but the operators must be in the same btree * operator family.  We use the above operator implication tables to * derive implications between nonidentical clauses.  (Note: "foo" is known * immutable, and constants are surely immutable, but we have to check that * the operators are too.  As of 8.0 it's possible for opfamilies to contain * operators that are merely stable, and we dare not make deductions with * these.) */static boolbtree_predicate_proof(Expr *predicate, Node *clause, bool refute_it){	Node	   *leftop,			   *rightop;	Node	   *pred_var,			   *clause_var;	Const	   *pred_const,			   *clause_const;	bool		pred_var_on_left,				clause_var_on_left,				pred_op_negated;	Oid			pred_op,				clause_op,				pred_op_negator,				clause_op_negator,				test_op = InvalidOid;	Oid			opfamily_id;	bool		found = false;	StrategyNumber pred_strategy,				clause_strategy,				test_strategy;	Oid			clause_righttype;	Expr	   *test_expr;	ExprState  *test_exprstate;	Datum		test_result;	bool		isNull;	CatCList   *catlist;	int			i;	EState	   *estate;	MemoryContext oldcontext;	/*	 * Both expressions must be binary opclauses with a Const on one side, and	 * identical subexpressions on the other sides. Note we don't have to	 * think about binary relabeling of the Const node, since that would have	 * been folded right into the Const.	 *	 * If either Const is null, we also fail right away; this assumes that the	 * test operator will always be strict.	 */	if (!is_opclause(predicate))		return false;	leftop = get_leftop(predicate);	rightop = get_rightop(predicate);	if (rightop == NULL)		return false;			/* not a binary opclause */	if (IsA(rightop, Const))	{		pred_var = leftop;		pred_const = (Const *) rightop;		pred_var_on_left = true;	}	else if (IsA(leftop, Const))	{		pred_var = rightop;		pred_const = (Const *) leftop;		pred_var_on_left = false;	}	else		return false;			/* no Const to be found */	if (pred_const->constisnull)		return false;	if (!is_opclause(clause))		return false;	leftop = get_leftop((Expr *) clause);	rightop = get_rightop((Expr *) clause);	if (rightop == NULL)		return false;			/* not a binary opclause */	if (IsA(rightop, Const))	{		clause_var = leftop;		clause_const = (Const *) rightop;		clause_var_on_left = true;	}	else if (IsA(leftop, Const))	{		clause_var = rightop;		clause_const = (Const *) leftop;		clause_var_on_left = false;	}	else		return false;			/* no Const to be found */	if (clause_const->constisnull)		return false;	/*	 * Check for matching subexpressions on the non-Const sides.  We used to	 * only allow a simple Var, but it's about as easy to allow any	 * expression.	Remember we already know that the pred expression does not	 * contain any non-immutable functions, so identical expressions should	 * yield identical results.	 */	if (!equal(pred_var, clause_var))		return false;	/*	 * Okay, get the operators in the two clauses we're comparing. Commute	 * them if needed so that we can assume the variables are on the left.	 */	pred_op = ((OpExpr *) predicate)->opno;	if (!pred_var_on_left)	{		pred_op = get_commutator(pred_op);		if (!OidIsValid(pred_op))			return false;	}	clause_op = ((OpExpr *) clause)->opno;	if (!clause_var_on_left)	{		clause_op = get_commutator(clause_op);		if (!OidIsValid(clause_op))			return false;	}	/*	 * Try to find a btree opfamily containing the needed operators.	 *	 * We must find a btree opfamily that contains both operators, else the	 * implication can't be determined.  Also, the opfamily must contain a	 * suitable test operator taking the pred_const and clause_const	 * datatypes.	 *	 * If there are multiple matching opfamilies, 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 opfamilies.	 */	catlist = SearchSysCacheList(AMOPOPID, 1,								 ObjectIdGetDatum(pred_op),								 0, 0, 0);	/*	 * If we couldn't find any opfamily containing the pred_op, perhaps it is	 * a <> operator.  See if it has a negator that is in an opfamily.	 */	pred_op_negated = false;	if (catlist->n_members == 0)	{		pred_op_negator = get_negator(pred_op);		if (OidIsValid(pred_op_negator))		{			pred_op_negated = true;			ReleaseSysCacheList(catlist);			catlist = SearchSysCacheList(AMOPOPID, 1,										 ObjectIdGetDatum(pred_op_negator),										 0, 0, 0);		}	}	/* Also may need the clause_op's negator */	clause_op_negator = get_negator(clause_op);	/* Now search the opfamilies */	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;		/* Must be btree */		if (pred_form->amopmethod != BTREE_AM_OID)			continue;		/* Get the predicate operator's btree strategy number */		opfamily_id = pred_form->amopfamily;		pred_strategy = (StrategyNumber) pred_form->amopstrategy;		Assert(pred_strategy >= 1 && pred_strategy <= 5);		if (pred_op_negated)		{			/* Only consider negators that are = */			if (pred_strategy != BTEqualStrategyNumber)				continue;			pred_strategy = BTNE;		}		/*		 * From the same opfamily, find a strategy number for the clause_op,		 * if possible		 */		clause_tuple = SearchSysCache(AMOPOPID,									  ObjectIdGetDatum(clause_op),									  ObjectIdGetDatum(opfamily_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/datatype */			clause_strategy = (StrategyNumber) clause_form->amopstrategy;			Assert(clause_strategy >= 1 && clause_strategy <= 5);			Assert(clause_form->amoplefttype == pred_form->amoplefttype);			clause_righttype = clause_form->amoprighttype;			ReleaseSysCache(clause_tuple);		}		else if (OidIsValid(clause_op_negator))		{			clause_tuple = SearchSysCache(AMOPOPID,										  ObjectIdGetDatum(clause_op_negator),										  ObjectIdGetDatum(opfamily_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/datatype */				clause_strategy = (StrategyNumber) clause_form->amopstrategy;				Assert(clause_strategy >= 1 && clause_strategy <= 5);				Assert(clause_form->amoplefttype == pred_form->amoplefttype);				clause_righttype = clause_form->amoprighttype;				ReleaseSysCache(clause_tuple);				/* Only consider negators that are = */				if (clause_strategy != BTEqualStrategyNumber)					continue;				clause_strategy = BTNE;			}			else				continue;		}		else			continue;		/*		 * Look up the "test" strategy number in the implication table		 */		if (refute_it)			test_strategy = BT_refute_table[clause_strategy - 1][pred_strategy - 1];		else			test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];		if (test_strategy == 0)		{			/* Can't determine implication using this interpretation */			continue;		}		/*		 * See if opfamily has an operator for the test strategy and the		 * datatypes.		 */		if (test_strategy == BTNE)		{			test_op = get_opfamily_member(opfamily_id,										  pred_form->amoprighttype,										  clause_righttype,										  BTEqualStrategyNumber);			if (OidIsValid(test_op))				test_op = get_negator(test_op);		}		else		{			test_op = get_opfamily_member(opfamily_id,										  pred_form->amoprighttype,										  clause_righttype,										  test_strategy);		}		if (OidIsValid(test_op))		{			/*			 * Last check: test_op must be immutable.			 *			 * Note that we require only the test_op to be immutable, not the			 * original clause_op.	(pred_op is assumed to have been checked			 * immutable by the caller.)  Essentially we are assuming that the			 * opfamily is consistent even if it contains operators that are			 * merely stable.			 */			if (op_volatile(test_op) == PROVOLATILE_IMMUTABLE)			{				found = true;				break;			}		}	}	ReleaseSysCacheList(catlist);	if (!found)	{		/* couldn't find a btree opfamily to interpret the operators */		return false;	}	/*	 * 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 *) pred_const,							  (Expr *) clause_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 non-proof ... but it's a tad fishy ... */		elog(DEBUG2, "null predicate test result");		return false;	}	return DatumGetBool(test_result);}

⌨️ 快捷键说明

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