dbms: development [#CONV-2944].

This commit is contained in:
Alexey Milovidov 2011-11-01 17:57:37 +00:00
parent 859a86b382
commit d9e921a127
9 changed files with 190 additions and 158 deletions

View File

@ -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)

View 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_)
{
}
};
}

View File

@ -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

View File

@ -26,7 +26,7 @@ protected:
};
/** Идентификатор, например, x_yz123
/** Идентификатор, например, x_yz123 или `something special`
*/
class ParserIdentifier : public IParserBase
{

View File

@ -110,4 +110,9 @@ void readDoubleQuotedString(String & s, ReadBuffer & buf)
readAnyQuotedString<'"'>(s, buf);
}
void readBackQuotedString(String & s, ReadBuffer & buf)
{
readAnyQuotedString<'`'>(s, buf);
}
}

View File

@ -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);
}
}

View File

@ -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))
{

View File

@ -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";
}

View File

@ -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;