DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
Classes | Public Member Functions | Properties | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
Deveel.Data.Sql.Query.QueryTablePlanner Class Reference

Classes

class  ComplexSinglePlan
 
class  ConstantPlan
 
class  ExhaustiveJoinPlan
 
class  ExhaustiveSelectPlan
 
class  ExhaustiveSubQueryPlan
 
class  ExpressionPlan
 
class  SimplePatternPlan
 
class  SimpleSelectPlan
 
class  SimpleSinglePlan
 
class  SimpleSubQueryPlan
 
class  SingleColumnPlan
 
class  StandardJoinPlan
 
class  SubLogicPlan
 

Public Member Functions

 QueryTablePlanner ()
 
void AddPlan (TablePlan tablePlan)
 
void AddPlan (IQueryPlanNode plan, IFromTableSource tableSource)
 
void JoinAt (int betweenIndex, JoinType joinType, SqlExpression onExpression)
 
IQueryPlanNode PlanSearchExpression (SqlExpression searchExpression)
 

Properties

bool HasJoin [get, private set]
 
TablePlan SinglePlan [get]
 

Private Member Functions

int IndexOfPlan (TablePlan plan)
 
TablePlan MergePlans (TablePlan left, TablePlan right, IQueryPlanNode mergePlan)
 
TablePlan FindPlan (ObjectName reference)
 
TablePlan FindCommonPlan (IList< ObjectName > columnNames)
 
void SetCachePoints ()
 
TablePlan JoinPlansForColumns (IEnumerable< ObjectName > columnNames)
 
TablePlan NaturalJoinAll ()
 
TablePlan NaturallyJoinPlans (TablePlan plan1, TablePlan plan2)
 
TablePlan JoinToSingle (IList< TablePlan > allPlans)
 
IQueryPlanNode LogicalEvaluate (SqlExpression expression)
 
QueryTablePlanner Clone ()
 
void PlanAllOuterJoins ()
 
void PlanExpressionList (IEnumerable< SqlExpression > expressions)
 
void EvaluateSubLogic (List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
 
void EvaluateMultiples (List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
 
void EvaluateSubQueries (List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
 
void EvaluatePatterns (List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
 
void EvaluateSingles (List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
 
void EvaluateConstants (List< SqlExpression > list, List< ExpressionPlan > plans)
 
void PlanExpression (SqlExpression expression)
 

Static Private Member Functions

static TablePlan ConcatPlans (TablePlan left, TablePlan right, IQueryPlanNode plan)
 
static int AssertBeNaturalJoin (TablePlan plan1, TablePlan plan2)
 
static void AddSingleColumnPlan (IList< SingleColumnPlan > list, TablePlan table, ObjectName columnName, ObjectName uniqueName, SqlExpression[] expParts, SqlExpressionType op)
 

Private Attributes

List< TablePlantablePlans
 

Detailed Description

Definition at line 24 of file QueryTablePlanner.cs.

Constructor & Destructor Documentation

Deveel.Data.Sql.Query.QueryTablePlanner.QueryTablePlanner ( )
inline

Definition at line 27 of file QueryTablePlanner.cs.

27  {
28  tablePlans = new List<TablePlan>();
29  HasJoin = false;
30  }

Member Function Documentation

void Deveel.Data.Sql.Query.QueryTablePlanner.AddPlan ( TablePlan  tablePlan)
inline

Definition at line 772 of file QueryTablePlanner.cs.

772  {
773  tablePlans.Add(tablePlan);
774  HasJoin = true;
775  }
void Deveel.Data.Sql.Query.QueryTablePlanner.AddPlan ( IQueryPlanNode  plan,
IFromTableSource  tableSource 
)
inline

Definition at line 777 of file QueryTablePlanner.cs.

777  {
778  var columns = tableSource.ColumnNames;
779  var uniqueNames = new[] {tableSource.UniqueName};
780  AddPlan(new TablePlan(plan, columns, uniqueNames));
781  }
static void Deveel.Data.Sql.Query.QueryTablePlanner.AddSingleColumnPlan ( IList< SingleColumnPlan list,
TablePlan  table,
ObjectName  columnName,
ObjectName  uniqueName,
SqlExpression[]  expParts,
SqlExpressionType  op 
)
inlinestaticprivate

Definition at line 292 of file QueryTablePlanner.cs.

292  {
293  var exp = SqlExpression.Binary(expParts[0], op, expParts[1]);
294 
295  // Is this source in the list already?
296  foreach (var existingPlan in list) {
297  if (existingPlan.TablePlan == table &&
298  (columnName == null || existingPlan.ColumnName.Equals(columnName))) {
299  // Append to end of current expression
300  existingPlan.SetSource(columnName, SqlExpression.And(existingPlan.Expression, exp));
301  return;
302  }
303  }
304 
305  // Didn't find so make a new entry in the list.
306  list.Add(new SingleColumnPlan(table, columnName, uniqueName, exp));
307  }
static SqlBinaryExpression And(SqlExpression left, SqlExpression right)
static SqlBinaryExpression Add(SqlExpression left, SqlExpression right)
static SqlBinaryExpression Binary(SqlExpression left, SqlExpressionType expressionType, SqlExpression right)
Defines the base class for instances that represent SQL expression tree nodes.
static int Deveel.Data.Sql.Query.QueryTablePlanner.AssertBeNaturalJoin ( TablePlan  plan1,
TablePlan  plan2 
)
inlinestaticprivate

Definition at line 142 of file QueryTablePlanner.cs.

142  {
143  if (plan1.LeftPlan == plan2 || plan1.RightPlan == plan2)
144  return 0;
145  if (plan1.LeftPlan != null && plan2.LeftPlan != null)
146  // This is a left clash
147  return 2;
148  if (plan1.RightPlan != null && plan2.RightPlan != null)
149  // This is a right clash
150  return 1;
151  if ((plan1.LeftPlan == null && plan2.RightPlan == null) ||
152  (plan1.RightPlan == null && plan2.LeftPlan == null))
153  // This means a merge between the plans is fine
154  return 0;
155 
156  // Must be a left and right clash
157  return 2;
158  }
QueryTablePlanner Deveel.Data.Sql.Query.QueryTablePlanner.Clone ( )
inlineprivate

Definition at line 309 of file QueryTablePlanner.cs.

309  {
310  var copy = new QueryTablePlanner();
311 
312  int sz = tablePlans.Count;
313  for (int i = 0; i < sz; ++i) {
314  copy.tablePlans.Add(tablePlans[i].Clone());
315  }
316 
317  // Copy the left and right links in the PlanTableSource
318  for (int i = 0; i < sz; ++i) {
319  var src = tablePlans[i];
320  var mod = copy.tablePlans[i];
321 
322  // See how the left plan links to which index,
323  if (src.LeftPlan != null) {
324  int n = IndexOfPlan(src.LeftPlan);
325  mod.LeftJoin(copy.tablePlans[n], src.LeftJoinType, src.LeftOnExpression);
326  }
327 
328  // See how the right plan links to which index,
329  if (src.RightPlan != null) {
330  int n = IndexOfPlan(src.RightPlan);
331  mod.RightJoin(copy.tablePlans[n], src.RightJoinType, src.RightOnExpression);
332  }
333  }
334 
335  return copy;
336  }
static TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.ConcatPlans ( TablePlan  left,
TablePlan  right,
IQueryPlanNode  plan 
)
inlinestaticprivate

Definition at line 53 of file QueryTablePlanner.cs.

53  {
54  // Merge the variable list
55  var newVarList = new ObjectName[left.ColumnNames.Length + right.ColumnNames.Length];
56  Array.Copy(left.ColumnNames, 0, newVarList, 0, left.ColumnNames.Length);
57  Array.Copy(right.ColumnNames, 0, newVarList, left.ColumnNames.Length - 1, right.ColumnNames.Length);
58 
59  // Merge the unique table names list
60  var newUniqueList = new string[left.UniqueNames.Length + right.UniqueNames.Length];
61  Array.Copy(left.UniqueNames, 0, newUniqueList, 0, left.UniqueNames.Length);
62  Array.Copy(right.UniqueNames, 0, newUniqueList, left.UniqueNames.Length - 1, right.UniqueNames.Length);
63 
64  // Return the new table source plan.
65  return new TablePlan(plan, newVarList, newUniqueList);
66  }
void Deveel.Data.Sql.Query.QueryTablePlanner.EvaluateConstants ( List< SqlExpression list,
List< ExpressionPlan plans 
)
inlineprivate

Definition at line 659 of file QueryTablePlanner.cs.

659  {
660  // For each constant variable
661  plans.AddRange(list.Select(expr => new ConstantPlan(this, expr)).Cast<ExpressionPlan>());
662  }
void Deveel.Data.Sql.Query.QueryTablePlanner.EvaluateMultiples ( List< SqlBinaryExpression list,
List< ExpressionPlan plans 
)
inlineprivate

Definition at line 500 of file QueryTablePlanner.cs.

500  {
501  // FUTURE OPTIMIZATION:
502  // This join order planner is a little primitive in design. It orders
503  // optimizable joins first and least optimizable last, but does not
504  // take into account other factors that we could use to optimize
505  // joins in the future.
506 
507  foreach (var expression in list) {
508  // Get the list of variables in the left hand and right hand side
509  var lhsVar = expression.Left.AsReferenceName();
510  var rhsVar = expression.Right.AsReferenceName();
511 
512  // Work out how optimizable the join is.
513  // The calculation is as follows;
514  // a) If both the lhs and rhs are a single variable then the
515  // optimizable value is set to 0.6f.
516  // b) If only one of lhs or rhs is a single variable then the
517  // optimizable value is set to 0.64f.
518  // c) Otherwise it is set to 0.68f (exhaustive select guarenteed).
519 
520  if (lhsVar == null && rhsVar == null) {
521  // Neither lhs or rhs are single vars
522  plans.Add(new ExhaustiveJoinPlan(this, expression));
523  } else if (lhsVar != null && rhsVar != null) {
524  // Both lhs and rhs are a single var (most optimizable type of
525  // join).
526  plans.Add(new StandardJoinPlan(this, expression, 0.60f));
527  } else {
528  // Either lhs or rhs is a single var
529  plans.Add(new StandardJoinPlan(this, expression, 064f));
530  }
531  }
532  }
void Deveel.Data.Sql.Query.QueryTablePlanner.EvaluatePatterns ( List< SqlBinaryExpression list,
List< ExpressionPlan plans 
)
inlineprivate

Definition at line 588 of file QueryTablePlanner.cs.

588  {
589  foreach (var expression in list) {
590  // If the LHS is a single column and the RHS is a constant then
591  // the conditions are right for a simple pattern search.
592  var leftColumnName = expression.Left.AsReferenceName();
593 
594  if (expression.IsConstant()) {
595  plans.Add(new ConstantPlan(this, expression));
596  } else if (leftColumnName != null &&
597  expression.Right.IsConstant()) {
598  plans.Add(new SimplePatternPlan(this, leftColumnName, expression));
599  } else {
600  // Otherwise we must assume a complex pattern search which may
601  // require a join. For example, 'a + b LIKE 'a%'' or
602  // 'a LIKE b'. At the very least, this will be an exhaustive
603  // search and at the worst it will be a join + exhaustive search.
604  // So we should evaluate these at the end of the evaluation order.
605  plans.Add(new ExhaustiveSelectPlan(this, expression));
606  }
607  }
608  }
void Deveel.Data.Sql.Query.QueryTablePlanner.EvaluateSingles ( List< SqlBinaryExpression list,
List< ExpressionPlan plans 
)
inlineprivate

Definition at line 610 of file QueryTablePlanner.cs.

610  {
611  // The list of simple expression plans (lhs = single)
612  var simplePlanList = new List<SingleColumnPlan>();
613  // The list of complex function expression plans (lhs = expression)
614  var complexPlanList = new List<SingleColumnPlan>();
615 
616  foreach (var expression in list) {
617  // The single var
618  ObjectName singleVar;
619  SqlExpressionType op = expression.ExpressionType;
620  SqlExpression left = expression.Left, right = expression.Right;
621 
622  if (op.IsSubQuery()) {
623  singleVar = expression.Left.AsReferenceName();
624 
625  if (singleVar != null) {
626  plans.Add(new SimpleSelectPlan(this, singleVar, op, expression.Right));
627  } else {
628  singleVar = expression.Left.DiscoverReferences().First();
629  plans.Add(new ComplexSinglePlan(this, singleVar, expression));
630  }
631  } else {
632  singleVar = expression.Left.DiscoverReferences().FirstOrDefault();
633  if (singleVar == null) {
634  // Reverse the expressions and the operator
635  var tempExp = left;
636  left = right;
637  right = tempExp;
638  op = op.Reverse();
639  singleVar = left.DiscoverReferences().First();
640  }
641 
642  var tableSource = FindPlan(singleVar);
643 
644  // Simple LHS?
645  var v = left.AsReferenceName();
646  if (v != null) {
647  AddSingleColumnPlan(simplePlanList, tableSource, v, singleVar, new []{left, right}, op);
648  } else {
649  // No, complex lhs
650  AddSingleColumnPlan(complexPlanList, tableSource, null, singleVar, new []{left, right}, op);
651  }
652  }
653  }
654 
655  plans.AddRange(simplePlanList.Select(plan => new SimpleSinglePlan(this, plan.UniqueName, plan.Expression)).Cast<ExpressionPlan>());
656  plans.AddRange(complexPlanList.Select(plan => new ComplexSinglePlan(this, plan.UniqueName, plan.Expression)).Cast<ExpressionPlan>());
657  }
TablePlan FindPlan(ObjectName reference)
static void AddSingleColumnPlan(IList< SingleColumnPlan > list, TablePlan table, ObjectName columnName, ObjectName uniqueName, SqlExpression[] expParts, SqlExpressionType op)
SqlExpressionType
All the possible type of SqlExpression supported
static SqlBinaryExpression Add(SqlExpression left, SqlExpression right)
Defines the base class for instances that represent SQL expression tree nodes.
void Deveel.Data.Sql.Query.QueryTablePlanner.EvaluateSubLogic ( List< SqlBinaryExpression list,
List< ExpressionPlan plans 
)
inlineprivate

Definition at line 446 of file QueryTablePlanner.cs.

446  {
447  foreach (var expression in list) {
448  var orExprs = new[] {expression.Left, expression.Right};
449 
450  // An optimizations here;
451 
452  // If all the expressions we are ORing together are in the same table
453  // then we should execute them before the joins, otherwise they
454  // should go after the joins.
455 
456  // The reason for this is because if we can lesson the amount of work a
457  // join has to do then we should. The actual time it takes to perform
458  // an OR search shouldn't change if it is before or after the joins.
459 
460  TablePlan common = null;
461 
462  foreach (var orExpr in orExprs) {
463  var vars = orExpr.DiscoverReferences().ToArray();
464 
465  bool breakRule = false;
466 
467  // If there are no variables then don't bother with this expression
468  if (vars.Any()) {
469  // Find the common table source (if any)
470  var ts = FindCommonPlan(vars);
471  bool orAfterJoins = false;
472  if (ts == null) {
473  // No common table, so OR after the joins
474  orAfterJoins = true;
475  } else if (common == null) {
476  common = ts;
477  } else if (common != ts) {
478  // No common table with the vars in this OR list so do this OR
479  // after the joins.
480  orAfterJoins = true;
481  }
482 
483  if (orAfterJoins) {
484  plans.Add(new SubLogicPlan(this, expression, 0.70f));
485 
486  // Continue to the next logic expression
487  breakRule = true;
488  }
489  }
490 
491  if (!breakRule) {
492  // Either we found a common table or there are no variables in the OR.
493  // Either way we should evaluate this after the join.
494  plans.Add(new SubLogicPlan(this, expression, 0.58f));
495  }
496  }
497  }
498  }
TablePlan FindCommonPlan(IList< ObjectName > columnNames)
void Deveel.Data.Sql.Query.QueryTablePlanner.EvaluateSubQueries ( List< SqlBinaryExpression list,
List< ExpressionPlan plans 
)
inlineprivate

Definition at line 534 of file QueryTablePlanner.cs.

534  {
535  foreach (var expression in list) {
536  bool exhaustive;
537 
538  var op = expression.ExpressionType;
539  if (op.IsSubQuery()) {
540  // Must be an exhaustive sub-command
541  exhaustive = true;
542  } else {
543  // Check that the left is a simple enough variable reference
544  var leftColumn = expression.Left.AsReferenceName();
545  if (leftColumn == null) {
546  exhaustive = true;
547  } else {
548  // Check that the right is a sub-command plan.
549  IQueryPlanNode rightPlan = expression.Right.AsQueryPlan();
550  if (rightPlan == null)
551  exhaustive = true;
552  else {
553  // Finally, check if the plan is correlated or not
554  var cv = rightPlan.DiscoverQueryReferences(1);
555  exhaustive = cv.Count != 0;
556  }
557  }
558  }
559 
560  if (exhaustive) {
561  // This expression could involve multiple variables, so we may need
562  // to join.
563  var columnNames = expression.DiscoverReferences().ToList();
564 
565  // Also find all correlated variables.
566  int level = 0;
567  var allCorrelated = expression.DiscoverQueryReferences(ref level);
568  int sz = allCorrelated.Count;
569 
570  // If there are no variables (and no correlated variables) then this
571  // must be a constant select, For example, 3 in ( select ... )
572  if (!columnNames.Any() && sz == 0) {
573  plans.Add(new ConstantPlan(this, expression));
574  } else {
575  columnNames.AddRange(allCorrelated.Select(cv => cv.Name));
576 
577  // An exhaustive expression plan which might require a join or a
578  // slow correlated search. This should be evaluated after the
579  // multiple variables are processed.
580  plans.Add(new ExhaustiveSubQueryPlan(this, columnNames.ToArray(), expression));
581  }
582  } else {
583  plans.Add(new SimpleSubQueryPlan(this, expression));
584  }
585  }
586  }
TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.FindCommonPlan ( IList< ObjectName columnNames)
inlineprivate

Definition at line 96 of file QueryTablePlanner.cs.

96  {
97  if (columnNames.Count == 0)
98  return null;
99 
100  TablePlan pivotPlan = null;
101  foreach (var columnName in columnNames) {
102  var plan = FindPlan(columnName);
103  if (pivotPlan == null) {
104  pivotPlan = plan;
105  } else if (plan != pivotPlan) {
106  return null;
107  }
108  }
109 
110  return pivotPlan;
111  }
TablePlan FindPlan(ObjectName reference)
TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.FindPlan ( ObjectName  reference)
inlineprivate

Definition at line 83 of file QueryTablePlanner.cs.

83  {
84  // If there is only 1 plan then assume the variable is in there.
85  if (tablePlans.Count == 1)
86  return tablePlans[0];
87 
88  foreach (var source in tablePlans) {
89  if (source.ContainsColumn(reference))
90  return source;
91  }
92 
93  throw new ArgumentException("Unable to find table with variable reference: " + reference);
94  }
int Deveel.Data.Sql.Query.QueryTablePlanner.IndexOfPlan ( TablePlan  plan)
inlineprivate

Definition at line 43 of file QueryTablePlanner.cs.

43  {
44  int sz = tablePlans.Count;
45  for (int i = 0; i < sz; ++i) {
46  if (tablePlans[i] == plan)
47  return i;
48  }
49 
50  return -1;
51  }
void Deveel.Data.Sql.Query.QueryTablePlanner.JoinAt ( int  betweenIndex,
JoinType  joinType,
SqlExpression  onExpression 
)
inline

Definition at line 783 of file QueryTablePlanner.cs.

783  {
784  var planLeft = tablePlans[betweenIndex];
785  var planRight = tablePlans[betweenIndex + 1];
786  planLeft.RightJoin(planRight, joinType, onExpression);
787  planRight.LeftJoin(planLeft, joinType, onExpression);
788  }
TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.JoinPlansForColumns ( IEnumerable< ObjectName columnNames)
inlineprivate

Definition at line 119 of file QueryTablePlanner.cs.

119  {
120  // Collect all the plans that encapsulate these variables.
121  var touchedPlans = new List<TablePlan>();
122 
123  foreach (var name in columnNames) {
124  var plan = FindPlan(name);
125 
126  if (!touchedPlans.Contains(plan))
127  touchedPlans.Add(plan);
128  }
129 
130  return JoinToSingle(touchedPlans);
131  }
TablePlan FindPlan(ObjectName reference)
TablePlan JoinToSingle(IList< TablePlan > allPlans)
TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.JoinToSingle ( IList< TablePlan allPlans)
inlineprivate

Definition at line 224 of file QueryTablePlanner.cs.

224  {
225  // If there are no plans then return null
226  if (allPlans.Count == 0)
227  return null;
228 
229  if (allPlans.Count == 1)
230  // Return early if there is only 1 table.
231  return allPlans[0];
232 
233  // Make a working copy of the plan list.
234  var workingPlanList = new List<TablePlan>(allPlans);
235 
236  // We go through each plan in turn.
237  while (workingPlanList.Count > 1) {
238  var leftPlan = workingPlanList[0];
239  var rightPlan = workingPlanList[1];
240 
241  // First we need to determine if the left and right plan can be
242  // naturally joined.
243  int status = AssertBeNaturalJoin(leftPlan, rightPlan);
244  if (status == 0) {
245  // Yes they can so join them
246  var newPlan = NaturallyJoinPlans(leftPlan, rightPlan);
247 
248  // Remove the left and right plan from the list and add the new plan
249  workingPlanList.Remove(leftPlan);
250  workingPlanList.Remove(rightPlan);
251  workingPlanList.Insert(0, newPlan);
252  } else if (status == 1) {
253  // No we can't because of a right join clash, so we join the left
254  // plan right in hopes of resolving the clash.
255  var newPlan = NaturallyJoinPlans(leftPlan, leftPlan.RightPlan);
256  workingPlanList.Remove(leftPlan);
257  workingPlanList.Remove(leftPlan.RightPlan);
258  workingPlanList.Insert(0, newPlan);
259  } else if (status == 2) {
260  // No we can't because of a left join clash, so we join the left
261  // plan left in hopes of resolving the clash.
262  var newPlan = NaturallyJoinPlans(leftPlan, leftPlan.LeftPlan);
263  workingPlanList.Remove(leftPlan);
264  workingPlanList.Remove(leftPlan.LeftPlan);
265  workingPlanList.Insert(0, newPlan);
266  } else {
267  throw new InvalidOperationException(String.Format("Natural join assessed status {0} is unknown.", status));
268  }
269  }
270 
271  // Return the working plan of the merged tables.
272  return workingPlanList[0];
273  }
TablePlan NaturallyJoinPlans(TablePlan plan1, TablePlan plan2)
A long string in the system.
static int AssertBeNaturalJoin(TablePlan plan1, TablePlan plan2)
IQueryPlanNode Deveel.Data.Sql.Query.QueryTablePlanner.LogicalEvaluate ( SqlExpression  expression)
inlineprivate

Definition at line 275 of file QueryTablePlanner.cs.

275  {
276  if (expression == null) {
277  // Naturally join everything and return the plan.
278  NaturalJoinAll();
279  return SinglePlan.Plan;
280  }
281 
282  // Plan the expression
283  PlanExpression(expression);
284 
285  // Naturally join any straggling tables
286  NaturalJoinAll();
287 
288  // Return the plan
289  return SinglePlan.Plan;
290  }
IQueryPlanNode Plan
Returns the plan for this table source.
Definition: TablePlan.cs:41
void PlanExpression(SqlExpression expression)
TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.MergePlans ( TablePlan  left,
TablePlan  right,
IQueryPlanNode  mergePlan 
)
inlineprivate

Definition at line 68 of file QueryTablePlanner.cs.

68  {
69  // Remove the sources from the table list.
70  tablePlans.Remove(left);
71  tablePlans.Remove(right);
72 
73  // Add the concatenation of the left and right tables.
74  var newPlan = ConcatPlans(left, right, mergePlan);
75  newPlan.MergeJoin(left, right);
76  newPlan.SetUpdated();
77 
78  AddPlan(newPlan);
79 
80  return newPlan;
81  }
static TablePlan ConcatPlans(TablePlan left, TablePlan right, IQueryPlanNode plan)
TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.NaturalJoinAll ( )
inlineprivate

Definition at line 133 of file QueryTablePlanner.cs.

133  {
134  int sz = tablePlans.Count;
135  if (sz == 1)
136  return tablePlans[0];
137 
138  // Produce a plan that naturally joins all tables.
139  return JoinToSingle(tablePlans);
140  }
TablePlan JoinToSingle(IList< TablePlan > allPlans)
TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.NaturallyJoinPlans ( TablePlan  plan1,
TablePlan  plan2 
)
inlineprivate

Definition at line 160 of file QueryTablePlanner.cs.

160  {
161  JoinType joinType;
162  SqlExpression onExpr;
163  TablePlan leftPlan, rightPlan;
164 
165  // Are the plans linked by common join information?
166  if (plan1.RightPlan == plan2) {
167  joinType = plan1.RightJoinType;
168  onExpr = plan1.RightOnExpression;
169  leftPlan = plan1;
170  rightPlan = plan2;
171  } else if (plan1.LeftPlan == plan2) {
172  joinType = plan1.LeftJoinType;
173  onExpr = plan1.LeftOnExpression;
174  leftPlan = plan2;
175  rightPlan = plan1;
176  } else {
177  // Assertion - make sure no join clashes!
178  if ((plan1.LeftPlan != null && plan2.LeftPlan != null) ||
179  (plan1.RightPlan != null && plan2.RightPlan != null)) {
180  throw new InvalidOperationException("Plans can not be naturally join because " +
181  "the left/right join plans clash.");
182  }
183 
184  // Else we must assume a non-dependent join (not an outer join).
185  // Perform a natural join
186  IQueryPlanNode node1 = new NaturalJoinNode(plan1.Plan, plan2.Plan);
187  return MergePlans(plan1, plan2, node1);
188  }
189 
190  // This means plan1 and plan2 are linked by a common join and ON
191  // expression which we evaluate now.
192  bool outerJoin;
193  if (joinType == JoinType.Left) {
194  // Mark the left plan
195  leftPlan.UpdatePlan(new MarkerNode(leftPlan.Plan, "OUTER_JOIN"));
196  outerJoin = true;
197  } else if (joinType == JoinType.Right) {
198  // Mark the right plan
199  rightPlan.UpdatePlan(new MarkerNode(rightPlan.Plan, "OUTER_JOIN"));
200  outerJoin = true;
201  } else if (joinType == JoinType.Inner) {
202  // Inner join with ON expression
203  outerJoin = false;
204  } else {
205  throw new InvalidOperationException(String.Format("Join type ({0}) is not supported.", joinType));
206  }
207 
208  // Make a Planner object for joining these plans.
209  var planner = new QueryTablePlanner();
210  planner.AddPlan(leftPlan.Clone());
211  planner.AddPlan(rightPlan.Clone());
212 
213  // Evaluate the on expression
214  var node = planner.LogicalEvaluate(onExpr);
215 
216  // If outer join add the left outer join node
217  if (outerJoin)
218  node = new LeftOuterJoinNode(node, "OUTER_JOIN");
219 
220  // And merge the plans in this set with the new node.
221  return MergePlans(plan1, plan2, node);
222  }
A long string in the system.
JoinType
Enumerates the kind of group join in a selection query.
Definition: JoinType.cs:23
TablePlan MergePlans(TablePlan left, TablePlan right, IQueryPlanNode mergePlan)
Defines the base class for instances that represent SQL expression tree nodes.
void Deveel.Data.Sql.Query.QueryTablePlanner.PlanAllOuterJoins ( )
inlineprivate

Definition at line 338 of file QueryTablePlanner.cs.

338  {
339  int sz = tablePlans.Count;
340  if (sz <= 1)
341  return;
342 
343  // Make a working copy of the plan list.
344  var workingPlanList = new List<TablePlan>(tablePlans);
345 
346  var plan1 = workingPlanList[0];
347  for (int i = 1; i < sz; ++i) {
348  var plan2 = workingPlanList[i];
349 
350  if (plan1.RightPlan == plan2) {
351  plan1 = NaturallyJoinPlans(plan1, plan2);
352  } else {
353  plan1 = plan2;
354  }
355  }
356  }
TablePlan NaturallyJoinPlans(TablePlan plan1, TablePlan plan2)
void Deveel.Data.Sql.Query.QueryTablePlanner.PlanExpression ( SqlExpression  expression)
inlineprivate

Definition at line 664 of file QueryTablePlanner.cs.

664  {
665  if (expression is SqlBinaryExpression &&
666  expression.ExpressionType.IsLogical()) {
667  var binary = (SqlBinaryExpression) expression;
668 
669  if (expression.ExpressionType == SqlExpressionType.Or) {
670  // parsing an OR block
671  // Split left and right of logical operator.
672  var exps = new[]{binary.Left, binary.Right};
673 
674  // If we are an 'or' then evaluate left and right and union the
675  // result.
676 
677  // Before we branch set cache points.
678  SetCachePoints();
679 
680  // Make copies of the left and right planner
681  var leftPlanner = Clone();
682  var rightPlanner = Clone();
683 
684  // Plan the left and right side of the OR
685  leftPlanner.PlanExpression(exps[0]);
686  rightPlanner.PlanExpression(exps[1]);
687 
688  // Fix the left and right planner so that they represent the same
689  // 'group'.
690  // The current implementation naturally joins all sources if the
691  // number of sources is different than the original size.
692  int leftSz = leftPlanner.tablePlans.Count;
693  int rightSz = rightPlanner.tablePlans.Count;
694  if (leftSz != rightSz || leftPlanner.HasJoin || rightPlanner.HasJoin) {
695  // Naturally join all in the left and right plan
696  leftPlanner.NaturalJoinAll();
697  rightPlanner.NaturalJoinAll();
698  }
699 
700  // Union all table sources, but only if they have changed.
701  var leftTableList = leftPlanner.tablePlans;
702  var rightTableList = rightPlanner.tablePlans;
703  int sz = leftTableList.Count;
704 
705  // First we must determine the plans that need to be joined in the
706  // left and right plan.
707  var leftJoinList = new List<TablePlan>();
708  var rightJoinList = new List<TablePlan>();
709  for (int i = 0; i < sz; ++i) {
710  var leftPlan = leftTableList[i];
711  var rightPlan = rightTableList[i];
712  if (leftPlan.IsUpdated || rightPlan.IsUpdated) {
713  leftJoinList.Add(leftPlan);
714  rightJoinList.Add(rightPlan);
715  }
716  }
717 
718  // Make sure the plans are joined in the left and right planners
719  leftPlanner.JoinToSingle(leftJoinList);
720  rightPlanner.JoinToSingle(rightJoinList);
721 
722  // Since the planner lists may have changed we update them here.
723  leftTableList = leftPlanner.tablePlans;
724  rightTableList = rightPlanner.tablePlans;
725  sz = leftTableList.Count;
726 
727  var newTableList = new List<TablePlan>(sz);
728 
729  for (int i = 0; i < sz; ++i) {
730  var leftPlan = leftTableList[i];
731  var rightPlan = rightTableList[i];
732 
733  TablePlan newPlan;
734 
735  // If left and right plan updated so we need to union them
736  if (leftPlan.IsUpdated || rightPlan.IsUpdated) {
737  // In many causes, the left and right branches will contain
738  // identical branches that would best be optimized out.
739 
740  // Take the left plan, add the logical union to it, and make it
741  // the plan for this.
742  var node = new LogicalUnionNode(leftPlan.Plan, rightPlan.Plan);
743 
744  // Update the plan in this table list
745  leftPlan.UpdatePlan(node);
746 
747  newPlan = leftPlan;
748  } else {
749  // If the left and right plan didn't update, then use the
750  // left plan (it doesn't matter if we use left or right because
751  // they are the same).
752  newPlan = leftPlan;
753  }
754 
755  // Add the left plan to the new table list we are creating
756  newTableList.Add(newPlan);
757 
758  }
759 
760  // Set the new table list
761  tablePlans = newTableList;
762  } else if (expression.ExpressionType == SqlExpressionType.And) {
763  PlanExpressionList(new[]{binary.Left, binary.Right});
764  } else {
765  throw new InvalidOperationException();
766  }
767  } else {
768  PlanExpressionList(new []{expression});
769  }
770  }
SqlExpressionType
All the possible type of SqlExpression supported
void PlanExpressionList(IEnumerable< SqlExpression > expressions)
abstract SqlExpressionType ExpressionType
Gets the type code of this SQL expression.
void Deveel.Data.Sql.Query.QueryTablePlanner.PlanExpressionList ( IEnumerable< SqlExpression expressions)
inlineprivate

Definition at line 358 of file QueryTablePlanner.cs.

358  {
359  var subLogicExpressions = new List<SqlBinaryExpression>();
360  // The list of expressions that have a sub-select in them.
361  var subQueryExpressions = new List<SqlBinaryExpression>();
362  // The list of all constant expressions ( true = true )
363  var constants = new List<SqlExpression>();
364  // The list of pattern matching expressions (eg. 't LIKE 'a%')
365  var patternExpressions = new List<SqlBinaryExpression>();
366  // The list of all expressions that are a single variable on one
367  // side, a conditional operator, and a constant on the other side.
368  var singleVars = new List<SqlBinaryExpression>();
369  // The list of multi variable expressions (possible joins)
370  var multiVars = new List<SqlBinaryExpression>();
371 
372  foreach (var expression in expressions) {
374 
375  if (!(expression is SqlBinaryExpression)) {
376  // If this is not a binary expression we imply
377  // [expression] = 'true'
378  exp = SqlExpression.Equal(expression, SqlExpression.Constant(true));
379  } else {
380  exp = (SqlBinaryExpression) expression;
381  }
382 
383  if (exp.ExpressionType.IsLogical()) {
384  subLogicExpressions.Add(exp);
385  } else if (exp.HasSubQuery()) {
386  subQueryExpressions.Add(exp);
387  } else if (exp.ExpressionType.IsPattern()) {
388  patternExpressions.Add(exp);
389  } else {
390  // The list of variables in the expression.
391  var columnNames = exp.DiscoverReferences().ToList();
392  if (columnNames.Count == 0) {
393  // These are ( 54 + 9 = 9 ), ( "z" > "a" ), ( 9.01 - 2 ), etc
394  constants.Add(exp);
395  } else if (columnNames.Count == 1) {
396  // These are ( id = 90 ), ( 'a' < number ), etc
397  singleVars.Add(exp);
398  } else if (columnNames.Count > 1) {
399  // These are ( id = part_id ),
400  // ( cost_of + value_of < sold_at ), ( id = part_id - 10 )
401  multiVars.Add(exp);
402  } else {
403  throw new InvalidOperationException("Invalid number of column names");
404  }
405  }
406  }
407 
408  // The order in which expression are evaluated,
409  // (ExpressionPlan)
410  var evaluateOrder = new List<ExpressionPlan>();
411 
412  // Evaluate the constants. These should always be evaluated first
413  // because they always evaluate to either true or false or null.
414  EvaluateConstants(constants, evaluateOrder);
415 
416  // Evaluate the singles. If formed well these can be evaluated
417  // using fast indices. eg. (a > 9 - 3) is more optimal than
418  // (a + 3 > 9).
419  EvaluateSingles(singleVars, evaluateOrder);
420 
421  // Evaluate the pattern operators. Note that some patterns can be
422  // optimized better than others, but currently we keep this near the
423  // middle of our evaluation sequence.
424  EvaluatePatterns(patternExpressions, evaluateOrder);
425 
426  // Evaluate the sub-queries. These are queries of the form,
427  // (a IN ( SELECT ... )), (a = ( SELECT ... ) = ( SELECT ... )), etc.
428  EvaluateSubQueries(subQueryExpressions, evaluateOrder);
429 
430  // Evaluate multiple variable expressions. It's possible these are
431  // joins.
432  EvaluateMultiples(multiVars, evaluateOrder);
433 
434  // Lastly evaluate the sub-logic expressions. These expressions are
435  // OR type expressions.
436  EvaluateSubLogic(subLogicExpressions, evaluateOrder);
437 
438  evaluateOrder.Sort();
439 
440  // And add each expression to the plan
441  foreach (ExpressionPlan plan in evaluateOrder) {
442  plan.AddToPlanTree();
443  }
444  }
void EvaluateConstants(List< SqlExpression > list, List< ExpressionPlan > plans)
void EvaluatePatterns(List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
static SqlBinaryExpression Equal(SqlExpression left, SqlExpression right)
void EvaluateSubQueries(List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
static SqlBinaryExpression Add(SqlExpression left, SqlExpression right)
void EvaluateSubLogic(List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
Defines the base class for instances that represent SQL expression tree nodes.
static SqlConstantExpression Constant(object value)
void EvaluateSingles(List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
void EvaluateMultiples(List< SqlBinaryExpression > list, List< ExpressionPlan > plans)
IQueryPlanNode Deveel.Data.Sql.Query.QueryTablePlanner.PlanSearchExpression ( SqlExpression  searchExpression)
inline

Definition at line 790 of file QueryTablePlanner.cs.

790  {
791  // First perform all outer tables.
793 
794  return LogicalEvaluate(searchExpression);
795  }
IQueryPlanNode LogicalEvaluate(SqlExpression expression)
void Deveel.Data.Sql.Query.QueryTablePlanner.SetCachePoints ( )
inlineprivate

Definition at line 113 of file QueryTablePlanner.cs.

113  {
114  foreach (var plan in tablePlans) {
115  plan.SetCachePoint();
116  }
117  }

Member Data Documentation

List<TablePlan> Deveel.Data.Sql.Query.QueryTablePlanner.tablePlans
private

Definition at line 25 of file QueryTablePlanner.cs.

Property Documentation

bool Deveel.Data.Sql.Query.QueryTablePlanner.HasJoin
getprivate set

Definition at line 32 of file QueryTablePlanner.cs.

TablePlan Deveel.Data.Sql.Query.QueryTablePlanner.SinglePlan
get

Definition at line 34 of file QueryTablePlanner.cs.


The documentation for this class was generated from the following file: