Merge pull request #25913 from vitlibar/fix-crash-on-dictget-with-bad-argument

Fix crash on call dictGet() with bad arguments.
This commit is contained in:
alexey-milovidov 2021-07-03 04:53:23 +03:00 committed by GitHub
commit ca063c3a70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 20 deletions

View File

@ -11,6 +11,26 @@
namespace DB
{
namespace
{
void replaceArgumentWithTableIdentifierIfNotAlias(ASTFunction & func, size_t argument_pos, const Aliases & aliases)
{
if (!func.arguments || (func.arguments->children.size() <= argument_pos))
return;
auto arg = func.arguments->children[argument_pos];
auto identifier = arg->as<ASTIdentifier>();
if (!identifier)
return;
if (aliases.contains(identifier->name()))
return;
auto table_identifier = identifier->createTable();
if (!table_identifier)
return;
func.arguments->children[argument_pos] = table_identifier;
}
}
bool MarkTableIdentifiersMatcher::needChildVisit(ASTPtr & node, const ASTPtr & child)
{
if (child->as<ASTSelectQuery>())
@ -23,37 +43,22 @@ bool MarkTableIdentifiersMatcher::needChildVisit(ASTPtr & node, const ASTPtr & c
void MarkTableIdentifiersMatcher::visit(ASTPtr & ast, Data & data)
{
if (auto * node_func = ast->as<ASTFunction>())
visit(*node_func, ast, data);
visit(*node_func, data);
}
void MarkTableIdentifiersMatcher::visit(const ASTFunction & func, ASTPtr & ptr, Data & data)
void MarkTableIdentifiersMatcher::visit(ASTFunction & func, const Data & data)
{
/// `IN t` can be specified, where t is a table, which is equivalent to `IN (SELECT * FROM t)`.
if (checkFunctionIsInOrGlobalInOperator(func))
{
auto ast = func.arguments->children.at(1);
auto opt_name = tryGetIdentifierName(ast);
if (opt_name && !data.aliases.count(*opt_name) && ast->as<ASTIdentifier>())
{
ptr->as<ASTFunction>()->arguments->children[1] = ast->as<ASTIdentifier>()->createTable();
assert(ptr->as<ASTFunction>()->arguments->children[1]);
}
replaceArgumentWithTableIdentifierIfNotAlias(func, 1, data.aliases);
}
// First argument of joinGet can be a table name, perhaps with a database.
// First argument of dictGet can be a dictionary name, perhaps with a database.
else if (functionIsJoinGet(func.name) || functionIsDictGet(func.name))
{
if (!func.arguments || func.arguments->children.empty())
return;
auto ast = func.arguments->children.at(0);
auto opt_name = tryGetIdentifierName(ast);
if (opt_name && !data.aliases.count(*opt_name) && ast->as<ASTIdentifier>())
{
ptr->as<ASTFunction>()->arguments->children[0] = ast->as<ASTIdentifier>()->createTable();
assert(ptr->as<ASTFunction>()->arguments->children[0]);
}
replaceArgumentWithTableIdentifierIfNotAlias(func, 0, data.aliases);
}
}

View File

@ -24,7 +24,7 @@ public:
static void visit(ASTPtr & ast, Data & data);
private:
static void visit(const ASTFunction & func, ASTPtr &, Data &);
static void visit(ASTFunction & func, const Data & data);
};
using MarkTableIdentifiersVisitor = MarkTableIdentifiersMatcher::Visitor;

View File

@ -0,0 +1,7 @@
SELECT dictGet(t.nest.a, concat(currentDatabase(), '.dict.dict'), 's', number) FROM numbers(5); -- { serverError 47 }
SELECT dictGetFloat64(t.b.s, 'database_for_dict.dict1', dictGetFloat64('Ta\0', toUInt64('databas\0_for_dict.dict1databas\0_for_dict.dict1', dictGetFloat64('', '', toUInt64(1048577), toDate(NULL)), NULL), toDate(dictGetFloat64(257, 'database_for_dict.dict1database_for_dict.dict1', '', toUInt64(NULL), 2, toDate(NULL)), '2019-05-2\0')), NULL, toUInt64(dictGetFloat64('', '', toUInt64(-9223372036854775808), toDate(NULL)), NULL)); -- { serverError 47 }
SELECT NULL AND (2147483648 AND NULL) AND -2147483647, toUUID(((1048576 AND NULL) AND (2147483647 AND 257 AND NULL AND -2147483649) AND NULL) IN (test_01103.t1_distr.id), '00000000-e1fe-11e\0-bb8f\0853d60c00749'), stringToH3('89184926cc3ffff89184926cc3ffff89184926cc3ffff89184926cc3ffff89184926cc3ffff89184926cc3ffff89184926cc3ffff89184926cc3ffff'); -- { serverError 47 }
SELECT 'still alive';