OSDN Git Service

Minor code rearrangement & doc improvement in eval_const_expressions().
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 19 Mar 2000 18:20:38 +0000 (18:20 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 19 Mar 2000 18:20:38 +0000 (18:20 +0000)
src/backend/optimizer/util/clauses.c

index 3ec5118..72f9b11 100644 (file)
@@ -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
@@ -1297,6 +1207,120 @@ eval_const_expressions_mutator (Node *node, 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
  *
  * We used to have near-duplicate code in many different routines that