/// <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);
                }
            }
        }
Beispiel #4
0
        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);
        }