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

Code before:
    {
        /// Use protected constructor.
        struct QueryUUID : Poco::UUID
        {
            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 = {

Review comment (refactor):
The existing `setCurrentDatabase` method already performs empty string validation before calling `setCurrentDatabaseWithLock`. Consider extracting this validation into a private helper method to avoid code duplication between `setCurrentDatabase` and `setCurrentDatabaseUnchecked`.

Code after:
    if (!current_database.empty())
        throw Exception(ErrorCodes::LOGICAL_ERROR, "Default database name cannot be changed in global context without server restart");

    current_database = name;
}

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();