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 + -
显示快捷键?