ClickHouse/src/Parsers/ParserBackupQuery.cpp
2023-03-30 00:11:13 +02:00

377 lines
13 KiB
C++

#include <Parsers/ParserBackupQuery.h>
#include <Parsers/ASTBackupQuery.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier_fwd.h>
#include <Parsers/ASTSetQuery.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ParserPartition.h>
#include <Parsers/ParserSetQuery.h>
#include <Parsers/parseDatabaseAndTableName.h>
#include <Common/assert_cast.h>
#include <boost/range/algorithm_ext/erase.hpp>
namespace DB
{
namespace
{
using Kind = ASTBackupQuery::Kind;
using Element = ASTBackupQuery::Element;
using ElementType = ASTBackupQuery::ElementType;
bool parsePartitions(IParser::Pos & pos, Expected & expected, std::optional<ASTs> & partitions)
{
if (!ParserKeyword{"PARTITION"}.ignore(pos, expected) && !ParserKeyword{"PARTITIONS"}.ignore(pos, expected))
return false;
ASTs result;
auto parse_list_element = [&]
{
ASTPtr ast;
if (!ParserPartition{}.parse(pos, ast, expected))
return false;
result.push_back(ast);
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_list_element, false))
return false;
partitions = std::move(result);
return true;
}
bool parseExceptDatabases(IParser::Pos & pos, Expected & expected, std::set<String> & except_databases)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserKeyword{"EXCEPT DATABASE"}.ignore(pos, expected) && !ParserKeyword{"EXCEPT DATABASES"}.ignore(pos, expected))
return false;
std::set<String> result;
auto parse_list_element = [&]
{
ASTPtr ast;
if (!ParserIdentifier{}.parse(pos, ast, expected))
return false;
result.insert(getIdentifierName(ast));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_list_element, false))
return false;
except_databases = std::move(result);
return true;
});
}
bool parseExceptTables(IParser::Pos & pos, Expected & expected, const std::optional<String> & database_name, std::set<DatabaseAndTableName> & except_tables)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserKeyword{"EXCEPT TABLE"}.ignore(pos, expected) && !ParserKeyword{"EXCEPT TABLES"}.ignore(pos, expected))
return false;
std::set<DatabaseAndTableName> result;
auto parse_list_element = [&]
{
DatabaseAndTableName table_name;
if (database_name)
{
ASTPtr ast;
if (!ParserIdentifier{}.parse(pos, ast, expected))
return false;
table_name.first = *database_name;
table_name.second = getIdentifierName(ast);
}
else
{
if (!parseDatabaseAndTableName(pos, expected, table_name.first, table_name.second))
return false;
}
result.emplace(std::move(table_name));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_list_element, false))
return false;
except_tables = std::move(result);
return true;
});
}
bool parseElement(IParser::Pos & pos, Expected & expected, Element & element)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (ParserKeyword{"TABLE"}.ignore(pos, expected) || ParserKeyword{"DICTIONARY"}.ignore(pos, expected) ||
ParserKeyword{"VIEW"}.ignore(pos, expected))
{
element.type = ElementType::TABLE;
if (!parseDatabaseAndTableName(pos, expected, element.database_name, element.table_name))
return false;
element.new_database_name = element.database_name;
element.new_table_name = element.table_name;
if (ParserKeyword("AS").ignore(pos, expected))
{
if (!parseDatabaseAndTableName(pos, expected, element.new_database_name, element.new_table_name))
return false;
}
parsePartitions(pos, expected, element.partitions);
return true;
}
if (ParserKeyword{"TEMPORARY TABLE"}.ignore(pos, expected))
{
element.type = ElementType::TEMPORARY_TABLE;
ASTPtr ast;
if (!ParserIdentifier{}.parse(pos, ast, expected))
return false;
element.table_name = getIdentifierName(ast);
element.new_table_name = element.table_name;
if (ParserKeyword("AS").ignore(pos, expected))
{
ast = nullptr;
if (!ParserIdentifier{}.parse(pos, ast, expected))
return false;
element.new_table_name = getIdentifierName(ast);
}
return true;
}
if (ParserKeyword{"DATABASE"}.ignore(pos, expected))
{
element.type = ElementType::DATABASE;
ASTPtr ast;
if (!ParserIdentifier{}.parse(pos, ast, expected))
return false;
element.database_name = getIdentifierName(ast);
element.new_database_name = element.database_name;
if (ParserKeyword("AS").ignore(pos, expected))
{
ast = nullptr;
if (!ParserIdentifier{}.parse(pos, ast, expected))
return false;
element.new_database_name = getIdentifierName(ast);
}
parseExceptTables(pos, expected, element.database_name, element.except_tables);
return true;
}
if (ParserKeyword{"ALL"}.ignore(pos, expected))
{
element.type = ElementType::ALL;
parseExceptDatabases(pos, expected, element.except_databases);
parseExceptTables(pos, expected, {}, element.except_tables);
return true;
}
return false;
});
}
bool parseElements(IParser::Pos & pos, Expected & expected, std::vector<Element> & elements)
{
return IParserBase::wrapParseImpl(pos, [&]
{
std::vector<Element> result;
auto parse_element = [&]
{
Element element;
if (parseElement(pos, expected, element))
{
result.emplace_back(std::move(element));
return true;
}
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_element, false))
return false;
elements = std::move(result);
return true;
});
}
bool parseBackupName(IParser::Pos & pos, Expected & expected, ASTPtr & backup_name)
{
if (!ParserIdentifierWithOptionalParameters{}.parse(pos, backup_name, expected))
return false;
backup_name->as<ASTFunction &>().kind = ASTFunction::Kind::BACKUP_NAME;
return true;
}
bool parseBaseBackupSetting(IParser::Pos & pos, Expected & expected, ASTPtr & base_backup_name)
{
return IParserBase::wrapParseImpl(pos, [&]
{
return ParserKeyword{"base_backup"}.ignore(pos, expected)
&& ParserToken(TokenType::Equals).ignore(pos, expected)
&& parseBackupName(pos, expected, base_backup_name);
});
}
bool parseClusterHostIDs(IParser::Pos & pos, Expected & expected, ASTPtr & cluster_host_ids)
{
return ParserArray{}.parse(pos, cluster_host_ids, expected);
}
bool parseClusterHostIDsSetting(IParser::Pos & pos, Expected & expected, ASTPtr & cluster_host_ids)
{
return IParserBase::wrapParseImpl(pos, [&]
{
return ParserKeyword{"cluster_host_ids"}.ignore(pos, expected)
&& ParserToken(TokenType::Equals).ignore(pos, expected)
&& parseClusterHostIDs(pos, expected, cluster_host_ids);
});
}
bool parseSettings(IParser::Pos & pos, Expected & expected, ASTPtr & settings, ASTPtr & base_backup_name, ASTPtr & cluster_host_ids)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserKeyword{"SETTINGS"}.ignore(pos, expected))
return false;
SettingsChanges settings_changes;
ASTPtr res_base_backup_name;
ASTPtr res_cluster_host_ids;
auto parse_setting = [&]
{
if (!res_base_backup_name && parseBaseBackupSetting(pos, expected, res_base_backup_name))
return true;
if (!res_cluster_host_ids && parseClusterHostIDsSetting(pos, expected, res_cluster_host_ids))
return true;
SettingChange setting;
if (ParserSetQuery::parseNameValuePair(setting, pos, expected))
{
settings_changes.push_back(std::move(setting));
return true;
}
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_setting, false))
return false;
ASTPtr res_settings;
if (!settings_changes.empty())
{
auto settings_changes_ast = std::make_shared<ASTSetQuery>();
settings_changes_ast->changes = std::move(settings_changes);
settings_changes_ast->is_standalone = false;
res_settings = settings_changes_ast;
}
settings = std::move(res_settings);
base_backup_name = std::move(res_base_backup_name);
cluster_host_ids = std::move(res_cluster_host_ids);
return true;
});
}
bool parseSyncOrAsync(IParser::Pos & pos, Expected & expected, ASTPtr & settings)
{
bool async;
if (ParserKeyword{"ASYNC"}.ignore(pos, expected))
async = true;
else if (ParserKeyword{"SYNC"}.ignore(pos, expected))
async = false;
else
return false;
SettingsChanges changes;
if (settings)
{
changes = assert_cast<ASTSetQuery *>(settings.get())->changes;
}
boost::remove_erase_if(changes, [](const SettingChange & change) { return change.name == "async"; });
changes.emplace_back("async", async);
auto new_settings = std::make_shared<ASTSetQuery>();
new_settings->changes = std::move(changes);
new_settings->is_standalone = false;
settings = new_settings;
return true;
}
bool parseOnCluster(IParserBase::Pos & pos, Expected & expected, String & cluster)
{
return IParserBase::wrapParseImpl(pos, [&]
{
return ParserKeyword{"ON"}.ignore(pos, expected) && ASTQueryWithOnCluster::parse(pos, cluster, expected);
});
}
}
bool ParserBackupQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
Kind kind;
if (ParserKeyword{"BACKUP"}.ignore(pos, expected))
kind = Kind::BACKUP;
else if (ParserKeyword{"RESTORE"}.ignore(pos, expected))
kind = Kind::RESTORE;
else
return false;
std::vector<Element> elements;
if (!parseElements(pos, expected, elements))
return false;
String cluster;
parseOnCluster(pos, expected, cluster);
if (!ParserKeyword{(kind == Kind::BACKUP) ? "TO" : "FROM"}.ignore(pos, expected))
return false;
ASTPtr backup_name;
if (!parseBackupName(pos, expected, backup_name))
return false;
ASTPtr settings;
ASTPtr base_backup_name;
ASTPtr cluster_host_ids;
parseSettings(pos, expected, settings, base_backup_name, cluster_host_ids);
parseSyncOrAsync(pos, expected, settings);
auto query = std::make_shared<ASTBackupQuery>();
node = query;
query->kind = kind;
query->elements = std::move(elements);
query->cluster = std::move(cluster);
if (backup_name)
query->set(query->backup_name, backup_name);
query->settings = std::move(settings);
query->cluster_host_ids = std::move(cluster_host_ids);
if (base_backup_name)
query->set(query->base_backup_name, base_backup_name);
return true;
}
}