mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 00:30:49 +00:00
dbms: development [#CONV-2944].
This commit is contained in:
parent
859a86b382
commit
d9e921a127
@ -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)
|
||||
|
33
dbms/include/DB/IO/WriteBufferFromString.h
Normal file
33
dbms/include/DB/IO/WriteBufferFromString.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <DB/IO/WriteBuffer.h>
|
||||
|
||||
|
||||
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<Position>(&s[old_size]), reinterpret_cast<Position>(&*s.end()));
|
||||
working_buffer = internal_buffer;
|
||||
}
|
||||
|
||||
public:
|
||||
WriteBufferFromString(std::string & s_)
|
||||
: WriteBuffer(reinterpret_cast<Position>(&s_[0]), s_.size()), s(s_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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 <char c>
|
||||
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 <char c>
|
||||
void writeAnyQuotedString(const String & s, WriteBuffer & buf)
|
||||
{
|
||||
writeChar(c, buf);
|
||||
writeAnyEscapedString<c>(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
|
||||
|
@ -26,7 +26,7 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
/** Идентификатор, например, x_yz123
|
||||
/** Идентификатор, например, x_yz123 или `something special`
|
||||
*/
|
||||
class ParserIdentifier : public IParserBase
|
||||
{
|
||||
|
@ -110,4 +110,9 @@ void readDoubleQuotedString(String & s, ReadBuffer & buf)
|
||||
readAnyQuotedString<'"'>(s, buf);
|
||||
}
|
||||
|
||||
void readBackQuotedString(String & s, ReadBuffer & buf)
|
||||
{
|
||||
readAnyQuotedString<'`'>(s, buf);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,36 +33,51 @@ void Expression::addSemantic(ASTPtr & ast)
|
||||
}
|
||||
else if (ASTFunction * node = dynamic_cast<ASTFunction *>(&*ast))
|
||||
{
|
||||
Functions::const_iterator it = context.functions->find(node->name);
|
||||
|
||||
/// Типы аргументов
|
||||
DataTypes argument_types;
|
||||
ASTs & arguments = dynamic_cast<ASTExpressionList &>(*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<ASTFunction *>(&**it))
|
||||
argument_types.push_back(arg->return_type);
|
||||
else if (ASTIdentifier * arg = dynamic_cast<ASTIdentifier *>(&**it))
|
||||
argument_types.push_back(arg->type);
|
||||
else if (ASTLiteral * arg = dynamic_cast<ASTLiteral *>(&**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<ASTExpressionList &>(*node->arguments).children;
|
||||
|
||||
for (ASTs::iterator it = arguments.begin(); it != arguments.end(); ++it)
|
||||
{
|
||||
if (ASTFunction * arg = dynamic_cast<ASTFunction *>(&**it))
|
||||
argument_types.push_back(arg->return_type);
|
||||
else if (ASTIdentifier * arg = dynamic_cast<ASTIdentifier *>(&**it))
|
||||
argument_types.push_back(arg->type);
|
||||
else if (ASTLiteral * arg = dynamic_cast<ASTLiteral *>(&**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<ASTIdentifier *>(&*ast))
|
||||
{
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include <Poco/FileStream.h>
|
||||
|
||||
#include <DB/IO/WriteBufferFromString.h>
|
||||
#include <DB/IO/WriteHelpers.h>
|
||||
|
||||
#include <DB/DataStreams/copyData.h>
|
||||
|
||||
#include <DB/Parsers/ASTCreateQuery.h>
|
||||
@ -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";
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <errno.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <DB/IO/ReadHelpers.h>
|
||||
|
||||
#include <DB/Parsers/IAST.h>
|
||||
#include <DB/Parsers/ASTExpressionList.h>
|
||||
#include <DB/Parsers/ASTFunction.h>
|
||||
@ -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<char *>(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;
|
||||
|
Loading…
Reference in New Issue
Block a user