clauses.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,294 行 · 第 1/5 页

C
2,294
字号
			if (!tle->resjunk)				return true;	/* non-junk, non-DISTINCT, so DISTINCT ON */			if (targetIsInSortList(tle, InvalidOid, 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;}/* * CommuteOpExpr: commute a binary operator clause * * XXX the clause is destructively modified! */voidCommuteOpExpr(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;}/* * CommuteRowCompareExpr: commute a RowCompareExpr clause * * XXX the clause is destructively modified! */voidCommuteRowCompareExpr(RowCompareExpr *clause){	List	   *newops;	List	   *temp;	ListCell   *l;	/* Sanity checks: caller is at fault if these fail */	if (!IsA(clause, RowCompareExpr))		elog(ERROR, "expected a RowCompareExpr");	/* Build list of commuted operators */	newops = NIL;	foreach(l, clause->opnos)	{		Oid			opoid = lfirst_oid(l);		opoid = get_commutator(opoid);		if (!OidIsValid(opoid))			elog(ERROR, "could not find commutator for operator %u",				 lfirst_oid(l));		newops = lappend_oid(newops, opoid);	}	/*	 * modify the clause in-place!	 */	switch (clause->rctype)	{		case ROWCOMPARE_LT:			clause->rctype = ROWCOMPARE_GT;			break;		case ROWCOMPARE_LE:			clause->rctype = ROWCOMPARE_GE;			break;		case ROWCOMPARE_GE:			clause->rctype = ROWCOMPARE_LE;			break;		case ROWCOMPARE_GT:			clause->rctype = ROWCOMPARE_LT;			break;		default:			elog(ERROR, "unexpected RowCompare type: %d",				 (int) clause->rctype);			break;	}	clause->opnos = newops;	/*	 * Note: we need not change the opfamilies list; we assume any btree	 * opfamily containing an operator will also contain its commutator.	 */	temp = clause->largs;	clause->largs = clause->rargs;	clause->rargs = 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, CoerceViaIO))	{		CoerceViaIO *c = (CoerceViaIO *) node;		if (c->coerceformat == COERCE_IMPLICIT_CAST)			return strip_implicit_coercions((Node *) c->arg);	}	else if (IsA(node, ArrayCoerceExpr))	{		ArrayCoerceExpr *c = (ArrayCoerceExpr *) node;		if (c->coerceformat == COERCE_IMPLICIT_CAST)			return strip_implicit_coercions((Node *) c->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, CoerceViaIO))		((CoerceViaIO *) node)->coerceformat = COERCE_DONTCARE;	else if (IsA(node, ArrayCoerceExpr))		((ArrayCoerceExpr *) node)->coerceformat = 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)	{		ReleaseTupleDesc(tupdesc);		return false;	}	attr = tupdesc->attrs[fieldnum - 1];	if (attr->attisdropped ||		attr->atttypid != expectedtype ||		attr->atttypmod != expectedtypmod)	{		ReleaseTupleDesc(tupdesc);		return false;	}	ReleaseTupleDesc(tupdesc);	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: "root" can be passed as NULL if the caller never wants to do any * Param substitutions. * * 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(PlannerInfo *root, Node *node){	eval_const_expressions_context context;	if (root)		context.boundParams = root->glob->boundParams;	/* bound Params */	else		context.boundParams = NULL;	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(), even if the Param isn't marked *	  constant.  This effectively means that we plan using the first supplied *	  value of the Param. * 2. Fold stable, as well as immutable, functions to constants. *-------------------- */Node *estimate_expression_value(PlannerInfo *root, Node *node){	eval_const_expressions_context context;	context.boundParams = root->glob->boundParams;		/* bound Params */	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;		/* Look to see if we've been given a value for this Param */		if (param->paramkind == PARAM_EXTERN &&			context->boundParams != NULL &&			param->paramid > 0 &&			param->paramid <= context->boundParams->numParams)		{			ParamExternData *prm = &context->boundParams->params[param->paramid - 1];			if (OidIsValid(prm->ptype))			{				/* OK to substitute parameter value? */				if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))				{					/*					 * Return a Const representing the param value.  Must copy					 * pass-by-ref datatypes, since the Param might be in a					 * memory context shorter-lived than our output plan					 * should be.					 */					int16		typLen;					bool		typByVal;					Datum		pval;					Assert(prm->ptype == param->paramtype);					get_typlenbyval(param->paramtype, &typLen, &typByVal);					if (prm->isnull || typByVal)						pval = prm->value;					else						pval = datumCopy(prm->value, typByVal, typLen);					return (Node *) makeConst(param->paramtype,											  param->paramtypmod,											  (int) typLen,											  pval,											  prm->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.  Note: exprTypmod normally returns -1 for a		 * FuncExpr, but not when the node is recognizably a length coercion;		 * we want to preserve the typmod in the eventual Const if so.		 */		simple = simplify_function(expr->funcid,								   expr->funcresulttype, exprTypmod(node),								   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);

⌨️ 快捷键说明

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