Ejemplo n.º 1
0
        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));
        }
Ejemplo n.º 2
0
        public static SqlToken Peek(this ITokenizer ITokenizer)
        {
            var t = ITokenizer.GetNext();

            ITokenizer.PutBack(t);
            return(t);
        }
Ejemplo n.º 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));
        }
Ejemplo n.º 4
0
        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
            });
        }
Ejemplo n.º 6
0
        private SqlNumberNode ParseNumber(ITokenizer t)
        {
            var next = t.GetNext();

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

            t.PutBack(next);
            return(null);
        }
Ejemplo n.º 7
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));
        }
Ejemplo n.º 8
0
 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;
         }
     }
 }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 12
0
        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)
            });
        }
Ejemplo n.º 13
0
        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);
        }
Ejemplo n.º 14
0
        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);
        }