2012-06-18 06:20:23 +00:00
|
|
|
|
#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()
|
|
|
|
|
{
|
2012-08-02 17:33:31 +00:00
|
|
|
|
String path = context.getPath();
|
|
|
|
|
String current_database = context.getCurrentDatabase();
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
|
|
|
|
ASTRenameQuery & rename = typeid_cast<ASTRenameQuery &>(*query_ptr);
|
2012-06-18 06:20:23 +00:00
|
|
|
|
|
|
|
|
|
/** Если в процессе переименования произошла ошибка, то может быть переименована только часть таблиц,
|
|
|
|
|
* или состояние может стать неконсистентным. (Это имеет смысл исправить.)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (ASTRenameQuery::Elements::const_iterator it = rename.elements.begin(); it != rename.elements.end(); ++it)
|
|
|
|
|
{
|
2012-08-02 17:33:31 +00:00
|
|
|
|
String from_database_name = it->from.database.empty() ? current_database : it->from.database;
|
2012-06-18 06:20:23 +00:00
|
|
|
|
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);
|
2012-08-02 17:33:31 +00:00
|
|
|
|
String from_metadata_path = path + "metadata/" + from_database_name_escaped + "/" + (!from_table_name.empty() ? from_table_name_escaped + ".sql" : "");
|
2012-06-18 06:20:23 +00:00
|
|
|
|
|
2012-08-02 17:33:31 +00:00
|
|
|
|
String to_database_name = it->to.database.empty() ? current_database : it->to.database;
|
2012-06-18 06:20:23 +00:00
|
|
|
|
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);
|
2012-08-02 17:33:31 +00:00
|
|
|
|
String to_metadata_path = path + "metadata/" + to_database_name_escaped + "/" + (!to_table_name.empty() ? to_table_name_escaped + ".sql" : "");
|
2014-06-26 00:58:14 +00:00
|
|
|
|
|
2014-03-20 10:59:45 +00:00
|
|
|
|
/// Заблокировать таблицу нужно при незаблокированном контексте.
|
|
|
|
|
StoragePtr table = context.getTable(from_database_name, from_table_name);
|
2014-03-20 13:00:42 +00:00
|
|
|
|
auto table_lock = table->lockForAlter();
|
2014-03-20 10:59:45 +00:00
|
|
|
|
|
|
|
|
|
/** Все таблицы переименовываются под глобальной блокировкой. */
|
|
|
|
|
Poco::ScopedLock<Poco::Mutex> lock(context.getMutex());
|
|
|
|
|
|
2012-06-18 07:49:19 +00:00
|
|
|
|
context.assertTableDoesntExist(to_database_name, to_table_name);
|
2012-06-18 06:20:23 +00:00
|
|
|
|
|
2014-03-20 10:59:45 +00:00
|
|
|
|
|
2014-03-19 10:45:13 +00:00
|
|
|
|
table->rename(path + "data/" + to_database_name_escaped + "/", to_table_name);
|
2012-06-18 06:20:23 +00:00
|
|
|
|
|
|
|
|
|
/// Пишем новый файл с метаданными.
|
|
|
|
|
{
|
|
|
|
|
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;
|
2014-06-12 00:48:56 +00:00
|
|
|
|
Expected expected = "";
|
2012-06-18 06:20:23 +00:00
|
|
|
|
bool parse_res = parser.parse(pos, end, ast, expected);
|
|
|
|
|
|
|
|
|
|
/// Распарсенный запрос должен заканчиваться на конец входных данных или на точку с запятой.
|
|
|
|
|
if (!parse_res || (pos != end && *pos != ';'))
|
2014-04-13 08:52:50 +00:00
|
|
|
|
throw Exception(getSyntaxErrorMessage(parse_res, create_query.data(), end, pos, expected, "in file " + from_metadata_path),
|
2012-06-18 06:20:23 +00:00
|
|
|
|
ErrorCodes::SYNTAX_ERROR);
|
|
|
|
|
|
2014-06-26 00:58:14 +00:00
|
|
|
|
typeid_cast<ASTCreateQuery &>(*ast).table = to_table_name;
|
2012-06-18 06:20:23 +00:00
|
|
|
|
|
|
|
|
|
Poco::FileOutputStream ostr(to_metadata_path);
|
|
|
|
|
formatAST(*ast, ostr, 0, false);
|
|
|
|
|
ostr << '\n';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Переименовываем таблицу в контексте.
|
2013-09-30 01:29:19 +00:00
|
|
|
|
context.addTable(to_database_name, to_table_name,
|
|
|
|
|
context.detachTable(from_database_name, from_table_name));
|
2012-06-18 06:20:23 +00:00
|
|
|
|
|
|
|
|
|
/// Удаляем старый файл с метаданными.
|
|
|
|
|
Poco::File(from_metadata_path).remove();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|