Commit e6381966 authored by Tom Lane's avatar Tom Lane

Major planner/optimizer revision: get rid of PathOrder node type,

store all ordering information in pathkeys lists (which are now lists of
lists of PathKeyItem nodes, not just lists of lists of vars).  This was
a big win --- the code is smaller and IMHO more understandable than it
was, even though it handles more cases.  I believe the node changes will
not force an initdb for anyone; planner nodes don't show up in stored
rules.
parent 08320bfb
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.90 1999/08/09 06:20:23 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.91 1999/08/16 02:17:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1030,10 +1030,6 @@ _copyRelOptInfo(RelOptInfo *from) ...@@ -1030,10 +1030,6 @@ _copyRelOptInfo(RelOptInfo *from)
newnode->indexkeys[len] = 0; newnode->indexkeys[len] = 0;
} }
newnode->relam = from->relam;
newnode->indproc = from->indproc;
Node_Copy(from, newnode, indpred);
if (from->ordering) if (from->ordering)
{ {
for (len = 0; from->ordering[len] != 0; len++) for (len = 0; from->ordering[len] != 0; len++)
...@@ -1044,6 +1040,10 @@ _copyRelOptInfo(RelOptInfo *from) ...@@ -1044,6 +1040,10 @@ _copyRelOptInfo(RelOptInfo *from)
newnode->ordering[len] = 0; newnode->ordering[len] = 0;
} }
newnode->relam = from->relam;
newnode->indproc = from->indproc;
Node_Copy(from, newnode, indpred);
Node_Copy(from, newnode, restrictinfo); Node_Copy(from, newnode, restrictinfo);
Node_Copy(from, newnode, joininfo); Node_Copy(from, newnode, joininfo);
Node_Copy(from, newnode, innerjoin); Node_Copy(from, newnode, innerjoin);
...@@ -1061,8 +1061,6 @@ _copyRelOptInfo(RelOptInfo *from) ...@@ -1061,8 +1061,6 @@ _copyRelOptInfo(RelOptInfo *from)
static void static void
CopyPathFields(Path *from, Path *newnode) CopyPathFields(Path *from, Path *newnode)
{ {
newnode->pathtype = from->pathtype;
/* /*
* Modify the next line, since it causes the copying to cycle (i.e. * Modify the next line, since it causes the copying to cycle (i.e.
* the parent points right back here! -- JMH, 7/7/92. Old version: * the parent points right back here! -- JMH, 7/7/92. Old version:
...@@ -1072,32 +1070,9 @@ CopyPathFields(Path *from, Path *newnode) ...@@ -1072,32 +1070,9 @@ CopyPathFields(Path *from, Path *newnode)
newnode->path_cost = from->path_cost; newnode->path_cost = from->path_cost;
newnode->pathorder = makeNode(PathOrder); newnode->pathtype = from->pathtype;
newnode->pathorder->ordtype = from->pathorder->ordtype;
if (from->pathorder->ordtype == SORTOP_ORDER)
{
int len,
i;
Oid *ordering = from->pathorder->ord.sortop;
if (ordering)
{
for (len = 0; ordering[len] != 0; len++)
;
newnode->pathorder->ord.sortop = (Oid *) palloc(sizeof(Oid) * (len + 1));
for (i = 0; i < len; i++)
newnode->pathorder->ord.sortop[i] = ordering[i];
newnode->pathorder->ord.sortop[len] = 0;
}
}
else
Node_Copy(from, newnode, pathorder->ord.merge);
Node_Copy(from, newnode, pathkeys); Node_Copy(from, newnode, pathkeys);
newnode->outerjoincost = from->outerjoincost;
newnode->joinid = listCopy(from->joinid);
} }
/* ---------------- /* ----------------
...@@ -1135,32 +1110,20 @@ _copyIndexPath(IndexPath *from) ...@@ -1135,32 +1110,20 @@ _copyIndexPath(IndexPath *from)
*/ */
newnode->indexid = listCopy(from->indexid); newnode->indexid = listCopy(from->indexid);
Node_Copy(from, newnode, indexqual); Node_Copy(from, newnode, indexqual);
newnode->joinrelids = listCopy(from->joinrelids);
if (from->indexkeys)
{
int i,
len;
for (len = 0; from->indexkeys[len] != 0; len++)
;
newnode->indexkeys = (int *) palloc(sizeof(int) * (len + 1));
for (i = 0; i < len; i++)
newnode->indexkeys[i] = from->indexkeys[i];
newnode->indexkeys[len] = 0;
}
return newnode; return newnode;
} }
/* ---------------- /* ----------------
* CopyNestPathFields * CopyJoinPathFields
* *
* This function copies the fields of the NestPath node. It is used by * This function copies the fields of the JoinPath node. It is used by
* all the copy functions for classes which inherit from NestPath. * all the copy functions for classes which inherit from JoinPath.
* ---------------- * ----------------
*/ */
static void static void
CopyNestPathFields(NestPath *from, NestPath *newnode) CopyJoinPathFields(JoinPath *from, JoinPath *newnode)
{ {
Node_Copy(from, newnode, pathinfo); Node_Copy(from, newnode, pathinfo);
Node_Copy(from, newnode, outerjoinpath); Node_Copy(from, newnode, outerjoinpath);
...@@ -1181,7 +1144,7 @@ _copyNestPath(NestPath *from) ...@@ -1181,7 +1144,7 @@ _copyNestPath(NestPath *from)
* ---------------- * ----------------
*/ */
CopyPathFields((Path *) from, (Path *) newnode); CopyPathFields((Path *) from, (Path *) newnode);
CopyNestPathFields(from, newnode); CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
return newnode; return newnode;
} }
...@@ -1200,7 +1163,7 @@ _copyMergePath(MergePath *from) ...@@ -1200,7 +1163,7 @@ _copyMergePath(MergePath *from)
* ---------------- * ----------------
*/ */
CopyPathFields((Path *) from, (Path *) newnode); CopyPathFields((Path *) from, (Path *) newnode);
CopyNestPathFields((NestPath *) from, (NestPath *) newnode); CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
/* ---------------- /* ----------------
* copy the remainder of the node * copy the remainder of the node
...@@ -1227,76 +1190,32 @@ _copyHashPath(HashPath *from) ...@@ -1227,76 +1190,32 @@ _copyHashPath(HashPath *from)
* ---------------- * ----------------
*/ */
CopyPathFields((Path *) from, (Path *) newnode); CopyPathFields((Path *) from, (Path *) newnode);
CopyNestPathFields((NestPath *) from, (NestPath *) newnode); CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
/* ---------------- /* ----------------
* copy remainder of node * copy remainder of node
* ---------------- * ----------------
*/ */
Node_Copy(from, newnode, path_hashclauses); Node_Copy(from, newnode, path_hashclauses);
Node_Copy(from, newnode, outerhashkeys);
Node_Copy(from, newnode, innerhashkeys);
return newnode;
}
/* ----------------
* _copyOrderKey
* ----------------
*/
static OrderKey *
_copyOrderKey(OrderKey *from)
{
OrderKey *newnode = makeNode(OrderKey);
/* ----------------
* copy remainder of node
* ----------------
*/
newnode->attribute_number = from->attribute_number;
newnode->array_index = from->array_index;
return newnode; return newnode;
} }
/* ---------------- /* ----------------
* _copyJoinKey * _copyPathKeyItem
* ---------------- * ----------------
*/ */
static JoinKey * static PathKeyItem *
_copyJoinKey(JoinKey *from) _copyPathKeyItem(PathKeyItem *from)
{ {
JoinKey *newnode = makeNode(JoinKey); PathKeyItem *newnode = makeNode(PathKeyItem);
/* ---------------- /* ----------------
* copy remainder of node * copy remainder of node
* ---------------- * ----------------
*/ */
Node_Copy(from, newnode, outer); Node_Copy(from, newnode, key);
Node_Copy(from, newnode, inner); newnode->sortop = from->sortop;
return newnode;
}
/* ----------------
* _copyMergeOrder
* ----------------
*/
static MergeOrder *
_copyMergeOrder(MergeOrder *from)
{
MergeOrder *newnode = makeNode(MergeOrder);
/* ----------------
* copy remainder of node
* ----------------
*/
newnode->join_operator = from->join_operator;
newnode->left_operator = from->left_operator;
newnode->right_operator = from->right_operator;
newnode->left_type = from->left_type;
newnode->right_type = from->right_type;
return newnode; return newnode;
} }
...@@ -1315,83 +1234,16 @@ _copyRestrictInfo(RestrictInfo *from) ...@@ -1315,83 +1234,16 @@ _copyRestrictInfo(RestrictInfo *from)
* ---------------- * ----------------
*/ */
Node_Copy(from, newnode, clause); Node_Copy(from, newnode, clause);
newnode->selectivity = from->selectivity; newnode->selectivity = from->selectivity;
Node_Copy(from, newnode, subclauseindices);
Node_Copy(from, newnode, indexids); newnode->mergejoinoperator = from->mergejoinoperator;
Node_Copy(from, newnode, mergejoinorder); newnode->left_sortop = from->left_sortop;
newnode->right_sortop = from->right_sortop;
newnode->hashjoinoperator = from->hashjoinoperator; newnode->hashjoinoperator = from->hashjoinoperator;
return newnode; return newnode;
} }
/* ----------------
* CopyJoinMethodFields
*
* This function copies the fields of the JoinMethod node. It is used by
* all the copy functions for classes which inherit from JoinMethod.
* ----------------
*/
static void
CopyJoinMethodFields(JoinMethod *from, JoinMethod *newnode)
{
Node_Copy(from, newnode, jmkeys);
Node_Copy(from, newnode, clauses);
return;
}
/* ----------------
* _copyJoinMethod
* ----------------
*/
static JoinMethod *
_copyJoinMethod(JoinMethod *from)
{
JoinMethod *newnode = makeNode(JoinMethod);
CopyJoinMethodFields(from, newnode);
return newnode;
}
/* ----------------
* _copyHashInfo
* ----------------
*/
static HashInfo *
_copyHashInfo(HashInfo *from)
{
HashInfo *newnode = makeNode(HashInfo);
/* ----------------
* copy remainder of node
* ----------------
*/
CopyJoinMethodFields((JoinMethod *) from, (JoinMethod *) newnode);
newnode->hashop = from->hashop;
return newnode;
}
/* ----------------
* _copyMergeInfo
* ----------------
*/
static MergeInfo *
_copyMergeInfo(MergeInfo *from)
{
MergeInfo *newnode = makeNode(MergeInfo);
/* ----------------
* copy remainder of node
* ----------------
*/
CopyJoinMethodFields((JoinMethod *) from, (JoinMethod *) newnode);
Node_Copy(from, newnode, m_ordering);
return newnode;
}
/* ---------------- /* ----------------
* _copyJoinInfo * _copyJoinInfo
* ---------------- * ----------------
...@@ -1408,9 +1260,6 @@ _copyJoinInfo(JoinInfo *from) ...@@ -1408,9 +1260,6 @@ _copyJoinInfo(JoinInfo *from)
newnode->unjoined_relids = listCopy(from->unjoined_relids); newnode->unjoined_relids = listCopy(from->unjoined_relids);
Node_Copy(from, newnode, jinfo_restrictinfo); Node_Copy(from, newnode, jinfo_restrictinfo);
newnode->mergejoinable = from->mergejoinable;
newnode->hashjoinable = from->hashjoinable;
return newnode; return newnode;
} }
...@@ -1756,27 +1605,12 @@ copyObject(void *from) ...@@ -1756,27 +1605,12 @@ copyObject(void *from)
case T_HashPath: case T_HashPath:
retval = _copyHashPath(from); retval = _copyHashPath(from);
break; break;
case T_OrderKey: case T_PathKeyItem:
retval = _copyOrderKey(from); retval = _copyPathKeyItem(from);
break;
case T_JoinKey:
retval = _copyJoinKey(from);
break;
case T_MergeOrder:
retval = _copyMergeOrder(from);
break; break;
case T_RestrictInfo: case T_RestrictInfo:
retval = _copyRestrictInfo(from); retval = _copyRestrictInfo(from);
break; break;
case T_JoinMethod:
retval = _copyJoinMethod(from);
break;
case T_HashInfo:
retval = _copyHashInfo(from);
break;
case T_MergeInfo:
retval = _copyMergeInfo(from);
break;
case T_JoinInfo: case T_JoinInfo:
retval = _copyJoinInfo(from); retval = _copyJoinInfo(from);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.46 1999/08/09 06:20:24 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.47 1999/08/16 02:17:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -264,15 +264,15 @@ _equalRelOptInfo(RelOptInfo *a, RelOptInfo *b) ...@@ -264,15 +264,15 @@ _equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
/* We treat RelOptInfos as equal if they refer to the same base rels /* We treat RelOptInfos as equal if they refer to the same base rels
* joined in the same order. Is this sufficient? * joined in the same order. Is this sufficient?
*/ */
return equal(a->relids, b->relids); return equali(a->relids, b->relids);
} }
static bool static bool
_equalJoinMethod(JoinMethod *a, JoinMethod *b) _equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
{ {
if (!equal(a->jmkeys, b->jmkeys)) if (a->sortop != b->sortop)
return false; return false;
if (!equal(a->clauses, b->clauses)) if (!equal(a->key, b->key))
return false; return false;
return true; return true;
} }
...@@ -282,48 +282,13 @@ _equalPath(Path *a, Path *b) ...@@ -282,48 +282,13 @@ _equalPath(Path *a, Path *b)
{ {
if (a->pathtype != b->pathtype) if (a->pathtype != b->pathtype)
return false; return false;
if (a->parent != b->parent) /* should this use equal() ? */ if (!equal(a->parent, b->parent))
return false; return false;
/* do not check path_cost, since it may not be set yet, and being /* do not check path_cost, since it may not be set yet, and being
* a float there are roundoff error issues anyway... * a float there are roundoff error issues anyway...
*/ */
/* XXX this should probably be in an _equalPathOrder function... */
if (a->pathorder->ordtype != b->pathorder->ordtype)
return false;
if (a->pathorder->ordtype == SORTOP_ORDER)
{
if (a->pathorder->ord.sortop == NULL ||
b->pathorder->ord.sortop == NULL)
{
if (a->pathorder->ord.sortop != b->pathorder->ord.sortop)
return false;
}
else
{
int i = 0;
while (a->pathorder->ord.sortop[i] != 0)
{
if (a->pathorder->ord.sortop[i] != b->pathorder->ord.sortop[i])
return false;
i++;
}
if (b->pathorder->ord.sortop[i] != 0)
return false;
}
}
else
{
if (!equal(a->pathorder->ord.merge, b->pathorder->ord.merge))
return false;
}
if (!equal(a->pathkeys, b->pathkeys)) if (!equal(a->pathkeys, b->pathkeys))
return false; return false;
/* do not check outerjoincost either */
if (!equali(a->joinid, b->joinid))
return false;
return true; return true;
} }
...@@ -336,12 +301,13 @@ _equalIndexPath(IndexPath *a, IndexPath *b) ...@@ -336,12 +301,13 @@ _equalIndexPath(IndexPath *a, IndexPath *b)
return false; return false;
if (!equal(a->indexqual, b->indexqual)) if (!equal(a->indexqual, b->indexqual))
return false; return false;
/* We do not need to check indexkeys */ if (!equali(a->joinrelids, b->joinrelids))
return false;
return true; return true;
} }
static bool static bool
_equalNestPath(NestPath *a, NestPath *b) _equalJoinPath(JoinPath *a, JoinPath *b)
{ {
if (!_equalPath((Path *) a, (Path *) b)) if (!_equalPath((Path *) a, (Path *) b))
return false; return false;
...@@ -355,65 +321,33 @@ _equalNestPath(NestPath *a, NestPath *b) ...@@ -355,65 +321,33 @@ _equalNestPath(NestPath *a, NestPath *b)
} }
static bool static bool
_equalMergePath(MergePath *a, MergePath *b) _equalNestPath(NestPath *a, NestPath *b)
{
if (!_equalNestPath((NestPath *) a, (NestPath *) b))
return false;
if (!equal(a->path_mergeclauses, b->path_mergeclauses))
return false;
if (!equal(a->outersortkeys, b->outersortkeys))
return false;
if (!equal(a->innersortkeys, b->innersortkeys))
return false;
return true;
}
static bool
_equalHashPath(HashPath *a, HashPath *b)
{
if (!_equalNestPath((NestPath *) a, (NestPath *) b))
return false;
if (!equal(a->path_hashclauses, b->path_hashclauses))
return false;
if (!equal(a->outerhashkeys, b->outerhashkeys))
return false;
if (!equal(a->innerhashkeys, b->innerhashkeys))
return false;
return true;
}
static bool
_equalJoinKey(JoinKey *a, JoinKey *b)
{ {
if (!equal(a->outer, b->outer)) if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
return false;
if (!equal(a->inner, b->inner))
return false; return false;
return true; return true;
} }
static bool static bool
_equalMergeOrder(MergeOrder *a, MergeOrder *b) _equalMergePath(MergePath *a, MergePath *b)
{ {
if (a->join_operator != b->join_operator) if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
return false;
if (a->left_operator != b->left_operator)
return false; return false;
if (a->right_operator != b->right_operator) if (!equal(a->path_mergeclauses, b->path_mergeclauses))
return false; return false;
if (a->left_type != b->left_type) if (!equal(a->outersortkeys, b->outersortkeys))
return false; return false;
if (a->right_type != b->right_type) if (!equal(a->innersortkeys, b->innersortkeys))
return false; return false;
return true; return true;
} }
static bool static bool
_equalHashInfo(HashInfo *a, HashInfo *b) _equalHashPath(HashPath *a, HashPath *b)
{ {
if (!_equalJoinMethod((JoinMethod *) a, (JoinMethod *) b)) if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
return false; return false;
if (a->hashop != b->hashop) if (!equal(a->path_hashclauses, b->path_hashclauses))
return false; return false;
return true; return true;
} }
...@@ -458,30 +392,32 @@ _equalSubPlan(SubPlan *a, SubPlan *b) ...@@ -458,30 +392,32 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
} }
static bool static bool
_equalJoinInfo(JoinInfo *a, JoinInfo *b) _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
{ {
if (!equal(a->unjoined_relids, b->unjoined_relids)) if (!equal(a->clause, b->clause))
return false; return false;
if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo)) /* do not check selectivity because of roundoff error worries */
if (!equal(a->subclauseindices, b->subclauseindices))
return false;
if (a->mergejoinoperator != b->mergejoinoperator)
return false; return false;
if (a->mergejoinable != b->mergejoinable) if (a->left_sortop != b->left_sortop)
return false; return false;
if (a->hashjoinable != b->hashjoinable) if (a->right_sortop != b->right_sortop)
return false;
if (a->hashjoinoperator != b->hashjoinoperator)
return false; return false;
return true; return true;
} }
static bool static bool
_equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) _equalJoinInfo(JoinInfo *a, JoinInfo *b)
{ {
if (!equal(a->clause, b->clause)) if (!equali(a->unjoined_relids, b->unjoined_relids))
return false;
/* do not check selectivity because of roundoff error worries */
if (!equal(a->mergejoinorder, b->mergejoinorder))
return false; return false;
if (a->hashjoinoperator != b->hashjoinoperator) if (!equal(a->jinfo_restrictinfo, b->jinfo_restrictinfo))
return false; return false;
return equal(a->indexids, b->indexids); return true;
} }
static bool static bool
...@@ -778,8 +714,8 @@ equal(void *a, void *b) ...@@ -778,8 +714,8 @@ equal(void *a, void *b)
case T_RelOptInfo: case T_RelOptInfo:
retval = _equalRelOptInfo(a, b); retval = _equalRelOptInfo(a, b);
break; break;
case T_JoinMethod: case T_PathKeyItem:
retval = _equalJoinMethod(a, b); retval = _equalPathKeyItem(a, b);
break; break;
case T_Path: case T_Path:
retval = _equalPath(a, b); retval = _equalPath(a, b);
...@@ -796,15 +732,6 @@ equal(void *a, void *b) ...@@ -796,15 +732,6 @@ equal(void *a, void *b)
case T_HashPath: case T_HashPath:
retval = _equalHashPath(a, b); retval = _equalHashPath(a, b);
break; break;
case T_JoinKey:
retval = _equalJoinKey(a, b);
break;
case T_MergeOrder:
retval = _equalMergeOrder(a, b);
break;
case T_HashInfo:
retval = _equalHashInfo(a, b);
break;
case T_IndexScan: case T_IndexScan:
retval = _equalIndexScan(a, b); retval = _equalIndexScan(a, b);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.24 1999/07/27 03:51:08 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.25 1999/08/16 02:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -706,6 +706,9 @@ _freeRelOptInfo(RelOptInfo *node) ...@@ -706,6 +706,9 @@ _freeRelOptInfo(RelOptInfo *node)
freeObject(node->targetlist); freeObject(node->targetlist);
freeObject(node->pathlist); freeObject(node->pathlist);
/* is this right? cheapestpath will typically be a pointer into
* pathlist, won't it?
*/
freeObject(node->cheapestpath); freeObject(node->cheapestpath);
if (node->classlist) if (node->classlist)
...@@ -714,11 +717,11 @@ _freeRelOptInfo(RelOptInfo *node) ...@@ -714,11 +717,11 @@ _freeRelOptInfo(RelOptInfo *node)
if (node->indexkeys) if (node->indexkeys)
pfree(node->indexkeys); pfree(node->indexkeys);
freeObject(node->indpred);
if (node->ordering) if (node->ordering)
pfree(node->ordering); pfree(node->ordering);
freeObject(node->indpred);
freeObject(node->restrictinfo); freeObject(node->restrictinfo);
freeObject(node->joininfo); freeObject(node->joininfo);
freeObject(node->innerjoin); freeObject(node->innerjoin);
...@@ -736,20 +739,9 @@ _freeRelOptInfo(RelOptInfo *node) ...@@ -736,20 +739,9 @@ _freeRelOptInfo(RelOptInfo *node)
static void static void
FreePathFields(Path *node) FreePathFields(Path *node)
{ {
if (node->pathorder->ordtype == SORTOP_ORDER) /* we do NOT free the parent; it doesn't belong to the Path */
{
if (node->pathorder->ord.sortop)
pfree(node->pathorder->ord.sortop);
}
else
freeObject(node->pathorder->ord.merge);
pfree(node->pathorder); /* is it an object, but we don't have
* separate free for it */
freeObject(node->pathkeys); freeObject(node->pathkeys);
freeList(node->joinid);
} }
/* ---------------- /* ----------------
...@@ -783,22 +775,20 @@ _freeIndexPath(IndexPath *node) ...@@ -783,22 +775,20 @@ _freeIndexPath(IndexPath *node)
*/ */
freeList(node->indexid); freeList(node->indexid);
freeObject(node->indexqual); freeObject(node->indexqual);
freeList(node->joinrelids);
if (node->indexkeys)
pfree(node->indexkeys);
pfree(node); pfree(node);
} }
/* ---------------- /* ----------------
* FreeNestPathFields * FreeJoinPathFields
* *
* This function frees the fields of the NestPath node. It is used by * This function frees the fields of the JoinPath node. It is used by
* all the free functions for classes which inherit node NestPath. * all the free functions for classes which inherit node JoinPath.
* ---------------- * ----------------
*/ */
static void static void
FreeNestPathFields(NestPath *node) FreeJoinPathFields(JoinPath *node)
{ {
freeObject(node->pathinfo); freeObject(node->pathinfo);
freeObject(node->outerjoinpath); freeObject(node->outerjoinpath);
...@@ -817,7 +807,7 @@ _freeNestPath(NestPath *node) ...@@ -817,7 +807,7 @@ _freeNestPath(NestPath *node)
* ---------------- * ----------------
*/ */
FreePathFields((Path *) node); FreePathFields((Path *) node);
FreeNestPathFields(node); FreeJoinPathFields((JoinPath *) node);
pfree(node); pfree(node);
} }
...@@ -834,7 +824,7 @@ _freeMergePath(MergePath *node) ...@@ -834,7 +824,7 @@ _freeMergePath(MergePath *node)
* ---------------- * ----------------
*/ */
FreePathFields((Path *) node); FreePathFields((Path *) node);
FreeNestPathFields((NestPath *) node); FreeJoinPathFields((JoinPath *) node);
/* ---------------- /* ----------------
* free the remainder of the node * free the remainder of the node
...@@ -859,60 +849,33 @@ _freeHashPath(HashPath *node) ...@@ -859,60 +849,33 @@ _freeHashPath(HashPath *node)
* ---------------- * ----------------
*/ */
FreePathFields((Path *) node); FreePathFields((Path *) node);
FreeNestPathFields((NestPath *) node); FreeJoinPathFields((JoinPath *) node);
/* ---------------- /* ----------------
* free remainder of node * free remainder of node
* ---------------- * ----------------
*/ */
freeObject(node->path_hashclauses); freeObject(node->path_hashclauses);
freeObject(node->outerhashkeys);
freeObject(node->innerhashkeys);
pfree(node);
}
/* ----------------
* _freeOrderKey
* ----------------
*/
static void
_freeOrderKey(OrderKey *node)
{
pfree(node); pfree(node);
} }
/* ---------------- /* ----------------
* _freeJoinKey * _freePathKeyItem
* ---------------- * ----------------
*/ */
static void static void
_freeJoinKey(JoinKey *node) _freePathKeyItem(PathKeyItem *node)
{ {
/* ---------------- /* ----------------
* free remainder of node * free remainder of node
* ---------------- * ----------------
*/ */
freeObject(node->outer); freeObject(node->key);
freeObject(node->inner);
pfree(node); pfree(node);
} }
/* ----------------
* _freeMergeOrder
* ----------------
*/
static void
_freeMergeOrder(MergeOrder *node)
{
/* ----------------
* free remainder of node
* ----------------
*/
pfree(node);
}
/* ---------------- /* ----------------
* _freeRestrictInfo * _freeRestrictInfo
...@@ -926,68 +889,10 @@ _freeRestrictInfo(RestrictInfo *node) ...@@ -926,68 +889,10 @@ _freeRestrictInfo(RestrictInfo *node)
* ---------------- * ----------------
*/ */
freeObject(node->clause); freeObject(node->clause);
freeObject(node->indexids); /* this is certainly wrong? index RelOptInfos don't belong to
freeObject(node->mergejoinorder); * RestrictInfo...
pfree(node);
}
/* ----------------
* FreeJoinMethodFields
*
* This function frees the fields of the JoinMethod node. It is used by
* all the free functions for classes which inherit node JoinMethod.
* ----------------
*/
static void
FreeJoinMethodFields(JoinMethod *node)
{
freeObject(node->jmkeys);
freeObject(node->clauses);
return;
}
/* ----------------
* _freeJoinMethod
* ----------------
*/
static void
_freeJoinMethod(JoinMethod *node)
{
FreeJoinMethodFields(node);
pfree(node);
}
/* ----------------
* _freeHInfo
* ----------------
*/
static void
_freeHashInfo(HashInfo *node)
{
/* ----------------
* free remainder of node
* ----------------
*/
FreeJoinMethodFields((JoinMethod *) node);
pfree(node);
}
/* ----------------
* _freeMInfo
* ----------------
*/
static void
_freeMergeInfo(MergeInfo *node)
{
/* ----------------
* free remainder of node
* ----------------
*/ */
FreeJoinMethodFields((JoinMethod *) node); freeObject(node->subclauseindices);
freeObject(node->m_ordering);
pfree(node); pfree(node);
} }
...@@ -1279,27 +1184,12 @@ freeObject(void *node) ...@@ -1279,27 +1184,12 @@ freeObject(void *node)
case T_HashPath: case T_HashPath:
_freeHashPath(node); _freeHashPath(node);
break; break;
case T_OrderKey: case T_PathKeyItem:
_freeOrderKey(node); _freePathKeyItem(node);
break;
case T_JoinKey:
_freeJoinKey(node);
break;
case T_MergeOrder:
_freeMergeOrder(node);
break; break;
case T_RestrictInfo: case T_RestrictInfo:
_freeRestrictInfo(node); _freeRestrictInfo(node);
break; break;
case T_JoinMethod:
_freeJoinMethod(node);
break;
case T_HashInfo:
_freeHashInfo(node);
break;
case T_MergeInfo:
_freeMergeInfo(node);
break;
case T_JoinInfo: case T_JoinInfo:
_freeJoinInfo(node); _freeJoinInfo(node);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.26 1999/08/14 19:29:35 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.27 1999/08/16 02:17:42 tgl Exp $
* *
* NOTES * NOTES
* XXX a few of the following functions are duplicated to handle * XXX a few of the following functions are duplicated to handle
...@@ -447,6 +447,31 @@ intLispRemove(int elem, List *list) ...@@ -447,6 +447,31 @@ intLispRemove(int elem, List *list)
#endif #endif
/*
* ltruncate
* Truncate a list to n elements.
* Does nothing if n >= length(list).
* NB: the list is modified in-place!
*/
List *
ltruncate(int n, List *list)
{
List *ptr;
if (n <= 0)
return NIL; /* truncate to zero length */
foreach(ptr, list)
{
if (--n == 0)
{
lnext(ptr) = NIL;
break;
}
}
return list;
}
/* /*
* set_difference * set_difference
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.10 1999/07/17 20:17:07 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.11 1999/08/16 02:17:42 tgl Exp $
* *
* HISTORY * HISTORY
* Andrew Yu Oct 20, 1994 file creation * Andrew Yu Oct 20, 1994 file creation
...@@ -32,7 +32,7 @@ newNode(Size size, NodeTag tag) ...@@ -32,7 +32,7 @@ newNode(Size size, NodeTag tag)
{ {
Node *newNode; Node *newNode;
Assert(size >= 4); /* need the tag, at least */ Assert(size >= sizeof(Node)); /* need the tag, at least */
newNode = (Node *) palloc(size); newNode = (Node *) palloc(size);
MemSet((char *) newNode, 0, size); MemSet((char *) newNode, 0, size);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: outfuncs.c,v 1.92 1999/08/09 06:20:24 momjian Exp $ * $Id: outfuncs.c,v 1.93 1999/08/16 02:17:42 tgl Exp $
* *
* NOTES * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -880,35 +880,6 @@ _outRowMark(StringInfo str, RowMark *node) ...@@ -880,35 +880,6 @@ _outRowMark(StringInfo str, RowMark *node)
appendStringInfo(str, " ROWMARK :rti %u :info %u", node->rti, node->info); appendStringInfo(str, " ROWMARK :rti %u :info %u", node->rti, node->info);
} }
/*
* Path is a subclass of Node.
*/
static void
_outPathOrder(StringInfo str, PathOrder *node)
{
appendStringInfo(str, " PATHORDER :ordtype %d ",
node->ordtype);
if (node->ordtype == SORTOP_ORDER)
{
int i;
appendStringInfo(str, " :sortop ");
if (node->ord.sortop == NULL)
appendStringInfo(str, "<>");
else
{
for (i = 0; node->ord.sortop[i] != 0; i++)
appendStringInfo(str, " %d ", node->ord.sortop[i]);
appendStringInfo(str, " %d ", 0);
}
}
else
{
appendStringInfo(str, " :merge ");
_outNode(str, node->ord.merge);
}
}
/* /*
* Path is a subclass of Node. * Path is a subclass of Node.
*/ */
...@@ -919,9 +890,6 @@ _outPath(StringInfo str, Path *node) ...@@ -919,9 +890,6 @@ _outPath(StringInfo str, Path *node)
node->pathtype, node->pathtype,
node->path_cost); node->path_cost);
_outNode(str, node->pathkeys); _outNode(str, node->pathkeys);
appendStringInfo(str, " :pathorder ");
_outNode(str, node->pathorder);
} }
/* /*
...@@ -936,14 +904,14 @@ _outIndexPath(StringInfo str, IndexPath *node) ...@@ -936,14 +904,14 @@ _outIndexPath(StringInfo str, IndexPath *node)
node->path.path_cost); node->path.path_cost);
_outNode(str, node->path.pathkeys); _outNode(str, node->path.pathkeys);
appendStringInfo(str, " :pathorder ");
_outNode(str, node->path.pathorder);
appendStringInfo(str, " :indexid "); appendStringInfo(str, " :indexid ");
_outIntList(str, node->indexid); _outIntList(str, node->indexid);
appendStringInfo(str, " :indexqual "); appendStringInfo(str, " :indexqual ");
_outNode(str, node->indexqual); _outNode(str, node->indexqual);
appendStringInfo(str, " :joinrelids ");
_outIntList(str, node->joinrelids);
} }
/* /*
...@@ -958,9 +926,6 @@ _outNestPath(StringInfo str, NestPath *node) ...@@ -958,9 +926,6 @@ _outNestPath(StringInfo str, NestPath *node)
node->path.path_cost); node->path.path_cost);
_outNode(str, node->path.pathkeys); _outNode(str, node->path.pathkeys);
appendStringInfo(str, " :pathorder ");
_outNode(str, node->path.pathorder);
appendStringInfo(str, " :pathinfo "); appendStringInfo(str, " :pathinfo ");
_outNode(str, node->pathinfo); _outNode(str, node->pathinfo);
...@@ -970,11 +935,9 @@ _outNestPath(StringInfo str, NestPath *node) ...@@ -970,11 +935,9 @@ _outNestPath(StringInfo str, NestPath *node)
*/ */
appendStringInfo(str, appendStringInfo(str,
" :outerjoinpath @ 0x%x :innerjoinpath @ 0x%x :outjoincost %f :joinid ", " :outerjoinpath @ 0x%x :innerjoinpath @ 0x%x ",
(int) node->outerjoinpath, (int) node->outerjoinpath,
(int) node->innerjoinpath, (int) node->innerjoinpath);
node->path.outerjoincost);
_outIntList(str, node->path.joinid);
} }
/* /*
...@@ -989,9 +952,6 @@ _outMergePath(StringInfo str, MergePath *node) ...@@ -989,9 +952,6 @@ _outMergePath(StringInfo str, MergePath *node)
node->jpath.path.path_cost); node->jpath.path.path_cost);
_outNode(str, node->jpath.path.pathkeys); _outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :pathorder ");
_outNode(str, node->jpath.path.pathorder);
appendStringInfo(str, " :pathinfo "); appendStringInfo(str, " :pathinfo ");
_outNode(str, node->jpath.pathinfo); _outNode(str, node->jpath.pathinfo);
...@@ -1001,11 +961,9 @@ _outMergePath(StringInfo str, MergePath *node) ...@@ -1001,11 +961,9 @@ _outMergePath(StringInfo str, MergePath *node)
*/ */
appendStringInfo(str, appendStringInfo(str,
" :outerjoinpath @ 0x%x :innerjoinpath @ 0x%x :outerjoincost %f :joinid ", " :outerjoinpath @ 0x%x :innerjoinpath @ 0x%x ",
(int) node->jpath.outerjoinpath, (int) node->jpath.outerjoinpath,
(int) node->jpath.innerjoinpath, (int) node->jpath.innerjoinpath);
(int) node->jpath.path.outerjoincost);
_outIntList(str, node->jpath.path.joinid);
appendStringInfo(str, " :path_mergeclauses "); appendStringInfo(str, " :path_mergeclauses ");
_outNode(str, node->path_mergeclauses); _outNode(str, node->path_mergeclauses);
...@@ -1029,9 +987,6 @@ _outHashPath(StringInfo str, HashPath *node) ...@@ -1029,9 +987,6 @@ _outHashPath(StringInfo str, HashPath *node)
node->jpath.path.path_cost); node->jpath.path.path_cost);
_outNode(str, node->jpath.path.pathkeys); _outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :pathorder ");
_outNode(str, node->jpath.path.pathorder);
appendStringInfo(str, " :pathinfo "); appendStringInfo(str, " :pathinfo ");
_outNode(str, node->jpath.pathinfo); _outNode(str, node->jpath.pathinfo);
...@@ -1041,64 +996,23 @@ _outHashPath(StringInfo str, HashPath *node) ...@@ -1041,64 +996,23 @@ _outHashPath(StringInfo str, HashPath *node)
*/ */
appendStringInfo(str, appendStringInfo(str,
" :outerjoinpath @ 0x%x :innerjoinpath @ 0x%x :outerjoincost %f :joinid ", " :outerjoinpath @ 0x%x :innerjoinpath @ 0x%x ",
(int) node->jpath.outerjoinpath, (int) node->jpath.outerjoinpath,
(int) node->jpath.innerjoinpath, (int) node->jpath.innerjoinpath);
node->jpath.path.outerjoincost);
_outIntList(str, node->jpath.path.joinid);
appendStringInfo(str, " :path_hashclauses "); appendStringInfo(str, " :path_hashclauses ");
_outNode(str, node->path_hashclauses); _outNode(str, node->path_hashclauses);
appendStringInfo(str, " :outerhashkeys ");
_outNode(str, node->outerhashkeys);
appendStringInfo(str, " :innerhashkeys ");
_outNode(str, node->innerhashkeys);
}
/*
* OrderKey is a subclass of Node.
*/
static void
_outOrderKey(StringInfo str, OrderKey *node)
{
appendStringInfo(str,
" ORDERKEY :attribute_number %d :array_index %d ",
node->attribute_number,
node->array_index);
} }
/* /*
* JoinKey is a subclass of Node. * PathKeyItem is a subclass of Node.
*/ */
static void static void
_outJoinKey(StringInfo str, JoinKey *node) _outPathKeyItem(StringInfo str, PathKeyItem *node)
{ {
appendStringInfo(str, " JOINKEY :outer "); appendStringInfo(str, " PATHKEYITEM :sortop %u :key ",
_outNode(str, node->outer); node->sortop);
_outNode(str, node->key);
appendStringInfo(str, " :inner ");
_outNode(str, node->inner);
}
/*
* MergeOrder is a subclass of Node.
*/
static void
_outMergeOrder(StringInfo str, MergeOrder *node)
{
appendStringInfo(str,
" MERGEORDER :join_operator %u :left_operator %u :right_operator %u ",
node->join_operator,
node->left_operator,
node->right_operator);
appendStringInfo(str,
" :left_type %u :right_type %u ",
node->left_type,
node->right_type);
} }
/* /*
...@@ -1111,41 +1025,14 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) ...@@ -1111,41 +1025,14 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
_outNode(str, node->clause); _outNode(str, node->clause);
appendStringInfo(str, appendStringInfo(str,
" :selectivity %f :indexids ", " :selectivity %f :subclauseindices ",
node->selectivity); node->selectivity);
_outNode(str, node->indexids); _outNode(str, node->subclauseindices);
appendStringInfo(str, " :mergejoinorder ");
_outNode(str, node->mergejoinorder);
appendStringInfo(str, " :mergejoinoperator %u ", node->mergejoinoperator);
appendStringInfo(str, " :left_sortop %u ", node->left_sortop);
appendStringInfo(str, " :right_sortop %u ", node->right_sortop);
appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator); appendStringInfo(str, " :hashjoinoperator %u ", node->hashjoinoperator);
}
/*
* JoinMethod is a subclass of Node.
*/
static void
_outJoinMethod(StringInfo str, JoinMethod *node)
{
appendStringInfo(str, " JOINMETHOD :jmkeys ");
_outNode(str, node->jmkeys);
appendStringInfo(str, " :clauses ");
_outNode(str, node->clauses);
}
/*
* HashInfo is a subclass of JoinMethod.
*/
static void
_outHashInfo(StringInfo str, HashInfo *node)
{
appendStringInfo(str, " HASHINFO :hashop %u :jmkeys ", node->hashop);
_outNode(str, node->jmethod.jmkeys);
appendStringInfo(str, " :clauses ");
_outNode(str, node->jmethod.clauses);
} }
/* /*
...@@ -1159,10 +1046,6 @@ _outJoinInfo(StringInfo str, JoinInfo *node) ...@@ -1159,10 +1046,6 @@ _outJoinInfo(StringInfo str, JoinInfo *node)
appendStringInfo(str, " :jinfo_restrictinfo "); appendStringInfo(str, " :jinfo_restrictinfo ");
_outNode(str, node->jinfo_restrictinfo); _outNode(str, node->jinfo_restrictinfo);
appendStringInfo(str, " :mergejoinable %s :hashjoinable %s ",
node->mergejoinable ? "true" : "false",
node->hashjoinable ? "true" : "false");
} }
/* /*
...@@ -1541,9 +1424,6 @@ _outNode(StringInfo str, void *obj) ...@@ -1541,9 +1424,6 @@ _outNode(StringInfo str, void *obj)
case T_RowMark: case T_RowMark:
_outRowMark(str, obj); _outRowMark(str, obj);
break; break;
case T_PathOrder:
_outPathOrder(str, obj);
break;
case T_Path: case T_Path:
_outPath(str, obj); _outPath(str, obj);
break; break;
...@@ -1559,24 +1439,12 @@ _outNode(StringInfo str, void *obj) ...@@ -1559,24 +1439,12 @@ _outNode(StringInfo str, void *obj)
case T_HashPath: case T_HashPath:
_outHashPath(str, obj); _outHashPath(str, obj);
break; break;
case T_OrderKey: case T_PathKeyItem:
_outOrderKey(str, obj); _outPathKeyItem(str, obj);
break;
case T_JoinKey:
_outJoinKey(str, obj);
break;
case T_MergeOrder:
_outMergeOrder(str, obj);
break; break;
case T_RestrictInfo: case T_RestrictInfo:
_outRestrictInfo(str, obj); _outRestrictInfo(str, obj);
break; break;
case T_JoinMethod:
_outJoinMethod(str, obj);
break;
case T_HashInfo:
_outHashInfo(str, obj);
break;
case T_JoinInfo: case T_JoinInfo:
_outJoinInfo(str, obj); _outJoinInfo(str, obj);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.31 1999/07/17 20:17:08 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.32 1999/08/16 02:17:43 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -204,7 +204,7 @@ print_expr(Node *expr, List *rtable) ...@@ -204,7 +204,7 @@ print_expr(Node *expr, List *rtable)
/* /*
* print_pathkeys - * print_pathkeys -
* pathkeys list of list of Var's * pathkeys list of list of PathKeyItems
*/ */
void void
print_pathkeys(List *pathkeys, List *rtable) print_pathkeys(List *pathkeys, List *rtable)
...@@ -220,9 +220,9 @@ print_pathkeys(List *pathkeys, List *rtable) ...@@ -220,9 +220,9 @@ print_pathkeys(List *pathkeys, List *rtable)
printf("("); printf("(");
foreach(k, pathkey) foreach(k, pathkey)
{ {
Node *var = lfirst(k); PathKeyItem *item = lfirst(k);
print_expr(var, rtable); print_expr(item->key, rtable);
if (lnext(k)) if (lnext(k))
printf(", "); printf(", ");
} }
......
This diff is collapsed.
Summary Summary
------- -------
The optimizer generates optimial query plans by doing several steps: The optimizer generates optimal query plans by doing a more-or-less
exhaustive search through the ways of executing the query. During
1) Take each relation in a query, and make a RelOptInfo structure for the planning/optimizing process, we build "Path" trees representing
it. Find each way of accessing the relation, called a Path, including the different ways of doing a query. We select the cheapest Path
sequential and index scans, and add it to RelOptInfo.pathlist. Also that generates the desired relation and turn it into a Plan to pass
create RelOptInfo.joininfo that lists all the joins that involve this to the executor. (There is pretty much a one-to-one correspondence
relation. For example, the WHERE clause "tab1.col1 = tab2.col1" between the Path and Plan trees, but Path nodes omit info that won't
generates a JoinInfo for tab1 listing tab2 as an unjoined relation, and be needed during planning, and include info needed for planning that
tab2's joininfo shows tab1 as an unjoined relation. won't be needed by the executor.)
2) Join each RelOptInfo to other RelOptInfo as specified in The best Path tree is found by a recursive process:
RelOptInfo.joininfo. At this point each RelOptInfo is a single
relation, so you are joining every relation to the other relations as 1) Take each base relation in the query, and make a RelOptInfo structure
joined in the WHERE clause. for it. Find each potentially useful way of accessing the relation,
including sequential and index scans, and make a Path representing that
Joins occur using two RelOptInfos. One is outer, the other inner. way. All the Paths made for a given relation are placed in its
Outers drive lookups of values in the inner. In a nested loop, lookups RelOptInfo.pathlist. (Actually, we discard Paths that are obviously
of values in the inner occur by scanning to find each matching inner inferior alternatives before they ever get into the pathlist --- what
row. In a mergejoin, inner and outer rows are ordered, and are accessed ends up in the pathlist is the cheapest way of generating each potentially
in order, so only one scan of inner is required to perform the entire useful sort ordering of the relation.) Also create RelOptInfo.joininfo
join. In a hashjoin, inner rows are hashed for lookups. nodes that list all the joins that involve this relation. For example,
the WHERE clause "tab1.col1 = tab2.col1" generates a JoinInfo for tab1
Each unique join combination becomes a new RelOptInfo. The RelOptInfo listing tab2 as an unjoined relation, and also one for tab2 showing tab1
is now the joining of two relations. RelOptInfo.pathlist are various as an unjoined relation.
paths to create the joined result, having different orderings depending
on the join method used. 2) Consider joining each RelOptInfo to each other RelOptInfo specified in
its RelOptInfo.joininfo, and generate a Path for each possible join method.
3) At this point, every RelOptInfo is joined to each other again, with At this stage each input RelOptInfo is a single relation, so we are joining
a new relation added to each RelOptInfo. This continues until all every relation to the other relations as joined in the WHERE clause. We
relations have been joined into one RelOptInfo, and the cheapest Path is generate a new "join" RelOptInfo for each possible combination of two
chosen. "base" RelOptInfos, and put all the plausible paths for that combination
into the join RelOptInfo's pathlist. (As before, we keep only the cheapest
alternative that generates any one sort ordering of the result.)
Joins always occur using two RelOptInfos. One is outer, the other inner.
Outers drive lookups of values in the inner. In a nested loop, lookups of
values in the inner occur by scanning the inner path once per outer tuple
to find each matching inner row. In a mergejoin, inner and outer rows are
ordered, and are accessed in order, so only one scan is required to perform
the entire join: both inner and outer paths are scanned in-sync. (There's
not a lot of difference between inner and outer in a mergejoin...) In a
hashjoin, the inner is scanned first and all its rows are entered in a
hashtable, then the outer is scanned and for each row we lookup the join
key in the hashtable.
A Path for a join relation is actually a tree structure, with the top
Path node representing the join method. It has left and right subpaths
that represent the scan methods used for the two input relations.
3) If we only had two base relations, we are done: we just pick the
cheapest path for the join RelOptInfo. If we had more than two, we now
need to consider ways of joining join RelOptInfos to each other to make
join RelOptInfos that represent more than two base relations. This process
is repeated until we have finally built a RelOptInfo that represents all
the base relations in the query. Then we pick its cheapest Path.
For example:
SELECT * SELECT *
FROM tab1, tab2, tab3, tab4 FROM tab1, tab2, tab3, tab4
...@@ -67,8 +93,11 @@ Optimizer Functions ...@@ -67,8 +93,11 @@ Optimizer Functions
These directories take the Query structure returned by the parser, and These directories take the Query structure returned by the parser, and
generate a plan used by the executor. The /plan directory generates the generate a plan used by the executor. The /plan directory generates the
plan, the /path generates all possible ways to join the tables, and actual output plan, the /path code generates all possible ways to join the
/prep handles special cases like inheritance. /utils is utility stuff. tables, and /prep handles special cases like inheritance. /util is utility
stuff. /geqo is the separate "genetic optimization" planner --- it does
a semi-random search rather than exhaustively considering all possible
join trees.
planner() planner()
handle inheritance by processing separately handle inheritance by processing separately
...@@ -136,8 +165,8 @@ planner() ...@@ -136,8 +165,8 @@ planner()
Optimizer Structures Optimizer Data Structures
-------------------- -------------------------
RelOptInfo - a relation or joined relations RelOptInfo - a relation or joined relations
...@@ -145,9 +174,39 @@ RelOptInfo - a relation or joined relations ...@@ -145,9 +174,39 @@ RelOptInfo - a relation or joined relations
JoinInfo - join clauses, including the relids needed for the join JoinInfo - join clauses, including the relids needed for the join
Path - every way to generate a RelOptInfo(sequential,index,joins) Path - every way to generate a RelOptInfo(sequential,index,joins)
SeqScan - a plain Path node with nodeTag = T_SeqScan
IndexPath - index scans IndexPath - index scans
NestPath - nested joins NestPath - nested-loop joins
MergePath - merge joins MergePath - merge joins
HashPath - hash joins HashPath - hash joins
PathOrder - every ordering type (sort, merge of relations) PathKeys - a data structure representing the ordering of a path
The optimizer spends a good deal of its time worrying about the ordering
of the tuples returned by a path. The reason this is useful is that by
knowing the sort ordering of a path, we may be able to use that path as
the left or right input of a mergejoin and avoid an explicit sort step.
Nestloops and hash joins don't really care what the order of their inputs
is, but mergejoin needs suitably ordered inputs. Therefore, all paths
generated during the optimization process are marked with their sort order
(to the extent that it is known) for possible use by a higher-level merge.
It is also possible to avoid an explicit sort step to implement a user's
ORDER BY clause if the final path has the right ordering already.
Currently, this is not very well implemented: we avoid generating a
redundant sort if the chosen path has the desired order, but we do not do
anything to encourage the selection of such a path --- so we only avoid the
sort if the path that would be chosen anyway (because it is cheapest
without regard to its ordering) is properly sorted. The path winnowing
process needs to be aware of the desired output order and account for the
cost of doing an explicit sort while it is choosing the best path.
When we are generating paths for a particular RelOptInfo, we discard a path
if it is more expensive than another known path that has the same or better
sort order. We will never discard a path that is the only known way to
achieve a given sort order. In this way, the next level up will have the
maximum freedom to build mergejoins without sorting, since it can pick from
any of the paths retained for its inputs.
See path/pathkeys.c for an explanation of the PathKeys data structure that
represents what is known about the sort order of a particular Path.
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: geqo_eval.c,v 1.42 1999/07/16 04:59:08 momjian Exp $ * $Id: geqo_eval.c,v 1.43 1999/08/16 02:17:48 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -23,9 +23,6 @@ ...@@ -23,9 +23,6 @@
#include "postgres.h" #include "postgres.h"
#ifdef HAVE_LIMITS_H #ifdef HAVE_LIMITS_H
#include <limits.h> #include <limits.h>
#ifndef MAXINT
#define MAXINT INT_MAX
#endif
#else #else
#include <values.h> #include <values.h>
#endif #endif
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: geqo_misc.c,v 1.23 1999/07/17 20:17:09 momjian Exp $ * $Id: geqo_misc.c,v 1.24 1999/08/16 02:17:48 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,7 +21,10 @@ ...@@ -21,7 +21,10 @@
#include "postgres.h" #include "postgres.h"
#include "optimizer/geqo_misc.h" #include "optimizer/geqo_misc.h"
#include "nodes/print.h"
static float avg_pool(Pool *pool); static float avg_pool(Pool *pool);
...@@ -213,32 +216,14 @@ geqo_print_path(Query *root, Path *path, int indent) ...@@ -213,32 +216,14 @@ geqo_print_path(Query *root, Path *path, int indent)
int size = path->parent->size; int size = path->parent->size;
int relid = lfirsti(path->parent->relids); int relid = lfirsti(path->parent->relids);
printf("%s(%d) size=%d cost=%f", printf("%s(%d) size=%d cost=%f\n",
ptype, relid, size, path->path_cost); ptype, relid, size, path->path_cost);
if (nodeTag(path) == T_IndexPath) if (IsA(path, IndexPath))
{ {
List *k,
*l;
printf(" pathkeys="); printf(" pathkeys=");
foreach(k, path->pathkeys) print_pathkeys(path->pathkeys, root->rtable);
{
printf("(");
foreach(l, lfirst(k))
{
Var *var = lfirst(l);
printf("%d.%d", var->varnoold, var->varoattno);
if (lnext(l))
printf(", ");
}
printf(")");
if (lnext(k))
printf(", ");
}
} }
printf("\n");
} }
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Makefile for optimizer/path # Makefile for optimizer/path
# #
# IDENTIFICATION # IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/optimizer/path/Makefile,v 1.8 1999/02/20 15:27:42 momjian Exp $ # $Header: /cvsroot/pgsql/src/backend/optimizer/path/Makefile,v 1.9 1999/08/16 02:17:50 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -13,8 +13,8 @@ include ../../../Makefile.global ...@@ -13,8 +13,8 @@ include ../../../Makefile.global
CFLAGS += -I../.. CFLAGS += -I../..
OBJS = allpaths.o clausesel.o costsize.o hashutils.o indxpath.o \ OBJS = allpaths.o clausesel.o costsize.o indxpath.o \
joinpath.o joinrels.o mergeutils.o orindxpath.o pathkeys.o prune.o joinpath.o joinrels.o orindxpath.o pathkeys.o prune.o
all: SUBSYS.o all: SUBSYS.o
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.52 1999/07/30 22:34:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.53 1999/08/16 02:17:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -331,32 +331,14 @@ print_path(Query *root, Path *path, int indent) ...@@ -331,32 +331,14 @@ print_path(Query *root, Path *path, int indent)
int size = path->parent->size; int size = path->parent->size;
int relid = lfirsti(path->parent->relids); int relid = lfirsti(path->parent->relids);
printf("%s(%d) size=%d cost=%f", printf("%s(%d) size=%d cost=%f\n",
ptype, relid, size, path->path_cost); ptype, relid, size, path->path_cost);
if (nodeTag(path) == T_IndexPath) if (IsA(path, IndexPath))
{ {
List *k,
*l;
printf(" pathkeys="); printf(" pathkeys=");
foreach(k, path->pathkeys) print_pathkeys(path->pathkeys, root->rtable);
{
printf("(");
foreach(l, lfirst(k))
{
Var *var = lfirst(l);
printf("%d.%d", var->varnoold, var->varoattno);
if (lnext(l))
printf(", ");
}
printf(")");
if (lnext(k))
printf(", ");
}
} }
printf("\n");
} }
} }
......
/*-------------------------------------------------------------------------
*
* hashutils.c
* Utilities for finding applicable merge clauses and pathkeys
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/hashutils.c,v 1.18 1999/07/16 04:59:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/clauses.h"
#include "optimizer/paths.h"
static HashInfo *match_hashop_hashinfo(Oid hashop, List *hashinfo_list);
/*
* group_clauses_by_hashop
* If a join clause node in 'restrictinfo_list' is hashjoinable, store
* it within a hashinfo node containing other clause nodes with the same
* hash operator.
*
* 'restrictinfo_list' is the list of restrictinfo nodes
* 'inner_relids' is the list of relids in the inner join relation
* (used to determine whether a join var is inner or outer)
*
* Returns the new list of hashinfo nodes.
*
*/
List *
group_clauses_by_hashop(List *restrictinfo_list,
Relids inner_relids)
{
List *hashinfo_list = NIL;
RestrictInfo *restrictinfo;
List *i;
Oid hashjoinop;
foreach(i, restrictinfo_list)
{
restrictinfo = (RestrictInfo *) lfirst(i);
hashjoinop = restrictinfo->hashjoinoperator;
/*
* Create a new hashinfo node and add it to 'hashinfo_list' if one
* does not yet exist for this hash operator.
*/
if (hashjoinop)
{
Expr *clause = restrictinfo->clause;
Var *leftop = get_leftop(clause);
Var *rightop = get_rightop(clause);
HashInfo *xhashinfo;
JoinKey *joinkey;
xhashinfo = match_hashop_hashinfo(hashjoinop, hashinfo_list);
joinkey = makeNode(JoinKey);
if (intMember(leftop->varno, inner_relids))
{
joinkey->outer = rightop;
joinkey->inner = leftop;
}
else
{
joinkey->outer = leftop;
joinkey->inner = rightop;
}
if (xhashinfo == NULL)
{
xhashinfo = makeNode(HashInfo);
xhashinfo->hashop = hashjoinop;
xhashinfo->jmethod.jmkeys = NIL;
xhashinfo->jmethod.clauses = NIL;
hashinfo_list = lcons(xhashinfo, hashinfo_list);
}
xhashinfo->jmethod.clauses = lcons(clause,
xhashinfo->jmethod.clauses);
xhashinfo->jmethod.jmkeys = lcons(joinkey,
xhashinfo->jmethod.jmkeys);
}
}
return hashinfo_list;
}
/*
* match_hashop_hashinfo
* Searches the list 'hashinfo_list' for a hashinfo node whose hash op
* field equals 'hashop'.
*
* Returns the node if it exists.
*
*/
static HashInfo *
match_hashop_hashinfo(Oid hashop, List *hashinfo_list)
{
Oid key = 0;
HashInfo *xhashinfo = (HashInfo *) NULL;
List *i = NIL;
foreach(i, hashinfo_list)
{
xhashinfo = (HashInfo *) lfirst(i);
key = xhashinfo->hashop;
if (hashop == key)
{ /* found */
return xhashinfo; /* should be a hashinfo node ! */
}
}
return (HashInfo *) NIL;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*-------------------------------------------------------------------------
*
* mergeutils.c
* Utilities for finding applicable merge clauses and pathkeys
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/mergeutils.c,v 1.24 1999/07/16 04:59:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/clauses.h"
#include "optimizer/ordering.h"
#include "optimizer/paths.h"
/*
* group_clauses_by_order
* If a join clause node in 'restrictinfo_list' is mergejoinable, store
* it within a mergeinfo node containing other clause nodes with the same
* mergejoin ordering.
*
* XXX This is completely braindead: there is no reason anymore to segregate
* mergejoin clauses by join operator, since the executor can handle mergejoin
* clause sets with different operators in them. Instead, we ought to be
* building a MergeInfo for each potentially useful ordering of the input
* relations. But right now the optimizer's internal data structures do not
* support that (MergeInfo can only store one MergeOrder for a set of clauses).
* Something to fix next time...
*
* 'restrictinfo_list' is the list of restrictinfo nodes
* 'inner_relids' is the list of relids in the inner join relation
* (used to determine whether a join var is inner or outer)
*
* Returns the new list of mergeinfo nodes.
*
*/
List *
group_clauses_by_order(List *restrictinfo_list,
Relids inner_relids)
{
List *mergeinfo_list = NIL;
List *xrestrictinfo;
foreach(xrestrictinfo, restrictinfo_list)
{
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(xrestrictinfo);
MergeOrder *merge_ordering = restrictinfo->mergejoinorder;
if (merge_ordering)
{
/*
* Create a new mergeinfo node and add it to 'mergeinfo_list'
* if one does not yet exist for this merge ordering.
*/
Expr *clause = restrictinfo->clause;
Var *leftop = get_leftop(clause);
Var *rightop = get_rightop(clause);
PathOrder *pathorder;
MergeInfo *xmergeinfo;
JoinKey *jmkeys;
pathorder = makeNode(PathOrder);
pathorder->ordtype = MERGE_ORDER;
pathorder->ord.merge = merge_ordering;
xmergeinfo = match_order_mergeinfo(pathorder, mergeinfo_list);
jmkeys = makeNode(JoinKey);
if (intMember(leftop->varno, inner_relids))
{
jmkeys->outer = rightop;
jmkeys->inner = leftop;
}
else
{
jmkeys->outer = leftop;
jmkeys->inner = rightop;
}
if (xmergeinfo == NULL)
{
xmergeinfo = makeNode(MergeInfo);
xmergeinfo->m_ordering = merge_ordering;
mergeinfo_list = lcons(xmergeinfo, mergeinfo_list);
}
xmergeinfo->jmethod.clauses = lcons(clause,
xmergeinfo->jmethod.clauses);
xmergeinfo->jmethod.jmkeys = lcons(jmkeys,
xmergeinfo->jmethod.jmkeys);
}
}
return mergeinfo_list;
}
/*
* match_order_mergeinfo
* Searches the list 'mergeinfo_list' for a mergeinfo node whose order
* field equals 'ordering'.
*
* Returns the node if it exists.
*
*/
MergeInfo *
match_order_mergeinfo(PathOrder *ordering, List *mergeinfo_list)
{
MergeOrder *xmergeorder;
List *xmergeinfo = NIL;
foreach(xmergeinfo, mergeinfo_list)
{
MergeInfo *mergeinfo = (MergeInfo *) lfirst(xmergeinfo);
xmergeorder = mergeinfo->m_ordering;
if ((ordering->ordtype == MERGE_ORDER &&
equal_merge_ordering(ordering->ord.merge, xmergeorder)) ||
(ordering->ordtype == SORTOP_ORDER &&
equal_path_merge_ordering(ordering->ord.sortop, xmergeorder)))
{
return mergeinfo;
}
}
return (MergeInfo *) NIL;
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.31 1999/07/27 03:51:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.32 1999/08/16 02:17:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,12 +66,12 @@ create_or_index_paths(Query *root, ...@@ -66,12 +66,12 @@ create_or_index_paths(Query *root,
* saved by create_index_paths(). * saved by create_index_paths().
*/ */
if (restriction_is_or_clause(clausenode) && if (restriction_is_or_clause(clausenode) &&
clausenode->indexids) clausenode->subclauseindices)
{ {
bool all_indexable = true; bool all_indexable = true;
List *temp; List *temp;
foreach(temp, clausenode->indexids) foreach(temp, clausenode->subclauseindices)
{ {
if (lfirst(temp) == NIL) if (lfirst(temp) == NIL)
{ {
...@@ -94,7 +94,7 @@ create_or_index_paths(Query *root, ...@@ -94,7 +94,7 @@ create_or_index_paths(Query *root,
best_or_subclause_indices(root, best_or_subclause_indices(root,
rel, rel,
clausenode->clause->args, clausenode->clause->args,
clausenode->indexids, clausenode->subclauseindices,
&indexquals, &indexquals,
&indexids, &indexids,
&cost, &cost,
...@@ -102,20 +102,17 @@ create_or_index_paths(Query *root, ...@@ -102,20 +102,17 @@ create_or_index_paths(Query *root,
pathnode->path.pathtype = T_IndexScan; pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel; pathnode->path.parent = rel;
pathnode->path.pathorder = makeNode(PathOrder);
pathnode->path.pathorder->ordtype = SORTOP_ORDER;
/* /*
* This is an IndexScan, but the overall result will consist * This is an IndexScan, but the overall result will consist
* of tuples extracted in multiple passes (one for each * of tuples extracted in multiple passes (one for each
* subclause of the OR), so the result cannot be claimed * subclause of the OR), so the result cannot be claimed
* to have any particular ordering. * to have any particular ordering.
*/ */
pathnode->path.pathorder->ord.sortop = NULL;
pathnode->path.pathkeys = NIL; pathnode->path.pathkeys = NIL;
pathnode->indexqual = indexquals;
pathnode->indexid = indexids; pathnode->indexid = indexids;
pathnode->indexqual = indexquals;
pathnode->joinrelids = NIL; /* no join clauses here */
pathnode->path.path_cost = cost; pathnode->path.path_cost = cost;
clausenode->selectivity = (Cost) selec; clausenode->selectivity = (Cost) selec;
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.42 1999/07/16 04:59:16 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.43 1999/08/16 02:17:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,17 +18,15 @@ ...@@ -18,17 +18,15 @@
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
static List *merge_rel_with_same_relids(RelOptInfo *rel, List *unmerged_rels);
static List *merge_rel_with_same_relids(RelOptInfo *rel, Relids unjoined_relids);
/* /*
* merge_rels_with_same_relids * merge_rels_with_same_relids
* Removes any redundant relation entries from a list of rel nodes * Removes any redundant relation entries from a list of rel nodes
* 'rel_list'. Obviously, the first relation can't be a duplicate. * 'rel_list', merging their pathlists into the first non-duplicate
* relation entry for each value of relids.
* *
* Returns the resulting list. * Returns the resulting list.
*
*/ */
void void
merge_rels_with_same_relids(List *rel_list) merge_rels_with_same_relids(List *rel_list)
...@@ -37,17 +35,21 @@ merge_rels_with_same_relids(List *rel_list) ...@@ -37,17 +35,21 @@ merge_rels_with_same_relids(List *rel_list)
/* /*
* rel_list can shorten while running as duplicate relations are * rel_list can shorten while running as duplicate relations are
* deleted * deleted. Obviously, the first relation can't be a duplicate,
* so the list head pointer won't change.
*/ */
foreach(i, rel_list) foreach(i, rel_list)
lnext(i) = merge_rel_with_same_relids((RelOptInfo *) lfirst(i), lnext(i)); {
lnext(i) = merge_rel_with_same_relids((RelOptInfo *) lfirst(i),
lnext(i));
}
} }
/* /*
* merge_rel_with_same_relids * merge_rel_with_same_relids
* Prunes those relations from 'unjoined_relids' that are redundant with * Prunes those relations from 'unmerged_rels' that are redundant with
* 'rel'. A relation is redundant if it is built up of the same * 'rel'. A relation is redundant if it is built up of the same
* relations as 'rel'. Paths for the redundant relation are merged into * relations as 'rel'. Paths for the redundant relations are merged into
* the pathlist of 'rel'. * the pathlist of 'rel'.
* *
* Returns a list of non-redundant relations, and sets the pathlist field * Returns a list of non-redundant relations, and sets the pathlist field
...@@ -55,50 +57,52 @@ merge_rels_with_same_relids(List *rel_list) ...@@ -55,50 +57,52 @@ merge_rels_with_same_relids(List *rel_list)
* *
*/ */
static List * static List *
merge_rel_with_same_relids(RelOptInfo *rel, Relids unjoined_relids) merge_rel_with_same_relids(RelOptInfo *rel, List *unmerged_rels)
{ {
List *i = NIL;
List *result = NIL; List *result = NIL;
List *i;
foreach(i, unjoined_relids) foreach(i, unmerged_rels)
{ {
RelOptInfo *unjoined_rel = (RelOptInfo *) lfirst(i); RelOptInfo *unmerged_rel = (RelOptInfo *) lfirst(i);
if (same(rel->relids, unjoined_rel->relids))
if (same(rel->relids, unmerged_rel->relids))
{
/* /*
* This are on the same relations, so get the best of their * These rels are for the same set of base relations,
* pathlists. * so get the best of their pathlists. We assume it's
* ok to reassign a path to the other RelOptInfo without
* doing more than changing its parent pointer (cf. pathnode.c).
*/ */
rel->pathlist = add_pathlist(rel, rel->pathlist = add_pathlist(rel,
rel->pathlist, rel->pathlist,
unjoined_rel->pathlist); unmerged_rel->pathlist);
}
else else
result = lappend(result, unjoined_rel); result = lappend(result, unmerged_rel);
} }
return result; return result;
} }
/* /*
* rels_set_cheapest * rels_set_cheapest
* For each relation entry in 'rel_list' (which corresponds to a join * For each relation entry in 'rel_list' (which should contain only join
* relation), set pointers to the cheapest path * relations), set pointers to the cheapest path and compute rel size.
*/ */
void void
rels_set_cheapest(List *rel_list) rels_set_cheapest(List *rel_list)
{ {
List *x = NIL; List *x;
RelOptInfo *rel = (RelOptInfo *) NULL;
JoinPath *cheapest;
foreach(x, rel_list) foreach(x, rel_list)
{ {
rel = (RelOptInfo *) lfirst(x); RelOptInfo *rel = (RelOptInfo *) lfirst(x);
JoinPath *cheapest;
cheapest = (JoinPath *) set_cheapest(rel, rel->pathlist); cheapest = (JoinPath *) set_cheapest(rel, rel->pathlist);
if (IsA_JoinPath(cheapest)) if (IsA_JoinPath(cheapest))
rel->size = compute_joinrel_size(cheapest); rel->size = compute_joinrel_size(cheapest);
else else
elog(ERROR, "non JoinPath called"); elog(ERROR, "rels_set_cheapest: non JoinPath found");
} }
} }
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.36 1999/08/10 03:00:14 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.37 1999/08/16 02:17:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,9 +30,8 @@ static void add_restrict_and_join_to_rel(Query *root, Node *clause); ...@@ -30,9 +30,8 @@ static void add_restrict_and_join_to_rel(Query *root, Node *clause);
static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo, static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
Relids join_relids); Relids join_relids);
static void add_vars_to_targetlist(Query *root, List *vars); static void add_vars_to_targetlist(Query *root, List *vars);
static void check_mergejoinable(RestrictInfo *restrictinfo);
static MergeOrder *mergejoinop(Expr *clause); static void check_hashjoinable(RestrictInfo *restrictinfo);
static Oid hashjoinop(Expr *clause);
/***************************************************************************** /*****************************************************************************
...@@ -123,8 +122,8 @@ add_missing_vars_to_tlist(Query *root, List *tlist) ...@@ -123,8 +122,8 @@ add_missing_vars_to_tlist(Query *root, List *tlist)
/* /*
* add_restrict_and_join_to_rels- * add_restrict_and_join_to_rels
* Initializes RestrictInfo and JoinInfo fields of relation entries for all * Fill RestrictInfo and JoinInfo lists of relation entries for all
* relations appearing within clauses. Creates new relation entries if * relations appearing within clauses. Creates new relation entries if
* necessary, adding them to *query_relation_list*. * necessary, adding them to *query_relation_list*.
* *
...@@ -140,11 +139,11 @@ add_restrict_and_join_to_rels(Query *root, List *clauses) ...@@ -140,11 +139,11 @@ add_restrict_and_join_to_rels(Query *root, List *clauses)
} }
/* /*
* add_restrict_and_join_to_rel- * add_restrict_and_join_to_rel
* Add clause information to either the 'RestrictInfo' or 'JoinInfo' field * Add clause information to either the 'RestrictInfo' or 'JoinInfo' field
* of a relation entry (depending on whether or not the clause is a join) * (depending on whether the clause is a join) of each base relation
* by creating a new RestrictInfo node and setting appropriate fields * mentioned in the clause. A RestrictInfo node is created and added to
* within the nodes. * the appropriate list for each rel.
*/ */
static void static void
add_restrict_and_join_to_rel(Query *root, Node *clause) add_restrict_and_join_to_rel(Query *root, Node *clause)
...@@ -154,9 +153,11 @@ add_restrict_and_join_to_rel(Query *root, Node *clause) ...@@ -154,9 +153,11 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
List *vars; List *vars;
restrictinfo->clause = (Expr *) clause; restrictinfo->clause = (Expr *) clause;
restrictinfo->indexids = NIL; restrictinfo->subclauseindices = NIL;
restrictinfo->mergejoinorder = (MergeOrder *) NULL; restrictinfo->mergejoinoperator = InvalidOid;
restrictinfo->hashjoinoperator = (Oid) 0; restrictinfo->left_sortop = InvalidOid;
restrictinfo->right_sortop = InvalidOid;
restrictinfo->hashjoinoperator = InvalidOid;
/* /*
* The selectivity of the clause must be computed regardless of * The selectivity of the clause must be computed regardless of
...@@ -196,7 +197,7 @@ add_restrict_and_join_to_rel(Query *root, Node *clause) ...@@ -196,7 +197,7 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
/* /*
* add_join_info_to_rels * add_join_info_to_rels
* For every relation participating in a join clause, add 'restrictinfo' to * For every relation participating in a join clause, add 'restrictinfo' to
* the appropriate joininfo node (creating a new one and adding it to the * the appropriate joininfo list (creating a new one and adding it to the
* appropriate rel node if necessary). * appropriate rel node if necessary).
* *
* 'restrictinfo' describes the join clause * 'restrictinfo' describes the join clause
...@@ -211,21 +212,22 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo, ...@@ -211,21 +212,22 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
/* For every relid, find the joininfo, and add the proper join entries */ /* For every relid, find the joininfo, and add the proper join entries */
foreach(join_relid, join_relids) foreach(join_relid, join_relids)
{ {
int cur_relid = lfirsti(join_relid);
JoinInfo *joininfo; JoinInfo *joininfo;
Relids unjoined_relids = NIL; Relids unjoined_relids = NIL;
List *rel; List *otherrel;
/* Get the relids not equal to the current relid */ /* Get the relids not equal to the current relid */
foreach(rel, join_relids) foreach(otherrel, join_relids)
{ {
if (lfirsti(rel) != lfirsti(join_relid)) if (lfirsti(otherrel) != cur_relid)
unjoined_relids = lappendi(unjoined_relids, lfirsti(rel)); unjoined_relids = lappendi(unjoined_relids, lfirsti(otherrel));
} }
/* /*
* Find or make the joininfo node for this combination of rels * Find or make the joininfo node for this combination of rels
*/ */
joininfo = find_joininfo_node(get_base_rel(root, lfirsti(join_relid)), joininfo = find_joininfo_node(get_base_rel(root, cur_relid),
unjoined_relids); unjoined_relids);
/* /*
...@@ -247,12 +249,8 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo, ...@@ -247,12 +249,8 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
/* /*
* set_joininfo_mergeable_hashable * set_joininfo_mergeable_hashable
* Set the MergeJoinable or HashJoinable field for every joininfo node * Examine each join clause used in a query and set the merge and hash
* (within a rel node) and the mergejoinorder or hashjoinop field for * info fields in those that are mergejoinable or hashjoinable.
* each restrictinfo node (within a joininfo node) for all relations in a
* query.
*
* Returns nothing.
*/ */
void void
set_joininfo_mergeable_hashable(List *rel_list) set_joininfo_mergeable_hashable(List *rel_list)
...@@ -272,111 +270,102 @@ set_joininfo_mergeable_hashable(List *rel_list) ...@@ -272,111 +270,102 @@ set_joininfo_mergeable_hashable(List *rel_list)
foreach(z, joininfo->jinfo_restrictinfo) foreach(z, joininfo->jinfo_restrictinfo)
{ {
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(z); RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(z);
Expr *clause = restrictinfo->clause;
if (is_joinable((Node *) clause))
{
if (_enable_mergejoin_) if (_enable_mergejoin_)
{ check_mergejoinable(restrictinfo);
MergeOrder *sortop = mergejoinop(clause);
if (sortop)
{
restrictinfo->mergejoinorder = sortop;
joininfo->mergejoinable = true;
}
}
if (_enable_hashjoin_) if (_enable_hashjoin_)
{ check_hashjoinable(restrictinfo);
Oid hashop = hashjoinop(clause);
if (hashop)
{
restrictinfo->hashjoinoperator = hashop;
joininfo->hashjoinable = true;
}
}
}
} }
} }
} }
} }
/* /*
* mergejoinop * check_mergejoinable
* Returns a MergeOrder node for 'clause' iff 'clause' is mergejoinable, * If the restrictinfo's clause is mergejoinable, set the mergejoin
* i.e., both operands are single vars and the operator is * info fields in the restrictinfo.
* a mergejoinable operator. *
* Currently, we support mergejoin for binary opclauses where
* both operands are simple Vars and the operator is a mergejoinable
* operator. (Note: since we are only examining clauses that were
* classified as joins, it is certain that the two Vars belong to
* different relations... if we accepted more general clause structures
* we might need to check that the two sides refer to different rels...)
*/ */
static MergeOrder * static void
mergejoinop(Expr *clause) check_mergejoinable(RestrictInfo *restrictinfo)
{ {
Expr *clause = restrictinfo->clause;
Var *left, Var *left,
*right; *right;
Oid opno, Oid opno,
leftOp, leftOp,
rightOp; rightOp;
bool sortable;
if (!is_opclause((Node *) clause)) if (! is_opclause((Node *) clause))
return NULL; return;
left = get_leftop(clause); left = get_leftop(clause);
right = get_rightop(clause); right = get_rightop(clause);
/* caution: is_opclause accepts more than I do, so check it */ /* caution: is_opclause accepts more than I do, so check it */
if (!right) if (! right)
return NULL; /* unary opclauses need not apply */ return; /* unary opclauses need not apply */
if (!IsA(left, Var) || !IsA(right, Var)) if (!IsA(left, Var) || !IsA(right, Var))
return NULL; return;
opno = ((Oper *) clause->oper)->opno; opno = ((Oper *) clause->oper)->opno;
sortable = op_mergejoinable(opno, if (op_mergejoinable(opno,
left->vartype, left->vartype,
right->vartype, right->vartype,
&leftOp, &leftOp,
&rightOp); &rightOp))
if (sortable)
{ {
MergeOrder *morder = makeNode(MergeOrder); restrictinfo->mergejoinoperator = opno;
restrictinfo->left_sortop = leftOp;
morder->join_operator = opno; restrictinfo->right_sortop = rightOp;
morder->left_operator = leftOp;
morder->right_operator = rightOp;
morder->left_type = left->vartype;
morder->right_type = right->vartype;
return morder;
} }
else
return NULL;
} }
/* /*
* hashjoinop * check_hashjoinable
* Returns the hashjoin operator iff 'clause' is hashjoinable, * If the restrictinfo's clause is hashjoinable, set the hashjoin
* i.e., both operands are single vars and the operator is * info fields in the restrictinfo.
* a hashjoinable operator. *
* Currently, we support hashjoin for binary opclauses where
* both operands are simple Vars and the operator is a hashjoinable
* operator. (Note: since we are only examining clauses that were
* classified as joins, it is certain that the two Vars belong to
* different relations... if we accepted more general clause structures
* we might need to check that the two sides refer to different rels...)
*/ */
static Oid static void
hashjoinop(Expr *clause) check_hashjoinable(RestrictInfo *restrictinfo)
{ {
Expr *clause = restrictinfo->clause;
Var *left, Var *left,
*right; *right;
Oid opno;
if (!is_opclause((Node *) clause)) if (! is_opclause((Node *) clause))
return InvalidOid; return;
left = get_leftop(clause); left = get_leftop(clause);
right = get_rightop(clause); right = get_rightop(clause);
/* caution: is_opclause accepts more than I do, so check it */ /* caution: is_opclause accepts more than I do, so check it */
if (!right) if (! right)
return InvalidOid; /* unary opclauses need not apply */ return; /* unary opclauses need not apply */
if (!IsA(left, Var) || !IsA(right, Var)) if (!IsA(left, Var) || !IsA(right, Var))
return InvalidOid; return;
opno = ((Oper *) clause->oper)->opno;
return op_hashjoinable(((Oper *) clause->oper)->opno, if (op_hashjoinable(opno,
left->vartype, left->vartype,
right->vartype); right->vartype))
{
restrictinfo->hashjoinoperator = opno;
}
} }
This diff is collapsed.
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Makefile for optimizer/util # Makefile for optimizer/util
# #
# IDENTIFICATION # IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.8 1999/02/05 19:59:28 momjian Exp $ # $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.9 1999/08/16 02:17:56 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -14,7 +14,7 @@ include ../../../Makefile.global ...@@ -14,7 +14,7 @@ include ../../../Makefile.global
CFLAGS += -I../.. CFLAGS += -I../..
OBJS = restrictinfo.o clauses.o indexnode.o plancat.o \ OBJS = restrictinfo.o clauses.o indexnode.o plancat.o \
joininfo.o keys.o ordering.o pathnode.o relnode.o tlist.o var.o joininfo.o pathnode.o relnode.o tlist.o var.o
# not ready yet: predmig.o xfunc.o # not ready yet: predmig.o xfunc.o
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment