Rearrange top-level rewrite operations so that EXPLAIN works
authorTom Lane
Sun, 9 May 1999 23:31:47 +0000 (23:31 +0000)
committerTom Lane
Sun, 9 May 1999 23:31:47 +0000 (23:31 +0000)
on queries involving UNION, EXCEPT, INTERSECT.

src/backend/commands/explain.c
src/backend/rewrite/rewriteHandler.c
src/backend/tcop/postgres.c

index a26579270c96b5ac5d3896b98e562257677b8725..6a04417964b2139c31e68cc7e3630e6f8054c32e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 1994-5, Regents of the University of California
  *
- *   $Id: explain.c,v 1.35 1999/04/25 03:19:09 tgl Exp $
+ *   $Id: explain.c,v 1.36 1999/05/09 23:31:45 tgl Exp $
  *
  */
 #include 
@@ -49,15 +49,18 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
    List    *rewritten;
    List    *l;
 
+   /* rewriter and planner may not work in aborted state? */
    if (IsAbortedTransactionBlockState())
    {
-       char       *tag = "*ABORT STATE*";
-
-       EndCommand(tag, dest);
-
        elog(NOTICE, "(transaction aborted): %s",
             "queries ignored until END");
+       return;
+   }
 
+   /* rewriter and planner will not cope with utility statements */
+   if (query->commandType == CMD_UTILITY)
+   {
+       elog(NOTICE, "Utility statements have no plan structure");
        return;
    }
 
@@ -67,7 +70,7 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
    /* In the case of an INSTEAD NOTHING, tell at least that */
    if (rewritten == NIL)
    {
-       elog(NOTICE, "query rewrites to nothing");
+       elog(NOTICE, "Query rewrites to nothing");
        return;
    }
 
@@ -88,7 +91,7 @@ ExplainOneQuery(Query *query, bool verbose, CommandDest dest)
    Plan       *plan;
    ExplainState *es;
 
-   /* plan the queries (XXX we've ignored rewrite!!) */
+   /* plan the query */
    plan = planner(query);
 
    /* pg_plan could have failed */
@@ -195,7 +198,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
            pname = "Hash";
            break;
        default:
-           pname = "";
+           pname = "???";
            break;
    }
 
index a9ff8a0a3b18b7ab3855f088296849ceeb57b5bc..1ba1a5dd56e4a4c399ad3c40e4a82c4bc7d8abf7 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.37 1999/02/22 05:26:46 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.38 1999/05/09 23:31:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,8 +59,6 @@ static void modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_ind
 static void modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr);
 static SubLink *modifyAggrefMakeSublink(Expr *origexp, Query *parsetree);
 static void modifyAggrefQual(Node **nodePtr, Query *parsetree);
-
-
 static Query *fireRIRrules(Query *parsetree);
 
 
@@ -2634,12 +2632,12 @@ RewritePreprocessQuery(Query *parsetree)
 
 
 /*
- * QueryRewrite -
+ * BasicQueryRewrite -
  *   rewrite one query via query rewrite system, possibly returning 0
  *   or many queries
  */
-List *
-QueryRewrite(Query *parsetree)
+static List *
+BasicQueryRewrite(Query *parsetree)
 {
    List        *querylist;
    List        *results = NIL;
@@ -2672,10 +2670,57 @@ QueryRewrite(Query *parsetree)
    }
    return results;
 }
-/***S*I***/
-/* This function takes two targetlists as arguments and checks if the targetlists are compatible
- * (i.e. both select for the same number of attributes and the types are compatible 
+
+/*
+ * QueryRewrite -
+ *   Primary entry point to the query rewriter.
+ *   Rewrite one query via query rewrite system, possibly returning 0
+ *   or many queries.
+ *
+ * NOTE: The code in QueryRewrite was formerly in pg_parse_and_plan(), and was
+ * moved here so that it would be invoked during EXPLAIN.  The division of
+ * labor between this routine and BasicQueryRewrite is not obviously correct
+ * ... at least not to me ... tgl 5/99.
  */
+List *
+QueryRewrite(Query *parsetree)
+{
+   List       *rewritten,
+              *rewritten_item;
+
+   /***S*I***/
+   /* Rewrite Union, Intersect and Except Queries
+    * to normal Union Queries using IN and NOT IN subselects */
+   if (parsetree->intersectClause)
+       parsetree = Except_Intersect_Rewrite(parsetree);
+
+   /* Rewrite basic queries (retrieve, append, delete, replace) */
+   rewritten = BasicQueryRewrite(parsetree);
+
+   /*
+    * Rewrite the UNIONS.
+    */
+   foreach (rewritten_item, rewritten)
+   {
+       Query      *qry = (Query *) lfirst(rewritten_item);
+       List       *union_result = NIL;
+       List       *union_item;
+
+       foreach (union_item, qry->unionClause)
+       {
+           union_result = nconc(union_result,
+                           BasicQueryRewrite((Query *) lfirst(union_item)));
+       }
+       qry->unionClause = union_result;
+   }
+
+   return rewritten;
+}
+
+/***S*I***/
+/* This function takes two targetlists as arguments and checks if the
+ * targetlists are compatible (i.e. both select for the same number of
+ * attributes and the types are compatible */
 void check_targetlists_are_compatible(List *prev_target, List *current_target)
 {
   List *next_target;
index f196e51eaf0de775777151a6178bc0d8f5fadf49..24b2303ee9dbf17146615e194e02e49da13b4457 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.110 1999/05/03 19:09:54 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.111 1999/05/09 23:31:47 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -399,6 +399,49 @@ pg_parse_and_plan(char *query_string,  /* string to execute */
    List       *rewritten = NIL;
    Query      *querytree;
 
+   if (DebugPrintQuery)
+   {
+       if (DebugPrintQuery > 3)
+       {             
+           /* Print the query string as is if query debug level > 3 */
+           TPRINTF(TRACE_QUERY, "query: %s", query_string); 
+       }
+       else
+       {
+           /* Print condensed query string to fit in one log line */
+           char        buff[MAX_QUERY_SIZE + 1];
+           char        c,
+                       *s,
+                       *d;
+           int         n,
+                       is_space = 1;
+
+           for (s = query_string, d = buff, n = 0; (c = *s) && (n < MAX_QUERY_SIZE); s++)
+           {
+               switch (c)
+               {
+                   case '\r':
+                   case '\n':
+                   case '\t':
+                       c = ' ';
+                       /* fall through */
+                   case ' ':
+                       if (is_space)
+                           continue;
+                       is_space = 1;
+                       break;
+                   default:
+                       is_space = 0;
+                       break;
+               }
+               *d++ = c;
+               n++;
+           }
+           *d = '\0';
+           TPRINTF(TRACE_QUERY, "query: %s", buff);
+       }
+   }
+
    /* ----------------
     *  (1) parse the request string into a list of parse trees
     * ----------------
@@ -421,84 +464,30 @@ pg_parse_and_plan(char *query_string, /* string to execute */
 
    /* ----------------
     *  (2) rewrite the queries, as necessary
+    *
+    *  j counts queries output into new_list; the number of rewritten
+    *  queries can be different from the original number.
     * ----------------
     */
-   j = 0;                      /* counter for the new_list, new_list can
-                                * be longer than old list as a result of
-                                * rewrites */
+   j = 0;
    for (i = 0; i < querytree_list->len; i++)
    {
-       List       *union_result,
-                  *union_list,
-                  *rewritten_list;
-
        querytree = querytree_list->qtrees[i];
 
-       /***S*I***/
-       /* Rewrite Union, Intersect and Except Queries
-        * to normal Union Queries using IN and NOT IN subselects */
-       if(querytree->intersectClause != NIL) 
-         {   
-           querytree = Except_Intersect_Rewrite(querytree);
-         }
-
-       if (DebugPrintQuery)
+       if (DebugPrintParse)
        {
-           if (DebugPrintQuery > 3)
-           {             
-             /* Print the query string as is if query debug level > 3 */
-             TPRINTF(TRACE_QUERY, "query: %s", query_string); 
-           }
-           else
-           {
-               /* Print condensed query string to fit in one log line */
-               char        buff[MAX_QUERY_SIZE + 1];
-               char        c,
-                          *s,
-                          *d;
-               int         n,
-                           is_space = 1;
-
-               for (s = query_string, d = buff, n = 0; (c = *s) && (n < MAX_QUERY_SIZE); s++)
-               {
-                   switch (c)
-                   {
-                       case '\r':
-                       case '\n':
-                       case '\t':
-                           c = ' ';
-                           /* fall through */
-                       case ' ':
-                           if (is_space)
-                               continue;
-                           is_space = 1;
-                           break;
-                       default:
-                           is_space = 0;
-                           break;
-                   }
-                   *d++ = c;
-                   n++;
-               }
-               *d = '\0';
-               TPRINTF(TRACE_QUERY, "query: %s", buff);
-           }
+           TPRINTF(TRACE_PARSE, "parser outputs:");
+           nodeDisplay(querytree);
        }
 
-       /* don't rewrite utilites */
+       /* don't rewrite utilites, just dump 'em into new_list */
        if (querytree->commandType == CMD_UTILITY)
        {
            new_list->qtrees[j++] = querytree;
            continue;
        }
 
-       if (DebugPrintParse)
-       {
-           TPRINTF(TRACE_PARSE, "parser outputs:");
-           nodeDisplay(querytree);
-       }
-
-       /* rewrite queries (retrieve, append, delete, replace) */
+       /* rewrite regular queries */
        rewritten = QueryRewrite(querytree);
 
        if (rewritten != NIL)
@@ -506,19 +495,6 @@ pg_parse_and_plan(char *query_string,  /* string to execute */
            int         len,
                        k;
 
-           /*
-            * Rewrite the UNIONS.
-            */
-           foreach(rewritten_list, rewritten)
-           {
-               Query      *qry = (Query *) lfirst(rewritten_list);
-
-               union_result = NIL;
-               foreach(union_list, qry->unionClause)
-                   union_result = nconc(union_result, QueryRewrite((Query *) lfirst(union_list)));
-               qry->unionClause = union_result;
-           }
-
            len = length(rewritten);
            if (len == 1)
                new_list->qtrees[j++] = (Query *) lfirst(rewritten);
@@ -530,19 +506,14 @@ pg_parse_and_plan(char *query_string, /* string to execute */
                                                 * we allocated one space
                                                 * for the query */
                new_list->qtrees = realloc(new_list->qtrees,
-                                       new_list->len * sizeof(Query *));
+                                          new_list->len * sizeof(Query *));
                for (k = 0; k < len; k++)
                    new_list->qtrees[j++] = (Query *) nth(k, rewritten);
            }
        }
    }
 
-   /* ----------
-    * Due to rewriting, the new list could also have been
-    * shrunk (do instead nothing). Forget obsolete queries
-    * at the end.
-    * ----------
-    */
+   /* Update new_list with correct final length */
    new_list->len = j;
 
    /* we're done with the original lists, free it */
@@ -657,7 +628,7 @@ pg_parse_and_plan(char *query_string,   /* string to execute */
    }
 
    /* ----------
-    * Check if the rewriting had thrown away anything
+    * Check if the rewriting had thrown away everything
     * ----------
     */
    if (querytree_list->len == 0)
@@ -1539,7 +1510,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.110 $ $Date: 1999/05/03 19:09:54 $\n");
+       puts("$Revision: 1.111 $ $Date: 1999/05/09 23:31:47 $\n");
    }
 
    /* ----------------