Rearrange top-level rewrite operations so that EXPLAIN works
on queries involving UNION, EXCEPT, INTERSECT.
This commit is contained in:
parent
6458daa180
commit
0b69d8a27c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user