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++) {