Ejemplo n.º 1
0
        public Result <SelectStatement, SqlStatementError> ParseSelect(SqlStatement statement)
        {
            var selectStatement = new SelectStatement();

            var errors = new List <SqlStatementError>();

            var rules = Configuration.SelectStatementConfiguration.Rules();

            var args  = new Dictionary <string, string>();
            var words = ParserUtils.GetWords(statement.Sql).ToList();

            if (words.First() != "select")
            {
                errors.Add(new SqlStatementError("No 'Select' statement found.", 0));
            }
            else
            {
                var currentIndex = 0;

                while (true)
                {
                    var word = words[currentIndex];

                    var rule = rules.SingleOrDefault(x => x.Name == word);

                    if (rule == null)
                    {
                        break;
                    }

                    if (rule.NextTokens.Any())
                    {
                        int?nextTokenIndex = null;

                        foreach (var nextToken in rule.NextTokens)
                        {
                            nextTokenIndex = FindInArray(words, currentIndex, nextToken);

                            if (nextTokenIndex.HasValue)
                            {
                                break;
                            }
                        }

                        if (rule.RequiresNextToken && nextTokenIndex.HasValue == false)
                        {
                            errors.Add(new SqlStatementError($"Incomplete statement after {word}", 0));
                            break;
                        }

                        if (rule.Args)
                        {
                            var count = nextTokenIndex.HasValue
                                ? nextTokenIndex.Value - currentIndex - 1
                                : words.Count - currentIndex - 1;

                            var tokenArgs = string.Join(" ", words.GetRange(currentIndex + 1, count));

                            if (string.IsNullOrWhiteSpace(tokenArgs))
                            {
                                errors.Add(new SqlStatementError($"Expected arguments after {word}", 0));
                                break;
                            }

                            args.Add(word, tokenArgs);
                        }

                        currentIndex = nextTokenIndex ?? words.Count - 1;
                    }
                    else
                    {
                        if (rule.Args)
                        {
                            var tokenArgs = string.Join(" ", words.GetRange(currentIndex + 1, words.Count - currentIndex - 1));

                            if (string.IsNullOrWhiteSpace(tokenArgs))
                            {
                                errors.Add(new SqlStatementError($"Expected arguments after {word}", 0));
                                break;
                            }

                            args.Add(word, tokenArgs);

                            break;
                        }
                    }
                }
            }

            foreach (var token in args.Keys)
            {
                var tokenPath = "select." + token;

                var parsers = Configuration.SelectStatementConfiguration.Parsers().Where(x => string.Equals(x.TokenPath, tokenPath));

                foreach (var parser in parsers)
                {
                    var parseArgs = new ParseArgs <SelectStatement>()
                    {
                        Statement        = selectStatement,
                        StatementArgs    = args[token],
                        StatementsParser = this
                    };

                    var parseResults = tokenPath == "select.select"
                        ? new SelectStatementTokenSelectParser().Parse(parseArgs)
                        : parser.Parse(parseArgs);

                    if (parseResults.Errors.Any())
                    {
                        errors.AddRange(parseResults.Errors);
                    }
                }
            }

            var result = new Result <SelectStatement, SqlStatementError>(selectStatement)
            {
                Errors = errors
            };

            return(result);
        }
Ejemplo n.º 2
0
        public TokenParserResults Parse(ParseArgs <SelectStatement> parseArgs)
        {
            var selectStatement = parseArgs.Statement;
            var args            = parseArgs.StatementArgs;

            var results = new TokenParserResults();

            var words = ParserUtils.GetWords(args).ToList();

            var segments = ParserUtils.SplitTokens(words);

            foreach (var wordList in segments)
            {
                if (wordList.Any() == false)
                {
                    results.Errors.Add(new SqlStatementError("No order clause specified", 0));

                    return(results);
                }

                SelectOrderBase orderColumn = null;

                var startWord = wordList[0];

                var number = 0;

                if (int.TryParse(startWord, out number))
                {
                    if (wordList.Count > 2)
                    {
                        results.Errors.Add(new SqlStatementError("Unknown tokens", 0));

                        return(results);
                    }
                    else if (wordList.Count == 2)
                    {
                        if (wordList[1] != "asc" && wordList[1] != "desc")
                        {
                            results.Errors.Add(new SqlStatementError("Expecting 'Asc' or 'Desc' keyword", 0));

                            return(results);
                        }

                        var sortDirection = wordList[1] == "asc" ? OrderDirection.Asc : OrderDirection.Desc;

                        orderColumn = new SelectOrderPosition(number, sortDirection);
                    }
                    else if (wordList.Count == 1)
                    {
                        orderColumn = new SelectOrderPosition(number);
                    }
                }
                else if (startWord.StartsWith("'") && startWord.EndsWith("'"))
                {
                    results.Errors.Add(new SqlStatementError("A constant expression was encountered in the ORDER BY list", 0));

                    return(results);
                }
                else if (char.IsLetter(startWord[0]))
                {
                    if (wordList.Count > 2)
                    {
                        results.Errors.Add(new SqlStatementError("Unknown tokens", 0));

                        return(results);
                    }
                    else if (wordList.Count == 2)
                    {
                        if (wordList[1] != "asc" && wordList[1] != "desc")
                        {
                            results.Errors.Add(new SqlStatementError("Expecting 'Asc' or 'Desc' keyword", 0));

                            return(results);
                        }

                        var sortDirection = wordList[1] == "asc" ? OrderDirection.Asc : OrderDirection.Desc;

                        orderColumn = new SelectOrderColumn(startWord, sortDirection);
                    }
                    else if (wordList.Count == 1)
                    {
                        orderColumn = new SelectOrderColumn(startWord);
                    }
                }

                if (orderColumn == null)
                {
                    throw new NotSupportedException();
                }

                selectStatement.Order.Add(orderColumn);
            }

            return(results);
        }
Ejemplo n.º 3
0
        public TokenParserResults Parse(ParseArgs <SelectStatement> parseArgs)
        {
            var selectStatement = parseArgs.Statement;
            var args            = parseArgs.StatementArgs;

            var results = new TokenParserResults();

            var words = GetWords != null
                ? GetWords(args).ToList()
                : ParserUtils.GetWords(args).ToList();

            if (words.Any())
            {
                var currentGroup = new SelectWhereGroup();
                var groupStack   = new Stack <SelectWhereGroup>();
                var clauseWords  = new List <string>();

                for (int i = 0; i < words.Count; i++)
                {
                    var word = words[i];

                    if (word.In("(", ")", "and", "or"))
                    {
                        ParseClauseWords(clauseWords, currentGroup);
                    }

                    if (word == "(")
                    {
                        groupStack.Push(currentGroup);

                        var newGroup = new SelectWhereGroup();

                        currentGroup.Clauses.Add(newGroup);

                        currentGroup = newGroup;
                    }
                    else if (word == ")")
                    {
                        currentGroup = groupStack.Pop();
                    }
                    else if (word == "or")
                    {
                        var clauseOperator = new SelectWhereOperator(SelectWhereClauseOperatorEnum.Or);

                        currentGroup.Clauses.Add(clauseOperator);
                    }
                    else if (word == "and")
                    {
                        var clauseOperator = new SelectWhereOperator(SelectWhereClauseOperatorEnum.And);

                        currentGroup.Clauses.Add(clauseOperator);
                    }
                    else
                    {
                        clauseWords.Add(word);
                    }
                }

                ParseClauseWords(clauseWords, currentGroup);

                selectStatement.Where = currentGroup.Clauses;
            }

            return(results);
        }
Ejemplo n.º 4
0
        internal Result <List <SqlStatement>, SqlStatementError> SplitIntoStatements(string sql)
        {
            var statements = new List <SqlStatement>();
            var errors     = new List <SqlStatementError>();

            var inInlineComment    = false;
            var inMultilineComment = false;
            var inQuotes           = false;
            var parenthesesCount   = 0;
            var trimStart          = true;
            var sourceIndex        = -1;
            var index    = -1;
            var keywords = new List <string>()
            {
                "select", "as", "order", "by", "asc", "desc", "group", "by",
                "left", "right", "inner", "outer", "join", "on",
                "delete",
                "update", "set",
                "from",
                "where", "or", "and", "in", "between", "like"
            };

            var initStatementKeywords = new List <string>()
            {
                "select", "update", "delete"
            };

            var statement = new SqlStatement();

            Action newStatement = () =>
            {
                if (string.IsNullOrWhiteSpace(statement.Sql) == false)
                {
                    var sbFormatted = new StringBuilder();

                    foreach (var word in ParserUtils.GetWords(statement.Sql))
                    {
                        if (keywords.Any(keyword => string.Equals(keyword, word, StringComparison.OrdinalIgnoreCase)))
                        {
                            sbFormatted.Append(word.ToLowerInvariant());
                        }
                        else
                        {
                            sbFormatted.Append(word);
                        }
                        sbFormatted.Append(" ");
                    }

                    statement.Builder = sbFormatted;

                    statements.Add(statement);
                }

                statement = new SqlStatement();

                index     = -1;
                trimStart = true;
            };

            for (int i = 0; i < sql.Length; i++)
            {
                sourceIndex++;
                index++;

                var c = sql[i];

                if (trimStart)
                {
                    if (c == ' ')
                    {
                        index--;
                        continue;
                    }
                    trimStart = false;
                }

                if (inMultilineComment)
                {
                    if (c == '*')
                    {
                        var str = sql.Substring(i, 2);

                        if (str == "*/")
                        {
                            inMultilineComment = false;
                            i++;
                            sourceIndex++;
                            index--;
                        }

                        continue;
                    }
                }
                else
                {
                    if (inQuotes == false)
                    {
                        if (c == '\n')
                        {
                            inInlineComment = false;
                            statement.Builder.Append(' ');
                            continue;
                        }

                        if (inInlineComment)
                        {
                            continue;
                        }

                        if (c == '/')
                        {
                            var str = sql.Substring(i, 2);

                            if (str == "/*")
                            {
                                inMultilineComment = true;
                                continue;
                            }

                            if (str == "//")
                            {
                                inInlineComment = true;
                                continue;
                            }
                        }
                    }
                }

                if (inMultilineComment)
                {
                    index--;
                    continue;
                }

                if (c == '\'')
                {
                    if (i == 0 || sql[i - 1] != '\\') // ignore if escaped
                    {
                        inQuotes = !inQuotes;
                    }
                }

                if (c == '(')
                {
                    parenthesesCount++;
                }

                if (c == ')')
                {
                    parenthesesCount--;

                    statement.Builder.Append(c);

                    continue;
                }

                if (parenthesesCount > 0)
                {
                    statement.Builder.Append(c);

                    continue;
                }

                if (c == ';')
                {
                    newStatement();

                    continue;
                }

                if (c == ' ' && ((i > 0 && sql[i - 1] == ' ') || (statement.Sql[statement.Sql.Length - 1] == ' ')))
                {
                    index--;
                    continue;
                }

                if (c == '\t')
                {
                    index--;
                    continue;
                }

                // if we reached here, we are not in a comment or string

                if (inQuotes == false && char.IsLetter(c))
                {
                    foreach (var keyword in initStatementKeywords)
                    {
                        if (i + keyword.Length > sql.Length)
                        {
                            continue;
                        }

                        var word = sql.Substring(i, keyword.Length);

                        if (string.Equals(word, keyword))
                        {
                            newStatement();

                            continue;
                        }
                    }
                }

                statement.Builder.Append(c);

                if (index != sourceIndex)
                {
                    //statement.Indexes.Add(new SqlIndex(index, sourceIndex));
                }
            }

            if (statement != null && string.IsNullOrWhiteSpace(statement.Sql) == false)
            {
                newStatement();
            }

            var result = new Result <List <SqlStatement>, SqlStatementError>(statements)
            {
                Errors = errors
            };

            return(result);
        }
Ejemplo n.º 5
0
        private SelectColumnBase ParseColumn(List <string> wordList, List <SqlStatementError> errors)
        {
            var startWord      = wordList[0];
            var ascTokenIndex  = 0;
            var descTokenIndex = wordList.Count - 1;
            var nextToken      = wordList.Count > 1
                ? wordList[++ascTokenIndex]
                : null;

            if (nextToken == "(")
            {
                var functionName  = startWord;
                var functionLabel = "";

                if (wordList[descTokenIndex] == ")")
                {
                    functionLabel = startWord;
                    descTokenIndex--;
                }
                else
                {
                    functionLabel = wordList[descTokenIndex];

                    descTokenIndex--;

                    if (wordList[descTokenIndex].NotIn(")", "as"))
                    {
                        throw new Exception($"Unexpected token after function '{wordList[wordList.Count - 2]}'");
                    }

                    if (wordList[descTokenIndex] == "as")
                    {
                        descTokenIndex--;
                    }

                    if (wordList[descTokenIndex] == ")")
                    {
                        descTokenIndex--;
                    }
                }

                var functionColumn = new SelectColumnFunction(functionName, functionLabel);

                var argList = wordList.GetRange(2, descTokenIndex - 1);

                var functionArgs = ParserUtils.SplitTokens(argList);

                foreach (var functionArg in functionArgs)
                {
                    functionColumn.Args.Add(ParseColumn(functionArg, errors));
                }

                return(functionColumn);
            }

            double           number       = 0;
            SelectColumnBase selectColumn = null;

            if (startWord.IsQuoted() || (double.TryParse(startWord, out number)))
            {
                object value = startWord.IsQuoted()
                    ? startWord.CleanRaw()
                    : number.ToString();

                var valueType = startWord.IsQuoted()
                    ? typeof(string)
                    : typeof(double);

                if (startWord.IsQuoted() == false && startWord.IndexOf(".", StringComparison.Ordinal) < 0)
                {
                    valueType = typeof(int);
                    value     = int.Parse(startWord);
                }

                if (wordList.Count > 3)
                {
                    errors.Add(new SqlStatementError("Unknown tokens", 0));

                    return(null);
                }

                if (wordList.Count == 3)
                {
                    if (wordList[1] != "as")
                    {
                        errors.Add(new SqlStatementError("Expecting 'As' keyword", 0));

                        return(null);
                    }

                    selectColumn = new RawSelectColumn(wordList[2], value)
                    {
                        ValueType = valueType
                    };
                }
                else if (wordList.Count == 2)
                {
                    selectColumn = new RawSelectColumn(wordList[1], value)
                    {
                        ValueType = valueType
                    };
                }
                else
                {
                    selectColumn = new RawSelectColumn(null, value)
                    {
                        ValueType = valueType
                    };
                }

                return(selectColumn);
            }

            if (char.IsLetter(startWord[0]))
            {
                if (wordList.Count > 3)
                {
                    errors.Add(new SqlStatementError("Unknown tokens", 0));

                    return(null);
                }

                if (wordList.Count == 3)
                {
                    if (wordList[1] != "as")
                    {
                        errors.Add(new SqlStatementError("Expecting 'As' keyword", 0));

                        return(null);
                    }

                    selectColumn = new FieldSelectColumn(wordList[2], startWord);
                }
                else if (wordList.Count == 2)
                {
                    selectColumn = new FieldSelectColumn(wordList[1], startWord);
                }
                else
                {
                    selectColumn = new FieldSelectColumn(null, startWord);
                }

                return(selectColumn);
            }

            throw new Exception("Unexpected function arguments.");
        }
Ejemplo n.º 6
0
        public TokenParserResults Parse(ParseArgs <SelectStatement> parseArgs)
        {
            var selectStatement = parseArgs.Statement;
            var args            = parseArgs.StatementArgs;
            var statementParser = parseArgs.StatementsParser;

            var results = new TokenParserResults();

            var words = ParserUtils.GetWords(args).ToList();

            var index = 0;

            if (words.Any())
            {
                if (words[0] == "top")
                {
                    if (words.Count >= 2)
                    {
                        var value = 0;

                        if (int.TryParse(words[1], out value))
                        {
                            selectStatement.Top = value;
                            index = 2;
                        }
                        else
                        {
                            results.Errors.Add(new SqlStatementError("Top expects a numerical value", 0));
                        }
                    }
                    else
                    {
                        results.Errors.Add(new SqlStatementError("Top without a numerical value", 0));
                    }
                }

                if (results.Errors.Any())
                {
                    return(results);
                }

                var columns = ParserUtils.SplitTokens(words.GetRange(index, words.Count - index));

                foreach (var wordList in columns)
                {
                    if (wordList.Any() == false)
                    {
                        results.Errors.Add(new SqlStatementError("No column specified", 0));

                        return(results);
                    }

                    SelectColumnBase selectColumn = null;

                    var startWord = wordList[0];

                    double number = 0;

                    if (startWord.IsQuoted() || double.TryParse(startWord, out number))
                    {
                        object value = startWord.IsQuoted()
                            ? startWord.CleanRaw()
                            : number.ToString();

                        var valueType = startWord.IsQuoted()
                            ? typeof(string)
                            : typeof(double);

                        if (startWord.IsQuoted() == false && startWord.IndexOf(".", StringComparison.Ordinal) < 0)
                        {
                            valueType = typeof(int);
                            value     = int.Parse(startWord);
                        }

                        if (wordList.Count > 3)
                        {
                            results.Errors.Add(new SqlStatementError("Unknown tokens", 0));

                            return(results);
                        }

                        if (wordList.Count == 3)
                        {
                            if (wordList[1] != "as")
                            {
                                results.Errors.Add(new SqlStatementError("Expecting 'As' keyword", 0));

                                return(results);
                            }

                            selectColumn = new RawSelectColumn(wordList[2], value)
                            {
                                ValueType = valueType
                            };
                        }
                        else if (wordList.Count == 2)
                        {
                            selectColumn = new RawSelectColumn(wordList[1], value)
                            {
                                ValueType = valueType
                            };
                        }
                        else
                        {
                            selectColumn = new RawSelectColumn(null, value)
                            {
                                ValueType = valueType
                            };
                        }
                    }
                    else if (startWord.StartsWith("*"))
                    {
                        if (wordList.Count > 1)
                        {
                            results.Errors.Add(new SqlStatementError("Found unsupported tokens after '*'", 0));

                            return(results);
                        }

                        selectColumn = new AllSelectColumn();
                    }
                    else if (startWord.StartsWith("+"))
                    {
                        if (wordList.Count > 1)
                        {
                            results.Errors.Add(new SqlStatementError("Found unsupported tokens after '+'", 0));

                            return(results);
                        }

                        selectColumn = new SystemSelectColumn();
                    }
                    else if (char.IsLetter(startWord[0]))
                    {
                        selectColumn = ParseColumn(wordList, results.Errors);
                    }
                    else if (startWord == "(")
                    {
                        var nextWord = wordList[1];

                        if (nextWord == "select")
                        {
                            var startIndex = 1;
                            var endIndex   = wordList.FindLastIndex(x => x == ")");
                            var innerSql   = string.Join(" ", wordList.GetRange(startIndex, endIndex - startIndex));

                            var statement = statementParser.ParseSelect(new SqlStatement()
                            {
                                Builder = new StringBuilder(innerSql)
                            });

                            if (statement.Errors.Any())
                            {
                                throw new Exception($"Unable to parse inner select statement '{innerSql}'");
                            }

                            var descTokenIndex = wordList.Count - 1;

                            var label = wordList[descTokenIndex];

                            descTokenIndex--;

                            if (wordList[descTokenIndex].NotIn(")", "as"))
                            {
                                throw new Exception($"Unexpected token after inner select '{innerSql}'");
                            }

                            if (wordList[descTokenIndex] == "as")
                            {
                                descTokenIndex--;
                            }

                            if (wordList[descTokenIndex] != ")")
                            {
                                throw new Exception($"Unexpected token after inner select '{innerSql}'");
                            }

                            selectColumn = new InnerSelectColumn(label, statement.Value);
                        }
                    }

                    if (selectColumn == null)
                    {
                        throw new NotSupportedException();
                    }

                    selectStatement.Columns.Add(selectColumn);
                }
            }

            return(results);
        }