From d9e921a1273760e9a96ea685171e87a1f50136a2 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Tue, 1 Nov 2011 17:57:37 +0000 Subject: [PATCH] dbms: development [#CONV-2944]. --- dbms/include/DB/IO/ReadHelpers.h | 2 + dbms/include/DB/IO/WriteBufferFromString.h | 33 +++++++ dbms/include/DB/IO/WriteHelpers.h | 78 ++++++++++++++-- .../DB/Parsers/ExpressionElementParsers.h | 2 +- dbms/src/IO/ReadHelpers.cpp | 5 + dbms/src/IO/WriteHelpers.cpp | 91 ------------------- dbms/src/Interpreters/Expression.cpp | 69 ++++++++------ .../Interpreters/InterpreterCreateQuery.cpp | 11 ++- dbms/src/Parsers/ExpressionElementParsers.cpp | 57 +++++------- 9 files changed, 190 insertions(+), 158 deletions(-) create mode 100644 dbms/include/DB/IO/WriteBufferFromString.h diff --git a/dbms/include/DB/IO/ReadHelpers.h b/dbms/include/DB/IO/ReadHelpers.h index 4c46e0df79c..cfdc0d0fcc6 100644 --- a/dbms/include/DB/IO/ReadHelpers.h +++ b/dbms/include/DB/IO/ReadHelpers.h @@ -274,6 +274,8 @@ void readQuotedString(String & s, ReadBuffer & buf); void readDoubleQuotedString(String & s, ReadBuffer & buf); +void readBackQuotedString(String & s, ReadBuffer & buf); + /// в формате YYYY-MM-DD inline void readDateText(Yandex::DayNum_t & date, ReadBuffer & buf) diff --git a/dbms/include/DB/IO/WriteBufferFromString.h b/dbms/include/DB/IO/WriteBufferFromString.h new file mode 100644 index 00000000000..c0632173756 --- /dev/null +++ b/dbms/include/DB/IO/WriteBufferFromString.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include + + +namespace DB +{ + +/** Пишет данные в строку. + */ +class WriteBufferFromString : public WriteBuffer +{ +private: + std::string & s; + + void nextImpl() + { + size_t old_size = s.size(); + s.resize(old_size * 2); + internal_buffer = Buffer(reinterpret_cast(&s[old_size]), reinterpret_cast(&*s.end())); + working_buffer = internal_buffer; + } + +public: + WriteBufferFromString(std::string & s_) + : WriteBuffer(reinterpret_cast(&s_[0]), s_.size()), s(s_) + { + } +}; + +} diff --git a/dbms/include/DB/IO/WriteHelpers.h b/dbms/include/DB/IO/WriteHelpers.h index 0a35c773576..cc60a8c467a 100644 --- a/dbms/include/DB/IO/WriteHelpers.h +++ b/dbms/include/DB/IO/WriteHelpers.h @@ -124,18 +124,84 @@ inline void writeString(const String & s, WriteBuffer & buf) buf.write(s.data(), s.size()); } -/// предполагается, что строка в оперативке хранится непрерывно, и \0-terminated. -void writeEscapedString(const String & s, WriteBuffer & buf); + +template +void writeAnyEscapedString(const String & s, WriteBuffer & buf) +{ + for (String::const_iterator it = s.begin(); it != s.end(); ++it) + { + switch (*it) + { + case '\b': + writeChar('\\', buf); + writeChar('b', buf); + break; + case '\f': + writeChar('\\', buf); + writeChar('f', buf); + break; + case '\n': + writeChar('\\', buf); + writeChar('n', buf); + break; + case '\r': + writeChar('\\', buf); + writeChar('r', buf); + break; + case '\t': + writeChar('\\', buf); + writeChar('t', buf); + break; + case '\0': + writeChar('\\', buf); + writeChar('0', buf); + break; + case '\\': + writeChar('\\', buf); + writeChar('\\', buf); + break; + case c: + writeChar('\\', buf); + writeChar(c, buf); + break; + default: + writeChar(*it, buf); + } + } +} + + +inline void writeEscapedString(const String & s, WriteBuffer & buf) +{ + writeAnyEscapedString<'\''>(s, buf); +} + + +template +void writeAnyQuotedString(const String & s, WriteBuffer & buf) +{ + writeChar(c, buf); + writeAnyEscapedString(s, buf); + writeChar(c, buf); +} + inline void writeQuotedString(const String & s, WriteBuffer & buf) { - writeChar('\'', buf); - writeEscapedString(s, buf); - writeChar('\'', buf); + writeAnyQuotedString<'\''>(s, buf); } /// Совместимо с JSON. -void writeDoubleQuotedString(const String & s, WriteBuffer & buf); +inline void writeDoubleQuotedString(const String & s, WriteBuffer & buf) +{ + writeAnyQuotedString<'"'>(s, buf); +} + +/// Совместимо с JSON. +inline void writeBackQuotedString(const String & s, WriteBuffer & buf) +{ + writeAnyQuotedString<'`'>(s, buf); +} /// в формате YYYY-MM-DD diff --git a/dbms/include/DB/Parsers/ExpressionElementParsers.h b/dbms/include/DB/Parsers/ExpressionElementParsers.h index 035d82d46bc..a8796866c5c 100644 --- a/dbms/include/DB/Parsers/ExpressionElementParsers.h +++ b/dbms/include/DB/Parsers/ExpressionElementParsers.h @@ -26,7 +26,7 @@ protected: }; -/** Идентификатор, например, x_yz123 +/** Идентификатор, например, x_yz123 или `something special` */ class ParserIdentifier : public IParserBase { diff --git a/dbms/src/IO/ReadHelpers.cpp b/dbms/src/IO/ReadHelpers.cpp index 2cd41da171b..ee5a69f59a4 100644 --- a/dbms/src/IO/ReadHelpers.cpp +++ b/dbms/src/IO/ReadHelpers.cpp @@ -110,4 +110,9 @@ void readDoubleQuotedString(String & s, ReadBuffer & buf) readAnyQuotedString<'"'>(s, buf); } +void readBackQuotedString(String & s, ReadBuffer & buf) +{ + readAnyQuotedString<'`'>(s, buf); +} + } diff --git a/dbms/src/IO/WriteHelpers.cpp b/dbms/src/IO/WriteHelpers.cpp index 1b0a79a2bc6..4c2c357c181 100644 --- a/dbms/src/IO/WriteHelpers.cpp +++ b/dbms/src/IO/WriteHelpers.cpp @@ -3,95 +3,4 @@ namespace DB { -void writeEscapedString(const String & s, WriteBuffer & buf) -{ - for (String::const_iterator it = s.begin(); it != s.end(); ++it) - { - switch (*it) - { - case '\b': - writeChar('\\', buf); - writeChar('b', buf); - break; - case '\f': - writeChar('\\', buf); - writeChar('f', buf); - break; - case '\n': - writeChar('\\', buf); - writeChar('n', buf); - break; - case '\r': - writeChar('\\', buf); - writeChar('r', buf); - break; - case '\t': - writeChar('\\', buf); - writeChar('t', buf); - break; - case '\0': - writeChar('\\', buf); - writeChar('0', buf); - break; - case '\'': - writeChar('\\', buf); - writeChar('\'', buf); - break; - case '\\': - writeChar('\\', buf); - writeChar('\\', buf); - break; - default: - writeChar(*it, buf); - } - } -} - - -void writeDoubleQuotedString(const String & s, WriteBuffer & buf) -{ - writeChar('"', buf); - for (String::const_iterator it = s.begin(); it != s.end(); ++it) - { - switch (*it) - { - case '\b': - writeChar('\\', buf); - writeChar('b', buf); - break; - case '\f': - writeChar('\\', buf); - writeChar('f', buf); - break; - case '\n': - writeChar('\\', buf); - writeChar('n', buf); - break; - case '\r': - writeChar('\\', buf); - writeChar('r', buf); - break; - case '\t': - writeChar('\\', buf); - writeChar('t', buf); - break; - case '\0': - writeChar('\\', buf); - writeChar('0', buf); - break; - case '"': - writeChar('\\', buf); - writeChar('"', buf); - break; - case '\\': - writeChar('\\', buf); - writeChar('\\', buf); - break; - default: - writeChar(*it, buf); - } - } - writeChar('"', buf); -} - } diff --git a/dbms/src/Interpreters/Expression.cpp b/dbms/src/Interpreters/Expression.cpp index 7760f726f54..53653e7f8b0 100644 --- a/dbms/src/Interpreters/Expression.cpp +++ b/dbms/src/Interpreters/Expression.cpp @@ -33,36 +33,51 @@ void Expression::addSemantic(ASTPtr & ast) } else if (ASTFunction * node = dynamic_cast(&*ast)) { - Functions::const_iterator it = context.functions->find(node->name); - - /// Типы аргументов - DataTypes argument_types; - ASTs & arguments = dynamic_cast(*node->arguments).children; - - for (ASTs::iterator it = arguments.begin(); it != arguments.end(); ++it) + /** Нет ли в таблице столбца, название которого полностью совпадает с записью функции? + * Например, в таблице есть столбец "domain(URL)", и мы запросили domain(URL). + */ + String function_string = node->getColumnName(); + NamesAndTypesMap::const_iterator it = context.columns.find(function_string); + if (context.columns.end() != it) { - if (ASTFunction * arg = dynamic_cast(&**it)) - argument_types.push_back(arg->return_type); - else if (ASTIdentifier * arg = dynamic_cast(&**it)) - argument_types.push_back(arg->type); - else if (ASTLiteral * arg = dynamic_cast(&**it)) - argument_types.push_back(arg->type); - } - - node->aggregate_function = context.aggregate_function_factory->tryGet(node->name, argument_types); - if (it == context.functions->end() && node->aggregate_function.isNull()) - throw Exception("Unknown function " + node->name, ErrorCodes::UNKNOWN_FUNCTION); - if (it != context.functions->end()) - node->function = it->second; - - /// Получаем типы результата - if (node->aggregate_function) - { - node->aggregate_function->setArguments(argument_types); - node->return_type = node->aggregate_function->getReturnType(); + ASTIdentifier * ast_id = new ASTIdentifier(node->range, node->name); + ast_id->type = it->second; + required_columns.insert(function_string); + ast = ast_id; } else - node->return_type = node->function->getReturnType(argument_types); + { + Functions::const_iterator it = context.functions->find(node->name); + + /// Типы аргументов + DataTypes argument_types; + ASTs & arguments = dynamic_cast(*node->arguments).children; + + for (ASTs::iterator it = arguments.begin(); it != arguments.end(); ++it) + { + if (ASTFunction * arg = dynamic_cast(&**it)) + argument_types.push_back(arg->return_type); + else if (ASTIdentifier * arg = dynamic_cast(&**it)) + argument_types.push_back(arg->type); + else if (ASTLiteral * arg = dynamic_cast(&**it)) + argument_types.push_back(arg->type); + } + + node->aggregate_function = context.aggregate_function_factory->tryGet(node->name, argument_types); + if (it == context.functions->end() && node->aggregate_function.isNull()) + throw Exception("Unknown function " + node->name, ErrorCodes::UNKNOWN_FUNCTION); + if (it != context.functions->end()) + node->function = it->second; + + /// Получаем типы результата + if (node->aggregate_function) + { + node->aggregate_function->setArguments(argument_types); + node->return_type = node->aggregate_function->getReturnType(); + } + else + node->return_type = node->function->getReturnType(argument_types); + } } else if (ASTIdentifier * node = dynamic_cast(&*ast)) { diff --git a/dbms/src/Interpreters/InterpreterCreateQuery.cpp b/dbms/src/Interpreters/InterpreterCreateQuery.cpp index 0c3f23a7469..d3cd7487208 100644 --- a/dbms/src/Interpreters/InterpreterCreateQuery.cpp +++ b/dbms/src/Interpreters/InterpreterCreateQuery.cpp @@ -1,5 +1,8 @@ #include +#include +#include + #include #include @@ -111,7 +114,13 @@ StoragePtr InterpreterCreateQuery::execute() << "(\n"; for (NamesAndTypesList::const_iterator it = columns->begin(); it != columns->end(); ++it) - metadata_file << (it != columns->begin() ? ",\n" : "") << "\t" << it->first << " " << it->second->getName(); + { + String quoted_column_name; + WriteBufferFromString buf(quoted_column_name); + writeBackQuotedString(it->first, buf); + + metadata_file << (it != columns->begin() ? ",\n" : "") << "\t" << quoted_column_name << " " << it->second->getName(); + } metadata_file << "\n) ENGINE = " << storage_name << "\n"; } diff --git a/dbms/src/Parsers/ExpressionElementParsers.cpp b/dbms/src/Parsers/ExpressionElementParsers.cpp index d50c8974a7a..98df92c0582 100644 --- a/dbms/src/Parsers/ExpressionElementParsers.cpp +++ b/dbms/src/Parsers/ExpressionElementParsers.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include #include #include @@ -95,20 +97,33 @@ bool ParserIdentifier::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & exp { 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) + /// Идентификатор в обратных кавычках + if (pos != end && *pos == '`') { - node = new ASTIdentifier(StringRange(begin, pos), String(begin, pos - begin)); + ReadBuffer buf(const_cast(pos), end - pos, 0); + String s; + readBackQuotedString(s, buf); + pos += buf.count(); + node = new ASTIdentifier(StringRange(begin, pos), s); return true; } else - return false; + { + 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; + } } @@ -199,28 +214,6 @@ bool ParserNumber::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expecte } -static 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; - } -} - - bool ParserStringLiteral::parseImpl(Pos & pos, Pos end, ASTPtr & node, String & expected) { Pos begin = pos;