📄 clauses.c
字号:
* The expression cannot be simplified any further, so build and * return a replacement OpExpr node using the possibly-simplified * arguments. */ newexpr = makeNode(OpExpr); newexpr->opno = expr->opno; newexpr->opfuncid = expr->opfuncid; newexpr->opresulttype = expr->opresulttype; newexpr->opretset = expr->opretset; newexpr->args = args; return (Node *) newexpr; } if (IsA(node, DistinctExpr)) { DistinctExpr *expr = (DistinctExpr *) node; List *args; ListCell *arg; bool has_null_input = false; bool all_null_input = true; bool has_nonconst_input = false; Expr *simple; DistinctExpr *newexpr; /* * Reduce constants in the DistinctExpr'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); /* * We must do our own check for NULLs because DistinctExpr has * different results for NULL input than the underlying operator does. */ foreach(arg, args) { if (IsA(lfirst(arg), Const)) { has_null_input |= ((Const *) lfirst(arg))->constisnull; all_null_input &= ((Const *) lfirst(arg))->constisnull; } else has_nonconst_input = true; } /* all constants? then can optimize this out */ if (!has_nonconst_input) { /* all nulls? then not distinct */ if (all_null_input) return makeBoolConst(false, false); /* one null? then distinct */ if (has_null_input) return makeBoolConst(true, false); /* otherwise try to evaluate the '=' operator */ /* (NOT okay to try to inline it, though!) */ /* * Need to get OID of underlying function. Okay to scribble on * input to this extent. */ set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */ /* * Code for op/func reduction is pretty bulky, so split it out as * a separate function. */ simple = simplify_function(expr->opfuncid, expr->opresulttype, args, false, context); if (simple) /* successfully simplified it */ { /* * Since the underlying operator is "=", must negate its * result */ Const *csimple = (Const *) simple; Assert(IsA(csimple, Const)); csimple->constvalue = BoolGetDatum(!DatumGetBool(csimple->constvalue)); return (Node *) csimple; } } /* * The expression cannot be simplified any further, so build and * return a replacement DistinctExpr node using the * possibly-simplified arguments. */ newexpr = makeNode(DistinctExpr); newexpr->opno = expr->opno; newexpr->opfuncid = expr->opfuncid; newexpr->opresulttype = expr->opresulttype; newexpr->opretset = expr->opretset; newexpr->args = args; return (Node *) newexpr; } if (IsA(node, BoolExpr)) { BoolExpr *expr = (BoolExpr *) node; switch (expr->boolop) { case OR_EXPR: { List *newargs; bool haveNull = false; bool forceTrue = false; newargs = simplify_or_arguments(expr->args, context, &haveNull, &forceTrue); if (forceTrue) return makeBoolConst(true, false); if (haveNull) newargs = lappend(newargs, makeBoolConst(false, true)); /* If all the inputs are FALSE, result is FALSE */ if (newargs == NIL) return makeBoolConst(false, false); /* If only one nonconst-or-NULL input, it's the result */ if (list_length(newargs) == 1) return (Node *) linitial(newargs); /* Else we still need an OR node */ return (Node *) make_orclause(newargs); } case AND_EXPR: { List *newargs; bool haveNull = false; bool forceFalse = false; newargs = simplify_and_arguments(expr->args, context, &haveNull, &forceFalse); if (forceFalse) return makeBoolConst(false, false); if (haveNull) newargs = lappend(newargs, makeBoolConst(false, true)); /* If all the inputs are TRUE, result is TRUE */ if (newargs == NIL) return makeBoolConst(true, false); /* If only one nonconst-or-NULL input, it's the result */ if (list_length(newargs) == 1) return (Node *) linitial(newargs); /* Else we still need an AND node */ return (Node *) make_andclause(newargs); } case NOT_EXPR: { Node *arg; Assert(list_length(expr->args) == 1); arg = eval_const_expressions_mutator(linitial(expr->args), context); if (IsA(arg, Const)) { Const *const_input = (Const *) arg; /* NOT NULL => NULL */ if (const_input->constisnull) return makeBoolConst(false, true); /* otherwise pretty easy */ return makeBoolConst(!DatumGetBool(const_input->constvalue), false); } else if (not_clause(arg)) { /* Cancel NOT/NOT */ return (Node *) get_notclausearg((Expr *) arg); } /* Else we still need a NOT node */ return (Node *) make_notclause((Expr *) arg); } default: elog(ERROR, "unrecognized boolop: %d", (int) expr->boolop); break; } } if (IsA(node, SubPlan)) { /* * Return a SubPlan unchanged --- too late to do anything with it. * * XXX should we ereport() here instead? Probably this routine should * never be invoked after SubPlan creation. */ return node; } if (IsA(node, RelabelType)) { /* * If we can simplify the input to a constant, then we don't need the * RelabelType node anymore: just change the type field of the Const * node. Otherwise, must copy the RelabelType node. */ RelabelType *relabel = (RelabelType *) node; Node *arg; arg = eval_const_expressions_mutator((Node *) relabel->arg, context); /* * If we find stacked RelabelTypes (eg, from foo :: int :: oid) we can * discard all but the top one. */ while (arg && IsA(arg, RelabelType)) arg = (Node *) ((RelabelType *) arg)->arg; if (arg && IsA(arg, Const)) { Const *con = (Const *) arg; con->consttype = relabel->resulttype; /* * relabel's resulttypmod is discarded, which is OK for now; if * the type actually needs a runtime length coercion then there * should be a function call to do it just above this node. */ return (Node *) con; } else { RelabelType *newrelabel = makeNode(RelabelType); newrelabel->arg = (Expr *) arg; newrelabel->resulttype = relabel->resulttype; newrelabel->resulttypmod = relabel->resulttypmod; return (Node *) newrelabel; } } if (IsA(node, CaseExpr)) { /*---------- * CASE expressions can be simplified if there are constant * condition clauses: * FALSE (or NULL): drop the alternative * TRUE: drop all remaining alternatives * If the first non-FALSE alternative is a constant TRUE, we can * simplify the entire CASE to that alternative's expression. * If there are no non-FALSE alternatives, we simplify the entire * CASE to the default result (ELSE result). * * If we have a simple-form CASE with constant test expression, * we substitute the constant value for contained CaseTestExpr * placeholder nodes, so that we have the opportunity to reduce * constant test conditions. For example this allows * CASE 0 WHEN 0 THEN 1 ELSE 1/0 END * to reduce to 1 rather than drawing a divide-by-0 error. *---------- */ CaseExpr *caseexpr = (CaseExpr *) node; CaseExpr *newcase; Node *save_case_val; Node *newarg; List *newargs; bool const_true_cond; Node *defresult = NULL; ListCell *arg; /* Simplify the test expression, if any */ newarg = eval_const_expressions_mutator((Node *) caseexpr->arg, context); /* Set up for contained CaseTestExpr nodes */ save_case_val = context->case_val; if (newarg && IsA(newarg, Const)) context->case_val = newarg; else context->case_val = NULL; /* Simplify the WHEN clauses */ newargs = NIL; const_true_cond = false; foreach(arg, caseexpr->args) { CaseWhen *oldcasewhen = (CaseWhen *) lfirst(arg); Node *casecond; Node *caseresult; Assert(IsA(oldcasewhen, CaseWhen)); /* Simplify this alternative's test condition */ casecond = eval_const_expressions_mutator((Node *) oldcasewhen->expr, context); /* * If the test condition is constant FALSE (or NULL), then drop * this WHEN clause completely, without processing the result. */ if (casecond && IsA(casecond, Const)) { Const *const_input = (Const *) casecond; if (const_input->constisnull || !DatumGetBool(const_input->constvalue)) continue; /* drop alternative with FALSE condition */ /* Else it's constant TRUE */ const_true_cond = true; } /* Simplify this alternative's result value */ caseresult = eval_const_expressions_mutator((Node *) oldcasewhen->result, context); /* If non-constant test condition, emit a new WHEN node */ if (!const_true_cond) { CaseWhen *newcasewhen = makeNode(CaseWhen); newcasewhen->expr = (Expr *) casecond; newcasewhen->result = (Expr *) caseresult; newargs = lappend(newargs, newcasewhen); continue; } /* * Found a TRUE condition, so none of the remaining alternatives * can be reached. We treat the result as the default result. */ defresult = caseresult; break; } /* Simplify the default result, unless we replaced it above */ if (!const_true_cond) defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult, context); context->case_val = save_case_val; /* If no non-FALSE alternatives, CASE reduces to the default result */ if (newargs == NIL) return defresult; /* Otherwise we need a new CASE node */ newcase = makeNode(CaseExpr); newcase->casetype = caseexpr->casetype; newcase->arg = (Expr *) newarg; newcase->args = newargs; newcase->defresult = (Expr *) defresult; return (Node *) newcase; } if (IsA(node, CaseTestExpr)) { /* * If we know a constant test value for the current CASE construct, * substitute it for the placeholder. Else just return the * placeholder as-is. */ if (context->case_val) return copyObject(context->case_val); else return copyObject(node); } if (IsA(node, ArrayExpr)) { ArrayExpr *arrayexpr = (ArrayExpr *) node; ArrayExpr *newarray; bool all_const = true; List *newelems; ListCell *element; newelems = NIL; foreach(element, arrayexpr->elements) { Node *e; e = eval_const_expressions_mutator((Node *) lfirst(element), context); if (!IsA(e, Const)) all_const = false; newelems = lappend(newelems, e); } newarray = makeNode(ArrayExpr); newarray->array_typeid = arrayexpr->array_typeid; newarray->element_typeid = arrayexpr->element_typeid; newarray->elements = newelems; newarray->multidims = arrayexpr->multidims; if (all_const) return (Node *) evaluate_expr((Expr *) newarray, newarray->array_typeid); return (Node *) newarray; } if (IsA(node, CoalesceExpr)) { CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; CoalesceExpr *newcoalesce; List *newargs; ListCell *arg; newargs = NIL; foreach(arg, coalesceexpr->args) { Node *e; e = eval_const_expressions_mutator((Node *) lfirst(arg), context); /* * We can remove null constants from the list. For a non-null * constant, if it has not been preceded by any other * non-null-constant expressions then that is the result. */ if (IsA(e, Const)) { if (((Const *) e)->constisnull) continue; /* drop null constant */ if (newargs == NIL) return e; /* first expr */ } newargs = lappend(newargs, e); } /* If all the arguments were constant null, the result is just null */ if (newargs == NIL) return (Node *) makeNullConst(coalesceexpr->coalescetype); newcoalesce = makeNode(CoalesceExpr); newcoalesce->coalescetype = coalesceexpr->coalescetype; newcoalesce->args = newargs; return (Node *) newcoalesce; } if (IsA(node, FieldSelect)) { /* * We can optimize field selection from a whole-row Var into a simple * Var. (This case won't be generated directly by the parser, because * ParseComplexProjection short-circuits it. But it can arise while * simplifying functions.) Also, we can optimize field selection from * a RowExpr construct. * * We must however check that the declared type of the field is still * the same as when the FieldSelect was created --- this can change if * someone did ALTER COLUMN TYPE on the rowtype. */ FieldSelect *fselect = (FieldSelect *) node; FieldSelect *newfselect; Node *arg; arg = eval_const_expressions_mutator((Node *) fselect->arg, context); if (arg && IsA(arg, Var) && ((Var *) arg)->varattno == InvalidAttrNumber) { if (rowtype_field_matches(((Var *) arg)->vartype, fselect->fieldnum,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -