Commit fabef304 authored by Tom Lane's avatar Tom Lane

Minor refactoring to eliminate duplicate code and make startup a

tad faster.
parent 05b4293b
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.72 2005/05/13 21:20:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.73 2005/05/14 21:29:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -525,6 +525,86 @@ MJCompare(MergeJoinState *mergestate) ...@@ -525,6 +525,86 @@ MJCompare(MergeJoinState *mergestate)
return result; return result;
} }
/*
* Generate a fake join tuple with nulls for the inner tuple,
* and return it if it passes the non-join quals.
*/
static TupleTableSlot *
MJFillOuter(MergeJoinState *node)
{
ExprContext *econtext = node->js.ps.ps_ExprContext;
List *otherqual = node->js.ps.qual;
ResetExprContext(econtext);
econtext->ecxt_outertuple = node->mj_OuterTupleSlot;
econtext->ecxt_innertuple = node->mj_NullInnerTupleSlot;
if (ExecQual(otherqual, econtext, false))
{
/*
* qualification succeeded. now form the desired projection tuple
* and return the slot containing it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning outer fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
}
return NULL;
}
/*
* Generate a fake join tuple with nulls for the outer tuple,
* and return it if it passes the non-join quals.
*/
static TupleTableSlot *
MJFillInner(MergeJoinState *node)
{
ExprContext *econtext = node->js.ps.ps_ExprContext;
List *otherqual = node->js.ps.qual;
ResetExprContext(econtext);
econtext->ecxt_outertuple = node->mj_NullOuterTupleSlot;
econtext->ecxt_innertuple = node->mj_InnerTupleSlot;
if (ExecQual(otherqual, econtext, false))
{
/*
* qualification succeeded. now form the desired projection tuple
* and return the slot containing it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning inner fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
{
node->js.ps.ps_TupFromTlist =
(isDone == ExprMultipleResult);
return result;
}
}
return NULL;
}
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecMergeTupleDump * ExecMergeTupleDump
* *
...@@ -612,33 +692,8 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -612,33 +692,8 @@ ExecMergeJoin(MergeJoinState *node)
econtext = node->js.ps.ps_ExprContext; econtext = node->js.ps.ps_ExprContext;
joinqual = node->js.joinqual; joinqual = node->js.joinqual;
otherqual = node->js.ps.qual; otherqual = node->js.ps.qual;
doFillOuter = node->mj_FillOuter;
switch (node->js.jointype) doFillInner = node->mj_FillInner;
{
case JOIN_INNER:
case JOIN_IN:
doFillOuter = false;
doFillInner = false;
break;
case JOIN_LEFT:
doFillOuter = true;
doFillInner = false;
break;
case JOIN_FULL:
doFillOuter = true;
doFillInner = true;
break;
case JOIN_RIGHT:
doFillOuter = false;
doFillInner = true;
break;
default:
elog(ERROR, "unrecognized join type: %d",
(int) node->js.jointype);
doFillOuter = false; /* keep compiler quiet */
doFillInner = false;
break;
}
/* /*
* Check to see if we're still projecting out tuples from a previous * Check to see if we're still projecting out tuples from a previous
...@@ -707,15 +762,27 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -707,15 +762,27 @@ ExecMergeJoin(MergeJoinState *node)
} }
/* Compute join values and check for unmatchability */ /* Compute join values and check for unmatchability */
if (!MJEvalOuterValues(node) && !doFillOuter) if (MJEvalOuterValues(node))
{ {
/* Stay in same state to fetch next outer tuple */ /* OK to go get the first inner tuple */
node->mj_JoinState = EXEC_MJ_INITIALIZE_OUTER; node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
} }
else else
{ {
/* OK to go get the first inner tuple */ /* Stay in same state to fetch next outer tuple */
node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER; if (doFillOuter)
{
/*
* Generate a fake join tuple with nulls for the inner
* tuple, and return it if it passes the non-join
* quals.
*/
TupleTableSlot *result;
result = MJFillOuter(node);
if (result)
return result;
}
} }
break; break;
...@@ -745,12 +812,7 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -745,12 +812,7 @@ ExecMergeJoin(MergeJoinState *node)
} }
/* Compute join values and check for unmatchability */ /* Compute join values and check for unmatchability */
if (!MJEvalInnerValues(node, innerTupleSlot) && !doFillInner) if (MJEvalInnerValues(node, innerTupleSlot))
{
/* Stay in same state to fetch next inner tuple */
node->mj_JoinState = EXEC_MJ_INITIALIZE_INNER;
}
else
{ {
/* /*
* OK, we have the initial tuples. Begin by skipping * OK, we have the initial tuples. Begin by skipping
...@@ -758,6 +820,23 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -758,6 +820,23 @@ ExecMergeJoin(MergeJoinState *node)
*/ */
node->mj_JoinState = EXEC_MJ_SKIP_TEST; node->mj_JoinState = EXEC_MJ_SKIP_TEST;
} }
else
{
/* Stay in same state to fetch next inner tuple */
if (doFillInner)
{
/*
* Generate a fake join tuple with nulls for the outer
* tuple, and return it if it passes the non-join
* quals.
*/
TupleTableSlot *result;
result = MJFillInner(node);
if (result)
return result;
}
}
break; break;
/* /*
...@@ -856,37 +935,13 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -856,37 +935,13 @@ ExecMergeJoin(MergeJoinState *node)
* tuple, and return it if it passes the non-join * tuple, and return it if it passes the non-join
* quals. * quals.
*/ */
node->mj_MatchedInner = true; /* do it only once */ TupleTableSlot *result;
ResetExprContext(econtext);
outerTupleSlot = node->mj_NullOuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false)) node->mj_MatchedInner = true; /* do it only once */
{
/*
* qualification succeeded. now form the desired
* projection tuple and return the slot containing
* it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult) result = MJFillInner(node);
{ if (result)
node->js.ps.ps_TupFromTlist = return result;
(isDone == ExprMultipleResult);
return result;
}
}
} }
/* /*
...@@ -961,37 +1016,13 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -961,37 +1016,13 @@ ExecMergeJoin(MergeJoinState *node)
* tuple, and return it if it passes the non-join * tuple, and return it if it passes the non-join
* quals. * quals.
*/ */
node->mj_MatchedOuter = true; /* do it only once */ TupleTableSlot *result;
ResetExprContext(econtext); node->mj_MatchedOuter = true; /* do it only once */
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = node->mj_NullInnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
{
/*
* qualification succeeded. now form the desired
* projection tuple and return the slot containing
* it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult) result = MJFillOuter(node);
{ if (result)
node->js.ps.ps_TupFromTlist = return result;
(isDone == ExprMultipleResult);
return result;
}
}
} }
/* /*
...@@ -1223,37 +1254,13 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -1223,37 +1254,13 @@ ExecMergeJoin(MergeJoinState *node)
* tuple, and return it if it passes the non-join * tuple, and return it if it passes the non-join
* quals. * quals.
*/ */
node->mj_MatchedOuter = true; /* do it only once */ TupleTableSlot *result;
ResetExprContext(econtext);
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = node->mj_NullInnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
{
/*
* qualification succeeded. now form the desired
* projection tuple and return the slot containing
* it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning fill tuple\n"); node->mj_MatchedOuter = true; /* do it only once */
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult) result = MJFillOuter(node);
{ if (result)
node->js.ps.ps_TupFromTlist = return result;
(isDone == ExprMultipleResult);
return result;
}
}
} }
/* /*
...@@ -1311,37 +1318,13 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -1311,37 +1318,13 @@ ExecMergeJoin(MergeJoinState *node)
* tuple, and return it if it passes the non-join * tuple, and return it if it passes the non-join
* quals. * quals.
*/ */
node->mj_MatchedInner = true; /* do it only once */ TupleTableSlot *result;
ResetExprContext(econtext);
outerTupleSlot = node->mj_NullOuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
{
/*
* qualification succeeded. now form the desired
* projection tuple and return the slot containing
* it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning fill tuple\n"); node->mj_MatchedInner = true; /* do it only once */
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult) result = MJFillInner(node);
{ if (result)
node->js.ps.ps_TupFromTlist = return result;
(isDone == ExprMultipleResult);
return result;
}
}
} }
/* /*
...@@ -1402,37 +1385,13 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -1402,37 +1385,13 @@ ExecMergeJoin(MergeJoinState *node)
* tuple, and return it if it passes the non-join * tuple, and return it if it passes the non-join
* quals. * quals.
*/ */
node->mj_MatchedInner = true; /* do it only once */ TupleTableSlot *result;
ResetExprContext(econtext);
outerTupleSlot = node->mj_NullOuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = node->mj_InnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false)) node->mj_MatchedInner = true; /* do it only once */
{
/*
* qualification succeeded. now form the desired
* projection tuple and return the slot containing
* it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult) result = MJFillInner(node);
{ if (result)
node->js.ps.ps_TupFromTlist = return result;
(isDone == ExprMultipleResult);
return result;
}
}
} }
/* /*
...@@ -1469,37 +1428,13 @@ ExecMergeJoin(MergeJoinState *node) ...@@ -1469,37 +1428,13 @@ ExecMergeJoin(MergeJoinState *node)
* tuple, and return it if it passes the non-join * tuple, and return it if it passes the non-join
* quals. * quals.
*/ */
node->mj_MatchedOuter = true; /* do it only once */ TupleTableSlot *result;
ResetExprContext(econtext); node->mj_MatchedOuter = true; /* do it only once */
outerTupleSlot = node->mj_OuterTupleSlot;
econtext->ecxt_outertuple = outerTupleSlot;
innerTupleSlot = node->mj_NullInnerTupleSlot;
econtext->ecxt_innertuple = innerTupleSlot;
if (ExecQual(otherqual, econtext, false))
{
/*
* qualification succeeded. now form the desired
* projection tuple and return the slot containing
* it.
*/
TupleTableSlot *result;
ExprDoneCond isDone;
MJ_printf("ExecMergeJoin: returning fill tuple\n");
result = ExecProject(node->js.ps.ps_ProjInfo,
&isDone);
if (isDone != ExprEndResult) result = MJFillOuter(node);
{ if (result)
node->js.ps.ps_TupFromTlist = return result;
(isDone == ExprMultipleResult);
return result;
}
}
} }
/* /*
...@@ -1601,13 +1536,19 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate) ...@@ -1601,13 +1536,19 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate)
{ {
case JOIN_INNER: case JOIN_INNER:
case JOIN_IN: case JOIN_IN:
mergestate->mj_FillOuter = false;
mergestate->mj_FillInner = false;
break; break;
case JOIN_LEFT: case JOIN_LEFT:
mergestate->mj_FillOuter = true;
mergestate->mj_FillInner = false;
mergestate->mj_NullInnerTupleSlot = mergestate->mj_NullInnerTupleSlot =
ExecInitNullTupleSlot(estate, ExecInitNullTupleSlot(estate,
ExecGetResultType(innerPlanState(mergestate))); ExecGetResultType(innerPlanState(mergestate)));
break; break;
case JOIN_RIGHT: case JOIN_RIGHT:
mergestate->mj_FillOuter = false;
mergestate->mj_FillInner = true;
mergestate->mj_NullOuterTupleSlot = mergestate->mj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate, ExecInitNullTupleSlot(estate,
ExecGetResultType(outerPlanState(mergestate))); ExecGetResultType(outerPlanState(mergestate)));
...@@ -1622,6 +1563,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate) ...@@ -1622,6 +1563,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate)
errmsg("RIGHT JOIN is only supported with merge-joinable join conditions"))); errmsg("RIGHT JOIN is only supported with merge-joinable join conditions")));
break; break;
case JOIN_FULL: case JOIN_FULL:
mergestate->mj_FillOuter = true;
mergestate->mj_FillInner = true;
mergestate->mj_NullOuterTupleSlot = mergestate->mj_NullOuterTupleSlot =
ExecInitNullTupleSlot(estate, ExecInitNullTupleSlot(estate,
ExecGetResultType(outerPlanState(mergestate))); ExecGetResultType(outerPlanState(mergestate)));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.132 2005/05/13 21:20:16 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.133 2005/05/14 21:29:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1031,6 +1031,8 @@ typedef struct NestLoopState ...@@ -1031,6 +1031,8 @@ typedef struct NestLoopState
* NumClauses number of mergejoinable join clauses * NumClauses number of mergejoinable join clauses
* Clauses info for each mergejoinable clause * Clauses info for each mergejoinable clause
* JoinState current "state" of join. see execdefs.h * JoinState current "state" of join. see execdefs.h
* 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 * MatchedOuter true if found a join match for current outer tuple
* MatchedInner true if found a join match for current inner tuple * MatchedInner true if found a join match for current inner tuple
* OuterTupleSlot slot in tuple table for cur outer tuple * OuterTupleSlot slot in tuple table for cur outer tuple
...@@ -1051,6 +1053,8 @@ typedef struct MergeJoinState ...@@ -1051,6 +1053,8 @@ typedef struct MergeJoinState
int mj_NumClauses; int mj_NumClauses;
MergeJoinClause mj_Clauses; /* array of length mj_NumClauses */ MergeJoinClause mj_Clauses; /* array of length mj_NumClauses */
int mj_JoinState; int mj_JoinState;
bool mj_FillOuter;
bool mj_FillInner;
bool mj_MatchedOuter; bool mj_MatchedOuter;
bool mj_MatchedInner; bool mj_MatchedInner;
TupleTableSlot *mj_OuterTupleSlot; TupleTableSlot *mj_OuterTupleSlot;
......
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