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
|
* 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>
|
#include <stdio.h>
|
||||||
|
@ -49,15 +49,18 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
|
||||||
List *rewritten;
|
List *rewritten;
|
||||||
List *l;
|
List *l;
|
||||||
|
|
||||||
|
/* rewriter and planner may not work in aborted state? */
|
||||||
if (IsAbortedTransactionBlockState())
|
if (IsAbortedTransactionBlockState())
|
||||||
{
|
{
|
||||||
char *tag = "*ABORT STATE*";
|
|
||||||
|
|
||||||
EndCommand(tag, dest);
|
|
||||||
|
|
||||||
elog(NOTICE, "(transaction aborted): %s",
|
elog(NOTICE, "(transaction aborted): %s",
|
||||||
"queries ignored until END");
|
"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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +70,7 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
|
||||||
/* In the case of an INSTEAD NOTHING, tell at least that */
|
/* In the case of an INSTEAD NOTHING, tell at least that */
|
||||||
if (rewritten == NIL)
|
if (rewritten == NIL)
|
||||||
{
|
{
|
||||||
elog(NOTICE, "query rewrites to nothing");
|
elog(NOTICE, "Query rewrites to nothing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +91,7 @@ ExplainOneQuery(Query *query, bool verbose, CommandDest dest)
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
ExplainState *es;
|
ExplainState *es;
|
||||||
|
|
||||||
/* plan the queries (XXX we've ignored rewrite!!) */
|
/* plan the query */
|
||||||
plan = planner(query);
|
plan = planner(query);
|
||||||
|
|
||||||
/* pg_plan could have failed */
|
/* pg_plan could have failed */
|
||||||
|
@ -195,7 +198,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||||
pname = "Hash";
|
pname = "Hash";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pname = "";
|
pname = "???";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 void modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr);
|
||||||
static SubLink *modifyAggrefMakeSublink(Expr *origexp, Query *parsetree);
|
static SubLink *modifyAggrefMakeSublink(Expr *origexp, Query *parsetree);
|
||||||
static void modifyAggrefQual(Node **nodePtr, Query *parsetree);
|
static void modifyAggrefQual(Node **nodePtr, Query *parsetree);
|
||||||
|
|
||||||
|
|
||||||
static Query *fireRIRrules(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
|
* rewrite one query via query rewrite system, possibly returning 0
|
||||||
* or many queries
|
* or many queries
|
||||||
*/
|
*/
|
||||||
List *
|
static List *
|
||||||
QueryRewrite(Query *parsetree)
|
BasicQueryRewrite(Query *parsetree)
|
||||||
{
|
{
|
||||||
List *querylist;
|
List *querylist;
|
||||||
List *results = NIL;
|
List *results = NIL;
|
||||||
|
@ -2672,10 +2670,57 @@ QueryRewrite(Query *parsetree)
|
||||||
}
|
}
|
||||||
return results;
|
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)
|
void check_targetlists_are_compatible(List *prev_target, List *current_target)
|
||||||
{
|
{
|
||||||
List *next_target;
|
List *next_target;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* 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;
|
List *rewritten = NIL;
|
||||||
Query *querytree;
|
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
|
* (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
|
* (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
|
j = 0;
|
||||||
* be longer than old list as a result of
|
|
||||||
* rewrites */
|
|
||||||
for (i = 0; i < querytree_list->len; i++)
|
for (i = 0; i < querytree_list->len; i++)
|
||||||
{
|
{
|
||||||
List *union_result,
|
|
||||||
*union_list,
|
|
||||||
*rewritten_list;
|
|
||||||
|
|
||||||
querytree = querytree_list->qtrees[i];
|
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)
|
if (DebugPrintParse)
|
||||||
{
|
{
|
||||||
TPRINTF(TRACE_PARSE, "parser outputs:");
|
TPRINTF(TRACE_PARSE, "parser outputs:");
|
||||||
nodeDisplay(querytree);
|
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);
|
rewritten = QueryRewrite(querytree);
|
||||||
|
|
||||||
if (rewritten != NIL)
|
if (rewritten != NIL)
|
||||||
|
@ -506,19 +495,6 @@ pg_parse_and_plan(char *query_string, /* string to execute */
|
||||||
int len,
|
int len,
|
||||||
k;
|
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);
|
len = length(rewritten);
|
||||||
if (len == 1)
|
if (len == 1)
|
||||||
new_list->qtrees[j++] = (Query *) lfirst(rewritten);
|
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
|
* we allocated one space
|
||||||
* for the query */
|
* for the query */
|
||||||
new_list->qtrees = realloc(new_list->qtrees,
|
new_list->qtrees = realloc(new_list->qtrees,
|
||||||
new_list->len * sizeof(Query *));
|
new_list->len * sizeof(Query *));
|
||||||
for (k = 0; k < len; k++)
|
for (k = 0; k < len; k++)
|
||||||
new_list->qtrees[j++] = (Query *) nth(k, rewritten);
|
new_list->qtrees[j++] = (Query *) nth(k, rewritten);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------
|
/* Update new_list with correct final length */
|
||||||
* Due to rewriting, the new list could also have been
|
|
||||||
* shrunk (do instead nothing). Forget obsolete queries
|
|
||||||
* at the end.
|
|
||||||
* ----------
|
|
||||||
*/
|
|
||||||
new_list->len = j;
|
new_list->len = j;
|
||||||
|
|
||||||
/* we're done with the original lists, free it */
|
/* 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)
|
if (querytree_list->len == 0)
|
||||||
|
@ -1539,7 +1510,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
|
||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface ");
|
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…
Reference in New Issue