private void PlanExpressionList(IEnumerable<SqlExpression> expressions)
{
var subLogicExpressions = new List<SqlBinaryExpression>();
// The list of expressions that have a sub-select in them.
var subQueryExpressions = new List<SqlBinaryExpression>();
// The list of all constant expressions ( true = true )
var constants = new List<SqlExpression>();
// The list of pattern matching expressions (eg. 't LIKE 'a%')
var patternExpressions = new List<SqlBinaryExpression>();
// The list of all expressions that are a single variable on one
// side, a conditional operator, and a constant on the other side.
var singleVars = new List<SqlBinaryExpression>();
// The list of multi variable expressions (possible joins)
var multiVars = new List<SqlBinaryExpression>();
foreach (var expression in expressions) {
SqlBinaryExpression exp;
if (!(expression is SqlBinaryExpression)) {
// If this is not a binary expression we imply
// [expression] = 'true'
exp = SqlExpression.Equal(expression, SqlExpression.Constant(true));
} else {
exp = (SqlBinaryExpression) expression;
}
if (exp.ExpressionType.IsLogical()) {
subLogicExpressions.Add(exp);
} else if (exp.HasSubQuery()) {
subQueryExpressions.Add(exp);
} else if (exp.ExpressionType.IsPattern()) {
patternExpressions.Add(exp);
} else {
// The list of variables in the expression.
var columnNames = exp.DiscoverReferences().ToList();
if (columnNames.Count == 0) {
// These are ( 54 + 9 = 9 ), ( "z" > "a" ), ( 9.01 - 2 ), etc
constants.Add(exp);
} else if (columnNames.Count == 1) {
// These are ( id = 90 ), ( 'a' < number ), etc
singleVars.Add(exp);
} else if (columnNames.Count > 1) {
// These are ( id = part_id ),
// ( cost_of + value_of < sold_at ), ( id = part_id - 10 )
multiVars.Add(exp);
} else {
throw new InvalidOperationException("Invalid number of column names");
}
}
}
// The order in which expression are evaluated,
// (ExpressionPlan)
var evaluateOrder = new List<ExpressionPlan>();
// Evaluate the constants. These should always be evaluated first
// because they always evaluate to either true or false or null.
EvaluateConstants(constants, evaluateOrder);
// Evaluate the singles. If formed well these can be evaluated
// using fast indices. eg. (a > 9 - 3) is more optimal than
// (a + 3 > 9).
EvaluateSingles(singleVars, evaluateOrder);
// Evaluate the pattern operators. Note that some patterns can be
// optimized better than others, but currently we keep this near the
// middle of our evaluation sequence.
EvaluatePatterns(patternExpressions, evaluateOrder);
// Evaluate the sub-queries. These are queries of the form,
// (a IN ( SELECT ... )), (a = ( SELECT ... ) = ( SELECT ... )), etc.
EvaluateSubQueries(subQueryExpressions, evaluateOrder);
// Evaluate multiple variable expressions. It's possible these are
// joins.
EvaluateMultiples(multiVars, evaluateOrder);
// Lastly evaluate the sub-logic expressions. These expressions are
// OR type expressions.
EvaluateSubLogic(subLogicExpressions, evaluateOrder);
evaluateOrder.Sort();
// And add each expression to the plan
foreach (ExpressionPlan plan in evaluateOrder) {
plan.AddToPlanTree();
}
}