From a36436ea3f402293bc5484b83823eed8d6a8dfc3 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 24 Nov 2007 00:39:44 +0000 Subject: [PATCH] Change fix_scan_expr() to avoid copying the input node tree in the common case 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 | 49 ++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index b3be9b7415..307ab431dd 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -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 -- 2.40.0