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 c7c43b5c5 feat(c/driver/sqlite): ensure batch rows option can be
retrieved (#4645)
c7c43b5c5 is described below
commit c7c43b5c58d69287cad4702097b911e7b1a89e66
Author: David Li <[email protected]>
AuthorDate: Tue Sep 8 08:31:32 2026 +0900
feat(c/driver/sqlite): ensure batch rows option can be retrieved (#4645)
The getter existed, but the framework needed to be extended to also
allow fetching it as a string, and tests were added.
Closes #3456.
Assisted-by: GPT-5.6 Sol <[email protected]>
---
c/driver/framework/base_driver.h | 25 ++++++--
c/driver/framework/status.h | 4 --
c/driver/postgresql/meson.build | 2 +-
c/driver/postgresql/result_helper.cc | 1 -
c/driver/sqlite/meson.build | 2 +-
c/driver/sqlite/sqlite.cc | 1 -
c/driver/sqlite/sqlite_test.cc | 71 +++++++++++++++++++++++
c/subprojects/fmt.wrap | 20 +++----
docs/source/cpp/recipe_driver/CMakeLists.txt | 10 +++-
python/adbc_driver_sqlite/tests/test_lowlevel.py | 7 +++
r/adbcdrivermanager/src/Makevars | 2 +-
r/adbcdrivermanager/src/Makevars.win | 2 +-
r/adbcdrivermanager/tests/testthat/test-options.R | 32 +++++-----
13 files changed, 136 insertions(+), 43 deletions(-)
diff --git a/c/driver/framework/base_driver.h b/c/driver/framework/base_driver.h
index bebdffea6..578bb3066 100644
--- a/c/driver/framework/base_driver.h
+++ b/c/driver/framework/base_driver.h
@@ -30,6 +30,8 @@
#include <arrow-adbc/adbc.h>
+#include "fmt/core.h"
+
#include "driver/framework/status.h"
/// \file base.h ADBC Driver Framework
@@ -54,8 +56,7 @@ enum class LifecycleState {
kInitialized,
};
-/// \brief A typed option value wrapper. It currently does not attempt
-/// conversion (i.e., getting a double option as a string).
+/// \brief A typed option value wrapper. Attempts some conversions between
types.
class Option {
public:
/// \brief The option is unset.
@@ -169,11 +170,23 @@ class Option {
return std::visit(
[&](auto&& value) -> AdbcStatusCode {
using T = std::decay_t<decltype(value)>;
- if constexpr (std::is_same_v<T, std::string>) {
- size_t value_size_with_terminator = value.size() + 1;
+ if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T,
int64_t> ||
+ std::is_same_v<T, double>) {
+ std::string_view string_value;
+ std::string allocated_value;
+ if constexpr (std::is_same_v<T, int64_t>) {
+ allocated_value = fmt::format("{}", value);
+ string_value = allocated_value;
+ } else if constexpr (std::is_same_v<T, double>) {
+ allocated_value = fmt::format("{}", value);
+ string_value = allocated_value;
+ } else {
+ string_value = value;
+ }
+ size_t value_size_with_terminator = string_value.size() + 1;
if (*length >= value_size_with_terminator) {
- std::memcpy(out, value.data(), value.size());
- out[value.size()] = 0;
+ std::memcpy(out, string_value.data(), string_value.size());
+ out[string_value.size()] = 0;
}
*length = value_size_with_terminator;
return ADBC_STATUS_OK;
diff --git a/c/driver/framework/status.h b/c/driver/framework/status.h
index 1fac2272a..6cb400314 100644
--- a/c/driver/framework/status.h
+++ b/c/driver/framework/status.h
@@ -26,10 +26,8 @@
#include <variant>
#include <vector>
-#if defined(ADBC_FRAMEWORK_USE_FMT)
#include <fmt/core.h>
#include <fmt/format.h>
-#endif
#include <arrow-adbc/adbc.h>
@@ -326,7 +324,6 @@ STATUS_CTOR(Unknown, UNKNOWN)
} // namespace adbc::driver::status
-#if defined(ADBC_FRAMEWORK_USE_FMT)
namespace adbc::driver::status::fmt {
#define STATUS_CTOR(NAME, CODE)
\
@@ -348,7 +345,6 @@ STATUS_CTOR(Unknown, UNKNOWN)
#undef STATUS_CTOR
} // namespace adbc::driver::status::fmt
-#endif
#define UNWRAP_ERRNO_IMPL(NAME, CODE, RHS)
\
do {
\
diff --git a/c/driver/postgresql/meson.build b/c/driver/postgresql/meson.build
index 7af8f849d..fcb87c01a 100644
--- a/c/driver/postgresql/meson.build
+++ b/c/driver/postgresql/meson.build
@@ -70,7 +70,7 @@ foreach name, conf : postgres_tests
sources: conf['sources'],
include_directories: [include_dir, driver_dir, c_dir, safe_math_dir],
link_with: [adbc_common_lib, adbc_postgres_driver_lib],
- dependencies: [libpq_dep, adbc_validation_dep],
+ dependencies: [libpq_dep, adbc_validation_dep, fmt_dep],
cpp_args: cpp_args,
)
test('adbc-' + name, exc)
diff --git a/c/driver/postgresql/result_helper.cc
b/c/driver/postgresql/result_helper.cc
index 2557e8f94..1fcc42a9c 100644
--- a/c/driver/postgresql/result_helper.cc
+++ b/c/driver/postgresql/result_helper.cc
@@ -27,7 +27,6 @@
#include <string>
#include <vector>
-#define ADBC_FRAMEWORK_USE_FMT
#include "driver/framework/status.h"
#include "error.h"
diff --git a/c/driver/sqlite/meson.build b/c/driver/sqlite/meson.build
index 6ddc91d03..c34b02486 100644
--- a/c/driver/sqlite/meson.build
+++ b/c/driver/sqlite/meson.build
@@ -49,6 +49,6 @@ exc = executable(
sources: ['sqlite_test.cc'],
include_directories: [include_dir, c_dir, driver_dir],
link_with: [adbc_common_lib, adbc_sqlite3_driver_lib],
- dependencies: [sqlite3_dep, adbc_validation_dep],
+ dependencies: [sqlite3_dep, adbc_validation_dep, fmt_dep],
)
test('adbc-driver-sqlite', exc)
diff --git a/c/driver/sqlite/sqlite.cc b/c/driver/sqlite/sqlite.cc
index 62dec5ab2..6aea5ee14 100644
--- a/c/driver/sqlite/sqlite.cc
+++ b/c/driver/sqlite/sqlite.cc
@@ -26,7 +26,6 @@
#include <sqlite3.h>
#include <nanoarrow/nanoarrow.hpp>
-#define ADBC_FRAMEWORK_USE_FMT
#include "driver/framework/base_driver.h"
#include "driver/framework/connection.h"
#include "driver/framework/database.h"
diff --git a/c/driver/sqlite/sqlite_test.cc b/c/driver/sqlite/sqlite_test.cc
index 243449eb0..77ad60e85 100644
--- a/c/driver/sqlite/sqlite_test.cc
+++ b/c/driver/sqlite/sqlite_test.cc
@@ -454,6 +454,77 @@ TEST(SqliteUriWrapper, SqliteUriFilename) {
adbc_validation::IsOkStatus(&error));
}
+TEST(SqliteOptions, BatchRowsGetOption) {
+ struct AdbcError error = ADBC_ERROR_INIT;
+ adbc_validation::Handle<struct AdbcDatabase> database;
+ adbc_validation::Handle<struct AdbcConnection> connection;
+ adbc_validation::Handle<struct AdbcStatement> statement;
+ constexpr const char* kBatchRows = "adbc.sqlite.query.batch_rows";
+
+ ASSERT_THAT(AdbcDatabaseNew(&database.value, &error),
+ adbc_validation::IsOkStatus(&error));
+
+ int64_t int_value = 0;
+ ASSERT_THAT(AdbcDatabaseGetOptionInt(&database.value, kBatchRows,
&int_value, &error),
+ adbc_validation::IsOkStatus(&error));
+ EXPECT_EQ(1024, int_value);
+
+ char too_small[2] = {'x', 'x'};
+ size_t length = sizeof(too_small);
+ ASSERT_THAT(
+ AdbcDatabaseGetOption(&database.value, kBatchRows, too_small, &length,
&error),
+ adbc_validation::IsOkStatus(&error));
+ EXPECT_EQ(5, length);
+ EXPECT_THAT(too_small, ::testing::ElementsAre('x', 'x'));
+
+ ASSERT_THAT(AdbcDatabaseSetOption(&database.value, kBatchRows, "41", &error),
+ adbc_validation::IsOkStatus(&error));
+ char string_value[3] = {};
+ length = sizeof(string_value);
+ ASSERT_THAT(
+ AdbcDatabaseGetOption(&database.value, kBatchRows, string_value,
&length, &error),
+ adbc_validation::IsOkStatus(&error));
+ EXPECT_EQ(3, length);
+ EXPECT_STREQ("41", string_value);
+
+ ASSERT_THAT(AdbcDatabaseInit(&database.value, &error),
+ adbc_validation::IsOkStatus(&error));
+ ASSERT_THAT(AdbcConnectionNew(&connection.value, &error),
+ adbc_validation::IsOkStatus(&error));
+ ASSERT_THAT(AdbcConnectionInit(&connection.value, &database.value, &error),
+ adbc_validation::IsOkStatus(&error));
+ ASSERT_THAT(
+ AdbcConnectionGetOptionInt(&connection.value, kBatchRows, &int_value,
&error),
+ adbc_validation::IsOkStatus(&error));
+ EXPECT_EQ(41, int_value);
+
+ ASSERT_THAT(AdbcStatementNew(&connection.value, &statement.value, &error),
+ adbc_validation::IsOkStatus(&error));
+ ASSERT_THAT(AdbcStatementGetOptionInt(&statement.value, kBatchRows,
&int_value, &error),
+ adbc_validation::IsOkStatus(&error));
+ EXPECT_EQ(41, int_value);
+
+ ASSERT_THAT(AdbcStatementSetOptionInt(&statement.value, kBatchRows, 42,
&error),
+ adbc_validation::IsOkStatus(&error));
+ char statement_value[3] = {};
+ length = sizeof(statement_value);
+ ASSERT_THAT(AdbcStatementGetOption(&statement.value, kBatchRows,
statement_value,
+ &length, &error),
+ adbc_validation::IsOkStatus(&error));
+ EXPECT_EQ(3, length);
+ EXPECT_STREQ("42", statement_value);
+
+ ASSERT_THAT(AdbcStatementSetOption(&statement.value,
"adbc.statement.bind_by_name",
+ ADBC_OPTION_VALUE_ENABLED, &error),
+ adbc_validation::IsOkStatus(&error));
+ char bind_by_name[sizeof(ADBC_OPTION_VALUE_ENABLED)] = {};
+ length = sizeof(bind_by_name);
+ ASSERT_THAT(AdbcStatementGetOption(&statement.value,
"adbc.statement.bind_by_name",
+ bind_by_name, &length, &error),
+ adbc_validation::IsOkStatus(&error));
+ EXPECT_STREQ(ADBC_OPTION_VALUE_ENABLED, bind_by_name);
+}
+
class SqliteStatementTest : public ::testing::Test,
public adbc_validation::StatementTest {
public:
diff --git a/c/subprojects/fmt.wrap b/c/subprojects/fmt.wrap
index 4e9646010..7e9c5c42b 100644
--- a/c/subprojects/fmt.wrap
+++ b/c/subprojects/fmt.wrap
@@ -1,13 +1,13 @@
[wrap-file]
-directory = fmt-10.2.0
-source_url = https://github.com/fmtlib/fmt/archive/10.2.0.tar.gz
-source_filename = fmt-10.2.0.tar.gz
-source_hash = 3ca91733a7313a8ad41c0885929415f8ec0a2a31d4dc7e27e9331412f4ca26ac
-patch_filename = fmt_10.2.0-2_patch.zip
-patch_url = https://wrapdb.mesonbuild.com/v2/fmt_10.2.0-2/get_patch
-patch_hash = 2428c3a386a8390c76378f81ef804a297f4edc3b789499dd56629b7902b8ddb7
-source_fallback_url =
https://github.com/mesonbuild/wrapdb/releases/download/fmt_10.2.0-2/fmt-10.2.0.tar.gz
-wrapdb_version = 10.2.0-2
+directory = fmt-12.0.0
+source_url = https://github.com/fmtlib/fmt/archive/12.0.0.tar.gz
+source_filename = fmt-12.0.0.tar.gz
+source_hash = aa3e8fbb6a0066c03454434add1f1fc23299e85758ceec0d7d2d974431481e40
+source_fallback_url =
https://github.com/mesonbuild/wrapdb/releases/download/fmt_12.0.0-1/fmt-12.0.0.tar.gz
+patch_filename = fmt_12.0.0-1_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/fmt_12.0.0-1/get_patch
+patch_hash = 307f288ebf3850abf2f0c50ac1fb07de97df9538d39146d802f3c0d6cada8998
+wrapdb_version = 12.0.0-1
[provide]
-fmt = fmt_dep
+dependency_names = fmt
diff --git a/docs/source/cpp/recipe_driver/CMakeLists.txt
b/docs/source/cpp/recipe_driver/CMakeLists.txt
index b4c6b0619..aae426f30 100644
--- a/docs/source/cpp/recipe_driver/CMakeLists.txt
+++ b/docs/source/cpp/recipe_driver/CMakeLists.txt
@@ -29,6 +29,12 @@ set(CMAKE_CXX_STANDARD 17)
set(NANOARROW_IPC ON)
set(NANOARROW_NAMESPACE "DriverExamplePrivate")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+fetchcontent_declare(fmt
+ GIT_REPOSITORY https://github.com/fmtlib/fmt
+ GIT_TAG 1be298e1bd68957e4cd352e1f676f00e07dcfb57) # 12.2.0
+fetchcontent_makeavailable(fmt)
+
fetchcontent_declare(nanoarrow
GIT_REPOSITORY
https://github.com/apache/arrow-nanoarrow.git
GIT_TAG apache-arrow-nanoarrow-0.9.0
@@ -43,11 +49,11 @@ add_library(adbc_driver_framework
../../../../c/driver/framework/utility.cc
../../../../c/driver/framework/objects.cc)
target_include_directories(adbc_driver_framework PRIVATE ../../../../c
../../../../c/include)
-target_link_libraries(adbc_driver_framework PRIVATE
nanoarrow::nanoarrow_static)
+target_link_libraries(adbc_driver_framework PRIVATE fmt::fmt
nanoarrow::nanoarrow_static)
add_library(driver_example SHARED driver_example.cc)
target_include_directories(driver_example PRIVATE ../../../../c
../../../../c/include)
-target_link_libraries(driver_example PRIVATE adbc_driver_framework
+target_link_libraries(driver_example PRIVATE adbc_driver_framework fmt::fmt
nanoarrow::nanoarrow_ipc)
install(TARGETS driver_example)
diff --git a/python/adbc_driver_sqlite/tests/test_lowlevel.py
b/python/adbc_driver_sqlite/tests/test_lowlevel.py
index 9c8afcac3..f1f2174a6 100644
--- a/python/adbc_driver_sqlite/tests/test_lowlevel.py
+++ b/python/adbc_driver_sqlite/tests/test_lowlevel.py
@@ -49,6 +49,13 @@ def test_options(sqlite):
adbc_driver_sqlite.StatementOptions.BATCH_ROWS.value: "1",
}
)
+ assert (
+
stmt.get_option(adbc_driver_sqlite.StatementOptions.BATCH_ROWS.value) == "1"
+ )
+ assert (
+
stmt.get_option_int(adbc_driver_sqlite.StatementOptions.BATCH_ROWS.value)
+ == 1
+ )
stmt.set_sql_query("SELECT 1")
stream, _ = stmt.execute_query()
reader = pyarrow.RecordBatchReader._import_from_c(stream.address)
diff --git a/r/adbcdrivermanager/src/Makevars b/r/adbcdrivermanager/src/Makevars
index 5476c6e35..f17dd3681 100644
--- a/r/adbcdrivermanager/src/Makevars
+++ b/r/adbcdrivermanager/src/Makevars
@@ -17,7 +17,7 @@
CXX_STD = CXX20
CONDA_BUILD ?= "0"
-PKG_CPPFLAGS=-I../src/c/include -I../src/c -I../src/c/vendor -DADBC_EXPORT=""
-DADBC_CONDA_BUILD=$(CONDA_BUILD)
+PKG_CPPFLAGS=-I../src/c/include -I../src/c -I../src/c/vendor
-I../src/c/vendor/fmt/include -DADBC_EXPORT=""
-DADBC_CONDA_BUILD=$(CONDA_BUILD) -DFMT_HEADER_ONLY=1
OBJECTS = driver_test.o \
error.o \
diff --git a/r/adbcdrivermanager/src/Makevars.win
b/r/adbcdrivermanager/src/Makevars.win
index 6a086d369..ac0c8cec9 100644
--- a/r/adbcdrivermanager/src/Makevars.win
+++ b/r/adbcdrivermanager/src/Makevars.win
@@ -17,7 +17,7 @@
CXX_STD = CXX20
CONDA_BUILD ?= "0"
-PKG_CPPFLAGS=-I../src/c/include -I../src/c -I../src/c/vendor -DADBC_EXPORT=""
-DADBC_CONDA_BUILD=$(CONDA_BUILD)
+PKG_CPPFLAGS=-I../src/c/include -I../src/c -I../src/c/vendor
-I../src/c/vendor/fmt/include -DADBC_EXPORT=""
-DADBC_CONDA_BUILD=$(CONDA_BUILD) -DFMT_HEADER_ONLY=1
PKG_LIBS=-lshell32 -ladvapi32 -luuid
OBJECTS = driver_test.o \
diff --git a/r/adbcdrivermanager/tests/testthat/test-options.R
b/r/adbcdrivermanager/tests/testthat/test-options.R
index 8d978f838..dc8c2f295 100644
--- a/r/adbcdrivermanager/tests/testthat/test-options.R
+++ b/r/adbcdrivermanager/tests/testthat/test-options.R
@@ -251,43 +251,35 @@ test_that("void driver errors getting bytes option of
incorrect type", {
)
})
-test_that("void driver errors getting integer option of incorrect type", {
+test_that("void driver errors getting integer option as bytes", {
db <- adbc_database_init(adbc_driver_void())
adbc_database_set_options(db, list("some_key" = 123L))
- expect_error(
- adbc_database_get_option(db, "some_key"),
- class = "adbc_status_not_found"
- )
-
expect_error(
adbc_database_get_option_bytes(db, "some_key"),
class = "adbc_status_not_found"
)
-
-
})
test_that("void driver can get integer option of compatible type", {
db <- adbc_database_init(adbc_driver_void())
adbc_database_set_options(db, list("some_key" = 123L))
+ expect_identical(
+ adbc_database_get_option(db, "some_key"),
+ "123"
+ )
+
expect_identical(
adbc_database_get_option_double(db, "some_key"),
123.0
)
})
-
-test_that("void driver errors getting double option of incorrect type", {
+test_that("void driver errors getting double option as incompatible type", {
db <- adbc_database_init(adbc_driver_void())
adbc_database_set_options(db, list("some_key" = 123.4))
- expect_error(
- adbc_database_get_option(db, "some_key"),
- class = "adbc_status_not_found"
- )
-
expect_error(
adbc_database_get_option_bytes(db, "some_key"),
class = "adbc_status_not_found"
@@ -299,6 +291,16 @@ test_that("void driver errors getting double option of
incorrect type", {
)
})
+test_that("void driver can get double option of compatible type", {
+ db <- adbc_database_init(adbc_driver_void())
+ adbc_database_set_options(db, list("some_key" = 123.4))
+
+ expect_identical(
+ adbc_database_get_option(db, "some_key"),
+ "123.4"
+ )
+})
+
test_that("key_value_options works", {
expect_identical(
key_value_options(NULL),