Commit f41803bb authored by Tom Lane's avatar Tom Lane

Refactor planner's pathkeys data structure to create a separate, explicit

representation of equivalence classes of variables.  This is an extensive
rewrite, but it brings a number of benefits:
* planner no longer fails in the presence of "incomplete" operator families
that don't offer operators for every possible combination of datatypes.
* avoid generating and then discarding redundant equality clauses.
* remove bogus assumption that derived equalities always use operators
named "=".
* mergejoins can work with a variety of sort orders (e.g., descending) now,
instead of tying each mergejoinable operator to exactly one sort order.
* better recognition of redundant sort columns.
* can make use of equalities appearing underneath an outer join.
parent 2b7334d4
<!-- $PostgreSQL: pgsql/doc/src/sgml/xoper.sgml,v 1.37 2006/12/23 00:43:08 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/xoper.sgml,v 1.38 2007/01/20 20:45:38 tgl Exp $ -->
<sect1 id="xoper"> <sect1 id="xoper">
<title>User-Defined Operators</title> <title>User-Defined Operators</title>
...@@ -337,7 +337,7 @@ table1.column1 OP table2.column2 ...@@ -337,7 +337,7 @@ table1.column1 OP table2.column2
join will never compare them at all, implicitly assuming that the join will never compare them at all, implicitly assuming that the
result of the join operator must be false. So it never makes sense result of the join operator must be false. So it never makes sense
to specify <literal>HASHES</literal> for operators that do not represent to specify <literal>HASHES</literal> for operators that do not represent
equality. some form of equality.
</para> </para>
<para> <para>
...@@ -347,7 +347,7 @@ table1.column1 OP table2.column2 ...@@ -347,7 +347,7 @@ table1.column1 OP table2.column2
exist yet. But attempts to use the operator in hash joins will fail exist yet. But attempts to use the operator in hash joins will fail
at run time if no such operator family exists. The system needs the at run time if no such operator family exists. The system needs the
operator family to find the data-type-specific hash function for the operator family to find the data-type-specific hash function for the
operator's input data type. Of course, you must also supply a suitable operator's input data type. Of course, you must also create a suitable
hash function before you can create the operator family. hash function before you can create the operator family.
</para> </para>
...@@ -382,8 +382,9 @@ table1.column1 OP table2.column2 ...@@ -382,8 +382,9 @@ table1.column1 OP table2.column2
false, never null, for any two nonnull inputs. If this rule is false, never null, for any two nonnull inputs. If this rule is
not followed, hash-optimization of <literal>IN</> operations may not followed, hash-optimization of <literal>IN</> operations may
generate wrong results. (Specifically, <literal>IN</> might return generate wrong results. (Specifically, <literal>IN</> might return
false where the correct answer according to the standard would be null; or it might false where the correct answer according to the standard would be null;
yield an error complaining that it wasn't prepared for a null result.) or it might yield an error complaining that it wasn't prepared for a
null result.)
</para> </para>
</note> </note>
...@@ -407,19 +408,18 @@ table1.column1 OP table2.column2 ...@@ -407,19 +408,18 @@ table1.column1 OP table2.column2
that can only succeed for pairs of values that fall at the that can only succeed for pairs of values that fall at the
<quote>same place</> <quote>same place</>
in the sort order. In practice this means that the join operator must in the sort order. In practice this means that the join operator must
behave like equality. But unlike hash join, where the left and right behave like equality. But it is possible to merge-join two
data types had better be the same (or at least bitwise equivalent),
it is possible to merge-join two
distinct data types so long as they are logically compatible. For distinct data types so long as they are logically compatible. For
example, the <type>smallint</type>-versus-<type>integer</type> equality operator example, the <type>smallint</type>-versus-<type>integer</type>
is merge-joinable. equality operator is merge-joinable.
We only need sorting operators that will bring both data types into a We only need sorting operators that will bring both data types into a
logically compatible sequence. logically compatible sequence.
</para> </para>
<para> <para>
To be marked <literal>MERGES</literal>, the join operator must appear To be marked <literal>MERGES</literal>, the join operator must appear
in a btree index operator family. This is not enforced when you create as an equality member of a btree index operator family.
This is not enforced when you create
the operator, since of course the referencing operator family couldn't the operator, since of course the referencing operator family couldn't
exist yet. But the operator will not actually be used for merge joins exist yet. But the operator will not actually be used for merge joins
unless a matching operator family can be found. The unless a matching operator family can be found. The
...@@ -428,30 +428,14 @@ table1.column1 OP table2.column2 ...@@ -428,30 +428,14 @@ table1.column1 OP table2.column2
</para> </para>
<para> <para>
There are additional restrictions on operators that you mark A merge-joinable operator must have a commutator (itself if the two
merge-joinable. These restrictions are not currently checked by operand data types are the same, or a related equality operator
<command>CREATE OPERATOR</command>, but errors may occur when if they are different) that appears in the same operator family.
the operator is used if any are not true: If this is not the case, planner errors may occur when the operator
is used. Also, it is a good idea (but not strictly required) for
<itemizedlist> a btree operator family that supports multiple datatypes to provide
<listitem> equality operators for every combination of the datatypes; this
<para> allows better optimization.
A merge-joinable equality operator must have a merge-joinable
commutator (itself if the two operand data types are the same, or a related
equality operator if they are different).
</para>
</listitem>
<listitem>
<para>
If there is a merge-joinable operator relating any two data types
A and B, and another merge-joinable operator relating B to any
third data type C, then A and C must also have a merge-joinable
operator; in other words, having a merge-joinable operator must
be transitive.
</para>
</listitem>
</itemizedlist>
</para> </para>
<note> <note>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.361 2007/01/10 18:06:02 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.362 2007/01/20 20:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1284,16 +1284,18 @@ _copyFromExpr(FromExpr *from) ...@@ -1284,16 +1284,18 @@ _copyFromExpr(FromExpr *from)
*/ */
/* /*
* _copyPathKeyItem * _copyPathKey
*/ */
static PathKeyItem * static PathKey *
_copyPathKeyItem(PathKeyItem *from) _copyPathKey(PathKey *from)
{ {
PathKeyItem *newnode = makeNode(PathKeyItem); PathKey *newnode = makeNode(PathKey);
COPY_NODE_FIELD(key); /* EquivalenceClasses are never moved, so just shallow-copy the pointer */
COPY_SCALAR_FIELD(sortop); COPY_SCALAR_FIELD(pk_eclass);
COPY_SCALAR_FIELD(nulls_first); COPY_SCALAR_FIELD(pk_opfamily);
COPY_SCALAR_FIELD(pk_strategy);
COPY_SCALAR_FIELD(pk_nulls_first);
return newnode; return newnode;
} }
...@@ -1316,21 +1318,15 @@ _copyRestrictInfo(RestrictInfo *from) ...@@ -1316,21 +1318,15 @@ _copyRestrictInfo(RestrictInfo *from)
COPY_BITMAPSET_FIELD(left_relids); COPY_BITMAPSET_FIELD(left_relids);
COPY_BITMAPSET_FIELD(right_relids); COPY_BITMAPSET_FIELD(right_relids);
COPY_NODE_FIELD(orclause); COPY_NODE_FIELD(orclause);
/* EquivalenceClasses are never copied, so shallow-copy the pointers */
COPY_SCALAR_FIELD(parent_ec);
COPY_SCALAR_FIELD(eval_cost); COPY_SCALAR_FIELD(eval_cost);
COPY_SCALAR_FIELD(this_selec); COPY_SCALAR_FIELD(this_selec);
COPY_SCALAR_FIELD(mergejoinoperator); COPY_NODE_FIELD(mergeopfamilies);
COPY_SCALAR_FIELD(left_sortop); /* EquivalenceClasses are never copied, so shallow-copy the pointers */
COPY_SCALAR_FIELD(right_sortop); COPY_SCALAR_FIELD(left_ec);
COPY_SCALAR_FIELD(mergeopfamily); COPY_SCALAR_FIELD(right_ec);
COPY_SCALAR_FIELD(outer_is_left);
/*
* Do not copy pathkeys, since they'd not be canonical in a copied query
*/
newnode->left_pathkey = NIL;
newnode->right_pathkey = NIL;
COPY_SCALAR_FIELD(left_mergescansel);
COPY_SCALAR_FIELD(right_mergescansel);
COPY_SCALAR_FIELD(hashjoinoperator); COPY_SCALAR_FIELD(hashjoinoperator);
COPY_SCALAR_FIELD(left_bucketsize); COPY_SCALAR_FIELD(left_bucketsize);
COPY_SCALAR_FIELD(right_bucketsize); COPY_SCALAR_FIELD(right_bucketsize);
...@@ -3033,8 +3029,8 @@ copyObject(void *from) ...@@ -3033,8 +3029,8 @@ copyObject(void *from)
/* /*
* RELATION NODES * RELATION NODES
*/ */
case T_PathKeyItem: case T_PathKey:
retval = _copyPathKeyItem(from); retval = _copyPathKey(from);
break; break;
case T_RestrictInfo: case T_RestrictInfo:
retval = _copyRestrictInfo(from); retval = _copyRestrictInfo(from);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.295 2007/01/10 18:06:03 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.296 2007/01/20 20:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -596,11 +596,27 @@ _equalFromExpr(FromExpr *a, FromExpr *b) ...@@ -596,11 +596,27 @@ _equalFromExpr(FromExpr *a, FromExpr *b)
*/ */
static bool static bool
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b) _equalPathKey(PathKey *a, PathKey *b)
{ {
COMPARE_NODE_FIELD(key); /*
COMPARE_SCALAR_FIELD(sortop); * This is normally used on non-canonicalized PathKeys, so must chase
COMPARE_SCALAR_FIELD(nulls_first); * up to the topmost merged EquivalenceClass and see if those are the
* same (by pointer equality).
*/
EquivalenceClass *a_eclass;
EquivalenceClass *b_eclass;
a_eclass = a->pk_eclass;
while (a_eclass->ec_merged)
a_eclass = a_eclass->ec_merged;
b_eclass = b->pk_eclass;
while (b_eclass->ec_merged)
b_eclass = b_eclass->ec_merged;
if (a_eclass != b_eclass)
return false;
COMPARE_SCALAR_FIELD(pk_opfamily);
COMPARE_SCALAR_FIELD(pk_strategy);
COMPARE_SCALAR_FIELD(pk_nulls_first);
return true; return true;
} }
...@@ -2016,8 +2032,8 @@ equal(void *a, void *b) ...@@ -2016,8 +2032,8 @@ equal(void *a, void *b)
/* /*
* RELATION NODES * RELATION NODES
*/ */
case T_PathKeyItem: case T_PathKey:
retval = _equalPathKeyItem(a, b); retval = _equalPathKey(a, b);
break; break;
case T_RestrictInfo: case T_RestrictInfo:
retval = _equalRestrictInfo(a, b); retval = _equalRestrictInfo(a, b);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.293 2007/01/10 18:06:03 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.294 2007/01/20 20:45:38 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -1196,29 +1196,11 @@ _outNestPath(StringInfo str, NestPath *node) ...@@ -1196,29 +1196,11 @@ _outNestPath(StringInfo str, NestPath *node)
static void static void
_outMergePath(StringInfo str, MergePath *node) _outMergePath(StringInfo str, MergePath *node)
{ {
int numCols;
int i;
WRITE_NODE_TYPE("MERGEPATH"); WRITE_NODE_TYPE("MERGEPATH");
_outJoinPathInfo(str, (JoinPath *) node); _outJoinPathInfo(str, (JoinPath *) node);
WRITE_NODE_FIELD(path_mergeclauses); WRITE_NODE_FIELD(path_mergeclauses);
numCols = list_length(node->path_mergeclauses);
appendStringInfo(str, " :path_mergeFamilies");
for (i = 0; i < numCols; i++)
appendStringInfo(str, " %u", node->path_mergeFamilies[i]);
appendStringInfo(str, " :path_mergeStrategies");
for (i = 0; i < numCols; i++)
appendStringInfo(str, " %d", node->path_mergeStrategies[i]);
appendStringInfo(str, " :path_mergeNullsFirst");
for (i = 0; i < numCols; i++)
appendStringInfo(str, " %d", (int) node->path_mergeNullsFirst[i]);
WRITE_NODE_FIELD(outersortkeys); WRITE_NODE_FIELD(outersortkeys);
WRITE_NODE_FIELD(innersortkeys); WRITE_NODE_FIELD(innersortkeys);
} }
...@@ -1241,7 +1223,8 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node) ...@@ -1241,7 +1223,8 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
/* NB: this isn't a complete set of fields */ /* NB: this isn't a complete set of fields */
WRITE_NODE_FIELD(parse); WRITE_NODE_FIELD(parse);
WRITE_NODE_FIELD(join_rel_list); WRITE_NODE_FIELD(join_rel_list);
WRITE_NODE_FIELD(equi_key_list); WRITE_NODE_FIELD(eq_classes);
WRITE_NODE_FIELD(canon_pathkeys);
WRITE_NODE_FIELD(left_join_clauses); WRITE_NODE_FIELD(left_join_clauses);
WRITE_NODE_FIELD(right_join_clauses); WRITE_NODE_FIELD(right_join_clauses);
WRITE_NODE_FIELD(full_join_clauses); WRITE_NODE_FIELD(full_join_clauses);
...@@ -1284,6 +1267,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node) ...@@ -1284,6 +1267,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
WRITE_NODE_FIELD(subplan); WRITE_NODE_FIELD(subplan);
WRITE_NODE_FIELD(baserestrictinfo); WRITE_NODE_FIELD(baserestrictinfo);
WRITE_NODE_FIELD(joininfo); WRITE_NODE_FIELD(joininfo);
WRITE_BOOL_FIELD(has_eclass_joins);
WRITE_BITMAPSET_FIELD(index_outer_relids); WRITE_BITMAPSET_FIELD(index_outer_relids);
WRITE_NODE_FIELD(index_inner_paths); WRITE_NODE_FIELD(index_inner_paths);
} }
...@@ -1306,13 +1290,48 @@ _outIndexOptInfo(StringInfo str, IndexOptInfo *node) ...@@ -1306,13 +1290,48 @@ _outIndexOptInfo(StringInfo str, IndexOptInfo *node)
} }
static void static void
_outPathKeyItem(StringInfo str, PathKeyItem *node) _outEquivalenceClass(StringInfo str, EquivalenceClass *node)
{ {
WRITE_NODE_TYPE("PATHKEYITEM"); /*
* To simplify reading, we just chase up to the topmost merged EC and
* print that, without bothering to show the merge-ees separately.
*/
while (node->ec_merged)
node = node->ec_merged;
WRITE_NODE_FIELD(key); WRITE_NODE_TYPE("EQUIVALENCECLASS");
WRITE_OID_FIELD(sortop);
WRITE_BOOL_FIELD(nulls_first); WRITE_NODE_FIELD(ec_opfamilies);
WRITE_NODE_FIELD(ec_members);
WRITE_NODE_FIELD(ec_sources);
WRITE_BITMAPSET_FIELD(ec_relids);
WRITE_BOOL_FIELD(ec_has_const);
WRITE_BOOL_FIELD(ec_has_volatile);
WRITE_BOOL_FIELD(ec_below_outer_join);
WRITE_BOOL_FIELD(ec_broken);
}
static void
_outEquivalenceMember(StringInfo str, EquivalenceMember *node)
{
WRITE_NODE_TYPE("EQUIVALENCEMEMBER");
WRITE_NODE_FIELD(em_expr);
WRITE_BITMAPSET_FIELD(em_relids);
WRITE_BOOL_FIELD(em_is_const);
WRITE_BOOL_FIELD(em_is_child);
WRITE_OID_FIELD(em_datatype);
}
static void
_outPathKey(StringInfo str, PathKey *node)
{
WRITE_NODE_TYPE("PATHKEY");
WRITE_NODE_FIELD(pk_eclass);
WRITE_OID_FIELD(pk_opfamily);
WRITE_INT_FIELD(pk_strategy);
WRITE_BOOL_FIELD(pk_nulls_first);
} }
static void static void
...@@ -1331,12 +1350,11 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) ...@@ -1331,12 +1350,11 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
WRITE_BITMAPSET_FIELD(left_relids); WRITE_BITMAPSET_FIELD(left_relids);
WRITE_BITMAPSET_FIELD(right_relids); WRITE_BITMAPSET_FIELD(right_relids);
WRITE_NODE_FIELD(orclause); WRITE_NODE_FIELD(orclause);
WRITE_OID_FIELD(mergejoinoperator); WRITE_NODE_FIELD(parent_ec);
WRITE_OID_FIELD(left_sortop); WRITE_NODE_FIELD(mergeopfamilies);
WRITE_OID_FIELD(right_sortop); WRITE_NODE_FIELD(left_ec);
WRITE_OID_FIELD(mergeopfamily); WRITE_NODE_FIELD(right_ec);
WRITE_NODE_FIELD(left_pathkey); WRITE_BOOL_FIELD(outer_is_left);
WRITE_NODE_FIELD(right_pathkey);
WRITE_OID_FIELD(hashjoinoperator); WRITE_OID_FIELD(hashjoinoperator);
} }
...@@ -2163,8 +2181,14 @@ _outNode(StringInfo str, void *obj) ...@@ -2163,8 +2181,14 @@ _outNode(StringInfo str, void *obj)
case T_IndexOptInfo: case T_IndexOptInfo:
_outIndexOptInfo(str, obj); _outIndexOptInfo(str, obj);
break; break;
case T_PathKeyItem: case T_EquivalenceClass:
_outPathKeyItem(str, obj); _outEquivalenceClass(str, obj);
break;
case T_EquivalenceMember:
_outEquivalenceMember(str, obj);
break;
case T_PathKey:
_outPathKey(str, obj);
break; break;
case T_RestrictInfo: case T_RestrictInfo:
_outRestrictInfo(str, obj); _outRestrictInfo(str, obj);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.82 2007/01/05 22:19:30 momjian Exp $ * $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.83 2007/01/20 20:45:38 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -404,7 +404,7 @@ print_expr(Node *expr, List *rtable) ...@@ -404,7 +404,7 @@ print_expr(Node *expr, List *rtable)
/* /*
* print_pathkeys - * print_pathkeys -
* pathkeys list of list of PathKeyItems * pathkeys list of PathKeys
*/ */
void void
print_pathkeys(List *pathkeys, List *rtable) print_pathkeys(List *pathkeys, List *rtable)
...@@ -414,17 +414,26 @@ print_pathkeys(List *pathkeys, List *rtable) ...@@ -414,17 +414,26 @@ print_pathkeys(List *pathkeys, List *rtable)
printf("("); printf("(");
foreach(i, pathkeys) foreach(i, pathkeys)
{ {
List *pathkey = (List *) lfirst(i); PathKey *pathkey = (PathKey *) lfirst(i);
EquivalenceClass *eclass;
ListCell *k; ListCell *k;
bool first = true;
eclass = pathkey->pk_eclass;
/* chase up, in case pathkey is non-canonical */
while (eclass->ec_merged)
eclass = eclass->ec_merged;
printf("("); printf("(");
foreach(k, pathkey) foreach(k, eclass->ec_members)
{ {
PathKeyItem *item = (PathKeyItem *) lfirst(k); EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
print_expr(item->key, rtable); if (first)
if (lnext(k)) first = false;
else
printf(", "); printf(", ");
print_expr((Node *) mem->em_expr, rtable);
} }
printf(")"); printf(")");
if (lnext(i)) if (lnext(i))
......
This diff is collapsed.
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# Makefile for optimizer/path # Makefile for optimizer/path
# #
# IDENTIFICATION # IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/optimizer/path/Makefile,v 1.17 2007/01/20 17:16:11 petere Exp $ # $PostgreSQL: pgsql/src/backend/optimizer/path/Makefile,v 1.18 2007/01/20 20:45:38 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -12,7 +12,7 @@ subdir = src/backend/optimizer/path ...@@ -12,7 +12,7 @@ subdir = src/backend/optimizer/path
top_builddir = ../../../.. top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
OBJS = allpaths.o clausesel.o costsize.o indxpath.o \ OBJS = allpaths.o clausesel.o costsize.o equivclass.o indxpath.o \
joinpath.o joinrels.o orindxpath.o pathkeys.o tidpath.o joinpath.o joinrels.o orindxpath.o pathkeys.o tidpath.o
all: SUBSYS.o all: SUBSYS.o
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.156 2007/01/09 02:14:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.157 2007/01/20 20:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -325,6 +325,16 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, ...@@ -325,6 +325,16 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
adjust_appendrel_attrs((Node *) rel->joininfo, adjust_appendrel_attrs((Node *) rel->joininfo,
appinfo); appinfo);
/*
* We have to make child entries in the EquivalenceClass data
* structures as well.
*/
if (rel->has_eclass_joins)
{
add_child_rel_equivalences(root, appinfo, rel, childrel);
childrel->has_eclass_joins = true;
}
/* /*
* Copy the parent's attr_needed data as well, with appropriate * Copy the parent's attr_needed data as well, with appropriate
* adjustment of relids and attribute numbers. * adjustment of relids and attribute numbers.
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.174 2007/01/10 18:06:03 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.175 2007/01/20 20:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1258,8 +1258,6 @@ cost_mergejoin(MergePath *path, PlannerInfo *root) ...@@ -1258,8 +1258,6 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
Path *outer_path = path->jpath.outerjoinpath; Path *outer_path = path->jpath.outerjoinpath;
Path *inner_path = path->jpath.innerjoinpath; Path *inner_path = path->jpath.innerjoinpath;
List *mergeclauses = path->path_mergeclauses; List *mergeclauses = path->path_mergeclauses;
Oid *mergeFamilies = path->path_mergeFamilies;
int *mergeStrategies = path->path_mergeStrategies;
List *outersortkeys = path->outersortkeys; List *outersortkeys = path->outersortkeys;
List *innersortkeys = path->innersortkeys; List *innersortkeys = path->innersortkeys;
Cost startup_cost = 0; Cost startup_cost = 0;
...@@ -1268,7 +1266,6 @@ cost_mergejoin(MergePath *path, PlannerInfo *root) ...@@ -1268,7 +1266,6 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
Selectivity merge_selec; Selectivity merge_selec;
QualCost merge_qual_cost; QualCost merge_qual_cost;
QualCost qp_qual_cost; QualCost qp_qual_cost;
RestrictInfo *firstclause;
double outer_path_rows = PATH_ROWS(outer_path); double outer_path_rows = PATH_ROWS(outer_path);
double inner_path_rows = PATH_ROWS(inner_path); double inner_path_rows = PATH_ROWS(inner_path);
double outer_rows, double outer_rows,
...@@ -1347,32 +1344,47 @@ cost_mergejoin(MergePath *path, PlannerInfo *root) ...@@ -1347,32 +1344,47 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
* inputs that will actually need to be scanned. We use only the first * inputs that will actually need to be scanned. We use only the first
* (most significant) merge clause for this purpose. * (most significant) merge clause for this purpose.
* *
* Since this calculation is somewhat expensive, and will be the same for * XXX mergejoinscansel is a bit expensive, can we cache its results?
* all mergejoin paths associated with the merge clause, we cache the
* results in the RestrictInfo node. XXX that won't work anymore once
* we support multiple possible orderings!
*/ */
if (mergeclauses && path->jpath.jointype != JOIN_FULL) if (mergeclauses && path->jpath.jointype != JOIN_FULL)
{ {
firstclause = (RestrictInfo *) linitial(mergeclauses); RestrictInfo *firstclause = (RestrictInfo *) linitial(mergeclauses);
if (firstclause->left_mergescansel < 0) /* not computed yet? */ List *opathkeys;
List *ipathkeys;
PathKey *opathkey;
PathKey *ipathkey;
Selectivity leftscansel,
rightscansel;
/* Get the input pathkeys to determine the sort-order details */
opathkeys = outersortkeys ? outersortkeys : outer_path->pathkeys;
ipathkeys = innersortkeys ? innersortkeys : inner_path->pathkeys;
Assert(opathkeys);
Assert(ipathkeys);
opathkey = (PathKey *) linitial(opathkeys);
ipathkey = (PathKey *) linitial(ipathkeys);
/* debugging check */
if (opathkey->pk_opfamily != ipathkey->pk_opfamily ||
opathkey->pk_strategy != ipathkey->pk_strategy ||
opathkey->pk_nulls_first != ipathkey->pk_nulls_first)
elog(ERROR, "left and right pathkeys do not match in mergejoin");
mergejoinscansel(root, (Node *) firstclause->clause, mergejoinscansel(root, (Node *) firstclause->clause,
mergeFamilies[0], opathkey->pk_opfamily, opathkey->pk_strategy,
mergeStrategies[0], &leftscansel, &rightscansel);
&firstclause->left_mergescansel,
&firstclause->right_mergescansel);
if (bms_is_subset(firstclause->left_relids, outer_path->parent->relids)) if (bms_is_subset(firstclause->left_relids,
outer_path->parent->relids))
{ {
/* left side of clause is outer */ /* left side of clause is outer */
outerscansel = firstclause->left_mergescansel; outerscansel = leftscansel;
innerscansel = firstclause->right_mergescansel; innerscansel = rightscansel;
} }
else else
{ {
/* left side of clause is inner */ /* left side of clause is inner */
outerscansel = firstclause->right_mergescansel; outerscansel = rightscansel;
innerscansel = firstclause->left_mergescansel; innerscansel = leftscansel;
} }
if (path->jpath.jointype == JOIN_LEFT) if (path->jpath.jointype == JOIN_LEFT)
outerscansel = 1.0; outerscansel = 1.0;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.83 2007/01/05 22:19:31 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.84 2007/01/20 20:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -72,7 +72,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) ...@@ -72,7 +72,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
other_rels = list_head(joinrels[1]); /* consider all initial other_rels = list_head(joinrels[1]); /* consider all initial
* rels */ * rels */
if (old_rel->joininfo != NIL) if (old_rel->joininfo != NIL || old_rel->has_eclass_joins)
{ {
/* /*
* Note that if all available join clauses for this rel require * Note that if all available join clauses for this rel require
...@@ -152,7 +152,8 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) ...@@ -152,7 +152,8 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
* outer joins --- then we might have to force a bushy outer * outer joins --- then we might have to force a bushy outer
* join. See have_relevant_joinclause(). * join. See have_relevant_joinclause().
*/ */
if (old_rel->joininfo == NIL && root->oj_info_list == NIL) if (old_rel->joininfo == NIL && !old_rel->has_eclass_joins &&
root->oj_info_list == NIL)
continue; continue;
if (k == other_level) if (k == other_level)
...@@ -251,8 +252,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels) ...@@ -251,8 +252,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
/* /*
* make_rels_by_clause_joins * make_rels_by_clause_joins
* Build joins between the given relation 'old_rel' and other relations * Build joins between the given relation 'old_rel' and other relations
* that are mentioned within old_rel's joininfo list (i.e., relations * that participate in join clauses that 'old_rel' also participates in.
* that participate in join clauses that 'old_rel' also participates in).
* The join rel nodes are returned in a list. * The join rel nodes are returned in a list.
* *
* 'old_rel' is the relation entry for the relation to be joined * 'old_rel' is the relation entry for the relation to be joined
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.98 2007/01/05 22:19:32 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.99 2007/01/20 20:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -110,14 +110,14 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, ...@@ -110,14 +110,14 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
* for "simple" rels. * for "simple" rels.
* *
* NOTE: in_info_list and append_rel_list were set up by subquery_planner, * NOTE: in_info_list and append_rel_list were set up by subquery_planner,
* do not touch here * do not touch here; eq_classes may contain data already, too.
*/ */
root->simple_rel_array_size = list_length(parse->rtable) + 1; root->simple_rel_array_size = list_length(parse->rtable) + 1;
root->simple_rel_array = (RelOptInfo **) root->simple_rel_array = (RelOptInfo **)
palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *)); palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *));
root->join_rel_list = NIL; root->join_rel_list = NIL;
root->join_rel_hash = NULL; root->join_rel_hash = NULL;
root->equi_key_list = NIL; root->canon_pathkeys = NIL;
root->left_join_clauses = NIL; root->left_join_clauses = NIL;
root->right_join_clauses = NIL; root->right_join_clauses = NIL;
root->full_join_clauses = NIL; root->full_join_clauses = NIL;
...@@ -165,8 +165,8 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, ...@@ -165,8 +165,8 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
* Examine the targetlist and qualifications, adding entries to baserel * Examine the targetlist and qualifications, adding entries to baserel
* targetlists for all referenced Vars. Restrict and join clauses are * targetlists for all referenced Vars. Restrict and join clauses are
* added to appropriate lists belonging to the mentioned relations. We * added to appropriate lists belonging to the mentioned relations. We
* also build lists of equijoined keys for pathkey construction, and form * also build EquivalenceClasses for provably equivalent expressions,
* a target joinlist for make_one_rel() to work from. * and form a target joinlist for make_one_rel() to work from.
* *
* Note: all subplan nodes will have "flat" (var-only) tlists. This * Note: all subplan nodes will have "flat" (var-only) tlists. This
* implies that all expression evaluations are done at the root of the * implies that all expression evaluations are done at the root of the
...@@ -179,16 +179,23 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, ...@@ -179,16 +179,23 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
joinlist = deconstruct_jointree(root); joinlist = deconstruct_jointree(root);
/* /*
* Use the completed lists of equijoined keys to deduce any implied but * Reconsider any postponed outer-join quals now that we have built up
* unstated equalities (for example, A=B and B=C imply A=C). * equivalence classes. (This could result in further additions or
* mergings of classes.)
*/ */
generate_implied_equalities(root); reconsider_outer_join_clauses(root);
/* /*
* We should now have all the pathkey equivalence sets built, so it's now * If we formed any equivalence classes, generate additional restriction
* possible to convert the requested query_pathkeys to canonical form. * clauses as appropriate. (Implied join clauses are formed on-the-fly
* Also canonicalize the groupClause and sortClause pathkeys for use * later.)
* later. */
generate_base_implied_equalities(root);
/*
* We have completed merging equivalence sets, so it's now possible to
* convert the requested query_pathkeys to canonical form. Also
* canonicalize the groupClause and sortClause pathkeys for use later.
*/ */
root->query_pathkeys = canonicalize_pathkeys(root, root->query_pathkeys); root->query_pathkeys = canonicalize_pathkeys(root, root->query_pathkeys);
root->group_pathkeys = canonicalize_pathkeys(root, root->group_pathkeys); root->group_pathkeys = canonicalize_pathkeys(root, root->group_pathkeys);
......
This diff is collapsed.
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.45 2007/01/05 22:19:32 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.46 2007/01/20 20:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -292,6 +292,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, ...@@ -292,6 +292,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
*/ */
subroot = makeNode(PlannerInfo); subroot = makeNode(PlannerInfo);
subroot->parse = subquery; subroot->parse = subquery;
subroot->planner_cxt = CurrentMemoryContext;
subroot->in_info_list = NIL; subroot->in_info_list = NIL;
subroot->append_rel_list = NIL; subroot->append_rel_list = NIL;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.135 2007/01/05 22:19:32 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.136 2007/01/20 20:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1195,10 +1195,8 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context) ...@@ -1195,10 +1195,8 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
*/ */
newinfo->eval_cost.startup = -1; newinfo->eval_cost.startup = -1;
newinfo->this_selec = -1; newinfo->this_selec = -1;
newinfo->left_pathkey = NIL; newinfo->left_ec = NULL;
newinfo->right_pathkey = NIL; newinfo->right_ec = NULL;
newinfo->left_mergescansel = -1;
newinfo->right_mergescansel = -1;
newinfo->left_bucketsize = -1; newinfo->left_bucketsize = -1;
newinfo->right_bucketsize = -1; newinfo->right_bucketsize = -1;
......
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