clauses.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,256 行 · 第 1/5 页
C
2,256 行
} /* Else we still need a NOT node */ return (Node *) make_notclause(lfirst(args)); 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, active_fns); /* * 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). *---------- */ CaseExpr *caseexpr = (CaseExpr *) node; CaseExpr *newcase; FastList newargs; Node *defresult; Const *const_input; List *arg; FastListInit(&newargs); foreach(arg, caseexpr->args) { /* Simplify this alternative's condition and result */ CaseWhen *casewhen = (CaseWhen *) expression_tree_mutator((Node *) lfirst(arg), eval_const_expressions_mutator, (void *) active_fns); Assert(IsA(casewhen, CaseWhen)); if (casewhen->expr == NULL || !IsA(casewhen->expr, Const)) { FastAppend(&newargs, casewhen); continue; } const_input = (Const *) casewhen->expr; if (const_input->constisnull || !DatumGetBool(const_input->constvalue)) continue; /* drop alternative with FALSE condition */ /* * Found a TRUE condition. If it's the first (un-dropped) * alternative, the CASE reduces to just this alternative. */ if (FastListValue(&newargs) == NIL) return (Node *) casewhen->result; /* * Otherwise, add it to the list, and drop all the rest. */ FastAppend(&newargs, casewhen); break; } /* Simplify the default result */ defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult, active_fns); /* * If no non-FALSE alternatives, CASE reduces to the default * result */ if (FastListValue(&newargs) == NIL) return defresult; /* Otherwise we need a new CASE node */ newcase = makeNode(CaseExpr); newcase->casetype = caseexpr->casetype; newcase->arg = NULL; newcase->args = FastListValue(&newargs); newcase->defresult = (Expr *) defresult; return (Node *) newcase; } if (IsA(node, ArrayExpr)) { ArrayExpr *arrayexpr = (ArrayExpr *) node; ArrayExpr *newarray; bool all_const = true; FastList newelems; List *element; FastListInit(&newelems); foreach(element, arrayexpr->elements) { Node *e; e = eval_const_expressions_mutator((Node *) lfirst(element), active_fns); if (!IsA(e, Const)) all_const = false; FastAppend(&newelems, e); } newarray = makeNode(ArrayExpr); newarray->array_typeid = arrayexpr->array_typeid; newarray->element_typeid = arrayexpr->element_typeid; newarray->elements = FastListValue(&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; FastList newargs; List *arg; FastListInit(&newargs); foreach(arg, coalesceexpr->args) { Node *e; e = eval_const_expressions_mutator((Node *) lfirst(arg), active_fns); /* * 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 (FastListValue(&newargs) == NIL) return e; /* first expr */ } FastAppend(&newargs, e); } newcoalesce = makeNode(CoalesceExpr); newcoalesce->coalescetype = coalesceexpr->coalescetype; newcoalesce->args = FastListValue(&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.) If the argument * isn't a whole-row Var, just fall through to do generic * processing. */ FieldSelect *fselect = (FieldSelect *) node; Var *argvar = (Var *) fselect->arg; if (argvar && IsA(argvar, Var) && argvar->varattno == InvalidAttrNumber) { return (Node *) makeVar(argvar->varno, fselect->fieldnum, fselect->resulttype, fselect->resulttypmod, argvar->varlevelsup); } } /* * For any node type not handled above, we recurse using * expression_tree_mutator, which will copy the node unchanged but try * to simplify its arguments (if any) using this routine. For example: * we cannot eliminate an ArrayRef node, but we might be able to * simplify constant expressions in its subscripts. */ return expression_tree_mutator(node, eval_const_expressions_mutator, (void *) active_fns);}/* * Subroutine for eval_const_expressions: try to simplify a function call * (which might originally have been an operator; we don't care) * * Inputs are the function OID, actual result type OID (which is needed for * polymorphic functions), and the pre-simplified argument list; * also a list of already-active inline function expansions. * * Returns a simplified expression if successful, or NULL if cannot * simplify the function call. */static Expr *simplify_function(Oid funcid, Oid result_type, List *args, bool allow_inline, List *active_fns){ HeapTuple func_tuple; Expr *newexpr; /* * We have two strategies for simplification: either execute the * function to deliver a constant result, or expand in-line the body * of the function definition (which only works for simple * SQL-language functions, but that is a common case). In either case * we need access to the function's pg_proc tuple, so fetch it just * once to use in both attempts. */ func_tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); if (!HeapTupleIsValid(func_tuple)) elog(ERROR, "cache lookup failed for function %u", funcid); newexpr = evaluate_function(funcid, result_type, args, func_tuple); if (!newexpr && allow_inline) newexpr = inline_function(funcid, result_type, args, func_tuple, active_fns); ReleaseSysCache(func_tuple); return newexpr;}/* * evaluate_function: try to pre-evaluate a function call * * We can do this if the function is strict and has any constant-null inputs * (just return a null constant), or if the function is immutable and has all * constant inputs (call it and return the result as a Const node). * * Returns a simplified expression if successful, or NULL if cannot * simplify the function. */static Expr *evaluate_function(Oid funcid, Oid result_type, List *args, HeapTuple func_tuple){ Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); bool has_nonconst_input = false; bool has_null_input = false; List *arg; FuncExpr *newexpr; char result_typtype; /* * Can't simplify if it returns a set. */ if (funcform->proretset) return NULL; /* * Check for constant inputs and especially constant-NULL inputs. */ foreach(arg, args) { if (IsA(lfirst(arg), Const)) has_null_input |= ((Const *) lfirst(arg))->constisnull; else has_nonconst_input = true; } /* * If the function is strict and has a constant-NULL input, it will * never be called at all, so we can replace the call by a NULL * constant, even if there are other inputs that aren't constant, and * even if the function is not otherwise immutable. */ if (funcform->proisstrict && has_null_input) return (Expr *) makeNullConst(result_type); /* * Otherwise, can simplify only if the function is immutable and all * inputs are constants. (For a non-strict function, constant NULL * inputs are treated the same as constant non-NULL inputs.) */ if (funcform->provolatile != PROVOLATILE_IMMUTABLE || has_nonconst_input) return NULL; /* * Can't simplify functions returning composite types (mainly because * datumCopy() doesn't cope; FIXME someday when we have a saner * representation for whole-tuple results). */ result_typtype = get_typtype(funcform->prorettype); if (result_typtype == 'c') return NULL; /* * OK, looks like we can simplify this operator/function. * * Build a new FuncExpr node containing the already-simplified arguments. */ newexpr = makeNode(FuncExpr); newexpr->funcid = funcid; newexpr->funcresulttype = result_type; newexpr->funcretset = false; newexpr->funcformat = COERCE_EXPLICIT_CALL; /* doesn't matter */ newexpr->args = args; return evaluate_expr((Expr *) newexpr, result_type);}/* * inline_function: try to expand a function call inline * * If the function is a sufficiently simple SQL-language function * (just "SELECT expression"), then we can inline it and avoid the rather * high per-call overhead of SQL functions. Furthermore, this can expose * opportunities for constant-folding within the function expression. * * We have to beware of some special cases however. A directly or * indirectly recursive function would cause us to recurse forever, * so we keep track of which functions we are already expanding and * do not re-expand them. Also, if a parameter is used more than once * in the SQL-function body, we require it not to contain any volatile * functions (volatiles might deliver inconsistent answers) nor to be * unreasonably expensive to evaluate. The expensiveness check not only * prevents us from doing multiple evaluations of an expensive parameter * at runtime, but is a safety value to limit growth of an expression due * to repeated inlining. * * We must also beware of changing the volatility or strictness status of * functions by inlining them. * * Returns a simplified expression if successful, or NULL if cannot * simplify the function. */static Expr *inline_function(Oid funcid, Oid result_type, List *args, HeapTuple func_tuple, List *active_fns){ Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); char result_typtype; bool polymorphic = false; Oid argtypes[FUNC_MAX_ARGS]; char *src; Datum tmp; bool isNull; MemoryContext oldcxt; MemoryContext mycxt; ErrorContextCallback sqlerrcontext; List *raw_parsetree_list; List *querytree_list; Query *querytree; Node *newexpr; int *usecounts; List *arg; int i; /* * Forget it if the function is not SQL-language or has other * showstopper properties. (The nargs check is just paranoia.) */ if (funcform->prolang != SQLlanguageId || funcform->prosecdef || funcform->proretset || funcform->pronargs != length(args)) return NULL; /* * Forget it if declared return type is not base, domain, or * polymorphic */ result_typtype = get_typtype(funcform->prorettype); if (result_typtype != 'b' && result_typtype != 'd') { if (funcform->prorettype == ANYARRAYOID || funcform->prorettype == ANYELEMENTOID) polymorphic = true; else return NULL; } /* Check for recursive function, and give up trying to expand if so */ if (oidMember(funcid, active_fns)) return NULL; /* Check permission to call function (fail later, if not) */ if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK) return NULL; /* Check for polymorphic arguments, and substitute actual arg types */ memcpy(argtypes, funcform->proargtypes, FUNC_MAX_ARGS * sizeof(Oid)); for (i = 0; i < funcform->pronargs; i++) { if (argtypes[i] == ANYARRAYOID || argtypes[i] == ANYELEMENTOID) { polymorphic = true; argtypes[i] = exprType((Node *) nth(i, args)); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?