public void Visit(CteInnerExpressionNode node)
        {
            var set = Nodes.Pop();

            var collector = new SelectFieldsCollectVisitor();
            var traverser = new CloneTraverseVisitor(collector);

            set.Accept(traverser);

            var table = new VariableTable(collector.CollectedFieldNames);

            _currentScope.Parent.ScopeSymbolTable.AddSymbol(node.Name,
                                                            new TableSymbol(node.Name, new TransitionSchema(node.Name, table), table, false));

            Nodes.Push(new CteInnerExpressionNode(set, node.Name));
        }
Example #2
0
        public void Visit(QueryNode node)
        {
            var orderBy = node.OrderBy != null?Nodes.Pop() as OrderByNode : null;

            var groupBy = node.GroupBy != null?Nodes.Pop() as GroupByNode : null;

            var skip = node.Skip != null?Nodes.Pop() as SkipNode : null;

            var take = node.Take != null?Nodes.Pop() as TakeNode : null;

            var select = Nodes.Pop() as SelectNode;

            var where = node.Where != null?Nodes.Pop() as WhereNode : null;

            var from = Nodes.Pop() as ExpressionFromNode;

            var scoreSelect = select;
            var scoreWhere  = where;

            QueryNode query;

            var splittedNodes = new List <Node>();
            var source        = from.Alias.ToRowsSource().WithRowsUsage();

            QueryNode lastJoinQuery = null;

            _scope[MetaAttributes.MethodName] = $"ComputeTable_{from.Alias}";

            IReadOnlyList <AccessMethodNode> usedRefreshMethods = null;

            if (_scope.ScopeSymbolTable.SymbolIsOfType <RefreshMethodsSymbol>(from.Alias.ToRefreshMethodsSymbolName()))
            {
                usedRefreshMethods = _scope.ScopeSymbolTable
                                     .GetSymbol <RefreshMethodsSymbol>(from.Alias.ToRefreshMethodsSymbolName()).RefreshMethods;
            }

            if (from.Expression is JoinsNode)
            {
                var current = _joinedTables[0];
                var left    = _scope.ScopeSymbolTable.GetSymbol <TableSymbol>(current.Source.Alias);
                var right   = _scope.ScopeSymbolTable.GetSymbol <TableSymbol>(current.With.Alias);

                var scopeCreateTable = _scope.AddScope("Table");
                var scopeJoinedQuery = _scope.AddScope("Query");

                var bothForCreateTable = CreateAndConcatFields(left, current.Source.Alias, right, current.With.Alias,
                                                               (name, alias) => NamingHelper.ToColumnName(alias, name));
                var bothForSelect = CreateAndConcatFields(left, current.Source.Alias, right, current.With.Alias,
                                                          (name, alias) => name);

                scopeJoinedQuery.ScopeSymbolTable.AddSymbol(current.Source.Alias, left);
                scopeJoinedQuery.ScopeSymbolTable.AddSymbol(current.With.Alias, right);

                var targetTableName = $"{current.Source.Alias}{current.With.Alias}";

                scopeJoinedQuery.ScopeSymbolTable.AddSymbol(targetTableName,
                                                            _scope.ScopeSymbolTable.GetSymbol(targetTableName));
                scopeJoinedQuery[MetaAttributes.SelectIntoVariableName]  = targetTableName.ToTransitionTable();
                scopeCreateTable[MetaAttributes.CreateTableVariableName] = targetTableName.ToTransitionTable();


                var joinedQuery = new InternalQueryNode(
                    new SelectNode(bothForSelect),
                    new ExpressionFromNode(new JoinSourcesTableFromNode(current.Source, current.With,
                                                                        current.Expression)),
                    null,
                    null,
                    null,
                    null,
                    null,
                    new RefreshNode(new AccessMethodNode[0]));

                var targetTable = new CreateTableNode(targetTableName, new string[0], bothForCreateTable, false);

                splittedNodes.Add(targetTable);
                splittedNodes.Add(joinedQuery);

                lastJoinQuery = joinedQuery;
                source        = targetTableName.ToTransitionTable().ToTransformedRowsSource();

                var usedTables = new Dictionary <string, string>
                {
                    { current.Source.Alias, targetTableName },
                    { current.With.Alias, targetTableName }
                };

                for (var i = 1; i < _joinedTables.Count; i++)
                {
                    current = _joinedTables[i];
                    left    = _scope.ScopeSymbolTable.GetSymbol <TableSymbol>(current.Source.Alias);
                    right   = _scope.ScopeSymbolTable.GetSymbol <TableSymbol>(current.With.Alias);

                    targetTableName = $"{current.Source.Alias}{current.With.Alias}";

                    scopeCreateTable = _scope.AddScope("Table");
                    scopeJoinedQuery = _scope.AddScope("Query");

                    bothForCreateTable = CreateAndConcatFields(left, current.Source.Alias, right, current.With.Alias,
                                                               (name, alias) => NamingHelper.ToColumnName(alias, name));
                    bothForSelect = CreateAndConcatFields(
                        left,
                        current.Source.Alias,
                        right,
                        current.With.Alias,
                        (name, alias) => NamingHelper.ToColumnName(alias, name),
                        (name, alias) => name,
                        (name, alias) => NamingHelper.ToColumnName(alias, name),
                        (name, alias) => name);

                    scopeJoinedQuery.ScopeSymbolTable.AddSymbol(current.Source.Alias, left);
                    scopeJoinedQuery.ScopeSymbolTable.AddSymbol(current.With.Alias, right);

                    scopeJoinedQuery.ScopeSymbolTable.AddSymbol(targetTableName,
                                                                _scope.ScopeSymbolTable.GetSymbol(targetTableName));
                    scopeJoinedQuery[MetaAttributes.SelectIntoVariableName]  = targetTableName.ToTransitionTable();
                    scopeCreateTable[MetaAttributes.CreateTableVariableName] = targetTableName.ToTransitionTable();

                    var expressionUpdater = new RewriteWhereConditionWithUpdatedColumnAccess(usedTables);
                    var traverser         = new CloneTraverseVisitor(expressionUpdater);

                    new WhereNode(current.Expression).Accept(traverser);

                    foreach (var key in usedTables.Keys.ToArray())
                    {
                        usedTables[key] = targetTableName;
                    }

                    usedTables[current.Source.Alias] = targetTableName;
                    usedTables.Add(current.With.Alias, targetTableName);

                    joinedQuery = new InternalQueryNode(
                        new SelectNode(bothForSelect),
                        new ExpressionFromNode(new JoinInMemoryWithSourceTableFromNode(current.Source.Alias,
                                                                                       current.With, expressionUpdater.Where.Expression)),
                        null,
                        null,
                        null,
                        null,
                        null,
                        new RefreshNode(new AccessMethodNode[0]));

                    targetTable = new CreateTableNode(targetTableName, new string[0], bothForCreateTable, false);

                    splittedNodes.Add(targetTable);
                    splittedNodes.Add(joinedQuery);

                    lastJoinQuery = joinedQuery;
                    source        = targetTableName.ToTransitionTable().ToTransformedRowsSource();
                }

                var rewriter       = new RewritePartsToUseJoinTransitionTable();
                var partsTraverser = new CloneTraverseVisitor(rewriter);

                select.Accept(partsTraverser);
                where?.Accept(partsTraverser);

                scoreSelect = rewriter.ChangedSelect;
                scoreWhere  = rewriter.ChangedWhere;
            }

            if (groupBy != null)
            {
                var nestedFrom = splittedNodes.Count > 0
                    ? new ExpressionFromNode(new InMemoryGroupedFromNode(lastJoinQuery.From.Alias))
                    : from;

                var splitted       = SplitBetweenAggreateAndNonAggreagate(select.Fields, groupBy.Fields, true);
                var refreshMethods = CreateRefreshMethods(usedRefreshMethods);
                var aggSelect      = new SelectNode(ConcatAggregateFieldsWithGroupByFields(splitted[0], groupBy.Fields)
                                                    .Reverse().ToArray());
                var outSelect = new SelectNode(splitted[1]);

                var scopeCreateTranformingTable = _scope.AddScope("Table");
                var scopeTransformedQuery       = _scope.AddScope("Query");
                var scopeCreateResultTable      = _scope.AddScope("Table");
                var scopeResultQuery            = _scope.AddScope("Query");

                scopeCreateTranformingTable[MetaAttributes.CreateTableVariableName] = nestedFrom.Alias.ToGroupingTable();
                scopeCreateResultTable[MetaAttributes.CreateTableVariableName]      = nestedFrom.Alias.ToScoreTable();

                var destination = nestedFrom.Alias.ToGroupingTable().ToTransformedRowsSource();
                scopeTransformedQuery[MetaAttributes.SelectIntoVariableName] = destination;
                scopeTransformedQuery[MetaAttributes.SourceName]             = splittedNodes.Count > 0
                    ? nestedFrom.Alias.ToTransitionTable().ToTransformedRowsSource()
                    : nestedFrom.Alias.ToRowsSource().WithRowsUsage();
                scopeTransformedQuery.ScopeSymbolTable.AddSymbol(nestedFrom.Alias,
                                                                 _scope.ScopeSymbolTable.GetSymbol(nestedFrom.Alias));

                if (splittedNodes.Count > 0)
                {
                    var selectRewriter  = new RewritePartsToUseJoinTransitionTable(nestedFrom.Alias);
                    var selectTraverser = new CloneTraverseVisitor(selectRewriter);

                    groupBy.Accept(selectTraverser);
                    groupBy = selectRewriter.ChangedGroupBy;

                    scopeTransformedQuery.ScopeSymbolTable.AddSymbol("groupFields",
                                                                     new FieldsNamesSymbol(groupBy.Fields.Select(f => f.FieldName).ToArray()));

                    var newRefreshMethods = new List <AccessMethodNode>();
                    foreach (var method in refreshMethods.Nodes)
                    {
                        var newNodes = new List <Node>();
                        foreach (var arg in method.Arguments.Args)
                        {
                            arg.Accept(selectTraverser);
                            newNodes.Add(selectRewriter.RewrittenNode);
                        }

                        var newArgs = new ArgsListNode(newNodes.ToArray());
                        newRefreshMethods.Add(new AccessMethodNode(method.FToken, newArgs,
                                                                   method.ExtraAggregateArguments, method.Method));
                    }

                    refreshMethods = new RefreshNode(newRefreshMethods.ToArray());
                }
                else
                {
                    scopeTransformedQuery.ScopeSymbolTable.AddSymbol("groupFields",
                                                                     new FieldsNamesSymbol(groupBy.Fields.Select(f => f.Expression.ToString()).ToArray()));
                }

                var transformingQuery = new InternalQueryNode(aggSelect, nestedFrom, where, groupBy, null, null, null,
                                                              refreshMethods);

                var returnScore = nestedFrom.Alias.ToScoreTable();
                scopeResultQuery[MetaAttributes.SelectIntoVariableName] = returnScore;
                scopeResultQuery[MetaAttributes.SourceName]             = destination;

                query = new DetailedQueryNode(
                    outSelect,
                    new ExpressionFromNode(
                        new InMemoryGroupedFromNode(returnScore)),
                    null,
                    null,
                    null,
                    skip,
                    take,
                    returnScore);

                splittedNodes.Add(new CreateTableNode(destination, new string[0], transformingQuery.Select.Fields, true));
                splittedNodes.Add(transformingQuery);
                splittedNodes.Add(new CreateTableNode(query.From.Alias, new string[0], query.Select.Fields, false));
                splittedNodes.Add(query);

                Nodes.Push(
                    new MultiStatementNode(
                        splittedNodes.ToArray(),
                        null));
            }
            else
            {
                var splitted = SplitBetweenAggreateAndNonAggreagate(select.Fields, new FieldNode[0], true);

                if (IsQueryWithMixedAggregateAndNonAggregateMethods(splitted))
                {
                    query = new InternalQueryNode(select, from, where, null, null, skip, take,
                                                  CreateRefreshMethods(usedRefreshMethods));
                }
                else
                {
                    var scopeCreateResultTable = _scope.AddScope("Table");
                    var scopeResultQuery       = _scope.AddScope("Query");

                    scopeCreateResultTable[MetaAttributes.CreateTableVariableName] = from.Alias.ToScoreTable();
                    scopeResultQuery[MetaAttributes.SelectIntoVariableName]        = from.Alias.ToScoreTable();
                    scopeResultQuery[MetaAttributes.SourceName] = source;

                    var newFrom = lastJoinQuery != null
                        ? new ExpressionFromNode(new InMemoryGroupedFromNode(lastJoinQuery.From.Alias))
                        : from;

                    splittedNodes.Add(new CreateTableNode(scopeResultQuery[MetaAttributes.SelectIntoVariableName], new string[0], select.Fields, false));
                    splittedNodes.Add(new DetailedQueryNode(scoreSelect, newFrom, scoreWhere, null, null, skip, take,
                                                            scopeResultQuery[MetaAttributes.SelectIntoVariableName]));

                    Nodes.Push(
                        new MultiStatementNode(
                            splittedNodes.ToArray(),
                            null));
                }
            }

            _joinedTables.Clear();
        }