Skip to content

Commit 06e7def

Browse files
authored
Merge pull request ClickHouse#78582 from MikhailBurdukov/create_named_collection
Add create_query, source columns to system.named_collections
2 parents 94264b1 + 5556274 commit 06e7def

File tree

9 files changed

+295
-131
lines changed

9 files changed

+295
-131
lines changed

src/Common/NamedCollections/NamedCollections.cpp

Lines changed: 135 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <IO/Operators.h>
66
#include <Common/NamedCollections/NamedCollectionConfiguration.h>
77
#include <Poco/Util/AbstractConfiguration.h>
8+
#include <Common/FieldVisitorToString.h>
89

910
#include <fmt/ranges.h>
1011

@@ -16,6 +17,7 @@ namespace ErrorCodes
1617
{
1718
extern const int NAMED_COLLECTION_IS_IMMUTABLE;
1819
extern const int BAD_ARGUMENTS;
20+
extern const int NOT_IMPLEMENTED;
1921
}
2022

2123
namespace Configuration = NamedCollectionConfiguration;
@@ -176,27 +178,14 @@ class NamedCollection::Impl
176178
NamedCollection::NamedCollection(
177179
ImplPtr pimpl_,
178180
const std::string & collection_name_,
179-
SourceId source_id_,
180-
bool is_mutable_)
181+
const bool is_mutable_)
181182
: pimpl(std::move(pimpl_))
182183
, collection_name(collection_name_)
183-
, source_id(source_id_)
184184
, is_mutable(is_mutable_)
185185
{
186186
}
187187

188-
MutableNamedCollectionPtr NamedCollection::create(
189-
const Poco::Util::AbstractConfiguration & config,
190-
const std::string & collection_name,
191-
const std::string & collection_path,
192-
const Keys & keys,
193-
SourceId source_id,
194-
bool is_mutable)
195-
{
196-
auto impl = Impl::create(config, collection_name, collection_path, keys);
197-
return std::unique_ptr<NamedCollection>(
198-
new NamedCollection(std::move(impl), collection_name, source_id, is_mutable));
199-
}
188+
NamedCollection::~NamedCollection() = default;
200189

201190
bool NamedCollection::has(const Key & key) const
202191
{
@@ -297,8 +286,7 @@ MutableNamedCollectionPtr NamedCollection::duplicate() const
297286
std::lock_guard lock(mutex);
298287
auto impl = pimpl->createCopy(collection_name);
299288
return std::unique_ptr<NamedCollection>(
300-
new NamedCollection(
301-
std::move(impl), collection_name, SourceId::NONE, true));
289+
new NamedCollection(std::move(impl), collection_name, true));
302290
}
303291

304292
NamedCollection::Keys NamedCollection::getKeys(ssize_t depth, const std::string & prefix) const
@@ -334,6 +322,136 @@ std::unique_lock<std::mutex> NamedCollection::lock()
334322
return std::unique_lock(mutex);
335323
}
336324

325+
326+
void NamedCollection::update(const ASTAlterNamedCollectionQuery & /*query*/)
327+
{
328+
throw Exception(
329+
ErrorCodes::NOT_IMPLEMENTED,
330+
"update() not implemented for NamedCollection base class.");
331+
}
332+
333+
NamedCollectionFromConfig::NamedCollectionFromConfig(
334+
const Poco::Util::AbstractConfiguration & config_,
335+
const std::string & collection_name_,
336+
const std::string & collection_path_,
337+
const Keys & keys_)
338+
: NamedCollection(Impl::create(config_, collection_name_, collection_path_, keys_), collection_name_, /* is_mutable */ false)
339+
{
340+
}
341+
342+
MutableNamedCollectionPtr NamedCollectionFromConfig::create(
343+
const Poco::Util::AbstractConfiguration & config_,
344+
const std::string & collection_name_,
345+
const std::string & collection_path_,
346+
const Keys & keys_)
347+
{
348+
return std::unique_ptr<NamedCollection>(
349+
new NamedCollectionFromConfig(config_, collection_name_, collection_path_, keys_));
350+
}
351+
352+
353+
MutableNamedCollectionPtr NamedCollectionFromSQL::create(const ASTCreateNamedCollectionQuery & query)
354+
{
355+
return std::unique_ptr<NamedCollection>(new NamedCollectionFromSQL(query));
356+
}
357+
358+
NamedCollectionFromSQL::NamedCollectionFromSQL(const ASTCreateNamedCollectionQuery & query_)
359+
: NamedCollection(nullptr, query_.collection_name, true)
360+
, create_query_ptr(query_.clone()->as<ASTCreateNamedCollectionQuery &>())
361+
{
362+
const auto config = NamedCollectionConfiguration::createConfiguration(collection_name, create_query_ptr.changes, create_query_ptr.overridability);
363+
364+
std::set<std::string, std::less<>> keys;
365+
for (const auto & [name, _] : create_query_ptr.changes)
366+
keys.insert(name);
367+
368+
pimpl = Impl::create(*config, collection_name, "", keys);
369+
}
370+
371+
String NamedCollectionFromSQL::getCreateStatement(bool show_secrects)
372+
{
373+
auto & changes = create_query_ptr.changes;
374+
std::sort(
375+
changes.begin(), changes.end(),
376+
[](const SettingChange & lhs, const SettingChange & rhs) { return lhs.name < rhs.name; });
377+
378+
return create_query_ptr.formatWithPossiblyHidingSensitiveData(
379+
/*max_length=*/0,
380+
/*one_line=*/true,
381+
/*show_secrets=*/show_secrects,
382+
/*print_pretty_type_names=*/false,
383+
/*identifier_quoting_rule=*/IdentifierQuotingRule::WhenNecessary,
384+
/*identifier_quoting_style=*/IdentifierQuotingStyle::Backticks);
385+
}
386+
387+
void NamedCollectionFromSQL::update(const ASTAlterNamedCollectionQuery & alter_query)
388+
{
389+
std::lock_guard lock(mutex);
390+
391+
std::unordered_map<std::string, Field> result_changes_map;
392+
for (const auto & [name, value] : alter_query.changes)
393+
{
394+
auto [it, inserted] = result_changes_map.emplace(name, value);
395+
if (!inserted)
396+
{
397+
throw Exception(
398+
ErrorCodes::BAD_ARGUMENTS,
399+
"Value with key `{}` is used twice in the SET query (collection name: {})",
400+
name, alter_query.collection_name);
401+
}
402+
}
403+
404+
for (const auto & [name, value] : create_query_ptr.changes)
405+
result_changes_map.emplace(name, value);
406+
407+
std::unordered_map<std::string, bool> result_overridability_map;
408+
for (const auto & [name, value] : alter_query.overridability)
409+
result_overridability_map.emplace(name, value);
410+
for (const auto & [name, value] : create_query_ptr.overridability)
411+
result_overridability_map.emplace(name, value);
412+
413+
for (const auto & delete_key : alter_query.delete_keys)
414+
{
415+
auto it = result_changes_map.find(delete_key);
416+
if (it == result_changes_map.end())
417+
{
418+
throw Exception(
419+
ErrorCodes::BAD_ARGUMENTS,
420+
"Cannot delete key `{}` because it does not exist in collection",
421+
delete_key);
422+
}
423+
424+
result_changes_map.erase(it);
425+
auto it_override = result_overridability_map.find(delete_key);
426+
if (it_override != result_overridability_map.end())
427+
result_overridability_map.erase(it_override);
428+
}
429+
430+
create_query_ptr.changes.clear();
431+
for (const auto & [name, value] : result_changes_map)
432+
create_query_ptr.changes.emplace_back(name, value);
433+
create_query_ptr.overridability = std::move(result_overridability_map);
434+
435+
if (create_query_ptr.changes.empty())
436+
throw Exception(
437+
ErrorCodes::BAD_ARGUMENTS,
438+
"Named collection cannot be empty (collection name: {})",
439+
collection_name);
440+
441+
chassert(create_query_ptr.collection_name == alter_query.collection_name);
442+
for (const auto & [name, value] : alter_query.changes)
443+
{
444+
auto it_override = alter_query.overridability.find(name);
445+
if (it_override != alter_query.overridability.end())
446+
setOrUpdate<String, true>(name, convertFieldToString(value), it_override->second);
447+
else
448+
setOrUpdate<String, true>(name, convertFieldToString(value), {});
449+
}
450+
451+
for (const auto & key : alter_query.delete_keys)
452+
remove<true>(key);
453+
}
454+
337455
template String NamedCollection::get<String>(const NamedCollection::Key & key) const;
338456
template UInt64 NamedCollection::get<UInt64>(const NamedCollection::Key & key) const;
339457
template Int64 NamedCollection::get<Int64>(const NamedCollection::Key & key) const;

src/Common/NamedCollections/NamedCollections.h

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#pragma once
22
#include <Interpreters/Context.h>
33
#include <Common/NamedCollections/NamedCollections_fwd.h>
4+
#include <Parsers/ASTCreateNamedCollectionQuery.h>
5+
#include <Parsers/ASTAlterNamedCollectionQuery.h>
6+
47

58
namespace Poco { namespace Util { class AbstractConfiguration; } }
69

@@ -24,19 +27,13 @@ class NamedCollection
2427
using Keys = std::set<Key, std::less<>>;
2528
enum class SourceId : uint8_t
2629
{
30+
/// None source_id is possible only if the object is a
31+
/// duplicate of some named collection. See `duplicate` method.
2732
NONE = 0,
2833
CONFIG = 1,
2934
SQL = 2,
3035
};
3136

32-
static MutableNamedCollectionPtr create(
33-
const Poco::Util::AbstractConfiguration & config,
34-
const std::string & collection_name,
35-
const std::string & collection_path,
36-
const Keys & keys,
37-
SourceId source_id_,
38-
bool is_mutable_);
39-
4037
bool has(const Key & key) const;
4138

4239
bool hasAny(const std::initializer_list<Key> & keys) const;
@@ -61,6 +58,7 @@ class NamedCollection
6158

6259
template <bool locked = false> void remove(const Key & key);
6360

61+
/// Creates mutable, with NONE source id full copy.
6462
MutableNamedCollectionPtr duplicate() const;
6563

6664
Keys getKeys(ssize_t depth = -1, const std::string & prefix = "") const;
@@ -76,25 +74,72 @@ class NamedCollection
7674

7775
bool isMutable() const { return is_mutable; }
7876

79-
SourceId getSourceId() const { return source_id; }
77+
virtual SourceId getSourceId() const { return SourceId::NONE; }
8078

81-
private:
79+
virtual String getCreateStatement(bool /*show_secrects*/) { return {}; }
80+
81+
virtual void update(const ASTAlterNamedCollectionQuery & query);
82+
83+
virtual ~NamedCollection();
84+
85+
protected:
8286
class Impl;
8387
using ImplPtr = std::unique_ptr<Impl>;
84-
8588
NamedCollection(
8689
ImplPtr pimpl_,
8790
const std::string & collection_name,
88-
SourceId source_id,
89-
bool is_mutable);
91+
bool is_mutable_
92+
);
9093

9194
void assertMutable() const;
9295

96+
9397
ImplPtr pimpl;
9498
const std::string collection_name;
95-
const SourceId source_id;
9699
const bool is_mutable;
97100
mutable std::mutex mutex;
98101
};
99102

103+
class NamedCollectionFromSQL final : public NamedCollection
104+
{
105+
public:
106+
static MutableNamedCollectionPtr create(const ASTCreateNamedCollectionQuery & query);
107+
108+
String getCreateStatement(bool show_secrects) override;
109+
110+
void update(const ASTAlterNamedCollectionQuery & query) override;
111+
112+
NamedCollection::SourceId getSourceId() const override { return SourceId::SQL; }
113+
114+
private:
115+
explicit NamedCollectionFromSQL(const ASTCreateNamedCollectionQuery & query_);
116+
117+
ASTCreateNamedCollectionQuery create_query_ptr;
118+
};
119+
120+
class NamedCollectionFromConfig final : public NamedCollection
121+
{
122+
public:
123+
124+
static MutableNamedCollectionPtr create(
125+
const Poco::Util::AbstractConfiguration & config,
126+
const std::string & collection_name,
127+
const std::string & collection_path,
128+
const Keys & keys);
129+
130+
String getCreateStatement(bool /*show_secrects*/) override { return {}; }
131+
132+
void update(const ASTAlterNamedCollectionQuery & /*query*/) override { NamedCollection::assertMutable(); }
133+
134+
NamedCollection::SourceId getSourceId() const override { return SourceId::CONFIG; }
135+
136+
private:
137+
138+
NamedCollectionFromConfig(
139+
const Poco::Util::AbstractConfiguration & config,
140+
const std::string & collection_name,
141+
const std::string & collection_path,
142+
const Keys & keys);
143+
};
144+
100145
}

src/Common/NamedCollections/NamedCollectionsFactory.cpp

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace ErrorCodes
1515
extern const int NAMED_COLLECTION_DOESNT_EXIST;
1616
extern const int NAMED_COLLECTION_ALREADY_EXISTS;
1717
extern const int NAMED_COLLECTION_IS_IMMUTABLE;
18+
extern const int LOGICAL_ERROR;
1819
}
1920

2021
NamedCollectionFactory & NamedCollectionFactory::instance()
@@ -200,8 +201,8 @@ namespace
200201
keys.emplace(path.substr(collection_prefix.size() + 1));
201202
}
202203

203-
return NamedCollection::create(
204-
config, collection_name, collection_prefix, keys, NamedCollection::SourceId::CONFIG, /* is_mutable */false);
204+
return NamedCollectionFromConfig::create(
205+
config, collection_name, collection_prefix, keys);
205206
}
206207

207208
NamedCollectionsMap getNamedCollections(const Poco::Util::AbstractConfiguration & config)
@@ -321,33 +322,37 @@ void NamedCollectionFactory::updateFromSQL(const ASTAlterNamedCollectionQuery &
321322
std::lock_guard lock(mutex);
322323
loadIfNot(lock);
323324

324-
if (!exists(query.collection_name, lock))
325+
auto collection_name = query.collection_name;
326+
if (!exists(collection_name, lock))
325327
{
326328
if (query.if_exists)
327329
return;
328330

329331
throw Exception(
330332
ErrorCodes::NAMED_COLLECTION_DOESNT_EXIST,
331-
"Cannot remove collection `{}`, because it doesn't exist",
332-
query.collection_name);
333+
"Cannot update collection `{}`, because it doesn't exist",
334+
collection_name);
333335
}
336+
auto updated_collection_ptr = metadata_storage->update(query);
334337

335-
metadata_storage->update(query);
336-
337-
auto collection = getMutable(query.collection_name, lock);
338-
auto collection_lock = collection->lock();
339-
340-
for (const auto & [name, value] : query.changes)
338+
auto it = loaded_named_collections.find(collection_name);
339+
if (it == loaded_named_collections.end())
341340
{
342-
auto it_override = query.overridability.find(name);
343-
if (it_override != query.overridability.end())
344-
collection->setOrUpdate<String, true>(name, convertFieldToString(value), it_override->second);
345-
else
346-
collection->setOrUpdate<String, true>(name, convertFieldToString(value), {});
341+
throw Exception(
342+
ErrorCodes::LOGICAL_ERROR,
343+
"The named collection {} unexpectedly does not exist.",
344+
collection_name);
347345
}
348346

349-
for (const auto & key : query.delete_keys)
350-
collection->remove<true>(key);
347+
if (!it->second->isMutable())
348+
{
349+
throw Exception(
350+
ErrorCodes::NAMED_COLLECTION_IS_IMMUTABLE,
351+
"Cannot get collection `{}` for modification, "
352+
"because collection was defined as immutable",
353+
collection_name);
354+
}
355+
it->second = updated_collection_ptr;
351356
}
352357

353358
void NamedCollectionFactory::reloadFromSQL()

0 commit comments

Comments
 (0)