1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-23 03:21:12 +03:00

Restructure handling of inheritance queries so that they work with outer

joins, and clean things up a good deal at the same time.  Append plan node
no longer hacks on rangetable at runtime --- instead, all child tables are
given their own RT entries during planning.  Concept of multiple target
tables pushed up into execMain, replacing bug-prone implementation within
nodeAppend.  Planner now supports generating Append plans for inheritance
sets either at the top of the plan (the old way) or at the bottom.  Expanding
at the bottom is appropriate for tables used as sources, since they may
appear inside an outer join; but we must still expand at the top when the
target of an UPDATE or DELETE is an inheritance set, because we actually need
a different targetlist and junkfilter for each target table in that case.
Fortunately a target table can't be inside an outer join...  Bizarre mutual
recursion between union_planner and prepunion.c is gone --- in fact,
union_planner doesn't really have much to do with union queries anymore,
so I renamed it grouping_planner.
This commit is contained in:
Tom Lane
2000-11-12 00:37:02 +00:00
parent 609f9199af
commit 6543d81d65
37 changed files with 1258 additions and 1253 deletions

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.130 2000/11/05 22:50:19 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.131 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -176,8 +176,7 @@ _copyAppend(Append *from)
* ----------------
*/
Node_Copy(from, newnode, appendplans);
newnode->inheritrelid = from->inheritrelid;
Node_Copy(from, newnode, inheritrtable);
newnode->isTarget = from->isTarget;
return newnode;
}
@ -1275,6 +1274,30 @@ _copyTidPath(TidPath *from)
return newnode;
}
/* ----------------
* _copyAppendPath
* ----------------
*/
static AppendPath *
_copyAppendPath(AppendPath *from)
{
AppendPath *newnode = makeNode(AppendPath);
/* ----------------
* copy the node superclass fields
* ----------------
*/
CopyPathFields((Path *) from, (Path *) newnode);
/* ----------------
* copy remainder of node
* ----------------
*/
Node_Copy(from, newnode, subpaths);
return newnode;
}
/* ----------------
* CopyJoinPathFields
*
@ -1767,6 +1790,8 @@ _copyQuery(Query *from)
Node_Copy(from, newnode, setOperations);
newnode->resultRelations = listCopy(from->resultRelations);
/*
* We do not copy the planner internal fields: base_rel_list,
* join_rel_list, equi_key_list, query_pathkeys. Not entirely clear if
@ -2677,6 +2702,9 @@ copyObject(void *from)
case T_TidPath:
retval = _copyTidPath(from);
break;
case T_AppendPath:
retval = _copyAppendPath(from);
break;
case T_NestPath:
retval = _copyNestPath(from);
break;

View File

@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.80 2000/11/05 22:50:19 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.81 2000/11/12 00:36:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -435,6 +435,16 @@ _equalTidPath(TidPath *a, TidPath *b)
return true;
}
static bool
_equalAppendPath(AppendPath *a, AppendPath *b)
{
if (!_equalPath((Path *) a, (Path *) b))
return false;
if (!equal(a->subpaths, b->subpaths))
return false;
return true;
}
static bool
_equalJoinPath(JoinPath *a, JoinPath *b)
{
@ -555,28 +565,6 @@ _equalStream(Stream *a, Stream *b)
return equal(a->downstream, b->downstream);
}
/*
* Stuff from execnodes.h
*/
/*
* EState is a subclass of Node.
*/
static bool
_equalEState(EState *a, EState *b)
{
if (a->es_direction != b->es_direction)
return false;
if (!equal(a->es_range_table, b->es_range_table))
return false;
if (a->es_result_relation_info != b->es_result_relation_info)
return false;
return true;
}
/*
* Stuff from parsenodes.h
*/
@ -624,6 +612,8 @@ _equalQuery(Query *a, Query *b)
return false;
if (!equal(a->setOperations, b->setOperations))
return false;
if (!equali(a->resultRelations, b->resultRelations))
return false;
/*
* We do not check the internal-to-the-planner fields: base_rel_list,
@ -1851,14 +1841,13 @@ equal(void *a, void *b)
case T_TidPath:
retval = _equalTidPath(a, b);
break;
case T_AppendPath:
retval = _equalAppendPath(a, b);
break;
case T_IndexOptInfo:
retval = _equalIndexOptInfo(a, b);
break;
case T_EState:
retval = _equalEState(a, b);
break;
case T_List:
{
List *la = (List *) a;

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.131 2000/10/31 13:59:52 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.132 2000/11/12 00:36:57 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
@ -296,6 +296,9 @@ _outQuery(StringInfo str, Query *node)
appendStringInfo(str, " :setOperations ");
_outNode(str, node->setOperations);
appendStringInfo(str, " :resultRelations ");
_outIntList(str, node->resultRelations);
}
static void
@ -327,17 +330,18 @@ _outSetOperationStmt(StringInfo str, SetOperationStmt *node)
/*
* print the basic stuff of all nodes that inherit from Plan
*
* NOTE: we deliberately omit the execution state (EState)
*/
static void
_outPlanInfo(StringInfo str, Plan *node)
{
appendStringInfo(str,
":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :state %s :qptargetlist ",
":startup_cost %.2f :total_cost %.2f :rows %.0f :width %d :qptargetlist ",
node->startup_cost,
node->total_cost,
node->plan_rows,
node->plan_width,
node->state ? "not-NULL" : "<>");
node->plan_width);
_outNode(str, node->targetlist);
appendStringInfo(str, " :qpqual ");
@ -394,9 +398,8 @@ _outAppend(StringInfo str, Append *node)
appendStringInfo(str, " :appendplans ");
_outNode(str, node->appendplans);
appendStringInfo(str, " :inheritrelid %u :inheritrtable ",
node->inheritrelid);
_outNode(str, node->inheritrtable);
appendStringInfo(str, " :isTarget %s ",
node->isTarget ? "true" : "false");
}
/*
@ -945,25 +948,6 @@ _outJoinExpr(StringInfo str, JoinExpr *node)
_outNode(str, node->colvars);
}
/*
* Stuff from execnodes.h
*/
/*
* EState is a subclass of Node.
*/
static void
_outEState(StringInfo str, EState *node)
{
appendStringInfo(str,
" ESTATE :direction %d :range_table ",
node->es_direction);
_outNode(str, node->es_range_table);
appendStringInfo(str, " :result_relation_info @ 0x%x ",
(int) (node->es_result_relation_info));
}
/*
* Stuff from relation.h
*/
@ -1107,10 +1091,27 @@ _outTidPath(StringInfo str, TidPath *node)
appendStringInfo(str, " :tideval ");
_outNode(str, node->tideval);
appendStringInfo(str, " :un joined_relids ");
appendStringInfo(str, " :unjoined_relids ");
_outIntList(str, node->unjoined_relids);
}
/*
* AppendPath is a subclass of Path.
*/
static void
_outAppendPath(StringInfo str, AppendPath *node)
{
appendStringInfo(str,
" APPENDPATH :pathtype %d :startup_cost %.2f :total_cost %.2f :pathkeys ",
node->path.pathtype,
node->path.startup_cost,
node->path.total_cost);
_outNode(str, node->path.pathkeys);
appendStringInfo(str, " :subpaths ");
_outNode(str, node->subpaths);
}
/*
* NestPath is a subclass of Path
*/
@ -1632,9 +1633,6 @@ _outNode(StringInfo str, void *obj)
case T_JoinExpr:
_outJoinExpr(str, obj);
break;
case T_EState:
_outEState(str, obj);
break;
case T_RelOptInfo:
_outRelOptInfo(str, obj);
break;
@ -1656,6 +1654,9 @@ _outNode(StringInfo str, void *obj)
case T_TidPath:
_outTidPath(str, obj);
break;
case T_AppendPath:
_outAppendPath(str, obj);
break;
case T_NestPath:
_outNestPath(str, obj);
break;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.99 2000/10/22 22:14:54 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.100 2000/11/12 00:36:57 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
@ -150,6 +150,9 @@ _readQuery(void)
token = lsptok(NULL, &length); /* skip :setOperations */
local_node->setOperations = nodeRead(true);
token = lsptok(NULL, &length); /* skip :resultRelations */
local_node->resultRelations = toIntList(nodeRead(true));
return local_node;
}
@ -260,17 +263,6 @@ _getPlan(Plan *node)
token = lsptok(NULL, &length); /* get the plan_width */
node->plan_width = atoi(token);
token = lsptok(NULL, &length); /* eat the :state stuff */
token = lsptok(NULL, &length); /* now get the state */
if (length == 0)
node->state = (EState *) NULL;
else
{ /* Disgusting hack until I figure out what
* to do here */
node->state = (EState *) !NULL;
}
token = lsptok(NULL, &length); /* eat :qptargetlist */
node->targetlist = nodeRead(true);
@ -283,6 +275,8 @@ _getPlan(Plan *node)
token = lsptok(NULL, &length); /* eat :righttree */
node->righttree = (Plan *) nodeRead(true);
node->state = (EState *) NULL; /* never read in */
return;
}
@ -348,12 +342,9 @@ _readAppend(void)
token = lsptok(NULL, &length); /* eat :appendplans */
local_node->appendplans = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* eat :inheritrelid */
token = lsptok(NULL, &length); /* get inheritrelid */
local_node->inheritrelid = strtoul(token, NULL, 10);
token = lsptok(NULL, &length); /* eat :inheritrtable */
local_node->inheritrtable = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* eat :isTarget */
token = lsptok(NULL, &length); /* get isTarget */
local_node->isTarget = (token[0] == 't') ? true : false;
return local_node;
}
@ -1297,43 +1288,6 @@ _readJoinExpr(void)
return local_node;
}
/*
* Stuff from execnodes.h
*/
/* ----------------
* _readEState
*
* EState is a subclass of Node.
* ----------------
*/
static EState *
_readEState(void)
{
EState *local_node;
char *token;
int length;
local_node = makeNode(EState);
token = lsptok(NULL, &length); /* get :direction */
token = lsptok(NULL, &length); /* now read it */
local_node->es_direction = atoi(token);
token = lsptok(NULL, &length); /* get :range_table */
local_node->es_range_table = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :result_relation_info */
token = lsptok(NULL, &length); /* get @ */
token = lsptok(NULL, &length); /* now read it */
sscanf(token, "%x", (unsigned int *) &local_node->es_result_relation_info);
return local_node;
}
/*
* Stuff from relation.h
*/
@ -1639,6 +1593,42 @@ _readTidPath(void)
return local_node;
}
/* ----------------
* _readAppendPath
*
* AppendPath is a subclass of Path.
* ----------------
*/
static AppendPath *
_readAppendPath(void)
{
AppendPath *local_node;
char *token;
int length;
local_node = makeNode(AppendPath);
token = lsptok(NULL, &length); /* get :pathtype */
token = lsptok(NULL, &length); /* now read it */
local_node->path.pathtype = atol(token);
token = lsptok(NULL, &length); /* get :startup_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.startup_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :total_cost */
token = lsptok(NULL, &length); /* now read it */
local_node->path.total_cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* get :pathkeys */
local_node->path.pathkeys = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :subpaths */
local_node->subpaths = nodeRead(true); /* now read it */
return local_node;
}
/* ----------------
* _readNestPath
*
@ -1984,8 +1974,6 @@ parsePlanString(void)
return_value = _readOper();
else if (length == 5 && strncmp(token, "PARAM", length) == 0)
return_value = _readParam();
else if (length == 6 && strncmp(token, "ESTATE", length) == 0)
return_value = _readEState();
else if (length == 10 && strncmp(token, "RELOPTINFO", length) == 0)
return_value = _readRelOptInfo();
else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
@ -1998,6 +1986,8 @@ parsePlanString(void)
return_value = _readIndexPath();
else if (length == 7 && strncmp(token, "TIDPATH", length) == 0)
return_value = _readTidPath();
else if (length == 10 && strncmp(token, "APPENDPATH", length) == 0)
return_value = _readAppendPath();
else if (length == 8 && strncmp(token, "NESTPATH", length) == 0)
return_value = _readNestPath();
else if (length == 9 && strncmp(token, "MERGEPATH", length) == 0)