| 1 | #include <Poco/Util/AbstractConfiguration.h> | 
|---|
| 2 | #include <Common/Macros.h> | 
|---|
| 3 | #include <Common/Exception.h> | 
|---|
| 4 | #include <IO/WriteHelpers.h> | 
|---|
| 5 |  | 
|---|
| 6 |  | 
|---|
| 7 | namespace DB | 
|---|
| 8 | { | 
|---|
| 9 |  | 
|---|
| 10 | namespace ErrorCodes | 
|---|
| 11 | { | 
|---|
| 12 | extern const int SYNTAX_ERROR; | 
|---|
| 13 | } | 
|---|
| 14 |  | 
|---|
| 15 | Macros::Macros() {} | 
|---|
| 16 |  | 
|---|
| 17 | Macros::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 |  | 
|---|
| 27 | String 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 |  | 
|---|
| 80 | String 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 |  | 
|---|
| 87 | String 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 |  | 
|---|
| 92 | Names 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 |  | 
|---|