public static SqlToken MaybeGetKeywordSequence(this ITokenizer ITokenizer, params string[] allowed) { var lookup = new HashSet <string>(allowed); var keywords = new List <SqlToken>(); while (true) { var next = ITokenizer.GetNext(); if (!next.IsType(SqlTokenType.Keyword)) { ITokenizer.PutBack(next); break; } if (!lookup.Contains(next.Value)) { ITokenizer.PutBack(next); break; } keywords.Add(next); } if (!keywords.Any()) { return(null); } var combined = string.Join(" ", keywords.Select(k => k.Value)); return(SqlToken.Keyword(combined, keywords.First().Location)); }
public static SqlToken Peek(this ITokenizer ITokenizer) { var t = ITokenizer.GetNext(); ITokenizer.PutBack(t); return(t); }
private ISqlNode ParseSelectColumn(ITokenizer t) { var next = t.GetNext(); // "*" if (next.Is(SqlTokenType.Symbol, "*")) { return(new SqlOperatorNode(next)); } // TODO: Should change this to (<Variable> "=")? <SelectColumnExpression> // <Variable> ("=" <SelectColumnExpression>)? if (next.IsType(SqlTokenType.Variable)) { if (t.NextIs(SqlTokenType.Symbol, "=")) { var equalsOperator = t.GetNext(); var rvalue = ParseScalarExpression(t); return(new SqlInfixOperationNode { Location = equalsOperator.Location, Left = new SqlVariableNode(next), Right = rvalue, Operator = new SqlOperatorNode(equalsOperator) }); } } t.PutBack(next); // <SelectColumnExpression> (AS <Alias>)? return(ParseMaybeAliasedScalar(t, ParseSelectColumnExpression)); }
public static bool NextIs(this ITokenizer ITokenizer, SqlTokenType type, string value, bool consume = false) { var t = ITokenizer.GetNext(); bool isSame = t.Type == type && t.Value == value; if (!isSame) { ITokenizer.PutBack(t); return(false); } if (!consume) { ITokenizer.PutBack(t); } return(true); }
private ISqlNode ParseFunctionCall(ITokenizer t) { var name = t.GetNext(); if (name.Type != SqlTokenType.Keyword && name.Type != SqlTokenType.Identifier) { throw ParsingException.UnexpectedToken(SqlTokenType.Identifier, name); } // "COUNT" "(" "*" ")" if (name.IsKeyword("COUNT")) { var openParen = t.Expect(SqlTokenType.Symbol, "("); var maybeStar = t.Peek(); if (maybeStar.IsSymbol("*")) { t.GetNext(); t.Expect(SqlTokenType.Symbol, ")"); return(new SqlFunctionCallNode { Location = name.Location, Name = new SqlKeywordNode(name), Arguments = new SqlListNode <ISqlNode> { new SqlOperatorNode(maybeStar) } }); } // It's not *, so put everything back, fallthrough, and let the rest of the parsing happen t.PutBack(openParen); } // TODO: "CONVERT" "(" <DataType>, <ScalarExpression> ("," <int>)? ")" // "CAST" "(" <ScalarExpression> "AS" <DataType> ")" if (name.IsKeyword("CAST")) { t.Expect(SqlTokenType.Symbol, "("); var first = ParseScalarExpression(t); t.Expect(SqlTokenType.Keyword, "AS"); var type = ParseDataType(t); t.Expect(SqlTokenType.Symbol, ")"); return(new SqlCastNode { Location = name.Location, Expression = first, DataType = type }); } // <Name> "(" <ScalarExpressionList> ")" return(new SqlFunctionCallNode { Location = name.Location, Name = Facts.IsBuiltInFunctionName(name.Value) ? (ISqlNode) new SqlKeywordNode(name.Value.ToUpperInvariant(), name.Location) : new SqlIdentifierNode(name), Arguments = ParseParenthesis(t, x => ParseList(x, ParseScalarExpression)).Expression }); }
private SqlNumberNode ParseNumber(ITokenizer t) { var next = t.GetNext(); if (next.IsType(SqlTokenType.Number)) { return(new SqlNumberNode(next)); } t.PutBack(next); return(null); }
private ISqlNode ParseVariableOrObjectIdentifier(ITokenizer t) { var next = t.GetNext(); // <Variable> if (next.IsType(SqlTokenType.Variable)) { return(new SqlVariableNode(next)); } t.PutBack(next); return(ParseObjectIdentifier(t)); }
public static void Skip(this ITokenizer ITokenizer, SqlTokenType type) { while (true) { var t = ITokenizer.GetNext(); if (t.Type == SqlTokenType.EndOfInput || type == SqlTokenType.EndOfInput) { break; } if (t.Type != type) { ITokenizer.PutBack(t); break; } } }
private ISqlNode ParseVariableOrQualifiedIdentifier(ITokenizer t) { var next = t.GetNext(); // <Variable> if (next.IsType(SqlTokenType.Variable)) { return(new SqlVariableNode(next)); } t.PutBack(next); var identifier = ParseQualifiedIdentifier(t); if (identifier != null) { return(identifier); } throw ParsingException.CouldNotParseRule(nameof(ParseVariableOrQualifiedIdentifier), next); }
private ISqlNode ParseVariableOrConstant(ITokenizer t) { var next = t.GetNext(); if (next.IsType(SqlTokenType.Variable)) { return(new SqlVariableNode(next)); } if (next.IsType(SqlTokenType.QuotedString)) { return(new SqlStringNode(next)); } t.PutBack(next); var number = ParseNumber(t); if (number != null) { return(number); } throw ParsingException.CouldNotParseRule(nameof(ParseVariableOrConstant), next); }
private ISqlNode ParseScalarExpression0(ITokenizer t) { // Terminal expression // <MethodCall> | <Identifier> | <Variable> | <String> | <Number> | "(" <Expression> ")" var next = t.Peek(); if (next.IsKeyword("TARGET", "SOURCE")) { return(ParseQualifiedIdentifier(t)); } if (next.IsKeyword("CAST", "CONVERT", "COUNT")) { var name = t.GetNext(); if (t.Peek().IsSymbol("(")) { t.PutBack(name); return(ParseFunctionCall(t)); } throw ParsingException.CouldNotParseRule(nameof(ParseScalarExpression0), next); } if (next.IsType(SqlTokenType.Identifier)) { var name = t.GetNext(); if (t.Peek().IsSymbol("(")) { t.PutBack(name); return(ParseFunctionCall(t)); } t.PutBack(name); return(ParseQualifiedIdentifier(t)); } if (next.IsType(SqlTokenType.Variable)) { return(new SqlVariableNode(t.GetNext())); } if (next.IsType(SqlTokenType.QuotedString)) { return(new SqlStringNode(t.GetNext())); } if (next.IsType(SqlTokenType.Number)) { return(new SqlNumberNode(t.GetNext())); } if (next.IsSymbol("(")) { // "(" (<QueryExpression> | <ScalarExpression>) ")" // e.g. SET @x = (select 5) or INSERT INTO x(num) VALUES (1, 2, (select 3)) var value = ParseParenthesis(t, x => { if (x.Peek().IsKeyword("SELECT")) { return(ParseQueryExpression(t)); } return(ParseScalarExpression(t)); }); if (value.Expression is SqlSelectNode) { return(value); } return(value.Expression); } throw ParsingException.CouldNotParseRule(nameof(ParseScalarExpression0), next); }
public SqlExecuteArgumentNode ParseExecArgument(ITokenizer t) { // (<parameter> "=")? (<Expression> | "DEFAULT" | <Variable> ("OUT"|"OUTPUT")) var next = t.GetNext(); if (next.IsSymbol(";") || next.IsType(SqlTokenType.EndOfInput)) { return(null); } if (next.IsKeyword("DEFAULT")) { var keyword = new SqlKeywordNode(next); return(new SqlExecuteArgumentNode { Location = keyword.Location, Value = keyword }); } if (next.IsType(SqlTokenType.Variable)) { var lookahead = t.Peek(); if (lookahead.IsSymbol("=")) { t.GetNext(); return(new SqlExecuteArgumentNode { Location = next.Location, AssignVariable = new SqlVariableNode(next), Value = ParseScalarExpression(t), IsOut = t.NextIs(SqlTokenType.Keyword, "OUT", true) || t.NextIs(SqlTokenType.Keyword, "OUTPUT", true) }); } } ISqlNode expression = null; if (next.IsType(SqlTokenType.Identifier, SqlTokenType.Number, SqlTokenType.QuotedString, SqlTokenType.Variable)) { t.PutBack(next); expression = ParseScalarExpression(t); } else if (next.IsType(SqlTokenType.Keyword)) { if (t.Peek().IsSymbol("(")) { t.PutBack(next); expression = ParseScalarExpression(t); } } if (expression == null) { t.PutBack(next); return(null); } return(new SqlExecuteArgumentNode { Location = next.Location, Value = expression, IsOut = t.NextIs(SqlTokenType.Keyword, "OUT", true) || t.NextIs(SqlTokenType.Keyword, "OUTPUT", true) }); }
private ISqlNode ParseUnterminatedStatement(ITokenizer t) { t.Skip(SqlTokenType.Whitespace); var keyword = t.Peek(); if (keyword.Type == SqlTokenType.Keyword) { if (keyword.Value == "SELECT") { return(ParseQueryExpression(t)); } if (keyword.Value == "WITH") { return(ParseWithStatement(t)); } if (keyword.Value == "INSERT") { return(ParseInsertStatement(t)); } if (keyword.Value == "UPDATE") { return(ParseUpdateStatement(t)); } if (keyword.Value == "DELETE") { return(ParseDeleteStatement(t)); } if (keyword.Value == "DECLARE") { return(ParseDeclare(t)); } if (keyword.Value == "EXEC" || keyword.Value == "EXECUTE") { return(ParseExecute(t)); } if (keyword.Value == "BEGIN") { return(ParseBeginEndStatementList(t)); } if (keyword.Value == "IF") { return(ParseIf(t)); } if (keyword.Value == "MERGE") { return(ParseMergeStatement(t)); } } if (keyword.Type == SqlTokenType.Identifier || keyword.Type == SqlTokenType.Variable) { var id = t.GetNext(); var op = t.Peek(); t.PutBack(id); if (op.IsSymbol(":=")) { return(ParseSet(t)); } } // TODO: RETURN? // TODO: THROW/TRY/CATCH // TODO: WHILE/CONTINUE/BREAK // TODO: CREATE/DROP/ALTER? Do we want to handle DDL statments here? return(null); }
private SqlOperatorNode ParseJoinOperator(ITokenizer t) { // "CROSS" ("APPLY" | "JOIN") // "NATURAL" "JOIN" // "INNER" "JOIN" // ("LEFT" | "RIGHT")? "OUTER"? "JOIN" var k = t.GetNext(); if (!k.IsKeyword()) { t.PutBack(k); return(null); } if (k.Value == "CROSS") { if (t.NextIs(SqlTokenType.Keyword, "APPLY", true)) { return(new SqlOperatorNode("CROSS APPLY", k.Location)); } if (t.NextIs(SqlTokenType.Keyword, "JOIN", true)) { return(new SqlOperatorNode("CROSS JOIN", k.Location)); } throw ParsingException.CouldNotParseRule(nameof(ParseJoinOperator), k); } if (k.Value == "NATURAL") { t.Expect(SqlTokenType.Keyword, "JOIN"); return(new SqlOperatorNode("NATURAL JOIN", k.Location)); } if (k.Value == "INNER") { t.Expect(SqlTokenType.Keyword, "JOIN"); return(new SqlOperatorNode("INNER JOIN", k.Location)); } var joinOperator = new List <SqlToken>(); var location = k.Location; if (k.Value == "FULL" || k.Value == "LEFT" || k.Value == "RIGHT") { joinOperator.Add(k); k = t.GetNext(); } if (k.Value == "OUTER") { joinOperator.Add(k); k = t.GetNext(); if (k.Value == "APPLY") { return(new SqlOperatorNode("OUTER APPLY")); } } // TODO: hints: "MERGE" | "HASH" | "REDISTRIBUTE" | "REPLICATE" | "REDUCE" if (k.Value == "JOIN") { joinOperator.Add(k); var op = string.Join(" ", joinOperator.Select(j => j.Value)); return(new SqlOperatorNode(op, location)); } if (joinOperator.Count > 0) { throw ParsingException.CouldNotParseRule(nameof(ParseJoinOperator), k); } t.PutBack(k); return(null); }