From d6429e552db105d31efd576733b70b68ed6ae706 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 19 Mar 2000 18:20:38 +0000 Subject: [PATCH] Minor code rearrangement & doc improvement in eval_const_expressions(). --- src/backend/optimizer/util/clauses.c | 234 +++++++++++++++------------ 1 file changed, 129 insertions(+), 105 deletions(-) diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 3ec5118ff7..72f9b1117b 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.61 2000/03/12 19:32:06 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.62 2000/03/19 18:20:38 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -52,6 +52,7 @@ static bool check_subplans_for_ungrouped_vars_walker(Node *node, check_subplans_for_ungrouped_vars_context *context); static int is_single_func(Node *node); static Node *eval_const_expressions_mutator (Node *node, void *context); +static Expr *simplify_op_or_func(Expr *expr, List *args); Expr * @@ -918,108 +919,15 @@ eval_const_expressions_mutator (Node *node, void *context) { case OP_EXPR: case FUNC_EXPR: - { - /* - * For an operator or function, we cannot simplify - * unless all the inputs are constants. (XXX possible - * future improvement: if the op/func is strict and - * at least one input is NULL, we could simplify to NULL. - * But we do not currently have any way to know if the - * op/func is strict or not. For now, a NULL input is - * treated the same as any other constant node.) - */ - bool args_all_const = true; - List *arg; - Oid funcid; - Oid result_typeid; - HeapTuple func_tuple; - Form_pg_proc funcform; - Type resultType; - Datum const_val; - bool const_is_null; - bool isDone; - - foreach(arg, args) - { - if (! IsA(lfirst(arg), Const)) - { - args_all_const = false; - break; - } - } - if (! args_all_const) - break; - /* - * Get the function procedure's OID and look to see - * whether it is marked proiscachable. - */ - if (expr->opType == OP_EXPR) - { - Oper *oper = (Oper *) expr->oper; - - replace_opid(oper); - funcid = oper->opid; - result_typeid = oper->opresulttype; - } - else - { - Func *func = (Func *) expr->oper; - - funcid = func->funcid; - result_typeid = func->functype; - } - /* Someday lsyscache.c might provide a function for this */ - func_tuple = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(funcid), - 0, 0, 0); - if (!HeapTupleIsValid(func_tuple)) - elog(ERROR, "Function OID %u does not exist", funcid); - funcform = (Form_pg_proc) GETSTRUCT(func_tuple); - if (! funcform->proiscachable) - break; - /* - * Also check to make sure it doesn't return a set. - * - * XXX would it be better to take the result type from the - * pg_proc tuple, rather than the Oper or Func node? - */ - if (funcform->proretset) - break; - /* - * OK, looks like we can simplify this operator/function. - * We use the executor's routine ExecEvalExpr() to avoid - * duplication of code and ensure we get the same result - * as the executor would get. - * - * Build a new Expr node containing the already-simplified - * arguments. The only other setup needed here is the - * replace_opid() that we already did for the OP_EXPR case. - */ - newexpr = makeNode(Expr); - newexpr->typeOid = expr->typeOid; - newexpr->opType = expr->opType; - newexpr->oper = expr->oper; - newexpr->args = args; - /* - * It is OK to pass econtext = NULL because none of the - * ExecEvalExpr() code used in this situation will use - * econtext. That might seem fortuitous, but it's not - * so unreasonable --- a constant expression does not - * depend on context, by definition, n'est ce pas? - */ - const_val = ExecEvalExpr((Node *) newexpr, NULL, - &const_is_null, &isDone); - Assert(isDone); /* if this isn't set, we blew it... */ - pfree(newexpr); /* - * Make the constant result node. + * Code for op/func case is pretty bulky, so split it out + * as a separate function. */ - resultType = typeidType(result_typeid); - return (Node *) makeConst(result_typeid, typeLen(resultType), - const_val, const_is_null, - typeByVal(resultType), - false, false); - } + newexpr = simplify_op_or_func(expr, args); + if (newexpr) /* successfully simplified it */ + return (Node *) newexpr; + /* else fall out to build new Expr node with simplified args */ + break; case OR_EXPR: { /* @@ -1163,10 +1071,7 @@ eval_const_expressions_mutator (Node *node, void *context) /* * 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 keep the RelabelType node. - * - * XXX if relabel has a nondefault resulttypmod, do we need to - * keep it to show that? At present I don't think so. + * the Const node. Otherwise, copy the RelabelType node. */ RelabelType *relabel = (RelabelType *) node; Node *arg; @@ -1177,6 +1082,11 @@ eval_const_expressions_mutator (Node *node, void *context) 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 @@ -1296,6 +1206,120 @@ eval_const_expressions_mutator (Node *node, void *context) (void *) context); } +/* + * Subroutine for eval_const_expressions: try to evaluate an op or func + * + * Inputs are the op or func Expr node, and the pre-simplified argument list. + * Returns a simplified expression if successful, or NULL if cannot + * simplify the op/func. + * + * XXX Possible future improvement: if the func is SQL-language, and its + * definition is simply "SELECT expression", we could parse and substitute + * the expression here. This would avoid much runtime overhead, and perhaps + * expose opportunities for constant-folding within the expression even if + * not all the func's input args are constants. It'd be appropriate to do + * here, and not in the parser, since we wouldn't want it to happen until + * after rule substitution/rewriting. + */ +static Expr * +simplify_op_or_func(Expr *expr, List *args) +{ + List *arg; + Oid funcid; + Oid result_typeid; + HeapTuple func_tuple; + Form_pg_proc funcform; + Type resultType; + Expr *newexpr; + Datum const_val; + bool const_is_null; + bool isDone; + + /* + * For an operator or function, we cannot simplify unless all the inputs + * are constants. (XXX possible future improvement: if the op/func is + * strict and at least one input is NULL, we could simplify to NULL. + * But we do not currently have any way to know if the op/func is strict + * or not. For now, a NULL input is treated the same as any other + * constant node.) + */ + foreach(arg, args) + { + if (! IsA(lfirst(arg), Const)) + return NULL; + } + /* + * Get the function procedure's OID and look to see + * whether it is marked proiscachable. + */ + if (expr->opType == OP_EXPR) + { + Oper *oper = (Oper *) expr->oper; + + replace_opid(oper); /* OK to scribble on input to this extent */ + funcid = oper->opid; + result_typeid = oper->opresulttype; + } + else + { + Func *func = (Func *) expr->oper; + + funcid = func->funcid; + result_typeid = func->functype; + } + /* Someday lsyscache.c might provide a function for this */ + func_tuple = SearchSysCacheTuple(PROCOID, + ObjectIdGetDatum(funcid), + 0, 0, 0); + if (!HeapTupleIsValid(func_tuple)) + elog(ERROR, "Function OID %u does not exist", funcid); + funcform = (Form_pg_proc) GETSTRUCT(func_tuple); + if (! funcform->proiscachable) + return NULL; + /* + * Also check to make sure it doesn't return a set. + */ + if (funcform->proretset) + return NULL; + /* + * OK, looks like we can simplify this operator/function. + * + * We use the executor's routine ExecEvalExpr() to avoid duplication of + * code and ensure we get the same result as the executor would get. + * + * Build a new Expr node containing the already-simplified arguments. + * The only other setup needed here is the replace_opid() that we already + * did for the OP_EXPR case. + */ + newexpr = makeNode(Expr); + newexpr->typeOid = expr->typeOid; + newexpr->opType = expr->opType; + newexpr->oper = expr->oper; + newexpr->args = args; + /* + * It is OK to pass econtext = NULL because none of the ExecEvalExpr() + * code used in this situation will use econtext. That might seem + * fortuitous, but it's not so unreasonable --- a constant expression does + * not depend on context, by definition, n'est ce pas? + */ + const_val = ExecEvalExpr((Node *) newexpr, NULL, + &const_is_null, &isDone); + Assert(isDone); /* if this isn't set, we blew it... */ + pfree(newexpr); + /* + * Make the constant result node. + * + * XXX would it be better to take the result type from the + * pg_proc tuple, rather than the Oper or Func node? + */ + resultType = typeidType(result_typeid); + return (Expr *) makeConst(result_typeid, typeLen(resultType), + const_val, const_is_null, + typeByVal(resultType), + false, false); +} + + /* * Standard expression-tree walking support * -- 2.39.5