1#include <Poco/Util/AbstractConfiguration.h>
2#include <Common/Macros.h>
3#include <Common/Exception.h>
4#include <IO/WriteHelpers.h>
5
6
7namespace DB
8{
9
10namespace ErrorCodes
11{
12 extern const int SYNTAX_ERROR;
13}
14
15Macros::Macros() {}
16
17Macros::Macros(const Poco::Util::AbstractConfiguration & config, const String & root_key)
18{
19 Poco::Util::AbstractConfiguration::Keys keys;
20 config.keys(root_key, keys);
21 for (const String & key : keys)
22 {
23 macros[key] = config.getString(root_key + "." + key);
24 }
25}
26
27String Macros::expand(const String & s, size_t level, const String & database_name, const String & table_name) const
28{
29 if (s.find('{') == String::npos)
30 return s;
31
32 if (level && s.size() > 65536)
33 throw Exception("Too long string while expanding macros", ErrorCodes::SYNTAX_ERROR);
34
35 if (level >= 10)
36 throw Exception("Too deep recursion while expanding macros: '" + s + "'", ErrorCodes::SYNTAX_ERROR);
37
38 String res;
39 size_t pos = 0;
40 while (true)
41 {
42 size_t begin = s.find('{', pos);
43
44 if (begin == String::npos)
45 {
46 res.append(s, pos, String::npos);
47 break;
48 }
49 else
50 {
51 res.append(s, pos, begin - pos);
52 }
53
54 ++begin;
55 size_t end = s.find('}', begin);
56 if (end == String::npos)
57 throw Exception("Unbalanced { and } in string with macros: '" + s + "'", ErrorCodes::SYNTAX_ERROR);
58
59 String macro_name = s.substr(begin, end - begin);
60 auto it = macros.find(macro_name);
61
62 /// Prefer explicit macros over implicit.
63 if (it != macros.end())
64 res += it->second;
65 else if (macro_name == "database" && !database_name.empty())
66 res += database_name;
67 else if (macro_name == "table" && !table_name.empty())
68 res += table_name;
69 else
70 throw Exception("No macro '" + macro_name +
71 "' in config while processing substitutions in '" + s + "' at "
72 + toString(begin), ErrorCodes::SYNTAX_ERROR);
73
74 pos = end + 1;
75 }
76
77 return expand(res, level + 1, database_name, table_name);
78}
79
80String Macros::getValue(const String & key) const
81{
82 if (auto it = macros.find(key); it != macros.end())
83 return it->second;
84 throw Exception("No macro " + key + " in config", ErrorCodes::SYNTAX_ERROR);
85}
86
87String Macros::expand(const String & s, const String & database_name, const String & table_name) const
88{
89 return expand(s, 0, database_name, table_name);
90}
91
92Names Macros::expand(const Names & source_names, size_t level) const
93{
94 Names result_names;
95 result_names.reserve(source_names.size());
96
97 for (const String & name : source_names)
98 result_names.push_back(expand(name, level));
99
100 return result_names;
101}
102}
103