Commit e549722a authored by Tom Lane's avatar Tom Lane

Get rid of the rather fuzzily defined FlattenedSubLink node type in favor of

making pull_up_sublinks() construct a full-blown JoinExpr tree representation
of IN/EXISTS SubLinks that it is able to convert to semi or anti joins.
This makes pull_up_sublinks() a shade more complex, but the gain in semantic
clarity is worth it.  I still have more to do in this area to address the
previously-discussed problems, but this commit in itself fixes at least one
bug in HEAD, as shown by added regression test case.
parent 7380b638
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.424 2009/02/24 10:06:32 petere Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.425 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1624,22 +1624,6 @@ _copyRestrictInfo(RestrictInfo *from)
return newnode;
}
/*
* _copyFlattenedSubLink
*/
static FlattenedSubLink *
_copyFlattenedSubLink(FlattenedSubLink *from)
{
FlattenedSubLink *newnode = makeNode(FlattenedSubLink);
COPY_SCALAR_FIELD(jointype);
COPY_BITMAPSET_FIELD(lefthand);
COPY_BITMAPSET_FIELD(righthand);
COPY_NODE_FIELD(quals);
return newnode;
}
/*
* _copyPlaceHolderVar
*/
......@@ -3710,9 +3694,6 @@ copyObject(void *from)
case T_RestrictInfo:
retval = _copyRestrictInfo(from);
break;
case T_FlattenedSubLink:
retval = _copyFlattenedSubLink(from);
break;
case T_PlaceHolderVar:
retval = _copyPlaceHolderVar(from);
break;
......
......@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.348 2009/02/24 10:06:32 petere Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.349 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -766,17 +766,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
return true;
}
static bool
_equalFlattenedSubLink(FlattenedSubLink *a, FlattenedSubLink *b)
{
COMPARE_SCALAR_FIELD(jointype);
COMPARE_BITMAPSET_FIELD(lefthand);
COMPARE_BITMAPSET_FIELD(righthand);
COMPARE_NODE_FIELD(quals);
return true;
}
static bool
_equalPlaceHolderVar(PlaceHolderVar *a, PlaceHolderVar *b)
{
......@@ -2496,9 +2485,6 @@ equal(void *a, void *b)
case T_RestrictInfo:
retval = _equalRestrictInfo(a, b);
break;
case T_FlattenedSubLink:
retval = _equalFlattenedSubLink(a, b);
break;
case T_PlaceHolderVar:
retval = _equalPlaceHolderVar(a, b);
break;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.37 2009/01/01 17:23:43 momjian Exp $
* $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.38 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1309,14 +1309,6 @@ expression_tree_walker(Node *node,
/* groupClauses are deemed uninteresting */
}
break;
case T_FlattenedSubLink:
{
FlattenedSubLink *fslink = (FlattenedSubLink *) node;
if (walker(fslink->quals, context))
return true;
}
break;
case T_PlaceHolderVar:
return walker(((PlaceHolderVar *) node)->phexpr, context);
case T_AppendRelInfo:
......@@ -1972,17 +1964,6 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
case T_FlattenedSubLink:
{
FlattenedSubLink *fslink = (FlattenedSubLink *) node;
FlattenedSubLink *newnode;
FLATCOPY(newnode, fslink, FlattenedSubLink);
/* Assume we need not copy the relids bitmapsets */
MUTATE(newnode->quals, fslink->quals, Expr *);
return (Node *) newnode;
}
break;
case T_PlaceHolderVar:
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.352 2009/02/06 23:43:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.353 2009/02/25 03:30:37 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
......@@ -1630,17 +1630,6 @@ _outInnerIndexscanInfo(StringInfo str, InnerIndexscanInfo *node)
WRITE_NODE_FIELD(cheapest_total_innerpath);
}
static void
_outFlattenedSubLink(StringInfo str, FlattenedSubLink *node)
{
WRITE_NODE_TYPE("FLATTENEDSUBLINK");
WRITE_ENUM_FIELD(jointype, JoinType);
WRITE_BITMAPSET_FIELD(lefthand);
WRITE_BITMAPSET_FIELD(righthand);
WRITE_NODE_FIELD(quals);
}
static void
_outPlaceHolderVar(StringInfo str, PlaceHolderVar *node)
{
......@@ -2660,9 +2649,6 @@ _outNode(StringInfo str, void *obj)
case T_InnerIndexscanInfo:
_outInnerIndexscanInfo(str, obj);
break;
case T_FlattenedSubLink:
_outFlattenedSubLink(str, obj);
break;
case T_PlaceHolderVar:
_outPlaceHolderVar(str, obj);
break;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.147 2009/02/20 00:01:03 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.148 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -52,9 +52,6 @@ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
Relids qualscope,
Relids ojscope,
Relids outerjoin_nonnullable);
static void distribute_sublink_quals_to_rels(PlannerInfo *root,
FlattenedSubLink *fslink,
bool below_outer_join);
static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
bool is_pushed_down);
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
......@@ -336,15 +333,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
/* FlattenedSubLink wrappers need special processing */
if (qual && IsA(qual, FlattenedSubLink))
distribute_sublink_quals_to_rels(root,
(FlattenedSubLink *) qual,
below_outer_join);
else
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
*qualscope, NULL, NULL);
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
*qualscope, NULL, NULL);
}
}
else if (IsA(jtnode, JoinExpr))
......@@ -399,6 +390,18 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*inner_join_rels = bms_union(left_inners, right_inners);
nonnullable_rels = leftids;
break;
case JOIN_SEMI:
leftjoinlist = deconstruct_recurse(root, j->larg,
below_outer_join,
&leftids, &left_inners);
rightjoinlist = deconstruct_recurse(root, j->rarg,
below_outer_join,
&rightids, &right_inners);
*qualscope = bms_union(leftids, rightids);
*inner_join_rels = bms_union(left_inners, right_inners);
/* Semi join adds no restrictions for quals */
nonnullable_rels = NULL;
break;
case JOIN_FULL:
leftjoinlist = deconstruct_recurse(root, j->larg,
true,
......@@ -425,6 +428,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
* semantic scope (ojscope) to pass to distribute_qual_to_rels. But
* we mustn't add it to join_info_list just yet, because we don't want
* distribute_qual_to_rels to think it is an outer join below us.
*
* Semijoins are a bit of a hybrid: we build a SpecialJoinInfo,
* but we want ojscope = NULL for distribute_qual_to_rels.
*/
if (j->jointype != JOIN_INNER)
{
......@@ -433,7 +439,11 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*inner_join_rels,
j->jointype,
(List *) j->quals);
ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
if (j->jointype == JOIN_SEMI)
ojscope = NULL;
else
ojscope = bms_union(sjinfo->min_lefthand,
sjinfo->min_righthand);
}
else
{
......@@ -446,16 +456,10 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
/* FlattenedSubLink wrappers need special processing */
if (qual && IsA(qual, FlattenedSubLink))
distribute_sublink_quals_to_rels(root,
(FlattenedSubLink *) qual,
below_outer_join);
else
distribute_qual_to_rels(root, qual,
false, below_outer_join, j->jointype,
*qualscope,
ojscope, nonnullable_rels);
distribute_qual_to_rels(root, qual,
false, below_outer_join, j->jointype,
*qualscope,
ojscope, nonnullable_rels);
}
/* Now we can add the SpecialJoinInfo to join_info_list */
......@@ -1044,64 +1048,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
distribute_restrictinfo_to_rels(root, restrictinfo);
}
/*
* distribute_sublink_quals_to_rels
* Pull sublink quals out of a FlattenedSubLink node and distribute
* them appropriately; then add a SpecialJoinInfo node to the query's
* join_info_list. The FlattenedSubLink node itself is no longer
* needed and does not propagate into further processing.
*/
static void
distribute_sublink_quals_to_rels(PlannerInfo *root,
FlattenedSubLink *fslink,
bool below_outer_join)
{
List *quals = make_ands_implicit(fslink->quals);
SpecialJoinInfo *sjinfo;
Relids qualscope;
Relids ojscope;
Relids outerjoin_nonnullable;
ListCell *l;
/*
* Build a suitable SpecialJoinInfo for the sublink. Note: using
* righthand as inner_join_rels is the conservative worst case;
* it might be possible to use a smaller set and thereby allow
* the sublink join to commute with others inside its RHS.
*/
sjinfo = make_outerjoininfo(root,
fslink->lefthand, fslink->righthand,
fslink->righthand,
fslink->jointype,
quals);
/* Treat as inner join if SEMI, outer join if ANTI */
qualscope = bms_union(sjinfo->syn_lefthand, sjinfo->syn_righthand);
if (fslink->jointype == JOIN_SEMI)
{
ojscope = outerjoin_nonnullable = NULL;
}
else
{
Assert(fslink->jointype == JOIN_ANTI);
ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
outerjoin_nonnullable = fslink->lefthand;
}
/* Distribute the join quals much as for a regular JOIN node */
foreach(l, quals)
{
Node *qual = (Node *) lfirst(l);
distribute_qual_to_rels(root, qual,
false, below_outer_join, fslink->jointype,
qualscope, ojscope, outerjoin_nonnullable);
}
/* Now we can add the SpecialJoinInfo to join_info_list */
root->join_info_list = lappend(root->join_info_list, sjinfo);
}
/*
* check_outerjoin_delay
* Detect whether a qual referencing the given relids must be delayed
......
This diff is collapsed.
This diff is collapsed.
......@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.165 2009/02/06 23:43:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.166 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1587,23 +1587,6 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
j->rtindex = context->child_relid;
return (Node *) j;
}
if (IsA(node, FlattenedSubLink))
{
/* Copy the FlattenedSubLink node with correct mutation of subnodes */
FlattenedSubLink *fslink;
fslink = (FlattenedSubLink *) expression_tree_mutator(node,
adjust_appendrel_attrs_mutator,
(void *) context);
/* now fix FlattenedSubLink's relid sets */
fslink->lefthand = adjust_relid_set(fslink->lefthand,
context->parent_relid,
context->child_relid);
fslink->righthand = adjust_relid_set(fslink->righthand,
context->parent_relid,
context->child_relid);
return (Node *) fslink;
}
if (IsA(node, PlaceHolderVar))
{
/* Copy the PlaceHolderVar node with correct mutation of subnodes */
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.275 2009/01/09 15:46:10 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.276 2009/02/25 03:30:37 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -1300,15 +1300,6 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
expr->booltesttype == IS_NOT_UNKNOWN))
result = find_nonnullable_rels_walker((Node *) expr->arg, false);
}
else if (IsA(node, FlattenedSubLink))
{
/* JOIN_SEMI sublinks preserve strictness, but JOIN_ANTI ones don't */
FlattenedSubLink *expr = (FlattenedSubLink *) node;
if (expr->jointype == JOIN_SEMI)
result = find_nonnullable_rels_walker((Node *) expr->quals,
top_level);
}
else if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
......@@ -1511,15 +1502,6 @@ find_nonnullable_vars_walker(Node *node, bool top_level)
expr->booltesttype == IS_NOT_UNKNOWN))
result = find_nonnullable_vars_walker((Node *) expr->arg, false);
}
else if (IsA(node, FlattenedSubLink))
{
/* JOIN_SEMI sublinks preserve strictness, but JOIN_ANTI ones don't */
FlattenedSubLink *expr = (FlattenedSubLink *) node;
if (expr->jointype == JOIN_SEMI)
result = find_nonnullable_vars_walker((Node *) expr->quals,
top_level);
}
else if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
......@@ -2943,24 +2925,6 @@ eval_const_expressions_mutator(Node *node,
newbtest->booltesttype = btest->booltesttype;
return (Node *) newbtest;
}
if (IsA(node, FlattenedSubLink))
{
FlattenedSubLink *fslink = (FlattenedSubLink *) node;
FlattenedSubLink *newfslink;
Expr *quals;
/* Simplify and also canonicalize the arguments */
quals = (Expr *) eval_const_expressions_mutator((Node *) fslink->quals,
context);
quals = canonicalize_qual(quals);
newfslink = makeNode(FlattenedSubLink);
newfslink->jointype = fslink->jointype;
newfslink->lefthand = fslink->lefthand;
newfslink->righthand = fslink->righthand;
newfslink->quals = quals;
return (Node *) newfslink;
}
if (IsA(node, PlaceHolderVar) && context->estimate)
{
/*
......
......@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.83 2009/01/01 17:23:45 momjian Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.84 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -766,24 +766,6 @@ flatten_join_alias_vars_mutator(Node *node,
/* Recurse in case join input is itself a join */
return flatten_join_alias_vars_mutator(newvar, context);
}
if (IsA(node, FlattenedSubLink))
{
/* Copy the FlattenedSubLink node with correct mutation of subnodes */
FlattenedSubLink *fslink;
fslink = (FlattenedSubLink *) expression_tree_mutator(node,
flatten_join_alias_vars_mutator,
(void *) context);
/* now fix FlattenedSubLink's relid sets */
if (context->sublevels_up == 0)
{
fslink->lefthand = alias_relid_set(context->root,
fslink->lefthand);
fslink->righthand = alias_relid_set(context->root,
fslink->righthand);
}
return (Node *) fslink;
}
if (IsA(node, PlaceHolderVar))
{
/* Copy the PlaceHolderVar node with correct mutation of subnodes */
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.120 2009/01/01 17:23:47 momjian Exp $
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.121 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -348,23 +348,10 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
{
JoinExpr *j = (JoinExpr *) node;
if (context->sublevels_up == 0)
if (j->rtindex && context->sublevels_up == 0)
j->rtindex += context->offset;
/* fall through to examine children */
}
if (IsA(node, FlattenedSubLink))
{
FlattenedSubLink *fslink = (FlattenedSubLink *) node;
if (context->sublevels_up == 0)
{
fslink->lefthand = offset_relid_set(fslink->lefthand,
context->offset);
fslink->righthand = offset_relid_set(fslink->righthand,
context->offset);
}
/* fall through to examine children */
}
if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
......@@ -530,21 +517,6 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
j->rtindex = context->new_index;
/* fall through to examine children */
}
if (IsA(node, FlattenedSubLink))
{
FlattenedSubLink *fslink = (FlattenedSubLink *) node;
if (context->sublevels_up == 0)
{
fslink->lefthand = adjust_relid_set(fslink->lefthand,
context->rt_index,
context->new_index);
fslink->righthand = adjust_relid_set(fslink->righthand,
context->rt_index,
context->new_index);
}
/* fall through to examine children */
}
if (IsA(node, PlaceHolderVar))
{
PlaceHolderVar *phv = (PlaceHolderVar *) node;
......@@ -838,7 +810,6 @@ rangeTableEntry_used_walker(Node *node,
/* fall through to examine children */
}
/* Shouldn't need to handle planner auxiliary nodes here */
Assert(!IsA(node, FlattenedSubLink));
Assert(!IsA(node, PlaceHolderVar));
Assert(!IsA(node, SpecialJoinInfo));
Assert(!IsA(node, AppendRelInfo));
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.220 2009/02/02 19:31:40 alvherre Exp $
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.221 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -216,7 +216,6 @@ typedef enum NodeTag
T_PathKey,
T_RestrictInfo,
T_InnerIndexscanInfo,
T_FlattenedSubLink,
T_PlaceHolderVar,
T_SpecialJoinInfo,
T_AppendRelInfo,
......
......@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.145 2009/01/01 17:24:00 momjian Exp $
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.146 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1137,7 +1137,9 @@ typedef struct RangeTblRef
*
* During parse analysis, an RTE is created for the Join, and its index
* is filled into rtindex. This RTE is present mainly so that Vars can
* be created that refer to the outputs of the join.
* be created that refer to the outputs of the join. The planner sometimes
* generates JoinExprs internally; these can have rtindex = 0 if there are
* no join alias variables referencing such joins.
*----------
*/
typedef struct JoinExpr
......@@ -1150,7 +1152,7 @@ typedef struct JoinExpr
List *using; /* USING clause, if any (list of String) */
Node *quals; /* qualifiers on join, if any */
Alias *alias; /* user-written alias clause, if any */
int rtindex; /* RT index assigned for join */
int rtindex; /* RT index assigned for join, or 0 */
} JoinExpr;
/*----------
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.168 2009/02/06 23:43:24 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.169 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1075,30 +1075,6 @@ typedef struct InnerIndexscanInfo
Path *cheapest_total_innerpath; /* cheapest total cost */
} InnerIndexscanInfo;
/*
* "Flattened SubLinks"
*
* When we pull an IN or EXISTS SubLink up into the parent query, the
* join conditions extracted from the IN/EXISTS clause need to be specially
* treated in distribute_qual_to_rels processing. We handle this by
* wrapping such expressions in a FlattenedSubLink node that identifies
* the join they come from. The FlattenedSubLink node is discarded after
* distribute_qual_to_rels, having served its purpose.
*
* Although the planner treats this as an expression node type, it is not
* recognized by the parser or executor, so we declare it here rather than
* in primnodes.h.
*/
typedef struct FlattenedSubLink
{
Expr xpr;
JoinType jointype; /* must be JOIN_SEMI or JOIN_ANTI */
Relids lefthand; /* base relids treated as syntactic LHS */
Relids righthand; /* base relids syntactically within RHS */
Expr *quals; /* join quals (in explicit-AND format) */
} FlattenedSubLink;
/*
* Placeholder node for an expression to be evaluated below the top level
* of a plan tree. This is used during planning to represent the contained
......@@ -1171,8 +1147,11 @@ typedef struct PlaceHolderVar
* For purposes of join selectivity estimation, we create transient
* SpecialJoinInfo structures for regular inner joins; so it is possible
* to have jointype == JOIN_INNER in such a structure, even though this is
* not allowed within join_info_list. Note that lhs_strict, delay_upper_joins,
* and join_quals are not set meaningfully for such structs.
* not allowed within join_info_list. We also create transient
* SpecialJoinInfos with jointype == JOIN_INNER for outer joins, since for
* cost estimation purposes it is sometimes useful to know the join size under
* plain innerjoin semantics. Note that lhs_strict, delay_upper_joins, and
* join_quals are not set meaningfully within such structs.
*/
typedef struct SpecialJoinInfo
......
......@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.35 2009/01/01 17:24:00 momjian Exp $
* $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.36 2009/02/25 03:30:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,13 +16,13 @@
#include "nodes/relation.h"
extern void SS_process_ctes(PlannerInfo *root);
extern bool convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
Relids available_rels,
Node **new_qual, List **fromlist);
extern bool convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
bool under_not,
Relids available_rels,
Node **new_qual, List **fromlist);
extern JoinExpr *convert_ANY_sublink_to_join(PlannerInfo *root,
SubLink *sublink,
Relids available_rels);
extern JoinExpr *convert_EXISTS_sublink_to_join(PlannerInfo *root,
SubLink *sublink,
bool under_not,
Relids available_rels);
extern Node *SS_replace_correlation_vars(PlannerInfo *root, Node *expr);
extern Node *SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual);
extern void SS_finalize_plan(PlannerInfo *root, Plan *plan,
......
......@@ -2333,3 +2333,22 @@ where a.unique1 = 42 and
---------+-----+----------+---------+---------
(0 rows)
--
-- test proper positioning of one-time quals in EXISTS (8.4devel bug)
--
prepare foo(bool) as
select count(*) from tenk1 a left join tenk1 b
on (a.unique2 = b.unique1 and exists
(select 1 from tenk1 c where c.thousand = b.unique2 and $1));
execute foo(true);
count
-------
10000
(1 row)
execute foo(false);
count
-------
10000
(1 row)
......@@ -2333,3 +2333,22 @@ where a.unique1 = 42 and
---------+-----+----------+---------+---------
(0 rows)
--
-- test proper positioning of one-time quals in EXISTS (8.4devel bug)
--
prepare foo(bool) as
select count(*) from tenk1 a left join tenk1 b
on (a.unique2 = b.unique1 and exists
(select 1 from tenk1 c where c.thousand = b.unique2 and $1));
execute foo(true);
count
-------
10000
(1 row)
execute foo(false);
count
-------
10000
(1 row)
......@@ -495,3 +495,13 @@ select a.unique2, a.ten, b.tenthous, b.unique2, b.hundred
from tenk1 a left join tenk1 b on a.unique2 = b.tenthous
where a.unique1 = 42 and
((b.unique2 is null and a.ten = 2) or b.hundred = 3);
--
-- test proper positioning of one-time quals in EXISTS (8.4devel bug)
--
prepare foo(bool) as
select count(*) from tenk1 a left join tenk1 b
on (a.unique2 = b.unique1 and exists
(select 1 from tenk1 c where c.thousand = b.unique2 and $1));
execute foo(true);
execute foo(false);
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