Repository: ClickHouse/ClickHouse
File: src/Interpreters/Context.cpp (C++)

Code before:
        {
            QueryUUID(const char * bytes, Poco::UUID::Version version)
                : Poco::UUID(bytes, version) {}
        };

        query_id_to_set = QueryUUID(random.bytes, Poco::UUID::UUID_RANDOM).toString();
    }

    client_info.current_query_id = query_id_to_set;

    if (client_info.query_kind == ClientInfo::QueryKind::INITIAL_QUERY)
        client_info.initial_query_id = client_info.current_query_id;
}

void Context::setBackgroundOperationTypeForContext(ClientInfo::BackgroundOperationType background_operation)
{
    chassert(background_operation != ClientInfo::BackgroundOperationType::NOT_A_BACKGROUND_OPERATION);
    client_info.background_operation_type = background_operation;
}

bool Context::isBackgroundOperationContext() const
{
    return client_info.background_operation_type != ClientInfo::BackgroundOperationType::NOT_A_BACKGROUND_OPERATION;
}

void Context::killCurrentQuery() const
{
    if (auto elem = getProcessListElement())
        elem->cancelQuery(CancelReason::CANCELLED_BY_USER);
}

bool Context::isCurrentQueryKilled() const
{
    /// Here getProcessListElementSafe is used, not getProcessListElement call
    /// getProcessListElement requires that process list exists
    /// In the most cases it is true, because process list exists during the query execution time.
    /// That is valid for all operations with parts, like read and write operations.
    /// However that Context::isCurrentQueryKilled call could be used on the edges
    /// when query is starting or finishing, in such edges context still exist but process list already expired
    if (auto elem = getProcessListElementSafe())
        return elem->isKilled();

    return false;
}

void Context::setInsertionTable(StorageID db_and_table, std::optional<Names> column_names, std::optional<ColumnsDescription> column_description)
{
    insertion_table_info = {
        .table = std::move(db_and_table),
        .column_names = std::move(column_names),
        .columns_description = std::move(column_description),

Review comment (bug):
Setting `need_recalculate_access = true` in `setCurrentDatabaseUnchecked()` may not be sufficient. The regular `setCurrentDatabase()` validates database existence before setting access flags. When bypassing database validation, consider whether access control checks could be bypassed or produce incorrect results if the database doesn't exist or has different permissions than expected.

Code after:

void Context::setCurrentDatabaseWithLock(const String & name, const std::lock_guard<ContextSharedMutex> &)
{
    if (name.empty())
        throw Exception(ErrorCodes::LOGICAL_ERROR, "Database name cannot be empty");

    DatabaseCatalog::instance().assertDatabaseExists(name);
    current_database = name;
    need_recalculate_access = true;
}

void Context::setCurrentDatabase(const String & name)
{
    std::lock_guard lock(mutex);
    setCurrentDatabaseWithLock(name, lock);
}

void Context::setCurrentDatabaseUnchecked(const String & name)
{
    if (name.empty())
        throw Exception(ErrorCodes::LOGICAL_ERROR, "Database name cannot be empty");

    std::lock_guard lock(mutex);
    current_database = name;
    need_recalculate_access = true;
}

void Context::setCurrentQueryId(const String & query_id)
{
    /// Generate random UUID, but using lower quality RNG,
    ///  because Poco::UUIDGenerator::generateRandom method is using /dev/random, that is very expensive.
    /// NOTE: Actually we don't need to use UUIDs for query identifiers.
    /// We could use any suitable string instead.
    union
    {
        char bytes[16];
        struct
        {
            UInt64 a;
            UInt64 b;
        } words;
        UUID uuid{};
    } random;

    random.words.a = thread_local_rng();
    random.words.b = thread_local_rng();


    String query_id_to_set = query_id;
    if (query_id_to_set.empty())    /// If the user did not submit his query_id, then we generate it ourselves.
    {