1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-06 13:46:51 +03:00

Implement SEMI and ANTI joins in the planner and executor. (Semijoins replace

the old JOIN_IN code, but antijoins are new functionality.)  Teach the planner
to convert appropriate EXISTS and NOT EXISTS subqueries into semi and anti
joins respectively.  Also, LEFT JOINs with suitable upper-level IS NULL
filters are recognized as being anti joins.  Unify the InClauseInfo and
OuterJoinInfo infrastructure into "SpecialJoinInfo".  With that change,
it becomes possible to associate a SpecialJoinInfo with every join attempt,
which permits some cleanup of join selectivity estimation.  That needs to be
taken much further than this patch does, but the next step is to change the
API for oprjoin selectivity functions, which seems like material for a
separate patch.  So for the moment the output size estimates for semi and
especially anti joins are quite bogus.
This commit is contained in:
Tom Lane
2008-08-14 18:48:00 +00:00
parent ef1c807c25
commit e006a24ad1
40 changed files with 2129 additions and 1204 deletions

View File

@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.399 2008/08/07 19:35:02 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.400 2008/08/14 18:47:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1444,36 +1444,37 @@ _copyRestrictInfo(RestrictInfo *from)
}
/*
* _copyOuterJoinInfo
* _copyFlattenedSubLink
*/
static OuterJoinInfo *
_copyOuterJoinInfo(OuterJoinInfo *from)
static FlattenedSubLink *
_copyFlattenedSubLink(FlattenedSubLink *from)
{
OuterJoinInfo *newnode = makeNode(OuterJoinInfo);
FlattenedSubLink *newnode = makeNode(FlattenedSubLink);
COPY_BITMAPSET_FIELD(min_lefthand);
COPY_BITMAPSET_FIELD(min_righthand);
COPY_BITMAPSET_FIELD(syn_lefthand);
COPY_BITMAPSET_FIELD(syn_righthand);
COPY_SCALAR_FIELD(is_full_join);
COPY_SCALAR_FIELD(lhs_strict);
COPY_SCALAR_FIELD(delay_upper_joins);
COPY_SCALAR_FIELD(jointype);
COPY_BITMAPSET_FIELD(lefthand);
COPY_BITMAPSET_FIELD(righthand);
COPY_NODE_FIELD(quals);
return newnode;
}
/*
* _copyInClauseInfo
* _copySpecialJoinInfo
*/
static InClauseInfo *
_copyInClauseInfo(InClauseInfo *from)
static SpecialJoinInfo *
_copySpecialJoinInfo(SpecialJoinInfo *from)
{
InClauseInfo *newnode = makeNode(InClauseInfo);
SpecialJoinInfo *newnode = makeNode(SpecialJoinInfo);
COPY_BITMAPSET_FIELD(lefthand);
COPY_BITMAPSET_FIELD(righthand);
COPY_NODE_FIELD(sub_targetlist);
COPY_NODE_FIELD(in_operators);
COPY_BITMAPSET_FIELD(min_lefthand);
COPY_BITMAPSET_FIELD(min_righthand);
COPY_BITMAPSET_FIELD(syn_lefthand);
COPY_BITMAPSET_FIELD(syn_righthand);
COPY_SCALAR_FIELD(jointype);
COPY_SCALAR_FIELD(lhs_strict);
COPY_SCALAR_FIELD(delay_upper_joins);
COPY_NODE_FIELD(join_quals);
return newnode;
}
@@ -3233,11 +3234,11 @@ copyObject(void *from)
case T_RestrictInfo:
retval = _copyRestrictInfo(from);
break;
case T_OuterJoinInfo:
retval = _copyOuterJoinInfo(from);
case T_FlattenedSubLink:
retval = _copyFlattenedSubLink(from);
break;
case T_InClauseInfo:
retval = _copyInClauseInfo(from);
case T_SpecialJoinInfo:
retval = _copySpecialJoinInfo(from);
break;
case T_AppendRelInfo:
retval = _copyAppendRelInfo(from);

View File

@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.326 2008/08/07 01:11:47 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.327 2008/08/14 18:47:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -702,26 +702,27 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
}
static bool
_equalOuterJoinInfo(OuterJoinInfo *a, OuterJoinInfo *b)
_equalFlattenedSubLink(FlattenedSubLink *a, FlattenedSubLink *b)
{
COMPARE_BITMAPSET_FIELD(min_lefthand);
COMPARE_BITMAPSET_FIELD(min_righthand);
COMPARE_BITMAPSET_FIELD(syn_lefthand);
COMPARE_BITMAPSET_FIELD(syn_righthand);
COMPARE_SCALAR_FIELD(is_full_join);
COMPARE_SCALAR_FIELD(lhs_strict);
COMPARE_SCALAR_FIELD(delay_upper_joins);
COMPARE_SCALAR_FIELD(jointype);
COMPARE_BITMAPSET_FIELD(lefthand);
COMPARE_BITMAPSET_FIELD(righthand);
COMPARE_NODE_FIELD(quals);
return true;
}
static bool
_equalInClauseInfo(InClauseInfo *a, InClauseInfo *b)
_equalSpecialJoinInfo(SpecialJoinInfo *a, SpecialJoinInfo *b)
{
COMPARE_BITMAPSET_FIELD(lefthand);
COMPARE_BITMAPSET_FIELD(righthand);
COMPARE_NODE_FIELD(sub_targetlist);
COMPARE_NODE_FIELD(in_operators);
COMPARE_BITMAPSET_FIELD(min_lefthand);
COMPARE_BITMAPSET_FIELD(min_righthand);
COMPARE_BITMAPSET_FIELD(syn_lefthand);
COMPARE_BITMAPSET_FIELD(syn_righthand);
COMPARE_SCALAR_FIELD(jointype);
COMPARE_SCALAR_FIELD(lhs_strict);
COMPARE_SCALAR_FIELD(delay_upper_joins);
COMPARE_NODE_FIELD(join_quals);
return true;
}
@@ -2185,11 +2186,11 @@ equal(void *a, void *b)
case T_RestrictInfo:
retval = _equalRestrictInfo(a, b);
break;
case T_OuterJoinInfo:
retval = _equalOuterJoinInfo(a, b);
case T_FlattenedSubLink:
retval = _equalFlattenedSubLink(a, b);
break;
case T_InClauseInfo:
retval = _equalInClauseInfo(a, b);
case T_SpecialJoinInfo:
retval = _equalSpecialJoinInfo(a, b);
break;
case T_AppendRelInfo:
retval = _equalAppendRelInfo(a, b);

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/list.c,v 1.69 2008/01/01 19:45:50 momjian Exp $
* $PostgreSQL: pgsql/src/backend/nodes/list.c,v 1.70 2008/08/14 18:47:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -783,6 +783,42 @@ list_union_oid(List *list1, List *list2)
return result;
}
/*
* Return a list that contains all the cells that are in both list1 and
* list2. The returned list is freshly allocated via palloc(), but the
* cells themselves point to the same objects as the cells of the
* input lists.
*
* Duplicate entries in list1 will not be suppressed, so it's only a true
* "intersection" if list1 is known unique beforehand.
*
* This variant works on lists of pointers, and determines list
* membership via equal(). Note that the list1 member will be pointed
* to in the result.
*/
List *
list_intersection(List *list1, List *list2)
{
List *result;
ListCell *cell;
if (list1 == NIL || list2 == NIL)
return NIL;
Assert(IsPointerList(list1));
Assert(IsPointerList(list2));
result = NIL;
foreach(cell, list1)
{
if (list_member(list2, lfirst(cell)))
result = lappend(result, lfirst(cell));
}
check_list_invariants(result);
return result;
}
/*
* Return a list that contains all the cells in list1 that are not in
* list2. The returned list is freshly allocated via palloc(), but the

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.333 2008/08/07 19:35:02 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.334 2008/08/14 18:47:58 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1267,6 +1267,8 @@ _outUniquePath(StringInfo str, UniquePath *node)
WRITE_NODE_FIELD(subpath);
WRITE_ENUM_FIELD(umethod, UniquePathMethod);
WRITE_NODE_FIELD(in_operators);
WRITE_NODE_FIELD(uniq_exprs);
WRITE_FLOAT_FIELD(rows, "%.0f");
}
@@ -1332,8 +1334,7 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
WRITE_NODE_FIELD(left_join_clauses);
WRITE_NODE_FIELD(right_join_clauses);
WRITE_NODE_FIELD(full_join_clauses);
WRITE_NODE_FIELD(oj_info_list);
WRITE_NODE_FIELD(in_info_list);
WRITE_NODE_FIELD(join_info_list);
WRITE_NODE_FIELD(append_rel_list);
WRITE_NODE_FIELD(query_pathkeys);
WRITE_NODE_FIELD(group_pathkeys);
@@ -1342,7 +1343,6 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
WRITE_FLOAT_FIELD(total_table_pages, "%.0f");
WRITE_FLOAT_FIELD(tuple_fraction, "%.4f");
WRITE_BOOL_FIELD(hasJoinRTEs);
WRITE_BOOL_FIELD(hasOuterJoins);
WRITE_BOOL_FIELD(hasHavingQual);
WRITE_BOOL_FIELD(hasPseudoConstantQuals);
}
@@ -1479,28 +1479,29 @@ _outInnerIndexscanInfo(StringInfo str, InnerIndexscanInfo *node)
}
static void
_outOuterJoinInfo(StringInfo str, OuterJoinInfo *node)
_outFlattenedSubLink(StringInfo str, FlattenedSubLink *node)
{
WRITE_NODE_TYPE("OUTERJOININFO");
WRITE_NODE_TYPE("FLATTENEDSUBLINK");
WRITE_ENUM_FIELD(jointype, JoinType);
WRITE_BITMAPSET_FIELD(lefthand);
WRITE_BITMAPSET_FIELD(righthand);
WRITE_NODE_FIELD(quals);
}
static void
_outSpecialJoinInfo(StringInfo str, SpecialJoinInfo *node)
{
WRITE_NODE_TYPE("SPECIALJOININFO");
WRITE_BITMAPSET_FIELD(min_lefthand);
WRITE_BITMAPSET_FIELD(min_righthand);
WRITE_BITMAPSET_FIELD(syn_lefthand);
WRITE_BITMAPSET_FIELD(syn_righthand);
WRITE_BOOL_FIELD(is_full_join);
WRITE_ENUM_FIELD(jointype, JoinType);
WRITE_BOOL_FIELD(lhs_strict);
WRITE_BOOL_FIELD(delay_upper_joins);
}
static void
_outInClauseInfo(StringInfo str, InClauseInfo *node)
{
WRITE_NODE_TYPE("INCLAUSEINFO");
WRITE_BITMAPSET_FIELD(lefthand);
WRITE_BITMAPSET_FIELD(righthand);
WRITE_NODE_FIELD(sub_targetlist);
WRITE_NODE_FIELD(in_operators);
WRITE_NODE_FIELD(join_quals);
}
static void
@@ -2352,11 +2353,11 @@ _outNode(StringInfo str, void *obj)
case T_InnerIndexscanInfo:
_outInnerIndexscanInfo(str, obj);
break;
case T_OuterJoinInfo:
_outOuterJoinInfo(str, obj);
case T_FlattenedSubLink:
_outFlattenedSubLink(str, obj);
break;
case T_InClauseInfo:
_outInClauseInfo(str, obj);
case T_SpecialJoinInfo:
_outSpecialJoinInfo(str, obj);
break;
case T_AppendRelInfo:
_outAppendRelInfo(str, obj);