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

📄 clauses.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
 * * Returns a list of the pseudo-constant clauses in constantQual and the * remaining quals as the return value. */List *pull_constant_clauses(List *quals, List **constantQual){	List	   *constqual = NIL,			   *restqual = NIL;	ListCell   *q;	foreach(q, quals)	{		Node	   *qual = (Node *) lfirst(q);		if (is_pseudo_constant_clause(qual))			constqual = lappend(constqual, qual);		else			restqual = lappend(restqual, qual);	}	*constantQual = constqual;	return restqual;}/***************************************************************************** *		Tests on clauses of queries * * Possibly this code should go someplace else, since this isn't quite the * same meaning of "clause" as is used elsewhere in this module.  But I can't * think of a better place for it... *****************************************************************************//* * Test whether a query uses DISTINCT ON, ie, has a distinct-list that is * not the same as the set of output columns. */boolhas_distinct_on_clause(Query *query){	ListCell   *l;	/* Is there a DISTINCT clause at all? */	if (query->distinctClause == NIL)		return false;	/*	 * If the DISTINCT list contains all the nonjunk targetlist items, and	 * nothing else (ie, no junk tlist items), then it's a simple DISTINCT,	 * else it's DISTINCT ON.  We do not require the lists to be in the same	 * order (since the parser may have adjusted the DISTINCT clause ordering	 * to agree with ORDER BY).  Furthermore, a non-DISTINCT junk tlist item	 * that is in the sortClause is also evidence of DISTINCT ON, since we	 * don't allow ORDER BY on junk tlist items when plain DISTINCT is used.	 *	 * This code assumes that the DISTINCT list is valid, ie, all its entries	 * match some entry of the tlist.	 */	foreach(l, query->targetList)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		if (tle->ressortgroupref == 0)		{			if (tle->resjunk)				continue;		/* we can ignore unsorted junk cols */			return true;		/* definitely not in DISTINCT list */		}		if (targetIsInSortList(tle, query->distinctClause))		{			if (tle->resjunk)				return true;	/* junk TLE in DISTINCT means DISTINCT ON */			/* else this TLE is okay, keep looking */		}		else		{			/* This TLE is not in DISTINCT list */			if (!tle->resjunk)				return true;	/* non-junk, non-DISTINCT, so DISTINCT ON */			if (targetIsInSortList(tle, query->sortClause))				return true;	/* sorted, non-distinct junk */			/* unsorted junk is okay, keep looking */		}	}	/* It's a simple DISTINCT */	return false;}/* * Test whether a query uses simple DISTINCT, ie, has a distinct-list that * is the same as the set of output columns. */boolhas_distinct_clause(Query *query){	/* Is there a DISTINCT clause at all? */	if (query->distinctClause == NIL)		return false;	/* It's DISTINCT if it's not DISTINCT ON */	return !has_distinct_on_clause(query);}/***************************************************************************** *																			 * *		General clause-manipulating routines								 * *																			 * *****************************************************************************//* * NumRelids *		(formerly clause_relids) * * Returns the number of different relations referenced in 'clause'. */intNumRelids(Node *clause){	Relids		varnos = pull_varnos(clause);	int			result = bms_num_members(varnos);	bms_free(varnos);	return result;}/* * CommuteClause: commute a binary operator clause * * XXX the clause is destructively modified! */voidCommuteClause(OpExpr *clause){	Oid			opoid;	Node	   *temp;	/* Sanity checks: caller is at fault if these fail */	if (!is_opclause(clause) ||		list_length(clause->args) != 2)		elog(ERROR, "cannot commute non-binary-operator clause");	opoid = get_commutator(clause->opno);	if (!OidIsValid(opoid))		elog(ERROR, "could not find commutator for operator %u",			 clause->opno);	/*	 * modify the clause in-place!	 */	clause->opno = opoid;	clause->opfuncid = InvalidOid;	/* opresulttype and opretset are assumed not to change */	temp = linitial(clause->args);	linitial(clause->args) = lsecond(clause->args);	lsecond(clause->args) = temp;}/* * strip_implicit_coercions: remove implicit coercions at top level of tree * * Note: there isn't any useful thing we can do with a RowExpr here, so * just return it unchanged, even if it's marked as an implicit coercion. */Node *strip_implicit_coercions(Node *node){	if (node == NULL)		return NULL;	if (IsA(node, FuncExpr))	{		FuncExpr   *f = (FuncExpr *) node;		if (f->funcformat == COERCE_IMPLICIT_CAST)			return strip_implicit_coercions(linitial(f->args));	}	else if (IsA(node, RelabelType))	{		RelabelType *r = (RelabelType *) node;		if (r->relabelformat == COERCE_IMPLICIT_CAST)			return strip_implicit_coercions((Node *) r->arg);	}	else if (IsA(node, ConvertRowtypeExpr))	{		ConvertRowtypeExpr *c = (ConvertRowtypeExpr *) node;		if (c->convertformat == COERCE_IMPLICIT_CAST)			return strip_implicit_coercions((Node *) c->arg);	}	else if (IsA(node, CoerceToDomain))	{		CoerceToDomain *c = (CoerceToDomain *) node;		if (c->coercionformat == COERCE_IMPLICIT_CAST)			return strip_implicit_coercions((Node *) c->arg);	}	return node;}/* * set_coercionform_dontcare: set all CoercionForm fields to COERCE_DONTCARE * * This is used to make index expressions and index predicates more easily * comparable to clauses of queries.  CoercionForm is not semantically * significant (for cases where it does matter, the significant info is * coded into the coercion function arguments) so we can ignore it during * comparisons.  Thus, for example, an index on "foo::int4" can match an * implicit coercion to int4. * * Caution: the passed expression tree is modified in-place. */voidset_coercionform_dontcare(Node *node){	(void) set_coercionform_dontcare_walker(node, NULL);}static boolset_coercionform_dontcare_walker(Node *node, void *context){	if (node == NULL)		return false;	if (IsA(node, FuncExpr))		((FuncExpr *) node)->funcformat = COERCE_DONTCARE;	else if (IsA(node, RelabelType))		((RelabelType *) node)->relabelformat = COERCE_DONTCARE;	else if (IsA(node, ConvertRowtypeExpr))		((ConvertRowtypeExpr *) node)->convertformat = COERCE_DONTCARE;	else if (IsA(node, RowExpr))		((RowExpr *) node)->row_format = COERCE_DONTCARE;	else if (IsA(node, CoerceToDomain))		((CoerceToDomain *) node)->coercionformat = COERCE_DONTCARE;	return expression_tree_walker(node, set_coercionform_dontcare_walker,								  context);}/* * Helper for eval_const_expressions: check that datatype of an attribute * is still what it was when the expression was parsed.  This is needed to * guard against improper simplification after ALTER COLUMN TYPE.  (XXX we * may well need to make similar checks elsewhere?) */static boolrowtype_field_matches(Oid rowtypeid, int fieldnum,					  Oid expectedtype, int32 expectedtypmod){	TupleDesc	tupdesc;	Form_pg_attribute attr;	/* No issue for RECORD, since there is no way to ALTER such a type */	if (rowtypeid == RECORDOID)		return true;	tupdesc = lookup_rowtype_tupdesc(rowtypeid, -1);	if (fieldnum <= 0 || fieldnum > tupdesc->natts)		return false;	attr = tupdesc->attrs[fieldnum - 1];	if (attr->attisdropped ||		attr->atttypid != expectedtype ||		attr->atttypmod != expectedtypmod)		return false;	return true;}/*-------------------- * eval_const_expressions * * Reduce any recognizably constant subexpressions of the given * expression tree, for example "2 + 2" => "4".  More interestingly, * we can reduce certain boolean expressions even when they contain * non-constant subexpressions: "x OR true" => "true" no matter what * the subexpression x is.	(XXX We assume that no such subexpression * will have important side-effects, which is not necessarily a good * assumption in the presence of user-defined functions; do we need a * pg_proc flag that prevents discarding the execution of a function?) * * We do understand that certain functions may deliver non-constant * results even with constant inputs, "nextval()" being the classic * example.  Functions that are not marked "immutable" in pg_proc * will not be pre-evaluated here, although we will reduce their * arguments as far as possible. * * We assume that the tree has already been type-checked and contains * only operators and functions that are reasonable to try to execute. * * NOTE: the planner assumes that this will always flatten nested AND and * OR clauses into N-argument form.  See comments in prepqual.c. *-------------------- */Node *eval_const_expressions(Node *node){	eval_const_expressions_context context;	context.active_fns = NIL;	/* nothing being recursively simplified */	context.case_val = NULL;	/* no CASE being examined */	context.estimate = false;	/* safe transformations only */	return eval_const_expressions_mutator(node, &context);}/*-------------------- * estimate_expression_value * * This function attempts to estimate the value of an expression for * planning purposes.  It is in essence a more aggressive version of * eval_const_expressions(): we will perform constant reductions that are * not necessarily 100% safe, but are reasonable for estimation purposes. * * Currently the extra steps that are taken in this mode are: * 1. Substitute values for Params, where a bound Param value has been made *	  available by the caller of planner(). * 2. Fold stable, as well as immutable, functions to constants. *-------------------- */Node *estimate_expression_value(Node *node){	eval_const_expressions_context context;	context.active_fns = NIL;	/* nothing being recursively simplified */	context.case_val = NULL;	/* no CASE being examined */	context.estimate = true;	/* unsafe transformations OK */	return eval_const_expressions_mutator(node, &context);}static Node *eval_const_expressions_mutator(Node *node,							   eval_const_expressions_context *context){	if (node == NULL)		return NULL;	if (IsA(node, Param))	{		Param	   *param = (Param *) node;		/* OK to try to substitute value? */		if (context->estimate && param->paramkind != PARAM_EXEC &&			PlannerBoundParamList != NULL)		{			ParamListInfo paramInfo;			/* Search to see if we've been given a value for this Param */			paramInfo = lookupParam(PlannerBoundParamList,									param->paramkind,									param->paramname,									param->paramid,									true);			if (paramInfo)			{				/*				 * Found it, so return a Const representing the param value.				 * Note that we don't copy pass-by-ref datatypes, so the Const				 * will only be valid as long as the bound parameter list				 * exists. This is okay for intended uses of				 * estimate_expression_value().				 */				int16		typLen;				bool		typByVal;				Assert(paramInfo->ptype == param->paramtype);				get_typlenbyval(param->paramtype, &typLen, &typByVal);				return (Node *) makeConst(param->paramtype,										  (int) typLen,										  paramInfo->value,										  paramInfo->isnull,										  typByVal);			}		}		/* Not replaceable, so just copy the Param (no need to recurse) */		return (Node *) copyObject(param);	}	if (IsA(node, FuncExpr))	{		FuncExpr   *expr = (FuncExpr *) node;		List	   *args;		Expr	   *simple;		FuncExpr   *newexpr;		/*		 * Reduce constants in the FuncExpr's arguments.  We know args is		 * either NIL or a List node, so we can call expression_tree_mutator		 * directly rather than recursing to self.		 */		args = (List *) expression_tree_mutator((Node *) expr->args,											  eval_const_expressions_mutator,												(void *) context);		/*		 * Code for op/func reduction is pretty bulky, so split it out as a		 * separate function.		 */		simple = simplify_function(expr->funcid, expr->funcresulttype, args,								   true, context);		if (simple)				/* successfully simplified it */			return (Node *) simple;		/*		 * The expression cannot be simplified any further, so build and		 * return a replacement FuncExpr node using the possibly-simplified		 * arguments.		 */		newexpr = makeNode(FuncExpr);		newexpr->funcid = expr->funcid;		newexpr->funcresulttype = expr->funcresulttype;		newexpr->funcretset = expr->funcretset;		newexpr->funcformat = expr->funcformat;		newexpr->args = args;		return (Node *) newexpr;	}	if (IsA(node, OpExpr))	{		OpExpr	   *expr = (OpExpr *) node;		List	   *args;		Expr	   *simple;		OpExpr	   *newexpr;		/*		 * Reduce constants in the OpExpr's arguments.  We know args is either		 * NIL or a List node, so we can call expression_tree_mutator directly		 * rather than recursing to self.		 */		args = (List *) expression_tree_mutator((Node *) expr->args,											  eval_const_expressions_mutator,												(void *) context);		/*		 * Need to get OID of underlying function.	Okay to scribble on input		 * to this extent.		 */		set_opfuncid(expr);		/*		 * Code for op/func reduction is pretty bulky, so split it out as a		 * separate function.		 */		simple = simplify_function(expr->opfuncid, expr->opresulttype, args,								   true, context);		if (simple)				/* successfully simplified it */			return (Node *) simple;		/*		 * If the operator is boolean equality, we know how to simplify cases		 * involving one constant and one non-constant argument.		 */		if (expr->opno == BooleanEqualOperator)		{			simple = simplify_boolean_equality(args);			if (simple)			/* successfully simplified it */				return (Node *) simple;		}		/*

⌨️ 快捷键说明

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