2018-11-28 11:37:12 +00:00
|
|
|
#include "MySQLDictionarySource.h"
|
2020-04-16 12:31:57 +00:00
|
|
|
|
2021-06-10 08:34:57 +00:00
|
|
|
|
|
|
|
#if USE_MYSQL
|
|
|
|
# include <mysqlxx/PoolFactory.h>
|
|
|
|
#endif
|
|
|
|
|
2018-11-28 11:37:12 +00:00
|
|
|
#include <Poco/Util/AbstractConfiguration.h>
|
2018-12-10 15:25:45 +00:00
|
|
|
#include "DictionarySourceFactory.h"
|
|
|
|
#include "DictionaryStructure.h"
|
2019-12-15 06:34:43 +00:00
|
|
|
#include "registerDictionaries.h"
|
2021-04-10 01:37:56 +00:00
|
|
|
#include <Core/Settings.h>
|
|
|
|
#include <Interpreters/Context.h>
|
2021-10-16 14:03:50 +00:00
|
|
|
#include <QueryPipeline/Pipe.h>
|
|
|
|
#include <QueryPipeline/QueryPipeline.h>
|
2021-12-13 22:06:46 +00:00
|
|
|
#include <Storages/MySQL/MySQLHelpers.h>
|
|
|
|
#include <Storages/MySQL/MySQLSettings.h>
|
2023-02-20 20:37:38 +00:00
|
|
|
#include <Storages/NamedCollectionsHelpers.h>
|
2022-05-27 20:51:37 +00:00
|
|
|
#include <Columns/ColumnString.h>
|
|
|
|
#include <DataTypes/DataTypeString.h>
|
|
|
|
#include <IO/WriteBufferFromString.h>
|
|
|
|
#include <IO/WriteHelpers.h>
|
|
|
|
#include <Common/LocalDateTime.h>
|
2023-04-13 17:33:58 +00:00
|
|
|
#include <Common/parseRemoteDescription.h>
|
2022-05-27 20:51:37 +00:00
|
|
|
#include <Common/logger_useful.h>
|
|
|
|
#include "readInvalidateQuery.h"
|
2021-09-02 13:01:26 +00:00
|
|
|
|
2018-11-28 11:37:12 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
2021-04-10 01:37:56 +00:00
|
|
|
|
|
|
|
[[maybe_unused]]
|
|
|
|
static const size_t default_num_tries_on_connection_loss = 3;
|
|
|
|
|
2018-11-28 11:37:12 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int SUPPORT_IS_DISABLED;
|
2021-07-29 20:57:06 +00:00
|
|
|
extern const int UNSUPPORTED_METHOD;
|
2018-11-28 11:37:12 +00:00
|
|
|
}
|
|
|
|
|
2023-04-13 17:33:58 +00:00
|
|
|
static const ValidateKeysMultiset<ExternalDatabaseEqualKeysSet> dictionary_allowed_keys = {
|
2021-12-29 10:02:18 +00:00
|
|
|
"host", "port", "user", "password",
|
|
|
|
"db", "database", "table", "schema",
|
|
|
|
"update_field", "invalidate_query", "priority",
|
2022-03-07 10:29:10 +00:00
|
|
|
"update_lag", "dont_check_update_time",
|
2021-12-29 10:02:18 +00:00
|
|
|
"query", "where", "name" /* name_collection */, "socket",
|
|
|
|
"share_connection", "fail_on_connection_loss", "close_connection",
|
|
|
|
"ssl_ca", "ssl_cert", "ssl_key",
|
|
|
|
"enable_local_infile", "opt_reconnect",
|
|
|
|
"connect_timeout", "mysql_connect_timeout",
|
|
|
|
"mysql_rw_timeout", "rw_timeout"};
|
|
|
|
|
2018-11-28 11:37:12 +00:00
|
|
|
void registerDictionarySourceMysql(DictionarySourceFactory & factory)
|
|
|
|
{
|
2021-04-10 01:37:56 +00:00
|
|
|
auto create_table_source = [=]([[maybe_unused]] const DictionaryStructure & dict_struct,
|
|
|
|
[[maybe_unused]] const Poco::Util::AbstractConfiguration & config,
|
|
|
|
[[maybe_unused]] const std::string & config_prefix,
|
|
|
|
[[maybe_unused]] Block & sample_block,
|
2021-08-12 15:16:55 +00:00
|
|
|
[[maybe_unused]] ContextPtr global_context,
|
2021-09-03 14:41:00 +00:00
|
|
|
const std::string & /* default_database */,
|
|
|
|
[[maybe_unused]] bool created_from_ddl) -> DictionarySourcePtr {
|
2017-12-09 06:32:22 +00:00
|
|
|
#if USE_MYSQL
|
2021-09-02 13:01:26 +00:00
|
|
|
StreamSettings mysql_input_stream_settings(
|
|
|
|
global_context->getSettingsRef(),
|
|
|
|
config.getBool(config_prefix + ".mysql.close_connection", false) || config.getBool(config_prefix + ".mysql.share_connection", false),
|
|
|
|
false,
|
|
|
|
config.getBool(config_prefix + ".mysql.fail_on_connection_loss", false) ? 1 : default_num_tries_on_connection_loss);
|
2021-06-10 08:34:57 +00:00
|
|
|
|
|
|
|
auto settings_config_prefix = config_prefix + ".mysql";
|
2021-09-25 14:46:03 +00:00
|
|
|
std::shared_ptr<mysqlxx::PoolWithFailover> pool;
|
2022-01-10 11:00:03 +00:00
|
|
|
MySQLSettings mysql_settings;
|
2023-02-20 20:37:38 +00:00
|
|
|
|
2023-04-13 17:33:58 +00:00
|
|
|
std::optional<MySQLDictionarySource::Configuration> dictionary_configuration;
|
2023-06-06 12:46:34 +00:00
|
|
|
auto named_collection = created_from_ddl ? tryGetNamedCollectionWithOverrides(config, settings_config_prefix, global_context) : nullptr;
|
2021-09-25 14:46:03 +00:00
|
|
|
if (named_collection)
|
|
|
|
{
|
2023-04-13 17:33:58 +00:00
|
|
|
auto allowed_arguments{dictionary_allowed_keys};
|
|
|
|
for (const auto & setting : mysql_settings.all())
|
|
|
|
allowed_arguments.insert(setting.getName());
|
|
|
|
validateNamedCollection<ValidateKeysMultiset<ExternalDatabaseEqualKeysSet>>(*named_collection, {}, allowed_arguments);
|
|
|
|
|
|
|
|
StorageMySQL::Configuration::Addresses addresses;
|
|
|
|
const auto addresses_expr = named_collection->getOrDefault<String>("addresses_expr", "");
|
|
|
|
if (addresses_expr.empty())
|
|
|
|
{
|
|
|
|
const auto host = named_collection->getAnyOrDefault<String>({"host", "hostname"}, "");
|
|
|
|
const auto port = static_cast<UInt16>(named_collection->get<UInt64>("port"));
|
|
|
|
addresses = {std::make_pair(host, port)};
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t max_addresses = global_context->getSettingsRef().glob_expansion_max_elements;
|
|
|
|
addresses = parseRemoteDescriptionForExternalDatabase(addresses_expr, max_addresses, 3306);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto & address : addresses)
|
|
|
|
global_context->getRemoteHostFilter().checkHostAndPort(address.first, toString(address.second));
|
|
|
|
|
|
|
|
dictionary_configuration.emplace(MySQLDictionarySource::Configuration{
|
|
|
|
.db = named_collection->getAnyOrDefault<String>({"database", "db"}, ""),
|
|
|
|
.table = named_collection->getOrDefault<String>("table", ""),
|
|
|
|
.query = named_collection->getOrDefault<String>("query", ""),
|
|
|
|
.where = named_collection->getOrDefault<String>("where", ""),
|
|
|
|
.invalidate_query = named_collection->getOrDefault<String>("invalidate_query", ""),
|
|
|
|
.update_field = named_collection->getOrDefault<String>("update_field", ""),
|
|
|
|
.update_lag = named_collection->getOrDefault<UInt64>("update_lag", 1),
|
|
|
|
.dont_check_update_time = named_collection->getOrDefault<bool>("dont_check_update_time", false),
|
|
|
|
});
|
2022-07-13 14:53:23 +00:00
|
|
|
|
2021-12-13 22:06:46 +00:00
|
|
|
const auto & settings = global_context->getSettingsRef();
|
2022-01-10 11:00:03 +00:00
|
|
|
if (!mysql_settings.isChanged("connect_timeout"))
|
|
|
|
mysql_settings.connect_timeout = settings.external_storage_connect_timeout_sec;
|
|
|
|
if (!mysql_settings.isChanged("read_write_timeout"))
|
|
|
|
mysql_settings.read_write_timeout = settings.external_storage_rw_timeout_sec;
|
2023-02-20 20:37:38 +00:00
|
|
|
|
2023-04-13 17:33:58 +00:00
|
|
|
for (const auto & setting : mysql_settings.all())
|
2022-07-13 14:53:23 +00:00
|
|
|
{
|
2023-04-13 17:33:58 +00:00
|
|
|
const auto & setting_name = setting.getName();
|
|
|
|
if (named_collection->has(setting_name))
|
|
|
|
mysql_settings.set(setting_name, named_collection->get<String>(setting_name));
|
2022-07-13 14:53:23 +00:00
|
|
|
}
|
|
|
|
|
2023-04-13 17:33:58 +00:00
|
|
|
pool = std::make_shared<mysqlxx::PoolWithFailover>(
|
|
|
|
createMySQLPoolWithFailover(
|
|
|
|
dictionary_configuration->db,
|
|
|
|
addresses,
|
|
|
|
named_collection->getAnyOrDefault<String>({"user", "username"}, ""),
|
|
|
|
named_collection->getOrDefault<String>("password", ""),
|
|
|
|
mysql_settings));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dictionary_configuration.emplace(MySQLDictionarySource::Configuration{
|
|
|
|
.db = config.getString(settings_config_prefix + ".db", ""),
|
|
|
|
.table = config.getString(settings_config_prefix + ".table", ""),
|
|
|
|
.query = config.getString(settings_config_prefix + ".query", ""),
|
|
|
|
.where = config.getString(settings_config_prefix + ".where", ""),
|
|
|
|
.invalidate_query = config.getString(settings_config_prefix + ".invalidate_query", ""),
|
|
|
|
.update_field = config.getString(settings_config_prefix + ".update_field", ""),
|
|
|
|
.update_lag = config.getUInt64(settings_config_prefix + ".update_lag", 1),
|
|
|
|
.dont_check_update_time = config.getBool(settings_config_prefix + ".dont_check_update_time", false)
|
|
|
|
});
|
|
|
|
|
|
|
|
pool = std::make_shared<mysqlxx::PoolWithFailover>(
|
|
|
|
mysqlxx::PoolFactory::instance().get(config, settings_config_prefix));
|
2021-09-25 14:46:03 +00:00
|
|
|
}
|
|
|
|
|
2023-04-13 17:33:58 +00:00
|
|
|
if (dictionary_configuration->query.empty() && dictionary_configuration->table.empty())
|
2021-07-29 20:57:06 +00:00
|
|
|
throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "MySQL dictionary source configuration must contain table or query field");
|
|
|
|
|
2023-04-13 17:33:58 +00:00
|
|
|
return std::make_unique<MySQLDictionarySource>(dict_struct, *dictionary_configuration, std::move(pool), sample_block, mysql_input_stream_settings);
|
2018-11-28 11:37:12 +00:00
|
|
|
#else
|
2021-04-10 18:48:36 +00:00
|
|
|
throw Exception(ErrorCodes::SUPPORT_IS_DISABLED,
|
|
|
|
"Dictionary source of type `mysql` is disabled because ClickHouse was built without mysql support.");
|
2018-11-28 11:37:12 +00:00
|
|
|
#endif
|
|
|
|
};
|
2021-06-10 08:34:57 +00:00
|
|
|
|
2020-03-23 02:12:31 +00:00
|
|
|
factory.registerSource("mysql", create_table_source);
|
2018-11-28 11:37:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2017-12-09 06:32:22 +00:00
|
|
|
|
2018-11-28 11:37:12 +00:00
|
|
|
|
|
|
|
#if USE_MYSQL
|
2018-06-05 19:46:49 +00:00
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2018-12-10 15:25:45 +00:00
|
|
|
MySQLDictionarySource::MySQLDictionarySource(
|
|
|
|
const DictionaryStructure & dict_struct_,
|
2021-06-10 08:34:57 +00:00
|
|
|
const Configuration & configuration_,
|
|
|
|
mysqlxx::PoolWithFailoverPtr pool_,
|
2021-04-10 01:37:56 +00:00
|
|
|
const Block & sample_block_,
|
|
|
|
const StreamSettings & settings_)
|
2020-05-30 21:57:37 +00:00
|
|
|
: log(&Poco::Logger::get("MySQLDictionarySource"))
|
2021-06-10 08:34:57 +00:00
|
|
|
, update_time(std::chrono::system_clock::from_time_t(0))
|
|
|
|
, dict_struct(dict_struct_)
|
|
|
|
, configuration(configuration_)
|
|
|
|
, pool(std::move(pool_))
|
|
|
|
, sample_block(sample_block_)
|
2021-07-29 20:57:06 +00:00
|
|
|
, query_builder(dict_struct, configuration.db, "", configuration.table, configuration.query, configuration.where, IdentifierQuotingStyle::Backticks)
|
2021-08-09 11:23:44 +00:00
|
|
|
, load_all_query(query_builder.composeLoadAllQuery())
|
2021-04-10 01:37:56 +00:00
|
|
|
, settings(settings_)
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/// copy-constructor is provided in order to support cloneability
|
|
|
|
MySQLDictionarySource::MySQLDictionarySource(const MySQLDictionarySource & other)
|
2020-05-30 21:57:37 +00:00
|
|
|
: log(&Poco::Logger::get("MySQLDictionarySource"))
|
2021-06-10 08:34:57 +00:00
|
|
|
, update_time(other.update_time)
|
|
|
|
, dict_struct(other.dict_struct)
|
|
|
|
, configuration(other.configuration)
|
|
|
|
, pool(other.pool)
|
|
|
|
, sample_block(other.sample_block)
|
2021-07-29 20:57:06 +00:00
|
|
|
, query_builder{dict_struct, configuration.db, "", configuration.table, configuration.query, configuration.where, IdentifierQuotingStyle::Backticks}
|
2018-12-10 15:25:45 +00:00
|
|
|
, load_all_query{other.load_all_query}
|
|
|
|
, last_modification{other.last_modification}
|
|
|
|
, invalidate_query_response{other.invalidate_query_response}
|
2021-04-10 01:37:56 +00:00
|
|
|
, settings(other.settings)
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-02-15 13:08:23 +00:00
|
|
|
std::string MySQLDictionarySource::getUpdateFieldAndDate()
|
2018-01-15 12:44:39 +00:00
|
|
|
{
|
2018-02-15 13:08:23 +00:00
|
|
|
if (update_time != std::chrono::system_clock::from_time_t(0))
|
2018-01-15 12:44:39 +00:00
|
|
|
{
|
2021-06-10 08:34:57 +00:00
|
|
|
time_t hr_time = std::chrono::system_clock::to_time_t(update_time) - configuration.update_lag;
|
2021-03-15 19:23:27 +00:00
|
|
|
std::string str_time = DateLUT::instance().timeToString(hr_time);
|
2018-01-15 12:44:39 +00:00
|
|
|
update_time = std::chrono::system_clock::now();
|
2021-06-10 08:34:57 +00:00
|
|
|
return query_builder.composeUpdateQuery(configuration.update_field, str_time);
|
2018-01-15 12:44:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
update_time = std::chrono::system_clock::now();
|
2021-07-29 20:57:06 +00:00
|
|
|
return load_all_query;
|
2018-01-15 12:44:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-20 19:49:31 +00:00
|
|
|
QueryPipeline MySQLDictionarySource::loadFromQuery(const String & query)
|
2021-02-27 08:18:28 +00:00
|
|
|
{
|
2022-05-20 19:49:31 +00:00
|
|
|
return QueryPipeline(std::make_shared<MySQLWithFailoverSource>(
|
2021-08-05 18:08:52 +00:00
|
|
|
pool, query, sample_block, settings));
|
2021-02-27 08:18:28 +00:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:49:31 +00:00
|
|
|
QueryPipeline MySQLDictionarySource::loadAll()
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
2021-03-27 14:35:44 +00:00
|
|
|
auto connection = pool->get();
|
2020-02-27 09:34:06 +00:00
|
|
|
last_modification = getLastModification(connection, false);
|
2016-06-05 15:21:35 +00:00
|
|
|
|
Use fmt::runtime() for LOG_* for non constexpr
Here is oneliner:
$ gg 'LOG_\(DEBUG\|TRACE\|INFO\|TEST\|WARNING\|ERROR\|FATAL\)([^,]*, [a-zA-Z]' -- :*.cpp :*.h | cut -d: -f1 | sort -u | xargs -r sed -E -i 's#(LOG_[A-Z]*)\(([^,]*), ([A-Za-z][^,)]*)#\1(\2, fmt::runtime(\3)#'
Note, that I tried to do this with coccinelle (tool for semantic
patchin), but it cannot parse C++:
$ cat fmt.cocci
@@
expression log;
expression var;
@@
-LOG_DEBUG(log, var)
+LOG_DEBUG(log, fmt::runtime(var))
I've also tried to use some macros/templates magic to do this implicitly
in logger_useful.h, but I failed to do so, and apparently it is not
possible for now.
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
v2: manual fixes
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2022-02-01 09:10:27 +00:00
|
|
|
LOG_TRACE(log, fmt::runtime(load_all_query));
|
2021-04-02 16:12:14 +00:00
|
|
|
return loadFromQuery(load_all_query);
|
2018-02-15 13:08:23 +00:00
|
|
|
}
|
2018-01-15 12:44:39 +00:00
|
|
|
|
2022-05-20 19:49:31 +00:00
|
|
|
QueryPipeline MySQLDictionarySource::loadUpdatedAll()
|
2018-02-15 13:08:23 +00:00
|
|
|
{
|
2021-03-27 14:35:44 +00:00
|
|
|
auto connection = pool->get();
|
2020-02-27 09:34:06 +00:00
|
|
|
last_modification = getLastModification(connection, false);
|
2018-01-15 12:44:39 +00:00
|
|
|
|
2018-02-15 13:08:23 +00:00
|
|
|
std::string load_update_query = getUpdateFieldAndDate();
|
Use fmt::runtime() for LOG_* for non constexpr
Here is oneliner:
$ gg 'LOG_\(DEBUG\|TRACE\|INFO\|TEST\|WARNING\|ERROR\|FATAL\)([^,]*, [a-zA-Z]' -- :*.cpp :*.h | cut -d: -f1 | sort -u | xargs -r sed -E -i 's#(LOG_[A-Z]*)\(([^,]*), ([A-Za-z][^,)]*)#\1(\2, fmt::runtime(\3)#'
Note, that I tried to do this with coccinelle (tool for semantic
patchin), but it cannot parse C++:
$ cat fmt.cocci
@@
expression log;
expression var;
@@
-LOG_DEBUG(log, var)
+LOG_DEBUG(log, fmt::runtime(var))
I've also tried to use some macros/templates magic to do this implicitly
in logger_useful.h, but I failed to do so, and apparently it is not
possible for now.
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
v2: manual fixes
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2022-02-01 09:10:27 +00:00
|
|
|
LOG_TRACE(log, fmt::runtime(load_update_query));
|
2021-04-02 16:12:14 +00:00
|
|
|
return loadFromQuery(load_update_query);
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:49:31 +00:00
|
|
|
QueryPipeline MySQLDictionarySource::loadIds(const std::vector<UInt64> & ids)
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
2017-03-26 01:28:07 +00:00
|
|
|
/// We do not log in here and do not update the modification time, as the request can be large, and often called.
|
2016-06-05 15:21:35 +00:00
|
|
|
const auto query = query_builder.composeLoadIdsQuery(ids);
|
2021-04-02 16:12:14 +00:00
|
|
|
return loadFromQuery(query);
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
2022-05-20 19:49:31 +00:00
|
|
|
QueryPipeline MySQLDictionarySource::loadKeys(const Columns & key_columns, const std::vector<size_t> & requested_rows)
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
2017-03-26 01:28:07 +00:00
|
|
|
/// We do not log in here and do not update the modification time, as the request can be large, and often called.
|
2016-06-05 15:21:35 +00:00
|
|
|
const auto query = query_builder.composeLoadKeysQuery(key_columns, requested_rows, ExternalQueryBuilder::AND_OR_CHAIN);
|
2021-04-02 16:12:14 +00:00
|
|
|
return loadFromQuery(query);
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MySQLDictionarySource::isModified() const
|
|
|
|
{
|
2021-06-10 08:34:57 +00:00
|
|
|
if (!configuration.invalidate_query.empty())
|
2017-05-15 14:16:10 +00:00
|
|
|
{
|
2021-06-10 08:34:57 +00:00
|
|
|
auto response = doInvalidateQuery(configuration.invalidate_query);
|
2023-02-19 22:15:09 +00:00
|
|
|
if (response == invalidate_query_response)
|
2017-05-15 14:16:10 +00:00
|
|
|
return false;
|
2021-06-10 08:34:57 +00:00
|
|
|
|
2017-05-15 14:16:10 +00:00
|
|
|
invalidate_query_response = response;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-10 08:34:57 +00:00
|
|
|
if (configuration.dont_check_update_time)
|
2016-06-05 15:21:35 +00:00
|
|
|
return true;
|
2021-06-10 08:34:57 +00:00
|
|
|
|
2021-03-27 14:35:44 +00:00
|
|
|
auto connection = pool->get();
|
2020-02-27 09:34:06 +00:00
|
|
|
return getLastModification(connection, true) > last_modification;
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MySQLDictionarySource::supportsSelectiveLoad() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-01-15 12:44:39 +00:00
|
|
|
bool MySQLDictionarySource::hasUpdateField() const
|
|
|
|
{
|
2021-06-10 08:34:57 +00:00
|
|
|
return !configuration.update_field.empty();
|
2018-01-15 12:44:39 +00:00
|
|
|
}
|
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
DictionarySourcePtr MySQLDictionarySource::clone() const
|
|
|
|
{
|
2021-12-15 12:55:28 +00:00
|
|
|
return std::make_shared<MySQLDictionarySource>(*this);
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string MySQLDictionarySource::toString() const
|
|
|
|
{
|
2021-06-10 08:34:57 +00:00
|
|
|
const auto & where = configuration.where;
|
|
|
|
return "MySQL: " + configuration.db + '.' + configuration.table + (where.empty() ? "" : ", where: " + where);
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 08:34:57 +00:00
|
|
|
std::string MySQLDictionarySource::quoteForLike(const std::string & value)
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
|
|
|
std::string tmp;
|
2021-06-10 08:34:57 +00:00
|
|
|
tmp.reserve(value.size());
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-06-10 08:34:57 +00:00
|
|
|
for (auto c : value)
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
|
|
|
if (c == '%' || c == '_' || c == '\\')
|
|
|
|
tmp.push_back('\\');
|
|
|
|
tmp.push_back(c);
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2017-07-31 21:39:24 +00:00
|
|
|
WriteBufferFromOwnString out;
|
|
|
|
writeQuoted(tmp, out);
|
|
|
|
return out.str();
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
2020-02-27 09:34:06 +00:00
|
|
|
LocalDateTime MySQLDictionarySource::getLastModification(mysqlxx::Pool::Entry & connection, bool allow_connection_closure) const
|
2016-06-05 15:21:35 +00:00
|
|
|
{
|
2018-08-10 04:02:56 +00:00
|
|
|
LocalDateTime modification_time{std::time(nullptr)};
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-06-10 08:34:57 +00:00
|
|
|
if (configuration.dont_check_update_time)
|
2018-08-10 04:02:56 +00:00
|
|
|
return modification_time;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
try
|
|
|
|
{
|
2021-06-10 08:34:57 +00:00
|
|
|
auto query = connection->query("SHOW TABLE STATUS LIKE " + quoteForLike(configuration.table));
|
2017-04-01 07:20:54 +00:00
|
|
|
|
Use fmt::runtime() for LOG_* for non constexpr
Here is oneliner:
$ gg 'LOG_\(DEBUG\|TRACE\|INFO\|TEST\|WARNING\|ERROR\|FATAL\)([^,]*, [a-zA-Z]' -- :*.cpp :*.h | cut -d: -f1 | sort -u | xargs -r sed -E -i 's#(LOG_[A-Z]*)\(([^,]*), ([A-Za-z][^,)]*)#\1(\2, fmt::runtime(\3)#'
Note, that I tried to do this with coccinelle (tool for semantic
patchin), but it cannot parse C++:
$ cat fmt.cocci
@@
expression log;
expression var;
@@
-LOG_DEBUG(log, var)
+LOG_DEBUG(log, fmt::runtime(var))
I've also tried to use some macros/templates magic to do this implicitly
in logger_useful.h, but I failed to do so, and apparently it is not
possible for now.
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
v2: manual fixes
Signed-off-by: Azat Khuzhin <a.khuzhin@semrush.com>
2022-02-01 09:10:27 +00:00
|
|
|
LOG_TRACE(log, fmt::runtime(query.str()));
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
auto result = query.use();
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
size_t fetched_rows = 0;
|
|
|
|
if (auto row = result.fetch())
|
|
|
|
{
|
|
|
|
++fetched_rows;
|
2020-03-23 02:12:31 +00:00
|
|
|
static const auto UPDATE_TIME_IDX = 12;
|
2016-06-05 15:21:35 +00:00
|
|
|
const auto & update_time_value = row[UPDATE_TIME_IDX];
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
if (!update_time_value.isNull())
|
|
|
|
{
|
2018-08-10 04:02:56 +00:00
|
|
|
modification_time = update_time_value.getDateTime();
|
2021-03-15 19:23:27 +00:00
|
|
|
LOG_TRACE(log, "Got modification time: {}", update_time_value.getString());
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
/// fetch remaining rows to avoid "commands out of sync" error
|
|
|
|
while (result.fetch())
|
|
|
|
++fetched_rows;
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2021-04-10 01:37:56 +00:00
|
|
|
if (settings.auto_close && allow_connection_closure)
|
2020-02-27 09:34:06 +00:00
|
|
|
{
|
|
|
|
connection.disconnect();
|
|
|
|
}
|
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
if (0 == fetched_rows)
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_ERROR(log, "Cannot find table in SHOW TABLE STATUS result.");
|
2017-04-01 07:20:54 +00:00
|
|
|
|
2016-06-05 15:21:35 +00:00
|
|
|
if (fetched_rows > 1)
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_ERROR(log, "Found more than one table in SHOW TABLE STATUS result.");
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
tryLogCurrentException("MySQLDictionarySource");
|
|
|
|
}
|
|
|
|
/// we suppose failure to get modification time is not an error, therefore return current time
|
2018-08-10 04:02:56 +00:00
|
|
|
return modification_time;
|
2016-06-05 15:21:35 +00:00
|
|
|
}
|
|
|
|
|
2017-05-22 16:38:24 +00:00
|
|
|
std::string MySQLDictionarySource::doInvalidateQuery(const std::string & request) const
|
2017-05-15 14:16:10 +00:00
|
|
|
{
|
2018-08-10 04:02:56 +00:00
|
|
|
Block invalidate_sample_block;
|
2017-12-14 01:43:19 +00:00
|
|
|
ColumnPtr column(ColumnString::create());
|
2018-08-10 04:02:56 +00:00
|
|
|
invalidate_sample_block.insert(ColumnWithTypeAndName(column, std::make_shared<DataTypeString>(), "Sample Block"));
|
2021-09-16 17:40:42 +00:00
|
|
|
return readInvalidateQuery(QueryPipeline(std::make_unique<MySQLSource>(pool->get(), request, invalidate_sample_block, settings)));
|
2017-05-15 14:16:10 +00:00
|
|
|
}
|
2016-06-05 15:21:35 +00:00
|
|
|
|
|
|
|
}
|
2017-04-19 00:25:57 +00:00
|
|
|
|
2021-08-06 08:41:45 +00:00
|
|
|
#endif
|