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 3ec5118ff77acf500367137febeb887f2cdb6379..72f9b1117b58a0bf3b52927508621ac292d0ad31 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
@@ -1296,6 +1206,120 @@ eval_const_expressions_mutator (Node *node, 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
  *