paleolimbot commented on code in PR #3876:
URL: https://github.com/apache/arrow-adbc/pull/3876#discussion_r2795996251


##########
c/driver_manager/adbc_driver_manager.cc:
##########
@@ -1042,6 +1137,261 @@ 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;
+
+  void PopulateConnectionProfile(struct AdbcConnectionProfile* out) {
+    options_keys.reserve(options.size());
+    options_values.reserve(options.size());
+    for (const auto& [key, value] : options) {
+      options_keys.push_back(key.c_str());
+      options_values.push_back(value.c_str());
+    }
+
+    int_option_keys.reserve(int_options.size());
+    int_option_values.reserve(int_options.size());
+    for (const auto& [key, value] : int_options) {
+      int_option_keys.push_back(key.c_str());
+      int_option_values.push_back(value);
+    }
+
+    double_option_keys.reserve(double_options.size());
+    double_option_values.reserve(double_options.size());
+    for (const auto& [key, value] : double_options) {
+      double_option_keys.push_back(key.c_str());
+      double_option_values.push_back(value);
+    }
+
+    out->private_data = new FilesystemProfile(std::move(*this));
+    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 VisitTable(const std::string& prefix, toml::table& table) {
+    for (const auto& [key, value] : table) {
+      if (auto* str = value.as_string()) {
+        profile.options[prefix + key.data()] = str->get();
+      } else if (auto* int_val = value.as_integer()) {
+        profile.int_options[prefix + key.data()] = int_val->get();
+      } else if (auto* double_val = value.as_floating_point()) {
+        profile.double_options[prefix + key.data()] = double_val->get();
+      } else if (auto* bool_val = value.as_boolean()) {
+        profile.options[prefix + key.data()] = bool_val->get() ? "true" : 
"false";
+      } else if (value.is_table()) {
+        if (!VisitTable(prefix + key.data() + ".", *value.as_table())) {
+          return false;
+        }
+      } else {
+        std::string message = "Unsupported value type for key '" +
+                              std::string(key.str()) + "' in profile '" +
+                              profile_path.string() + "'";
+        SetError(error, std::move(message));
+        return false;
+      }
+    }
+    return !error->message;
+  }
+};
+
+AdbcStatusCode LoadProfileFile(const std::filesystem::path& profile_path,
+                               FilesystemProfile& profile, struct AdbcError* 
error) {
+  toml::table config;
+  try {
+    config = toml::parse_file(profile_path.native());
+  } catch (const toml::parse_error& err) {
+    std::string message = "Could not open profile. ";
+    message += err.what();
+    message += ". Profile: ";
+    message += profile_path.string();
+    SetError(error, std::move(message));
+    return ADBC_STATUS_INVALID_ARGUMENT;
+  }
+
+  profile.path = profile_path;
+  if (!config["version"].is_integer()) {
+    std::string message =
+        "Profile version is not an integer in profile '" + 
profile_path.string() + "'";
+    SetError(error, std::move(message));
+    return ADBC_STATUS_INVALID_ARGUMENT;
+  }
+
+  const auto version = config["version"].value_or(int64_t(1));
+  switch (version) {
+    case 1:
+      break;
+    default: {
+      std::string message =
+          "Profile version '" + std::to_string(version) +
+          "' is not supported by this driver manager. Profile: " + 
profile_path.string();
+      SetError(error, std::move(message));
+      return ADBC_STATUS_INVALID_ARGUMENT;
+    }
+  }
+
+  profile.driver = config["driver"].value_or(""s);
+
+  auto options = config.at_path("options");
+  if (!options.is_table()) {
+    std::string message =
+        "Profile options is not a table in profile '" + profile_path.string() 
+ "'";
+    SetError(error, std::move(message));
+    return ADBC_STATUS_INVALID_ARGUMENT;
+  }
+
+  auto* options_table = options.as_table();
+  ProfileVisitor v{profile, profile_path, error};
+  if (!v.VisitTable("", *options_table)) {
+    return ADBC_STATUS_INVALID_ARGUMENT;
+  }
+
+  return ADBC_STATUS_OK;
+}
+
+SearchPaths GetProfileSearchPaths(const char* additional_search_path_list) {
+  SearchPaths search_paths;
+  {
+    std::vector<std::filesystem::path> additional_paths;
+    if (additional_search_path_list) {
+      additional_paths = InternalAdbcParsePath(additional_search_path_list);
+    }
+
+    for (const auto& path : additional_paths) {
+      search_paths.emplace_back(SearchPathSource::kAdditional, path);
+    }
+  }
+
+  {
+    auto env_paths = GetEnvPaths(kAdbcProfilePath);
+    search_paths.insert(search_paths.end(), env_paths.begin(), 
env_paths.end());
+  }
+
+#if ADBC_CONDA_BUILD
+#ifdef _WIN32
+  const wchar_t* conda_name = L"CONDA_PREFIX";
+#else
+  const char* conda_name = "CONDA_PREFIX";
+#endif  // _WIN32
+
+  auto venv = GetEnvPaths(conda_name);
+  for (const auto& [_, venv_path] : venv) {
+    search_paths.emplace_back(SearchPathSource::kConda,
+                              venv_path / "etc" / "adbc" / "profiles");
+  }
+#else
+  search_paths.emplace_back(SearchPathSource::kDisabledAtCompileTime, "Conda 
prefix");
+#endif  // ADBC_CONDA_BUILD
+
+#ifdef _WIN32
+  const wchar_t* profiles_dir = L"Profiles";
+#elif defined(__APPLE__)

Review Comment:
   I suppose if anybody notices they can open an issue 🙂 



-- 
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]

Reply via email to