public TSQLExpression Parse(ITSQLTokenizer tokenizer) { TSQLExpression expression = ParseNext(tokenizer); if ( tokenizer.Current != null && tokenizer.Current.Text != "*" && tokenizer.Current.Type.In( TSQLTokenType.Operator) && // check for operator =, when expression type is column, and don't parse operator if found // e.g. IsFinishedGoods = p.FinishedGoodsFlag ( tokenizer.Current.Text != "=" || expression?.Type != TSQLExpressionType.Column )) { if ( expression?.Type == TSQLExpressionType.Variable && // https://docs.microsoft.com/en-us/sql/t-sql/language-elements/compound-operators-transact-sql new string[] { "=", "+=", "-=", "*=", "/=", "%=", "&=", "|=" }.Contains(tokenizer.Current.AsOperator.Text)) { return(new TSQLVariableAssignmentExpressionParser().Parse( tokenizer, expression.AsVariable)); } else { return(new TSQLOperatorExpressionParser().Parse( tokenizer, expression)); } } else { return(expression); } }
public TSQLArgumentList Parse(ITSQLTokenizer tokenizer) { List <TSQLExpression> arguments = new List <TSQLExpression>(); TSQLValueExpressionParser factory = new TSQLValueExpressionParser(); List <TSQLToken> tokens = new List <TSQLToken>(); // need to do this before starting the argument loop // so we can handle an empty argument list of just whitespace // and comments TSQLTokenParserHelper.ReadCommentsAndWhitespace( tokenizer, tokens); while ( tokenizer.Current != null && !tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses)) { TSQLTokenParserHelper.ReadCommentsAndWhitespace( tokenizer, tokens); TSQLExpression argument = factory.Parse(tokenizer); tokens.AddRange(argument.Tokens); arguments.Add(argument); if (tokenizer.Current.IsCharacter(TSQLCharacters.Comma)) { tokens.Add(tokenizer.Current); tokenizer.MoveNext(); TSQLTokenParserHelper.ReadCommentsAndWhitespace( tokenizer, tokens); } } TSQLArgumentList argList = new TSQLArgumentList( arguments); argList.Tokens.AddRange(tokens); return(argList); }
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); }
public TSQLOperatorExpression Parse( ITSQLTokenizer tokenizer, TSQLExpression leftSide) { TSQLOperatorExpression opExpression = new TSQLOperatorExpression(); opExpression.LeftSide = leftSide; opExpression.Operator = tokenizer.Current.AsOperator; if (leftSide != null) { opExpression.Tokens.AddRange(leftSide.Tokens); } opExpression.Tokens.Add(tokenizer.Current); while ( tokenizer.MoveNext() && ( tokenizer.Current.IsWhitespace() || tokenizer.Current.IsComment() )) { opExpression.Tokens.Add(tokenizer.Current); } TSQLExpression rightSide = new TSQLValueExpressionParser().Parse( tokenizer); // a + (b + (c + d)) if ( tokenizer.Current != null && tokenizer.Current.Type.In( TSQLTokenType.Operator)) { rightSide = Parse( tokenizer, rightSide); } opExpression.RightSide = rightSide; opExpression.Tokens.AddRange(rightSide.Tokens); return(opExpression); }
public TSQLExpression Parse(ITSQLTokenizer tokenizer) { TSQLExpression expression = ParseNext(tokenizer); if ( tokenizer.Current != null && tokenizer.Current.Text != "*" && tokenizer.Current.Type.In( TSQLTokenType.Operator)) { return(new TSQLOperatorExpressionParser().Parse( tokenizer, expression)); } else { return(expression); } }
public static void RecurseParens( ITSQLTokenizer tokenizer, TSQLExpression expression, ref int nestedLevel) { if (tokenizer.Current.Type == TSQLTokenType.Character) { expression.Tokens.Add(tokenizer.Current); TSQLCharacters character = tokenizer.Current.AsCharacter.Character; if (character == TSQLCharacters.OpenParentheses) { // should we recurse for correlated subqueries? nestedLevel++; } else if (character == TSQLCharacters.CloseParentheses) { nestedLevel--; } } else if (tokenizer.Current.IsKeyword(TSQLKeywords.CASE)) { // not going to add CASE token directly because it will be contained // within the returned expression and we don't want to double up the // CASE token within the results. // CASE is a special situation because it's stop word (END) is part of // the expression itself and needs to be included in it's token list. // all other clauses stop at the beginning of the next clause and do // not include the stop token within their token list. TSQLCaseExpression caseExpression = new TSQLCaseExpressionParser().Parse(tokenizer); expression.Tokens.AddRange(caseExpression.Tokens); } else { expression.Tokens.Add(tokenizer.Current); } }
/// <summary> /// This reads recursively through parenthesis and returns when it hits /// one of the stop words outside of any nested parenthesis. /// </summary> public static void ReadUntilStop( ITSQLTokenizer tokenizer, TSQLExpression expression, List <TSQLFutureKeywords> futureKeywords, List <TSQLKeywords> keywords, bool lookForStatementStarts) { 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 && !futureKeywords.Any(fk => tokenizer.Current.IsFutureKeyword(fk)) ) || ( tokenizer.Current.Type == TSQLTokenType.Keyword && !keywords.Any(k => tokenizer.Current.AsKeyword.Keyword == k) && !( lookForStatementStarts && tokenizer.Current.AsKeyword.Keyword.IsStatementStart() ) ) )) { TSQLSubqueryHelper.RecurseParens( tokenizer, expression, ref nestedLevel); } }
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); } }