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

lidavidm 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 ba7e7f540d fix(c/driver/sqlite): handle other error codes (#4842)
ba7e7f540d is described below

commit ba7e7f540da64555507ad14eeebd373f0ff5d9a8
Author: David Li <[email protected]>
AuthorDate: Wed Sep 30 17:22:59 2026 -0700

    fix(c/driver/sqlite): handle other error codes (#4842)
    
    Also, properly map SQLITE_CONSTRAINT to ADBC_STATUS_INTEGRITY.
    
    Closes #4827.
---
 c/driver/framework/status.h        |  1 +
 c/driver/sqlite/sqlite.cc          |  7 ++++-
 c/driver/sqlite/sqlite_test.cc     | 54 ++++++++++++++++++++++++++++++++++++++
 c/driver/sqlite/statement_reader.c | 10 ++++---
 4 files changed, 67 insertions(+), 5 deletions(-)

diff --git a/c/driver/framework/status.h b/c/driver/framework/status.h
index a34f2f8cd6..df91469b5b 100644
--- a/c/driver/framework/status.h
+++ b/c/driver/framework/status.h
@@ -340,6 +340,7 @@ STATUS_CTOR(Internal, INTERNAL)
 STATUS_CTOR(InvalidArgument, INVALID_ARGUMENT)
 STATUS_CTOR(InvalidState, INVALID_STATE)
 STATUS_CTOR(IO, IO)
+STATUS_CTOR(Integrity, INTEGRITY)
 STATUS_CTOR(NotFound, NOT_FOUND)
 STATUS_CTOR(NotImplemented, NOT_IMPLEMENTED)
 STATUS_CTOR(Unknown, UNKNOWN)
diff --git a/c/driver/sqlite/sqlite.cc b/c/driver/sqlite/sqlite.cc
index b24cff80f3..d6f20857f9 100644
--- a/c/driver/sqlite/sqlite.cc
+++ b/c/driver/sqlite/sqlite.cc
@@ -1165,7 +1165,12 @@ class SqliteStatement : public 
driver::Statement<SqliteStatement> {
     }
     InternalAdbcSqliteBinderRelease(&binder_);
 
-    if (sqlite3_reset(stmt_) != SQLITE_OK) {
+    int rc = sqlite3_reset(stmt_);
+    if (rc == SQLITE_CONSTRAINT) {
+      const char* msg = sqlite3_errmsg(conn_);
+      return status::fmt::Integrity("failed to execute query: {}",
+                                    msg ? msg : "(unknown error)");
+    } else if (rc != SQLITE_OK) {
       const char* msg = sqlite3_errmsg(conn_);
       return status::fmt::IO("failed to execute query: {}",
                              msg ? msg : "(unknown error)");
diff --git a/c/driver/sqlite/sqlite_test.cc b/c/driver/sqlite/sqlite_test.cc
index 32e96296a2..5af3a5ed32 100644
--- a/c/driver/sqlite/sqlite_test.cc
+++ b/c/driver/sqlite/sqlite_test.cc
@@ -775,6 +775,60 @@ TEST_F(SqliteStatementTest, RowsAffectedBoundParameters) {
               adbc_validation::IsOkStatus(&error));
 }
 
+TEST_F(SqliteStatementTest, ConstraintError) {
+  ASSERT_THAT(quirks()->DropTable(&connection, "constrainttable", &error),
+              adbc_validation::IsOkStatus(&error));
+  ASSERT_THAT(AdbcStatementNew(&connection, &statement, &error),
+              adbc_validation::IsOkStatus(&error));
+
+  for (const auto& stmt : {
+           "CREATE TABLE constrainttable (id INTEGER PRIMARY KEY)",
+           "INSERT INTO constrainttable (id) VALUES (1)",
+       }) {
+    ASSERT_THAT(AdbcStatementSetSqlQuery(&statement, stmt, &error),
+                adbc_validation::IsOkStatus(&error));
+    ASSERT_THAT(AdbcStatementExecuteQuery(&statement, nullptr, nullptr, 
&error),
+                adbc_validation::IsOkStatus(&error));
+  }
+
+  ASSERT_THAT(AdbcStatementSetSqlQuery(
+                  &statement, "INSERT INTO constrainttable (id) VALUES (1)", 
&error),
+              adbc_validation::IsOkStatus(&error));
+
+  adbc_validation::StreamReader reader;
+  ASSERT_THAT(AdbcStatementExecuteQuery(&statement, &reader.stream.value,
+                                        &reader.rows_affected, &error),
+              adbc_validation::IsStatus(ADBC_STATUS_INTEGRITY, &error));
+  EXPECT_THAT(error.message,
+              ::testing::HasSubstr("UNIQUE constraint failed: 
constrainttable.id"));
+}
+
+TEST_F(SqliteStatementTest, ConstraintErrorNoStream) {
+  ASSERT_THAT(quirks()->DropTable(&connection, "constrainttable", &error),
+              adbc_validation::IsOkStatus(&error));
+  ASSERT_THAT(AdbcStatementNew(&connection, &statement, &error),
+              adbc_validation::IsOkStatus(&error));
+
+  for (const auto& stmt : {
+           "CREATE TABLE constrainttable (id INTEGER PRIMARY KEY)",
+           "INSERT INTO constrainttable (id) VALUES (1)",
+       }) {
+    ASSERT_THAT(AdbcStatementSetSqlQuery(&statement, stmt, &error),
+                adbc_validation::IsOkStatus(&error));
+    ASSERT_THAT(AdbcStatementExecuteQuery(&statement, nullptr, nullptr, 
&error),
+                adbc_validation::IsOkStatus(&error));
+  }
+
+  ASSERT_THAT(AdbcStatementSetSqlQuery(
+                  &statement, "INSERT INTO constrainttable (id) VALUES (1)", 
&error),
+              adbc_validation::IsOkStatus(&error));
+
+  ASSERT_THAT(AdbcStatementExecuteQuery(&statement, nullptr, nullptr, &error),
+              adbc_validation::IsStatus(ADBC_STATUS_INTEGRITY, &error));
+  EXPECT_THAT(error.message,
+              ::testing::HasSubstr("UNIQUE constraint failed: 
constrainttable.id"));
+}
+
 // -- SQLite Specific Tests ------------------------------------------
 
 constexpr size_t kInferRows = 16;
diff --git a/c/driver/sqlite/statement_reader.c 
b/c/driver/sqlite/statement_reader.c
index 96bcbae96b..0827a860ab 100644
--- a/c/driver/sqlite/statement_reader.c
+++ b/c/driver/sqlite/statement_reader.c
@@ -1241,15 +1241,17 @@ AdbcStatusCode InternalAdbcSqliteExportReader(sqlite3* 
db, sqlite3_stmt* stmt,
           }
         }
         continue;
-      } else if (rc == SQLITE_ERROR) {
+      } else if (rc == SQLITE_CONSTRAINT) {
+        InternalAdbcSetError(error, "%s", sqlite3_errmsg(db));
+        status = ADBC_STATUS_INTEGRITY;
+        (void)sqlite3_reset(stmt);
+        break;
+      } else if (rc != SQLITE_ROW) {
         InternalAdbcSetError(error, "Failed to step query: %s", 
sqlite3_errmsg(db));
         status = ADBC_STATUS_IO;
         // Reset here so that we don't get an error again in StatementRelease
         (void)sqlite3_reset(stmt);
         break;
-      } else if (rc != SQLITE_ROW) {
-        status = ADBC_STATUS_INTERNAL;
-        break;
       }
 
       for (int col = 0; col < num_columns; col++) {

Reply via email to