Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d6429e5

Browse files
committed
Minor code rearrangement & doc improvement in eval_const_expressions().
1 parent cf6420d commit d6429e5

File tree

1 file changed

+129
-105
lines changed

1 file changed

+129
-105
lines changed

src/backend/optimizer/util/clauses.c

+129-105
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.61 2000/03/12 19:32:06 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.62 2000/03/19 18:20:38 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHOR DATE MAJOR EVENT
@@ -52,6 +52,7 @@ static bool check_subplans_for_ungrouped_vars_walker(Node *node,
5252
check_subplans_for_ungrouped_vars_context *context);
5353
static int is_single_func(Node *node);
5454
static Node *eval_const_expressions_mutator (Node *node, void *context);
55+
static Expr *simplify_op_or_func(Expr *expr, List *args);
5556

5657

5758
Expr *
@@ -918,108 +919,15 @@ eval_const_expressions_mutator (Node *node, void *context)
918919
{
919920
case OP_EXPR:
920921
case FUNC_EXPR:
921-
{
922-
/*
923-
* For an operator or function, we cannot simplify
924-
* unless all the inputs are constants. (XXX possible
925-
* future improvement: if the op/func is strict and
926-
* at least one input is NULL, we could simplify to NULL.
927-
* But we do not currently have any way to know if the
928-
* op/func is strict or not. For now, a NULL input is
929-
* treated the same as any other constant node.)
930-
*/
931-
bool args_all_const = true;
932-
List *arg;
933-
Oid funcid;
934-
Oid result_typeid;
935-
HeapTuple func_tuple;
936-
Form_pg_proc funcform;
937-
Type resultType;
938-
Datum const_val;
939-
bool const_is_null;
940-
bool isDone;
941-
942-
foreach(arg, args)
943-
{
944-
if (! IsA(lfirst(arg), Const))
945-
{
946-
args_all_const = false;
947-
break;
948-
}
949-
}
950-
if (! args_all_const)
951-
break;
952-
/*
953-
* Get the function procedure's OID and look to see
954-
* whether it is marked proiscachable.
955-
*/
956-
if (expr->opType == OP_EXPR)
957-
{
958-
Oper *oper = (Oper *) expr->oper;
959-
960-
replace_opid(oper);
961-
funcid = oper->opid;
962-
result_typeid = oper->opresulttype;
963-
}
964-
else
965-
{
966-
Func *func = (Func *) expr->oper;
967-
968-
funcid = func->funcid;
969-
result_typeid = func->functype;
970-
}
971-
/* Someday lsyscache.c might provide a function for this */
972-
func_tuple = SearchSysCacheTuple(PROCOID,
973-
ObjectIdGetDatum(funcid),
974-
0, 0, 0);
975-
if (!HeapTupleIsValid(func_tuple))
976-
elog(ERROR, "Function OID %u does not exist", funcid);
977-
funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
978-
if (! funcform->proiscachable)
979-
break;
980-
/*
981-
* Also check to make sure it doesn't return a set.
982-
*
983-
* XXX would it be better to take the result type from the
984-
* pg_proc tuple, rather than the Oper or Func node?
985-
*/
986-
if (funcform->proretset)
987-
break;
988-
/*
989-
* OK, looks like we can simplify this operator/function.
990-
* We use the executor's routine ExecEvalExpr() to avoid
991-
* duplication of code and ensure we get the same result
992-
* as the executor would get.
993-
*
994-
* Build a new Expr node containing the already-simplified
995-
* arguments. The only other setup needed here is the
996-
* replace_opid() that we already did for the OP_EXPR case.
997-
*/
998-
newexpr = makeNode(Expr);
999-
newexpr->typeOid = expr->typeOid;
1000-
newexpr->opType = expr->opType;
1001-
newexpr->oper = expr->oper;
1002-
newexpr->args = args;
1003-
/*
1004-
* It is OK to pass econtext = NULL because none of the
1005-
* ExecEvalExpr() code used in this situation will use
1006-
* econtext. That might seem fortuitous, but it's not
1007-
* so unreasonable --- a constant expression does not
1008-
* depend on context, by definition, n'est ce pas?
1009-
*/
1010-
const_val = ExecEvalExpr((Node *) newexpr, NULL,
1011-
&const_is_null, &isDone);
1012-
Assert(isDone); /* if this isn't set, we blew it... */
1013-
pfree(newexpr);
1014922
/*
1015-
* Make the constant result node.
923+
* Code for op/func case is pretty bulky, so split it out
924+
* as a separate function.
1016925
*/
1017-
resultType = typeidType(result_typeid);
1018-
return (Node *) makeConst(result_typeid, typeLen(resultType),
1019-
const_val, const_is_null,
1020-
typeByVal(resultType),
1021-
false, false);
1022-
}
926+
newexpr = simplify_op_or_func(expr, args);
927+
if (newexpr) /* successfully simplified it */
928+
return (Node *) newexpr;
929+
/* else fall out to build new Expr node with simplified args */
930+
break;
1023931
case OR_EXPR:
1024932
{
1025933
/*
@@ -1163,10 +1071,7 @@ eval_const_expressions_mutator (Node *node, void *context)
11631071
/*
11641072
* If we can simplify the input to a constant, then we don't need
11651073
* the RelabelType node anymore: just change the type field of
1166-
* the Const node. Otherwise keep the RelabelType node.
1167-
*
1168-
* XXX if relabel has a nondefault resulttypmod, do we need to
1169-
* keep it to show that? At present I don't think so.
1074+
* the Const node. Otherwise, copy the RelabelType node.
11701075
*/
11711076
RelabelType *relabel = (RelabelType *) node;
11721077
Node *arg;
@@ -1177,6 +1082,11 @@ eval_const_expressions_mutator (Node *node, void *context)
11771082
Const *con = (Const *) arg;
11781083

11791084
con->consttype = relabel->resulttype;
1085+
/*
1086+
* relabel's resulttypmod is discarded, which is OK for now;
1087+
* if the type actually needs a runtime length coercion then
1088+
* there should be a function call to do it just above this node.
1089+
*/
11801090
return (Node *) con;
11811091
}
11821092
else
@@ -1296,6 +1206,120 @@ eval_const_expressions_mutator (Node *node, void *context)
12961206
(void *) context);
12971207
}
12981208

1209+
/*
1210+
* Subroutine for eval_const_expressions: try to evaluate an op or func
1211+
*
1212+
* Inputs are the op or func Expr node, and the pre-simplified argument list.
1213+
* Returns a simplified expression if successful, or NULL if cannot
1214+
* simplify the op/func.
1215+
*
1216+
* XXX Possible future improvement: if the func is SQL-language, and its
1217+
* definition is simply "SELECT expression", we could parse and substitute
1218+
* the expression here. This would avoid much runtime overhead, and perhaps
1219+
* expose opportunities for constant-folding within the expression even if
1220+
* not all the func's input args are constants. It'd be appropriate to do
1221+
* here, and not in the parser, since we wouldn't want it to happen until
1222+
* after rule substitution/rewriting.
1223+
*/
1224+
static Expr *
1225+
simplify_op_or_func(Expr *expr, List *args)
1226+
{
1227+
List *arg;
1228+
Oid funcid;
1229+
Oid result_typeid;
1230+
HeapTuple func_tuple;
1231+
Form_pg_proc funcform;
1232+
Type resultType;
1233+
Expr *newexpr;
1234+
Datum const_val;
1235+
bool const_is_null;
1236+
bool isDone;
1237+
1238+
/*
1239+
* For an operator or function, we cannot simplify unless all the inputs
1240+
* are constants. (XXX possible future improvement: if the op/func is
1241+
* strict and at least one input is NULL, we could simplify to NULL.
1242+
* But we do not currently have any way to know if the op/func is strict
1243+
* or not. For now, a NULL input is treated the same as any other
1244+
* constant node.)
1245+
*/
1246+
foreach(arg, args)
1247+
{
1248+
if (! IsA(lfirst(arg), Const))
1249+
return NULL;
1250+
}
1251+
/*
1252+
* Get the function procedure's OID and look to see
1253+
* whether it is marked proiscachable.
1254+
*/
1255+
if (expr->opType == OP_EXPR)
1256+
{
1257+
Oper *oper = (Oper *) expr->oper;
1258+
1259+
replace_opid(oper); /* OK to scribble on input to this extent */
1260+
funcid = oper->opid;
1261+
result_typeid = oper->opresulttype;
1262+
}
1263+
else
1264+
{
1265+
Func *func = (Func *) expr->oper;
1266+
1267+
funcid = func->funcid;
1268+
result_typeid = func->functype;
1269+
}
1270+
/* Someday lsyscache.c might provide a function for this */
1271+
func_tuple = SearchSysCacheTuple(PROCOID,
1272+
ObjectIdGetDatum(funcid),
1273+
0, 0, 0);
1274+
if (!HeapTupleIsValid(func_tuple))
1275+
elog(ERROR, "Function OID %u does not exist", funcid);
1276+
funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
1277+
if (! funcform->proiscachable)
1278+
return NULL;
1279+
/*
1280+
* Also check to make sure it doesn't return a set.
1281+
*/
1282+
if (funcform->proretset)
1283+
return NULL;
1284+
/*
1285+
* OK, looks like we can simplify this operator/function.
1286+
*
1287+
* We use the executor's routine ExecEvalExpr() to avoid duplication of
1288+
* code and ensure we get the same result as the executor would get.
1289+
*
1290+
* Build a new Expr node containing the already-simplified arguments.
1291+
* The only other setup needed here is the replace_opid() that we already
1292+
* did for the OP_EXPR case.
1293+
*/
1294+
newexpr = makeNode(Expr);
1295+
newexpr->typeOid = expr->typeOid;
1296+
newexpr->opType = expr->opType;
1297+
newexpr->oper = expr->oper;
1298+
newexpr->args = args;
1299+
/*
1300+
* It is OK to pass econtext = NULL because none of the ExecEvalExpr()
1301+
* code used in this situation will use econtext. That might seem
1302+
* fortuitous, but it's not so unreasonable --- a constant expression does
1303+
* not depend on context, by definition, n'est ce pas?
1304+
*/
1305+
const_val = ExecEvalExpr((Node *) newexpr, NULL,
1306+
&const_is_null, &isDone);
1307+
Assert(isDone); /* if this isn't set, we blew it... */
1308+
pfree(newexpr);
1309+
/*
1310+
* Make the constant result node.
1311+
*
1312+
* XXX would it be better to take the result type from the
1313+
* pg_proc tuple, rather than the Oper or Func node?
1314+
*/
1315+
resultType = typeidType(result_typeid);
1316+
return (Expr *) makeConst(result_typeid, typeLen(resultType),
1317+
const_val, const_is_null,
1318+
typeByVal(resultType),
1319+
false, false);
1320+
}
1321+
1322+
12991323
/*
13001324
* Standard expression-tree walking support
13011325
*

0 commit comments

Comments
 (0)