8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
* HISTORY
14
14
* AUTHOR DATE MAJOR EVENT
@@ -52,6 +52,7 @@ static bool check_subplans_for_ungrouped_vars_walker(Node *node,
52
52
check_subplans_for_ungrouped_vars_context * context );
53
53
static int is_single_func (Node * node );
54
54
static Node * eval_const_expressions_mutator (Node * node , void * context );
55
+ static Expr * simplify_op_or_func (Expr * expr , List * args );
55
56
56
57
57
58
Expr *
@@ -918,108 +919,15 @@ eval_const_expressions_mutator (Node *node, void *context)
918
919
{
919
920
case OP_EXPR :
920
921
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 );
1014
922
/*
1015
- * Make the constant result node.
923
+ * Code for op/func case is pretty bulky, so split it out
924
+ * as a separate function.
1016
925
*/
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 ;
1023
931
case OR_EXPR :
1024
932
{
1025
933
/*
@@ -1163,10 +1071,7 @@ eval_const_expressions_mutator (Node *node, void *context)
1163
1071
/*
1164
1072
* If we can simplify the input to a constant, then we don't need
1165
1073
* 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.
1170
1075
*/
1171
1076
RelabelType * relabel = (RelabelType * ) node ;
1172
1077
Node * arg ;
@@ -1177,6 +1082,11 @@ eval_const_expressions_mutator (Node *node, void *context)
1177
1082
Const * con = (Const * ) arg ;
1178
1083
1179
1084
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
+ */
1180
1090
return (Node * ) con ;
1181
1091
}
1182
1092
else
@@ -1296,6 +1206,120 @@ eval_const_expressions_mutator (Node *node, void *context)
1296
1206
(void * ) context );
1297
1207
}
1298
1208
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
+
1299
1323
/*
1300
1324
* Standard expression-tree walking support
1301
1325
*
0 commit comments