AST fuzzer support fuzzing SELECT query to EXPLAIN query randomly

This commit is contained in:
flynn 2023-03-21 14:26:39 +00:00
parent 455e55c6ea
commit db7582e060
2 changed files with 64 additions and 45 deletions

View File

@ -24,7 +24,6 @@
#include <IO/Operators.h> #include <IO/Operators.h>
#include <IO/UseSSL.h> #include <IO/UseSSL.h>
#include <IO/WriteBufferFromOStream.h> #include <IO/WriteBufferFromOStream.h>
#include <Parsers/ASTExplainQuery.h>
#include <Parsers/ASTExpressionList.h> #include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTFunction.h> #include <Parsers/ASTFunction.h>
#include <Parsers/ASTIdentifier.h> #include <Parsers/ASTIdentifier.h>
@ -684,43 +683,75 @@ void QueryFuzzer::fuzzTableName(ASTTableExpression & table)
void QueryFuzzer::fuzzExplainQuery(ASTExplainQuery & explain) void QueryFuzzer::fuzzExplainQuery(ASTExplainQuery & explain)
{ {
/// Fuzz ExplainKind explain.setExplainKind(fuzzExplainKind(explain.getKind()));
bool settings_have_fuzzed = false;
for (auto & child : explain.children)
{
if (auto * settings_ast = typeid_cast<ASTSetQuery *>(child.get()))
{
fuzzExplainSettings(*settings_ast, explain.getKind());
settings_have_fuzzed = true;
}
/// Fuzzing other child like Explain Query
else
{
fuzz(child);
}
}
if (!settings_have_fuzzed)
{
auto settings_ast = std::make_shared<ASTSetQuery>();
fuzzExplainSettings(*settings_ast, explain.getKind());
explain.setSettings(settings_ast);
}
}
ASTExplainQuery::ExplainKind QueryFuzzer::fuzzExplainKind(ASTExplainQuery::ExplainKind kind)
{
if (fuzz_rand() % 20 == 0) if (fuzz_rand() % 20 == 0)
{ {
/// Do not modify ExplainKind return kind;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::ParsedAST); return ASTExplainQuery::ExplainKind::ParsedAST;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::AnalyzedSyntax); return ASTExplainQuery::ExplainKind::AnalyzedSyntax;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::QueryTree); return ASTExplainQuery::ExplainKind::QueryTree;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::QueryPlan); return ASTExplainQuery::ExplainKind::QueryPlan;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::QueryPipeline); return ASTExplainQuery::ExplainKind::QueryPipeline;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::QueryEstimates); return ASTExplainQuery::ExplainKind::QueryEstimates;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::TableOverride); return ASTExplainQuery::ExplainKind::TableOverride;
} }
else if (fuzz_rand() % 11 == 0) else if (fuzz_rand() % 11 == 0)
{ {
explain.setExplainKind(ASTExplainQuery::ExplainKind::CurrentTransaction); return ASTExplainQuery::ExplainKind::CurrentTransaction;
} }
return kind;
}
void QueryFuzzer::fuzzExplainSettings(ASTSetQuery & settings_ast, ASTExplainQuery::ExplainKind kind)
{
auto & changes = settings_ast.changes;
static const std::unordered_map<ASTExplainQuery::ExplainKind, std::vector<String>> settings_by_kind static const std::unordered_map<ASTExplainQuery::ExplainKind, std::vector<String>> settings_by_kind
= {{ASTExplainQuery::ExplainKind::ParsedAST, {"graph", "optimize"}}, = {{ASTExplainQuery::ExplainKind::ParsedAST, {"graph", "optimize"}},
@ -732,44 +763,17 @@ void QueryFuzzer::fuzzExplainQuery(ASTExplainQuery & explain)
{ASTExplainQuery::ExplainKind::TableOverride, {}}, {ASTExplainQuery::ExplainKind::TableOverride, {}},
{ASTExplainQuery::ExplainKind::CurrentTransaction, {}}}; {ASTExplainQuery::ExplainKind::CurrentTransaction, {}}};
const auto & settings = settings_by_kind.at(explain.getKind()); const auto & settings = settings_by_kind.at(kind);
bool settings_have_fuzzed = false;
for (auto & child : explain.children)
{
if (auto * settings_ast = typeid_cast<ASTSetQuery *>(child.get()))
{
fuzzExplainSettings(*settings_ast, settings);
settings_have_fuzzed = true;
}
/// Fuzz other child like Explain Query
else
{
fuzz(child);
}
}
if (!settings_have_fuzzed && !settings.empty())
{
auto settings_ast = std::make_shared<ASTSetQuery>();
fuzzExplainSettings(*settings_ast, settings);
explain.setSettings(settings_ast);
}
}
void QueryFuzzer::fuzzExplainSettings(ASTSetQuery & settings, const std::vector<String> & names)
{
auto & changes = settings.changes;
if (fuzz_rand() % 50 == 0 && !changes.empty()) if (fuzz_rand() % 50 == 0 && !changes.empty())
{ {
changes.erase(changes.begin() + fuzz_rand() % changes.size()); changes.erase(changes.begin() + fuzz_rand() % changes.size());
} }
for (const auto & name : names) for (const auto & setting : settings)
{ {
if (fuzz_rand() % 5 == 0) if (fuzz_rand() % 5 == 0)
{ {
changes.emplace_back(name, true); changes.emplace_back(setting, true);
} }
} }
} }
@ -910,6 +914,20 @@ void QueryFuzzer::fuzz(ASTPtr & ast)
if (auto * with_union = typeid_cast<ASTSelectWithUnionQuery *>(ast.get())) if (auto * with_union = typeid_cast<ASTSelectWithUnionQuery *>(ast.get()))
{ {
fuzz(with_union->list_of_selects); fuzz(with_union->list_of_selects);
/// Fuzzing SELECT query to EXPLAIN query randomly
if (fuzz_rand() % 20 == 0)
{
auto explain = std::make_shared<ASTExplainQuery>();
explain->setExplainKind(fuzzExplainKind());
auto settings_ast = std::make_shared<ASTSetQuery>();
fuzzExplainSettings(*settings_ast, explain->getKind());
explain->setSettings(settings_ast);
explain->setExplainedQuery(ast);
ast = explain;
}
} }
else if (auto * with_intersect_except = typeid_cast<ASTSelectIntersectExceptQuery *>(ast.get())) else if (auto * with_intersect_except = typeid_cast<ASTSelectIntersectExceptQuery *>(ast.get()))
{ {

View File

@ -7,10 +7,11 @@
#include <pcg-random/pcg_random.hpp> #include <pcg-random/pcg_random.hpp>
#include <Core/Field.h>
#include <Parsers/ASTExplainQuery.h>
#include <Parsers/IAST.h>
#include <Common/randomSeed.h> #include <Common/randomSeed.h>
#include "Parsers/IAST_fwd.h" #include "Parsers/IAST_fwd.h"
#include <Core/Field.h>
#include <Parsers/IAST.h>
namespace DB namespace DB
@ -22,7 +23,6 @@ class ASTCreateQuery;
class ASTInsertQuery; class ASTInsertQuery;
class ASTColumnDeclaration; class ASTColumnDeclaration;
class ASTDropQuery; class ASTDropQuery;
class ASTExplainQuery;
class ASTSetQuery; class ASTSetQuery;
struct ASTTableExpression; struct ASTTableExpression;
struct ASTWindowDefinition; struct ASTWindowDefinition;
@ -89,7 +89,8 @@ struct QueryFuzzer
void fuzzWindowFrame(ASTWindowDefinition & def); void fuzzWindowFrame(ASTWindowDefinition & def);
void fuzzCreateQuery(ASTCreateQuery & create); void fuzzCreateQuery(ASTCreateQuery & create);
void fuzzExplainQuery(ASTExplainQuery & explain); void fuzzExplainQuery(ASTExplainQuery & explain);
void fuzzExplainSettings(ASTSetQuery & settings, const std::vector<String> & names); ASTExplainQuery::ExplainKind fuzzExplainKind(ASTExplainQuery::ExplainKind kind = ASTExplainQuery::ExplainKind::QueryPipeline);
void fuzzExplainSettings(ASTSetQuery & settings_ast, ASTExplainQuery::ExplainKind kind);
void fuzzColumnDeclaration(ASTColumnDeclaration & column); void fuzzColumnDeclaration(ASTColumnDeclaration & column);
void fuzzTableName(ASTTableExpression & table); void fuzzTableName(ASTTableExpression & table);
void fuzz(ASTs & asts); void fuzz(ASTs & asts);