Files
datastore/programs/local/LocalServer.h
T
Groene AI 35aa76f6b4 Fix clickhouse-local: apply user config from ~/.clickhouse-local/config.xml
`LocalServer::initialize` loads the configuration file from one of:

  - `--config-file` command-line flag
  - `./config.xml` in the current working directory
  - `getLocalConfigPath` discovery: `./clickhouse-local.{xml,yaml,yml}`,
    `~/.clickhouse-local/config.{xml,yaml,yml}`, `/etc/clickhouse-local/config.{xml,yaml,yml}`

But `LocalServer::setupUsers` only recognised the first two sources via its
gating condition:

    if (getClientConfiguration().has("config-file") || fs::exists("config.xml"))

For configs discovered by `getLocalConfigPath` (the documented user-config path
introduced by #67135), the condition was false and `setupUsers` fell through to
`minimal_default_user_xml`, silently dropping the user's `profiles`, `users`,
and `quotas`. Setting `max_threads = 42` in `~/.clickhouse-local/users.xml`
under the default profile was ignored, and the built-in default was returned.

The fix tracks the actual loaded config path in `LocalServer::loaded_config_path`
during `initialize`, and uses it in `setupUsers` both as the gate and as the
source of `config_dir` (which resolves relative `user_directories.users_xml.path`
entries against the config's own directory rather than the current working
directory). All three search paths plus `--config-file` and `./config.xml` now
share the same user-config loading code path.

A new regression test `04245_clickhouse_local_home_config.sh` exercises the
`HOME/.clickhouse-local/config.xml` and `./clickhouse-local.xml` discovery paths
and verifies that `--config-file` and the no-config fallback still work.

Closes #104932
2026-05-15 09:39:22 +00:00

93 lines
3.2 KiB
C++

#pragma once
#include <Client/ClientApplicationBase.h>
#include <Client/LocalConnection.h>
#include <Core/ServerSettings.h>
#include <Interpreters/Context_fwd.h>
#include <Loggers/Loggers.h>
#include <Common/MemoryWorker.h>
#include <Common/StatusFile.h>
#include <filesystem>
#include <memory>
#include <optional>
namespace DB
{
/// Lightweight Application for clickhouse-local
/// No networking, no extra configs and working directories, no pid and status files, no dictionaries, no logging.
/// Quiet mode by default
class LocalServer : public ClientApplicationBase, public Loggers
{
public:
LocalServer() = default;
void initialize(Poco::Util::Application & self) override;
int main(const std::vector<String> & /*args*/) override;
bool supportsLocalMetaCommands() const override { return true; }
protected:
Poco::Util::LayeredConfiguration & getClientConfiguration() override;
void connect() override;
void processError(std::string_view query) const override;
String getName() const override { return "local"; }
void printHelpMessage(const OptionsDescription & options_description) override;
void addExtraOptions(OptionsDescription & options_description) override;
void processOptions(const OptionsDescription & options_description, const CommandLineOptions & options,
const std::vector<Arguments> &, const std::vector<Arguments> &) override;
void processConfig() override;
void readArguments(int argc, char ** argv, Arguments & common_arguments, std::vector<Arguments> &, std::vector<Arguments> &) override;
void updateLoggerLevel(const String & logs_level) override;
private:
String getHelpHeader() const;
String getHelpFooter() const;
/** Composes CREATE subquery based on passed arguments (--structure --file --table and --input-format)
* This query will be executed first, before queries passed through --query argument
* Returns a pair of the table name and the corresponding create table statement.
* Returns empty strings if it cannot compose that query.
*/
std::pair<std::string, std::string> getInitialCreateTableQuery();
void tryInitPath();
void setupUsers();
void cleanup();
void applyCmdOptions(ContextMutablePtr context);
void applyCmdSettings(ContextMutablePtr context);
void createClientContext();
ServerSettings server_settings;
/// Path of the config file actually loaded in `initialize`. Empty if no config file was loaded.
/// Tracks loads from all sources: `--config-file` flag, `./config.xml`, and `getLocalConfigPath`
/// (`./clickhouse-local.{xml,yaml,yml}`, `~/.clickhouse-local/config.{xml,yaml,yml}`,
/// `/etc/clickhouse-local/config.{xml,yaml,yml}`). Needed by `setupUsers` to resolve relative
/// paths in `user_directories.users_xml.path` against the config's own directory.
String loaded_config_path;
std::optional<StatusFile> status;
std::optional<std::filesystem::path> temporary_directory_to_delete;
std::unique_ptr<ReadBufferFromFile> input;
/// MemoryWorker periodically updates RSS and resizes the userspace page cache.
/// Without it the page cache stays stuck at `page_cache_min_size`.
std::optional<MemoryWorker> memory_worker;
};
}