Rearrange top-level rewrite operations so that EXPLAIN works
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 9 May 1999 23:31:47 +0000 (23:31 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 <stdio.h>
@@ -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");
        }
 
        /* ----------------