private SqlOrderByEntryNode ParseOrderTerm(ITokenizer t) { // ( <QualifiedIdentifier> | <Number> ) ("ASC" | "DESC")? var identifier = ParseQualifiedIdentifier(t); if (identifier == null) { if (t.Peek().IsType(SqlTokenType.Number)) { var number = t.GetNext(); identifier = new SqlNumberNode(number); } } if (identifier == null) { throw ParsingException.CouldNotParseRule(nameof(ParseOrderTerm), t.Peek()); } var entry = new SqlOrderByEntryNode { Location = identifier.Location, Source = identifier }; var next = t.Peek(); if (next.IsKeyword("ASC") || next.IsKeyword("DESC")) { t.GetNext(); entry.Direction = next.Value; } return(entry); }
private ISqlNode ParseMaybeAliasedScalar(ITokenizer t, Func <ITokenizer, ISqlNode> parse) { var node = parse(t); var next = t.Peek(); if (next.IsKeyword("AS")) { var asToken = t.GetNext(); var alias = t.Expect(SqlTokenType.Identifier); return(new SqlAliasNode { Location = asToken.Location, Source = node, Alias = new SqlIdentifierNode(alias) }); } if (next.IsType(SqlTokenType.Identifier)) { t.GetNext(); return(new SqlAliasNode { Location = node.Location, Source = node, Alias = new SqlIdentifierNode(next) }); } return(node); }
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)); }
private ISqlNode ParseInsertOnConflictClause(ITokenizer t) { if (!t.Peek().IsKeyword("ON")) { return(null); } t.GetNext(); t.Expect(SqlTokenType.Keyword, "CONFLICT"); t.Expect(SqlTokenType.Keyword, "DO"); var next = t.Peek(); if (next.IsKeyword("NOTHING")) { return(new SqlKeywordNode(t.GetNext())); } if (next.IsKeyword("UPDATE")) { var updateToken = t.Expect(SqlTokenType.Keyword, "UPDATE"); return(new SqlUpdateNode { Location = updateToken.Location, SetClause = ParseUpdateSetClause(t), WhereClause = ParseWhereClause(t) }); } throw new ParsingException("Cannot parse INSERT ... ON CONFLICT clause. Unexpected token " + next); }
private ISqlNode ParseQualifiedIdentifier(ITokenizer t) { // ( <Qualifier> "." )? <Identifier> var next = t.Peek(); if (!next.IsType(SqlTokenType.Identifier) && !next.IsType(SqlTokenType.Keyword)) { return(null); } t.GetNext(); if (!t.Peek().Is(SqlTokenType.Symbol, ".")) { return(new SqlIdentifierNode(next)); } t.GetNext(); var qualifier = new SqlIdentifierNode(next); var identifier = t.GetNext(); return(new SqlQualifiedIdentifierNode { Location = qualifier.Location, Qualifier = qualifier, Identifier = identifier.Is(SqlTokenType.Symbol, "*") ? (ISqlNode) new SqlOperatorNode("*") : new SqlIdentifierNode(identifier) }); }
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 ISqlNode ParseTableOrSubexpression(ITokenizer t) { // <ObjectIdentifier> | <tableVariable> | "(" <QueryExpression> ")" | "(" <ValuesExpression> ")" var lookahead = t.Peek(); // <ObjectIdentifier> if (lookahead.IsType(SqlTokenType.Identifier)) { return(ParseObjectIdentifier(t)); } // <tableVariable> if (lookahead.IsType(SqlTokenType.Variable)) { return(new SqlVariableNode(t.GetNext())); } // "(" <Subexpression> ")" if (lookahead.Is(SqlTokenType.Symbol, "(")) { return(ParseParenthesis(t, ParseSubexpression)); } throw ParsingException.CouldNotParseRule(nameof(ParseTableOrSubexpression), lookahead); }
private ISqlNode ParseQuerySpecificiation(ITokenizer t) { // "SELECT" ... var selectToken = t.Expect(SqlTokenType.Keyword, "SELECT"); var selectNode = new SqlSelectNode { Location = selectToken.Location }; var modifier = t.Peek(); if (modifier.IsKeyword("ALL") || modifier.IsKeyword("DISTINCT")) { t.GetNext(); selectNode.Modifier = modifier.Value; } selectNode.Columns = ParseList(t, ParseSelectColumn); selectNode.FromClause = ParseSelectFromClause(t); selectNode.WhereClause = ParseWhereClause(t); selectNode.GroupByClause = ParseSelectGroupByClause(t); selectNode.HavingClause = ParseSelectHavingClause(t); selectNode.OrderByClause = ParseSelectOrderByClause(t); selectNode.TopLimitClause = ParseSelectLimitClause(t); selectNode.OffsetClause = ParseSelectOffsetClause(t); selectNode.FetchClause = ParseSelectFetchClause(t); return(selectNode); }
private SqlTopLimitNode ParseSelectTopClause(ITokenizer t) { // "TOP" "(" <Number> | <Variable> ")" "PERCENT"? "WITH TIES"? // "TOP" <Number> | <Variable> "PERCENT"? "WITH TIES"? if (!t.NextIs(SqlTokenType.Keyword, "TOP")) { return(null); } var topToken = t.GetNext(); var numberOrVariable = ParseMaybeParenthesis(t, ParseNumberOrVariable); bool percent = t.NextIs(SqlTokenType.Keyword, "PERCENT", true); bool withTies = false; if (t.NextIs(SqlTokenType.Keyword, "WITH", true)) { t.Expect(SqlTokenType.Keyword, "TIES"); withTies = true; } return(new SqlTopLimitNode { Location = topToken.Location, Value = numberOrVariable, Percent = percent, WithTies = withTies }); }
private SqlStatementListNode ParseBeginEndStatementList(ITokenizer t) { t.Expect(SqlTokenType.Keyword, "BEGIN"); var statements = new SqlStatementListNode { UseBeginEnd = true }; while (true) { var lookahead = t.Peek(); if (lookahead.IsType(SqlTokenType.EndOfInput)) { throw ParsingException.CouldNotParseRule(nameof(ParseBeginEndStatementList), lookahead); } if (lookahead.Is(SqlTokenType.Keyword, "END")) { t.GetNext(); break; } var statement = ParseStatement(t); if (statement == null) { throw ParsingException.CouldNotParseRule(nameof(ParseBeginEndStatementList), t.Peek()); } statements.Statements.Add(statement); } return(statements); }
public static SqlToken Peek(this ITokenizer ITokenizer) { var t = ITokenizer.GetNext(); ITokenizer.PutBack(t); return(t); }
public SqlInsertNode ParseMergeNotMatched(ITokenizer t) { var insertToken = t.Expect(SqlTokenType.Keyword, "INSERT"); var insertNode = new SqlInsertNode { Location = insertToken.Location, Columns = ParseInsertColumnList(t) }; var next = t.Peek(); if (next.IsKeyword("VALUES")) { insertNode.Source = ParseValues(t); } else if (next.IsKeyword("DEFAULT")) { t.GetNext(); t.Expect(SqlTokenType.Keyword, "VALUES"); insertNode.Source = new SqlKeywordNode("DEFAULT VALUES"); } else { throw new ParsingException("INSERT statement does not have a source"); } return(insertNode); }
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)); }
private SqlInfixOperationNode ParseUpdateColumnAssignExpression(ITokenizer t) { // (<Column> | <Variable>) <CompareOp> ("DEFAULT" | <Expression>) var columnName = ParseVariableOrQualifiedIdentifier(t); // TODO: Other assignment operators var opToken = t.Expect(SqlTokenType.Symbol, "=", "+=", "-=", "*=", "/=", "%=", "&=", "^=", "|="); ISqlNode rvalue; var lookahead = t.Peek(); if (lookahead.Is(SqlTokenType.Keyword, "DEFAULT")) { t.GetNext(); rvalue = new SqlKeywordNode(lookahead); } else { rvalue = ParseScalarExpression(t); } return(new SqlInfixOperationNode { Left = columnName, Location = columnName.Location, Operator = new SqlOperatorNode(opToken), Right = rvalue }); }
private ISqlNode ParseCaseExpression(ITokenizer t) { // "CASE" <Expression>? <When>+ <Else>? "END" var caseToken = t.Expect(SqlTokenType.Keyword, "CASE"); var caseNode = new SqlCaseNode { Location = caseToken.Location }; if (!t.Peek().IsKeyword("WHEN")) { caseNode.InputExpression = ParseScalarExpression(t); } while (true) { var lookahead = t.Peek(); if (lookahead.IsKeyword("END")) { t.GetNext(); return(caseNode); } if (lookahead.IsKeyword("ELSE")) { t.GetNext(); caseNode.ElseExpression = ParseScalarExpression(t); t.Expect(SqlTokenType.Keyword, "END"); return(caseNode); } if (lookahead.IsKeyword("WHEN")) { var whenNode = t.GetNext(); var condition = ParseBooleanExpression(t); t.Expect(SqlTokenType.Keyword, "THEN"); var result = ParseScalarExpression(t); caseNode.WhenExpressions.Add(new SqlCaseWhenNode { Location = whenNode.Location, Condition = condition, Result = result }); continue; } throw ParsingException.CouldNotParseRule(nameof(ParseCaseExpression), lookahead); } }
public static SqlToken GetIdentifierOrKeyword(this ITokenizer ITokenizer) { var next = ITokenizer.GetNext(); if (next.IsType(SqlTokenType.Identifier) || next.IsType(SqlTokenType.Keyword)) { return(next); } throw ParsingException.UnexpectedToken(SqlTokenType.Identifier, next); }
private ISqlNode ParseSelectFromClause(ITokenizer t) { // ("FROM" <join>)? if (!t.NextIs(SqlTokenType.Keyword, "FROM")) { return(null); } t.GetNext(); return(ParseJoin(t)); }
public static SqlToken Expect(this ITokenizer ITokenizer, SqlTokenType type) { var found = ITokenizer.GetNext(); if (found.Type != type) { throw ParsingException.UnexpectedToken(type, found); } return(found); }
private ISqlNode ParseSelectHavingClause(ITokenizer t) { // "HAVING" <BooleanExpression> if (!t.NextIs(SqlTokenType.Keyword, "HAVING")) { return(null); } t.GetNext(); return(ParseBooleanExpression(t)); }
private ISqlNode ParseWhereClause(ITokenizer t) { // "WHERE" <BooleanExpression> if (!t.NextIs(SqlTokenType.Keyword, "WHERE")) { return(null); } t.GetNext(); return(ParseBooleanExpression(t)); }
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 ParseSelectGroupByClause(ITokenizer t) { // "GROUP" "BY" <IdentifierList> if (!t.NextIs(SqlTokenType.Keyword, "GROUP")) { return(null); } t.GetNext(); t.Expect(SqlTokenType.Keyword, "BY"); return(ParseList(t, ParseQualifiedIdentifier)); }
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)); }
private ISqlNode ParseSelectOffsetClause(ITokenizer t) { if (!t.NextIs(SqlTokenType.Keyword, "OFFSET")) { return(null); } t.GetNext(); var offset = ParseNumberOrVariable(t); t.Expect(SqlTokenType.Keyword, "ROW", "ROWS"); return(offset); }
private SqlDataTypeNode ParseDataType(ITokenizer t) { // <Keyword> ("(" ("MAX" | <SizeList>)? ")")? var next = t.GetNext(); // TODO: Array types // TODO: Should we add TABLE declaration parsing? if (next.IsKeyword("TABLE")) { return(null); } var dataType = new SqlDataTypeNode { Location = next.Location, DataType = new SqlKeywordNode(next), }; if (t.Peek().IsSymbol("(")) { t.GetNext(); var lookahead = t.Peek(); if (lookahead.IsKeyword("MAX")) { dataType.Size = new SqlKeywordNode(t.GetNext()); } else if (lookahead.IsType(SqlTokenType.Number)) { dataType.Size = ParseList(t, ParseNumber); } else { throw ParsingException.CouldNotParseRule(nameof(ParseDataType), lookahead); } t.Expect(SqlTokenType.Symbol, ")"); } return(dataType); }
private ISqlNode ParseMaybeAliasedTable(ITokenizer t, Func <ITokenizer, ISqlNode> parse) { var node = parse(t); var next = t.Peek(); SqlToken aliasToken = null; Location location = null; if (next.IsKeyword("AS")) { location = t.GetNext().Location; aliasToken = t.GetIdentifierOrKeyword(); } else if (next.IsType(SqlTokenType.Identifier)) { aliasToken = t.GetNext(); } if (aliasToken == null) { return(node); } var alias = new SqlAliasNode { Location = location ?? aliasToken.Location, Source = node, Alias = new SqlIdentifierNode(aliasToken) }; if (t.Peek().IsSymbol("(")) { alias.ColumnNames = ParseParenthesis(t, x => ParseList(x, ParseIdentifier)).Expression; } return(alias); }
private ISqlNode ParseNumberOrVariable(ITokenizer t) { var next = t.GetNext(); if (next.IsType(SqlTokenType.Variable)) { return(new SqlVariableNode(next)); } if (next.IsType(SqlTokenType.Number)) { return(new SqlNumberNode(next)); } throw ParsingException.CouldNotParseRule(nameof(ParseNumberOrVariable), next); }
private ISqlNode ParseSelectFetchClause(ITokenizer t) { if (!t.NextIs(SqlTokenType.Keyword, "FETCH")) { return(null); } t.GetNext(); t.Expect(SqlTokenType.Keyword, "FIRST", "NEXT"); var fetch = ParseNumberOrVariable(t); t.Expect(SqlTokenType.Keyword, "ROW", "ROWS"); t.Expect(SqlTokenType.Keyword, "ONLY"); return(fetch); }
private ISqlNode ParseScalarExpression1(ITokenizer t) { // "NULL" | ("-" | "+" | "~") <Expression0> | <Expression0> var next = t.Peek(); if (next.IsKeyword("NULL")) { var nullToken = t.GetNext(); return(new SqlNullNode(nullToken)); } if (next.IsSymbol("-", "+", "~")) { var op = t.GetNext(); var expr = ParseScalarExpression1(t); return(new SqlPrefixOperationNode { Location = op.Location, Operator = new SqlOperatorNode(op), Right = expr }); } return(ParseScalarExpression0(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; } } }