예제 #1
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                string s = Parser.NextToken().ToUpper();
                if (s != "FROM")
                {
                    return(false);
                }

                ScriptNode Source = Parser.ParseNoWhiteSpace();
                ScriptNode Where  = null;

                s = Parser.PeekNextToken().ToUpper();
                if (s == "WHERE")
                {
                    Parser.NextToken();
                    Where = Parser.ParseOrs();
                }

                Result = new Delete(Source, Where, Parser.Start, Parser.Length, Parser.Expression);

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }
예제 #2
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                string s = Parser.NextToken().ToUpper();
                if (s != "INDEX")
                {
                    return(false);
                }

                ScriptNode Name = Parser.ParseNoWhiteSpace();

                s = Parser.NextToken().ToUpper();
                if (s != "ON")
                {
                    return(false);
                }

                if (!SelectParser.TryParseSources(Parser, out SourceDefinition Source))
                {
                    return(false);
                }

                Result = new DropIndex(Name, Source, Parser.Start, Parser.Length, Parser.Expression);

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }
예제 #3
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                string s = Parser.NextToken().ToUpper();
                if (s != "INDEX")
                {
                    return(false);
                }

                ScriptNode Name = Parser.ParseNoWhiteSpace();

                s = Parser.NextToken().ToUpper();
                if (s != "ON")
                {
                    return(false);
                }

                if (!SelectParser.TryParseSources(Parser, out SourceDefinition Source))
                {
                    return(false);
                }

                s = Parser.NextToken();
                if (s != "(")
                {
                    return(false);
                }

                this.ParseList(Parser, out ScriptNode[] Columns, out bool[] Ascending);

                if (Columns.Length == 0)
                {
                    return(false);
                }

                if (Parser.NextToken() != ")")
                {
                    return(false);
                }

                Result = new CreateIndex(Name, Source, Columns, Ascending, Parser.Start, Parser.Length, Parser.Expression);

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }
예제 #4
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                string s = Parser.NextToken().ToUpper();
                switch (s)
                {
                case "INDEX":
                    ScriptNode Name = Parser.ParseNoWhiteSpace();

                    s = Parser.NextToken().ToUpper();
                    if (s != "ON")
                    {
                        return(false);
                    }

                    if (!SelectParser.TryParseSources(Parser, out SourceDefinition Source))
                    {
                        return(false);
                    }

                    Result = new DropIndex(Name, Source, Parser.Start, Parser.Length, Parser.Expression);

                    return(true);

                case "TABLE":
                case "COLLECTION":
                    if (!SelectParser.TryParseSources(Parser, out Source))
                    {
                        return(false);
                    }

                    Result = new DropCollection(Source, Parser.Start, Parser.Length, Parser.Expression);

                    return(true);

                default:
                    return(false);
                }
            }
            catch (Exception)
            {
                return(false);
            }
        }
예제 #5
0
        internal void ParseList(ScriptParser Parser, out ScriptNode[] Columns, out bool[] Ascending)
        {
            List <ScriptNode> ColumnList    = new List <ScriptNode>();
            List <bool>       AscendingList = new List <bool>();
            string            s;

            do
            {
                ScriptNode Node = Parser.ParseIf();

                switch (s = Parser.PeekNextToken().ToUpper())
                {
                case "ASC":
                    Parser.NextToken();
                    ColumnList.Add(Node);
                    AscendingList.Add(true);
                    s = Parser.PeekNextToken();
                    break;

                case "DESC":
                    Parser.NextToken();
                    ColumnList.Add(Node);
                    AscendingList.Add(false);
                    s = Parser.PeekNextToken();
                    break;

                case ",":
                    Parser.NextToken();
                    ColumnList.Add(Node);
                    AscendingList.Add(true);
                    break;

                default:
                    ColumnList.Add(Node);
                    AscendingList.Add(true);
                    break;
                }
            }while (s == ",");

            Columns   = ColumnList.ToArray();
            Ascending = AscendingList.ToArray();
        }
예제 #6
0
        private static ScriptNode ParseJoinConditions(ScriptParser Parser)
        {
            if (Parser.PeekNextToken().ToUpper() != "ON")
            {
                return(null);
            }

            Parser.NextToken();

            return(Parser.ParseOrs());
        }
예제 #7
0
        internal static bool TryParseSource(ScriptParser Parser, out SourceDefinition Source)
        {
            Parser.SkipWhiteSpace();

            int        Start = Parser.Position;
            ScriptNode Node  = Parser.ParseNoWhiteSpace();
            ScriptNode Name  = null;
            string     s;

            Parser.SkipWhiteSpace();

            s = Parser.PeekNextToken().ToUpper();
            if (!string.IsNullOrEmpty(s) &&
                IsAlias(s) &&
                s != "INNER" &&
                s != "OUTER" &&
                s != "LEFT" &&
                s != "RIGHT" &&
                s != "FULL" &&
                s != "JOIN" &&
                s != "WHERE" &&
                s != "GROUP" &&
                s != "ORDER" &&
                s != "OFFSET" &&
                s != "ON" &&
                s != "SET" &&
                s != "SELECT" &&
                s != "OBJECT" &&
                s != "OBJECTS")
            {
                if (s == "AS")
                {
                    Parser.NextToken();
                }

                Name = Parser.ParseNoWhiteSpace();
            }
            else if (Node is VariableReference Ref)
            {
                Name = new ConstantElement(new StringValue(Ref.VariableName), Node.Start, Node.Length, Node.Expression);
            }

            Source = new SourceReference(Node, Name, Start, Parser.Position - Start, Parser.Expression);

            return(true);
        }
예제 #8
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                ScriptNode Source = Parser.ParseNoWhiteSpace();

                string s = Parser.NextToken().ToUpper();
                if (s != "SET")
                {
                    return(false);
                }

                List <Assignment> SetOperations = new List <Assignment>();
                ScriptNode        Node          = Parser.ParseList();

                if (!(Node is ElementList List))
                {
                    List = new ElementList(new ScriptNode[] { Node }, Node.Start, Node.Length, Node.Expression);
                }

                foreach (ScriptNode Operation in List.Elements)
                {
                    if (Operation is EqualTo EqualTo)
                    {
                        if (EqualTo.LeftOperand is VariableReference Ref)
                        {
                            SetOperations.Add(new Assignment(Ref.VariableName, EqualTo.RightOperand, EqualTo.Start, EqualTo.Length, EqualTo.Expression));
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    else if (Operation is Assignment Assignment)
                    {
                        SetOperations.Add(Assignment);
                    }
                    else
                    {
                        return(false);
                    }
                }

                ScriptNode Where = null;

                s = Parser.PeekNextToken().ToUpper();
                if (s == "WHERE")
                {
                    Parser.NextToken();
                    Where = Parser.ParseOrs();
                }

                Result = new Update(Source, SetOperations.ToArray(), Where, Parser.Start, Parser.Length, Parser.Expression);

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }
예제 #9
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                string s = Parser.NextToken().ToUpper();
                if (s != "INTO")
                {
                    return(false);
                }

                if (!SelectParser.TryParseSources(Parser, out SourceDefinition Source))
                {
                    return(false);
                }

                switch (Parser.PeekNextToken().ToUpper())
                {
                case "(":
                    Parser.NextToken();

                    ScriptNode Node = Parser.ParseList();
                    if (!(Node is ElementList Columns))
                    {
                        Columns = new ElementList(new ScriptNode[] { Node }, Node.Start, Node.Length, Node.Expression);
                    }

                    if (Parser.NextToken() != ")")
                    {
                        return(false);
                    }

                    if (Parser.NextToken().ToUpper() != "VALUES")
                    {
                        return(false);
                    }

                    if (Parser.NextToken() != "(")
                    {
                        return(false);
                    }

                    Node = Parser.ParseList();
                    if (!(Node is ElementList Values))
                    {
                        Values = new ElementList(new ScriptNode[] { Node }, Node.Start, Node.Length, Node.Expression);
                    }

                    if (Values.Elements.Length != Columns.Elements.Length)
                    {
                        return(false);
                    }

                    if (Parser.NextToken() != ")")
                    {
                        return(false);
                    }

                    Result = new InsertValues(Source, Columns, Values, Parser.Start, Parser.Length, Parser.Expression);
                    return(true);

                case "SELECT":
                    Node = Parser.ParseStatement();
                    if (!(Node is Select Select))
                    {
                        return(false);
                    }

                    Result = new InsertSelect(Source, Select, Parser.Start, Parser.Position, Parser.Expression);
                    return(true);

                case "OBJECT":
                case "OBJECTS":
                    Parser.NextToken();

                    Node = Parser.ParseList();
                    if (!(Node is ElementList Objects))
                    {
                        Objects = new ElementList(new ScriptNode[] { Node }, Node.Start, Node.Length, Node.Expression);
                    }

                    Result = new InsertObjects(Source, Objects, Parser.Start, Parser.Length, Parser.Expression);
                    return(true);

                default:
                    return(false);
                }
            }
            catch (Exception)
            {
                return(false);
            }
        }
예제 #10
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                List <ScriptNode> Columns;
                List <ScriptNode> ColumnNames;
                ScriptNode        Top = null;
                string            s;
                bool Distinct = false;

                s = Parser.PeekNextToken().ToUpper();
                if (string.IsNullOrEmpty(s))
                {
                    return(false);
                }

                while (s == "TOP" || s == "DISTINCT")
                {
                    switch (s)
                    {
                    case "TOP":
                        Parser.NextToken();
                        Top = Parser.ParseNoWhiteSpace();
                        break;

                    case "DISTINCT":
                        Parser.NextToken();
                        Distinct = true;
                        break;
                    }

                    s = Parser.PeekNextToken();
                    if (string.IsNullOrEmpty(s))
                    {
                        return(false);
                    }
                }

                if (s == "*")
                {
                    Parser.NextToken();
                    Columns     = null;
                    ColumnNames = null;
                }
                else
                {
                    Columns     = new List <ScriptNode>();
                    ColumnNames = new List <ScriptNode>();

                    while (true)
                    {
                        ScriptNode Node = Parser.ParseNoWhiteSpace();
                        ScriptNode Name = null;

                        Parser.SkipWhiteSpace();

                        s = Parser.PeekNextToken().ToUpper();
                        if (!string.IsNullOrEmpty(s) && s != "," && s != "FROM")
                        {
                            if (s == "AS")
                            {
                                Parser.NextToken();
                            }

                            Name = Parser.ParseNoWhiteSpace();
                            s    = Parser.PeekNextToken();
                        }
                        else if (Node is VariableReference Ref)
                        {
                            Name = new ConstantElement(new StringValue(Ref.VariableName), Node.Start, Node.Length, Node.Expression);
                        }
                        else if (Node is NamedMember NamedMember)
                        {
                            Name = new ConstantElement(new StringValue(NamedMember.Name), Node.Start, Node.Length, Node.Expression);
                        }

                        Columns.Add(Node);
                        ColumnNames.Add(Name);

                        if (s != ",")
                        {
                            break;
                        }

                        Parser.NextToken();
                    }
                }

                s = Parser.NextToken().ToUpper();
                if (s != "FROM")
                {
                    return(false);
                }

                if (!TryParseSources(Parser, out SourceDefinition Source))
                {
                    return(false);
                }

                ScriptNode Where = null;

                s = Parser.PeekNextToken().ToUpper();
                if (s == "WHERE")
                {
                    Parser.NextToken();
                    Where = Parser.ParseOrs();
                    s     = Parser.PeekNextToken().ToUpper();
                }

                List <ScriptNode> GroupBy      = null;
                List <ScriptNode> GroupByNames = null;
                ScriptNode        Having       = null;

                if (s == "GROUP")
                {
                    Parser.NextToken();
                    if (Parser.NextToken().ToUpper() != "BY")
                    {
                        return(false);
                    }

                    GroupBy      = new List <ScriptNode>();
                    GroupByNames = new List <ScriptNode>();

                    while (true)
                    {
                        ScriptNode Node = Parser.ParseNoWhiteSpace();
                        ScriptNode Name = null;

                        Parser.SkipWhiteSpace();

                        s = Parser.PeekNextToken().ToUpper();
                        if (!string.IsNullOrEmpty(s) && s != "," && s != "HAVING" && s != "ORDER" && s != "OFFSET")
                        {
                            if (s == "AS")
                            {
                                Parser.NextToken();
                            }

                            Name = Parser.ParseNoWhiteSpace();
                            s    = Parser.PeekNextToken().ToUpper();
                        }
                        else if (Node is VariableReference Ref)
                        {
                            Name = new ConstantElement(new StringValue(Ref.VariableName), Node.Start, Node.Length, Node.Expression);
                        }
                        else if (Node is NamedMember NamedMember)
                        {
                            Name = new ConstantElement(new StringValue(NamedMember.Name), Node.Start, Node.Length, Node.Expression);
                        }

                        GroupBy.Add(Node);
                        GroupByNames.Add(Name);

                        if (s != ",")
                        {
                            break;
                        }

                        Parser.NextToken();
                    }

                    if (s == "HAVING")
                    {
                        Parser.NextToken();
                        Having = Parser.ParseOrs();
                        s      = Parser.PeekNextToken().ToUpper();
                    }
                }
                else if (!(Columns is null))
                {
                    bool ImplicitGrouping = false;

                    foreach (ScriptNode Column in Columns)
                    {
                        if (this.ContainsVectorFunction(Column))
                        {
                            ImplicitGrouping = true;
                            break;
                        }
                    }

                    if (ImplicitGrouping)
                    {
                        GroupBy      = new List <ScriptNode>();
                        GroupByNames = new List <ScriptNode>();
                    }
                }

                List <KeyValuePair <ScriptNode, bool> > OrderBy = null;

                if (s == "ORDER")
                {
                    Parser.NextToken();
                    if (Parser.NextToken().ToUpper() != "BY")
                    {
                        return(false);
                    }

                    OrderBy = new List <KeyValuePair <ScriptNode, bool> >();

                    while (true)
                    {
                        ScriptNode Node = Parser.ParseNoWhiteSpace();

                        s = Parser.PeekNextToken().ToUpper();
                        if (s == "ASC")
                        {
                            Parser.NextToken();
                            OrderBy.Add(new KeyValuePair <ScriptNode, bool>(Node, true));
                            s = Parser.PeekNextToken().ToUpper();
                        }
                        else if (s == "DESC")
                        {
                            Parser.NextToken();
                            OrderBy.Add(new KeyValuePair <ScriptNode, bool>(Node, false));
                            s = Parser.PeekNextToken().ToUpper();
                        }
                        else
                        {
                            OrderBy.Add(new KeyValuePair <ScriptNode, bool>(Node, true));
                        }

                        if (s != ",")
                        {
                            break;
                        }

                        Parser.NextToken();
                    }
                }

                ScriptNode Offset = null;

                if (s == "OFFSET")
                {
                    Parser.NextToken();
                    Offset = Parser.ParseNoWhiteSpace();
                }

                Result = new Select(Columns?.ToArray(), ColumnNames?.ToArray(), Source, Where, GroupBy?.ToArray(),
                                    GroupByNames?.ToArray(), Having, OrderBy?.ToArray(), Top, Offset, Distinct,
                                    Parser.Start, Parser.Length, Parser.Expression);

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }
예제 #11
0
        internal static bool TryParseSources(ScriptParser Parser, out SourceDefinition Source)
        {
            if (!TryParseSource(Parser, out Source))
            {
                return(false);
            }

            while (true)
            {
                string s = Parser.PeekNextToken().ToUpper();

                switch (s)
                {
                case ",":
                    Parser.NextToken();
                    if (!TryParseSource(Parser, out SourceDefinition Source2))
                    {
                        return(false);
                    }

                    Source = new CrossJoin(Source, Source2, Source.Start, Parser.Position - Source.Start, Parser.Expression);
                    break;

                case "INNER":
                case "JOIN":
                    Parser.NextToken();

                    if (s == "INNER")
                    {
                        if (Parser.NextToken().ToUpper() != "JOIN")
                        {
                            return(false);
                        }
                    }

                    if (!TryParseSource(Parser, out Source2))
                    {
                        return(false);
                    }

                    ScriptNode Conditions = ParseJoinConditions(Parser);
                    Source = new InnerJoin(Source, Source2, Conditions, Source.Start, Parser.Position - Source.Start, Parser.Expression);
                    break;

                case "LEFT":
                    Parser.NextToken();

                    switch (Parser.NextToken().ToUpper())
                    {
                    case "JOIN":
                        break;

                    case "OUTER":
                        if (Parser.NextToken().ToUpper() != "JOIN")
                        {
                            return(false);
                        }
                        break;

                    default:
                        return(false);
                    }

                    if (!TryParseSource(Parser, out Source2))
                    {
                        return(false);
                    }

                    Conditions = ParseJoinConditions(Parser);
                    Source     = new LeftOuterJoin(Source, Source2, Conditions, Source.Start, Parser.Position - Source.Start, Parser.Expression);
                    break;

                case "RIGHT":
                    Parser.NextToken();

                    switch (Parser.NextToken().ToUpper())
                    {
                    case "JOIN":
                        break;

                    case "OUTER":
                        if (Parser.NextToken().ToUpper() != "JOIN")
                        {
                            return(false);
                        }
                        break;

                    default:
                        return(false);
                    }

                    if (!TryParseSource(Parser, out Source2))
                    {
                        return(false);
                    }

                    Conditions = ParseJoinConditions(Parser);
                    Source     = new RightOuterJoin(Source, Source2, Conditions, Source.Start, Parser.Position - Source.Start, Parser.Expression);
                    break;

                case "FULL":
                    Parser.NextToken();

                    switch (Parser.NextToken().ToUpper())
                    {
                    case "JOIN":
                        break;

                    case "OUTER":
                        if (Parser.NextToken().ToUpper() != "JOIN")
                        {
                            return(false);
                        }
                        break;

                    default:
                        return(false);
                    }

                    if (!TryParseSource(Parser, out Source2))
                    {
                        return(false);
                    }

                    Conditions = ParseJoinConditions(Parser);
                    Source     = new FullOuterJoin(Source, Source2, Conditions, Source.Start, Parser.Position - Source.Start, Parser.Expression);
                    break;

                case "OUTER":
                    Parser.NextToken();

                    if (Parser.NextToken().ToUpper() != "JOIN")
                    {
                        return(false);
                    }

                    if (!TryParseSource(Parser, out Source2))
                    {
                        return(false);
                    }

                    Conditions = ParseJoinConditions(Parser);
                    Source     = new FullOuterJoin(Source, Source2, Conditions, Source.Start, Parser.Position - Source.Start, Parser.Expression);
                    break;

                default:
                    return(true);
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Tries to parse a script node.
        /// </summary>
        /// <param name="Parser">Custom parser.</param>
        /// <param name="Result">Parsed Script Node.</param>
        /// <returns>If successful in parsing a script node.</returns>
        public bool TryParse(ScriptParser Parser, out ScriptNode Result)
        {
            Result = null;

            try
            {
                List <ScriptNode> Columns;
                List <ScriptNode> ColumnNames;
                ScriptNode        Top;
                string            s;

                s = Parser.PeekNextToken().ToUpper();
                if (s == string.Empty)
                {
                    return(false);
                }

                if (s == "TOP")
                {
                    Parser.NextToken();
                    Top = Parser.ParseNoWhiteSpace();

                    s = Parser.PeekNextToken();
                    if (s == string.Empty)
                    {
                        return(false);
                    }
                }
                else
                {
                    Top = null;
                }

                if (s == "*")
                {
                    Parser.NextToken();
                    Columns     = null;
                    ColumnNames = null;
                }
                else
                {
                    Columns     = new List <ScriptNode>();
                    ColumnNames = new List <ScriptNode>();

                    while (true)
                    {
                        ScriptNode Node = Parser.ParseNoWhiteSpace();
                        ScriptNode Name = null;

                        Parser.SkipWhiteSpace();

                        s = Parser.PeekNextToken().ToUpper();
                        if (!string.IsNullOrEmpty(s) && s != "," && s != "FROM")
                        {
                            Name = Parser.ParseNoWhiteSpace();
                            s    = Parser.PeekNextToken();
                        }
                        else if (Node is VariableReference Ref)
                        {
                            Name = new ConstantElement(new StringValue(Ref.VariableName), Node.Start, Node.Length, Node.Expression);
                        }

                        Columns.Add(Node);
                        ColumnNames.Add(Name);

                        if (s != ",")
                        {
                            break;
                        }

                        Parser.NextToken();
                    }
                }

                s = Parser.NextToken().ToUpper();
                if (s != "FROM")
                {
                    return(false);
                }

                List <ScriptNode> Sources     = new List <ScriptNode>();
                List <ScriptNode> SourceNames = new List <ScriptNode>();

                while (true)
                {
                    ScriptNode Node = Parser.ParseNoWhiteSpace();
                    ScriptNode Name = null;

                    Parser.SkipWhiteSpace();

                    s = Parser.PeekNextToken().ToUpper();
                    if (!string.IsNullOrEmpty(s) && s != "," && s != "WHERE" && s != "GROUP" && s != "ORDER" && s != "OFFSET")
                    {
                        Name = Parser.ParseNoWhiteSpace();
                        s    = Parser.PeekNextToken().ToUpper();
                    }
                    else if (Node is VariableReference Ref)
                    {
                        Name = new ConstantElement(new StringValue(Ref.VariableName), Node.Start, Node.Length, Node.Expression);
                    }

                    Sources.Add(Node);
                    SourceNames.Add(Name);

                    if (s != ",")
                    {
                        break;
                    }

                    Parser.NextToken();
                }

                ScriptNode Where = null;

                if (s == "WHERE")
                {
                    Parser.NextToken();
                    Where = Parser.ParseOrs();
                    s     = Parser.PeekNextToken().ToUpper();
                }

                List <ScriptNode> GroupBy      = null;
                List <ScriptNode> GroupByNames = null;
                ScriptNode        Having       = null;

                if (s == "GROUP")
                {
                    Parser.NextToken();
                    if (Parser.NextToken().ToUpper() != "BY")
                    {
                        return(false);
                    }

                    GroupBy      = new List <ScriptNode>();
                    GroupByNames = new List <ScriptNode>();

                    while (true)
                    {
                        ScriptNode Node = Parser.ParseNoWhiteSpace();
                        ScriptNode Name = null;

                        Parser.SkipWhiteSpace();

                        s = Parser.PeekNextToken().ToUpper();
                        if (!string.IsNullOrEmpty(s) && s != "," && s != "HAVING" && s != "ORDER" && s != "OFFSET")
                        {
                            Name = Parser.ParseNoWhiteSpace();
                            s    = Parser.PeekNextToken().ToUpper();
                        }
                        else if (Node is VariableReference Ref)
                        {
                            Name = new ConstantElement(new StringValue(Ref.VariableName), Node.Start, Node.Length, Node.Expression);
                        }

                        GroupBy.Add(Node);
                        GroupByNames.Add(Name);

                        if (s != ",")
                        {
                            break;
                        }

                        Parser.NextToken();
                    }

                    if (s == "HAVING")
                    {
                        Parser.NextToken();
                        Having = Parser.ParseOrs();
                        s      = Parser.PeekNextToken().ToUpper();
                    }
                }

                List <KeyValuePair <ScriptNode, bool> > OrderBy = null;

                if (s == "ORDER")
                {
                    Parser.NextToken();
                    if (Parser.NextToken().ToUpper() != "BY")
                    {
                        return(false);
                    }

                    OrderBy = new List <KeyValuePair <ScriptNode, bool> >();

                    while (true)
                    {
                        ScriptNode Node = Parser.ParseNoWhiteSpace();

                        s = Parser.PeekNextToken().ToUpper();
                        if (s == "ASC")
                        {
                            Parser.NextToken();
                            OrderBy.Add(new KeyValuePair <ScriptNode, bool>(Node, true));
                            s = Parser.PeekNextToken().ToUpper();
                        }
                        else if (s == "DESC")
                        {
                            Parser.NextToken();
                            OrderBy.Add(new KeyValuePair <ScriptNode, bool>(Node, false));
                            s = Parser.PeekNextToken().ToUpper();
                        }
                        else
                        {
                            OrderBy.Add(new KeyValuePair <ScriptNode, bool>(Node, true));
                        }

                        if (s != ",")
                        {
                            break;
                        }

                        Parser.NextToken();
                    }
                }

                ScriptNode Offset = null;

                if (s == "OFFSET")
                {
                    Parser.NextToken();
                    Offset = Parser.ParseNoWhiteSpace();
                }

                Result = new Select(Columns?.ToArray(), ColumnNames?.ToArray(), Sources.ToArray(), SourceNames.ToArray(),
                                    Where, GroupBy?.ToArray(), GroupByNames?.ToArray(), Having, OrderBy?.ToArray(), Top, Offset,
                                    Parser.Start, Parser.Length, Parser.Expression);

                return(true);
            }
            catch (Exception)
            {
                return(false);
            }
        }