Avoid exponential backtracking in parser, part 2

This commit is contained in:
Alexey Milovidov 2022-01-09 04:28:24 +03:00
parent 1813e7ad35
commit 5ba42d690c
4 changed files with 34 additions and 2 deletions

View File

@ -754,7 +754,10 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
has_all = true;
if (has_all && has_distinct)
{
pos.noBacktrackOnFailure();
return false;
}
if (has_all || has_distinct)
{
@ -772,11 +775,17 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
const char * contents_begin = pos->begin;
if (!contents.parse(pos, expr_list_args, expected))
{
pos.noBacktrackOnFailure();
return false;
}
const char * contents_end = pos->begin;
if (pos->type != TokenType::ClosingRoundBracket)
{
pos.noBacktrackOnFailure();
return false;
}
++pos;
/** Check for a common error case - often due to the complexity of quoting command-line arguments,
@ -809,7 +818,10 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
/// Parametric aggregate functions cannot have DISTINCT in parameters list.
if (has_distinct)
{
pos.noBacktrackOnFailure();
return false;
}
expr_list_params = expr_list_args;
expr_list_args = nullptr;
@ -827,7 +839,10 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
has_all = true;
if (has_all && has_distinct)
{
pos.noBacktrackOnFailure();
return false;
}
if (has_all || has_distinct)
{
@ -841,10 +856,16 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
}
if (!contents.parse(pos, expr_list_args, expected))
{
pos.noBacktrackOnFailure();
return false;
}
if (pos->type != TokenType::ClosingRoundBracket)
{
pos.noBacktrackOnFailure();
return false;
}
++pos;
}
@ -878,6 +899,7 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
ParserFilterClause filter_parser;
if (!filter_parser.parse(pos, function_node_as_iast, expected))
{
pos.noBacktrackOnFailure();
return false;
}
}
@ -891,6 +913,7 @@ bool ParserFunction::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
ParserWindowReference window_reference;
if (!window_reference.parse(pos, function_node_as_iast, expected))
{
pos.noBacktrackOnFailure();
return false;
}
}

View File

@ -59,6 +59,7 @@ public:
{
uint32_t depth = 0;
uint32_t max_depth = 0;
bool no_backtrack_on_failure = false;
Pos(Tokens & tokens_, uint32_t max_depth_) : TokenIterator(tokens_), max_depth(max_depth_) {}
@ -77,6 +78,11 @@ public:
throw Exception("Logical error in parser: incorrect calculation of parse depth", ErrorCodes::LOGICAL_ERROR);
--depth;
}
void noBacktrackOnFailure()
{
no_backtrack_on_failure = true;
}
};
/** Get the text of this parser parses. */

View File

@ -6,6 +6,9 @@ namespace DB
bool IParserBase::parse(Pos & pos, ASTPtr & node, Expected & expected)
{
if (pos.no_backtrack_on_failure)
return false;
expected.add(pos, getName());
return wrapParseImpl(pos, IncreaseDepthTag{}, [&]

View File

@ -16,7 +16,7 @@ public:
{
Pos begin = pos;
bool res = func();
if (!res)
if (!res && !pos.no_backtrack_on_failure)
pos = begin;
return res;
}
@ -30,7 +30,7 @@ public:
pos.increaseDepth();
bool res = func();
pos.decreaseDepth();
if (!res)
if (!res && !pos.no_backtrack_on_failure)
pos = begin;
return res;
}