2016-10-25 12:14:27 +00:00
|
|
|
#include "LocalServer.h"
|
2017-03-14 18:39:06 +00:00
|
|
|
|
2016-10-25 12:14:27 +00:00
|
|
|
#include <Poco/Util/XMLConfiguration.h>
|
2016-10-31 14:31:26 +00:00
|
|
|
#include <Poco/Util/HelpFormatter.h>
|
|
|
|
#include <Poco/Util/OptionCallback.h>
|
2016-12-13 18:51:19 +00:00
|
|
|
#include <Poco/String.h>
|
2018-01-15 14:58:21 +00:00
|
|
|
#include <Poco/Logger.h>
|
|
|
|
#include <Poco/NullChannel.h>
|
2018-03-23 20:46:43 +00:00
|
|
|
#include <Databases/DatabaseMemory.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Storages/System/attachSystemTables.h>
|
|
|
|
#include <Interpreters/ProcessList.h>
|
|
|
|
#include <Interpreters/executeQuery.h>
|
|
|
|
#include <Interpreters/loadMetadata.h>
|
2020-02-03 12:54:36 +00:00
|
|
|
#include <Interpreters/DatabaseCatalog.h>
|
2021-07-11 20:35:29 +00:00
|
|
|
#include <common/getFQDNOrHostName.h>
|
2021-08-01 22:12:15 +00:00
|
|
|
#include <common/scope_guard_safe.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/Exception.h>
|
|
|
|
#include <Common/Macros.h>
|
2018-02-28 20:34:25 +00:00
|
|
|
#include <Common/Config/ConfigProcessor.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/escapeForFileName.h>
|
2018-04-20 19:31:19 +00:00
|
|
|
#include <Common/ClickHouseRevision.h>
|
2019-01-28 11:18:00 +00:00
|
|
|
#include <Common/ThreadStatus.h>
|
2021-02-07 17:32:45 +00:00
|
|
|
#include <Common/UnicodeBar.h>
|
2018-07-18 09:48:45 +00:00
|
|
|
#include <Common/config_version.h>
|
2019-10-08 18:42:22 +00:00
|
|
|
#include <Common/quoteString.h>
|
2021-07-11 11:36:27 +00:00
|
|
|
#include <loggers/Loggers.h>
|
2020-10-14 08:50:36 +00:00
|
|
|
#include <IO/ReadBufferFromFile.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/ReadBufferFromString.h>
|
|
|
|
#include <IO/WriteBufferFromFileDescriptor.h>
|
2020-10-14 08:50:36 +00:00
|
|
|
#include <IO/ReadHelpers.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Parsers/parseQuery.h>
|
|
|
|
#include <Parsers/IAST.h>
|
2016-10-25 12:14:27 +00:00
|
|
|
#include <common/ErrorHandlers.h>
|
2017-04-21 17:47:27 +00:00
|
|
|
#include <Functions/registerFunctions.h>
|
2017-05-05 20:39:25 +00:00
|
|
|
#include <AggregateFunctions/registerAggregateFunctions.h>
|
2017-06-10 09:04:31 +00:00
|
|
|
#include <TableFunctions/registerTableFunctions.h>
|
2017-12-30 00:36:06 +00:00
|
|
|
#include <Storages/registerStorages.h>
|
2018-11-28 11:37:12 +00:00
|
|
|
#include <Dictionaries/registerDictionaries.h>
|
2019-11-27 09:39:44 +00:00
|
|
|
#include <Disks/registerDisks.h>
|
2020-10-29 03:39:43 +00:00
|
|
|
#include <Formats/registerFormats.h>
|
2018-04-20 19:31:19 +00:00
|
|
|
#include <boost/program_options/options_description.hpp>
|
|
|
|
#include <boost/program_options.hpp>
|
2019-06-14 15:35:45 +00:00
|
|
|
#include <common/argsToConfig.h>
|
2019-08-23 15:47:27 +00:00
|
|
|
#include <Common/TerminalSize.h>
|
2020-10-23 14:57:06 +00:00
|
|
|
#include <Common/randomSeed.h>
|
2020-06-24 19:03:28 +00:00
|
|
|
#include <filesystem>
|
|
|
|
|
2021-05-16 22:06:09 +00:00
|
|
|
namespace fs = std::filesystem;
|
2016-10-25 12:14:27 +00:00
|
|
|
|
2021-07-11 23:17:14 +00:00
|
|
|
|
2016-10-25 12:14:27 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2016-11-11 17:01:02 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2020-06-24 22:07:01 +00:00
|
|
|
extern const int BAD_ARGUMENTS;
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int CANNOT_LOAD_CONFIG;
|
2020-10-23 09:53:35 +00:00
|
|
|
extern const int FILE_ALREADY_EXISTS;
|
2021-08-03 08:33:54 +00:00
|
|
|
extern const int QUERY_WAS_CANCELLED;
|
2016-11-11 17:01:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-23 20:56:47 +00:00
|
|
|
void LocalServer::initialize(Poco::Util::Application & self)
|
2016-12-13 18:51:19 +00:00
|
|
|
{
|
2021-07-23 20:56:47 +00:00
|
|
|
Poco::Util::Application::initialize(self);
|
|
|
|
|
2019-06-14 14:00:37 +00:00
|
|
|
/// Load config files if exists
|
2021-05-16 22:06:09 +00:00
|
|
|
if (config().has("config-file") || fs::exists("config.xml"))
|
2019-06-14 14:00:37 +00:00
|
|
|
{
|
|
|
|
const auto config_path = config().getString("config-file", "config.xml");
|
|
|
|
ConfigProcessor config_processor(config_path, false, true);
|
2021-05-16 22:06:09 +00:00
|
|
|
config_processor.setConfigPath(fs::path(config_path).parent_path());
|
2019-06-14 14:00:37 +00:00
|
|
|
auto loaded_config = config_processor.loadConfig();
|
|
|
|
config_processor.savePreprocessedConfig(loaded_config, loaded_config.configuration->getString("path", "."));
|
|
|
|
config().add(loaded_config.configuration.duplicate(), PRIO_DEFAULT, false);
|
|
|
|
}
|
|
|
|
|
2020-06-28 23:40:43 +00:00
|
|
|
if (config().has("logger.console") || config().has("logger.level") || config().has("logger.log"))
|
2019-06-14 14:00:37 +00:00
|
|
|
{
|
2020-06-28 23:40:43 +00:00
|
|
|
// force enable logging
|
|
|
|
config().setString("logger", "logger");
|
2019-06-20 07:17:21 +00:00
|
|
|
// sensitive data rules are not used here
|
2021-07-14 21:46:40 +00:00
|
|
|
buildLoggers(config(), logger(), "clickhouse-local");
|
2019-06-14 14:00:37 +00:00
|
|
|
}
|
|
|
|
else
|
2018-01-15 14:58:21 +00:00
|
|
|
{
|
2019-06-14 14:00:37 +00:00
|
|
|
// Turn off server logging to stderr
|
|
|
|
if (!config().has("verbose"))
|
|
|
|
{
|
|
|
|
Poco::Logger::root().setLevel("none");
|
|
|
|
Poco::Logger::root().setChannel(Poco::AutoPtr<Poco::NullChannel>(new Poco::NullChannel()));
|
|
|
|
}
|
2018-01-15 14:58:21 +00:00
|
|
|
}
|
2016-10-25 12:14:27 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 14:31:26 +00:00
|
|
|
|
2016-12-13 18:51:19 +00:00
|
|
|
/// If path is specified and not empty, will try to setup server environment and load existing metadata
|
|
|
|
void LocalServer::tryInitPath()
|
|
|
|
{
|
2020-06-24 19:03:28 +00:00
|
|
|
std::string path;
|
|
|
|
|
|
|
|
if (config().has("path"))
|
|
|
|
{
|
|
|
|
// User-supplied path.
|
|
|
|
path = config().getString("path");
|
|
|
|
Poco::trimInPlace(path);
|
2016-12-13 18:51:19 +00:00
|
|
|
|
2020-06-24 19:03:28 +00:00
|
|
|
if (path.empty())
|
|
|
|
{
|
|
|
|
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
2020-08-08 01:21:04 +00:00
|
|
|
"Cannot work with empty storage path that is explicitly specified"
|
2020-06-24 22:07:01 +00:00
|
|
|
" by the --path option. Please check the program options and"
|
2020-06-24 19:03:28 +00:00
|
|
|
" correct the --path.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2018-04-20 15:32:40 +00:00
|
|
|
{
|
2020-10-26 07:59:15 +00:00
|
|
|
// The path is not provided explicitly - use a unique path in the system temporary directory
|
|
|
|
// (or in the current dir if temporary don't exist)
|
2020-10-23 09:53:35 +00:00
|
|
|
Poco::Logger * log = &logger();
|
|
|
|
std::filesystem::path parent_folder;
|
|
|
|
std::filesystem::path default_path;
|
2018-04-20 15:32:40 +00:00
|
|
|
|
2020-10-23 09:53:35 +00:00
|
|
|
try
|
2020-06-24 19:03:28 +00:00
|
|
|
{
|
2020-10-23 09:53:35 +00:00
|
|
|
// try to guess a tmp folder name, and check if it's a directory (throw exception otherwise)
|
|
|
|
parent_folder = std::filesystem::temp_directory_path();
|
|
|
|
|
|
|
|
}
|
2021-07-23 20:56:47 +00:00
|
|
|
catch (const fs::filesystem_error& e)
|
2020-10-23 09:53:35 +00:00
|
|
|
{
|
|
|
|
// tmp folder don't exists? misconfiguration? chroot?
|
|
|
|
LOG_DEBUG(log, "Can not get temporary folder: {}", e.what());
|
|
|
|
parent_folder = std::filesystem::current_path();
|
|
|
|
|
|
|
|
std::filesystem::is_directory(parent_folder); // that will throw an exception if it's not a directory
|
|
|
|
LOG_DEBUG(log, "Will create working directory inside current directory: {}", parent_folder.string());
|
|
|
|
}
|
|
|
|
|
2020-10-26 07:59:15 +00:00
|
|
|
/// we can have another clickhouse-local running simultaneously, even with the same PID (for ex. - several dockers mounting the same folder)
|
2020-10-23 09:53:35 +00:00
|
|
|
/// or it can be some leftovers from other clickhouse-local runs
|
|
|
|
/// as we can't accurately distinguish those situations we don't touch any existent folders
|
|
|
|
/// we just try to pick some free name for our working folder
|
|
|
|
|
2020-10-23 14:57:06 +00:00
|
|
|
default_path = parent_folder / fmt::format("clickhouse-local-{}-{}-{}", getpid(), time(nullptr), randomSeed());
|
2020-10-23 09:53:35 +00:00
|
|
|
|
2020-10-23 14:57:06 +00:00
|
|
|
if (exists(default_path))
|
2020-10-27 11:04:03 +00:00
|
|
|
throw Exception(ErrorCodes::FILE_ALREADY_EXISTS, "Unsuccessful attempt to create working directory: {} exist!", default_path.string());
|
2020-06-24 19:03:28 +00:00
|
|
|
|
|
|
|
create_directory(default_path);
|
|
|
|
temporary_directory_to_delete = default_path;
|
|
|
|
|
|
|
|
path = default_path.string();
|
2020-10-23 09:53:35 +00:00
|
|
|
LOG_DEBUG(log, "Working directory created: {}", path);
|
2018-04-20 15:32:40 +00:00
|
|
|
}
|
2016-12-13 18:51:19 +00:00
|
|
|
|
2020-06-24 19:03:28 +00:00
|
|
|
if (path.back() != '/')
|
|
|
|
path += '/';
|
|
|
|
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setPath(path);
|
2020-10-20 15:57:53 +00:00
|
|
|
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setTemporaryStorage(path + "tmp");
|
|
|
|
global_context->setFlagsPath(path + "flags");
|
2020-10-20 15:57:53 +00:00
|
|
|
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setUserFilesPath(""); // user's files are everywhere
|
2016-12-13 18:51:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
static void attachSystemTables(ContextPtr context)
|
2020-03-18 00:57:00 +00:00
|
|
|
{
|
|
|
|
DatabasePtr system_database = DatabaseCatalog::instance().tryGetDatabase(DatabaseCatalog::SYSTEM_DATABASE);
|
|
|
|
if (!system_database)
|
|
|
|
{
|
|
|
|
/// TODO: add attachTableDelayed into DatabaseMemory to speedup loading
|
2020-05-28 20:10:45 +00:00
|
|
|
system_database = std::make_shared<DatabaseMemory>(DatabaseCatalog::SYSTEM_DATABASE, context);
|
2020-03-18 00:57:00 +00:00
|
|
|
DatabaseCatalog::instance().attachDatabase(DatabaseCatalog::SYSTEM_DATABASE, system_database);
|
|
|
|
}
|
|
|
|
|
|
|
|
attachSystemTablesLocal(*system_database);
|
|
|
|
}
|
|
|
|
|
2021-07-11 23:17:14 +00:00
|
|
|
|
|
|
|
void LocalServer::cleanup()
|
|
|
|
{
|
|
|
|
// Delete the temporary directory if needed.
|
|
|
|
if (temporary_directory_to_delete)
|
|
|
|
{
|
|
|
|
const auto dir = *temporary_directory_to_delete;
|
|
|
|
temporary_directory_to_delete.reset();
|
|
|
|
LOG_DEBUG(&logger(), "Removing temporary directory: {}", dir.string());
|
|
|
|
remove_all(dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string LocalServer::getInitialCreateTableQuery()
|
|
|
|
{
|
|
|
|
if (!config().has("table-structure"))
|
|
|
|
return {};
|
|
|
|
|
|
|
|
auto table_name = backQuoteIfNeed(config().getString("table-name", "table"));
|
|
|
|
auto table_structure = config().getString("table-structure");
|
|
|
|
auto data_format = backQuoteIfNeed(config().getString("table-data-format", "TSV"));
|
|
|
|
|
|
|
|
String table_file;
|
|
|
|
if (!config().has("table-file") || config().getString("table-file") == "-")
|
|
|
|
{
|
|
|
|
/// Use Unix tools stdin naming convention
|
|
|
|
table_file = "stdin";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/// Use regular file
|
|
|
|
table_file = quoteString(config().getString("table-file"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt::format("CREATE TABLE {} ({}) ENGINE = File({}, {});",
|
|
|
|
table_name, table_structure, data_format, table_file);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-08-01 20:28:39 +00:00
|
|
|
void LocalServer::loadSuggestionData(Suggest & suggest)
|
|
|
|
{
|
2021-08-01 22:12:15 +00:00
|
|
|
if (is_interactive && !config().getBool("disable_suggestion", false))
|
2021-08-03 08:33:54 +00:00
|
|
|
suggest.load(global_context);
|
2021-08-01 22:12:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LocalServer::checkInterruptListener()
|
|
|
|
{
|
|
|
|
if (!interrupt_listener)
|
|
|
|
return;
|
2021-08-03 08:33:54 +00:00
|
|
|
assert(is_interactive);
|
2021-08-01 22:12:15 +00:00
|
|
|
|
|
|
|
if (interrupt_listener->check() && !cancelled && interrupt_listener_mutex.try_lock())
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
progress_indication.clearProgressOutput();
|
|
|
|
std::cout << "Cancelling query." << std::endl;
|
|
|
|
|
2021-08-02 14:46:21 +00:00
|
|
|
auto * process_list_elem = query_context->getProcessListElement();
|
|
|
|
if (process_list_elem)
|
2021-08-03 08:33:54 +00:00
|
|
|
cancelled = (process_list_elem->cancelQuery(true) == CancellationCode::CancelSent);
|
|
|
|
else
|
|
|
|
std::cerr << "Cannot cancel query: no process list element.";
|
2021-08-01 22:12:15 +00:00
|
|
|
|
|
|
|
interrupt_listener->unblock();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
cancelled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
interrupt_listener_mutex.unlock();
|
2021-08-01 20:28:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-29 09:45:09 +00:00
|
|
|
void LocalServer::executeSingleQuery(const String & query_to_execute, ASTPtr /* parsed_query */)
|
2021-07-11 23:17:14 +00:00
|
|
|
{
|
2021-07-12 12:25:17 +00:00
|
|
|
ReadBufferFromString read_buf(query_to_execute);
|
2021-07-11 23:17:14 +00:00
|
|
|
WriteBufferFromFileDescriptor write_buf(STDOUT_FILENO);
|
|
|
|
|
2021-08-01 22:12:15 +00:00
|
|
|
cancelled = false;
|
|
|
|
|
2021-07-30 07:46:22 +00:00
|
|
|
/// To support previous behaviour of clickhouse-local do not reset first exception in case --ignore-error,
|
|
|
|
/// it needs to be thrown after multiquery is finished (test 00385). But I do not think it is ok to output only
|
|
|
|
/// first exception or whether we need to even rethrow it because there is --ignore-error.
|
2021-07-31 12:34:29 +00:00
|
|
|
if (!ignore_error)
|
2021-07-30 07:46:22 +00:00
|
|
|
local_server_exception.reset();
|
2021-07-29 12:48:07 +00:00
|
|
|
|
2021-08-01 22:12:15 +00:00
|
|
|
std::function<void(WriteBuffer & out, size_t result_rows)> flush_buffer_func;
|
2021-07-11 23:17:14 +00:00
|
|
|
if (need_render_progress)
|
|
|
|
{
|
2021-08-01 22:12:15 +00:00
|
|
|
flush_buffer_func = [&](WriteBuffer & out, size_t result_rows)
|
2021-07-11 23:17:14 +00:00
|
|
|
{
|
2021-07-31 12:08:30 +00:00
|
|
|
written_first_block = true;
|
|
|
|
processed_rows = result_rows;
|
|
|
|
|
|
|
|
if (need_render_progress)
|
|
|
|
progress_indication.clearProgressOutput();
|
|
|
|
|
|
|
|
out.next();
|
|
|
|
|
|
|
|
/// Restore progress bar after data block.
|
|
|
|
if (need_render_progress)
|
|
|
|
progress_indication.writeProgress();
|
2021-08-01 22:12:15 +00:00
|
|
|
|
|
|
|
checkInterruptListener();
|
2021-07-11 23:17:14 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-08-01 22:12:15 +00:00
|
|
|
if (is_interactive)
|
|
|
|
interrupt_listener.emplace();
|
|
|
|
|
|
|
|
SCOPE_EXIT_SAFE({
|
|
|
|
if (interrupt_listener)
|
|
|
|
interrupt_listener.reset();
|
|
|
|
});
|
|
|
|
|
2021-08-03 08:33:54 +00:00
|
|
|
auto process_error = [&]()
|
2021-07-11 23:17:14 +00:00
|
|
|
{
|
2021-07-30 07:46:22 +00:00
|
|
|
if (!ignore_error)
|
2021-07-11 23:17:14 +00:00
|
|
|
throw;
|
|
|
|
|
2021-07-29 12:48:07 +00:00
|
|
|
local_server_exception = std::make_unique<Exception>(getCurrentExceptionMessage(true), getCurrentExceptionCode());
|
|
|
|
have_error = true;
|
2021-08-03 08:33:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
executeQuery(read_buf, write_buf, /* allow_into_outfile = */ true, query_context, {}, {}, flush_buffer_func);
|
|
|
|
}
|
|
|
|
catch (const Exception & e)
|
|
|
|
{
|
|
|
|
if (is_interactive && e.code() == ErrorCodes::QUERY_WAS_CANCELLED)
|
|
|
|
std::cout << "Query was cancelled." << std::endl;
|
|
|
|
else
|
|
|
|
process_error();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
process_error();
|
2021-07-11 23:17:14 +00:00
|
|
|
}
|
2021-08-03 08:33:54 +00:00
|
|
|
onEndOfStream();
|
2021-07-11 23:17:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static ConfigurationPtr getConfigurationFromXMLString(const char * xml_data)
|
|
|
|
{
|
|
|
|
std::stringstream ss{std::string{xml_data}}; // STYLE_CHECK_ALLOW_STD_STRING_STREAM
|
|
|
|
Poco::XML::InputSource input_source{ss};
|
|
|
|
return {new Poco::Util::XMLConfiguration{&input_source}};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LocalServer::setupUsers()
|
|
|
|
{
|
|
|
|
static const char * minimal_default_user_xml =
|
|
|
|
"<yandex>"
|
|
|
|
" <profiles>"
|
|
|
|
" <default></default>"
|
|
|
|
" </profiles>"
|
|
|
|
" <users>"
|
|
|
|
" <default>"
|
|
|
|
" <password></password>"
|
|
|
|
" <networks>"
|
|
|
|
" <ip>::/0</ip>"
|
|
|
|
" </networks>"
|
|
|
|
" <profile>default</profile>"
|
|
|
|
" <quota>default</quota>"
|
|
|
|
" </default>"
|
|
|
|
" </users>"
|
|
|
|
" <quotas>"
|
|
|
|
" <default></default>"
|
|
|
|
" </quotas>"
|
|
|
|
"</yandex>";
|
|
|
|
|
|
|
|
ConfigurationPtr users_config;
|
|
|
|
|
|
|
|
if (config().has("users_config") || config().has("config-file") || fs::exists("config.xml"))
|
|
|
|
{
|
|
|
|
const auto users_config_path = config().getString("users_config", config().getString("config-file", "config.xml"));
|
|
|
|
ConfigProcessor config_processor(users_config_path);
|
|
|
|
const auto loaded_config = config_processor.loadConfig();
|
|
|
|
config_processor.savePreprocessedConfig(loaded_config, config().getString("path", DBMS_DEFAULT_PATH));
|
|
|
|
users_config = loaded_config.configuration;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
users_config = getConfigurationFromXMLString(minimal_default_user_xml);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (users_config)
|
|
|
|
global_context->setUsersConfig(users_config);
|
|
|
|
else
|
|
|
|
throw Exception("Can't load config for users", ErrorCodes::CANNOT_LOAD_CONFIG);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-29 12:48:07 +00:00
|
|
|
bool LocalServer::processMultiQuery(const String & all_queries_text)
|
|
|
|
{
|
|
|
|
auto process_single_query = [&](const String & query_to_execute, const String &, ASTPtr)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
processSingleQueryImpl(query_to_execute, query_to_execute, nullptr, echo_queries, false);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-07-29 18:26:33 +00:00
|
|
|
local_server_exception = std::make_unique<Exception>(getCurrentExceptionMessage(false), getCurrentExceptionCode());
|
2021-07-29 12:48:07 +00:00
|
|
|
have_error = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return processMultiQueryImpl(all_queries_text, process_single_query);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LocalServer::processSingleQuery(const String & full_query)
|
|
|
|
{
|
|
|
|
ASTPtr parsed_query;
|
|
|
|
if (is_interactive)
|
|
|
|
{
|
2021-07-29 18:26:33 +00:00
|
|
|
const auto * this_query_begin = full_query.data();
|
2021-07-29 12:48:07 +00:00
|
|
|
parsed_query = parseQuery(this_query_begin, full_query.data() + full_query.size(), false);
|
|
|
|
}
|
2021-07-29 18:26:33 +00:00
|
|
|
|
2021-07-29 12:48:07 +00:00
|
|
|
processSingleQueryImpl(full_query, full_query, parsed_query, echo_queries);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String LocalServer::getQueryTextPrefix()
|
|
|
|
{
|
|
|
|
return getInitialCreateTableQuery();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-29 18:26:33 +00:00
|
|
|
void LocalServer::reportQueryError(const String & query) const
|
2021-07-29 12:48:07 +00:00
|
|
|
{
|
2021-07-29 18:26:33 +00:00
|
|
|
/// For non-interactive mode process exception only when all queries were executed.
|
|
|
|
if (local_server_exception && is_interactive)
|
2021-07-29 12:48:07 +00:00
|
|
|
{
|
2021-07-29 18:26:33 +00:00
|
|
|
fmt::print(stderr, "Error on processing query '{}':\n{}\n", query, local_server_exception->message());
|
|
|
|
fmt::print(stderr, "\n");
|
2021-07-29 12:48:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-23 20:56:47 +00:00
|
|
|
int LocalServer::mainImpl()
|
2021-07-31 12:34:29 +00:00
|
|
|
try
|
2016-10-25 12:14:27 +00:00
|
|
|
{
|
2021-07-31 12:34:29 +00:00
|
|
|
ThreadStatus thread_status;
|
|
|
|
|
|
|
|
/// We will terminate process on error
|
|
|
|
static KillingErrorHandler error_handler;
|
|
|
|
Poco::ErrorHandler::set(&error_handler);
|
|
|
|
|
|
|
|
/// Don't initialize DateLUT
|
|
|
|
registerFunctions();
|
|
|
|
registerAggregateFunctions();
|
|
|
|
registerTableFunctions();
|
|
|
|
registerStorages();
|
|
|
|
registerDictionaries();
|
|
|
|
registerDisks();
|
|
|
|
registerFormats();
|
|
|
|
|
|
|
|
processConfig();
|
|
|
|
|
|
|
|
/// we can't mutate global_context (can lead to races, as it was already passed to some background threads)
|
|
|
|
/// so we can't reuse it safely as a query context and need a copy here
|
|
|
|
query_context = Context::createCopy(global_context);
|
|
|
|
query_context->makeSessionContext();
|
|
|
|
query_context->makeQueryContext();
|
|
|
|
query_context->setUser("default", "", Poco::Net::SocketAddress{});
|
|
|
|
query_context->setCurrentQueryId("");
|
|
|
|
|
|
|
|
applyCmdSettings(query_context);
|
|
|
|
/// Use the same query_id (and thread group) for all queries
|
|
|
|
CurrentThread::QueryScope query_scope_holder(query_context);
|
|
|
|
|
|
|
|
if (need_render_progress)
|
2021-07-23 20:56:47 +00:00
|
|
|
{
|
2021-07-31 12:34:29 +00:00
|
|
|
/// Set progress callback, which can be run from multiple threads.
|
|
|
|
query_context->setProgressCallback([&](const Progress & value)
|
2021-07-23 20:54:49 +00:00
|
|
|
{
|
2021-08-01 22:12:15 +00:00
|
|
|
checkInterruptListener();
|
2021-07-31 12:34:29 +00:00
|
|
|
onProgress(value);
|
|
|
|
});
|
2021-07-27 09:29:35 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
/// Set callback for file processing progress.
|
|
|
|
progress_indication.setFileProgressCallback(query_context);
|
|
|
|
}
|
2021-07-23 20:54:49 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
if (is_interactive)
|
|
|
|
{
|
|
|
|
std::cout << std::endl;
|
2021-07-29 12:48:07 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
auto try_process_query_text = [&](std::function<bool()> func)
|
2021-07-27 09:29:35 +00:00
|
|
|
{
|
2021-07-31 12:34:29 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
return func();
|
|
|
|
}
|
|
|
|
catch (const Exception & e)
|
|
|
|
{
|
|
|
|
bool print_stack_trace = config().getBool("stacktrace", false);
|
|
|
|
std::cerr << "Received exception:" << std::endl << getExceptionMessage(e, print_stack_trace, true) << std::endl << std::endl;
|
|
|
|
}
|
2021-07-23 20:54:49 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
return true;
|
|
|
|
};
|
2021-07-27 09:29:35 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
runInteractive(try_process_query_text);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
runNonInteractive();
|
2021-07-23 20:54:49 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
if (local_server_exception)
|
|
|
|
local_server_exception->rethrow();
|
|
|
|
}
|
|
|
|
|
|
|
|
global_context->shutdown();
|
|
|
|
global_context.reset();
|
|
|
|
|
|
|
|
status.reset();
|
|
|
|
cleanup();
|
2021-07-23 20:54:49 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
return Application::EXIT_OK;
|
|
|
|
}
|
|
|
|
catch (const Exception & e)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
cleanup();
|
2021-07-27 09:29:35 +00:00
|
|
|
}
|
2021-07-31 12:34:29 +00:00
|
|
|
catch (...)
|
2021-07-27 09:29:35 +00:00
|
|
|
{
|
2021-07-31 12:34:29 +00:00
|
|
|
tryLogCurrentException(__PRETTY_FUNCTION__);
|
|
|
|
}
|
2021-07-23 20:54:49 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
if (!ignore_error)
|
|
|
|
std::cerr << getCurrentExceptionMessage(config().hasOption("stacktrace")) << '\n';
|
2021-07-30 07:46:22 +00:00
|
|
|
|
2021-07-31 12:34:29 +00:00
|
|
|
/// If exception code isn't zero, we should return non-zero return code anyway.
|
|
|
|
return e.code() ? e.code() : -1;
|
2021-07-23 20:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LocalServer::processConfig()
|
|
|
|
{
|
|
|
|
if (stdin_is_a_tty && !config().has("query") && !config().has("table-structure") && queries_files.empty())
|
|
|
|
{
|
|
|
|
if (config().has("query") && config().has("queries-file"))
|
|
|
|
throw Exception("Specify either `query` or `queries-file` option", ErrorCodes::BAD_ARGUMENTS);
|
|
|
|
|
|
|
|
is_interactive = true;
|
2021-07-29 12:48:07 +00:00
|
|
|
|
|
|
|
if (config().has("multiquery"))
|
|
|
|
is_multiquery = true;
|
2021-07-23 20:54:49 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
need_render_progress = config().getBool("progress", false);
|
2021-07-29 09:45:09 +00:00
|
|
|
echo_queries = config().hasOption("echo") || config().hasOption("verbose");
|
2021-07-23 20:54:49 +00:00
|
|
|
ignore_error = config().getBool("ignore-error", false);
|
2021-07-29 12:48:07 +00:00
|
|
|
is_multiquery = true;
|
2021-07-23 20:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
shared_context = Context::createShared();
|
|
|
|
global_context = Context::createGlobal(shared_context.get());
|
|
|
|
|
|
|
|
global_context->makeGlobalContext();
|
|
|
|
global_context->setApplicationType(Context::ApplicationType::LOCAL);
|
|
|
|
|
|
|
|
tryInitPath();
|
|
|
|
|
|
|
|
Poco::Logger * log = &logger();
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Maybe useless
|
|
|
|
if (config().has("macros"))
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setMacros(std::make_unique<Macros>(config(), "macros", log));
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/// Skip networking
|
|
|
|
|
2021-03-11 20:41:10 +00:00
|
|
|
/// Sets external authenticators config (LDAP, Kerberos).
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setExternalAuthenticatorsConfig(config());
|
2020-06-10 22:48:15 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
setupUsers();
|
|
|
|
|
|
|
|
/// Limit on total number of concurrently executing queries.
|
2020-03-28 03:02:26 +00:00
|
|
|
/// There is no need for concurrent queries, override max_concurrent_queries.
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->getProcessList().setMaxSize(0);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/// Size of cache for uncompressed blocks. Zero means disabled.
|
2017-04-12 16:37:19 +00:00
|
|
|
size_t uncompressed_cache_size = config().getUInt64("uncompressed_cache_size", 0);
|
2017-04-01 07:20:54 +00:00
|
|
|
if (uncompressed_cache_size)
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setUncompressedCache(uncompressed_cache_size);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/// Size of cache for marks (index of MergeTree family of tables). It is necessary.
|
|
|
|
/// Specify default value for mark_cache_size explicitly!
|
2017-04-12 16:37:19 +00:00
|
|
|
size_t mark_cache_size = config().getUInt64("mark_cache_size", 5368709120);
|
2017-04-01 07:20:54 +00:00
|
|
|
if (mark_cache_size)
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setMarkCache(mark_cache_size);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-03-28 01:10:30 +00:00
|
|
|
/// A cache for mmapped files.
|
|
|
|
size_t mmap_cache_size = config().getUInt64("mmap_cache_size", 1000); /// The choice of default is arbitrary.
|
|
|
|
if (mmap_cache_size)
|
2021-03-28 19:24:28 +00:00
|
|
|
global_context->setMMappedFileCache(mmap_cache_size);
|
2021-03-28 01:10:30 +00:00
|
|
|
|
2018-02-01 13:52:29 +00:00
|
|
|
/// Load global settings from default_profile and system_profile.
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setDefaultProfiles(config());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/** Init dummy default DB
|
2020-01-11 09:50:41 +00:00
|
|
|
* NOTE: We force using isolated default database to avoid conflicts with default database from server environment
|
2017-04-01 07:20:54 +00:00
|
|
|
* Otherwise, metadata of temporary File(format, EXPLICIT_PATH) tables will pollute metadata/ directory;
|
2018-01-15 14:58:21 +00:00
|
|
|
* if such tables will not be dropped, clickhouse-server will not be able to load them due to security reasons.
|
2017-04-01 07:20:54 +00:00
|
|
|
*/
|
2018-04-20 19:31:19 +00:00
|
|
|
std::string default_database = config().getString("default_database", "_local");
|
2021-04-10 23:33:54 +00:00
|
|
|
DatabaseCatalog::instance().attachDatabase(default_database, std::make_shared<DatabaseMemory>(default_database, global_context));
|
2020-10-22 07:37:03 +00:00
|
|
|
global_context->setCurrentDatabase(default_database);
|
2021-04-10 23:33:54 +00:00
|
|
|
applyCmdOptions(global_context);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-01-16 15:08:21 +00:00
|
|
|
if (config().has("path"))
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2021-01-16 15:08:21 +00:00
|
|
|
String path = global_context->getPath();
|
|
|
|
|
2018-04-20 15:32:40 +00:00
|
|
|
/// Lock path directory before read
|
2021-07-23 20:54:49 +00:00
|
|
|
status.emplace(fs::path(path) / "status", StatusFile::write_full_info);
|
2018-04-20 15:32:40 +00:00
|
|
|
|
2020-08-13 19:41:06 +00:00
|
|
|
LOG_DEBUG(log, "Loading metadata from {}", path);
|
2021-05-16 22:06:09 +00:00
|
|
|
fs::create_directories(fs::path(path) / "data/");
|
|
|
|
fs::create_directories(fs::path(path) / "metadata/");
|
2021-07-23 20:54:49 +00:00
|
|
|
|
2021-04-10 23:33:54 +00:00
|
|
|
loadMetadataSystem(global_context);
|
|
|
|
attachSystemTables(global_context);
|
|
|
|
loadMetadata(global_context);
|
2020-02-10 13:10:17 +00:00
|
|
|
DatabaseCatalog::instance().loadDatabases();
|
2021-07-23 20:54:49 +00:00
|
|
|
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_DEBUG(log, "Loaded metadata.");
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2021-01-10 11:12:02 +00:00
|
|
|
else if (!config().has("no-system-tables"))
|
2017-06-15 20:08:26 +00:00
|
|
|
{
|
2021-04-10 23:33:54 +00:00
|
|
|
attachSystemTables(global_context);
|
2017-06-15 20:08:26 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-07-23 20:54:49 +00:00
|
|
|
server_display_name = config().getString("display_name", getFQDNOrHostName());
|
2021-07-28 12:56:11 +00:00
|
|
|
prompt_by_server_display_name = config().getRawString("prompt_by_server_display_name.default", "{display_name} :) ");
|
|
|
|
std::map<String, String> prompt_substitutions{{"display_name", server_display_name}};
|
|
|
|
for (const auto & [key, value] : prompt_substitutions)
|
|
|
|
boost::replace_all(prompt_by_server_display_name, "{" + key + "}", value);
|
2021-07-11 20:35:29 +00:00
|
|
|
}
|
2016-10-28 17:38:32 +00:00
|
|
|
|
2020-06-24 19:03:28 +00:00
|
|
|
|
2020-03-18 00:57:00 +00:00
|
|
|
static std::string getHelpHeader()
|
2018-04-20 19:31:19 +00:00
|
|
|
{
|
|
|
|
return
|
|
|
|
"usage: clickhouse-local [initial table definition] [--query <query>]\n"
|
|
|
|
|
|
|
|
"clickhouse-local allows to execute SQL queries on your data files via single command line call."
|
|
|
|
" To do so, initially you need to define your data source and its format."
|
|
|
|
" After you can execute your SQL queries in usual manner.\n"
|
|
|
|
|
|
|
|
"There are two ways to define initial table keeping your data."
|
|
|
|
" Either just in first query like this:\n"
|
|
|
|
" CREATE TABLE <table> (<structure>) ENGINE = File(<input-format>, <file>);\n"
|
|
|
|
"Either through corresponding command line parameters --table --structure --input-format and --file.";
|
|
|
|
}
|
|
|
|
|
2021-07-11 23:17:14 +00:00
|
|
|
|
2020-03-18 00:57:00 +00:00
|
|
|
static std::string getHelpFooter()
|
2018-04-20 19:31:19 +00:00
|
|
|
{
|
|
|
|
return
|
|
|
|
"Example printing memory used by each Unix user:\n"
|
|
|
|
"ps aux | tail -n +2 | awk '{ printf(\"%s\\t%s\\n\", $1, $4) }' | "
|
|
|
|
"clickhouse-local -S \"user String, mem Float64\" -q"
|
|
|
|
" \"SELECT user, round(sum(mem), 2) as mem_total FROM table GROUP BY user ORDER"
|
|
|
|
" BY mem_total DESC FORMAT PrettyCompact\"";
|
|
|
|
}
|
|
|
|
|
2021-07-11 23:17:14 +00:00
|
|
|
|
2021-07-11 11:36:27 +00:00
|
|
|
void LocalServer::printHelpMessage(const OptionsDescription & options_description)
|
2018-04-20 19:31:19 +00:00
|
|
|
{
|
2021-07-11 11:36:27 +00:00
|
|
|
std::cout << getHelpHeader() << "\n";
|
|
|
|
std::cout << options_description.main_description.value() << "\n";
|
|
|
|
std::cout << getHelpFooter() << "\n";
|
|
|
|
}
|
2018-04-20 19:31:19 +00:00
|
|
|
|
2021-07-11 23:17:14 +00:00
|
|
|
|
2021-07-29 12:48:07 +00:00
|
|
|
void LocalServer::addAndCheckOptions(OptionsDescription & options_description, po::variables_map & options, Arguments & arguments)
|
2021-07-11 11:36:27 +00:00
|
|
|
{
|
|
|
|
options_description.main_description.emplace(createOptionsDescription("Main options", terminal_width));
|
|
|
|
options_description.main_description->add_options()
|
2018-04-20 19:31:19 +00:00
|
|
|
("help", "produce help message")
|
|
|
|
("config-file,c", po::value<std::string>(), "config-file path")
|
|
|
|
("query,q", po::value<std::string>(), "query")
|
2020-10-14 08:50:36 +00:00
|
|
|
("queries-file, qf", po::value<std::string>(), "file path with queries to execute")
|
2018-04-20 19:31:19 +00:00
|
|
|
("database,d", po::value<std::string>(), "database")
|
|
|
|
|
|
|
|
("table,N", po::value<std::string>(), "name of the initial table")
|
|
|
|
/// If structure argument is omitted then initial query is not generated
|
|
|
|
("structure,S", po::value<std::string>(), "structure of the initial table (list of column and type names)")
|
|
|
|
("file,f", po::value<std::string>(), "path to file with data of the initial table (stdin if not specified)")
|
|
|
|
("input-format", po::value<std::string>(), "input format of the initial table data")
|
|
|
|
("format,f", po::value<std::string>(), "default output format (clickhouse-client compatibility)")
|
|
|
|
("output-format", po::value<std::string>(), "default output format")
|
|
|
|
|
|
|
|
("stacktrace", "print stack traces of exceptions")
|
|
|
|
("echo", "print query before execution")
|
|
|
|
("verbose", "print query and other debugging info")
|
2020-06-28 23:40:43 +00:00
|
|
|
("logger.console", po::value<bool>()->implicit_value(true), "Log to console")
|
2019-06-14 14:00:37 +00:00
|
|
|
("logger.log", po::value<std::string>(), "Log file name")
|
|
|
|
("logger.level", po::value<std::string>(), "Log level")
|
2018-04-20 19:31:19 +00:00
|
|
|
("ignore-error", "do not stop processing if a query failed")
|
2021-01-10 11:12:02 +00:00
|
|
|
("no-system-tables", "do not attach system tables (better startup time)")
|
2018-04-20 19:31:19 +00:00
|
|
|
("version,V", "print version information and exit")
|
2021-04-30 21:39:44 +00:00
|
|
|
("progress", "print progress of queries execution")
|
2021-07-29 12:48:07 +00:00
|
|
|
|
|
|
|
("multiline,m", "multiline")
|
|
|
|
("multiquery,n", "multiquery")
|
|
|
|
("highlight", po::value<bool>()->default_value(true), "enable or disable basic syntax highlight in interactive command line")
|
2021-08-01 20:28:39 +00:00
|
|
|
|
2021-08-01 22:12:15 +00:00
|
|
|
("disable_suggestion,A", "Disable loading suggestion data. Shorthand option -A is for those who get used to mysql client.")
|
2019-04-25 14:08:20 +00:00
|
|
|
;
|
2021-07-29 12:48:07 +00:00
|
|
|
|
|
|
|
cmd_settings.addProgramOptions(options_description.main_description.value());
|
|
|
|
po::parsed_options parsed = po::command_line_parser(arguments).options(options_description.main_description.value()).run();
|
|
|
|
po::store(parsed, options);
|
2021-07-11 11:36:27 +00:00
|
|
|
}
|
2018-04-20 19:31:19 +00:00
|
|
|
|
2021-07-11 23:17:14 +00:00
|
|
|
|
|
|
|
void LocalServer::applyCmdSettings(ContextMutablePtr context)
|
|
|
|
{
|
|
|
|
context->applySettingsChanges(cmd_settings.changes());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void LocalServer::applyCmdOptions(ContextMutablePtr context)
|
|
|
|
{
|
2021-07-29 09:45:09 +00:00
|
|
|
context->setDefaultFormat(config().getString("output-format", config().getString("format", is_interactive ? "PrettyCompact" : "TSV")));
|
2021-07-11 23:17:14 +00:00
|
|
|
applyCmdSettings(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-11 11:36:27 +00:00
|
|
|
void LocalServer::readArguments(int argc, char ** argv, Arguments & arguments, std::vector<Arguments> &)
|
|
|
|
{
|
|
|
|
for (int arg_num = 1; arg_num < argc; ++arg_num)
|
|
|
|
arguments.emplace_back(argv[arg_num]);
|
|
|
|
}
|
2018-04-20 19:31:19 +00:00
|
|
|
|
2021-07-11 23:17:14 +00:00
|
|
|
|
2021-07-11 11:36:27 +00:00
|
|
|
void LocalServer::processOptions(const OptionsDescription &, const CommandLineOptions & options, const std::vector<Arguments> &)
|
|
|
|
{
|
2018-04-20 19:31:19 +00:00
|
|
|
/// Save received data into the internal config.
|
|
|
|
if (options.count("config-file"))
|
|
|
|
config().setString("config-file", options["config-file"].as<std::string>());
|
|
|
|
if (options.count("query"))
|
|
|
|
config().setString("query", options["query"].as<std::string>());
|
2020-10-14 08:50:36 +00:00
|
|
|
if (options.count("queries-file"))
|
|
|
|
config().setString("queries-file", options["queries-file"].as<std::string>());
|
2018-04-20 19:31:19 +00:00
|
|
|
if (options.count("database"))
|
|
|
|
config().setString("default_database", options["database"].as<std::string>());
|
|
|
|
|
|
|
|
if (options.count("table"))
|
|
|
|
config().setString("table-name", options["table"].as<std::string>());
|
|
|
|
if (options.count("file"))
|
|
|
|
config().setString("table-file", options["file"].as<std::string>());
|
|
|
|
if (options.count("structure"))
|
|
|
|
config().setString("table-structure", options["structure"].as<std::string>());
|
|
|
|
if (options.count("input-format"))
|
|
|
|
config().setString("table-data-format", options["input-format"].as<std::string>());
|
|
|
|
if (options.count("format"))
|
|
|
|
config().setString("format", options["format"].as<std::string>());
|
|
|
|
if (options.count("output-format"))
|
|
|
|
config().setString("output-format", options["output-format"].as<std::string>());
|
|
|
|
|
|
|
|
if (options.count("stacktrace"))
|
|
|
|
config().setBool("stacktrace", true);
|
2021-04-27 13:19:52 +00:00
|
|
|
if (options.count("progress"))
|
|
|
|
config().setBool("progress", true);
|
2018-04-20 19:31:19 +00:00
|
|
|
if (options.count("echo"))
|
|
|
|
config().setBool("echo", true);
|
|
|
|
if (options.count("verbose"))
|
|
|
|
config().setBool("verbose", true);
|
2020-06-28 23:40:43 +00:00
|
|
|
if (options.count("logger.console"))
|
|
|
|
config().setBool("logger.console", options["logger.console"].as<bool>());
|
2019-06-14 14:00:37 +00:00
|
|
|
if (options.count("logger.log"))
|
|
|
|
config().setString("logger.log", options["logger.log"].as<std::string>());
|
|
|
|
if (options.count("logger.level"))
|
|
|
|
config().setString("logger.level", options["logger.level"].as<std::string>());
|
2018-04-20 19:31:19 +00:00
|
|
|
if (options.count("ignore-error"))
|
|
|
|
config().setBool("ignore-error", true);
|
2021-01-10 11:12:02 +00:00
|
|
|
if (options.count("no-system-tables"))
|
|
|
|
config().setBool("no-system-tables", true);
|
2021-07-11 20:35:29 +00:00
|
|
|
|
|
|
|
if (options.count("queries-file"))
|
2021-07-28 12:56:11 +00:00
|
|
|
queries_files.emplace_back(config().getString("queries-file"));
|
2021-07-29 12:48:07 +00:00
|
|
|
|
|
|
|
if (options.count("multiline"))
|
|
|
|
config().setBool("multiline", true);
|
|
|
|
if (options.count("multiquery"))
|
|
|
|
config().setBool("multiquery", true);
|
2018-04-20 19:31:19 +00:00
|
|
|
}
|
|
|
|
|
2018-05-11 14:35:32 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 19:54:49 +00:00
|
|
|
|
2019-12-15 06:34:43 +00:00
|
|
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
|
|
|
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
|
|
|
|
2017-12-02 02:47:12 +00:00
|
|
|
int mainEntryClickHouseLocal(int argc, char ** argv)
|
|
|
|
{
|
|
|
|
DB::LocalServer app;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
app.init(argc, argv);
|
|
|
|
return app.run();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2018-08-23 00:14:26 +00:00
|
|
|
std::cerr << DB::getCurrentExceptionMessage(true) << '\n';
|
2017-12-02 02:47:12 +00:00
|
|
|
auto code = DB::getCurrentExceptionCode();
|
|
|
|
return code ? code : 1;
|
|
|
|
}
|
|
|
|
}
|