Rearrange top-level rewrite operations so that EXPLAIN works

on queries involving UNION, EXCEPT, INTERSECT.
This commit is contained in:
Tom Lane 1999-05-09 23:31:47 +00:00
parent 6458daa180
commit 0b69d8a27c
3 changed files with 125 additions and 106 deletions

View 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;
}

View 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;

View 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 (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);
}
}
/* don't rewrite utilites */
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) */
/* don't rewrite utilites, just dump 'em into new_list */
if (querytree->commandType == CMD_UTILITY)
{
new_list->qtrees[j++] = querytree;
continue;
}
/* 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");
}
/* ----------------