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:
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user