private TablePlan NaturallyJoinPlans(TablePlan plan1, TablePlan plan2)
{
JoinType joinType;
SqlExpression onExpr;
TablePlan leftPlan, rightPlan;
// Are the plans linked by common join information?
if (plan1.RightPlan == plan2) {
joinType = plan1.RightJoinType;
onExpr = plan1.RightOnExpression;
leftPlan = plan1;
rightPlan = plan2;
} else if (plan1.LeftPlan == plan2) {
joinType = plan1.LeftJoinType;
onExpr = plan1.LeftOnExpression;
leftPlan = plan2;
rightPlan = plan1;
} else {
// Assertion - make sure no join clashes!
if ((plan1.LeftPlan != null && plan2.LeftPlan != null) ||
(plan1.RightPlan != null && plan2.RightPlan != null)) {
throw new InvalidOperationException("Plans can not be naturally join because " +
"the left/right join plans clash.");
}
// Else we must assume a non-dependent join (not an outer join).
// Perform a natural join
var node1 = new NaturalJoinNode(plan1.Plan, plan2.Plan);
return MergePlans(plan1, plan2, node1);
}
// This means plan1 and plan2 are linked by a common join and ON
// expression which we evaluate now.
bool outerJoin;
if (joinType == JoinType.Left) {
// Mark the left plan
leftPlan.UpdatePlan(new MarkerNode(leftPlan.Plan, "OUTER_JOIN"));
outerJoin = true;
} else if (joinType == JoinType.Right) {
// Mark the right plan
rightPlan.UpdatePlan(new MarkerNode(rightPlan.Plan, "OUTER_JOIN"));
outerJoin = true;
} else if (joinType == JoinType.Inner) {
// Inner join with ON expression
outerJoin = false;
} else {
throw new InvalidOperationException(String.Format("Join type ({0}) is not supported.", joinType));
}
// Make a Planner object for joining these plans.
var planner = new QueryTablePlanner();
planner.AddPlan(leftPlan.Clone());
planner.AddPlan(rightPlan.Clone());
// Evaluate the on expression
var node = planner.LogicalEvaluate(onExpr);
// If outer join add the left outer join node
if (outerJoin)
node = new LeftOuterJoinNode(node, "OUTER_JOIN");
// And merge the plans in this set with the new node.
return MergePlans(plan1, plan2, node);
}