mirror of
https://github.com/postgres/postgres.git
synced 2025-06-04 00:02:37 -04:00
Minor code rearrangement & doc improvement in eval_const_expressions().
This commit is contained in:
parent
cf6420dd94
commit
d6429e552d
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* 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);
|
check_subplans_for_ungrouped_vars_context *context);
|
||||||
static int is_single_func(Node *node);
|
static int is_single_func(Node *node);
|
||||||
static Node *eval_const_expressions_mutator (Node *node, void *context);
|
static Node *eval_const_expressions_mutator (Node *node, void *context);
|
||||||
|
static Expr *simplify_op_or_func(Expr *expr, List *args);
|
||||||
|
|
||||||
|
|
||||||
Expr *
|
Expr *
|
||||||
@ -918,108 +919,15 @@ eval_const_expressions_mutator (Node *node, void *context)
|
|||||||
{
|
{
|
||||||
case OP_EXPR:
|
case OP_EXPR:
|
||||||
case FUNC_EXPR:
|
case FUNC_EXPR:
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* For an operator or function, we cannot simplify
|
* Code for op/func case is pretty bulky, so split it out
|
||||||
* unless all the inputs are constants. (XXX possible
|
* as a separate function.
|
||||||
* 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;
|
newexpr = simplify_op_or_func(expr, args);
|
||||||
List *arg;
|
if (newexpr) /* successfully simplified it */
|
||||||
Oid funcid;
|
return (Node *) newexpr;
|
||||||
Oid result_typeid;
|
/* else fall out to build new Expr node with simplified args */
|
||||||
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;
|
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.
|
|
||||||
*/
|
|
||||||
resultType = typeidType(result_typeid);
|
|
||||||
return (Node *) makeConst(result_typeid, typeLen(resultType),
|
|
||||||
const_val, const_is_null,
|
|
||||||
typeByVal(resultType),
|
|
||||||
false, false);
|
|
||||||
}
|
|
||||||
case OR_EXPR:
|
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
|
* 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 RelabelType node anymore: just change the type field of
|
||||||
* the Const node. Otherwise keep the RelabelType node.
|
* the Const node. Otherwise, copy 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.
|
|
||||||
*/
|
*/
|
||||||
RelabelType *relabel = (RelabelType *) node;
|
RelabelType *relabel = (RelabelType *) node;
|
||||||
Node *arg;
|
Node *arg;
|
||||||
@ -1177,6 +1082,11 @@ eval_const_expressions_mutator (Node *node, void *context)
|
|||||||
Const *con = (Const *) arg;
|
Const *con = (Const *) arg;
|
||||||
|
|
||||||
con->consttype = relabel->resulttype;
|
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;
|
return (Node *) con;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1296,6 +1206,120 @@ eval_const_expressions_mutator (Node *node, void *context)
|
|||||||
(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
|
* Standard expression-tree walking support
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user