|
6 | 6 | #include "duckdb/parser/parsed_data/drop_info.hpp"
|
7 | 7 | #include "duckdb/parser/parsed_data/create_schema_info.hpp"
|
8 | 8 | #include "duckdb/main/attached_database.hpp"
|
| 9 | +#include "duckdb/main/secret/secret_manager.hpp" |
9 | 10 |
|
10 | 11 | namespace duckdb {
|
11 | 12 |
|
12 |
| -MySQLCatalog::MySQLCatalog(AttachedDatabase &db_p, const string &path, AccessMode access_mode) |
13 |
| - : Catalog(db_p), path(path), access_mode(access_mode), schemas(*this) { |
14 |
| - default_schema = MySQLUtils::ParseConnectionParameters(path).db; |
| 13 | +MySQLCatalog::MySQLCatalog(AttachedDatabase &db_p, string connection_string_p, string attach_path_p, AccessMode access_mode) |
| 14 | + : Catalog(db_p), connection_string(std::move(connection_string_p)), attach_path(std::move(attach_path_p)), access_mode(access_mode), schemas(*this) { |
| 15 | + default_schema = MySQLUtils::ParseConnectionParameters(connection_string).db; |
15 | 16 | // try to connect
|
16 |
| - auto connection = MySQLConnection::Open(path); |
| 17 | + auto connection = MySQLConnection::Open(connection_string); |
17 | 18 | }
|
18 | 19 |
|
19 | 20 | MySQLCatalog::~MySQLCatalog() = default;
|
20 | 21 |
|
| 22 | +string EscapeConnectionString(const string &input) { |
| 23 | + string result = "\""; |
| 24 | + for (auto c : input) { |
| 25 | + if (c == '\\') { |
| 26 | + result += "\\\\"; |
| 27 | + } else if (c == '"') { |
| 28 | + result += "\\\""; |
| 29 | + } else { |
| 30 | + result += c; |
| 31 | + } |
| 32 | + } |
| 33 | + result += "\""; |
| 34 | + return result; |
| 35 | +} |
| 36 | + |
| 37 | +string AddConnectionOption(const KeyValueSecret &kv_secret, const string &name) { |
| 38 | + Value input_val = kv_secret.TryGetValue(name); |
| 39 | + if (input_val.IsNull()) { |
| 40 | + // not provided |
| 41 | + return string(); |
| 42 | + } |
| 43 | + string result; |
| 44 | + result += name; |
| 45 | + result += "="; |
| 46 | + result += EscapeConnectionString(input_val.ToString()); |
| 47 | + result += " "; |
| 48 | + return result; |
| 49 | +} |
| 50 | + |
| 51 | +unique_ptr<SecretEntry> GetSecret(ClientContext &context, const string &secret_name) { |
| 52 | + auto &secret_manager = SecretManager::Get(context); |
| 53 | + auto transaction = CatalogTransaction::GetSystemCatalogTransaction(context); |
| 54 | + // FIXME: this should be adjusted once the `GetSecretByName` API supports this |
| 55 | + // use case |
| 56 | + auto secret_entry = secret_manager.GetSecretByName(transaction, secret_name, "memory"); |
| 57 | + if (secret_entry) { |
| 58 | + return secret_entry; |
| 59 | + } |
| 60 | + secret_entry = secret_manager.GetSecretByName(transaction, secret_name, "local_file"); |
| 61 | + if (secret_entry) { |
| 62 | + return secret_entry; |
| 63 | + } |
| 64 | + return nullptr; |
| 65 | +} |
| 66 | + |
| 67 | +string MySQLCatalog::GetConnectionString(ClientContext &context, const string &attach_path, string secret_name) { |
| 68 | + // if no secret is specified we default to the unnamed mysql secret, if it |
| 69 | + // exists |
| 70 | + bool explicit_secret = !secret_name.empty(); |
| 71 | + if (!explicit_secret) { |
| 72 | + // look up settings from the default unnamed mysql secret if none is |
| 73 | + // provided |
| 74 | + secret_name = "__default_mysql"; |
| 75 | + } |
| 76 | + auto secret_entry = GetSecret(context, secret_name); |
| 77 | + auto connection_string = attach_path; |
| 78 | + if (secret_entry) { |
| 79 | + // secret found - read data |
| 80 | + const auto &kv_secret = dynamic_cast<const KeyValueSecret &>(*secret_entry->secret); |
| 81 | + string new_connection_info; |
| 82 | + |
| 83 | + new_connection_info += AddConnectionOption(kv_secret, "user"); |
| 84 | + new_connection_info += AddConnectionOption(kv_secret, "password"); |
| 85 | + new_connection_info += AddConnectionOption(kv_secret, "host"); |
| 86 | + new_connection_info += AddConnectionOption(kv_secret, "port"); |
| 87 | + new_connection_info += AddConnectionOption(kv_secret, "database"); |
| 88 | + new_connection_info += AddConnectionOption(kv_secret, "socket"); |
| 89 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_mode"); |
| 90 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_ca"); |
| 91 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_capath"); |
| 92 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_cert"); |
| 93 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_cipher"); |
| 94 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_crl"); |
| 95 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_crlpath"); |
| 96 | + new_connection_info += AddConnectionOption(kv_secret, "ssl_key"); |
| 97 | + connection_string = new_connection_info + connection_string; |
| 98 | + } else if (explicit_secret) { |
| 99 | + // secret not found and one was explicitly provided - throw an error |
| 100 | + throw BinderException("Secret with name \"%s\" not found", secret_name); |
| 101 | + } |
| 102 | + return connection_string; |
| 103 | +} |
| 104 | + |
21 | 105 | void MySQLCatalog::Initialize(bool load_builtin) {
|
22 | 106 | }
|
23 | 107 |
|
@@ -63,7 +147,7 @@ bool MySQLCatalog::InMemory() {
|
63 | 147 | }
|
64 | 148 |
|
65 | 149 | string MySQLCatalog::GetDBPath() {
|
66 |
| - return path; |
| 150 | + return attach_path; |
67 | 151 | }
|
68 | 152 |
|
69 | 153 | DatabaseSize MySQLCatalog::GetDatabaseSize(ClientContext &context) {
|
|
0 commit comments