| 2023 | |
| 2024 | |
| 2025 | static void executeASTFuzzerQueries(const ASTPtr & ast, const ContextMutablePtr & context, Float64 ast_fuzzer_runs_value, bool any_query) |
| 2026 | { |
| 2027 | if (!any_query && !isReadOnlyQuery(ast)) |
| 2028 | return; |
| 2029 | |
| 2030 | size_t num_runs = static_cast<size_t>(ast_fuzzer_runs_value); |
| 2031 | double fractional = ast_fuzzer_runs_value - static_cast<double>(num_runs); |
| 2032 | if (fractional > 0) |
| 2033 | { |
| 2034 | std::bernoulli_distribution dist(fractional); |
| 2035 | if (dist(thread_local_rng)) |
| 2036 | ++num_runs; |
| 2037 | } |
| 2038 | |
| 2039 | if (num_runs == 0) |
| 2040 | return; |
| 2041 | |
| 2042 | auto logger = getLogger("ASTFuzzer"); |
| 2043 | |
| 2044 | /// The fuzzer runs as a query finish callback, after the outer query's pipeline executor |
| 2045 | /// has stopped enforcing limits. Without these checks the outer query keeps spawning fuzzed |
| 2046 | /// queries while ignoring its own deadline, a KILL, or server shutdown, so it lingers in the |
| 2047 | /// processlist and can trip the stress test hung check. |
| 2048 | /// Some fuzzable queries (e.g. SHOW PROCESSLIST) are not inserted into the ProcessList, so |
| 2049 | /// the deadline/KILL check via checkTimeLimitSoft is unavailable; the shutdown metric still |
| 2050 | /// stops the loop in that case. |
| 2051 | QueryStatusPtr process_list_element = context->getProcessListElement(); |
| 2052 | |
| 2053 | ASTPtr base_ast = ast; |
| 2054 | |
| 2055 | for (size_t i = 0; i < num_runs; ++i) |
| 2056 | { |
| 2057 | if (CurrentMetrics::get(CurrentMetrics::IsServerShuttingDown)) |
| 2058 | { |
| 2059 | LOG_TRACE(logger, "Stopping AST fuzzer: the server is shutting down"); |
| 2060 | break; |
| 2061 | } |
| 2062 | |
| 2063 | /// checkTimeLimitSoft returns false without throwing on a KILL or the outer deadline. |
| 2064 | if (process_list_element && !process_list_element->checkTimeLimitSoft()) |
| 2065 | { |
| 2066 | LOG_TRACE(logger, "Stopping AST fuzzer: outer query was killed or timed out"); |
| 2067 | break; |
| 2068 | } |
| 2069 | |
| 2070 | ASTPtr fuzzed_ast; |
| 2071 | NameToNameMap fuzzed_query_params; |
| 2072 | { |
| 2073 | auto [fuzzer, lock] = getGlobalASTFuzzer(); |
| 2074 | fuzzed_ast = base_ast->clone(); |
| 2075 | fuzzer->fuzzMain(fuzzed_ast); |
| 2076 | fuzzed_query_params = fuzzer->getLastQueryParameters(); |
| 2077 | } |
| 2078 | |
| 2079 | /// Skip deeply nested ASTs to avoid stack overflow during formatting or execution. |
| 2080 | try |
| 2081 | { |
| 2082 | fuzzed_ast->checkDepth(500); |
no test coverage detected