clauses.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,294 行 · 第 1/5 页
C
2,294 行
/* * 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, -1, 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; } /* * 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, -1, 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; con->consttypmod = relabel->resulttypmod; return (Node *) con; } else { RelabelType *newrelabel = makeNode(RelabelType); newrelabel->arg = (Expr *) arg; newrelabel->resulttype = relabel->resulttype; newrelabel->resulttypmod = relabel->resulttypmod; newrelabel->relabelformat = relabel->relabelformat; return (Node *) newrelabel; } } if (IsA(node, CoerceViaIO)) { CoerceViaIO *expr = (CoerceViaIO *) node; Expr *arg; Oid outfunc; bool outtypisvarlena; Oid infunc; Oid intypioparam; Expr *simple; CoerceViaIO *newexpr; /* * Reduce constants in the CoerceViaIO's argument. */ arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg, context); /* * CoerceViaIO represents calling the source type's output function * then the result type's input function. So, try to simplify it * as though it were a stack of two such function calls. First we * need to know what the functions are. */ getTypeOutputInfo(exprType((Node *) arg), &outfunc, &outtypisvarlena); getTypeInputInfo(expr->resulttype, &infunc, &intypioparam); simple = simplify_function(outfunc, CSTRINGOID, -1, list_make1(arg), true, context); if (simple) /* successfully simplified output fn */ { /* * Input functions may want 1 to 3 arguments. We always supply * all three, trusting that nothing downstream will complain. */ List *args; args = list_make3(simple, makeConst(OIDOID, -1, sizeof(Oid), ObjectIdGetDatum(intypioparam), false, true), makeConst(INT4OID, -1, sizeof(int32), Int32GetDatum(-1), false, true)); simple = simplify_function(infunc, expr->resulttype, -1, args, true, context); if (simple) /* successfully simplified input fn */ return (Node *) simple; } /* * The expression cannot be simplified any further, so build and * return a replacement CoerceViaIO node using the possibly-simplified * argument. */ newexpr = makeNode(CoerceViaIO); newexpr->arg = arg; newexpr->resulttype = expr->resulttype; newexpr->coerceformat = expr->coerceformat; return (Node *) newexpr; } if (IsA(node, ArrayCoerceExpr)) { ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; Expr *arg; ArrayCoerceExpr *newexpr; /* * Reduce constants in the ArrayCoerceExpr's argument, then build * a new ArrayCoerceExpr. */ arg = (Expr *) eval_const_expressions_mutator((Node *) expr->arg, context); newexpr = makeNode(ArrayCoerceExpr); newexpr->arg = arg; newexpr->elemfuncid = expr->elemfuncid; newexpr->resulttype = expr->resulttype; newexpr->resulttypmod = expr->resulttypmod; newexpr->isExplicit = expr->isExplicit; newexpr->coerceformat = expr->coerceformat; /* * If constant argument and it's a binary-coercible or immutable * conversion, we can simplify it to a constant. */ if (arg && IsA(arg, Const) && (!OidIsValid(newexpr->elemfuncid) || func_volatile(newexpr->elemfuncid) == PROVOLATILE_IMMUTABLE)) return (Node *) evaluate_expr((Expr *) newexpr, newexpr->resulttype, newexpr->resulttypmod); /* Else we must return the partially-simplified node */ return (Node *) newexpr; } 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 (
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?