This is an automated email from the ASF dual-hosted git repository.

amoeba pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/main by this push:
     new fc6f7d003 feat(c): add source context to manifest and profile parse 
errors (#4633)
fc6f7d003 is described below

commit fc6f7d003cdbe5b21739a904485fab80656198c0
Author: Bryce Mecum <[email protected]>
AuthorDate: Fri Jul 31 14:56:21 2026 -0700

    feat(c): add source context to manifest and profile parse errors (#4633)
    
    If I have an manifest or profile that's invalid TOML, such as,
    
    ```toml
    profile_version = 1
    driver = not_a_valid_toml_value
    ```
    
     I get a vague error:
    
    > [Driver Manager] Could not open profile. Error while parsing value:
    could not determine value type
    
    It turns out the toml++ library can show the line and column number
    where the parse error occurred. This PR adds that context if it's
    available so we get a better error:
    
    > [Driver Manager] Could not open profile. Error while parsing value:
    could not determine value type (line 2, column 10).
---
 .../adbc_driver_manager_driver_loading.cc          |  8 +++++
 c/driver_manager/adbc_driver_manager_profiles.cc   |  8 +++++
 c/driver_manager/adbc_driver_manager_test.cc       | 40 ++++++++++++++++++++++
 .../adbc_driver_manager_driver_loading.cc          |  8 +++++
 go/adbc/drivermgr/adbc_driver_manager_profiles.cc  |  8 +++++
 python/adbc_driver_manager/tests/test_profile.py   | 32 +++++++++++++++++
 6 files changed, 104 insertions(+)

diff --git a/c/driver_manager/adbc_driver_manager_driver_loading.cc 
b/c/driver_manager/adbc_driver_manager_driver_loading.cc
index c17956057..9b2c84c97 100644
--- a/c/driver_manager/adbc_driver_manager_driver_loading.cc
+++ b/c/driver_manager/adbc_driver_manager_driver_loading.cc
@@ -163,6 +163,14 @@ AdbcStatusCode LoadDriverManifest(const 
std::filesystem::path& driver_manifest,
     // differentiate between bad syntax and other I/O error.
     std::string message = "Could not open manifest. ";
     message += err.what();
+    const auto& src = err.source();
+    if (src.begin) {
+      message += " (line ";
+      message += std::to_string(src.begin.line);
+      message += ", column ";
+      message += std::to_string(src.begin.column);
+      message += ")";
+    }
     message += ". Manifest: ";
     message += driver_manifest.string();
     SetError(error, std::move(message));
diff --git a/c/driver_manager/adbc_driver_manager_profiles.cc 
b/c/driver_manager/adbc_driver_manager_profiles.cc
index 703eddaf9..2ad571676 100644
--- a/c/driver_manager/adbc_driver_manager_profiles.cc
+++ b/c/driver_manager/adbc_driver_manager_profiles.cc
@@ -288,6 +288,14 @@ AdbcStatusCode LoadProfileFile(const 
std::filesystem::path& profile_path,
   } catch (const toml::parse_error& err) {
     std::string message = "Could not open profile. ";
     message += err.what();
+    const auto& src = err.source();
+    if (src.begin) {
+      message += " (line ";
+      message += std::to_string(src.begin.line);
+      message += ", column ";
+      message += std::to_string(src.begin.column);
+      message += ")";
+    }
     message += ". Profile: ";
     message += profile_path.string();
     SetError(error, std::move(message));
diff --git a/c/driver_manager/adbc_driver_manager_test.cc 
b/c/driver_manager/adbc_driver_manager_test.cc
index 3417b90c8..750b7fea7 100644
--- a/c/driver_manager/adbc_driver_manager_test.cc
+++ b/c/driver_manager/adbc_driver_manager_test.cc
@@ -2059,6 +2059,46 @@ TEST_F(ConnectionProfiles, CustomProfileProvider) {
   ASSERT_THAT(AdbcDatabaseRelease(&database.value, &error), 
IsOkStatus(&error));
 }
 
+TEST_F(ConnectionProfiles, ProfileParseErrorIncludesLocation) {
+  auto filepath = temp_dir / "badprofile.toml";
+  std::ofstream file(filepath);
+  ASSERT_TRUE(file.is_open());
+  file << "profile_version = 1\n"
+       << "driver = unquoted_value\n"
+       << "[Options]\n";
+  file.close();
+
+  adbc_validation::Handle<struct AdbcDatabase> database;
+  ASSERT_THAT(AdbcDatabaseNew(&database.value, &error), IsOkStatus(&error));
+  ASSERT_THAT(AdbcDatabaseSetOption(&database.value, "profile", 
filepath.string().c_str(),
+                                    &error),
+              IsOkStatus(&error));
+  ASSERT_THAT(AdbcDatabaseInit(&database.value, &error),
+              IsStatus(ADBC_STATUS_INVALID_ARGUMENT, &error));
+  ASSERT_THAT(error.message, ::testing::HasSubstr("line 2"));
+  ASSERT_THAT(error.message, ::testing::HasSubstr("column"));
+  ASSERT_THAT(AdbcDatabaseRelease(&database.value, &error), 
IsOkStatus(&error));
+}
+
+TEST_F(DriverManifest, ManifestParseErrorIncludesLocation) {
+  std::ofstream file(temp_dir / "baddriver.toml");
+  ASSERT_TRUE(file.is_open());
+  file << "manifest_version = 1\n"
+       << "[Driver]\n"
+       << "shared = unquoted_value\n";
+  file.close();
+
+  SetDriverPath(temp_dir.string().c_str());
+
+  ASSERT_THAT(AdbcFindLoadDriver("baddriver", nullptr, ADBC_VERSION_1_1_0,
+                                 ADBC_LOAD_FLAG_DEFAULT, nullptr, &driver, 
&error),
+              IsStatus(ADBC_STATUS_INVALID_ARGUMENT, &error));
+  ASSERT_THAT(error.message, ::testing::HasSubstr("line 3"));
+  ASSERT_THAT(error.message, ::testing::HasSubstr("column"));
+
+  UnsetDriverPath();
+}
+
 struct DriverUriProfile {
   std::string name;
   std::string driver;
diff --git a/go/adbc/drivermgr/adbc_driver_manager_driver_loading.cc 
b/go/adbc/drivermgr/adbc_driver_manager_driver_loading.cc
index c17956057..9b2c84c97 100644
--- a/go/adbc/drivermgr/adbc_driver_manager_driver_loading.cc
+++ b/go/adbc/drivermgr/adbc_driver_manager_driver_loading.cc
@@ -163,6 +163,14 @@ AdbcStatusCode LoadDriverManifest(const 
std::filesystem::path& driver_manifest,
     // differentiate between bad syntax and other I/O error.
     std::string message = "Could not open manifest. ";
     message += err.what();
+    const auto& src = err.source();
+    if (src.begin) {
+      message += " (line ";
+      message += std::to_string(src.begin.line);
+      message += ", column ";
+      message += std::to_string(src.begin.column);
+      message += ")";
+    }
     message += ". Manifest: ";
     message += driver_manifest.string();
     SetError(error, std::move(message));
diff --git a/go/adbc/drivermgr/adbc_driver_manager_profiles.cc 
b/go/adbc/drivermgr/adbc_driver_manager_profiles.cc
index 703eddaf9..2ad571676 100644
--- a/go/adbc/drivermgr/adbc_driver_manager_profiles.cc
+++ b/go/adbc/drivermgr/adbc_driver_manager_profiles.cc
@@ -288,6 +288,14 @@ AdbcStatusCode LoadProfileFile(const 
std::filesystem::path& profile_path,
   } catch (const toml::parse_error& err) {
     std::string message = "Could not open profile. ";
     message += err.what();
+    const auto& src = err.source();
+    if (src.begin) {
+      message += " (line ";
+      message += std::to_string(src.begin.line);
+      message += ", column ";
+      message += std::to_string(src.begin.column);
+      message += ")";
+    }
     message += ". Profile: ";
     message += profile_path.string();
     SetError(error, std::move(message));
diff --git a/python/adbc_driver_manager/tests/test_profile.py 
b/python/adbc_driver_manager/tests/test_profile.py
index 174285aae..a7cb8d998 100644
--- a/python/adbc_driver_manager/tests/test_profile.py
+++ b/python/adbc_driver_manager/tests/test_profile.py
@@ -368,6 +368,21 @@ profile_version = 9001
             pass
 
 
+def test_parse_error_includes_location(tmp_path, monkeypatch) -> None:
+    # Test that TOML parse errors include line/column information
+    monkeypatch.setenv("ADBC_PROFILE_PATH", str(tmp_path))
+
+    with (tmp_path / "badtoml.toml").open("w") as sink:
+        sink.write("""profile_version = 1
+driver = unquoted_value
+[Options]
+""")
+
+    with pytest.raises(dbapi.ProgrammingError, match=r"line 2.*column"):
+        with dbapi.connect("profile://badtoml"):
+            pass
+
+
 def test_reject_malformed(tmp_path, monkeypatch) -> None:
     # Test that invalid profiles are rejected
     monkeypatch.setenv("ADBC_PROFILE_PATH", str(tmp_path))
@@ -448,6 +463,23 @@ driver = "sqlitemanifest"
             assert cursor.fetchone() is not None
 
 
+def test_manifest_parse_error_includes_location(tmp_path, monkeypatch) -> None:
+    # Test that TOML parse errors in manifests include line/column information
+    manifest_path = tmp_path / "manifest"
+    manifest_path.mkdir()
+    monkeypatch.setenv("ADBC_DRIVER_PATH", str(manifest_path))
+
+    with (manifest_path / "badmanifest.toml").open("w") as sink:
+        sink.write("""manifest_version = 1
+[Driver]
+shared = unquoted_value
+""")
+
+    with pytest.raises(dbapi.ProgrammingError, match=r"line 3.*column"):
+        with dbapi.connect("badmanifest"):
+            pass
+
+
 def test_subdir(monkeypatch, tmp_path) -> None:
     # Test that we can search in subdirectories
     monkeypatch.setenv("ADBC_PROFILE_PATH", str(tmp_path))

Reply via email to