ClickHouse/dbms/src/Interpreters/InterpreterRenameQuery.cpp
Alexey Milovidov 0629fb4fdd Merge
2013-09-30 01:29:19 +00:00

104 lines
4.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <Poco/File.h>
#include <Poco/FileStream.h>
#include <DB/Common/escapeForFileName.h>
#include <DB/IO/ReadBufferFromFile.h>
#include <DB/IO/WriteBufferFromString.h>
#include <DB/IO/copyData.h>
#include <DB/Parsers/ASTRenameQuery.h>
#include <DB/Parsers/ParserCreateQuery.h>
#include <DB/Parsers/formatAST.h>
#include <DB/Interpreters/InterpreterRenameQuery.h>
namespace DB
{
InterpreterRenameQuery::InterpreterRenameQuery(ASTPtr query_ptr_, Context & context_)
: query_ptr(query_ptr_), context(context_)
{
}
void InterpreterRenameQuery::execute()
{
/** Все таблицы переименовываются под глобальной блокировкой. */
Poco::ScopedLock<Poco::Mutex> lock(context.getMutex());
String path = context.getPath();
String current_database = context.getCurrentDatabase();
ASTRenameQuery & rename = dynamic_cast<ASTRenameQuery &>(*query_ptr);
/** Если в процессе переименования произошла ошибка, то может быть переименована только часть таблиц,
* или состояние может стать неконсистентным. (Это имеет смысл исправить.)
*/
for (ASTRenameQuery::Elements::const_iterator it = rename.elements.begin(); it != rename.elements.end(); ++it)
{
String from_database_name = it->from.database.empty() ? current_database : it->from.database;
String from_database_name_escaped = escapeForFileName(from_database_name);
String from_table_name = it->from.table;
String from_table_name_escaped = escapeForFileName(from_table_name);
String from_metadata_path = path + "metadata/" + from_database_name_escaped + "/" + (!from_table_name.empty() ? from_table_name_escaped + ".sql" : "");
String to_database_name = it->to.database.empty() ? current_database : it->to.database;
String to_database_name_escaped = escapeForFileName(to_database_name);
String to_table_name = it->to.table;
String to_table_name_escaped = escapeForFileName(to_table_name);
String to_metadata_path = path + "metadata/" + to_database_name_escaped + "/" + (!to_table_name.empty() ? to_table_name_escaped + ".sql" : "");
context.assertTableExists(from_database_name, from_table_name);
context.assertTableDoesntExist(to_database_name, to_table_name);
/// Уведомляем таблицу о том, что она переименовается. Если таблица не поддерживает переименование - кинется исключение.
context.getTable(from_database_name, from_table_name)->rename(path + "data/" + to_database_name_escaped + "/", to_table_name);
/// Пишем новый файл с метаданными.
{
String create_query;
{
ReadBufferFromFile in(from_metadata_path, 1024);
WriteBufferFromString out(create_query);
copyData(in, out);
}
ParserCreateQuery parser;
const char * pos = create_query.data();
const char * end = pos + create_query.size();
ASTPtr ast;
String expected;
bool parse_res = parser.parse(pos, end, ast, expected);
/// Распарсенный запрос должен заканчиваться на конец входных данных или на точку с запятой.
if (!parse_res || (pos != end && *pos != ';'))
throw Exception("Syntax error in file " + from_metadata_path + ": failed at position "
+ toString(pos - create_query.data()) + ": "
+ std::string(pos, std::min(SHOW_CHARS_ON_SYNTAX_ERROR, end - pos))
+ ", expected " + (parse_res ? "end of query" : expected) + ".",
ErrorCodes::SYNTAX_ERROR);
dynamic_cast<ASTCreateQuery &>(*ast).table = to_table_name;
Poco::FileOutputStream ostr(to_metadata_path);
formatAST(*ast, ostr, 0, false);
ostr << '\n';
}
/// Переименовываем таблицу в контексте.
context.addTable(to_database_name, to_table_name,
context.detachTable(from_database_name, from_table_name));
/// Удаляем старый файл с метаданными.
Poco::File(from_metadata_path).remove();
}
}
}