Change fix_scan_expr() to avoid copying the input node tree in the common case
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 24 Nov 2007 00:39:44 +0000 (00:39 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 24 Nov 2007 00:39:44 +0000 (00:39 +0000)
where rtoffset == 0.  In that case there is no need to change Var nodes,
and since filling in unset opfuncid fields is always safe, scribbling on the
input tree to that extent is not objectionable.  This brings the cost of this
operation back down to what it was in 8.2 for simple queries.  Per
investigation of performance gripe from Guillaume Smet.

src/backend/optimizer/plan/setrefs.c

index b3be9b741520079f6dfa63209fe17c41b8518dc1..307ab431dd0775847441549617d0829f279f4e73 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.139 2007/11/15 22:25:15 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.140 2007/11/24 00:39:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,6 +73,7 @@ static Plan *set_subqueryscan_references(PlannerGlobal *glob,
 static bool trivial_subqueryscan(SubqueryScan *plan);
 static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset);
 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
+static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context);
 static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset);
 static void set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
                          indexed_tlist *outer_itlist);
@@ -625,7 +626,23 @@ fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset)
 
    context.glob = glob;
    context.rtoffset = rtoffset;
-   return fix_scan_expr_mutator(node, &context);
+
+   if (rtoffset != 0)
+   {
+       return fix_scan_expr_mutator(node, &context);
+   }
+   else
+   {
+       /*
+        * If rtoffset == 0, we don't need to change any Vars, which makes
+        * it OK to just scribble on the input node tree instead of copying
+        * (since the only change, filling in any unset opfuncid fields,
+        * is harmless).  This saves just enough cycles to be noticeable on
+        * trivial queries.
+        */
+       (void) fix_scan_expr_walker(node, &context);
+       return node;
+   }
 }
 
 static Node *
@@ -687,6 +704,34 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
                                   (void *) context);
 }
 
+static bool
+fix_scan_expr_walker(Node *node, fix_scan_expr_context *context)
+{
+   if (node == NULL)
+       return false;
+   if (IsA(node, OpExpr))
+       set_opfuncid((OpExpr *) node);
+   else if (IsA(node, DistinctExpr))
+       set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
+   else if (IsA(node, NullIfExpr))
+       set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
+   else if (IsA(node, ScalarArrayOpExpr))
+       set_sa_opfuncid((ScalarArrayOpExpr *) node);
+   else if (IsA(node, Const))
+   {
+       Const      *con = (Const *) node;
+
+       /* Check for regclass reference */
+       if (con->consttype == REGCLASSOID && !con->constisnull)
+           context->glob->relationOids =
+               lappend_oid(context->glob->relationOids,
+                           DatumGetObjectId(con->constvalue));
+       return false;
+   }
+   return expression_tree_walker(node, fix_scan_expr_walker,
+                                 (void *) context);
+}
+
 /*
  * set_join_references
  *   Modify the target list and quals of a join node to reference its