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); }
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 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 SqlObjectIdentifierNode ParseObjectIdentifier(ITokenizer t) { // (((<ServerName> ".")? <DatabaseName> ".")? <Schema> ".")? <Identifier> var item1 = t.Expect(SqlTokenType.Identifier); if (!t.NextIs(SqlTokenType.Symbol, ".", true)) { return(new SqlObjectIdentifierNode { Location = item1.Location, Name = new SqlIdentifierNode(item1) }); } var item2 = t.Expect(SqlTokenType.Identifier); if (!t.NextIs(SqlTokenType.Symbol, ".", true)) { return(new SqlObjectIdentifierNode { Location = item1.Location, Schema = new SqlIdentifierNode(item1), Name = new SqlIdentifierNode(item2) }); } var item3 = t.Expect(SqlTokenType.Identifier); if (!t.NextIs(SqlTokenType.Symbol, ".", true)) { return(new SqlObjectIdentifierNode { Location = item1.Location, Database = new SqlIdentifierNode(item1), Schema = new SqlIdentifierNode(item2), Name = new SqlIdentifierNode(item3) }); } var item4 = t.Expect(SqlTokenType.Identifier); return(new SqlObjectIdentifierNode { Location = item1.Location, Server = new SqlIdentifierNode(item1), Database = new SqlIdentifierNode(item2), Schema = new SqlIdentifierNode(item3), Name = new SqlIdentifierNode(item4) }); }
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 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 ISqlNode ParseJoin(ITokenizer t) { // <TableExpression> (<JoinOperator> <TableExpression> "ON" <JoinCondition>)? // TODO: <TableExpression> ("WITH" <Hint>)? var tableExpression1 = ParseMaybeAliasedTable(t, ParseTableOrSubexpression); var join = ParseJoinOperator(t); if (join == null) { return(tableExpression1); } var tableExpression2 = ParseMaybeAliasedTable(t, ParseTableOrSubexpression); ISqlNode condition = null; if (join.Operator != "NATURAL JOIN") { // "ON" <BooleanExpression> t.Expect(SqlTokenType.Keyword, "ON"); condition = ParseBooleanExpression(t); } return(new SqlJoinNode { Location = tableExpression1.Location, Left = tableExpression1, Operator = join, Right = tableExpression2, OnCondition = condition }); }
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 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 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 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); }
private SqlSetNode ParseSet(ITokenizer t) { // "SET" <variable> <assignOp> <Expression> var setToken = t.Expect(SqlTokenType.Keyword, "SET"); var v = t.Expect(SqlTokenType.Variable); var op = t.Expect(SqlTokenType.Symbol, "=", "+=", "-=", "*=", "/=", "%=", "&=", "^=", "|="); var expr = ParseScalarExpression(t); return(new SqlSetNode { Location = setToken.Location, Variable = new SqlVariableNode(v), Operator = new SqlOperatorNode(op), Right = expr }); }
private SqlListNode <SqlInfixOperationNode> ParseUpdateSetClause(ITokenizer t) { t.Expect(SqlTokenType.Keyword, "SET"); var setList = ParseList(t, ParseUpdateColumnAssignExpression); return(setList); }
public ISqlNode ParseExecute(ITokenizer t) { // ("EXEC"|"EXECUTE") ( <stringExpression> | <objectIdentifier> <ListOfArgument> ) // TODO: @return_status = ... // TODO: WITH <execute_option> var execToken = t.Expect(SqlTokenType.Keyword, "EXEC", "EXECUTE"); var execNode = new SqlExecuteNode() { Location = execToken.Location, }; if (t.Peek().IsType(SqlTokenType.Identifier)) { execNode.Name = ParseObjectIdentifier(t); execNode.Arguments = ParseList(t, ParseExecArgument); return(execNode); } bool isParenthesis = t.Peek().IsSymbol("("); var stringExpression = ParseScalarTerm(t); if (isParenthesis) { stringExpression = new SqlParenthesisNode <ISqlNode>(stringExpression); } execNode.Name = stringExpression; return(execNode); }
private ISqlNode ParseInsertStatement(ITokenizer t) { // "INSERT" "INTO" <ObjectIdOrVariable> "(" <ColumnList> ")" <ValuesOrSelect> var insertToken = t.Expect(SqlTokenType.Keyword, "INSERT"); t.Expect(SqlTokenType.Keyword, "INTO"); var insertNode = new SqlInsertNode { Location = insertToken.Location, Table = ParseObjectIdentifier(t), Columns = ParseInsertColumnList(t) }; // TODO: OUTPUT Clause var next = t.Peek(); if (next.IsKeyword("VALUES")) { insertNode.Source = ParseValues(t); } else if (next.IsKeyword("SELECT")) { insertNode.Source = ParseQueryExpression(t); } else if (next.IsKeyword("EXEC", "EXECUTE")) { insertNode.Source = ParseExecute(t); } else if (next.IsKeyword("DEFAULT")) { t.GetNext(); t.Expect(SqlTokenType.Keyword, "VALUES"); insertNode.Source = new SqlKeywordNode("DEFAULT VALUES"); } else { throw new ParsingException("INSERT INTO statement does not have a source"); } insertNode.OnConflict = ParseInsertOnConflictClause(t); // TODO: RETURNING clause return(insertNode); }
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 SqlMergeNode ParseMergeStatement(ITokenizer t) { var mergeToken = t.Expect(SqlTokenType.Keyword, "MERGE"); var mergeNode = new SqlMergeNode { Location = mergeToken.Location }; // TODO: "TOP" <maybeParenVariableOrNumericExpression> "PERCENT"? t.NextIs(SqlTokenType.Keyword, "INTO", true); mergeNode.Target = ParseMaybeAliasedTable(t, ParseObjectIdentifier); t.Expect(SqlTokenType.Keyword, "USING"); mergeNode.Source = ParseMaybeAliasedTable(t, ParseObjectIdentifier); t.Expect(SqlTokenType.Keyword, "ON"); mergeNode.MergeCondition = ParseBooleanExpression(t); while (true) { var whenClauseToken = t.MaybeGetKeywordSequence("WHEN", "NOT", "MATCHED", "BY", "SOURCE", "TARGET"); if (whenClauseToken == null) { break; } // TODO: "AND" <clauseSearchCondition> t.Expect(SqlTokenType.Keyword, "THEN"); if (whenClauseToken.Value == "WHEN MATCHED") { // TODO: Allow multiple mergeNode.Matched = ParseMergeMatched(t); } else if (whenClauseToken.Value == "WHEN NOT MATCHED" || whenClauseToken.Value == "WHEN NOT MATCHED BY TARGET") { mergeNode.NotMatchedByTarget = ParseMergeNotMatched(t); } else if (whenClauseToken.Value == "WHEN NOT MATCHED BY SOURCE") { // TODO: Allow multiple mergeNode.NotMatchedBySource = ParseMergeMatched(t); } } // TODO: Output clause // TODO: OPTION clause return(mergeNode); }
private ISqlNode ParseOverOrderBy(ITokenizer t) { // "ORDER" "BY" <OrderByTerm> ("," <OrderByTerm>)* if (!t.NextIs(SqlTokenType.Keyword, "ORDER", true)) { return(null); } t.Expect(SqlTokenType.Keyword, "BY"); return(ParseList(t, ParseOrderTerm)); }
private ISqlNode ParseOverPartitionBy(ITokenizer t) { // "PARTITION" "BY" <Expr> ("," <Expr>)* if (!t.NextIs(SqlTokenType.Keyword, "PARTITION", true)) { return(null); } t.Expect(SqlTokenType.Keyword, "BY"); return(ParseList(t, ParseScalarExpression)); }
private ISqlNode ParseValues(ITokenizer t) { // "VALUES" "(" <ValueList> ")" ("," "(" <ValueList> ")")* var valuesToken = t.Expect(SqlTokenType.Keyword, "VALUES"); return(new SqlValuesNode { Location = valuesToken.Location, Values = ParseList(t, a => ParseParenthesis(a, b => ParseList(b, ParseVariableOrConstant)).Expression) }); }
public ISqlNode ParseMergeMatched(ITokenizer t) { if (t.NextIs(SqlTokenType.Keyword, "UPDATE")) { var updateToken = t.Expect(SqlTokenType.Keyword, "UPDATE"); var setList = ParseUpdateSetClause(t); return(new SqlUpdateNode { Location = updateToken.Location, SetClause = setList }); } if (t.NextIs(SqlTokenType.Keyword, "DELETE")) { var deleteToken = t.Expect(SqlTokenType.Keyword, "DELETE"); return(new SqlKeywordNode(deleteToken)); } throw ParsingException.CouldNotParseRule(nameof(ParseMergeMatched), t.Peek()); }
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 ISqlNode ParseWithStatement(ITokenizer t) { // "WITH" <Cte> ("," <Cte>)* <WithChildStatement> var with = new SqlWithNode(); t.Expect(SqlTokenType.Keyword, "WITH"); with.Ctes = ParseList(t, ParseCte); var statement = ParseWithChildStatement(t); with.Statement = statement; return(with); }
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 SqlDeclareNode ParseDeclare(ITokenizer t) { // "DECLARE" <identifier> <DataType> (":=" <Expression>)? // TODO: "DECLARE" <identifier> <DataType> (":=" <Expression>)? ("," <identifier> <DataType> (":=" <Expression>)?)* var declare = t.Expect(SqlTokenType.Keyword, "DECLARE"); var v = t.Expect(SqlTokenType.Identifier); // TODO: Improve data type parsing var dataType = ParseDataType(t); var declareNode = new SqlDeclareNode { Location = declare.Location, DataType = dataType, Variable = new SqlIdentifierNode(v) }; if (t.NextIs(SqlTokenType.Symbol, ":=", true)) { declareNode.Initializer = ParseScalarExpression(t); } return(declareNode); }
private SqlParenthesisNode <TNode> ParseParenthesis <TNode>(ITokenizer t, Func <ITokenizer, TNode> parse) where TNode : class, ISqlNode { var openingParen = t.Expect(SqlTokenType.Symbol, "("); if (t.Peek().IsSymbol(")")) { t.GetNext(); return(new SqlParenthesisNode <TNode> { Location = openingParen.Location }); } var value = parse(t); t.Expect(SqlTokenType.Symbol, ")"); return(new SqlParenthesisNode <TNode> { Location = openingParen.Location, Expression = value }); }
private SqlWithCteNode ParseCte(ITokenizer t) { // <identifier> ("(" <columnList> ")")? "AS" "(" <QueryExpression> ")" var name = t.Expect(SqlTokenType.Identifier); var cteNode = new SqlWithCteNode { Location = name.Location, Name = new SqlIdentifierNode(name), Recursive = false }; var lookahead = t.Peek(); if (lookahead.IsSymbol("(")) { cteNode.ColumnNames = ParseParenthesis(t, x => ParseList(x, ParseIdentifier)).Expression; } t.Expect(SqlTokenType.Keyword, "AS"); cteNode.Select = ParseParenthesis(t, ParseQueryExpression).Expression; cteNode.DetectRecursion(); return(cteNode); }
private ISqlNode ParseSelectColumnExpression(ITokenizer t) { var expr = ParseScalarExpression(t); var lookahead = t.Peek(); if (lookahead.IsKeyword("OVER")) { // "OVER" "(" <OverPartitionBy>? <OverOrderBy>? <OverRows>? ")" var overToken = t.GetNext(); t.Expect(SqlTokenType.Symbol, "("); var overNode = new SqlOverNode { Location = overToken.Location, Expression = expr, PartitionBy = ParseOverPartitionBy(t), OrderBy = ParseOverOrderBy(t), RowsRange = ParseOverRows(t) }; t.Expect(SqlTokenType.Symbol, ")"); return(overNode); } return(expr); }
private SqlWithCteNode ParseCte(ITokenizer t) { // "RECURSIVE"? <identifier> ("(" <columnList> ")")? "AS" "(" <QueryExpression> ")" bool isRecursive = t.NextIs(SqlTokenType.Keyword, "RECURSIVE", true); var name = t.Expect(SqlTokenType.Identifier); var cteNode = new SqlWithCteNode { Location = name.Location, Name = new SqlIdentifierNode(name), Recursive = isRecursive }; var lookahead = t.Peek(); if (lookahead.IsSymbol("(")) { cteNode.ColumnNames = ParseParenthesis(t, x => ParseList(x, ParseIdentifier)).Expression; } t.Expect(SqlTokenType.Keyword, "AS"); // TODO: The CTE can contain INSERT, UPDATE and DELETE statements as well (usually with the RETURNING clause) cteNode.Select = ParseParenthesis(t, ParseQueryExpression).Expression; return(cteNode); }
private ISqlNode ParseBooleanExpression3(ITokenizer t) { // "(" <BooleanExpression> ") // <BooleanExpression2> var lookahead = t.Peek(); if (lookahead.IsSymbol("(")) { t.GetNext(); var value = ParseBooleanExpression(t); t.Expect(SqlTokenType.Symbol, ")"); return(value); } return(ParseBooleanExpression2(t)); }