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

📄 predtest.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * predtest.c *	  Routines to attempt to prove logical implications between predicate *	  expressions. * * Portions Copyright (c) 1996-2008, 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.19 2008/01/12 00:11:39 tgl 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 "parser/parse_expr.h"#include "utils/array.h"#include "utils/lsyscache.h"#include "utils/syscache.h"/* * To avoid redundant coding in predicate_implied_by_recurse and * predicate_refuted_by_recurse, we need to abstract out the notion of * iterating over the components of an expression that is logically an AND * or OR structure.  There are multiple sorts of expression nodes that can * be treated as ANDs or ORs, and we don't want to code each one separately. * Hence, these types and support routines. */typedef enum{	CLASS_ATOM,					/* expression that's not AND or OR */	CLASS_AND,					/* expression with AND semantics */	CLASS_OR					/* expression with OR semantics */} PredClass;typedef struct PredIterInfoData *PredIterInfo;typedef struct PredIterInfoData{	/* node-type-specific iteration state */	void	   *state;	/* initialize to do the iteration */	void		(*startup_fn) (Node *clause, PredIterInfo info);	/* next-component iteration function */	Node	   *(*next_fn) (PredIterInfo info);	/* release resources when done with iteration */	void		(*cleanup_fn) (PredIterInfo info);} PredIterInfoData;#define iterate_begin(item, clause, info)	\	do { \		Node   *item; \		(info).startup_fn((clause), &(info)); \		while ((item = (info).next_fn(&(info))) != NULL)#define iterate_end(info)	\		(info).cleanup_fn(&(info)); \	} while (0)static bool predicate_implied_by_recurse(Node *clause, Node *predicate);static bool predicate_refuted_by_recurse(Node *clause, Node *predicate);static PredClass predicate_classify(Node *clause, PredIterInfo info);static void list_startup_fn(Node *clause, PredIterInfo info);static Node *list_next_fn(PredIterInfo info);static void list_cleanup_fn(PredIterInfo info);static void boolexpr_startup_fn(Node *clause, PredIterInfo info);static void arrayconst_startup_fn(Node *clause, PredIterInfo info);static Node *arrayconst_next_fn(PredIterInfo info);static void arrayconst_cleanup_fn(PredIterInfo info);static void arrayexpr_startup_fn(Node *clause, PredIterInfo info);static Node *arrayexpr_next_fn(PredIterInfo info);static void arrayexpr_cleanup_fn(PredIterInfo info);static bool predicate_implied_by_simple_clause(Expr *predicate, Node *clause);static bool predicate_refuted_by_simple_clause(Expr *predicate, Node *clause);static Node *extract_not_arg(Node *clause);static bool list_member_strip(List *list, Expr *datum);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){	if (predicate_list == NIL)		return true;			/* no predicate: implication is vacuous */	if (restrictinfo_list == NIL)		return false;			/* no restriction: implication must fail */	/* Otherwise, away we go ... */	return predicate_implied_by_recurse((Node *) restrictinfo_list,										(Node *) predicate_list);}/* * 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. * * An important fine point is that truth of the clauses must imply that * the predicate returns FALSE, not that it does not return TRUE.  This * is normally used to try to refute CHECK constraints, and the only * thing we can assume about a CHECK constraint is that it didn't return * FALSE --- a NULL result isn't a violation per the SQL spec.  (Someday * perhaps this code should be extended to support both "strong" and * "weak" refutation, but for now we only need "strong".) * * 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 */	/* Otherwise, away we go ... */	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. * * 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){	PredIterInfoData clause_info;	PredIterInfoData pred_info;	PredClass	pclass;	bool		result;	/* skip through RestrictInfo */	Assert(clause != NULL);	if (IsA(clause, RestrictInfo))		clause = (Node *) ((RestrictInfo *) clause)->clause;	pclass = predicate_classify(predicate, &pred_info);	switch (predicate_classify(clause, &clause_info))	{		case CLASS_AND:			switch (pclass)			{				case CLASS_AND:					/*					 * AND-clause => AND-clause if A implies each of B's items					 */					result = true;					iterate_begin(pitem, predicate, pred_info)					{						if (!predicate_implied_by_recurse(clause, pitem))						{							result = false;							break;						}					}					iterate_end(pred_info);					return result;				case CLASS_OR:					/*					 * AND-clause => OR-clause if A implies any of B's items					 *					 * Needed to handle (x AND y) => ((x AND y) OR z)					 */					result = false;					iterate_begin(pitem, predicate, pred_info)					{						if (predicate_implied_by_recurse(clause, pitem))						{							result = true;							break;						}					}					iterate_end(pred_info);					if (result)						return result;					/*					 * Also check if any of A's items implies B					 *					 * Needed to handle ((x OR y) AND z) => (x OR y)					 */					iterate_begin(citem, clause, clause_info)					{						if (predicate_implied_by_recurse(citem, predicate))						{							result = true;							break;						}					}					iterate_end(clause_info);					return result;				case CLASS_ATOM:					/*					 * AND-clause => atom if any of A's items implies B					 */					result = false;					iterate_begin(citem, clause, clause_info)					{						if (predicate_implied_by_recurse(citem, predicate))						{							result = true;							break;						}					}					iterate_end(clause_info);					return result;			}			break;		case CLASS_OR:			switch (pclass)			{				case CLASS_OR:					/*					 * 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.					 */					result = true;					iterate_begin(citem, clause, clause_info)					{						bool		presult = false;						iterate_begin(pitem, predicate, pred_info)						{							if (predicate_implied_by_recurse(citem, pitem))							{								presult = true;								break;							}						}						iterate_end(pred_info);						if (!presult)						{							result = false;		/* doesn't imply any of B's */							break;						}					}					iterate_end(clause_info);					return result;				case CLASS_AND:				case CLASS_ATOM:					/*					 * OR-clause => AND-clause if each of A's items implies B					 *					 * OR-clause => atom if each of A's items implies B					 */					result = true;					iterate_begin(citem, clause, clause_info)					{						if (!predicate_implied_by_recurse(citem, predicate))						{							result = false;							break;						}					}					iterate_end(clause_info);					return result;			}			break;		case CLASS_ATOM:			switch (pclass)			{				case CLASS_AND:					/*					 * atom => AND-clause if A implies each of B's items					 */					result = true;					iterate_begin(pitem, predicate, pred_info)					{						if (!predicate_implied_by_recurse(clause, pitem))						{							result = false;							break;						}					}					iterate_end(pred_info);					return result;				case CLASS_OR:					/*					 * atom => OR-clause if A implies any of B's items					 */					result = false;					iterate_begin(pitem, predicate, pred_info)					{						if (predicate_implied_by_recurse(clause, pitem))						{							result = true;							break;						}					}					iterate_end(pred_info);					return result;				case CLASS_ATOM:					/*					 * atom => atom is the base case					 */					return						predicate_implied_by_simple_clause((Expr *) predicate,														   clause);			}			break;	}	/* can't get here */	elog(ERROR, "predicate_classify returned a bogus value");	return false;}/*---------- * 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 * * In addition, if the predicate is a NOT-clause then we can use *	A R=> NOT B if:					A => B * This works for several different SQL constructs that assert the non-truth * of their argument, ie NOT, IS FALSE, IS NOT TRUE, IS UNKNOWN. * Unfortunately we *cannot* use *	NOT A R=> B if:					B => A * because this type of reasoning fails to prove that B doesn't yield NULL. * * Other comments are as for predicate_implied_by_recurse(). *---------- */static boolpredicate_refuted_by_recurse(Node *clause, Node *predicate){	PredIterInfoData clause_info;	PredIterInfoData pred_info;	PredClass	pclass;	Node	   *not_arg;	bool		result;	/* skip through RestrictInfo */	Assert(clause != NULL);	if (IsA(clause, RestrictInfo))		clause = (Node *) ((RestrictInfo *) clause)->clause;	pclass = predicate_classify(predicate, &pred_info);	switch (predicate_classify(clause, &clause_info))	{		case CLASS_AND:			switch (pclass)			{				case CLASS_AND:					/*					 * 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)					 */					result = false;					iterate_begin(pitem, predicate, pred_info)					{						if (predicate_refuted_by_recurse(clause, pitem))						{							result = true;							break;						}					}					iterate_end(pred_info);					if (result)						return result;					/*					 * Also check if any of A's items refutes B					 *					 * Needed to handle ((x OR y) AND z) R=> (!x AND !y)					 */					iterate_begin(citem, clause, clause_info)					{						if (predicate_refuted_by_recurse(citem, predicate))						{							result = true;							break;						}					}					iterate_end(clause_info);					return result;				case CLASS_OR:					/*					 * AND-clause R=> OR-clause if A refutes each of B's items					 */					result = true;					iterate_begin(pitem, predicate, pred_info)					{						if (!predicate_refuted_by_recurse(clause, pitem))						{							result = false;							break;						}					}					iterate_end(pred_info);					return result;				case CLASS_ATOM:					/*					 * If B is a NOT-clause, A R=> B if A => B's arg					 */					not_arg = extract_not_arg(predicate);					if (not_arg &&						predicate_implied_by_recurse(clause, not_arg))						return true;					/*					 * AND-clause R=> atom if any of A's items refutes B					 */					result = false;					iterate_begin(citem, clause, clause_info)					{						if (predicate_refuted_by_recurse(citem, predicate))						{							result = true;							break;						}

⌨️ 快捷键说明

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