#include #include #include #include #include #include #include #include #include #include #include #include namespace DB { namespace { Block getBlockFromCheckResult(const CheckResults & check_results, bool check_query_single_value_result) { if (check_query_single_value_result) { bool result = std::all_of(check_results.begin(), check_results.end(), [] (const CheckResult & res) { return res.success; }); return Block{{ColumnUInt8::create(1, static_cast(result)), std::make_shared(), "result"}}; } NamesAndTypes block_structure = NamesAndTypes{ {"part_path", std::make_shared()}, {"is_passed", std::make_shared()}, {"message", std::make_shared()}, }; auto path_column = block_structure[0].type->createColumn(); auto is_passed_column = block_structure[1].type->createColumn(); auto message_column = block_structure[2].type->createColumn(); for (const auto & check_result : check_results) { path_column->insert(check_result.fs_path); is_passed_column->insert(static_cast(check_result.success)); message_column->insert(check_result.failure_message); } return Block({ {std::move(path_column), block_structure[0].type, block_structure[0].name}, {std::move(is_passed_column), block_structure[1].type, block_structure[1].name}, {std::move(message_column), block_structure[2].type, block_structure[2].name}, }); } class TableCheckResultSource : public ISource { public: explicit TableCheckResultSource(const ASTPtr & query_ptr_, StoragePtr table_, bool check_query_single_value_result_, ContextPtr context_) : ISource(getBlockFromCheckResult({}, check_query_single_value_result_).cloneEmpty()) , query_ptr(query_ptr_) , table(table_) , context(context_) , check_query_single_value_result(check_query_single_value_result_) { worker_result = std::async(std::launch::async, [this]{ worker(); }); } String getName() const override { return "TableCheckResultSource"; } protected: std::optional tryGenerate() override { if (is_check_completed) return {}; auto status = worker_result.wait_for(std::chrono::milliseconds(100)); is_check_completed = (status == std::future_status::ready); if (is_check_completed) { worker_result.get(); auto result_block = getBlockFromCheckResult(check_results, check_query_single_value_result); check_results.clear(); return Chunk(result_block.getColumns(), result_block.rows()); } std::lock_guard lock(mutex); progress(progress_rows, 0); progress_rows = 0; if (check_query_single_value_result || check_results.empty()) { return Chunk(); } auto result_block = getBlockFromCheckResult(check_results, check_query_single_value_result); check_results.clear(); return Chunk(result_block.getColumns(), result_block.rows()); } private: void worker() { table->checkData(query_ptr, context, [this](const CheckResult & check_result, size_t new_total_rows) { if (isCancelled()) return false; std::lock_guard lock(mutex); if (new_total_rows > total_rows) { addTotalRowsApprox(new_total_rows - total_rows); total_rows = new_total_rows; } progress_rows++; if (!check_result.success) { LOG_WARNING(&Poco::Logger::get("InterpreterCheckQuery"), "Check query for table {} failed, path {}, reason: {}", table->getStorageID().getNameForLogs(), check_result.fs_path, check_result.failure_message); } check_results.push_back(check_result); bool should_continue = check_result.success || !check_query_single_value_result; return should_continue; }); } ASTPtr query_ptr; StoragePtr table; ContextPtr context; bool check_query_single_value_result; std::future worker_result; std::mutex mutex; CheckResults check_results; size_t progress_rows = 0; size_t total_rows = 0; bool is_check_completed = false; }; } InterpreterCheckQuery::InterpreterCheckQuery(const ASTPtr & query_ptr_, ContextPtr context_) : WithContext(context_) , query_ptr(query_ptr_) { } BlockIO InterpreterCheckQuery::execute() { const auto & check = query_ptr->as(); const auto & context = getContext(); auto table_id = context->resolveStorageID(check, Context::ResolveOrdinary); context->checkAccess(AccessType::SHOW_TABLES, table_id); StoragePtr table = DatabaseCatalog::instance().getTable(table_id, context); BlockIO res; { bool check_query_single_value_result = context->getSettingsRef().check_query_single_value_result; auto result_source = std::make_shared(query_ptr, table, check_query_single_value_result, context); res.pipeline = QueryPipeline(result_source); } return res; } }