public TSQLGroupByClause Parse(ITSQLTokenizer tokenizer) { TSQLGroupByClause groupBy = new TSQLGroupByClause(); if (!tokenizer.Current.IsKeyword(TSQLKeywords.GROUP)) { throw new ApplicationException("GROUP expected."); } groupBy.Tokens.Add(tokenizer.Current); // subqueries 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.BY, 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.LIKE, TSQLKeywords.ALL, TSQLKeywords.WITH, TSQLKeywords.DISTINCT ) ) )) { groupBy.Tokens.Add(tokenizer.Current); if (tokenizer.Current.Type == TSQLTokenType.Character) { TSQLCharacters character = tokenizer.Current.AsCharacter.Character; if (character == TSQLCharacters.OpenParentheses) { // should we recurse for subqueries? nestedLevel++; if (tokenizer.MoveNext()) { if (tokenizer.Current.IsKeyword(TSQLKeywords.SELECT)) { TSQLSelectStatement selectStatement = new TSQLSelectStatementParser().Parse(tokenizer); groupBy.Tokens.AddRange(selectStatement.Tokens); if (tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)) { nestedLevel--; groupBy.Tokens.Add(tokenizer.Current); } } else { groupBy.Tokens.Add(tokenizer.Current); } } } else if (character == TSQLCharacters.CloseParentheses) { nestedLevel--; } } } return(groupBy); }
public TSQLFromClause Parse(ITSQLTokenizer tokenizer) { TSQLFromClause from = new TSQLFromClause(); if (!tokenizer.Current.IsKeyword(TSQLKeywords.FROM)) { throw new InvalidOperationException("FROM expected."); } from.Tokens.Add(tokenizer.Current); // derived tables // TVF int nestedLevel = 0; while ( tokenizer.MoveNext() && !( 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.JOIN, TSQLKeywords.ON, TSQLKeywords.INNER, TSQLKeywords.LEFT, TSQLKeywords.RIGHT, TSQLKeywords.OUTER, TSQLKeywords.CROSS, TSQLKeywords.FULL, TSQLKeywords.AS, TSQLKeywords.PIVOT, TSQLKeywords.UNPIVOT, TSQLKeywords.WITH, TSQLKeywords.MERGE, TSQLKeywords.TABLESAMPLE, TSQLKeywords.FOR, TSQLKeywords.FROM, // FOR SYSTEM_TIME FROM TSQLKeywords.BETWEEN, TSQLKeywords.AND, TSQLKeywords.IN, TSQLKeywords.REPEATABLE, TSQLKeywords.ALL ) ) )) { from.Tokens.Add(tokenizer.Current); if (tokenizer.Current.Type == TSQLTokenType.Character) { TSQLCharacters character = tokenizer.Current.AsCharacter.Character; if (character == TSQLCharacters.OpenParentheses) { // should we recurse for derived tables? nestedLevel++; if (tokenizer.MoveNext()) { if ( tokenizer.Current.Type == TSQLTokenType.Keyword && tokenizer.Current.AsKeyword.Keyword == TSQLKeywords.SELECT) { TSQLSelectStatement selectStatement = new TSQLSelectStatementParser().Parse(tokenizer); from.Tokens.AddRange(selectStatement.Tokens); if ( tokenizer.Current != null && tokenizer.Current.Type == TSQLTokenType.Character && tokenizer.Current.AsCharacter.Character == TSQLCharacters.CloseParentheses) { nestedLevel--; from.Tokens.Add(tokenizer.Current); } } else if (tokenizer.Current.IsCharacter( TSQLCharacters.CloseParentheses)) { nestedLevel--; from.Tokens.Add(tokenizer.Current); } else { from.Tokens.Add(tokenizer.Current); } } } else if (character == TSQLCharacters.CloseParentheses) { nestedLevel--; } } } return(from); }
public TSQLHavingClause Parse(TSQLTokenizer tokenizer) { TSQLHavingClause having = new TSQLHavingClause(); if ( tokenizer.Current == null || tokenizer.Current.Type != TSQLTokenType.Keyword || tokenizer.Current.AsKeyword.Keyword != TSQLKeywords.HAVING) { throw new ApplicationException("HAVING expected."); } having.Tokens.Add(tokenizer.Current); // subqueries 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.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.LIKE ) ) )) { having.Tokens.Add(tokenizer.Current); if (tokenizer.Current.Type == TSQLTokenType.Character) { TSQLCharacters character = tokenizer.Current.AsCharacter.Character; if (character == TSQLCharacters.OpenParentheses) { // should we recurse for subqueries? nestedLevel++; if (tokenizer.Read()) { if ( tokenizer.Current.Type == TSQLTokenType.Keyword && tokenizer.Current.AsKeyword.Keyword == TSQLKeywords.SELECT) { TSQLSelectStatement selectStatement = new TSQLSelectStatementParser().Parse(tokenizer); having.Tokens.AddRange(selectStatement.Tokens); if ( tokenizer.Current != null && tokenizer.Current.Type == TSQLTokenType.Character && tokenizer.Current.AsCharacter.Character == TSQLCharacters.CloseParentheses) { nestedLevel--; having.Tokens.Add(tokenizer.Current); } } else { having.Tokens.Add(tokenizer.Current); } } } else if (character == TSQLCharacters.CloseParentheses) { nestedLevel--; } } } return(having); }
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); }
public TSQLOrderByClause Parse(ITSQLTokenizer tokenizer) { TSQLOrderByClause orderBy = new TSQLOrderByClause(); if (!tokenizer.Current.IsKeyword(TSQLKeywords.ORDER)) { throw new InvalidOperationException("ORDER expected."); } orderBy.Tokens.Add(tokenizer.Current); // subqueries 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.BY, 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.LIKE, TSQLKeywords.ASC, TSQLKeywords.DESC, TSQLKeywords.FETCH, TSQLKeywords.COLLATE ) ) )) { orderBy.Tokens.Add(tokenizer.Current); if (tokenizer.Current.Type == TSQLTokenType.Character) { TSQLCharacters character = tokenizer.Current.AsCharacter.Character; if (character == TSQLCharacters.OpenParentheses) { // should we recurse for subqueries? nestedLevel++; if (tokenizer.MoveNext()) { if (tokenizer.Current.IsKeyword(TSQLKeywords.SELECT)) { TSQLSelectStatement selectStatement = new TSQLSelectStatementParser().Parse(tokenizer); orderBy.Tokens.AddRange(selectStatement.Tokens); if (tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)) { nestedLevel--; orderBy.Tokens.Add(tokenizer.Current); } } else if (tokenizer.Current.IsCharacter( TSQLCharacters.CloseParentheses)) { nestedLevel--; orderBy.Tokens.Add(tokenizer.Current); } else if (tokenizer.Current.IsCharacter( TSQLCharacters.OpenParentheses)) { nestedLevel++; orderBy.Tokens.Add(tokenizer.Current); } else { orderBy.Tokens.Add(tokenizer.Current); } } } else if (character == TSQLCharacters.CloseParentheses) { nestedLevel--; } } } return(orderBy); }
public TSQLExpression ParseNext( ITSQLTokenizer tokenizer) { if (tokenizer.Current == null) { return(null); } // look at the current/first token to determine what to do if (tokenizer.Current.Text == "*") { TSQLMulticolumnExpression simpleMulti = new TSQLMulticolumnExpression(); simpleMulti.Tokens.Add(tokenizer.Current); TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace( tokenizer, simpleMulti.Tokens); return(simpleMulti); // still need to seperately check for p.* below } // this checks for unary operators, e.g. +, -, and ~ else if (tokenizer.Current.Type.In( TSQLTokenType.Operator)) { return(null); } else if (tokenizer.Current.IsCharacter( TSQLCharacters.OpenParentheses)) { List <TSQLToken> tokens = new List <TSQLToken>(); tokens.Add(tokenizer.Current); // read through any whitespace so we can check specifically for a SELECT TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace( tokenizer, tokens); if (tokenizer.Current.IsKeyword(TSQLKeywords.SELECT)) { #region parse subquery TSQLSubqueryExpression subquery = new TSQLSubqueryExpression(); subquery.Tokens.AddRange(tokens); TSQLSelectStatement select = new TSQLSelectStatementParser(tokenizer).Parse(); subquery.Select = select; subquery.Tokens.AddRange(select.Tokens); if (tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)) { subquery.Tokens.Add(tokenizer.Current); tokenizer.MoveNext(); } return(subquery); #endregion } else { #region parse expression contained/grouped inside parenthesis TSQLGroupedExpression group = new TSQLGroupedExpression(); group.Tokens.AddRange(tokens); group.InnerExpression = new TSQLValueExpressionParser().Parse( tokenizer); group.Tokens.AddRange(group.InnerExpression.Tokens); if (tokenizer.Current.IsCharacter( TSQLCharacters.CloseParentheses)) { group.Tokens.Add(tokenizer.Current); tokenizer.MoveNext(); } return(group); #endregion } } else if (tokenizer.Current.Type.In( TSQLTokenType.Variable, TSQLTokenType.SystemVariable)) { TSQLVariableExpression variable = new TSQLVariableExpression(); variable.Tokens.Add(tokenizer.Current); variable.Variable = tokenizer.Current.AsVariable; TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace( tokenizer, variable.Tokens); return(variable); } else if (tokenizer.Current.Type.In( TSQLTokenType.BinaryLiteral, TSQLTokenType.MoneyLiteral, TSQLTokenType.NumericLiteral, TSQLTokenType.StringLiteral, TSQLTokenType.IncompleteString)) { TSQLConstantExpression constant = new TSQLConstantExpression(); constant.Literal = tokenizer.Current.AsLiteral; constant.Tokens.Add(tokenizer.Current); TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace( tokenizer, constant.Tokens); return(constant); } else if (tokenizer.Current.IsKeyword(TSQLKeywords.CASE)) { return(new TSQLCaseExpressionParser().Parse(tokenizer)); } else if (tokenizer.Current.Type.In( TSQLTokenType.SystemColumnIdentifier, TSQLTokenType.IncompleteIdentifier)) { TSQLColumnExpression column = new TSQLColumnExpression(); column.Column = tokenizer.Current.AsSystemColumnIdentifier; column.Tokens.Add(tokenizer.Current); TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace( tokenizer, column.Tokens); return(column); } else if (tokenizer.Current.Type.In( TSQLTokenType.Identifier, TSQLTokenType.SystemIdentifier)) { // column, with or without alias, or with full explicit table name with up to 5 parts // or function, up to 4 part naming // find last token up to and including possible first paren // if *, then multi column // if paren, then function // else column // alias would be any tokens prior to last period, removing whitespace List <TSQLToken> tokens = new List <TSQLToken>(); tokens.Add(tokenizer.Current); while (tokenizer.MoveNext()) { if (tokenizer.Current.IsCharacter(TSQLCharacters.OpenParentheses)) { #region parse function TSQLFunctionExpression function = new TSQLFunctionExpression(); function.Tokens.AddRange(tokens); function.Tokens.Add(tokenizer.Current); var identityTokens = tokens .Where(t => !t.IsComment() && !t.IsWhitespace()) .ToList(); function.Function = identityTokens[identityTokens.Count - 1] .AsIdentifier; if (identityTokens.Count > 1) { function.QualifiedPath = identityTokens .GetRange( 0, identityTokens.Count - 2); } tokenizer.MoveNext(); TSQLArgumentList arguments = null; // CAST function has it's own very unique argument syntax if (function.Function.IsIdentifier(TSQLIdentifiers.CAST)) { arguments = new TSQLValueAsTypeExpressionParser().Parse( tokenizer); } else { arguments = new TSQLArgumentListParser().Parse( tokenizer); } function.Tokens.AddRange(arguments.Tokens); function.Arguments = arguments; if (tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)) { function.Tokens.Add(tokenizer.Current); } tokenizer.MoveNext(); TSQLTokenParserHelper.ReadCommentsAndWhitespace( tokenizer, function); // look for windowed aggregate if (tokenizer.Current.IsKeyword(TSQLKeywords.OVER)) { function.Tokens.Add(tokenizer.Current); tokenizer.MoveNext(); TSQLTokenParserHelper.ReadCommentsAndWhitespace( tokenizer, function); if (tokenizer.Current.IsCharacter(TSQLCharacters.OpenParentheses)) { function.Tokens.Add(tokenizer.Current); // recursively look for final close parens TSQLTokenParserHelper.ReadUntilStop( tokenizer, function, new List <TSQLFutureKeywords> { }, new List <TSQLKeywords> { }, lookForStatementStarts: false); if (tokenizer.Current != null && tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)) { function.Tokens.Add(tokenizer.Current); tokenizer.MoveNext(); } } } return(function); #endregion } else if (tokenizer.Current.Text == "*") { #region parse multi column reference // e.g. p.* TSQLMulticolumnExpression multi = new TSQLMulticolumnExpression(); multi.Tokens.AddRange(tokens); multi.Tokens.Add(tokenizer.Current); List <TSQLToken> columnReference = tokens .Where(t => !t.IsComment() && !t.IsWhitespace()) .ToList(); if (columnReference.Count > 0) { // p.* will have the single token p in the final list // AdventureWorks..ErrorLog.* will have 4 tokens in the final list // e.g. {AdventureWorks, ., ., ErrorLog} multi.TableReference = columnReference .GetRange(0, columnReference .FindLastIndex(t => t.IsCharacter(TSQLCharacters.Period))) .ToList(); } TSQLTokenParserHelper.ReadThroughAnyCommentsOrWhitespace( tokenizer, multi.Tokens); return(multi); #endregion } else if ( tokenizer.Current.IsCharacter(TSQLCharacters.Comma) || tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses) || tokenizer.Current.Type.In( TSQLTokenType.Keyword, TSQLTokenType.Operator) || // this will be a nasty check, but I don't want to copy the internal logic elsewhere // two identifiers in a row means that the second one is an alias ( tokenizer.Current.Type.In( TSQLTokenType.Identifier, TSQLTokenType.IncompleteIdentifier) && tokens .Where(t => !t.IsComment() && !t.IsWhitespace()) .LastOrDefault() ?.Type.In( TSQLTokenType.Identifier, TSQLTokenType.BinaryLiteral, TSQLTokenType.MoneyLiteral, TSQLTokenType.NumericLiteral, TSQLTokenType.StringLiteral, TSQLTokenType.SystemColumnIdentifier, TSQLTokenType.SystemIdentifier, TSQLTokenType.SystemVariable, TSQLTokenType.Variable ) == true // Operator '&&' cannot be applied to operands of type 'bool' and 'bool?' )) { TSQLColumnExpression column = new TSQLColumnExpression(); column.Tokens.AddRange(tokens); List <TSQLToken> columnReference = tokens .Where(t => !t.IsComment() && !t.IsWhitespace()) .ToList(); if (columnReference.Count > 1) { // p.ProductID will have the single token p in the final list // AdventureWorks..ErrorLog.ErrorLogID will have 4 tokens in the final list // e.g. {AdventureWorks, ., ., ErrorLog} column.TableReference = columnReference .GetRange(0, columnReference .FindLastIndex(t => t.IsCharacter(TSQLCharacters.Period))) .ToList(); } column.Column = columnReference .Last() .AsIdentifier; return(column); } else { tokens.Add(tokenizer.Current); } } // this is the fall through if none of the "returns" hit above // will also hit if we parse a simple single column expression, e.g. "SELECT blah" TSQLColumnExpression simpleColumn = new TSQLColumnExpression(); simpleColumn.Tokens.AddRange(tokens); List <TSQLToken> simpleColumnReference = tokens .Where(t => !t.IsComment() && !t.IsWhitespace() && !t.IsCharacter(TSQLCharacters.Semicolon)) .ToList(); if (simpleColumnReference.Count > 1) { // p.ProductID will have the single token p in the final list // AdventureWorks..ErrorLog.ErrorLogID will have 4 tokens in the final list // e.g. {AdventureWorks, ., ., ErrorLog} simpleColumn.TableReference = simpleColumnReference .GetRange(0, simpleColumnReference .FindLastIndex(t => t.IsCharacter(TSQLCharacters.Period))) .ToList(); } simpleColumn.Column = simpleColumnReference .Last() .AsIdentifier; return(simpleColumn); } else { return(null); } }
public static void RecurseParens( ITSQLTokenizer tokenizer, TSQLExpression expression, ref int nestedLevel) { expression.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.MoveNext()) { if (tokenizer.Current.IsKeyword( TSQLKeywords.SELECT)) { TSQLSelectStatement selectStatement = new TSQLSelectStatementParser(tokenizer).Parse(); expression.Tokens.AddRange(selectStatement.Tokens); if (tokenizer.Current.IsCharacter( TSQLCharacters.CloseParentheses)) { nestedLevel--; expression.Tokens.Add(tokenizer.Current); } } else if (tokenizer.Current.IsCharacter( TSQLCharacters.CloseParentheses)) { nestedLevel--; expression.Tokens.Add(tokenizer.Current); } else if (tokenizer.Current.IsCharacter( TSQLCharacters.OpenParentheses)) { nestedLevel++; expression.Tokens.Add(tokenizer.Current); } else { expression.Tokens.Add(tokenizer.Current); } } } else if (character == TSQLCharacters.CloseParentheses) { nestedLevel--; } } else if (tokenizer.Current.IsKeyword(TSQLKeywords.CASE)) { TSQLCaseExpression caseExpression = new TSQLCaseExpressionParser().Parse(tokenizer); expression.Tokens.AddRange(caseExpression.Tokens); } }
public TSQLWhereClause Parse(IEnumerator <TSQLToken> tokenizer) { TSQLWhereClause where = new TSQLWhereClause(); TSQLKeyword keyword = tokenizer.Current.AsKeyword; if (keyword == null || keyword.Keyword != TSQLKeywords.WHERE) { throw new ApplicationException("WHERE expected."); } where.Tokens.Add(keyword); // subqueries int nestedLevel = 0; while ( tokenizer.MoveNext() && !( 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.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.LIKE ) ) )) { where.Tokens.Add(tokenizer.Current); if (tokenizer.Current.Type == TSQLTokenType.Character) { TSQLCharacters character = tokenizer.Current.AsCharacter.Character; if (character == TSQLCharacters.OpenParentheses) { // should we recurse for subqueries? nestedLevel++; if (tokenizer.MoveNext()) { if ( tokenizer.Current.Type == TSQLTokenType.Keyword && tokenizer.Current.AsKeyword.Keyword == TSQLKeywords.SELECT) { TSQLSelectStatement selectStatement = new TSQLSelectStatementParser().Parse(tokenizer); where.Tokens.AddRange(selectStatement.Tokens); if ( tokenizer.Current != null && tokenizer.Current.Type == TSQLTokenType.Character && tokenizer.Current.AsCharacter.Character == TSQLCharacters.CloseParentheses) { nestedLevel--; where.Tokens.Add(tokenizer.Current); } } else { where.Tokens.Add(tokenizer.Current); } } } else if (character == TSQLCharacters.CloseParentheses) { nestedLevel--; } } } return(where); }