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">
<title>User-Defined Operators</title>
......@@ -145,29 +145,29 @@ SELECT (a + b) AS c FROM test_complex;
<itemizedlist>
<listitem>
<para>
One way is to omit the <literal>COMMUTATOR</> clause in the first operator that
you define, and then provide one in the second operator's definition.
Since <productname>PostgreSQL</productname> knows that commutative
operators come in pairs, when it sees the second definition it will
automatically go back and fill in the missing <literal>COMMUTATOR</> clause in
the first definition.
One way is to omit the <literal>COMMUTATOR</> clause in the first operator that
you define, and then provide one in the second operator's definition.
Since <productname>PostgreSQL</productname> knows that commutative
operators come in pairs, when it sees the second definition it will
automatically go back and fill in the missing <literal>COMMUTATOR</> clause in
the first definition.
</para>
</listitem>
<listitem>
<para>
The other, more straightforward way is just to include <literal>COMMUTATOR</> clauses
in both definitions. When <productname>PostgreSQL</productname> processes
the first definition and realizes that <literal>COMMUTATOR</> refers to a nonexistent
operator, the system will make a dummy entry for that operator in the
system catalog. This dummy entry will have valid data only
for the operator name, left and right operand types, and result type,
since that's all that <productname>PostgreSQL</productname> can deduce
at this point. The first operator's catalog entry will link to this
dummy entry. Later, when you define the second operator, the system
updates the dummy entry with the additional information from the second
definition. If you try to use the dummy operator before it's been filled
in, you'll just get an error message.
The other, more straightforward way is just to include <literal>COMMUTATOR</> clauses
in both definitions. When <productname>PostgreSQL</productname> processes
the first definition and realizes that <literal>COMMUTATOR</> refers to a nonexistent
operator, the system will make a dummy entry for that operator in the
system catalog. This dummy entry will have valid data only
for the operator name, left and right operand types, and result type,
since that's all that <productname>PostgreSQL</productname> can deduce
at this point. The first operator's catalog entry will link to this
dummy entry. Later, when you define the second operator, the system
updates the dummy entry with the additional information from the second
definition. If you try to use the dummy operator before it's been filled
in, you'll just get an error message.
</para>
</listitem>
</itemizedlist>
......@@ -240,7 +240,7 @@ column OP constant
one of the system's standard estimators for many of your own operators.
These are the standard restriction estimators:
<simplelist>
<member><function>eqsel</> for <literal>=</></member>
<member><function>eqsel</> for <literal>=</></member>
<member><function>neqsel</> for <literal>&lt;&gt;</></member>
<member><function>scalarltsel</> for <literal>&lt;</> or <literal>&lt;=</></member>
<member><function>scalargtsel</> for <literal>&gt;</> or <literal>&gt;=</></member>
......@@ -337,7 +337,7 @@ table1.column1 OP table2.column2
join will never compare them at all, implicitly assuming that the
result of the join operator must be false. So it never makes sense
to specify <literal>HASHES</literal> for operators that do not represent
equality.
some form of equality.
</para>
<para>
......@@ -347,7 +347,7 @@ table1.column1 OP table2.column2
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
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.
</para>
......@@ -382,8 +382,9 @@ table1.column1 OP table2.column2
false, never null, for any two nonnull inputs. If this rule is
not followed, hash-optimization of <literal>IN</> operations may
generate wrong results. (Specifically, <literal>IN</> might return
false where the correct answer according to the standard would be null; or it might
yield an error complaining that it wasn't prepared for a null result.)
false where the correct answer according to the standard would be null;
or it might yield an error complaining that it wasn't prepared for a
null result.)
</para>
</note>
......@@ -407,19 +408,18 @@ table1.column1 OP table2.column2
that can only succeed for pairs of values that fall at the
<quote>same place</>
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
data types had better be the same (or at least bitwise equivalent),
it is possible to merge-join two
behave like equality. But it is possible to merge-join two
distinct data types so long as they are logically compatible. For
example, the <type>smallint</type>-versus-<type>integer</type> equality operator
is merge-joinable.
example, the <type>smallint</type>-versus-<type>integer</type>
equality operator is merge-joinable.
We only need sorting operators that will bring both data types into a
logically compatible sequence.
</para>
<para>
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
exist yet. But the operator will not actually be used for merge joins
unless a matching operator family can be found. The
......@@ -428,30 +428,14 @@ table1.column1 OP table2.column2
</para>
<para>
There are additional restrictions on operators that you mark
merge-joinable. These restrictions are not currently checked by
<command>CREATE OPERATOR</command>, but errors may occur when
the operator is used if any are not true:
<itemizedlist>
<listitem>
<para>
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>
A merge-joinable operator must have a commutator (itself if the two
operand data types are the same, or a related equality operator
if they are different) that appears in the same operator family.
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
a btree operator family that supports multiple datatypes to provide
equality operators for every combination of the datatypes; this
allows better optimization.
</para>
<note>
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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)
*/
/*
* _copyPathKeyItem
* _copyPathKey
*/
static PathKeyItem *
_copyPathKeyItem(PathKeyItem *from)
static PathKey *
_copyPathKey(PathKey *from)
{
PathKeyItem *newnode = makeNode(PathKeyItem);
PathKey *newnode = makeNode(PathKey);
COPY_NODE_FIELD(key);
COPY_SCALAR_FIELD(sortop);
COPY_SCALAR_FIELD(nulls_first);
/* EquivalenceClasses are never moved, so just shallow-copy the pointer */
COPY_SCALAR_FIELD(pk_eclass);
COPY_SCALAR_FIELD(pk_opfamily);
COPY_SCALAR_FIELD(pk_strategy);
COPY_SCALAR_FIELD(pk_nulls_first);
return newnode;
}
......@@ -1316,21 +1318,15 @@ _copyRestrictInfo(RestrictInfo *from)
COPY_BITMAPSET_FIELD(left_relids);
COPY_BITMAPSET_FIELD(right_relids);
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(this_selec);
COPY_SCALAR_FIELD(mergejoinoperator);
COPY_SCALAR_FIELD(left_sortop);
COPY_SCALAR_FIELD(right_sortop);
COPY_SCALAR_FIELD(mergeopfamily);
/*
* 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_NODE_FIELD(mergeopfamilies);
/* EquivalenceClasses are never copied, so shallow-copy the pointers */
COPY_SCALAR_FIELD(left_ec);
COPY_SCALAR_FIELD(right_ec);
COPY_SCALAR_FIELD(outer_is_left);
COPY_SCALAR_FIELD(hashjoinoperator);
COPY_SCALAR_FIELD(left_bucketsize);
COPY_SCALAR_FIELD(right_bucketsize);
......@@ -3033,8 +3029,8 @@ copyObject(void *from)
/*
* RELATION NODES
*/
case T_PathKeyItem:
retval = _copyPathKeyItem(from);
case T_PathKey:
retval = _copyPathKey(from);
break;
case T_RestrictInfo:
retval = _copyRestrictInfo(from);
......
......@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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)
*/
static bool
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
_equalPathKey(PathKey *a, PathKey *b)
{
COMPARE_NODE_FIELD(key);
COMPARE_SCALAR_FIELD(sortop);
COMPARE_SCALAR_FIELD(nulls_first);
/*
* This is normally used on non-canonicalized PathKeys, so must chase
* 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;
}
......@@ -2016,8 +2032,8 @@ equal(void *a, void *b)
/*
* RELATION NODES
*/
case T_PathKeyItem:
retval = _equalPathKeyItem(a, b);
case T_PathKey:
retval = _equalPathKey(a, b);
break;
case T_RestrictInfo:
retval = _equalRestrictInfo(a, b);
......
......@@ -8,7 +8,7 @@
*
*
* 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
* Every node type that can appear in stored rules' parsetrees *must*
......@@ -1196,29 +1196,11 @@ _outNestPath(StringInfo str, NestPath *node)
static void
_outMergePath(StringInfo str, MergePath *node)
{
int numCols;
int i;
WRITE_NODE_TYPE("MERGEPATH");
_outJoinPathInfo(str, (JoinPath *) node);
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(innersortkeys);
}
......@@ -1241,7 +1223,8 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
/* NB: this isn't a complete set of fields */
WRITE_NODE_FIELD(parse);
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(right_join_clauses);
WRITE_NODE_FIELD(full_join_clauses);
......@@ -1284,6 +1267,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
WRITE_NODE_FIELD(subplan);
WRITE_NODE_FIELD(baserestrictinfo);
WRITE_NODE_FIELD(joininfo);
WRITE_BOOL_FIELD(has_eclass_joins);
WRITE_BITMAPSET_FIELD(index_outer_relids);
WRITE_NODE_FIELD(index_inner_paths);
}
......@@ -1306,13 +1290,48 @@ _outIndexOptInfo(StringInfo str, IndexOptInfo *node)
}
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_OID_FIELD(sortop);
WRITE_BOOL_FIELD(nulls_first);
WRITE_NODE_TYPE("EQUIVALENCECLASS");
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
......@@ -1331,12 +1350,11 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
WRITE_BITMAPSET_FIELD(left_relids);
WRITE_BITMAPSET_FIELD(right_relids);
WRITE_NODE_FIELD(orclause);
WRITE_OID_FIELD(mergejoinoperator);
WRITE_OID_FIELD(left_sortop);
WRITE_OID_FIELD(right_sortop);
WRITE_OID_FIELD(mergeopfamily);
WRITE_NODE_FIELD(left_pathkey);
WRITE_NODE_FIELD(right_pathkey);
WRITE_NODE_FIELD(parent_ec);
WRITE_NODE_FIELD(mergeopfamilies);
WRITE_NODE_FIELD(left_ec);
WRITE_NODE_FIELD(right_ec);
WRITE_BOOL_FIELD(outer_is_left);
WRITE_OID_FIELD(hashjoinoperator);
}
......@@ -2163,8 +2181,14 @@ _outNode(StringInfo str, void *obj)
case T_IndexOptInfo:
_outIndexOptInfo(str, obj);
break;
case T_PathKeyItem:
_outPathKeyItem(str, obj);
case T_EquivalenceClass:
_outEquivalenceClass(str, obj);
break;
case T_EquivalenceMember:
_outEquivalenceMember(str, obj);
break;
case T_PathKey:
_outPathKey(str, obj);
break;
case T_RestrictInfo:
_outRestrictInfo(str, obj);
......
......@@ -8,7 +8,7 @@
*
*
* 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
* AUTHOR DATE MAJOR EVENT
......@@ -404,7 +404,7 @@ print_expr(Node *expr, List *rtable)
/*
* print_pathkeys -
* pathkeys list of list of PathKeyItems
* pathkeys list of PathKeys
*/
void
print_pathkeys(List *pathkeys, List *rtable)
......@@ -414,17 +414,26 @@ print_pathkeys(List *pathkeys, List *rtable)
printf("(");
foreach(i, pathkeys)
{
List *pathkey = (List *) lfirst(i);
PathKey *pathkey = (PathKey *) lfirst(i);
EquivalenceClass *eclass;
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("(");
foreach(k, pathkey)
foreach(k, eclass->ec_members)
{
PathKeyItem *item = (PathKeyItem *) lfirst(k);
EquivalenceMember *mem = (EquivalenceMember *) lfirst(k);
print_expr(item->key, rtable);
if (lnext(k))
if (first)
first = false;
else
printf(", ");
print_expr((Node *) mem->em_expr, rtable);
}
printf(")");
if (lnext(i))
......
This diff is collapsed.
......@@ -4,7 +4,7 @@
# Makefile for optimizer/path
#
# 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
top_builddir = ../../../..
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
all: SUBSYS.o
......
......@@ -8,7 +8,7 @@
*
*
* 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,
adjust_appendrel_attrs((Node *) rel->joininfo,
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
* adjustment of relids and attribute numbers.
......
......@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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)
Path *outer_path = path->jpath.outerjoinpath;
Path *inner_path = path->jpath.innerjoinpath;
List *mergeclauses = path->path_mergeclauses;
Oid *mergeFamilies = path->path_mergeFamilies;
int *mergeStrategies = path->path_mergeStrategies;
List *outersortkeys = path->outersortkeys;
List *innersortkeys = path->innersortkeys;
Cost startup_cost = 0;
......@@ -1268,7 +1266,6 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
Selectivity merge_selec;
QualCost merge_qual_cost;
QualCost qp_qual_cost;
RestrictInfo *firstclause;
double outer_path_rows = PATH_ROWS(outer_path);
double inner_path_rows = PATH_ROWS(inner_path);
double outer_rows,
......@@ -1347,32 +1344,47 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
* inputs that will actually need to be scanned. We use only the first
* (most significant) merge clause for this purpose.
*
* Since this calculation is somewhat expensive, and will be the same for
* 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!
* XXX mergejoinscansel is a bit expensive, can we cache its results?
*/
if (mergeclauses && path->jpath.jointype != JOIN_FULL)
{
firstclause = (RestrictInfo *) linitial(mergeclauses);
if (firstclause->left_mergescansel < 0) /* not computed yet? */
mergejoinscansel(root, (Node *) firstclause->clause,
mergeFamilies[0],
mergeStrategies[0],
&firstclause->left_mergescansel,
&firstclause->right_mergescansel);
if (bms_is_subset(firstclause->left_relids, outer_path->parent->relids))
RestrictInfo *firstclause = (RestrictInfo *) linitial(mergeclauses);
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,
opathkey->pk_opfamily, opathkey->pk_strategy,
&leftscansel, &rightscansel);
if (bms_is_subset(firstclause->left_relids,
outer_path->parent->relids))
{
/* left side of clause is outer */
outerscansel = firstclause->left_mergescansel;
innerscansel = firstclause->right_mergescansel;
outerscansel = leftscansel;
innerscansel = rightscansel;
}
else
{
/* left side of clause is inner */
outerscansel = firstclause->right_mergescansel;
innerscansel = firstclause->left_mergescansel;
outerscansel = rightscansel;
innerscansel = leftscansel;
}
if (path->jpath.jointype == JOIN_LEFT)
outerscansel = 1.0;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* 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)
other_rels = list_head(joinrels[1]); /* consider all initial
* 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
......@@ -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
* 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;
if (k == other_level)
......@@ -251,8 +252,7 @@ make_rels_by_joins(PlannerInfo *root, int level, List **joinrels)
/*
* make_rels_by_clause_joins
* 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.
*
* 'old_rel' is the relation entry for the relation to be joined
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -15,7 +15,7 @@
*
*
* 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,
*/
subroot = makeNode(PlannerInfo);
subroot->parse = subquery;
subroot->planner_cxt = CurrentMemoryContext;
subroot->in_info_list = NIL;
subroot->append_rel_list = NIL;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.75 2007/01/05 22:19:33 momjian Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.76 2007/01/20 20:45:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -171,6 +171,7 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
{
root = makeNode(PlannerInfo);
root->parse = qry;
root->planner_cxt = CurrentMemoryContext;
root->hasJoinRTEs = true;
groupClauses = (List *) flatten_join_alias_vars(root,
......
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