diff --git a/dbms/include/DB/Columns/Columns.h b/dbms/include/DB/Columns/Columns.h new file mode 100644 index 00000000000..bb4e9ca6661 --- /dev/null +++ b/dbms/include/DB/Columns/Columns.h @@ -0,0 +1,18 @@ +#ifndef DBMS_COLUMNS_COLUMNS_H +#define DBMS_COLUMNS_COLUMNS_H + +#include +#include +#include + + +namespace DB +{ + +using Poco::SharedPtr; + +typedef std::vector > Columns; + +} + +#endif diff --git a/dbms/include/DB/Columns/IColumn.h b/dbms/include/DB/Columns/IColumn.h index bddb3ea4404..0954abdeee5 100644 --- a/dbms/include/DB/Columns/IColumn.h +++ b/dbms/include/DB/Columns/IColumn.h @@ -1,5 +1,5 @@ -#ifndef DBMS_CORE_ICOLUMN_H -#define DBMS_CORE_ICOLUMN_H +#ifndef DBMS_COLUMNS_ICOLUMN_H +#define DBMS_COLUMNS_ICOLUMN_H #include diff --git a/dbms/include/DB/Core/ColumnNumbers.h b/dbms/include/DB/Core/ColumnNumbers.h new file mode 100644 index 00000000000..710770817dd --- /dev/null +++ b/dbms/include/DB/Core/ColumnNumbers.h @@ -0,0 +1,15 @@ +#ifndef DBMS_CORE_COLUMN_NUMBERS_H +#define DBMS_CORE_COLUMN_NUMBERS_H + +#include +#include + + +namespace DB +{ + +typedef std::vector ColumnNumbers; + +} + +#endif diff --git a/dbms/include/DB/Core/ErrorCodes.h b/dbms/include/DB/Core/ErrorCodes.h index 0727694301c..cc2c214401f 100644 --- a/dbms/include/DB/Core/ErrorCodes.h +++ b/dbms/include/DB/Core/ErrorCodes.h @@ -42,6 +42,8 @@ namespace ErrorCodes CANNOT_READ_COMPRESSED_CHUNK, ATTEMPT_TO_READ_AFTER_EOF, CANNOT_READ_ALL_DATA, + TOO_MUCH_ARGUMENTS_FOR_FUNCTION, + TOO_LESS_ARGUMENTS_FOR_FUNCTION, }; } diff --git a/dbms/include/DB/Parsers/ASTExpressionList.h b/dbms/include/DB/Parsers/ASTExpressionList.h new file mode 100644 index 00000000000..7531d38a12e --- /dev/null +++ b/dbms/include/DB/Parsers/ASTExpressionList.h @@ -0,0 +1,29 @@ +#ifndef DBMS_PARSERS_ASTEXPRESSIONLIST_H +#define DBMS_PARSERS_ASTEXPRESSIONLIST_H + +#include + + +namespace DB +{ + +using Poco::SharedPtr; + + +/** Список выражений типа "a, b + c, f(d)" + */ +class ASTExpressionList : public IAST +{ +public: + StringRange range; + ASTs children; + + ASTExpressionList(StringRange range_) : range(range_) {} + + /** Получить кусок текста, откуда был получен этот элемент. */ + StringRange getRange() { return range; } +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/ASTFunction.h b/dbms/include/DB/Parsers/ASTFunction.h new file mode 100644 index 00000000000..773aaaa995f --- /dev/null +++ b/dbms/include/DB/Parsers/ASTFunction.h @@ -0,0 +1,29 @@ +#ifndef DBMS_PARSERS_ASTFUNCTION_H +#define DBMS_PARSERS_ASTFUNCTION_H + +#include + + +namespace DB +{ + +/** Применение функции или оператора + */ +class ASTFunction : public IAST +{ +public: + StringRange range; + /// имя функции + String name; + /// параметры + ASTPtr arguments; + + ASTFunction(StringRange range_) : range(range_) {} + + /** Получить кусок текста, откуда был получен этот элемент. */ + StringRange getRange() { return range; } +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/ASTIdentifier.h b/dbms/include/DB/Parsers/ASTIdentifier.h new file mode 100644 index 00000000000..78a3671391d --- /dev/null +++ b/dbms/include/DB/Parsers/ASTIdentifier.h @@ -0,0 +1,27 @@ +#ifndef DBMS_PARSERS_ASTIDENTIFIER_H +#define DBMS_PARSERS_ASTIDENTIFIER_H + +#include + + +namespace DB +{ + +/** Идентификатор (столбца или алиас, или именованый элемент кортежа) + */ +class ASTIdentifier : public IAST +{ +public: + StringRange range; + /// имя + String name; + + ASTIdentifier(StringRange range_, const String & name_) : range(range_), name(name_) {} + + /** Получить кусок текста, откуда был получен этот элемент. */ + StringRange getRange() { return range; } +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/ASTLiteral.h b/dbms/include/DB/Parsers/ASTLiteral.h new file mode 100644 index 00000000000..3c57560cd55 --- /dev/null +++ b/dbms/include/DB/Parsers/ASTLiteral.h @@ -0,0 +1,28 @@ +#ifndef DBMS_PARSERS_ASTLITERAL_H +#define DBMS_PARSERS_ASTLITERAL_H + +#include +#include + + +namespace DB +{ + +/** Литерал (атомарный) - число, строка, NULL + */ +class ASTLiteral : public IAST +{ +public: + StringRange range; + /// значение + Field value; + + ASTLiteral(StringRange range_, const Field & value_) : range(range_), value(value_) {} + + /** Получить кусок текста, откуда был получен этот элемент. */ + StringRange getRange() { return range; } +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/ASTSelectQuery.h b/dbms/include/DB/Parsers/ASTSelectQuery.h new file mode 100644 index 00000000000..b8b263d19d5 --- /dev/null +++ b/dbms/include/DB/Parsers/ASTSelectQuery.h @@ -0,0 +1,27 @@ +#ifndef DBMS_PARSERS_ASTSELECTQUERY_H +#define DBMS_PARSERS_ASTSELECTQUERY_H + +#include + + +namespace DB +{ + + +/** SELECT запрос + */ +class ASTSelectQuery : public IAST +{ +public: + StringRange range; + ASTPtr select, from, where, group, having, order, limit; + + ASTSelectQuery(StringRange range_) : range(range_) {} + + /** Получить кусок текста, откуда был получен этот элемент. */ + StringRange getRange() { return range; } +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/CommonParsers.h b/dbms/include/DB/Parsers/CommonParsers.h new file mode 100644 index 00000000000..98f6c777168 --- /dev/null +++ b/dbms/include/DB/Parsers/CommonParsers.h @@ -0,0 +1,169 @@ +#ifndef DBMS_PARSERS_COMMONPARSERS_H +#define DBMS_PARSERS_COMMONPARSERS_H + +#include + +#include + + +namespace DB +{ + +using Poco::SharedPtr; + + +/** если прямо сейчас не s, то ошибка + */ +class ParserString : public IParserBase +{ +private: + const String & s; +public: + ParserString(const String & s_) : s(s_) {} +protected: + String getName() { return s; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + if (static_cast(s.size()) < end - pos || std::strncmp(pos, s.data(), s.size())) + return false; + else + { + pos += s.size(); + return true; + } + } +}; + + +/** если сейчас словарный символ - то ошибка + * понимается только латиница + */ +class ParserNotWordCharOrEnd : public IParserBase +{ +protected: + String getName() { return "non-word character"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + if (pos == end) + return true; + + if ((*pos >= 'a' && *pos <= 'z') || (*pos >= 'A' && *pos <= 'Z') || (*pos >= '0' && *pos <= '9') || *pos == '_') + return false; + + ++pos; + return true; + } +}; + + +/** пробельные символы + */ +class ParserWhiteSpace : public IParserBase +{ +protected: + String getName() { return "white space"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + Pos begin = pos; + while (*pos == ' ' || *pos == '\t' || *pos == '\n' || *pos == '\r' || *pos == '\f') + ++pos; + + return pos != begin; + } +}; + + +class ParserCStyleComment : public IParserBase +{ +protected: + String getName() { return "C-style comment"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + if (end - pos >= 4 && pos[0] == '/' && pos[1] == '*') + { + pos += 2; + while (end - pos >= 2 && pos[0] != '*' && pos[1] != '/') + ++pos; + + if (end - pos < 2) + { + expected = "closing of C-style comment '*/'"; + return false; + } + else + { + pos += 2; + return true; + } + } + else + return false; + } +}; + + +class ParserSQLStyleComment : public IParserBase +{ +protected: + String getName() { return "SQL-style comment"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + if (end - pos >= 2 && pos[0] == '-' && pos[1] == '-') + { + pos += 2; + while (pos != end && *pos != '\n') + ++pos; + + if (pos != end) + ++pos; + return true; + } + else + return false; + } +}; + + +/** комментарии '--' или c-style + */ +class ParserComment : public IParserBase +{ +protected: + String getName() { return "comment"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + ParserCStyleComment p1; + ParserSQLStyleComment p2; + + return p1.ignore(pos, end, expected) + || p2.ignore(pos, end, expected); + } +}; + + +class ParserWhiteSpaceOrComments : public IParserBase +{ +protected: + String getName() { return "white space or comments"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + ParserWhiteSpace p1; + ParserComment p2; + + bool res = false; + while (p1.ignore(pos, end, expected) || p2.ignore(pos, end, expected)) + res = true; + return res; + } +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/ExpressionElementParsers.h b/dbms/include/DB/Parsers/ExpressionElementParsers.h new file mode 100644 index 00000000000..1f847a5ef83 --- /dev/null +++ b/dbms/include/DB/Parsers/ExpressionElementParsers.h @@ -0,0 +1,124 @@ +#ifndef DBMS_PARSERS_EXPRESSIONELEMENTPARSERS_H +#define DBMS_PARSERS_EXPRESSIONELEMENTPARSERS_H + +#include + + +namespace DB +{ + + +class ParserArray : public IParserBase +{ +protected: + String getName() { return "array"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Если в скобках выражение из одного элемента - возвращает в node этот элемент; + * иначе возвращает функцию tuple от содержимого скобок. + */ +class ParserParenthesisExpression : public IParserBase +{ +protected: + String getName() { return "expression in parenthesis"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Идентификатор, например, x_yz123 + */ +class ParserIdentifier : public IParserBase +{ +protected: + String getName() { return "identifier"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Функция, например, f(x, y, z) + */ +class ParserFunction : public IParserBase +{ +protected: + String getName() { return "function"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** NULL. + */ +class ParserNull : public IParserBase +{ +protected: + String getName() { return "NULL"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Число. + */ +class ParserNumber : public IParserBase +{ +protected: + String getName() { return "number"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Строка в одинарных кавычках. + */ +class ParserStringLiteral : public IParserBase +{ +private: + inline char parseEscapeSequence(char c) + { + switch(c) + { + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case '0': + return '\0'; + default: + return c; + } + } + +protected: + String getName() { return "string literal"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Литерал - одно из: NULL, UInt64, Int64, Float64, String. + */ +class ParserLiteral : public IParserBase +{ +protected: + String getName() { return "literal"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Элемент выражения - одно из: выражение в круглых скобках, массив, литерал, функция, идентификатор. + */ +class ParserExpressionElement : public IParserBase +{ +protected: + String getName() { return "element of expression"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +} + +#endif diff --git a/dbms/include/DB/Parsers/ExpressionGrammar.h b/dbms/include/DB/Parsers/ExpressionGrammar.h deleted file mode 100644 index 418e26e0acc..00000000000 --- a/dbms/include/DB/Parsers/ExpressionGrammar.h +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef DBMS_PARSERS_EXPRESSION_H -#define DBMS_PARSERS_EXPRESSION_H - -#include -#include -#include -#include - -#include - -#include - - -namespace DB -{ - -/** Expression - это выражение, которое может стоять в запросе между SELECT и FROM - * Здесь представлен парсер этого выражения (пока без операторов). - * PS. Код довольно сложный :( - */ - -/** Типы данных, которые образуются автоматически в результате парсинга. - * Они должны быть в отдельном или глобальном namespace из-за BOOST_FUSION_ADAPT_STRUCT. - * - * spirit может собирать типы данных - результаты парсинга (атрибуты) автоматически, - * или можно использовать свои типы и заполнять их вручную с помощью семантических действий. - * Здесь используется вариант - автоматически. - * (но стоит на будущее иметь ввиду, что его очень сложно заставить скомпилироваться) - */ -namespace ExpressionGrammarTypes -{ - /// с тем, какой конкретно тип у числа, будем разбираться потом - typedef Float64 NumberConstant; /// 1, -1, 0.1 - typedef String StringConstant; /// 'abc', 'ab\'c', 'abc\\' - typedef Null NullConstant; /// NULL, null, NuLl - - typedef boost::variant< - NumberConstant, - StringConstant, - NullConstant> Constant; - - typedef String Name; /// x, sum, width - - struct Function; /// forward declaration для рекурсии - typedef boost::variant< - boost::recursive_wrapper, - Constant, - Name> Node; /// элемент выражения - - typedef std::vector Expression; /// выражение - набор элементов через запятую - - struct Function /// f(x), sum(a, 10), concat('a', 'bc') - { - Name name; /// sum - Expression args; /// a, 10 - }; -} - -} - - -/** Необходимо, чтобы struct Function был совместим с boost::fusion::vector (он же boost::tuple), - * который образуется автоматически при парсинге. - * Должно быть в глобальном namespace. - */ -BOOST_FUSION_ADAPT_STRUCT( - DB::ExpressionGrammarTypes::Function, - (DB::ExpressionGrammarTypes::Name, name) - (DB::ExpressionGrammarTypes::Expression, args) -) - - -namespace DB -{ - -namespace qi = boost::spirit::qi; -namespace ascii = boost::spirit::ascii; - - -/** Грамматика */ -template -struct ExpressionGrammar : qi::grammar -{ - ExpressionGrammar() : ExpressionGrammar::base_type(expression) - { - using qi::lexeme; - using qi::raw; - using qi::alpha; - using qi::alnum; - using qi::double_; - using qi::eps; - using qi::no_case; - using qi::char_; - using qi::_val; - using qi::_1; - - expression %= node % ','; - node %= function | constant | name; - name %= raw[lexeme[alpha >> -*(alnum | '_')]]; - constant %= number | string | null; - function %= name >> '(' >> expression >> ')'; - number %= double_; - null = eps[_val = boost::none] >> no_case["NULL"]; - string %= raw[lexeme['\'' >> *((char_ - (char_('\\') | '\'')) | (char_('\'') >> char_)) >> '\'']]; - } - - qi::rule expression; - qi::rule node; - qi::rule constant; - qi::rule name; - qi::rule function; - qi::rule number; - qi::rule string; - qi::rule null; -}; - -} - -#endif diff --git a/dbms/include/DB/Parsers/ExpressionListParsers.h b/dbms/include/DB/Parsers/ExpressionListParsers.h new file mode 100644 index 00000000000..93cd2bc39cc --- /dev/null +++ b/dbms/include/DB/Parsers/ExpressionListParsers.h @@ -0,0 +1,280 @@ +#ifndef DBMS_PARSERS_EXPRESSIONLISTPARSERS_H +#define DBMS_PARSERS_EXPRESSIONLISTPARSERS_H + +#include + +#include + +#include +#include + + +namespace DB +{ + +/** Оператор и соответствующая ему функция. Например, "+" -> "plus" */ +typedef std::map Operators_t; + + +/** Выражение с инфиксным бинарным лево-ассоциативным оператором. + * Например, a + b - c + d. + * NOTE: если оператор словесный (например, OR), то после него не требуется границы слова. + * то есть, можно написать a = b ORx = y. + */ +class ParserLeftAssociativeBinaryOperatorList : public IParserBase +{ +private: + const Operators_t & operators; + ParserPtr elem_parser; + +public: + /** operators_ - допустимые операторы и соответствующие им функции + */ + ParserLeftAssociativeBinaryOperatorList(const Operators_t & operators_, ParserPtr elem_parser_) + : operators(operators_), elem_parser(elem_parser_) + { + } + +protected: + String getName() { return "list, delimited by binary operators"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +/** Выражение с префиксным унарным оператором. + * Например, NOT x. + * NOTE: если оператор словесный (например, NOT), то после него не требуется границы слова. + * то есть, можно написать NOTx. + */ +class ParserPrefixUnaryOperatorExpression : public IParserBase +{ +private: + const Operators_t & operators; + ParserPtr elem_parser; + +public: + /** operators_ - допустимые операторы и соответствующие им функции + */ + ParserPrefixUnaryOperatorExpression(const Operators_t & operators_, ParserPtr elem_parser_) + : operators(operators_), elem_parser(elem_parser_) + { + } + +protected: + String getName() { return "expression with prefix unary operator"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +class ParserAccessExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserLeftAssociativeBinaryOperatorList operator_parser; +public: + ParserAccessExpression(); + +protected: + String getName() { return "acess expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +class ParserUnaryMinusExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserPrefixUnaryOperatorExpression operator_parser; +public: + ParserUnaryMinusExpression() + : elem_parser(new ParserAccessExpression), + operator_parser(boost::assign::map_list_of("-", "negate"), elem_parser) + { + } + +protected: + String getName() { return "unary minus expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +class ParserMultiplicativeExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserLeftAssociativeBinaryOperatorList operator_parser; +public: + ParserMultiplicativeExpression() + : elem_parser(new ParserUnaryMinusExpression), + operator_parser(boost::assign::map_list_of + ("*", "multiply") + ("/", "divide") + ("%", "modulo"), + elem_parser) + { + } + +protected: + String getName() { return "multiplicative expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +class ParserAdditiveExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserLeftAssociativeBinaryOperatorList operator_parser; +public: + ParserAdditiveExpression() + : elem_parser(new ParserMultiplicativeExpression), + operator_parser(boost::assign::map_list_of + ("+", "plus") + ("-", "minus"), + elem_parser) + { + } + +protected: + String getName() { return "additive expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +class ParserComparisonExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserLeftAssociativeBinaryOperatorList operator_parser; +public: + ParserComparisonExpression() + : elem_parser(new ParserAdditiveExpression), + operator_parser(boost::assign::map_list_of + ("==", "equals") + ("!=", "notEquals") + ("<>", "notEquals") + ("<=", "lessOrEquals") + (">=", "greaterOrEquals") + ("<", "less") + (">", "greater") + ("=", "equals"), + elem_parser) + { + } + +protected: + String getName() { return "comparison expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +class ParserLogicalNotExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserPrefixUnaryOperatorExpression operator_parser; +public: + ParserLogicalNotExpression() + : elem_parser(new ParserComparisonExpression), + operator_parser(boost::assign::map_list_of("NOT", "not"), elem_parser) + { + } + +protected: + String getName() { return "logical-NOT expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +class ParserLogicalAndExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserLeftAssociativeBinaryOperatorList operator_parser; +public: + ParserLogicalAndExpression() + : elem_parser(new ParserLogicalNotExpression), + operator_parser(boost::assign::map_list_of("AND", "and"), elem_parser) + { + } + +protected: + String getName() { return "logical-AND expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +class ParserLogicalOrExpression : public IParserBase +{ +private: + ParserPtr elem_parser; + ParserLeftAssociativeBinaryOperatorList operator_parser; +public: + ParserLogicalOrExpression() + : elem_parser(new ParserLogicalAndExpression), + operator_parser(boost::assign::map_list_of("OR", "or"), elem_parser) + { + } + +protected: + String getName() { return "logical-OR expression"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + return operator_parser.parse(pos, end, node, expected); + } +}; + + +/** Список выражений, разделённых запятыми, возможно пустой. */ +class ParserExpressionList : public IParserBase +{ +protected: + String getName() { return "list of expressions"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +class ParserNotEmptyExpressionList : public IParserBase +{ +private: + ParserExpressionList nested_parser; +protected: + String getName() { return "not empty list of expressions"; } + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected); +}; + + +} + + +#endif diff --git a/dbms/include/DB/Parsers/IAST.h b/dbms/include/DB/Parsers/IAST.h new file mode 100644 index 00000000000..28593ae6d1d --- /dev/null +++ b/dbms/include/DB/Parsers/IAST.h @@ -0,0 +1,33 @@ +#ifndef DBMS_PARSERS_IAST_H +#define DBMS_PARSERS_IAST_H + +#include +#include + +#include +#include + + +namespace DB +{ + +using Poco::SharedPtr; + + +/** Элемент синтаксического дерева (в дальнейшем - направленного ациклического графа с элементами семантики) + */ +class IAST +{ +public: + /** Получить кусок текста, откуда был получен этот элемент. */ + virtual StringRange getRange() = 0; + virtual ~IAST() {} +}; + + +typedef Poco::SharedPtr ASTPtr; +typedef std::list ASTs; + +} + +#endif diff --git a/dbms/include/DB/Parsers/IParser.h b/dbms/include/DB/Parsers/IParser.h new file mode 100644 index 00000000000..b689824c9f0 --- /dev/null +++ b/dbms/include/DB/Parsers/IParser.h @@ -0,0 +1,71 @@ +#ifndef DBMS_PARSERS_IPARSER_H +#define DBMS_PARSERS_IPARSER_H + +#include +#include + +#include +#include + + +namespace DB +{ + +using Poco::SharedPtr; + + +/** Интерфейс для классов-парсеров + */ +class IParser +{ +public: + typedef const char * Pos; + + /** Получить текст о том, что парсит этот парсер. */ + virtual String getName() = 0; + + /** Распарсить кусок текста с позиции pos, но не дальше конца строки (end - позиция после конца строки), + * переместить указатель pos на максимальное место, до которого удалось распарсить, + * вернуть в случае успеха true и результат в node, если он нужен, иначе false, + * в expected записать, что ожидалось в максимальной позиции, + * до которой удалось распарсить, если парсинг был неуспешным, + * или что парсит этот парсер, если парсинг был успешным. + * Везде предполагается, что строка, в которую входит диапазон [begin, end) 0-terminated. + */ + virtual bool parse(Pos & pos, Pos end, ASTPtr & node, String & expected) = 0; + + bool ignore(Pos & pos, Pos end, String & expected) + { + ASTPtr ignore_node; + return parse(pos, end, ignore_node, expected); + } + + bool ignore(Pos & pos, Pos end) + { + String expected; + return ignore(pos, end, expected); + } + + /** То же самое, но не двигать позицию и не записывать результат в node. + */ + bool check(Pos & pos, Pos end, String & expected) + { + Pos begin = pos; + ASTPtr node; + if (!parse(pos, end, node, expected)) + { + pos = begin; + return false; + } + else + return true; + } + + virtual ~IParser() {} +}; + +typedef SharedPtr ParserPtr; + +} + +#endif diff --git a/dbms/include/DB/Parsers/IParserBase.h b/dbms/include/DB/Parsers/IParserBase.h new file mode 100644 index 00000000000..8edeeec0845 --- /dev/null +++ b/dbms/include/DB/Parsers/IParserBase.h @@ -0,0 +1,30 @@ +#ifndef DBMS_PARSERS_IPARSERBASE_H +#define DBMS_PARSERS_IPARSERBASE_H + +#include +#include + +#include +#include + + +namespace DB +{ + +/** Базовый класс для большинства парсеров + */ +class IParserBase : public IParser +{ +public: + bool parse(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + expected = getName(); + return parseImpl(pos, end, node, expected); + } +protected: + virtual bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) = 0; +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/ParserSelectQuery.h b/dbms/include/DB/Parsers/ParserSelectQuery.h new file mode 100644 index 00000000000..93b3e640ea7 --- /dev/null +++ b/dbms/include/DB/Parsers/ParserSelectQuery.h @@ -0,0 +1,51 @@ +#ifndef DBMS_PARSERS_PARSERSELECTQUERY_H +#define DBMS_PARSERS_PARSERSELECTQUERY_H + +#include +#include +#include +#include + + +namespace DB +{ + + +class ParserSelectQuery : public IParserBase +{ +protected: + String getName() { return "SELECT query"; } + + bool parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) + { + Pos begin = pos; + + ASTPtr select_expression_list; + + ParserWhiteSpaceOrComments ws; + ParserString s("SELECT"); + ParserNotWordCharOrEnd nw; + ParserNotEmptyExpressionList exp_list; + + ws.ignore(pos, end); + + if (!(s.ignore(pos, end, expected) + && nw.check(pos, end, expected))) + return false; + + ws.ignore(pos, end); + + if (!exp_list.parse(pos, end, select_expression_list, expected)) + return false; + + ASTSelectQuery * select_query = new ASTSelectQuery(StringRange(begin, pos)); + node = select_query; + select_query->select = select_expression_list; + + return true; + } +}; + +} + +#endif diff --git a/dbms/include/DB/Parsers/StringRange.h b/dbms/include/DB/Parsers/StringRange.h new file mode 100644 index 00000000000..93a0ef8fc40 --- /dev/null +++ b/dbms/include/DB/Parsers/StringRange.h @@ -0,0 +1,14 @@ +#ifndef DBMS_PARSERS_STRINGRANGE_H +#define DBMS_PARSERS_STRINGRANGE_H + +#include + + +namespace DB +{ + +typedef std::pair StringRange; + +} + +#endif diff --git a/dbms/src/Parsers/ExpressionElementParsers.cpp b/dbms/src/Parsers/ExpressionElementParsers.cpp new file mode 100644 index 00000000000..e06bee24d33 --- /dev/null +++ b/dbms/src/Parsers/ExpressionElementParsers.cpp @@ -0,0 +1,308 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + + +namespace DB +{ + + +bool ParserArray::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + ASTPtr contents_node; + ParserString open("["), close("]"); + ParserExpressionList contents; + ParserWhiteSpaceOrComments ws; + + if (!open.ignore(pos, end, expected)) + return false; + + ws.ignore(pos, end); + contents.parse(pos, end, contents_node, expected); + ws.ignore(pos, end); + + if (!close.ignore(pos, end, expected)) + return false; + + ASTFunction * function_node = new ASTFunction(StringRange(begin, pos)); + function_node->name = "array"; + function_node->arguments = contents_node; + node = function_node; + + return true; +} + + +bool ParserParenthesisExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + ASTPtr contents_node; + ParserString open("("), close(")"); + ParserExpressionList contents; + ParserWhiteSpaceOrComments ws; + + if (!open.ignore(pos, end, expected)) + return false; + + ws.ignore(pos, end); + contents.parse(pos, end, contents_node, expected); + ws.ignore(pos, end); + + if (!close.ignore(pos, end, expected)) + return false; + + ASTExpressionList & expr_list = dynamic_cast(*node); + + /// пустое выражение в скобках недопустимо + if (expr_list.children.empty()) + { + expected = "not empty list of expressions in parenthesis"; + return false; + } + + if (expr_list.children.size() == 1) + { + node = expr_list.children.front(); + } + else + { + ASTFunction * function_node = new ASTFunction(StringRange(begin, pos)); + function_node->name = "tuple"; + function_node->arguments = contents_node; + node = function_node; + } + + return true; +} + + +bool ParserIdentifier::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + + while (pos != end + && ((*pos >= 'a' && *pos <= 'z') + || (*pos >= 'A' && *pos <= 'Z') + || (*pos == '_') + || (pos != begin && *pos >= '0' && *pos <= '9'))) + ++pos; + + if (pos != begin) + { + node = new ASTIdentifier(StringRange(begin, pos), String(begin, pos - begin)); + return true; + } + else + return false; +} + + +bool ParserFunction::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + ASTPtr contents_node; + + ParserIdentifier id_parser; + ParserString open("("), close(")"); + ParserExpressionList contents; + ParserWhiteSpaceOrComments ws; + + ASTIdentifier * p_identifier = new ASTIdentifier(StringRange(begin, pos), ""); + ASTIdentifier & identifier = *p_identifier; + ASTPtr identifier_node = p_identifier; + + ASTPtr expr_list_node = new ASTExpressionList(StringRange(begin, pos)); + + if (!id_parser.parse(pos, end, identifier_node, expected)) + return false; + + ws.ignore(pos, end); + + if (!open.ignore(pos, end, expected)) + return false; + + ws.ignore(pos, end); + contents.parse(pos, end, expr_list_node, expected); + ws.ignore(pos, end); + + if (!close.ignore(pos, end, expected)) + return false; + + ASTFunction * function_node = new ASTFunction(StringRange(begin, pos)); + function_node->name = identifier.name; + function_node->arguments = expr_list_node; + node = function_node; + return true; +} + + +bool ParserNull::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + ParserString nested_parser("NULL"); + if (nested_parser.parse(pos, end, node, expected)) + { + node = new ASTLiteral(StringRange(StringRange(begin, pos)), Null()); + return true; + } + else + return false; +} + + +bool ParserNumber::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Field res; + + Pos begin = pos; + if (pos == end) + return false; + + Float64 float_value = std::strtod(pos, const_cast(&pos)); + if (pos == begin || errno == ERANGE) + { + expected = "number (this cause range error)"; + return false; + } + res = float_value; + + /// попробуем использовать более точный тип - UInt64 или Int64 + + Pos pos_integer = begin; + if (float_value < 0) + { + Int64 int_value = std::strtoll(pos_integer, const_cast(&pos_integer), 0); + if (pos_integer == pos && errno != ERANGE) + res = int_value; + } + else + { + UInt64 uint_value = std::strtoull(pos_integer, const_cast(&pos_integer), 0); + if (pos_integer == pos && errno != ERANGE) + res = uint_value; + } + + node = new ASTLiteral(StringRange(begin, pos), res); + return true; +} + + +bool ParserStringLiteral::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + String s; + + if (pos == end || *pos != '\'') + { + expected = "opening single quote"; + return false; + } + + while (pos != end) + { + size_t bytes = 0; + for (; pos + bytes != end; ++bytes) + if (pos[bytes] == '\\' || pos[bytes] == '\'') + break; + + s.append(pos, bytes); + pos += bytes; + + if (*pos == '\'') + { + ++pos; + node = new ASTLiteral(StringRange(begin, pos), s); + return true; + } + + if (*pos == '\\') + { + ++pos; + if (pos == end) + { + expected = "escape sequence"; + return false; + } + s += parseEscapeSequence(*pos); + ++pos; + } + } + + expected = "closing single quote"; + return false; +} + + +bool ParserLiteral::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + + ParserNull null_p; + ParserNumber num_p; + ParserStringLiteral str_p; + + if (null_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + if (num_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + if (str_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + expected = "literal: one of NULL, number, single quoted string"; + return false; +} + + +bool ParserExpressionElement::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + Pos begin = pos; + + ParserParenthesisExpression paren_p; + ParserArray array_p; + ParserLiteral lit_p; + ParserFunction fun_p; + ParserIdentifier id_p; + + if (paren_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + if (array_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + if (lit_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + if (fun_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + if (id_p.parse(pos, end, node, expected)) + return true; + pos = begin; + + expected = "expression element: one of array, literal, function, identifier, parenthised expression"; + return false; +} + + +} + diff --git a/dbms/src/Parsers/ExpressionListParsers.cpp b/dbms/src/Parsers/ExpressionListParsers.cpp new file mode 100644 index 00000000000..62101554e3c --- /dev/null +++ b/dbms/src/Parsers/ExpressionListParsers.cpp @@ -0,0 +1,202 @@ +#include +#include +#include + +#include +#include + +#include + + +namespace DB +{ + +bool ParserLeftAssociativeBinaryOperatorList::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + bool first = true; + ParserWhiteSpaceOrComments ws; + + while (1) + { + if (first) + { + ASTPtr elem; + if (!elem_parser->parse(pos, end, elem, expected)) + break; + + node = elem; + } + else + { + ws.ignore(pos, end); + + /// пробуем найти какой-нибудь из допустимых операторов + Pos begin = pos; + Operators_t::const_iterator it; + for (it = operators.begin(); it != operators.end(); ++it) + { + ParserString op(it->first); + if (op.ignore(pos, end, expected)) + break; + } + + if (it == operators.end()) + break; + + ws.ignore(pos, end); + + /// функция, соответствующая оператору + ASTFunction * p_function = new ASTFunction(StringRange(pos, pos)); + ASTFunction & function = *p_function; + ASTPtr function_node = p_function; + + /// аргументы функции + ASTExpressionList * p_exp_list = new ASTExpressionList(StringRange(pos, pos)); + ASTExpressionList & exp_list = *p_exp_list; + ASTPtr exp_list_node = p_exp_list; + + ASTPtr elem; + if (!elem_parser->parse(pos, end, elem, expected)) + return false; + + /// первым аргументом функции будет предыдущий элемент, вторым - следующий + function.range.first = begin; + function.range.second = pos; + function.name = it->second; + function.arguments = exp_list_node; + + exp_list.children.push_back(node); + exp_list.children.push_back(elem); + exp_list.range.second = pos; + + /** специальное исключение для оператора доступа к элементу массива x[y], который + * содержит инфиксную часть '[' и суффиксную ']' (задаётся в виде '[') + */ + if (it->first == "[") + { + ParserString rest_p("]"); + + ws.ignore(pos, end); + if (!rest_p.ignore(pos, end, expected)) + return false; + } + + node = function_node; + } + + first = false; + } + + return true; +} + + +bool ParserPrefixUnaryOperatorExpression::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + ParserWhiteSpaceOrComments ws; + + ws.ignore(pos, end); + + /// пробуем найти какой-нибудь из допустимых операторов + Pos begin = pos; + Operators_t::const_iterator it; + for (it = operators.begin(); it != operators.end(); ++it) + { + ParserString op(it->first); + if (op.ignore(pos, end, expected)) + break; + } + + if (it == operators.end()) + return false; + + ws.ignore(pos, end); + + /// функция, соответствующая оператору + ASTFunction * p_function = new ASTFunction(StringRange(pos, pos)); + ASTFunction & function = *p_function; + ASTPtr function_node = p_function; + + /// аргументы функции + ASTExpressionList * p_exp_list = new ASTExpressionList(StringRange(pos, pos)); + ASTExpressionList & exp_list = *p_exp_list; + ASTPtr exp_list_node = p_exp_list; + + ASTPtr elem; + if (!elem_parser->parse(pos, end, elem, expected)) + return false; + + function.range.first = begin; + function.range.second = pos; + function.name = it->second; + function.arguments = exp_list_node; + + exp_list.children.push_back(elem); + exp_list.range.second = pos; + + node = function_node; + + return true; +} + + +ParserAccessExpression::ParserAccessExpression() + : elem_parser(new ParserExpressionElement), + operator_parser(boost::assign::map_list_of + (".", "tupleElement") + ("[", "arrayElement"), + elem_parser) +{ +} + + +bool ParserExpressionList::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + bool first = true; + ParserLogicalOrExpression nested_parser; + ParserWhiteSpaceOrComments ws; + ParserString comma(","); + + ASTExpressionList * p_expr_list = new ASTExpressionList(StringRange(pos, pos)); + ASTExpressionList & expr_list = *p_expr_list; + node = p_expr_list; + + while (1) + { + if (first) + { + ASTPtr elem; + if (!nested_parser.parse(pos, end, elem, expected)) + break; + + expr_list.children.push_back(elem); + } + else + { + ws.ignore(pos, end); + if (!comma.ignore(pos, end, expected)) + break; + ws.ignore(pos, end); + + ASTPtr elem; + if (!nested_parser.parse(pos, end, elem, expected)) + return false; + + expr_list.children.push_back(elem); + } + + first = false; + } + + return true; +} + + +bool ParserNotEmptyExpressionList::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) +{ + return nested_parser.parse(pos, end, node, expected) + && !dynamic_cast(*node).children.empty(); +} + + +} diff --git a/dbms/src/Parsers/tests/expression.cpp b/dbms/src/Parsers/tests/expression.cpp deleted file mode 100644 index cbea39c32a5..00000000000 --- a/dbms/src/Parsers/tests/expression.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include - -#include -#include - -#include - - -namespace qi = boost::spirit::qi; -namespace ascii = boost::spirit::ascii; - -typedef DB::ExpressionGrammarTypes::Expression Expr; - -class dumpConst : public boost::static_visitor<> -{ -public: - void operator() (const DB::ExpressionGrammarTypes::NumberConstant & x) const - { - std::cout << "Number: " << x << std::endl; - } - - void operator() (const DB::ExpressionGrammarTypes::StringConstant & x) const - { - std::cout << "String: " << x << std::endl; - } - - void operator() (const DB::ExpressionGrammarTypes::NullConstant & x) const - { - std::cout << "Null" << std::endl; - } -}; - -class dumpNode : public boost::static_visitor<> -{ -public: - void operator() (const DB::ExpressionGrammarTypes::Constant & x) const - { - boost::apply_visitor(dumpConst(), x); - } - - void operator() (const DB::ExpressionGrammarTypes::Name & x) const - { - std::cout << "Name: " << x << std::endl; - } - - void operator() (const DB::ExpressionGrammarTypes::Function & x) const - { - std::cout << "Function, name: " << x.name << ", args: " << std::endl; - for (Expr::const_iterator it = x.args.begin(); it != x.args.end(); ++it) - boost::apply_visitor(dumpNode(), *it); - std::cout << std::endl; - } -}; - -void dumpResult(const Expr & value) -{ - - for (Expr::const_iterator it = value.begin(); it != value.end(); ++it) - boost::apply_visitor(dumpNode(), *it); -} - - -int main(int argc, char ** argv) -{ - typedef std::string::const_iterator iterator_t; - - DB::ExpressionGrammar parser; - DB::ExpressionGrammarTypes::Expression value; - - std::string s = "ab1, b, f(c), 0, g(h(i), 1), -1, NULL, null, 'abc'"; - iterator_t it = s.begin(); - iterator_t end = s.end(); - - bool res = boost::spirit::qi::phrase_parse(it, end, parser, ascii::space, value); - - std::cout << res << '\t' << s.substr(0, it - s.begin()) << std::endl; - dumpResult(value); - - return 0; -} diff --git a/dbms/src/Parsers/tests/parsers.cpp b/dbms/src/Parsers/tests/parsers.cpp new file mode 100644 index 00000000000..dd928cec9d3 --- /dev/null +++ b/dbms/src/Parsers/tests/parsers.cpp @@ -0,0 +1,32 @@ +#include + +#include + +#include +#include + + +int main(int argc, char ** argv) +{ + DB::ParserSelectQuery parser; + DB::ASTPtr ast; + std::string input = "SELECT 1, 2, 3"; + std::string expected; + + const char * begin = input.data(); + const char * end = begin + input.size(); + const char * pos = begin; + + if (parser.parse(pos, end, ast, expected)) + { + std::cout << "Success." << std::endl; + } + else + { + std::cout << "Failed at position " << (pos - begin) << ": " + << strconvert::quote_fast << input.substr(pos - begin, 10) + << ", expected " << expected << "." << std::endl; + } + + return 0; +}