/// <summary> /// Build the current operation in the <see cref="QueryExecutionPlan"/> by reading the abstract syntax tree. /// </summary> /// <param name="scope">Scope of the current <see cref="ParseTreeNode"/>.</param> /// <param name="node">Current <see cref="ParseTreeNode"/> in the abstract syntax tree.</param> /// <param name="plan">The current <see cref="QueryExecutionPlan"/> being built.</param> public void BuildOperation(Stack<string> scope, ParseTreeNode node, QueryExecutionPlan plan) { if (node.Term.Name == "selectStmt") { // Select clause plan.Operations.Add(new LevelDbSelectOperation()); } else if (scope.Contains("selList") && node.Term.Name == "id_simple") { // Select column list plan.Current.ColumnNames.Add(node.Token.ValueString); } else if (scope.Contains("selList") && node.Term.Name == "*") { // Select column list plan.Current.ColumnNames.Add(node.Token.ValueString); } else if (scope.Contains("fromClauseOpt") && node.Term.Name == "id_simple") { // From clause plan.Current.TableName = node.Token.ValueString; } else if (scope.Contains("whereClauseOpt") && node.Term.Name == "binExpr") { // Where clause var column = node.ChildNodes[0].ChildNodes[0].Token.ValueString; var val = node.ChildNodes[2].Token.ValueString; plan.Current.WhereClauses.Add(column, val); } }
/// <summary> /// Build the current operation in the <see cref="QueryExecutionPlan"/> by reading the abstract syntax tree. /// </summary> /// <param name="scope">Scope of the current <see cref="ParseTreeNode"/>.</param> /// <param name="node">Current <see cref="ParseTreeNode"/> in the abstract syntax tree.</param> /// <param name="plan">The current <see cref="QueryExecutionPlan"/> being built.</param> public void BuildOperation(Stack <string> scope, ParseTreeNode node, QueryExecutionPlan plan) { if (node.Term.Name == this.OperationName) { // Select clause plan.Operations.Add(new SelectOperation()); } var operation = (SelectOperation)plan.Current; if (scope.Contains("selList") && node.Term.Name == "id_simple") { // Select column list operation.ColumnNames.Add(node.Token.ValueString); } else if (scope.Contains("selList") && node.Term.Name == "*") { // Select column list operation.ColumnNames.Add(node.Token.ValueString); } else if (scope.Contains("fromClauseOpt") && node.Term.Name == "id_simple") { // From clause operation.TableName = node.Token.ValueString; } else if (scope.Contains("whereClauseOpt") && node.Term.Name == "binExpr") { // Where clause if (node.ChildNodes[0].Term.Name == "binExpr") { // Handle multiple where clauses. foreach (var child in node.ChildNodes) { if (child.Term.Name == "binExpr") { var column = child.ChildNodes[0].ChildNodes[0].Token.ValueString; var val = child.ChildNodes[2].Token.ValueString; operation.WhereClauses.Add(column, val); } } } else if (node.Term.Name == "binExpr" && operation.WhereClauses.Count == 0) { // Handle a single where clause. var column = node.ChildNodes[0].ChildNodes[0].Token.ValueString; var val = node.ChildNodes[2].Token.ValueString; operation.WhereClauses.Add(column, val); } } }
/// <summary> /// Build the current operation in the <see cref="QueryExecutionPlan"/> by reading the abstract syntax tree. /// </summary> /// <param name="scope">Scope of the current <see cref="ParseTreeNode"/>.</param> /// <param name="node">Current <see cref="ParseTreeNode"/> in the abstract syntax tree.</param> /// <param name="plan">The current <see cref="QueryExecutionPlan"/> being built.</param> public void BuildOperation(Stack <string> scope, ParseTreeNode node, QueryExecutionPlan plan) { UpdateOperation operation; if (node.Term.Name == this.OperationName) { // Update statement operation = new UpdateOperation(); operation.TableName = node.ChildNodes[1].ChildNodes[0].Token.ValueString; plan.Operations.Add(operation); } operation = (UpdateOperation)plan.Current; if (node.Term.Name == "assignment") { operation.Assignments.Add(node.ChildNodes[0].ChildNodes[0].Token.ValueString, node.ChildNodes[2].Token.ValueString); } else if (scope.Contains("whereClauseOpt") && node.Term.Name == "binExpr") { // Where clause if (node.ChildNodes[0].Term.Name == "binExpr") { // Handle multiple where clauses. foreach (var child in node.ChildNodes) { if (child.Term.Name == "binExpr") { var column = child.ChildNodes[0].ChildNodes[0].Token.ValueString; var val = child.ChildNodes[2].Token.ValueString; operation.WhereClauses.Add(column, val); } } } else if (node.Term.Name == "binExpr" && operation.WhereClauses.Count == 0) { // Handle a single where clause. var column = node.ChildNodes[0].ChildNodes[0].Token.ValueString; var val = node.ChildNodes[2].Token.ValueString; operation.WhereClauses.Add(column, val); } } }
IList <PackedObject> ProcessAndQuery(AndQuery query, ExecutionPlan executionPlan) { if (query.Elements.Count == 1) { return(ProcessSimpleQuery(query.Elements[0], executionPlan)); } var queryExecutionPlan = new QueryExecutionPlan(query.ToString()); // this method can be called in parallel. The only common data is the global execution plan lock (executionPlan) { executionPlan.QueryPlans.Add(queryExecutionPlan); } queryExecutionPlan.StartPlanning(); var indexesToUse = GetIndexesForQuery(query); queryExecutionPlan.EndPlanning(); // this will contain all queries that have can not be resolved by indexes and need to be checked manually var restOfTheQuery = query.Clone(); ISet <PackedObject> result = null; var finalResult = new List <PackedObject>(); if (indexesToUse.Count == 1) // only one index can be used so do not bother with extra logic { queryExecutionPlan.StartIndexUse(); var plan = indexesToUse[0]; queryExecutionPlan.Trace($"single index: {plan.ResolvedQuery.PropertyName}"); result = plan.Index.GetMany(plan.ResolvedQuery.Values, plan.ResolvedQuery.Operator); // this query was resolved by an index so no need to check it manually restOfTheQuery.Elements.Remove(plan.ResolvedQuery); queryExecutionPlan.EndIndexUse(); } else if (indexesToUse.Count > 1) { queryExecutionPlan.StartIndexUse(); foreach (var plan in indexesToUse.OrderBy(p => p.Ranking).Take(2)) // no more than two indexes { if (result == null) { result = plan.Index.GetMany(plan.ResolvedQuery.Values, plan.ResolvedQuery.Operator); queryExecutionPlan.Trace($"first index: {plan.ResolvedQuery.PropertyName} = {plan.Ranking}"); } else { result.IntersectWith(plan.Index.GetMany(plan.ResolvedQuery.Values, plan.ResolvedQuery.Operator)); queryExecutionPlan.Trace($"then index: {plan.ResolvedQuery.PropertyName} = {plan.Ranking} => {result.Count}"); } // do not work too hard if indexes found nothing if (result.Count == 0) { break; } // this query was resolved by an index so no need to check it manually restOfTheQuery.Elements.Remove(plan.ResolvedQuery); } queryExecutionPlan.EndIndexUse(); } else // no index can be used so proceed to full-scan { queryExecutionPlan.FullScan = true; queryExecutionPlan.StartScan(); var res = _dataStore.PrimaryIndex.GetAll().Where(o => restOfTheQuery.Match(o)).ToList(); queryExecutionPlan.EndScan(); return(res); } if (result != null) { if (restOfTheQuery.Elements.Count == 0) // empty query left; fully resolved by indexes { return(result.ToList()); } queryExecutionPlan.StartScan(); foreach (var item in result) { if (restOfTheQuery.Match(item)) { finalResult.Add(item); } } queryExecutionPlan.EndScan(); } return(finalResult); }