1#pragma once
2
3#include <Common/Exception.h>
4#include <Common/NamePrompter.h>
5#include <Core/Types.h>
6#include <Poco/String.h>
7
8#include <unordered_map>
9
10namespace DB
11{
12
13namespace ErrorCodes
14{
15 extern const int LOGICAL_ERROR;
16}
17
18/** If stored objects may have several names (aliases)
19 * this interface may be helpful
20 * template parameter is available as Creator
21 */
22template <typename CreatorFunc>
23class IFactoryWithAliases : public IHints<2, IFactoryWithAliases<CreatorFunc>>
24{
25protected:
26 using Creator = CreatorFunc;
27
28 String getAliasToOrName(const String & name) const
29 {
30 if (aliases.count(name))
31 return aliases.at(name);
32 else if (String name_lowercase = Poco::toLower(name); case_insensitive_aliases.count(name_lowercase))
33 return case_insensitive_aliases.at(name_lowercase);
34 else
35 return name;
36 }
37
38public:
39 /// For compatibility with SQL, it's possible to specify that certain function name is case insensitive.
40 enum CaseSensitiveness
41 {
42 CaseSensitive,
43 CaseInsensitive
44 };
45
46 /** Register additional name for creator
47 * real_name have to be already registered.
48 */
49 void registerAlias(const String & alias_name, const String & real_name, CaseSensitiveness case_sensitiveness = CaseSensitive)
50 {
51 const auto & creator_map = getCreatorMap();
52 const auto & case_insensitive_creator_map = getCaseInsensitiveCreatorMap();
53 const String factory_name = getFactoryName();
54
55 String real_dict_name;
56 if (creator_map.count(real_name))
57 real_dict_name = real_name;
58 else if (auto real_name_lowercase = Poco::toLower(real_name); case_insensitive_creator_map.count(real_name_lowercase))
59 real_dict_name = real_name_lowercase;
60 else
61 throw Exception(factory_name + ": can't create alias '" + alias_name + "', the real name '" + real_name + "' is not registered",
62 ErrorCodes::LOGICAL_ERROR);
63
64 String alias_name_lowercase = Poco::toLower(alias_name);
65
66 if (creator_map.count(alias_name) || case_insensitive_creator_map.count(alias_name_lowercase))
67 throw Exception(
68 factory_name + ": the alias name '" + alias_name + "' is already registered as real name", ErrorCodes::LOGICAL_ERROR);
69
70 if (case_sensitiveness == CaseInsensitive)
71 if (!case_insensitive_aliases.emplace(alias_name_lowercase, real_dict_name).second)
72 throw Exception(
73 factory_name + ": case insensitive alias name '" + alias_name + "' is not unique", ErrorCodes::LOGICAL_ERROR);
74
75 if (!aliases.emplace(alias_name, real_dict_name).second)
76 throw Exception(factory_name + ": alias name '" + alias_name + "' is not unique", ErrorCodes::LOGICAL_ERROR);
77 }
78
79 std::vector<String> getAllRegisteredNames() const override
80 {
81 std::vector<String> result;
82 auto getter = [](const auto & pair) { return pair.first; };
83 std::transform(getCreatorMap().begin(), getCreatorMap().end(), std::back_inserter(result), getter);
84 std::transform(aliases.begin(), aliases.end(), std::back_inserter(result), getter);
85 return result;
86 }
87
88 bool isCaseInsensitive(const String & name) const
89 {
90 String name_lowercase = Poco::toLower(name);
91 return getCaseInsensitiveCreatorMap().count(name_lowercase) || case_insensitive_aliases.count(name_lowercase);
92 }
93
94 const String & aliasTo(const String & name) const
95 {
96 if (auto it = aliases.find(name); it != aliases.end())
97 return it->second;
98 else if (auto jt = case_insensitive_aliases.find(Poco::toLower(name)); jt != case_insensitive_aliases.end())
99 return jt->second;
100
101 throw Exception(getFactoryName() + ": name '" + name + "' is not alias", ErrorCodes::LOGICAL_ERROR);
102 }
103
104 bool isAlias(const String & name) const
105 {
106 return aliases.count(name) || case_insensitive_aliases.count(name);
107 }
108
109 virtual ~IFactoryWithAliases() override {}
110
111private:
112 using InnerMap = std::unordered_map<String, Creator>; // name -> creator
113 using AliasMap = std::unordered_map<String, String>; // alias -> original type
114
115 virtual const InnerMap & getCreatorMap() const = 0;
116 virtual const InnerMap & getCaseInsensitiveCreatorMap() const = 0;
117 virtual String getFactoryName() const = 0;
118
119 /// Alias map to data_types from previous two maps
120 AliasMap aliases;
121
122 /// Case insensitive aliases
123 AliasMap case_insensitive_aliases;
124};
125
126}
127