public TSQLUsingClause Parse(ITSQLTokenizer tokenizer) { TSQLUsingClause usingClause = new TSQLUsingClause(); if (!tokenizer.Current.IsFutureKeyword(TSQLFutureKeywords.USING)) { throw new InvalidOperationException("USING expected."); } usingClause.Tokens.Add(tokenizer.Current); /* can contain: * * <table_source> ::= * { * table_or_view_name [ [ AS ] table_alias ] [ <tablesample_clause> ] * [ WITH ( table_hint [ [ , ]...n ] ) ] * | rowset_function [ [ AS ] table_alias ] * [ ( bulk_column_alias [ ,...n ] ) ] * | user_defined_function [ [ AS ] table_alias ] * | OPENXML <openxml_clause> * | derived_table [ AS ] table_alias [ ( column_alias [ ,...n ] ) ] * | <joined_table> * | <pivoted_table> * | <unpivoted_table> * } * https://docs.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver15#syntax */ 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 ( // ON is required in MERGE statement after USING TSQLKeywords.ON ) ) )) { TSQLTokenParserHelper.RecurseParens( tokenizer, usingClause, ref nestedLevel); } return(usingClause); }
public TSQLSetClause Parse(ITSQLTokenizer tokenizer) { TSQLSetClause set = new TSQLSetClause(); if (!tokenizer.Current.IsKeyword(TSQLKeywords.SET)) { throw new InvalidOperationException("SET expected."); } set.Tokens.Add(tokenizer.Current); // TODO: parse this rare but valid horror scenario // update output // set output.output = 1 // output deleted.* // maybe create assignment expression parser? 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.IsFutureKeyword(TSQLFutureKeywords.OUTPUT) ) || ( tokenizer.Current.Type == TSQLTokenType.Keyword && !tokenizer.Current.AsKeyword.Keyword.In ( TSQLKeywords.FROM, TSQLKeywords.WHERE, TSQLKeywords.OPTION ) && !tokenizer.Current.AsKeyword.Keyword.IsStatementStart() ) )) { TSQLTokenParserHelper.RecurseParens( tokenizer, set, ref nestedLevel); } return(set); }
public TSQLIntoClause Parse(ITSQLTokenizer tokenizer) { TSQLIntoClause into = new TSQLIntoClause(); if (!tokenizer.Current.IsKeyword(TSQLKeywords.INTO)) { throw new InvalidOperationException("INTO expected."); } into.Tokens.Add(tokenizer.Current); int nestedLevel = 0; while ( tokenizer.MoveNext() && !tokenizer.Current.IsCharacter(TSQLCharacters.Semicolon) && !( nestedLevel == 0 && tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses) ) && ( nestedLevel > 0 || tokenizer.Current.Type == TSQLTokenType.Identifier || tokenizer.Current.IsCharacter(TSQLCharacters.Period) || tokenizer.Current.IsCharacter(TSQLCharacters.OpenParentheses) || tokenizer.Current.Type == TSQLTokenType.Whitespace || tokenizer.Current.Type == TSQLTokenType.SingleLineComment || tokenizer.Current.Type == TSQLTokenType.MultilineComment )) { TSQLTokenParserHelper.RecurseParens( tokenizer, into, ref nestedLevel); } return(into); }
public TSQLWithClause Parse(ITSQLTokenizer tokenizer) { TSQLWithClause with = new TSQLWithClause(); if (!tokenizer.Current.IsKeyword(TSQLKeywords.WITH)) { throw new InvalidOperationException("WITH expected."); } with.Tokens.Add(tokenizer.Current); // subqueries int nestedLevel = 0; int parenCount = 0; int identifierCount = 0; bool afterAs = false; while ( tokenizer.MoveNext() && !tokenizer.Current.IsCharacter(TSQLCharacters.Semicolon) && !( nestedLevel == 0 && tokenizer.Current.IsCharacter(TSQLCharacters.CloseParentheses) ) && !( // only allow a set of parens at root level // if it's following an AS // or if it's the column list between the CTE name and the AS nestedLevel == 0 && tokenizer.Current.IsCharacter(TSQLCharacters.OpenParentheses) && afterAs && parenCount >= identifierCount ) && ( nestedLevel > 0 || tokenizer.Current.Type != TSQLTokenType.Keyword || ( tokenizer.Current.Type == TSQLTokenType.Keyword && !tokenizer.Current.AsKeyword.Keyword.In ( TSQLKeywords.SELECT, TSQLKeywords.INSERT, TSQLKeywords.UPDATE, TSQLKeywords.DELETE, TSQLKeywords.MERGE ) ) )) { if (nestedLevel == 0) { if (afterAs && tokenizer.Current.IsCharacter(TSQLCharacters.OpenParentheses)) { parenCount++; } else if (tokenizer.Current.Type == TSQLTokenType.Identifier) { identifierCount++; afterAs = false; } else if (tokenizer.Current.IsKeyword(TSQLKeywords.AS)) { afterAs = true; } } TSQLTokenParserHelper.RecurseParens( tokenizer, with, ref nestedLevel); } return(with); }