private void PlanExpression(SqlExpression expression)
{
if (expression is SqlBinaryExpression &&
expression.ExpressionType.IsLogical()) {
var binary = (SqlBinaryExpression) expression;
if (expression.ExpressionType == SqlExpressionType.Or) {
// parsing an OR block
// Split left and right of logical operator.
var exps = new[]{binary.Left, binary.Right};
// If we are an 'or' then evaluate left and right and union the
// result.
// Before we branch set cache points.
SetCachePoints();
// Make copies of the left and right planner
var leftPlanner = Clone();
var rightPlanner = Clone();
// Plan the left and right side of the OR
leftPlanner.PlanExpression(exps[0]);
rightPlanner.PlanExpression(exps[1]);
// Fix the left and right planner so that they represent the same
// 'group'.
// The current implementation naturally joins all sources if the
// number of sources is different than the original size.
int leftSz = leftPlanner.tablePlans.Count;
int rightSz = rightPlanner.tablePlans.Count;
if (leftSz != rightSz || leftPlanner.HasJoin || rightPlanner.HasJoin) {
// Naturally join all in the left and right plan
leftPlanner.NaturalJoinAll();
rightPlanner.NaturalJoinAll();
}
// Union all table sources, but only if they have changed.
var leftTableList = leftPlanner.tablePlans;
var rightTableList = rightPlanner.tablePlans;
int sz = leftTableList.Count;
// First we must determine the plans that need to be joined in the
// left and right plan.
var leftJoinList = new List<TablePlan>();
var rightJoinList = new List<TablePlan>();
for (int i = 0; i < sz; ++i) {
var leftPlan = leftTableList[i];
var rightPlan = rightTableList[i];
if (leftPlan.IsUpdated || rightPlan.IsUpdated) {
leftJoinList.Add(leftPlan);
rightJoinList.Add(rightPlan);
}
}
// Make sure the plans are joined in the left and right planners
leftPlanner.JoinToSingle(leftJoinList);
rightPlanner.JoinToSingle(rightJoinList);
// Since the planner lists may have changed we update them here.
leftTableList = leftPlanner.tablePlans;
rightTableList = rightPlanner.tablePlans;
sz = leftTableList.Count;
var newTableList = new List<TablePlan>(sz);
for (int i = 0; i < sz; ++i) {
var leftPlan = leftTableList[i];
var rightPlan = rightTableList[i];
TablePlan newPlan;
// If left and right plan updated so we need to union them
if (leftPlan.IsUpdated || rightPlan.IsUpdated) {
// In many causes, the left and right branches will contain
// identical branches that would best be optimized out.
// Take the left plan, add the logical union to it, and make it
// the plan for this.
var node = new LogicalUnionNode(leftPlan.Plan, rightPlan.Plan);
// Update the plan in this table list
leftPlan.UpdatePlan(node);
newPlan = leftPlan;
} else {
// If the left and right plan didn't update, then use the
// left plan (it doesn't matter if we use left or right because
// they are the same).
newPlan = leftPlan;
}
// Add the left plan to the new table list we are creating
newTableList.Add(newPlan);
}
// Set the new table list
tablePlans = newTableList;
} else if (expression.ExpressionType == SqlExpressionType.And) {
PlanExpressionList(new[]{binary.Left, binary.Right});
} else {
throw new InvalidOperationException();
}
} else {
PlanExpressionList(new []{expression});
}
}