Use function ParserList::parseUtil() to parse lists more accurately.

This commit is contained in:
Vitaly Baranov 2020-06-06 00:31:37 +03:00
parent a5b70fbdda
commit 6146766465
13 changed files with 578 additions and 408 deletions

View File

@ -76,41 +76,25 @@ const char * ParserTupleElementExpression::operators[] =
bool ParserList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
bool first = true;
ASTs elements;
auto parse_element = [&]
{
ASTPtr element;
if (!elem_parser->parse(pos, element, expected))
return false;
elements.push_back(element);
return true;
};
if (!parseUtil(pos, expected, parse_element, *separator_parser, allow_empty))
return false;
auto list = std::make_shared<ASTExpressionList>(result_separator);
list->children = std::move(elements);
node = list;
while (true)
{
if (first)
{
ASTPtr elem;
if (!elem_parser->parse(pos, elem, expected))
break;
list->children.push_back(elem);
first = false;
}
else
{
auto prev_pos = pos;
if (!separator_parser->ignore(pos, expected))
break;
ASTPtr elem;
if (!elem_parser->parse(pos, elem, expected))
{
pos = prev_pos;
break;
}
list->children.push_back(elem);
}
}
return allow_empty || !first;
return true;
}

View File

@ -26,6 +26,43 @@ public:
, result_separator(result_separator_)
{
}
template <typename F>
static bool parseUtil(Pos & pos, Expected & expected, const F & parse_element, IParser & separator_parser_, bool allow_empty_ = true)
{
Pos begin = pos;
if (!parse_element())
{
pos = begin;
return allow_empty_;
}
while (true)
{
begin = pos;
if (!separator_parser_.ignore(pos, expected) || !parse_element())
{
pos = begin;
return true;
}
}
return false;
}
template <typename F>
static bool parseUtil(Pos & pos, Expected & expected, const F & parse_element, TokenType separator, bool allow_empty_ = true)
{
ParserToken sep_parser{separator};
return parseUtil(pos, expected, parse_element, sep_parser, allow_empty_);
}
template <typename F>
static bool parseUtil(Pos & pos, Expected & expected, const F & parse_element, bool allow_empty_ = true)
{
return parseUtil(pos, expected, parse_element, TokenType::Comma, allow_empty_);
}
protected:
const char * getName() const override { return "list of elements"; }
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;

View File

@ -8,6 +8,7 @@
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ExpressionListParsers.h>
#include <ext/range.h>
#include <boost/algorithm/string/predicate.hpp>
@ -126,17 +127,17 @@ namespace
}
bool parseLimit(IParserBase::Pos & pos, Expected & expected, bool first, bool & max_prefix_encountered, ResourceType & resource_type, ResourceAmount & max)
bool parseLimits(IParserBase::Pos & pos, Expected & expected, std::vector<std::pair<ResourceType, ResourceAmount>> & limits)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!first && !ParserToken{TokenType::Comma}.ignore(pos, expected))
return false;
std::vector<std::pair<ResourceType, ResourceAmount>> res_limits;
bool max_prefix_encountered = false;
auto parse_limit = [&]
{
max_prefix_encountered |= ParserKeyword{"MAX"}.ignore(pos, expected);
ResourceType res_resource_type;
if (!parseResourceType(pos, expected, res_resource_type))
ResourceType resource_type;
if (!parseResourceType(pos, expected, resource_type))
return false;
if (max_prefix_encountered)
@ -149,25 +150,32 @@ namespace
return false;
}
ResourceAmount res_max;
if (!parseMaxAmount(pos, expected, res_resource_type, res_max))
ResourceAmount max;
if (!parseMaxAmount(pos, expected, resource_type, max))
return false;
resource_type = res_resource_type;
max = res_max;
res_limits.emplace_back(resource_type, max);
return true;
});
};
if (!ParserList::parseUtil(pos, expected, parse_limit, false))
return false;
limits = std::move(res_limits);
return true;
}
bool parseIntervalWithLimits(IParserBase::Pos & pos, Expected & expected, ASTCreateQuotaQuery::Limits & limits)
bool parseIntervalsWithLimits(IParserBase::Pos & pos, Expected & expected, std::vector<ASTCreateQuotaQuery::Limits> & all_limits)
{
return IParserBase::wrapParseImpl(pos, [&]
std::vector<ASTCreateQuotaQuery::Limits> res_all_limits;
auto parse_interval_with_limits = [&]
{
ASTCreateQuotaQuery::Limits new_limits;
if (!ParserKeyword{"FOR"}.ignore(pos, expected))
return false;
new_limits.randomize_interval = ParserKeyword{"RANDOMIZED"}.ignore(pos, expected);
ASTCreateQuotaQuery::Limits limits;
limits.randomize_interval = ParserKeyword{"RANDOMIZED"}.ignore(pos, expected);
ParserKeyword{"INTERVAL"}.ignore(pos, expected);
@ -181,53 +189,34 @@ namespace
if (!parseIntervalKind(pos, expected, interval_kind))
return false;
new_limits.duration = std::chrono::seconds(static_cast<UInt64>(num_intervals * interval_kind.toAvgSeconds()));
limits.duration = std::chrono::seconds(static_cast<UInt64>(num_intervals * interval_kind.toAvgSeconds()));
std::vector<std::pair<ResourceType, ResourceAmount>> maxs;
if (ParserKeyword{"NO LIMITS"}.ignore(pos, expected))
{
new_limits.drop = true;
limits.drop = true;
}
else if (ParserKeyword{"TRACKING ONLY"}.ignore(pos, expected))
{
}
else if (parseLimits(pos, expected, maxs))
{
for (const auto & [resource_type, max] : maxs)
limits.max[resource_type] = max;
}
else
{
ResourceType resource_type;
ResourceAmount max;
bool max_prefix_encountered = false;
if (!parseLimit(pos, expected, true, max_prefix_encountered, resource_type, max))
return false;
return false;
new_limits.max[resource_type] = max;
while (parseLimit(pos, expected, false, max_prefix_encountered, resource_type, max))
new_limits.max[resource_type] = max;
}
limits = new_limits;
res_all_limits.emplace_back(std::move(limits));
return true;
});
}
};
bool parseIntervalsWithLimits(IParserBase::Pos & pos, Expected & expected, std::vector<ASTCreateQuotaQuery::Limits> & all_limits)
{
return IParserBase::wrapParseImpl(pos, [&]
{
size_t old_size = all_limits.size();
do
{
ASTCreateQuotaQuery::Limits limits;
if (!parseIntervalWithLimits(pos, expected, limits))
{
all_limits.resize(old_size);
return false;
}
all_limits.push_back(limits);
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
return true;
});
}
if (!ParserList::parseUtil(pos, expected, parse_interval_with_limits, false))
return false;
all_limits = std::move(res_all_limits);
return true;
}
bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)
{

View File

@ -6,6 +6,7 @@
#include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ParserSettingsProfileElement.h>
#include <Parsers/parseUserName.h>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB
@ -23,7 +24,7 @@ namespace
});
}
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTSettingsProfileElements> & settings)
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::vector<std::shared_ptr<ASTSettingsProfileElement>> & settings)
{
return IParserBase::wrapParseImpl(pos, [&]
{
@ -36,10 +37,7 @@ namespace
if (!elements_p.parse(pos, new_settings_ast, expected))
return false;
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
const auto & new_settings = new_settings_ast->as<const ASTSettingsProfileElements &>();
settings->elements.insert(settings->elements.end(), new_settings.elements.begin(), new_settings.elements.end());
settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
return true;
});
}
@ -99,8 +97,14 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
if (alter && new_name.empty() && (names.size() == 1) && parseRenameTo(pos, expected, new_name))
continue;
if (parseSettings(pos, expected, attach_mode, settings))
std::vector<std::shared_ptr<ASTSettingsProfileElement>> new_settings;
if (parseSettings(pos, expected, attach_mode, new_settings))
{
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
boost::range::push_back(settings->elements, std::move(new_settings));
continue;
}
if (cluster.empty() && parseOnCluster(pos, expected, cluster))
continue;

View File

@ -75,6 +75,7 @@ namespace
});
}
void addAllCommands(boost::container::flat_set<std::string_view> & commands)
{
for (auto condition_type : ext::range(MAX_CONDITION_TYPE))
@ -84,44 +85,47 @@ namespace
}
}
bool parseCommands(IParserBase::Pos & pos, Expected & expected, boost::container::flat_set<std::string_view> & commands)
bool parseCommands(IParserBase::Pos & pos, Expected & expected,
boost::container::flat_set<std::string_view> & commands)
{
return IParserBase::wrapParseImpl(pos, [&]
boost::container::flat_set<std::string_view> res_commands;
auto parse_command = [&]
{
if (ParserKeyword{"ALL"}.ignore(pos, expected))
{
addAllCommands(commands);
addAllCommands(res_commands);
return true;
}
boost::container::flat_set<std::string_view> res_commands;
do
for (auto condition_type : ext::range(MAX_CONDITION_TYPE))
{
bool found_keyword = false;
for (auto condition_type : ext::range(MAX_CONDITION_TYPE))
const std::string_view & command = ConditionTypeInfo::get(condition_type).command;
if (ParserKeyword{command.data()}.ignore(pos, expected))
{
const std::string_view & command = ConditionTypeInfo::get(condition_type).command;
if (ParserKeyword{command.data()}.ignore(pos, expected))
{
res_commands.emplace(command);
found_keyword = true;
break;
}
res_commands.emplace(command);
return true;
}
if (!found_keyword)
return false;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
commands = std::move(res_commands);
return true;
});
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_command, false))
return false;
commands = std::move(res_commands);
return true;
}
bool parseForClause(IParserBase::Pos & pos, Expected & expected, bool alter, std::vector<std::pair<ConditionType, ASTPtr>> & conditions)
bool
parseForClauses(IParserBase::Pos & pos, Expected & expected, bool alter, std::vector<std::pair<ConditionType, ASTPtr>> & conditions)
{
return IParserBase::wrapParseImpl(pos, [&]
std::vector<std::pair<ConditionType, ASTPtr>> res_conditions;
auto parse_for_clause = [&]
{
boost::container::flat_set<std::string_view> commands;
@ -158,32 +162,20 @@ namespace
if (commands.count(type_info.command))
{
if (type_info.is_check && check)
conditions.emplace_back(condition_type, *check);
res_conditions.emplace_back(condition_type, *check);
else if (filter)
conditions.emplace_back(condition_type, *filter);
res_conditions.emplace_back(condition_type, *filter);
}
}
return true;
});
}
};
bool parseForClauses(
IParserBase::Pos & pos, Expected & expected, bool alter, std::vector<std::pair<ConditionType, ASTPtr>> & conditions)
{
return IParserBase::wrapParseImpl(pos, [&]
{
std::vector<std::pair<ConditionType, ASTPtr>> res_conditions;
do
{
if (!parseForClause(pos, expected, alter, res_conditions))
return false;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
if (!ParserList::parseUtil(pos, expected, parse_for_clause, false))
return false;
conditions = std::move(res_conditions);
return true;
});
conditions = std::move(res_conditions);
return true;
}
bool parseToRoles(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTRolesOrUsersSet> & roles)

View File

@ -8,6 +8,7 @@
#include <Parsers/ParserRolesOrUsersSet.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/parseIdentifierOrStringLiteral.h>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB
@ -25,7 +26,7 @@ namespace
});
}
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTSettingsProfileElements> & settings)
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::vector<std::shared_ptr<ASTSettingsProfileElement>> & settings)
{
return IParserBase::wrapParseImpl(pos, [&]
{
@ -38,10 +39,7 @@ namespace
if (!elements_p.parse(pos, new_settings_ast, expected))
return false;
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
const auto & new_settings = new_settings_ast->as<const ASTSettingsProfileElements &>();
settings->elements.insert(settings->elements.end(), new_settings.elements.begin(), new_settings.elements.end());
settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
return true;
});
}
@ -51,7 +49,7 @@ namespace
return IParserBase::wrapParseImpl(pos, [&]
{
ASTPtr ast;
if (roles || !ParserKeyword{"TO"}.ignore(pos, expected))
if (!ParserKeyword{"TO"}.ignore(pos, expected))
return false;
ParserRolesOrUsersSet roles_p;
@ -119,8 +117,14 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
if (alter && new_name.empty() && (names.size() == 1) && parseRenameTo(pos, expected, new_name))
continue;
if (parseSettings(pos, expected, attach_mode, settings))
std::vector<std::shared_ptr<ASTSettingsProfileElement>> new_settings;
if (parseSettings(pos, expected, attach_mode, new_settings))
{
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
boost::range::push_back(settings->elements, std::move(new_settings));
continue;
}
if (cluster.empty() && parseOnCluster(pos, expected, cluster))
continue;

View File

@ -14,6 +14,7 @@
#include <Parsers/ParserSettingsProfileElement.h>
#include <ext/range.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
namespace DB
@ -32,7 +33,7 @@ namespace
}
bool parseAuthentication(IParserBase::Pos & pos, Expected & expected, std::optional<Authentication> & authentication)
bool parseAuthentication(IParserBase::Pos & pos, Expected & expected, Authentication & authentication)
{
return IParserBase::wrapParseImpl(pos, [&]
{
@ -96,91 +97,109 @@ namespace
authentication = Authentication{*type};
if (expect_password)
authentication->setPassword(password);
authentication.setPassword(password);
else if (expect_hash)
authentication->setPasswordHashHex(password);
authentication.setPasswordHashHex(password);
return true;
});
}
bool parseHosts(IParserBase::Pos & pos, Expected & expected, const char * prefix, std::optional<AllowedClientHosts> & hosts)
bool parseHostsWithoutPrefix(IParserBase::Pos & pos, Expected & expected, AllowedClientHosts & hosts)
{
AllowedClientHosts res_hosts;
auto parse_host = [&]
{
if (ParserKeyword{"NONE"}.ignore(pos, expected))
return true;
if (ParserKeyword{"ANY"}.ignore(pos, expected))
{
res_hosts.addAnyHost();
return true;
}
if (ParserKeyword{"LOCAL"}.ignore(pos, expected))
{
res_hosts.addLocalHost();
return true;
}
if (ParserKeyword{"REGEXP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_regexp_ast : ast->children)
res_hosts.addNameRegexp(name_regexp_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
if (ParserKeyword{"NAME"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_ast : ast->children)
res_hosts.addName(name_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
if (ParserKeyword{"IP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & subnet_ast : ast->children)
res_hosts.addSubnet(subnet_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
if (ParserKeyword{"LIKE"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & pattern_ast : ast->children)
res_hosts.addLikePattern(pattern_ast->as<const ASTLiteral &>().value.safeGet<String>());
return true;
}
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_host, false))
return false;
hosts = std::move(res_hosts);
return true;
}
bool parseHosts(IParserBase::Pos & pos, Expected & expected, const String & prefix, AllowedClientHosts & hosts)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (prefix && !ParserKeyword{prefix}.ignore(pos, expected))
if (!prefix.empty() && !ParserKeyword{prefix.c_str()}.ignore(pos, expected))
return false;
if (!ParserKeyword{"HOST"}.ignore(pos, expected))
return false;
if (ParserKeyword{"ANY"}.ignore(pos, expected))
{
if (!hosts)
hosts.emplace();
hosts->addAnyHost();
return true;
}
AllowedClientHosts res_hosts;
if (!parseHostsWithoutPrefix(pos, expected, res_hosts))
return false;
if (ParserKeyword{"NONE"}.ignore(pos, expected))
{
if (!hosts)
hosts.emplace();
return true;
}
AllowedClientHosts new_hosts;
do
{
if (ParserKeyword{"LOCAL"}.ignore(pos, expected))
{
new_hosts.addLocalHost();
}
else if (ParserKeyword{"REGEXP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_regexp_ast : ast->children)
new_hosts.addNameRegexp(name_regexp_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else if (ParserKeyword{"NAME"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & name_ast : ast->children)
new_hosts.addName(name_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else if (ParserKeyword{"IP"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & subnet_ast : ast->children)
new_hosts.addSubnet(subnet_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else if (ParserKeyword{"LIKE"}.ignore(pos, expected))
{
ASTPtr ast;
if (!ParserList{std::make_unique<ParserStringLiteral>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
for (const auto & pattern_ast : ast->children)
new_hosts.addLikePattern(pattern_ast->as<const ASTLiteral &>().value.safeGet<String>());
}
else
return false;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
if (!hosts)
hosts.emplace();
hosts->add(new_hosts);
hosts.add(std::move(res_hosts));
return true;
});
}
@ -206,7 +225,7 @@ namespace
}
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::shared_ptr<ASTSettingsProfileElements> & settings)
bool parseSettings(IParserBase::Pos & pos, Expected & expected, bool id_mode, std::vector<std::shared_ptr<ASTSettingsProfileElement>> & settings)
{
return IParserBase::wrapParseImpl(pos, [&]
{
@ -215,14 +234,11 @@ namespace
ASTPtr new_settings_ast;
ParserSettingsProfileElements elements_p;
elements_p.useInheritKeyword(true).useIDMode(id_mode);
elements_p.useIDMode(id_mode);
if (!elements_p.parse(pos, new_settings_ast, expected))
return false;
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
const auto & new_settings = new_settings_ast->as<const ASTSettingsProfileElements &>();
settings->elements.insert(settings->elements.end(), new_settings.elements.begin(), new_settings.elements.end());
settings = std::move(new_settings_ast->as<const ASTSettingsProfileElements &>().elements);
return true;
});
}
@ -286,14 +302,33 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
while (true)
{
if (!authentication && parseAuthentication(pos, expected, authentication))
continue;
if (!authentication)
{
Authentication new_authentication;
if (parseAuthentication(pos, expected, new_authentication))
{
authentication = std::move(new_authentication);
continue;
}
}
if (parseHosts(pos, expected, nullptr, hosts))
AllowedClientHosts new_hosts;
if (parseHosts(pos, expected, "", new_hosts))
{
if (!hosts)
hosts.emplace();
hosts->add(new_hosts);
continue;
}
if (parseSettings(pos, expected, attach_mode, settings))
std::vector<std::shared_ptr<ASTSettingsProfileElement>> new_settings;
if (parseSettings(pos, expected, attach_mode, new_settings))
{
if (!settings)
settings = std::make_shared<ASTSettingsProfileElements>();
boost::range::push_back(settings->elements, std::move(new_settings));
continue;
}
if (!default_roles && parseDefaultRoles(pos, expected, attach_mode, default_roles))
continue;
@ -306,8 +341,21 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
if (new_name.empty() && (names->size() == 1) && parseRenameTo(pos, expected, new_name))
continue;
if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "DROP", remove_hosts))
if (parseHosts(pos, expected, "ADD", new_hosts))
{
if (!add_hosts)
add_hosts.emplace();
add_hosts->add(new_hosts);
continue;
}
if (parseHosts(pos, expected, "DROP", new_hosts))
{
if (!remove_hosts)
remove_hosts.emplace();
remove_hosts->add(new_hosts);
continue;
}
}
break;

View File

@ -2,8 +2,11 @@
#include <Parsers/ASTGrantQuery.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTIdentifier.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ParserRolesOrUsersSet.h>
#include <boost/algorithm/string/predicate.hpp>
@ -66,15 +69,13 @@ namespace
if (!ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected))
return false;
ASTPtr ast;
if (!ParserList{std::make_unique<ParserIdentifier>(), std::make_unique<ParserToken>(TokenType::Comma), false}.parse(pos, ast, expected))
return false;
Strings res_columns;
do
{
ASTPtr column_ast;
if (!ParserIdentifier().parse(pos, column_ast, expected))
return false;
res_columns.emplace_back(getIdentifierName(column_ast));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
for (const auto & child : ast->children)
res_columns.emplace_back(getIdentifierName(child));
if (!ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected))
return false;
@ -150,25 +151,42 @@ namespace
}
bool parseAccessTypesWithColumns(IParser::Pos & pos, Expected & expected,
std::vector<std::pair<AccessFlags, Strings>> & access_and_columns)
{
std::vector<std::pair<AccessFlags, Strings>> res;
auto parse_access_and_columns = [&]
{
AccessFlags access_flags;
if (!parseAccessFlags(pos, expected, access_flags))
return false;
Strings columns;
parseColumnNames(pos, expected, columns);
res.emplace_back(access_flags, std::move(columns));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_access_and_columns, false))
return false;
access_and_columns = std::move(res);
return true;
}
bool parseAccessRightsElements(IParser::Pos & pos, Expected & expected, AccessRightsElements & elements)
{
return IParserBase::wrapParseImpl(pos, [&]
{
AccessRightsElements res_elements;
do
auto parse_around_on = [&]
{
std::vector<std::pair<AccessFlags, Strings>> access_and_columns;
do
{
AccessFlags access_flags;
if (!parseAccessFlags(pos, expected, access_flags))
return false;
Strings columns;
parseColumnNames(pos, expected, columns);
access_and_columns.emplace_back(access_flags, std::move(columns));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
if (!parseAccessTypesWithColumns(pos, expected, access_and_columns))
return false;
if (!ParserKeyword{"ON"}.ignore(pos, expected))
return false;
@ -190,8 +208,12 @@ namespace
element.table = table_name;
res_elements.emplace_back(std::move(element));
}
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_around_on, false))
return false;
elements = std::move(res_elements);
return true;

View File

@ -4,6 +4,7 @@
#include <Parsers/ASTLiteral.h>
#include <Parsers/ASTRolesOrUsersSet.h>
#include <Parsers/parseUserName.h>
#include <Parsers/ExpressionListParsers.h>
#include <boost/range/algorithm/find.hpp>
@ -11,11 +12,15 @@ namespace DB
{
namespace
{
bool parseRoleNameOrID(IParserBase::Pos & pos, Expected & expected, bool parse_id, String & res)
bool parseRoleNameOrID(
IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
String & res)
{
return IParserBase::wrapParseImpl(pos, [&]
{
if (!parse_id)
if (!id_mode)
return parseRoleName(pos, expected, res);
if (!ParserKeyword{"ID"}.ignore(pos, expected))
@ -40,60 +45,56 @@ namespace
Expected & expected,
bool id_mode,
bool allow_all,
bool allow_current_user_tag,
bool allow_current_user,
Strings & names,
bool & all,
bool & current_user)
{
return IParserBase::wrapParseImpl(pos, [&]
{
bool res_all = false;
bool res_current_user = false;
Strings res_names;
while (true)
{
if (ParserKeyword{"NONE"}.ignore(pos, expected))
{
}
else if (
allow_current_user_tag
&& (ParserKeyword{"CURRENT_USER"}.ignore(pos, expected) || ParserKeyword{"currentUser"}.ignore(pos, expected)))
{
if (ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected))
{
if (!ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected))
return false;
}
res_current_user = true;
}
else if (allow_all && ParserKeyword{"ALL"}.ignore(pos, expected))
{
res_all = true;
}
else
{
String name;
if (!parseRoleNameOrID(pos, expected, id_mode, name))
return false;
res_names.push_back(name);
}
bool res_all = false;
bool res_current_user = false;
Strings res_names;
if (!ParserToken{TokenType::Comma}.ignore(pos, expected))
break;
auto parse_element = [&]
{
if (ParserKeyword{"NONE"}.ignore(pos, expected))
return true;
if (allow_all && ParserKeyword{"ALL"}.ignore(pos, expected))
{
res_all = true;
return true;
}
all = res_all;
current_user = res_current_user;
names = std::move(res_names);
return true;
});
if (allow_current_user && parseCurrentUserTag(pos, expected))
{
res_current_user = true;
return true;
}
String name;
if (parseRoleNameOrID(pos, expected, id_mode, name))
{
res_names.emplace_back(std::move(name));
return true;
}
return false;
};
if (!ParserList::parseUtil(pos, expected, parse_element, false))
return false;
names = std::move(res_names);
all = res_all;
current_user = res_current_user;
return true;
}
bool parseExceptAndAfterExcept(
IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
bool allow_current_user_tag,
bool allow_current_user,
Strings & except_names,
bool & except_current_user)
{
@ -102,8 +103,8 @@ namespace
if (!ParserKeyword{"EXCEPT"}.ignore(pos, expected))
return false;
bool dummy;
return parseBeforeExcept(pos, expected, id_mode, false, allow_current_user_tag, except_names, dummy, except_current_user);
bool unused;
return parseBeforeExcept(pos, expected, id_mode, false, allow_current_user, except_names, unused, except_current_user);
});
}
}

View File

@ -4,6 +4,7 @@
#include <Parsers/parseDatabaseAndTableName.h>
#include <Parsers/ASTQueryWithOnCluster.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <boost/range/algorithm_ext/push_back.hpp>
@ -67,21 +68,18 @@ namespace
return false;
std::vector<std::pair<String, String>> res;
std::optional<IParser::Pos> pos_before_comma;
do
auto parse_db_and_table_name = [&]
{
String database, table_name;
if (!parseDBAndTableName(pos, expected, database, table_name))
{
if (!pos_before_comma)
return false;
pos = *pos_before_comma;
break;
}
return false;
res.emplace_back(std::move(database), std::move(table_name));
pos_before_comma = pos;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_db_and_table_name, false))
return false;
database_and_table_names = std::move(res);
return true;
@ -165,21 +163,28 @@ bool ParserRowPolicyName::parseImpl(Pos & pos, ASTPtr & node, Expected & expecte
bool ParserRowPolicyNames::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
std::vector<RowPolicy::NameParts> name_parts;
size_t num_added_names_last_time = 0;
String cluster;
do
auto parse_around_on = [&]
{
std::vector<RowPolicy::NameParts> new_name_parts;
if (!parseRowPolicyNamesAroundON(pos, expected, name_parts.empty(), name_parts.empty(), allow_on_cluster, new_name_parts, cluster))
return false;
if (!name_parts.empty())
{
if ((num_added_names_last_time != 1) || !cluster.empty())
return false;
}
size_t num_new_name_parts = new_name_parts.size();
assert(num_new_name_parts >= 1);
boost::range::push_back(name_parts, std::move(new_name_parts));
if ((num_new_name_parts != 1) || !cluster.empty())
break;
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
std::vector<RowPolicy::NameParts> new_name_parts;
if (!parseRowPolicyNamesAroundON(pos, expected, name_parts.empty(), name_parts.empty(), allow_on_cluster, new_name_parts, cluster))
return false;
num_added_names_last_time = new_name_parts.size();
boost::range::push_back(name_parts, std::move(new_name_parts));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_around_on, false))
return false;
auto result = std::make_shared<ASTRowPolicyNames>();
result->name_parts = std::move(name_parts);

View File

@ -1,5 +1,6 @@
#include <Parsers/ParserSettingsProfileElement.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/ExpressionElementParsers.h>
#include <Parsers/ASTSettingsProfileElement.h>
#include <Parsers/ASTLiteral.h>
@ -11,12 +12,19 @@ namespace DB
{
namespace
{
bool parseProfileNameOrID(IParserBase::Pos & pos, Expected & expected, bool parse_id, String & res)
bool parseProfileKeyword(IParserBase::Pos & pos, Expected & expected, bool use_inherit_keyword)
{
return ParserKeyword{"PROFILE"}.ignore(pos, expected) ||
(use_inherit_keyword && ParserKeyword{"INHERIT"}.ignore(pos, expected));
}
bool parseProfileNameOrID(IParserBase::Pos & pos, Expected & expected, bool id_mode, String & res)
{
return IParserBase::wrapParseImpl(pos, [&]
{
ASTPtr ast;
if (!parse_id)
if (!id_mode)
return parseIdentifierOrStringLiteral(pos, expected, res);
if (!ParserKeyword{"ID"}.ignore(pos, expected))
@ -96,52 +104,98 @@ namespace
return false;
});
}
bool parseSettingNameWithValueOrConstraints(
IParserBase::Pos & pos,
Expected & expected,
String & setting_name,
Field & value,
Field & min_value,
Field & max_value,
std::optional<bool> & readonly)
{
return IParserBase::wrapParseImpl(pos, [&]
{
ASTPtr name_ast;
if (!ParserIdentifier{}.parse(pos, name_ast, expected))
return false;
String res_setting_name = getIdentifierName(name_ast);
Field res_value;
Field res_min_value;
Field res_max_value;
std::optional<bool> res_readonly;
bool has_value_or_constraint = false;
while (parseValue(pos, expected, res_value) || parseMinMaxValue(pos, expected, res_min_value, res_max_value)
|| parseReadonlyOrWritableKeyword(pos, expected, res_readonly))
{
has_value_or_constraint = true;
}
if (!has_value_or_constraint)
return false;
setting_name = std::move(res_setting_name);
value = std::move(res_value);
min_value = std::move(res_min_value);
max_value = std::move(res_max_value);
readonly = res_readonly;
return true;
});
}
bool parseSettingsProfileElement(IParserBase::Pos & pos,
Expected & expected,
bool id_mode,
bool use_inherit_keyword,
bool previous_element_was_parent_profile,
std::shared_ptr<ASTSettingsProfileElement> & result)
{
return IParserBase::wrapParseImpl(pos, [&]
{
String parent_profile;
String setting_name;
Field value;
Field min_value;
Field max_value;
std::optional<bool> readonly;
if (parseSettingNameWithValueOrConstraints(pos, expected, setting_name, value, min_value, max_value, readonly))
{
}
else if (parseProfileKeyword(pos, expected, use_inherit_keyword) || previous_element_was_parent_profile)
{
if (!parseProfileNameOrID(pos, expected, id_mode, parent_profile))
return false;
}
else
return false;
result = std::make_shared<ASTSettingsProfileElement>();
result->parent_profile = std::move(parent_profile);
result->setting_name = std::move(setting_name);
result->value = std::move(value);
result->min_value = std::move(min_value);
result->max_value = std::move(max_value);
result->readonly = readonly;
result->id_mode = id_mode;
result->use_inherit_keyword = use_inherit_keyword;
return true;
});
}
}
bool ParserSettingsProfileElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
String parent_profile;
String setting_name;
Field value;
Field min_value;
Field max_value;
std::optional<bool> readonly;
std::shared_ptr<ASTSettingsProfileElement> res;
if (!parseSettingsProfileElement(pos, expected, id_mode, use_inherit_keyword, false, res))
return false;
if (ParserKeyword{"PROFILE"}.ignore(pos, expected) ||
(use_inherit_keyword && ParserKeyword{"INHERIT"}.ignore(pos, expected)))
{
if (!parseProfileNameOrID(pos, expected, id_mode, parent_profile))
return false;
}
else
{
ASTPtr name_ast;
if (!ParserIdentifier{}.parse(pos, name_ast, expected))
return false;
setting_name = getIdentifierName(name_ast);
bool has_value_or_constraint = false;
while (parseValue(pos, expected, value) || parseMinMaxValue(pos, expected, min_value, max_value)
|| parseReadonlyOrWritableKeyword(pos, expected, readonly))
{
has_value_or_constraint = true;
}
if (!has_value_or_constraint)
return false;
}
auto result = std::make_shared<ASTSettingsProfileElement>();
result->parent_profile = std::move(parent_profile);
result->setting_name = std::move(setting_name);
result->value = std::move(value);
result->min_value = std::move(min_value);
result->max_value = std::move(max_value);
result->readonly = readonly;
result->id_mode = id_mode;
result->use_inherit_keyword = use_inherit_keyword;
node = result;
node = res;
return true;
}
@ -155,17 +209,21 @@ bool ParserSettingsProfileElements::parseImpl(Pos & pos, ASTPtr & node, Expected
}
else
{
ParserSettingsProfileElement element_p;
element_p.useIDMode(id_mode).useInheritKeyword(use_inherit_keyword);
do
bool previous_element_was_parent_profile = false;
auto parse_element = [&]
{
ASTPtr ast;
if (!element_p.parse(pos, ast, expected))
std::shared_ptr<ASTSettingsProfileElement> element;
if (!parseSettingsProfileElement(pos, expected, id_mode, use_inherit_keyword, previous_element_was_parent_profile, element))
return false;
auto element = typeid_cast<std::shared_ptr<ASTSettingsProfileElement>>(ast);
elements.push_back(std::move(element));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
elements.push_back(element);
previous_element_was_parent_profile = !element->parent_profile.empty();
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_element, false))
return false;
}
auto result = std::make_shared<ASTSettingsProfileElements>();

View File

@ -1,35 +1,52 @@
#include <Parsers/ParserUserNameWithHost.h>
#include <Parsers/ASTUserNameWithHost.h>
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Parsers/parseIdentifierOrStringLiteral.h>
#include <boost/algorithm/string.hpp>
namespace DB
{
namespace
{
bool parseUserNameWithHost(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTUserNameWithHost> & ast)
{
return IParserBase::wrapParseImpl(pos, [&]
{
String base_name;
if (!parseIdentifierOrStringLiteral(pos, expected, base_name))
return false;
boost::algorithm::trim(base_name);
String host_pattern;
if (ParserToken{TokenType::At}.ignore(pos, expected))
{
if (!parseIdentifierOrStringLiteral(pos, expected, host_pattern))
return false;
boost::algorithm::trim(host_pattern);
if (host_pattern == "%")
host_pattern.clear();
}
ast = std::make_shared<ASTUserNameWithHost>();
ast->base_name = std::move(base_name);
ast->host_pattern = std::move(host_pattern);
return true;
});
}
}
bool ParserUserNameWithHost::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
String base_name;
if (!parseIdentifierOrStringLiteral(pos, expected, base_name))
std::shared_ptr<ASTUserNameWithHost> res;
if (!parseUserNameWithHost(pos, expected, res))
return false;
boost::algorithm::trim(base_name);
String host_pattern;
if (ParserToken{TokenType::At}.ignore(pos, expected))
{
if (!parseIdentifierOrStringLiteral(pos, expected, host_pattern))
return false;
boost::algorithm::trim(host_pattern);
if (host_pattern == "%")
host_pattern.clear();
}
auto result = std::make_shared<ASTUserNameWithHost>();
result->base_name = std::move(base_name);
result->host_pattern = std::move(host_pattern);
node = result;
node = res;
return true;
}
@ -37,15 +54,19 @@ bool ParserUserNameWithHost::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
bool ParserUserNamesWithHost::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
{
std::vector<std::shared_ptr<ASTUserNameWithHost>> names;
do
auto parse_single_name = [&]
{
ASTPtr ast;
if (!ParserUserNameWithHost{}.parse(pos, ast, expected))
std::shared_ptr<ASTUserNameWithHost> ast;
if (!parseUserNameWithHost(pos, expected, ast))
return false;
names.emplace_back(typeid_cast<std::shared_ptr<ASTUserNameWithHost>>(ast));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
names.emplace_back(std::move(ast));
return true;
};
if (!ParserList::parseUtil(pos, expected, parse_single_name, false))
return false;
auto result = std::make_shared<ASTUserNamesWithHost>();
result->names = std::move(names);

View File

@ -4,47 +4,52 @@
#include "ASTLiteral.h"
#include "ASTIdentifier.h"
#include <Parsers/CommonParsers.h>
#include <Parsers/ExpressionListParsers.h>
#include <Common/typeid_cast.h>
namespace DB
{
bool parseIdentifierOrStringLiteral(IParser::Pos & pos, Expected & expected, String & result)
{
ASTPtr res;
if (!ParserIdentifier().parse(pos, res, expected))
return IParserBase::wrapParseImpl(pos, [&]
{
if (!ParserStringLiteral().parse(pos, res, expected))
return false;
ASTPtr ast;
if (ParserIdentifier().parse(pos, ast, expected))
{
result = getIdentifierName(ast);
return true;
}
result = res->as<ASTLiteral &>().value.safeGet<String>();
}
else
result = getIdentifierName(res);
if (ParserStringLiteral().parse(pos, ast, expected))
{
result = ast->as<ASTLiteral &>().value.safeGet<String>();
return true;
}
return true;
return false;
});
}
bool parseIdentifiersOrStringLiterals(IParser::Pos & pos, Expected & expected, Strings & result)
{
return IParserBase::wrapParseImpl(pos, [&]
Strings res;
auto parse_single_id_or_literal = [&]
{
Strings strs;
do
{
String str;
if (!parseIdentifierOrStringLiteral(pos, expected, str))
return false;
String str;
if (!parseIdentifierOrStringLiteral(pos, expected, str))
return false;
strs.push_back(std::move(str));
}
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
result = std::move(strs);
res.emplace_back(std::move(str));
return true;
});
};
if (!ParserList::parseUtil(pos, expected, parse_single_id_or_literal, false))
return false;
result = std::move(res);
return true;
}
}