Tighten inline_function's test for overly complex parameters. This
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 3 Aug 2003 23:46:37 +0000 (23:46 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 3 Aug 2003 23:46:37 +0000 (23:46 +0000)
should catch most situations where repeated inlining blows up the
expression complexity unreasonably, as in Joe Conway's recent example.

src/backend/optimizer/util/clauses.c

index 6060f462e8f4c1219cc139a1947447f77817f482..3ebc1c650e87226807df288ba12fcf10671d6af0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.148 2003/07/28 18:33:18 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.149 2003/08/03 23:46:37 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -26,6 +26,7 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
+#include "optimizer/cost.h"
 #include "optimizer/planmain.h"
 #include "optimizer/var.h"
 #include "parser/analyze.h"
@@ -1710,8 +1711,12 @@ evaluate_function(Oid funcid, Oid result_type, List *args,
  * so we keep track of which functions we are already expanding and
  * do not re-expand them.  Also, if a parameter is used more than once
  * in the SQL-function body, we require it not to contain any volatile
- * functions or sublinks --- volatiles might deliver inconsistent answers,
- * and subplans might be unreasonably expensive to evaluate multiple times.
+ * functions (volatiles might deliver inconsistent answers) nor to be
+ * unreasonably expensive to evaluate.  The expensiveness check not only
+ * prevents us from doing multiple evaluations of an expensive parameter
+ * at runtime, but is a safety value to limit growth of an expression due
+ * to repeated inlining.
+ *
  * We must also beware of changing the volatility or strictness status of
  * functions by inlining them.
  *
@@ -1912,9 +1917,26 @@ inline_function(Oid funcid, Oid result_type, List *args,
                }
                else if (usecounts[i] != 1)
                {
-                       /* Param used multiple times: uncool if volatile or expensive */
-                       if (contain_volatile_functions(param) ||
-                               contain_subplans(param))
+                       /* Param used multiple times: uncool if expensive or volatile */
+                       QualCost        eval_cost;
+
+                       /*
+                        * We define "expensive" as "contains any subplan or more than
+                        * 10 operators".  Note that the subplan search has to be done
+                        * explicitly, since cost_qual_eval() will barf on unplanned
+                        * subselects.
+                        */
+                       if (contain_subplans(param))
+                               goto fail;
+                       cost_qual_eval(&eval_cost, makeList1(param));
+                       if (eval_cost.startup + eval_cost.per_tuple >
+                               10 * cpu_operator_cost)
+                               goto fail;
+                       /*
+                        * Check volatility last since this is more expensive than the
+                        * above tests
+                        */
+                       if (contain_volatile_functions(param))
                                goto fail;
                }
                i++;