mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-30 19:42:00 +00:00
AST fuzzer support fuzzing SELECT query to EXPLAIN query randomly
This commit is contained in:
parent
455e55c6ea
commit
db7582e060
@ -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()))
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user