📄 clauses.c
字号:
* * 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 + -