2017-08-04 15:54:00 +00:00
|
|
|
#include <Parsers/ParserSystemQuery.h>
|
|
|
|
#include <Parsers/ASTSystemQuery.h>
|
|
|
|
#include <Parsers/CommonParsers.h>
|
2019-12-15 13:48:11 +00:00
|
|
|
#include <Parsers/ExpressionElementParsers.h>
|
2020-06-05 07:03:51 +00:00
|
|
|
#include <Parsers/ASTIdentifier.h>
|
2019-12-15 13:48:11 +00:00
|
|
|
#include <Parsers/ASTLiteral.h>
|
2018-05-21 13:49:54 +00:00
|
|
|
#include <Parsers/parseDatabaseAndTableName.h>
|
2017-08-04 15:54:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2021-06-20 08:24:43 +00:00
|
|
|
static bool parseQueryWithOnClusterAndMaybeTable(std::shared_ptr<ASTSystemQuery> & res, IParser::Pos & pos,
|
|
|
|
Expected & expected, bool require_table, bool allow_string_literal)
|
|
|
|
{
|
|
|
|
/// Better form for user: SYSTEM <ACTION> table ON CLUSTER cluster
|
|
|
|
/// Query rewritten form + form while executing on cluster: SYSTEM <ACTION> ON CLUSTER cluster table
|
|
|
|
/// Need to support both
|
|
|
|
String cluster;
|
|
|
|
bool parsed_on_cluster = false;
|
|
|
|
|
|
|
|
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
|
|
|
{
|
|
|
|
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
|
|
|
return false;
|
|
|
|
parsed_on_cluster = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parsed_table = false;
|
|
|
|
if (allow_string_literal)
|
|
|
|
{
|
|
|
|
ASTPtr ast;
|
|
|
|
if (ParserStringLiteral{}.parse(pos, ast, expected))
|
|
|
|
{
|
|
|
|
res->database = {};
|
|
|
|
res->table = ast->as<ASTLiteral &>().value.safeGet<String>();
|
|
|
|
parsed_table = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!parsed_table)
|
|
|
|
parsed_table = parseDatabaseAndTableName(pos, expected, res->database, res->table);
|
|
|
|
|
|
|
|
if (!parsed_table && require_table)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!parsed_on_cluster && ParserKeyword{"ON"}.ignore(pos, expected))
|
|
|
|
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
res->cluster = cluster;
|
|
|
|
return true;
|
|
|
|
}
|
2017-08-04 15:54:00 +00:00
|
|
|
|
|
|
|
bool ParserSystemQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected & expected)
|
|
|
|
{
|
2019-12-07 23:05:57 +00:00
|
|
|
if (!ParserKeyword{"SYSTEM"}.ignore(pos, expected))
|
2017-08-04 15:54:00 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
using Type = ASTSystemQuery::Type;
|
|
|
|
|
|
|
|
auto res = std::make_shared<ASTSystemQuery>();
|
|
|
|
|
|
|
|
bool found = false;
|
2017-08-31 12:55:19 +00:00
|
|
|
for (int i = static_cast<int>(Type::UNKNOWN) + 1; i < static_cast<int>(Type::END); ++i)
|
2017-08-04 15:54:00 +00:00
|
|
|
{
|
|
|
|
Type t = static_cast<Type>(i);
|
2019-12-07 23:05:57 +00:00
|
|
|
if (ParserKeyword{ASTSystemQuery::typeToString(t)}.ignore(pos, expected))
|
2017-08-04 15:54:00 +00:00
|
|
|
{
|
|
|
|
res->type = t;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
return false;
|
|
|
|
|
2018-05-21 13:49:54 +00:00
|
|
|
switch (res->type)
|
2017-08-04 15:54:00 +00:00
|
|
|
{
|
2018-05-21 13:49:54 +00:00
|
|
|
case Type::RELOAD_DICTIONARY:
|
2019-12-15 13:48:11 +00:00
|
|
|
{
|
2021-06-20 08:24:43 +00:00
|
|
|
if (!parseQueryWithOnClusterAndMaybeTable(res, pos, expected, /* require table = */ true, /* allow_string_literal = */ true))
|
2018-05-21 13:49:54 +00:00
|
|
|
return false;
|
|
|
|
break;
|
2019-12-15 13:48:11 +00:00
|
|
|
}
|
2021-04-16 09:56:40 +00:00
|
|
|
case Type::RELOAD_MODEL:
|
|
|
|
{
|
|
|
|
String cluster_str;
|
|
|
|
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
|
|
|
{
|
|
|
|
if (!ASTQueryWithOnCluster::parse(pos, cluster_str, expected))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
res->cluster = cluster_str;
|
|
|
|
ASTPtr ast;
|
|
|
|
if (ParserStringLiteral{}.parse(pos, ast, expected))
|
|
|
|
{
|
|
|
|
res->target_model = ast->as<ASTLiteral &>().value.safeGet<String>();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ParserIdentifier model_parser;
|
|
|
|
ASTPtr model;
|
|
|
|
String target_model;
|
|
|
|
|
|
|
|
if (!model_parser.parse(pos, model, expected))
|
|
|
|
return false;
|
2018-05-21 13:49:54 +00:00
|
|
|
|
2021-04-16 09:56:40 +00:00
|
|
|
if (!tryGetIdentifierNameInto(model, res->target_model))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2020-05-17 12:44:22 +00:00
|
|
|
case Type::DROP_REPLICA:
|
|
|
|
{
|
|
|
|
ASTPtr ast;
|
|
|
|
if (!ParserStringLiteral{}.parse(pos, ast, expected))
|
|
|
|
return false;
|
|
|
|
res->replica = ast->as<ASTLiteral &>().value.safeGet<String>();
|
2020-06-05 07:03:51 +00:00
|
|
|
if (ParserKeyword{"FROM"}.ignore(pos, expected))
|
2020-05-17 12:44:22 +00:00
|
|
|
{
|
2020-06-05 07:03:51 +00:00
|
|
|
// way 1. parse replica database
|
|
|
|
// way 2. parse replica tables
|
|
|
|
// way 3. parse replica zkpath
|
|
|
|
if (ParserKeyword{"DATABASE"}.ignore(pos, expected))
|
|
|
|
{
|
|
|
|
ParserIdentifier database_parser;
|
|
|
|
ASTPtr database;
|
|
|
|
if (!database_parser.parse(pos, database, expected))
|
|
|
|
return false;
|
|
|
|
tryGetIdentifierNameInto(database, res->database);
|
|
|
|
}
|
|
|
|
else if (ParserKeyword{"TABLE"}.ignore(pos, expected))
|
|
|
|
{
|
|
|
|
parseDatabaseAndTableName(pos, expected, res->database, res->table);
|
|
|
|
}
|
|
|
|
else if (ParserKeyword{"ZKPATH"}.ignore(pos, expected))
|
|
|
|
{
|
|
|
|
ASTPtr path_ast;
|
|
|
|
if (!ParserStringLiteral{}.parse(pos, path_ast, expected))
|
|
|
|
return false;
|
|
|
|
String zk_path = path_ast->as<ASTLiteral &>().value.safeGet<String>();
|
|
|
|
if (!zk_path.empty() && zk_path[zk_path.size() - 1] == '/')
|
|
|
|
zk_path.pop_back();
|
|
|
|
res->replica_zk_path = zk_path;
|
|
|
|
}
|
|
|
|
else
|
2020-05-17 12:44:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-06-05 07:03:51 +00:00
|
|
|
else
|
|
|
|
res->is_drop_whole_replica = true;
|
2020-05-17 12:44:22 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-05-21 13:49:54 +00:00
|
|
|
case Type::RESTART_REPLICA:
|
|
|
|
case Type::SYNC_REPLICA:
|
2020-06-03 18:51:49 +00:00
|
|
|
if (!parseDatabaseAndTableName(pos, expected, res->database, res->table))
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
|
2021-04-21 09:53:46 +00:00
|
|
|
case Type::RESTART_DISK:
|
|
|
|
{
|
|
|
|
ASTPtr ast;
|
|
|
|
if (ParserIdentifier{}.parse(pos, ast, expected))
|
|
|
|
res->disk = ast->as<ASTIdentifier &>().name();
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-06-20 08:24:43 +00:00
|
|
|
/// FLUSH DISTRIBUTED requires table
|
|
|
|
/// START/STOP DISTRIBUTED SENDS does not require table
|
2020-06-03 18:51:49 +00:00
|
|
|
case Type::STOP_DISTRIBUTED_SENDS:
|
|
|
|
case Type::START_DISTRIBUTED_SENDS:
|
2021-06-20 08:24:43 +00:00
|
|
|
{
|
|
|
|
if (!parseQueryWithOnClusterAndMaybeTable(res, pos, expected, /* require table = */ false, /* allow_string_literal = */ false))
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-05-10 04:19:02 +00:00
|
|
|
case Type::FLUSH_DISTRIBUTED:
|
2021-06-20 08:24:43 +00:00
|
|
|
case Type::RESTORE_REPLICA:
|
2020-06-03 18:51:49 +00:00
|
|
|
{
|
2021-06-20 08:24:43 +00:00
|
|
|
if (!parseQueryWithOnClusterAndMaybeTable(res, pos, expected, /* require table = */ true, /* allow_string_literal = */ false))
|
|
|
|
return false;
|
2018-05-21 13:49:54 +00:00
|
|
|
break;
|
2020-06-03 18:51:49 +00:00
|
|
|
}
|
2018-05-21 13:49:54 +00:00
|
|
|
|
|
|
|
case Type::STOP_MERGES:
|
|
|
|
case Type::START_MERGES:
|
2020-10-20 15:10:24 +00:00
|
|
|
{
|
|
|
|
String storage_policy_str;
|
|
|
|
String volume_str;
|
|
|
|
|
|
|
|
if (ParserKeyword{"ON VOLUME"}.ignore(pos, expected))
|
|
|
|
{
|
|
|
|
ASTPtr ast;
|
|
|
|
if (ParserIdentifier{}.parse(pos, ast, expected))
|
2020-10-24 18:46:10 +00:00
|
|
|
storage_policy_str = ast->as<ASTIdentifier &>().name();
|
2020-10-20 15:10:24 +00:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!ParserToken{TokenType::Dot}.ignore(pos, expected))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (ParserIdentifier{}.parse(pos, ast, expected))
|
2020-10-24 18:46:10 +00:00
|
|
|
volume_str = ast->as<ASTIdentifier &>().name();
|
2020-10-20 15:10:24 +00:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
res->storage_policy = storage_policy_str;
|
|
|
|
res->volume = volume_str;
|
|
|
|
if (res->volume.empty() && res->storage_policy.empty())
|
|
|
|
parseDatabaseAndTableName(pos, expected, res->database, res->table);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-08-01 15:36:12 +00:00
|
|
|
case Type::STOP_TTL_MERGES:
|
|
|
|
case Type::START_TTL_MERGES:
|
2019-09-03 14:50:49 +00:00
|
|
|
case Type::STOP_MOVES:
|
|
|
|
case Type::START_MOVES:
|
2018-05-21 13:49:54 +00:00
|
|
|
case Type::STOP_FETCHES:
|
|
|
|
case Type::START_FETCHES:
|
|
|
|
case Type::STOP_REPLICATED_SENDS:
|
2019-02-02 11:28:43 +00:00
|
|
|
case Type::START_REPLICATED_SENDS:
|
2018-05-21 13:49:54 +00:00
|
|
|
case Type::STOP_REPLICATION_QUEUES:
|
|
|
|
case Type::START_REPLICATION_QUEUES:
|
2019-12-19 09:27:12 +00:00
|
|
|
parseDatabaseAndTableName(pos, expected, res->database, res->table);
|
2018-05-21 13:49:54 +00:00
|
|
|
break;
|
|
|
|
|
2021-01-07 19:19:33 +00:00
|
|
|
case Type::SUSPEND:
|
|
|
|
{
|
|
|
|
ASTPtr seconds;
|
|
|
|
if (!(ParserKeyword{"FOR"}.ignore(pos, expected)
|
|
|
|
&& ParserUnsignedInteger().parse(pos, seconds, expected)
|
|
|
|
&& ParserKeyword{"SECOND"}.ignore(pos, expected))) /// SECOND, not SECONDS to be consistent with INTERVAL parsing in SQL
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
res->seconds = seconds->as<ASTLiteral>()->value.get<UInt64>();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-05-21 13:49:54 +00:00
|
|
|
default:
|
|
|
|
/// There are no [db.table] after COMMAND NAME
|
|
|
|
break;
|
2017-08-04 15:54:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
node = std::move(res);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|