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

📄 predtest.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * predtest.c *	  Routines to attempt to prove logical implications between predicate *	  expressions. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.4 2005/10/15 02:49:21 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_amop.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "executor/executor.h"#include "optimizer/clauses.h"#include "optimizer/predtest.h"#include "utils/catcache.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static bool predicate_implied_by_recurse(Node *clause, Node *predicate);static bool predicate_refuted_by_recurse(Node *clause, Node *predicate);static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause);static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause);static bool btree_predicate_proof(Expr *predicate, Node *clause,					  bool refute_it);/* * predicate_implied_by *	  Recursively checks whether the clauses in restrictinfo_list imply *	  that the given predicate is true. * * The top-level List structure of each list corresponds to an AND list. * We assume that eval_const_expressions() has been applied and so there * are no un-flattened ANDs or ORs (e.g., no AND immediately within an AND, * including AND just below the top-level List structure). * If this is not true we might fail to prove an implication that is * valid, but no worse consequences will ensue. * * We assume the predicate has already been checked to contain only * immutable functions and operators.  (In most current uses this is true * because the predicate is part of an index predicate that has passed * CheckPredicate().)  We dare not make deductions based on non-immutable * functions, because they might change answers between the time we make * the plan and the time we execute the plan. */boolpredicate_implied_by(List *predicate_list, List *restrictinfo_list){	ListCell   *item;	if (predicate_list == NIL)		return true;			/* no predicate: implication is vacuous */	if (restrictinfo_list == NIL)		return false;			/* no restriction: implication must fail */	/*	 * In all cases where the predicate is an AND-clause,	 * predicate_implied_by_recurse() will prefer to iterate over the	 * predicate's components.  So we can just do that to start with here, and	 * eliminate the need for predicate_implied_by_recurse() to handle a bare	 * List on the predicate side.	 *	 * Logic is: restriction must imply each of the AND'ed predicate items.	 */	foreach(item, predicate_list)	{		if (!predicate_implied_by_recurse((Node *) restrictinfo_list,										  lfirst(item)))			return false;	}	return true;}/* * predicate_refuted_by *	  Recursively checks whether the clauses in restrictinfo_list refute *	  the given predicate (that is, prove it false). * * This is NOT the same as !(predicate_implied_by), though it is similar * in the technique and structure of the code. * * The top-level List structure of each list corresponds to an AND list. * We assume that eval_const_expressions() has been applied and so there * are no un-flattened ANDs or ORs (e.g., no AND immediately within an AND, * including AND just below the top-level List structure). * If this is not true we might fail to prove an implication that is * valid, but no worse consequences will ensue. * * We assume the predicate has already been checked to contain only * immutable functions and operators.  We dare not make deductions based on * non-immutable functions, because they might change answers between the * time we make the plan and the time we execute the plan. */boolpredicate_refuted_by(List *predicate_list, List *restrictinfo_list){	if (predicate_list == NIL)		return false;			/* no predicate: no refutation is possible */	if (restrictinfo_list == NIL)		return false;			/* no restriction: refutation must fail */	/*	 * Unlike the implication case, predicate_refuted_by_recurse needs to be	 * able to see the top-level AND structure on both sides --- otherwise it	 * will fail to handle the case where one restriction clause is an OR that	 * can refute the predicate AND as a whole, but not each predicate clause	 * separately.	 */	return predicate_refuted_by_recurse((Node *) restrictinfo_list,										(Node *) predicate_list);}/*---------- * predicate_implied_by_recurse *	  Does the predicate implication test for non-NULL restriction and *	  predicate clauses. * * The logic followed here is ("=>" means "implies"): *	atom A => atom B iff:			predicate_implied_by_simple_clause says so *	atom A => AND-expr B iff:		A => each of B's components *	atom A => OR-expr B iff:		A => any of B's components *	AND-expr A => atom B iff:		any of A's components => B *	AND-expr A => AND-expr B iff:	A => each of B's components *	AND-expr A => OR-expr B iff:	A => any of B's components, *									*or* any of A's components => B *	OR-expr A => atom B iff:		each of A's components => B *	OR-expr A => AND-expr B iff:	A => each of B's components *	OR-expr A => OR-expr B iff:		each of A's components => any of B's * * An "atom" is anything other than an AND or OR node.	Notice that we don't * have any special logic to handle NOT nodes; these should have been pushed * down or eliminated where feasible by prepqual.c. * * We can't recursively expand either side first, but have to interleave * the expansions per the above rules, to be sure we handle all of these * examples: *		(x OR y) => (x OR y OR z) *		(x AND y AND z) => (x AND y) *		(x AND y) => ((x AND y) OR z) *		((x OR y) AND z) => (x OR y) * This is still not an exhaustive test, but it handles most normal cases * under the assumption that both inputs have been AND/OR flattened. * * A bare List node on the restriction side is interpreted as an AND clause, * in order to handle the top-level restriction List properly.	However we * need not consider a List on the predicate side since predicate_implied_by() * already expanded it. * * We have to be prepared to handle RestrictInfo nodes in the restrictinfo * tree, though not in the predicate tree. *---------- */static boolpredicate_implied_by_recurse(Node *clause, Node *predicate){	ListCell   *item;	Assert(clause != NULL);	/* skip through RestrictInfo */	if (IsA(clause, RestrictInfo))	{		clause = (Node *) ((RestrictInfo *) clause)->clause;		Assert(clause != NULL);		Assert(!IsA(clause, RestrictInfo));	}	Assert(predicate != NULL);	/*	 * Since a restriction List clause is handled the same as an AND clause,	 * we can avoid duplicate code like this:	 */	if (and_clause(clause))		clause = (Node *) ((BoolExpr *) clause)->args;	if (IsA(clause, List))	{		if (and_clause(predicate))		{			/* AND-clause => AND-clause if A implies each of B's items */			foreach(item, ((BoolExpr *) predicate)->args)			{				if (!predicate_implied_by_recurse(clause, lfirst(item)))					return false;			}			return true;		}		else if (or_clause(predicate))		{			/* AND-clause => OR-clause if A implies any of B's items */			/* Needed to handle (x AND y) => ((x AND y) OR z) */			foreach(item, ((BoolExpr *) predicate)->args)			{				if (predicate_implied_by_recurse(clause, lfirst(item)))					return true;			}			/* Also check if any of A's items implies B */			/* Needed to handle ((x OR y) AND z) => (x OR y) */			foreach(item, (List *) clause)			{				if (predicate_implied_by_recurse(lfirst(item), predicate))					return true;			}			return false;		}		else		{			/* AND-clause => atom if any of A's items implies B */			foreach(item, (List *) clause)			{				if (predicate_implied_by_recurse(lfirst(item), predicate))					return true;			}			return false;		}	}	else if (or_clause(clause))	{		if (or_clause(predicate))		{			/*			 * OR-clause => OR-clause if each of A's items implies any of B's			 * items.  Messy but can't do it any more simply.			 */			foreach(item, ((BoolExpr *) clause)->args)			{				Node	   *citem = lfirst(item);				ListCell   *item2;				foreach(item2, ((BoolExpr *) predicate)->args)				{					if (predicate_implied_by_recurse(citem, lfirst(item2)))						break;				}				if (item2 == NULL)					return false;		/* doesn't imply any of B's */			}			return true;		}		else		{			/* OR-clause => AND-clause if each of A's items implies B */			/* OR-clause => atom if each of A's items implies B */			foreach(item, ((BoolExpr *) clause)->args)			{				if (!predicate_implied_by_recurse(lfirst(item), predicate))					return false;			}			return true;		}	}	else	{		if (and_clause(predicate))		{			/* atom => AND-clause if A implies each of B's items */			foreach(item, ((BoolExpr *) predicate)->args)			{				if (!predicate_implied_by_recurse(clause, lfirst(item)))					return false;			}			return true;		}		else if (or_clause(predicate))		{			/* atom => OR-clause if A implies any of B's items */			foreach(item, ((BoolExpr *) predicate)->args)			{				if (predicate_implied_by_recurse(clause, lfirst(item)))					return true;			}			return false;		}		else		{			/* atom => atom is the base case */			return predicate_implied_by_simple_clause((Expr *) predicate,													  clause);		}	}}/*---------- * predicate_refuted_by_recurse *	  Does the predicate refutation test for non-NULL restriction and *	  predicate clauses. * * The logic followed here is ("R=>" means "refutes"): *	atom A R=> atom B iff:			predicate_refuted_by_simple_clause says so *	atom A R=> AND-expr B iff:		A R=> any of B's components *	atom A R=> OR-expr B iff:		A R=> each of B's components *	AND-expr A R=> atom B iff:		any of A's components R=> B *	AND-expr A R=> AND-expr B iff:	A R=> any of B's components, *									*or* any of A's components R=> B *	AND-expr A R=> OR-expr B iff:	A R=> each of B's components *	OR-expr A R=> atom B iff:		each of A's components R=> B *	OR-expr A R=> AND-expr B iff:	each of A's components R=> any of B's *	OR-expr A R=> OR-expr B iff:	A R=> each of B's components * * Other comments are as for predicate_implied_by_recurse(), except that * we have to handle a top-level AND list on both sides. *---------- */static boolpredicate_refuted_by_recurse(Node *clause, Node *predicate){	ListCell   *item;	Assert(clause != NULL);	/* skip through RestrictInfo */	if (IsA(clause, RestrictInfo))	{		clause = (Node *) ((RestrictInfo *) clause)->clause;		Assert(clause != NULL);		Assert(!IsA(clause, RestrictInfo));	}	Assert(predicate != NULL);	/*	 * Since a restriction List clause is handled the same as an AND clause,	 * we can avoid duplicate code like this:	 */	if (and_clause(clause))		clause = (Node *) ((BoolExpr *) clause)->args;	/* Ditto for predicate AND-clause and List */	if (and_clause(predicate))		predicate = (Node *) ((BoolExpr *) predicate)->args;	if (IsA(clause, List))	{		if (IsA(predicate, List))		{			/* AND-clause R=> AND-clause if A refutes any of B's items */			/* Needed to handle (x AND y) R=> ((!x OR !y) AND z) */			foreach(item, (List *) predicate)			{				if (predicate_refuted_by_recurse(clause, lfirst(item)))					return true;			}			/* Also check if any of A's items refutes B */			/* Needed to handle ((x OR y) AND z) R=> (!x AND !y) */			foreach(item, (List *) clause)			{				if (predicate_refuted_by_recurse(lfirst(item), predicate))					return true;			}			return false;		}		else if (or_clause(predicate))		{			/* AND-clause R=> OR-clause if A refutes each of B's items */			foreach(item, ((BoolExpr *) predicate)->args)			{				if (!predicate_refuted_by_recurse(clause, lfirst(item)))					return false;			}			return true;		}		else		{			/* AND-clause R=> atom if any of A's items refutes B */			foreach(item, (List *) clause)			{				if (predicate_refuted_by_recurse(lfirst(item), predicate))					return true;			}			return false;		}	}	else if (or_clause(clause))	{		if (or_clause(predicate))		{			/* OR-clause R=> OR-clause if A refutes each of B's items */			foreach(item, ((BoolExpr *) predicate)->args)			{				if (!predicate_refuted_by_recurse(clause, lfirst(item)))					return false;			}			return true;		}		else if (IsA(predicate, List))		{			/*			 * OR-clause R=> AND-clause if each of A's items refutes any of			 * B's items.			 */			foreach(item, ((BoolExpr *) clause)->args)			{				Node	   *citem = lfirst(item);				ListCell   *item2;				foreach(item2, (List *) predicate)				{					if (predicate_refuted_by_recurse(citem, lfirst(item2)))						break;				}				if (item2 == NULL)					return false;		/* citem refutes nothing */			}			return true;		}		else		{			/* OR-clause R=> atom if each of A's items refutes B */			foreach(item, ((BoolExpr *) clause)->args)			{				if (!predicate_refuted_by_recurse(lfirst(item), predicate))					return false;			}			return true;		}	}	else	{		if (IsA(predicate, List))		{			/* atom R=> AND-clause if A refutes any of B's items */			foreach(item, (List *) predicate)			{				if (predicate_refuted_by_recurse(clause, lfirst(item)))					return true;			}			return false;		}		else if (or_clause(predicate))		{			/* atom R=> OR-clause if A refutes each of B's items */			foreach(item, ((BoolExpr *) predicate)->args)			{				if (!predicate_refuted_by_recurse(clause, lfirst(item)))					return false;			}			return true;		}		else		{			/* atom R=> atom is the base case */			return predicate_refuted_by_simple_clause((Expr *) predicate,													  clause);		}	}}/*---------- * predicate_implied_by_simple_clause *	  Does the predicate implication test for a "simple clause" predicate *	  and a "simple clause" restriction. * * We return TRUE if able to prove the implication, FALSE if not. * * We have three 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 the caller.) * * When the predicate is of the form "foo IS NOT NULL", we can conclude that * the predicate is implied if the clause is a strict operator or function * that has "foo" as an input.	In this case the clause must yield NULL when * "foo" is NULL, which we can take as equivalent to FALSE because we know * we are within an AND/OR subtree of a WHERE clause.  (Again, "foo" is * already known immutable, so the clause will certainly always fail.) * * Finally, we may be able to deduce something using knowledge about btree * operator classes; this is encapsulated in btree_predicate_proof(). *---------- */static boolpredicate_implied_by_simple_clause(Expr *predicate, Node *clause){	/* First try the equal() test */	if (equal((Node *) predicate, clause))		return true;	/* Next try the IS NOT NULL case */

⌨️ 快捷键说明

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