lidavidm commented on code in PR #3876:
URL: https://github.com/apache/arrow-adbc/pull/3876#discussion_r2726409474
##########
c/driver_manager/adbc_driver_manager.cc:
##########
@@ -1042,6 +1115,262 @@ struct ManagedLibrary {
#endif // defined(_WIN32)
};
+struct FilesystemProfile {
+ std::filesystem::path path;
+ std::string driver;
+ std::unordered_map<std::string, std::string> options;
+ std::unordered_map<std::string, int64_t> int_options;
+ std::unordered_map<std::string, double> double_options;
+
+ std::vector<const char*> options_keys;
+ std::vector<const char*> options_values;
+
+ std::vector<const char*> int_option_keys;
+ std::vector<int64_t> int_option_values;
+
+ std::vector<const char*> double_option_keys;
+ std::vector<double> double_option_values;
+
+ static void populate_connection_profile(FilesystemProfile&& profile,
+ struct AdbcConnectionProfile* out) {
+ profile.options_keys.reserve(profile.options.size());
+ profile.options_values.reserve(profile.options.size());
+ for (const auto& [key, value] : profile.options) {
+ profile.options_keys.push_back(key.c_str());
+ profile.options_values.push_back(value.c_str());
+ }
+
+ profile.int_option_keys.reserve(profile.int_options.size());
+ profile.int_option_values.reserve(profile.int_options.size());
+ for (const auto& [key, value] : profile.int_options) {
+ profile.int_option_keys.push_back(key.c_str());
+ profile.int_option_values.push_back(value);
+ }
+
+ profile.double_option_keys.reserve(profile.double_options.size());
+ profile.double_option_values.reserve(profile.double_options.size());
+ for (const auto& [key, value] : profile.double_options) {
+ profile.double_option_keys.push_back(key.c_str());
+ profile.double_option_values.push_back(value);
+ }
+
+ out->private_data = new FilesystemProfile(std::move(profile));
+ out->release = [](AdbcConnectionProfile* profile) {
+ if (!profile || !profile->private_data) {
+ return;
+ }
+
+ delete static_cast<FilesystemProfile*>(profile->private_data);
+ profile->private_data = nullptr;
+ profile->release = nullptr;
+ };
+
+ out->GetDriverName = [](AdbcConnectionProfile* profile, const char** out,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *out = fs_profile->driver.c_str();
+ return ADBC_STATUS_OK;
+ };
+
+ out->GetOptions = [](AdbcConnectionProfile* profile, const char*** keys,
+ const char*** values, size_t* num_options,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (!keys || !values || !num_options) {
+ SetError(error, "Output parameters cannot be null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *num_options = fs_profile->options.size();
+ *keys = fs_profile->options_keys.data();
+ *values = fs_profile->options_values.data();
+ return ADBC_STATUS_OK;
+ };
+
+ out->GetIntOptions = [](AdbcConnectionProfile* profile, const char*** keys,
+ const int64_t** values, size_t* num_options,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (!keys || !values || !num_options) {
+ SetError(error, "Output parameters cannot be null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *num_options = fs_profile->int_options.size();
+ *keys = fs_profile->int_option_keys.data();
+ *values = fs_profile->int_option_values.data();
+ return ADBC_STATUS_OK;
+ };
+
+ out->GetDoubleOptions = [](AdbcConnectionProfile* profile, const char***
keys,
+ const double** values, size_t* num_options,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (!keys || !values || !num_options) {
+ SetError(error, "Output parameters cannot be null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *num_options = fs_profile->double_options.size();
+ *keys = fs_profile->double_option_keys.data();
+ *values = fs_profile->double_option_values.data();
+ return ADBC_STATUS_OK;
+ };
+ }
+};
+
+struct profileVisitor {
+ FilesystemProfile& profile;
+ const std::filesystem::path& profile_path;
+ struct AdbcError* error;
+
+ bool visit_table(const std::string& prefix, toml::table& table) {
Review Comment:
This needs to be CamelCase
##########
c/driver_manager/adbc_driver_manager.cc:
##########
@@ -1042,6 +1115,262 @@ struct ManagedLibrary {
#endif // defined(_WIN32)
};
+struct FilesystemProfile {
+ std::filesystem::path path;
+ std::string driver;
+ std::unordered_map<std::string, std::string> options;
+ std::unordered_map<std::string, int64_t> int_options;
+ std::unordered_map<std::string, double> double_options;
+
+ std::vector<const char*> options_keys;
+ std::vector<const char*> options_values;
+
+ std::vector<const char*> int_option_keys;
+ std::vector<int64_t> int_option_values;
+
+ std::vector<const char*> double_option_keys;
+ std::vector<double> double_option_values;
+
+ static void populate_connection_profile(FilesystemProfile&& profile,
Review Comment:
(Why can't this be a method?)
##########
c/driver_manager/adbc_driver_manager.cc:
##########
@@ -1042,6 +1115,262 @@ struct ManagedLibrary {
#endif // defined(_WIN32)
};
+struct FilesystemProfile {
+ std::filesystem::path path;
+ std::string driver;
+ std::unordered_map<std::string, std::string> options;
+ std::unordered_map<std::string, int64_t> int_options;
+ std::unordered_map<std::string, double> double_options;
+
+ std::vector<const char*> options_keys;
+ std::vector<const char*> options_values;
+
+ std::vector<const char*> int_option_keys;
+ std::vector<int64_t> int_option_values;
+
+ std::vector<const char*> double_option_keys;
+ std::vector<double> double_option_values;
+
+ static void populate_connection_profile(FilesystemProfile&& profile,
+ struct AdbcConnectionProfile* out) {
+ profile.options_keys.reserve(profile.options.size());
+ profile.options_values.reserve(profile.options.size());
+ for (const auto& [key, value] : profile.options) {
+ profile.options_keys.push_back(key.c_str());
+ profile.options_values.push_back(value.c_str());
+ }
+
+ profile.int_option_keys.reserve(profile.int_options.size());
+ profile.int_option_values.reserve(profile.int_options.size());
+ for (const auto& [key, value] : profile.int_options) {
+ profile.int_option_keys.push_back(key.c_str());
+ profile.int_option_values.push_back(value);
+ }
+
+ profile.double_option_keys.reserve(profile.double_options.size());
+ profile.double_option_values.reserve(profile.double_options.size());
+ for (const auto& [key, value] : profile.double_options) {
+ profile.double_option_keys.push_back(key.c_str());
+ profile.double_option_values.push_back(value);
+ }
+
+ out->private_data = new FilesystemProfile(std::move(profile));
+ out->release = [](AdbcConnectionProfile* profile) {
+ if (!profile || !profile->private_data) {
+ return;
+ }
+
+ delete static_cast<FilesystemProfile*>(profile->private_data);
+ profile->private_data = nullptr;
+ profile->release = nullptr;
+ };
+
+ out->GetDriverName = [](AdbcConnectionProfile* profile, const char** out,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *out = fs_profile->driver.c_str();
+ return ADBC_STATUS_OK;
+ };
+
+ out->GetOptions = [](AdbcConnectionProfile* profile, const char*** keys,
+ const char*** values, size_t* num_options,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (!keys || !values || !num_options) {
+ SetError(error, "Output parameters cannot be null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *num_options = fs_profile->options.size();
+ *keys = fs_profile->options_keys.data();
+ *values = fs_profile->options_values.data();
+ return ADBC_STATUS_OK;
+ };
+
+ out->GetIntOptions = [](AdbcConnectionProfile* profile, const char*** keys,
+ const int64_t** values, size_t* num_options,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (!keys || !values || !num_options) {
+ SetError(error, "Output parameters cannot be null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *num_options = fs_profile->int_options.size();
+ *keys = fs_profile->int_option_keys.data();
+ *values = fs_profile->int_option_values.data();
+ return ADBC_STATUS_OK;
+ };
+
+ out->GetDoubleOptions = [](AdbcConnectionProfile* profile, const char***
keys,
+ const double** values, size_t* num_options,
+ struct AdbcError* error) -> AdbcStatusCode {
+ if (!profile || !profile->private_data) {
+ SetError(error, "Invalid connection profile");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (!keys || !values || !num_options) {
+ SetError(error, "Output parameters cannot be null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ auto* fs_profile =
static_cast<FilesystemProfile*>(profile->private_data);
+ *num_options = fs_profile->double_options.size();
+ *keys = fs_profile->double_option_keys.data();
+ *values = fs_profile->double_option_values.data();
+ return ADBC_STATUS_OK;
+ };
+ }
+};
+
+struct profileVisitor {
Review Comment:
This still needs to be UpperCamelCase
##########
c/driver_manager/adbc_driver_manager.cc:
##########
@@ -398,6 +416,59 @@ AdbcStatusCode LoadDriverFromRegistry(HKEY root, const
std::wstring& driver_name
}
#endif // _WIN32
+#define CHECK_STATUS(EXPR) \
+ if (auto _status = (EXPR); _status != ADBC_STATUS_OK) { \
+ return _status; \
+ }
+
+AdbcStatusCode ProcessProfileValue(std::string_view value, std::string& out,
+ struct AdbcError* error) {
+ if (value.empty()) {
+ SetError(error, "Profile value is null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ const auto pos = value.find("env_var(");
+ if (pos == std::string_view::npos || pos != 0) {
Review Comment:
Doesn't this mean you can't actually use `env_var()` for interpolation?
##########
c/driver_manager/adbc_driver_manager.cc:
##########
@@ -1042,6 +1115,262 @@ struct ManagedLibrary {
#endif // defined(_WIN32)
};
+struct FilesystemProfile {
+ std::filesystem::path path;
+ std::string driver;
+ std::unordered_map<std::string, std::string> options;
+ std::unordered_map<std::string, int64_t> int_options;
+ std::unordered_map<std::string, double> double_options;
+
+ std::vector<const char*> options_keys;
+ std::vector<const char*> options_values;
+
+ std::vector<const char*> int_option_keys;
+ std::vector<int64_t> int_option_values;
+
+ std::vector<const char*> double_option_keys;
+ std::vector<double> double_option_values;
+
+ static void populate_connection_profile(FilesystemProfile&& profile,
Review Comment:
This needs to follow CamelCase naming
##########
c/driver_manager/adbc_driver_manager.cc:
##########
@@ -1857,20 +2204,188 @@ AdbcStatusCode
AdbcDriverManagerDatabaseSetInitFunc(struct AdbcDatabase* databas
return ADBC_STATUS_OK;
}
+AdbcStatusCode AdbcFilesystemProfileProvider(const char* profile_name,
+ const char*
additional_search_path_list,
+ struct AdbcConnectionProfile* out,
+ struct AdbcError* error) {
+ if (profile_name == nullptr || strlen(profile_name) == 0) {
+ SetError(error, "Profile name is empty");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ if (!out) {
+ SetError(error, "Output profile is null");
+ return ADBC_STATUS_INVALID_ARGUMENT;
+ }
+
+ std::memset(out, 0, sizeof(*out));
+ std::filesystem::path profile_path(profile_name);
+ if (profile_path.has_extension()) {
+ if (HasExtension(profile_path, ".toml")) {
+ if (!std::filesystem::exists(profile_path)) {
+ SetError(error, "Profile file does not exist: " +
profile_path.string());
+ return ADBC_STATUS_NOT_FOUND;
+ }
+
+ FilesystemProfile profile;
+ CHECK_STATUS(LoadProfileFile(profile_path, profile, error));
+ FilesystemProfile::populate_connection_profile(std::move(profile), out);
+ return ADBC_STATUS_OK;
+ }
+ }
+
+ if (profile_path.is_absolute()) {
+ profile_path.replace_extension(".toml");
+
+ FilesystemProfile profile;
+ CHECK_STATUS(LoadProfileFile(profile_path, profile, error));
+ FilesystemProfile::populate_connection_profile(std::move(profile), out);
+ return ADBC_STATUS_OK;
+ }
+
+ SearchPaths search_paths =
GetProfileSearchPaths(additional_search_path_list);
+ SearchPaths extra_debug_info;
+ for (const auto& [source, search_path] : search_paths) {
+ if (source == SearchPathSource::kRegistry || source ==
SearchPathSource::kUnset ||
+ source == SearchPathSource::kDoesNotExist ||
+ source == SearchPathSource::kDisabledAtCompileTime ||
+ source == SearchPathSource::kDisabledAtRunTime ||
+ source == SearchPathSource::kOtherError) {
+ continue;
+ }
+
+ std::filesystem::path full_path = search_path / profile_path;
+ full_path.replace_extension(".toml");
+ if (std::filesystem::exists(full_path)) {
+ OwnedError intermediate_error;
+
+ FilesystemProfile profile;
+ auto status = LoadProfileFile(full_path, profile,
&intermediate_error.error);
+ if (status == ADBC_STATUS_OK) {
+ FilesystemProfile::populate_connection_profile(std::move(profile),
out);
+ return ADBC_STATUS_OK;
+ } else if (status == ADBC_STATUS_INVALID_ARGUMENT) {
+ search_paths.insert(search_paths.end(), extra_debug_info.begin(),
+ extra_debug_info.end());
+ if (intermediate_error.error.message) {
+ std::string error_message = intermediate_error.error.message;
+ AddSearchPathsToError(search_paths, SearchPathType::kProfile,
error_message);
+ SetError(error, std::move(error_message));
+ }
+ return status;
+ }
+
+ std::string message = "found ";
+ message += full_path.string();
+ message += " but: ";
+ if (intermediate_error.error.message) {
+ message += intermediate_error.error.message;
+ } else {
+ message += "could not load the profile";
+ }
+ extra_debug_info.emplace_back(SearchPathSource::kOtherError,
std::move(message));
+ }
+ }
+
+ search_paths.insert(search_paths.end(), extra_debug_info.begin(),
+ extra_debug_info.end());
+ std::string error_message = "Profile not found: " +
std::string(profile_name);
+ AddSearchPathsToError(search_paths, SearchPathType::kProfile, error_message);
+ SetError(error, std::move(error_message));
+ return ADBC_STATUS_NOT_FOUND;
+}
+
+struct ProfileGuard {
Review Comment:
It'd be less error-prone to have the guard own the profile
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]