clauses.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,256 行 · 第 1/5 页
C
2,256 行
} /* It's a simple DISTINCT */ return false;}/***************************************************************************** * * * General clause-manipulating routines * * * *****************************************************************************//* * clause_get_relids_vars * Retrieves distinct relids and vars appearing within a clause. * * '*relids' is set to the set of all distinct "varno"s appearing * in Vars within the clause. * '*vars' is set to a list of all distinct Vars appearing within the clause. * Var nodes are considered distinct if they have different varno * or varattno values. If there are several occurrences of the same * varno/varattno, you get a randomly chosen one... * * Note that upper-level vars are ignored, since they normally will * become Params with respect to this query level. */voidclause_get_relids_vars(Node *clause, Relids *relids, List **vars){ List *clvars = pull_var_clause(clause, false); Relids varnos = NULL; List *var_list = NIL; List *i; foreach(i, clvars) { Var *var = (Var *) lfirst(i); List *vi; varnos = bms_add_member(varnos, var->varno); foreach(vi, var_list) { Var *in_list = (Var *) lfirst(vi); if (in_list->varno == var->varno && in_list->varattno == var->varattno) break; } if (vi == NIL) var_list = lcons(var, var_list); } freeList(clvars); *relids = varnos; *vars = var_list;}/* * 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) || 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 = lfirst(clause->args); lfirst(clause->args) = lsecond(clause->args); lsecond(clause->args) = temp;}/*-------------------- * 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. *-------------------- */Node *eval_const_expressions(Node *node){ /* * The context for the mutator is a list of SQL functions being * recursively simplified, so we start with an empty list. */ return eval_const_expressions_mutator(node, NIL);}static Node *eval_const_expressions_mutator(Node *node, List *active_fns){ if (node == NULL) return NULL; 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 *) active_fns); /* * 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, active_fns); 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 *) active_fns); /* * 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, active_fns); 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; List *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 *) active_fns); /* * 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, active_fns); 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; List *args; Const *const_input; /* * Reduce constants in the BoolExpr'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 *) active_fns); switch (expr->boolop) { case OR_EXPR: { /*---------- * OR arguments are handled as follows: * non constant: keep * FALSE: drop (does not affect result) * TRUE: force result to TRUE * NULL: keep only one * We keep one NULL input because ExecEvalOr returns NULL * when no input is TRUE and at least one is NULL. *---------- */ FastList newargs; List *arg; bool haveNull = false; bool forceTrue = false; FastListInit(&newargs); foreach(arg, args) { if (!IsA(lfirst(arg), Const)) { FastAppend(&newargs, lfirst(arg)); continue; } const_input = (Const *) lfirst(arg); if (const_input->constisnull) haveNull = true; else if (DatumGetBool(const_input->constvalue)) forceTrue = true; /* otherwise, we can drop the constant-false input */ } /* * We could return TRUE before falling out of the * loop, but this coding method will be easier to * adapt if we ever add a notion of non-removable * functions. We'd need to check all the inputs for * non-removability. */ if (forceTrue) return MAKEBOOLCONST(true, false); if (haveNull) FastAppend(&newargs, MAKEBOOLCONST(false, true)); /* If all the inputs are FALSE, result is FALSE */ if (FastListValue(&newargs) == NIL) return MAKEBOOLCONST(false, false); /* If only one nonconst-or-NULL input, it's the result */ if (lnext(FastListValue(&newargs)) == NIL) return (Node *) lfirst(FastListValue(&newargs)); /* Else we still need an OR node */ return (Node *) make_orclause(FastListValue(&newargs)); } case AND_EXPR: { /*---------- * AND arguments are handled as follows: * non constant: keep * TRUE: drop (does not affect result) * FALSE: force result to FALSE * NULL: keep only one * We keep one NULL input because ExecEvalAnd returns NULL * when no input is FALSE and at least one is NULL. *---------- */ FastList newargs; List *arg; bool haveNull = false; bool forceFalse = false; FastListInit(&newargs); foreach(arg, args) { if (!IsA(lfirst(arg), Const)) { FastAppend(&newargs, lfirst(arg)); continue; } const_input = (Const *) lfirst(arg); if (const_input->constisnull) haveNull = true; else if (!DatumGetBool(const_input->constvalue)) forceFalse = true; /* otherwise, we can drop the constant-true input */ } /* * We could return FALSE before falling out of the * loop, but this coding method will be easier to * adapt if we ever add a notion of non-removable * functions. We'd need to check all the inputs for * non-removability. */ if (forceFalse) return MAKEBOOLCONST(false, false); if (haveNull) FastAppend(&newargs, MAKEBOOLCONST(false, true)); /* If all the inputs are TRUE, result is TRUE */ if (FastListValue(&newargs) == NIL) return MAKEBOOLCONST(true, false); /* If only one nonconst-or-NULL input, it's the result */ if (lnext(FastListValue(&newargs)) == NIL) return (Node *) lfirst(FastListValue(&newargs)); /* Else we still need an AND node */ return (Node *) make_andclause(FastListValue(&newargs)); } case NOT_EXPR: Assert(length(args) == 1); if (IsA(lfirst(args), Const)) { const_input = (Const *) lfirst(args); /* NOT NULL => NULL */ if (const_input->constisnull) return MAKEBOOLCONST(false, true); /* otherwise pretty easy */ return MAKEBOOLCONST(!DatumGetBool(const_input->constvalue), false);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?