public void SelectStatement_CommonSelect()
        {
            List <TSQLStatement> statements = TSQLStatementReader.ParseStatements(
                @"select t.a, t.b, (select 1) as e
				into #tempt
				from
					[table] t
						inner join [table] t2 on
							t.id = t2.id
				where
					t.c = 5
				group by
					t.a,
					t.b
				having
					count(*) > 1
				order by
					t.a,
					t.b;"                    ,
                includeWhitespace: true);
            TSQLSelectStatement select = statements[0] as TSQLSelectStatement;

            Assert.IsNotNull(statements);
            Assert.AreEqual(1, statements.Count);
            Assert.AreEqual(TSQLStatementType.Select, statements[0].Type);
            Assert.AreEqual(98, select.Tokens.Count);
            Assert.AreEqual(TSQLKeywords.SELECT, select.Tokens[0].AsKeyword.Keyword);
            TSQLSelectClause selectClause = select.Select;

            Assert.AreEqual(3, selectClause.Columns.Count);
            TSQLSelectColumn column = selectClause.Columns[0];

            Assert.AreEqual(TSQLExpressionType.Column, column.Expression.Type);
            Assert.AreEqual("t", column.Expression.AsColumn.TableReference.Single().AsIdentifier.Name);
            Assert.AreEqual("a", column.Expression.AsColumn.Column.Name);
            column = selectClause.Columns[1];
            Assert.AreEqual(TSQLExpressionType.Column, column.Expression.Type);
            Assert.AreEqual("t", column.Expression.AsColumn.TableReference.Single().AsIdentifier.Name);
            Assert.AreEqual("b", column.Expression.AsColumn.Column.Name);
            column = selectClause.Columns[2];
            Assert.AreEqual("e", column.ColumnAlias.AsIdentifier.Name);
            Assert.AreEqual(TSQLExpressionType.Subquery, column.Expression.Type);
            TSQLSubqueryExpression subquery = column.Expression.AsSubquery;

            Assert.AreEqual(1, subquery.Select.Select.Columns.Count);
            Assert.AreEqual(1, subquery.Select.Select.Columns[0].Expression.AsConstant.Literal.AsNumericLiteral.Value);
            Assert.AreEqual(" ", select.Tokens[1].AsWhitespace.Text);
            Assert.AreEqual("t", select.Tokens[2].AsIdentifier.Name);
            Assert.AreEqual(TSQLCharacters.Period, select.Tokens[3].AsCharacter.Character);
            Assert.AreEqual(22, select.Select.Tokens.Count);
            Assert.AreEqual(4, select.Into.Tokens.Count);
            Assert.AreEqual(26, select.From.Tokens.Count);
            Assert.AreEqual(10, select.Where.Tokens.Count);
            Assert.AreEqual(13, select.GroupBy.Tokens.Count);
            Assert.AreEqual(11, select.Having.Tokens.Count);
            Assert.AreEqual(12, select.OrderBy.Tokens.Count);
            Assert.AreEqual(3, select.Select.Columns.Count);
            Assert.AreEqual("e", select.Select.Columns[2].ColumnAlias.Text);
        }
Пример #2
0
        public TSQLSelectClause Parse(ITSQLTokenizer tokenizer)
        {
            TSQLSelectClause select = new TSQLSelectClause();

            if (!tokenizer.Current.IsKeyword(TSQLKeywords.SELECT))
            {
                throw new InvalidOperationException("SELECT expected.");
            }

            select.Tokens.Add(tokenizer.Current);

            // can contain ALL, DISTINCT, TOP, PERCENT, WITH TIES, AS

            // ends with FROM, semicolon, or keyword other than those listed above, when used outside of parens

            // recursively walk down and back up parens

            int nestedLevel = 0;

            while (
                tokenizer.MoveNext() &&
                !tokenizer.Current.IsCharacter(TSQLCharacters.Semicolon) &&
                !(
                    nestedLevel == 0 &&
                    tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)
                    ) &&
                (
                    nestedLevel > 0 ||
                    tokenizer.Current.Type != TSQLTokenType.Keyword ||
                    (
                        tokenizer.Current.Type == TSQLTokenType.Keyword &&
                        !tokenizer.Current.AsKeyword.Keyword.In
                        (
                            TSQLKeywords.INTO,
                            TSQLKeywords.FROM,
                            TSQLKeywords.WHERE,
                            TSQLKeywords.GROUP,
                            TSQLKeywords.HAVING,
                            TSQLKeywords.ORDER,
                            TSQLKeywords.UNION,
                            TSQLKeywords.EXCEPT,
                            TSQLKeywords.INTERSECT,
                            TSQLKeywords.FOR,
                            TSQLKeywords.OPTION
                        ) &&
                        !tokenizer.Current.AsKeyword.Keyword.IsStatementStart()
                    )
                ))
            {
                TSQLSubqueryHelper.RecurseParens(
                    tokenizer,
                    select,
                    ref nestedLevel);
            }

            return(select);
        }
Пример #3
0
 public static List <SelectItem> Fields(this TSQLSelectClause selectClause)
 {
     return(selectClause.Tokens
            .Where(t => t.Type == TSQLTokenType.Identifier)
            .Select(f => new SelectItem()
     {
         Column = f.Text.ToString()
     }).ToList());
 }
        public void SelectStatement_MultiLevelParens()
        {
            string query = "SELECT ((A/B)-1) FROM SomeTable";
            List <TSQLStatement> statements = TSQLStatementReader.ParseStatements(query);

            Assert.AreEqual(1, statements.Count);
            Assert.AreEqual(TSQLStatementType.Select, statements[0].Type);
            TSQLSelectStatement selectStatement = statements[0].AsSelect;

            Assert.AreEqual(12, selectStatement.Tokens.Count);
            TSQLSelectClause selectClause = selectStatement.Select;

            Assert.AreEqual(1, selectClause.Columns.Count);
            // outer parens
            TSQLExpression lvl1Expression = selectClause.Columns[0].Expression;

            Assert.AreEqual(TSQLExpressionType.Grouped, lvl1Expression.Type);
            // contents of outer parens
            TSQLExpression lvl2Expression = lvl1Expression.AsGrouped.InnerExpression;

            Assert.AreEqual(TSQLExpressionType.Operator, lvl2Expression.Type);
            Assert.AreEqual("-", lvl2Expression.AsOperator.Operator.Text);
            // (A/B)
            TSQLExpression lvl2aExpression = lvl2Expression.AsOperator.LeftSide;
            // 1
            TSQLExpression lvl2bExpression = lvl2Expression.AsOperator.RightSide;

            Assert.AreEqual(TSQLExpressionType.Grouped, lvl2aExpression.Type);
            Assert.AreEqual(TSQLExpressionType.Constant, lvl2bExpression.Type);
            Assert.AreEqual(1, lvl2bExpression.AsConstant.Literal.AsNumericLiteral.Value);
            // A/B
            TSQLExpression lvl3Expression = lvl2aExpression.AsGrouped.InnerExpression;

            Assert.AreEqual(TSQLExpressionType.Operator, lvl3Expression.Type);
            Assert.AreEqual("/", lvl3Expression.AsOperator.Operator.Text);
            // A
            TSQLExpression lvl3aExpression = lvl3Expression.AsOperator.LeftSide;
            // B
            TSQLExpression lvl3bExpression = lvl3Expression.AsOperator.RightSide;

            Assert.AreEqual(TSQLExpressionType.Column, lvl3aExpression.Type);
            Assert.AreEqual("A", lvl3aExpression.AsColumn.Column.Name);
            Assert.IsNull(lvl3aExpression.AsColumn.TableReference);
            Assert.AreEqual(TSQLExpressionType.Column, lvl3bExpression.Type);
            Assert.AreEqual("B", lvl3bExpression.AsColumn.Column.Name);
            Assert.IsNull(lvl3bExpression.AsColumn.TableReference);
        }
Пример #5
0
        public TSQLSelectClause Parse(ITSQLTokenizer tokenizer)
        {
            TSQLSelectClause select = new TSQLSelectClause();

            if (!tokenizer.Current.IsKeyword(TSQLKeywords.SELECT))
            {
                throw new InvalidOperationException("SELECT expected.");
            }

            select.Tokens.Add(tokenizer.Current);

            // can contain ALL, DISTINCT, TOP, PERCENT, WITH TIES, AS

            // ends with FROM, semicolon, or keyword other than those listed above, when used outside of parens

            // recursively walk down and back up parens

            TSQLSubqueryHelper.ReadUntilStop(
                tokenizer,
                select,
                new List <TSQLFutureKeywords>()
            {
            },
                new List <TSQLKeywords>()
            {
                TSQLKeywords.INTO,
                TSQLKeywords.FROM,
                TSQLKeywords.WHERE,
                TSQLKeywords.GROUP,
                TSQLKeywords.HAVING,
                TSQLKeywords.ORDER,
                TSQLKeywords.UNION,
                TSQLKeywords.EXCEPT,
                TSQLKeywords.INTERSECT,
                TSQLKeywords.FOR,
                TSQLKeywords.OPTION
            },
                lookForStatementStarts: true);

            return(select);
        }
        public TSQLSelectClause Parse(TSQLTokenizer tokenizer)
        {
            TSQLSelectClause select = new TSQLSelectClause();

            if (
                tokenizer.Current == null ||
                tokenizer.Current.Type != TSQLTokenType.Keyword ||
                tokenizer.Current.AsKeyword.Keyword != TSQLKeywords.SELECT)
            {
                throw new ApplicationException("SELECT expected.");
            }

            select.Tokens.Add(tokenizer.Current);

            // can contain ALL, DISTINCT, TOP, PERCENT, WITH TIES, AS

            // ends with FROM, semicolon, or keyword other than those listed above, when used outside of parens

            // recursively walk down and back up parens

            int nestedLevel = 0;

            while (
                tokenizer.Read() &&
                !(
                    tokenizer.Current.Type == TSQLTokenType.Character &&
                    tokenizer.Current.AsCharacter.Character == TSQLCharacters.Semicolon
                    ) &&
                !(
                    nestedLevel == 0 &&
                    tokenizer.Current.Type == TSQLTokenType.Character &&
                    tokenizer.Current.AsCharacter.Character == TSQLCharacters.CloseParentheses
                    ) &&
                (
                    nestedLevel > 0 ||
                    tokenizer.Current.Type != TSQLTokenType.Keyword ||
                    (
                        tokenizer.Current.Type == TSQLTokenType.Keyword &&
                        tokenizer.Current.AsKeyword.Keyword.In
                        (
                            TSQLKeywords.ALL,
                            TSQLKeywords.AS,
                            TSQLKeywords.DISTINCT,
                            TSQLKeywords.PERCENT,
                            TSQLKeywords.TOP,
                            TSQLKeywords.WITH,
                            TSQLKeywords.NULL,
                            TSQLKeywords.CASE,
                            TSQLKeywords.WHEN,
                            TSQLKeywords.THEN,
                            TSQLKeywords.ELSE,
                            TSQLKeywords.AND,
                            TSQLKeywords.OR,
                            TSQLKeywords.BETWEEN,
                            TSQLKeywords.EXISTS,
                            TSQLKeywords.END,
                            TSQLKeywords.IN,
                            TSQLKeywords.IS,
                            TSQLKeywords.NOT,
                            TSQLKeywords.OVER,
                            TSQLKeywords.IDENTITY,
                            TSQLKeywords.LIKE
                        )
                    )
                ))
            {
                select.Tokens.Add(tokenizer.Current);

                if (tokenizer.Current.Type == TSQLTokenType.Character)
                {
                    TSQLCharacters character = tokenizer.Current.AsCharacter.Character;

                    if (character == TSQLCharacters.OpenParentheses)
                    {
                        // should we recurse for correlated subqueries?
                        nestedLevel++;

                        if (tokenizer.Read())
                        {
                            if (
                                tokenizer.Current.Type == TSQLTokenType.Keyword &&
                                tokenizer.Current.AsKeyword.Keyword == TSQLKeywords.SELECT)
                            {
                                TSQLSelectStatement selectStatement = new TSQLSelectStatementParser().Parse(tokenizer);

                                select.Tokens.AddRange(selectStatement.Tokens);

                                if (
                                    tokenizer.Current != null &&
                                    tokenizer.Current.Type == TSQLTokenType.Character &&
                                    tokenizer.Current.AsCharacter.Character == TSQLCharacters.CloseParentheses)
                                {
                                    nestedLevel--;
                                    select.Tokens.Add(tokenizer.Current);
                                }
                            }
                            else
                            {
                                select.Tokens.Add(tokenizer.Current);
                            }
                        }
                    }
                    else if (character == TSQLCharacters.CloseParentheses)
                    {
                        nestedLevel--;
                    }
                }
            }

            return(select);
        }
Пример #7
0
        public TSQLSelectClause Parse(ITSQLTokenizer tokenizer)
        {
            TSQLSelectClause select = new TSQLSelectClause();

            if (!tokenizer.Current.IsKeyword(TSQLKeywords.SELECT))
            {
                throw new InvalidOperationException("SELECT expected.");
            }

            select.Tokens.Add(tokenizer.Current);

            tokenizer.MoveNext();

            TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                tokenizer,
                select);

            if (tokenizer.Current.IsKeyword(TSQLKeywords.ALL) ||
                tokenizer.Current.IsKeyword(TSQLKeywords.DISTINCT))
            {
                select.Tokens.Add(tokenizer.Current);

                tokenizer.MoveNext();

                TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                    tokenizer,
                    select);
            }

            if (tokenizer.Current.IsKeyword(TSQLKeywords.TOP))
            {
                select.Tokens.Add(tokenizer.Current);

                tokenizer.MoveNext();

                TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                    tokenizer,
                    select);

                if (tokenizer.Current.IsCharacter(TSQLCharacters.OpenParentheses))
                {
                    select.Tokens.Add(tokenizer.Current);

                    tokenizer.MoveNext();

                    TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                        tokenizer,
                        select);

                    // handling for TOP(@RowsToReturn)

                    // can also be used in a CROSS APPLY with an outer reference, e.g. TOP(p.RowCount)

                    if (tokenizer.Current != null &&
                        tokenizer.Current.Type.In(
                            TSQLTokenType.NumericLiteral,
                            TSQLTokenType.Identifier,
                            TSQLTokenType.IncompleteIdentifier,
                            TSQLTokenType.SystemVariable,
                            TSQLTokenType.Variable))
                    {
                        select.Tokens.Add(tokenizer.Current);

                        tokenizer.MoveNext();

                        TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                            tokenizer,
                            select);
                    }

                    if (tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses))
                    {
                        select.Tokens.Add(tokenizer.Current);

                        tokenizer.MoveNext();

                        TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                            tokenizer,
                            select);
                    }
                }
                else if (tokenizer.Current != null &&
                         tokenizer.Current.Type == TSQLTokenType.NumericLiteral)
                {
                    select.Tokens.Add(tokenizer.Current);

                    tokenizer.MoveNext();

                    TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                        tokenizer,
                        select);
                }

                if (tokenizer.Current.IsKeyword(TSQLKeywords.PERCENT))
                {
                    select.Tokens.Add(tokenizer.Current);

                    tokenizer.MoveNext();

                    TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                        tokenizer,
                        select);
                }

                if (tokenizer.Current.IsKeyword(TSQLKeywords.WITH))
                {
                    select.Tokens.Add(tokenizer.Current);

                    tokenizer.MoveNext();

                    TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                        tokenizer,
                        select);

                    if (tokenizer.Current != null &&
                        tokenizer.Current.Type == TSQLTokenType.Identifier &&
                        tokenizer.Current.AsIdentifier.Text.Equals(
                            "TIES",
                            StringComparison.InvariantCultureIgnoreCase))
                    {
                        select.Tokens.Add(tokenizer.Current);

                        tokenizer.MoveNext();

                        TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                            tokenizer,
                            select);
                    }
                }
            }

            while (
                tokenizer.Current != null &&
                !tokenizer.Current.IsCharacter(TSQLCharacters.Semicolon) &&
                !tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses) &&
                !(
                    tokenizer.Current.Type == TSQLTokenType.Keyword &&
                    (
                        tokenizer.Current.AsKeyword.Keyword.In(
                            TSQLKeywords.INTO,
                            TSQLKeywords.FROM,
                            TSQLKeywords.WHERE,
                            TSQLKeywords.GROUP,
                            TSQLKeywords.HAVING,
                            TSQLKeywords.ORDER,
                            TSQLKeywords.UNION,
                            TSQLKeywords.EXCEPT,
                            TSQLKeywords.INTERSECT,
                            TSQLKeywords.FOR,
                            TSQLKeywords.OPTION) ||
                        tokenizer.Current.AsKeyword.Keyword.IsStatementStart()
                    )
                    ))
            {
                TSQLSelectColumn column = new TSQLSelectColumnParser().Parse(tokenizer);

                select.Tokens.AddRange(column.Tokens);

                select.Columns.Add(column);

                TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                    tokenizer,
                    select);

                if (tokenizer.Current.IsCharacter(TSQLCharacters.Comma))
                {
                    select.Tokens.Add(tokenizer.Current);

                    tokenizer.MoveNext();

                    TSQLTokenParserHelper.ReadCommentsAndWhitespace(
                        tokenizer,
                        select);
                }
            }

            return(select);
        }
        public TSQLSelectClause Parse(TSQLTokenizer tokenizer)
        {
            TSQLSelectClause select = new TSQLSelectClause();

            if (
                tokenizer.Current == null ||
                tokenizer.Current.Type != TSQLTokenType.Keyword ||
                tokenizer.Current.AsKeyword.Keyword != TSQLKeywords.SELECT)
            {
                throw new ApplicationException("SELECT expected.");
            }

            select.Tokens.Add(tokenizer.Current);

            // can contain ALL, DISTINCT, TOP, PERCENT, WITH TIES, AS

            // ends with FROM, semicolon, or keyword other than those listed above, when used outside of parens

            // recursively walk down and back up parens

            int nestedLevel = 0;

            while (
                tokenizer.Read() &&
                !(
                    tokenizer.Current.Type == TSQLTokenType.Character &&
                    tokenizer.Current.AsCharacter.Character == TSQLCharacters.Semicolon
                ) &&
                !(
                    nestedLevel == 0 &&
                    tokenizer.Current.Type == TSQLTokenType.Character &&
                    tokenizer.Current.AsCharacter.Character == TSQLCharacters.CloseParentheses
                ) &&
                (
                    nestedLevel > 0 ||
                    tokenizer.Current.Type != TSQLTokenType.Keyword ||
                    (
                        tokenizer.Current.Type == TSQLTokenType.Keyword &&
                        tokenizer.Current.AsKeyword.Keyword.In
                        (
                            TSQLKeywords.ALL,
                            TSQLKeywords.AS,
                            TSQLKeywords.DISTINCT,
                            TSQLKeywords.PERCENT,
                            TSQLKeywords.TOP,
                            TSQLKeywords.WITH,
                            TSQLKeywords.NULL,
                            TSQLKeywords.CASE,
                            TSQLKeywords.WHEN,
                            TSQLKeywords.THEN,
                            TSQLKeywords.ELSE,
                            TSQLKeywords.AND,
                            TSQLKeywords.OR,
                            TSQLKeywords.BETWEEN,
                            TSQLKeywords.EXISTS,
                            TSQLKeywords.END,
                            TSQLKeywords.IN,
                            TSQLKeywords.IS,
                            TSQLKeywords.NOT,
                            TSQLKeywords.OVER,
                            TSQLKeywords.IDENTITY,
                            TSQLKeywords.LIKE
                        )
                    )
                ))
            {
                select.Tokens.Add(tokenizer.Current);

                if (tokenizer.Current.Type == TSQLTokenType.Character)
                {
                    TSQLCharacters character = tokenizer.Current.AsCharacter.Character;

                    if (character == TSQLCharacters.OpenParentheses)
                    {
                        // should we recurse for correlated subqueries?
                        nestedLevel++;

                        if (tokenizer.Read())
                        {
                            if (
                                tokenizer.Current.Type == TSQLTokenType.Keyword &&
                                tokenizer.Current.AsKeyword.Keyword == TSQLKeywords.SELECT)
                            {
                                TSQLSelectStatement selectStatement = new TSQLSelectStatementParser().Parse(tokenizer);

                                select.Tokens.AddRange(selectStatement.Tokens);

                                if (
                                    tokenizer.Current != null &&
                                    tokenizer.Current.Type == TSQLTokenType.Character &&
                                    tokenizer.Current.AsCharacter.Character == TSQLCharacters.CloseParentheses)
                                {
                                    nestedLevel--;
                                    select.Tokens.Add(tokenizer.Current);
                                }
                            }
                            else
                            {
                                select.Tokens.Add(tokenizer.Current);
                            }
                        }
                    }
                    else if (character == TSQLCharacters.CloseParentheses)
                    {
                        nestedLevel--;
                    }
                }
            }

            return select;
        }