]> granicus.if.org Git - postgresql/blobdiff - src/backend/optimizer/plan/setrefs.c
Do parse analysis of an EXPLAIN's contained statement during the normal
[postgresql] / src / backend / optimizer / plan / setrefs.c
index 454c3363918a1ded6b575a73430889fb88a27d28..aa4fd4e1ebe71b0eabf0eb826c50fe81119de8ea 100644 (file)
@@ -4,12 +4,12 @@
  *       Post-processing of a completed plan tree: fix references to subplan
  *       vars, compute regproc values for operators, etc
  *
- * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.154 2009/10/26 02:26:34 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.157 2010/01/15 22:36:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -101,6 +101,10 @@ static Var *search_indexed_tlist_for_var(Var *var,
 static Var *search_indexed_tlist_for_non_var(Node *node,
                                                                 indexed_tlist *itlist,
                                                                 Index newvarno);
+static Var *search_indexed_tlist_for_sortgroupref(Node *node,
+                                                                         Index sortgroupref,
+                                                                         indexed_tlist *itlist,
+                                                                         Index newvarno);
 static List *fix_join_expr(PlannerGlobal *glob,
                          List *clauses,
                          indexed_tlist *outer_itlist,
@@ -1197,10 +1201,25 @@ set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset)
                TargetEntry *tle = (TargetEntry *) lfirst(l);
                Node       *newexpr;
 
-               newexpr = fix_upper_expr(glob,
-                                                                (Node *) tle->expr,
-                                                                subplan_itlist,
-                                                                rtoffset);
+               /* If it's a non-Var sort/group item, first try to match by sortref */
+               if (tle->ressortgroupref != 0 && !IsA(tle->expr, Var))
+               {
+                       newexpr = (Node *)
+                               search_indexed_tlist_for_sortgroupref((Node *) tle->expr,
+                                                                                                         tle->ressortgroupref,
+                                                                                                         subplan_itlist,
+                                                                                                         OUTER);
+                       if (!newexpr)
+                               newexpr = fix_upper_expr(glob,
+                                                                                (Node *) tle->expr,
+                                                                                subplan_itlist,
+                                                                                rtoffset);
+               }
+               else
+                       newexpr = fix_upper_expr(glob,
+                                                                        (Node *) tle->expr,
+                                                                        subplan_itlist,
+                                                                        rtoffset);
                tle = flatCopyTargetEntry(tle);
                tle->expr = (Expr *) newexpr;
                output_targetlist = lappend(output_targetlist, tle);
@@ -1444,6 +1463,49 @@ search_indexed_tlist_for_non_var(Node *node,
        return NULL;                            /* no match */
 }
 
+/*
+ * search_indexed_tlist_for_sortgroupref --- find a sort/group expression
+ *             (which is assumed not to be just a Var)
+ *
+ * If a match is found, return a Var constructed to reference the tlist item.
+ * If no match, return NULL.
+ *
+ * This is needed to ensure that we select the right subplan TLE in cases
+ * where there are multiple textually-equal()-but-volatile sort expressions.
+ * And it's also faster than search_indexed_tlist_for_non_var.
+ */
+static Var *
+search_indexed_tlist_for_sortgroupref(Node *node,
+                                                                         Index sortgroupref,
+                                                                         indexed_tlist *itlist,
+                                                                         Index newvarno)
+{
+       ListCell   *lc;
+
+       foreach(lc, itlist->tlist)
+       {
+               TargetEntry *tle = (TargetEntry *) lfirst(lc);
+
+               /* The equal() check should be redundant, but let's be paranoid */
+               if (tle->ressortgroupref == sortgroupref &&
+                       equal(node, tle->expr))
+               {
+                       /* Found a matching subplan output expression */
+                       Var                *newvar;
+
+                       newvar = makeVar(newvarno,
+                                                        tle->resno,
+                                                        exprType((Node *) tle->expr),
+                                                        exprTypmod((Node *) tle->expr),
+                                                        0);
+                       newvar->varnoold = 0;   /* wasn't ever a plain Var */
+                       newvar->varoattno = 0;
+                       return newvar;
+               }
+       }
+       return NULL;                            /* no match */
+}
+
 /*
  * fix_join_expr
  *        Create a new set of targetlist entries or join qual clauses by
@@ -1843,14 +1905,15 @@ record_plan_function_dependency(PlannerGlobal *glob, Oid funcid)
 
 /*
  * extract_query_dependencies
- *             Given a list of not-yet-planned queries (i.e. Query nodes),
- *             extract their dependencies just as set_plan_references would do.
+ *             Given a not-yet-planned query or queries (i.e. a Query node or list
+ *             of Query nodes), extract dependencies just as set_plan_references
+ *             would do.
  *
  * This is needed by plancache.c to handle invalidation of cached unplanned
  * queries.
  */
 void
-extract_query_dependencies(List *queries,
+extract_query_dependencies(Node *query,
                                                   List **relationOids,
                                                   List **invalItems)
 {
@@ -1862,7 +1925,7 @@ extract_query_dependencies(List *queries,
        glob.relationOids = NIL;
        glob.invalItems = NIL;
 
-       (void) extract_query_dependencies_walker((Node *) queries, &glob);
+       (void) extract_query_dependencies_walker(query, &glob);
 
        *relationOids = glob.relationOids;
        *invalItems = glob.invalItems;
@@ -1881,6 +1944,19 @@ extract_query_dependencies_walker(Node *node, PlannerGlobal *context)
                Query      *query = (Query *) node;
                ListCell   *lc;
 
+               if (query->commandType == CMD_UTILITY)
+               {
+                       /* Ignore utility statements, except EXPLAIN */
+                       if (IsA(query->utilityStmt, ExplainStmt))
+                       {
+                               query = (Query *) ((ExplainStmt *) query->utilityStmt)->query;
+                               Assert(IsA(query, Query));
+                               Assert(query->commandType != CMD_UTILITY);
+                       }
+                       else
+                               return false;
+               }
+
                /* Collect relation OIDs in this Query's rtable */
                foreach(lc, query->rtable)
                {