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 * AUTHORDATEMAJOR EVENT
@@ -52,6 +52,7 @@ static bool check_subplans_for_ungrouped_vars_walker(Node *node,
5252check_subplans_for_ungrouped_vars_context * context );
5353static int is_single_func (Node * node );
5454static Node * eval_const_expressions_mutator (Node * node ,void * context );
55+ static Expr * simplify_op_or_func (Expr * expr ,List * args );
5556
5657
5758Expr *
@@ -918,108 +919,15 @@ eval_const_expressions_mutator (Node *node, void *context)
918919{
919920case OP_EXPR :
920921case 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 ;
1023931case 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 */
11711076RelabelType * relabel = (RelabelType * )node ;
11721077Node * arg ;
@@ -1177,6 +1082,11 @@ eval_const_expressions_mutator (Node *node, void *context)
11771082Const * con = (Const * )arg ;
11781083
11791084con -> 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+ */
11801090return (Node * )con ;
11811091}
11821092else
@@ -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 *