Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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
            });
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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
            });
        }
Beispiel #10
0
        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);
        }
Beispiel #12
0
        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));
        }
Beispiel #14
0
        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);
        }
Beispiel #17
0
 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);
        }
Beispiel #19
0
        private ISqlNode ParseSelectHavingClause(ITokenizer t)
        {
            // "HAVING" <BooleanExpression>
            if (!t.NextIs(SqlTokenType.Keyword, "HAVING"))
            {
                return(null);
            }

            t.GetNext();
            return(ParseBooleanExpression(t));
        }
Beispiel #20
0
        private ISqlNode ParseWhereClause(ITokenizer t)
        {
            // "WHERE" <BooleanExpression>
            if (!t.NextIs(SqlTokenType.Keyword, "WHERE"))
            {
                return(null);
            }

            t.GetNext();
            return(ParseBooleanExpression(t));
        }
Beispiel #21
0
        private SqlNumberNode ParseNumber(ITokenizer t)
        {
            var next = t.GetNext();

            if (next.IsType(SqlTokenType.Number))
            {
                return(new SqlNumberNode(next));
            }

            t.PutBack(next);
            return(null);
        }
Beispiel #22
0
        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));
        }
Beispiel #23
0
        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));
        }
Beispiel #24
0
        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);
        }
Beispiel #26
0
        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);
        }
Beispiel #27
0
        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);
        }
Beispiel #28
0
        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;
         }
     }
 }