aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeMergejoin.c59
-rw-r--r--src/backend/optimizer/path/joinpath.c12
-rw-r--r--src/include/nodes/execnodes.h4
-rw-r--r--src/test/regress/expected/join.out48
-rw-r--r--src/test/regress/sql/join.sql6
5 files changed, 116 insertions, 13 deletions
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 362181c26f4..0c611015134 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.99 2010/01/02 16:57:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.100 2010/01/05 23:25:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -398,8 +398,13 @@ MJCompare(MergeJoinState *mergestate)
* want to report that the tuples are equal. Instead, if result is still
* 0, change it to +1. This will result in advancing the inner side of
* the join.
+ *
+ * Likewise, if there was a constant-false joinqual, do not report
+ * equality. We have to check this as part of the mergequals, else the
+ * rescan logic will do the wrong thing.
*/
- if (nulleqnull && result == 0)
+ if (result == 0 &&
+ (nulleqnull || mergestate->mj_ConstFalseJoin))
result = 1;
MemoryContextSwitchTo(oldContext);
@@ -487,6 +492,32 @@ MJFillInner(MergeJoinState *node)
}
+/*
+ * Check that a qual condition is constant true or constant false.
+ * If it is constant false (or null), set *is_const_false to TRUE.
+ *
+ * Constant true would normally be represented by a NIL list, but we allow an
+ * actual bool Const as well. We do expect that the planner will have thrown
+ * away any non-constant terms that have been ANDed with a constant false.
+ */
+static bool
+check_constant_qual(List *qual, bool *is_const_false)
+{
+ ListCell *lc;
+
+ foreach(lc, qual)
+ {
+ Const *con = (Const *) lfirst(lc);
+
+ if (!con || !IsA(con, Const))
+ return false;
+ if (con->constisnull || !DatumGetBool(con->constvalue))
+ *is_const_false = true;
+ }
+ return true;
+}
+
+
/* ----------------------------------------------------------------
* ExecMergeTupleDump
*
@@ -1025,9 +1056,13 @@ ExecMergeJoin(MergeJoinState *node)
* state for the rescanned inner tuples. We know all of
* them will match this new outer tuple and therefore
* won't be emitted as fill tuples. This works *only*
- * because we require the extra joinquals to be nil when
- * doing a right or full join --- otherwise some of the
- * rescanned tuples might fail the extra joinquals.
+ * because we require the extra joinquals to be constant
+ * when doing a right or full join --- otherwise some of
+ * the rescanned tuples might fail the extra joinquals.
+ * This obviously won't happen for a constant-true extra
+ * joinqual, while the constant-false case is handled by
+ * forcing the merge clause to never match, so we never
+ * get here.
*/
ExecRestrPos(innerPlan);
@@ -1439,6 +1474,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate->js.joinqual = (List *)
ExecInitExpr((Expr *) node->join.joinqual,
(PlanState *) mergestate);
+ mergestate->mj_ConstFalseJoin = false;
/* mergeclauses are handled below */
/*
@@ -1498,10 +1534,11 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
ExecGetResultType(outerPlanState(mergestate)));
/*
- * Can't handle right or full join with non-nil extra joinclauses.
- * This should have been caught by planner.
+ * Can't handle right or full join with non-constant extra
+ * joinclauses. This should have been caught by planner.
*/
- if (node->join.joinqual != NIL)
+ if (!check_constant_qual(node->join.joinqual,
+ &mergestate->mj_ConstFalseJoin))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RIGHT JOIN is only supported with merge-joinable join conditions")));
@@ -1517,9 +1554,11 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
ExecGetResultType(innerPlanState(mergestate)));
/*
- * Can't handle right or full join with non-nil extra joinclauses.
+ * Can't handle right or full join with non-constant extra
+ * joinclauses. This should have been caught by planner.
*/
- if (node->join.joinqual != NIL)
+ if (!check_constant_qual(node->join.joinqual,
+ &mergestate->mj_ConstFalseJoin))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index f69ffbed7a8..2e208cb6210 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.128 2010/01/02 16:57:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.129 2010/01/05 23:25:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1184,10 +1184,18 @@ select_mergejoin_clauses(PlannerInfo *root,
if (isouterjoin && restrictinfo->is_pushed_down)
continue;
+ /* Check that clause is a mergeable operator clause */
if (!restrictinfo->can_join ||
restrictinfo->mergeopfamilies == NIL)
{
- have_nonmergeable_joinclause = true;
+ /*
+ * The executor can handle extra joinquals that are constants,
+ * but not anything else, when doing right/full merge join. (The
+ * reason to support constants is so we can do FULL JOIN ON
+ * FALSE.)
+ */
+ if (!restrictinfo->clause || !IsA(restrictinfo->clause, Const))
+ have_nonmergeable_joinclause = true;
continue; /* not mergejoinable */
}
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e091d0b1d43..866cd3ef3fd 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.216 2010/01/02 16:58:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.217 2010/01/05 23:25:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1396,6 +1396,7 @@ typedef struct NestLoopState
* Clauses info for each mergejoinable clause
* JoinState current "state" of join. see execdefs.h
* ExtraMarks true to issue extra Mark operations on inner scan
+ * ConstFalseJoin true if we have a constant-false joinqual
* FillOuter true if should emit unjoined outer tuples anyway
* FillInner true if should emit unjoined inner tuples anyway
* MatchedOuter true if found a join match for current outer tuple
@@ -1419,6 +1420,7 @@ typedef struct MergeJoinState
MergeJoinClause mj_Clauses; /* array of length mj_NumClauses */
int mj_JoinState;
bool mj_ExtraMarks;
+ bool mj_ConstFalseJoin;
bool mj_FillOuter;
bool mj_FillInner;
bool mj_MatchedOuter;
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index fed424cb33b..f2b346e5084 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -2443,3 +2443,51 @@ group by t1.q2 order by 1;
4567890123456789 | 6
(4 rows)
+--
+-- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE
+--
+select * from int4_tbl a full join int4_tbl b on true;
+ f1 | f1
+-------------+-------------
+ 0 | 0
+ 0 | 123456
+ 0 | -123456
+ 0 | 2147483647
+ 0 | -2147483647
+ 123456 | 0
+ 123456 | 123456
+ 123456 | -123456
+ 123456 | 2147483647
+ 123456 | -2147483647
+ -123456 | 0
+ -123456 | 123456
+ -123456 | -123456
+ -123456 | 2147483647
+ -123456 | -2147483647
+ 2147483647 | 0
+ 2147483647 | 123456
+ 2147483647 | -123456
+ 2147483647 | 2147483647
+ 2147483647 | -2147483647
+ -2147483647 | 0
+ -2147483647 | 123456
+ -2147483647 | -123456
+ -2147483647 | 2147483647
+ -2147483647 | -2147483647
+(25 rows)
+
+select * from int4_tbl a full join int4_tbl b on false;
+ f1 | f1
+-------------+-------------
+ | 0
+ | 123456
+ | -123456
+ | 2147483647
+ | -2147483647
+ 0 |
+ 123456 |
+ -123456 |
+ 2147483647 |
+ -2147483647 |
+(10 rows)
+
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 46ff66c6909..977765551d5 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -561,3 +561,9 @@ from int8_tbl t1 left join
(select q1, case when q2=1 then 1 else q2 end as q2 from int8_tbl) t2
on (t1.q2 = t2.q1)
group by t1.q2 order by 1;
+
+--
+-- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE
+--
+select * from int4_tbl a full join int4_tbl b on true;
+select * from int4_tbl a full join int4_tbl b on false;