This is an automated email from the ASF dual-hosted git repository.
paleolimbot 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 c75e983 feat(r): Add driver logging utility (#694)
c75e983 is described below
commit c75e983f7235ecb7ebd4af20aabb3c558224864a
Author: Dewey Dunnington <[email protected]>
AuthorDate: Fri May 19 08:31:27 2023 -0400
feat(r): Add driver logging utility (#694)
Initially I was hoping this would be able to wrap an arbitrary driver
and log the call + the return code, but that was too hard and I only
need a tiny subset of that behaviour to test #693. After this PR you can
verify that cleanup calls actually take place:
``` r
library(adbcdrivermanager)
db <- adbc_database_init(adbc_driver_log(), key = "value")
#> LogDriverInitFunc()
#> LogDriverInitFunc()
#> LogDatabaseNew()
#> LogDatabaseSetOption()
#> LogDatabaseInit()
con <- adbc_connection_init(db, key = "value")
#> LogConnectionNew()
#> LogConnectionInit()
#> LogConnectionSetOption()
stmt <- adbc_statement_init(con, key = "value")
#> LogStatementNew()
#> LogStatementSetOption()
try(adbc_statement_execute_query(stmt))
#> LogStatementExecuteQuery()
#> Error in stop_for_error(result$status, error) :
#> ADBC_STATUS_NOT_IMPLEMENTED (2)
adbc_statement_release(stmt)
#> LogStatementRelease()
adbc_connection_release(con)
#> LogConnectionRelease()
adbc_database_release(db)
#> LogDatabaseRelease()
#> LogDriverRelease()
```
<sup>Created on 2023-05-18 with [reprex
v2.0.2](https://reprex.tidyverse.org)</sup>
---
.pre-commit-config.yaml | 2 +
dev/release/rat_exclude_files.txt | 1 +
r/adbcdrivermanager/NAMESPACE | 4 +
r/adbcdrivermanager/R/driver_log.R | 74 +++++
r/adbcdrivermanager/man/adbc_driver_log.Rd | 27 ++
r/adbcdrivermanager/src/driver_log.c | 343 +++++++++++++++++++++
r/adbcdrivermanager/src/init.c | 4 +-
r/adbcdrivermanager/src/radbc.cc | 17 +
.../tests/testthat/_snaps/driver_log.md | 41 +++
.../tests/testthat/test-driver_log.R | 28 ++
10 files changed, 540 insertions(+), 1 deletion(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index aacf930..8353583 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -28,7 +28,9 @@ repos:
- id: check-yaml
exclude: ci/conda/meta.yaml
- id: end-of-file-fixer
+ exclude: r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
- id: trailing-whitespace
+ exclude: r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
diff --git a/dev/release/rat_exclude_files.txt
b/dev/release/rat_exclude_files.txt
index d13c65c..f8e26fb 100644
--- a/dev/release/rat_exclude_files.txt
+++ b/dev/release/rat_exclude_files.txt
@@ -16,6 +16,7 @@ rat.txt
r/adbcdrivermanager/DESCRIPTION
r/adbcdrivermanager/NAMESPACE
r/adbcdrivermanager/.Rbuildignore
+r/adbcdrivermanager/tests/testthat/_snaps/*
r/adbcsqlite/DESCRIPTION
r/adbcsqlite/NAMESPACE
r/adbcsqlite/.Rbuildignore
diff --git a/r/adbcdrivermanager/NAMESPACE b/r/adbcdrivermanager/NAMESPACE
index cf653a2..c13dd38 100644
--- a/r/adbcdrivermanager/NAMESPACE
+++ b/r/adbcdrivermanager/NAMESPACE
@@ -6,10 +6,13 @@ S3method("$<-",adbc_xptr)
S3method("[[",adbc_error)
S3method("[[",adbc_xptr)
S3method("[[<-",adbc_xptr)
+S3method(adbc_connection_init,adbc_database_log)
S3method(adbc_connection_init,adbc_database_monkey)
S3method(adbc_connection_init,default)
+S3method(adbc_database_init,adbc_driver_log)
S3method(adbc_database_init,adbc_driver_monkey)
S3method(adbc_database_init,default)
+S3method(adbc_statement_init,adbc_connection_log)
S3method(adbc_statement_init,adbc_connection_monkey)
S3method(adbc_statement_init,default)
S3method(length,adbc_error)
@@ -38,6 +41,7 @@ export(adbc_database_init_default)
export(adbc_database_release)
export(adbc_database_set_options)
export(adbc_driver)
+export(adbc_driver_log)
export(adbc_driver_monkey)
export(adbc_driver_void)
export(adbc_statement_bind)
diff --git a/r/adbcdrivermanager/R/driver_log.R
b/r/adbcdrivermanager/R/driver_log.R
new file mode 100644
index 0000000..b7b70f0
--- /dev/null
+++ b/r/adbcdrivermanager/R/driver_log.R
@@ -0,0 +1,74 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+#' Log calls to another driver
+#'
+#' Useful for debugging or ensuring that certain calls occur during
+#' initialization and/or cleanup. The current logging output should not
+#' be considered stable and may change in future releases.
+#'
+#'
+#' @return An object of class 'adbc_driver_log'
+#' @export
+#'
+#' @examples
+#' drv <- adbc_driver_log()
+#' db <- adbc_database_init(drv, key = "value")
+#' con <- adbc_connection_init(db, key = "value")
+#' stmt <- adbc_statement_init(con, key = "value")
+#' try(adbc_statement_execute_query(stmt))
+#' adbc_statement_release(stmt)
+#' adbc_connection_release(con)
+#' adbc_database_release(db)
+#'
+adbc_driver_log <- function() {
+ if (is.null(internal_driver_env$log)) {
+ internal_driver_env$log <- adbc_driver(
+ .Call(RAdbcLogDriverInitFunc),
+ subclass = "adbc_driver_log"
+ )
+ }
+
+ internal_driver_env$log
+}
+
+#' @export
+adbc_database_init.adbc_driver_log <- function(driver, ...) {
+ adbc_database_init_default(
+ driver,
+ options = list(...),
+ subclass = "adbc_database_log"
+ )
+}
+
+#' @export
+adbc_connection_init.adbc_database_log <- function(database, ...) {
+ adbc_connection_init_default(
+ database,
+ options = list(...),
+ subclass = "adbc_connection_log"
+ )
+}
+
+#' @export
+adbc_statement_init.adbc_connection_log <- function(connection, ...) {
+ adbc_statement_init_default(
+ connection,
+ options = list(...),
+ subclass = "adbc_statement_log"
+ )
+}
diff --git a/r/adbcdrivermanager/man/adbc_driver_log.Rd
b/r/adbcdrivermanager/man/adbc_driver_log.Rd
new file mode 100644
index 0000000..fbd3c76
--- /dev/null
+++ b/r/adbcdrivermanager/man/adbc_driver_log.Rd
@@ -0,0 +1,27 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/driver_log.R
+\name{adbc_driver_log}
+\alias{adbc_driver_log}
+\title{Log calls to another driver}
+\usage{
+adbc_driver_log()
+}
+\value{
+An object of class 'adbc_driver_log'
+}
+\description{
+Useful for debugging or ensuring that certain calls occur during
+initialization and/or cleanup. The current logging output should not
+be considered stable and may change in future releases.
+}
+\examples{
+drv <- adbc_driver_log()
+db <- adbc_database_init(drv, key = "value")
+con <- adbc_connection_init(db, key = "value")
+stmt <- adbc_statement_init(con, key = "value")
+try(adbc_statement_execute_query(stmt))
+adbc_statement_release(stmt)
+adbc_connection_release(con)
+adbc_database_release(db)
+
+}
diff --git a/r/adbcdrivermanager/src/driver_log.c
b/r/adbcdrivermanager/src/driver_log.c
new file mode 100644
index 0000000..5a0520d
--- /dev/null
+++ b/r/adbcdrivermanager/src/driver_log.c
@@ -0,0 +1,343 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#define R_NO_REMAP
+#include <R.h>
+#include <Rinternals.h>
+
+#include <string.h>
+
+#include <adbc.h>
+
+struct LogDriverPrivate {
+ char token[1024];
+};
+
+struct LogDatabasePrivate {
+ char token[1024];
+};
+
+struct LogConnectionPrivate {
+ char token[1024];
+};
+
+struct LogStatementPrivate {
+ char token[1024];
+};
+
+static void ResetError(struct AdbcError* error) {
+ memset(error, 0, sizeof(struct AdbcError));
+}
+
+static void SetErrorConst(struct AdbcError* error, const char* value) {
+ if (error == NULL) {
+ return;
+ }
+
+ ResetError(error);
+ error->message = (char*)value;
+}
+
+static AdbcStatusCode LogDriverRelease(struct AdbcDriver* driver,
+ struct AdbcError* error) {
+ Rprintf("LogDriverRelease()\n");
+ if (driver->private_data == NULL) {
+ return ADBC_STATUS_OK;
+ }
+
+ free(driver->private_data);
+ driver->private_data = NULL;
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogDatabaseNew(struct AdbcDatabase* database,
+ struct AdbcError* error) {
+ Rprintf("LogDatabaseNew()\n");
+
+ struct LogDatabasePrivate* database_private =
+ (struct LogDatabasePrivate*)malloc(sizeof(struct LogDatabasePrivate));
+ if (database_private == NULL) {
+ SetErrorConst(error, "failed to allocate LogDatabasePrivate");
+ return ADBC_STATUS_INTERNAL;
+ }
+
+ memset(database_private, 0, sizeof(struct LogDatabasePrivate));
+ database->private_data = database_private;
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogDatabaseInit(struct AdbcDatabase* database,
+ struct AdbcError* error) {
+ Rprintf("LogDatabaseInit()\n");
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogDatabaseSetOption(struct AdbcDatabase* database,
const char* key,
+ const char* value, struct
AdbcError* error) {
+ Rprintf("LogDatabaseSetOption()\n");
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogDatabaseRelease(struct AdbcDatabase* database,
+ struct AdbcError* error) {
+ Rprintf("LogDatabaseRelease()\n");
+ if (database->private_data == NULL) {
+ return ADBC_STATUS_OK;
+ }
+
+ free(database->private_data);
+ database->private_data = NULL;
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogConnectionCommit(struct AdbcConnection* connection,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionCommit()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogConnectionGetInfo(struct AdbcConnection* connection,
+ uint32_t* info_codes, size_t
info_codes_length,
+ struct ArrowArrayStream* stream,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionGetInfo()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogConnectionGetObjects(
+ struct AdbcConnection* connection, int depth, const char* catalog,
+ const char* db_schema, const char* table_name, const char** table_types,
+ const char* column_name, struct ArrowArrayStream* stream, struct
AdbcError* error) {
+ Rprintf("LogConnectionGetObjects()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogConnectionGetTableSchema(
+ struct AdbcConnection* connection, const char* catalog, const char*
db_schema,
+ const char* table_name, struct ArrowSchema* schema, struct AdbcError*
error) {
+ Rprintf("LogConnectionGetTableSchema()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogConnectionGetTableTypes(struct AdbcConnection*
connection,
+ struct ArrowArrayStream*
stream,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionGetTableTypes()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogConnectionInit(struct AdbcConnection* connection,
+ struct AdbcDatabase* database,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionInit()\n");
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogConnectionNew(struct AdbcConnection* connection,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionNew()\n");
+
+ struct LogConnectionPrivate* connection_private =
+ (struct LogConnectionPrivate*)malloc(sizeof(struct
LogConnectionPrivate));
+ if (connection_private == NULL) {
+ SetErrorConst(error, "failed to allocate LogConnectionPrivate");
+ return ADBC_STATUS_INTERNAL;
+ }
+
+ memset(connection_private, 0, sizeof(struct LogConnectionPrivate));
+ connection->private_data = connection_private;
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogConnectionReadPartition(struct AdbcConnection*
connection,
+ const uint8_t*
serialized_partition,
+ size_t serialized_length,
+ struct ArrowArrayStream* out,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionReadPartition()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogConnectionRelease(struct AdbcConnection* connection,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionRelease()\n");
+ if (connection->private_data == NULL) {
+ return ADBC_STATUS_OK;
+ }
+
+ free(connection->private_data);
+ connection->private_data = NULL;
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogConnectionRollback(struct AdbcConnection* connection,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionRollback()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogConnectionSetOption(struct AdbcConnection* connection,
+ const char* key, const char*
value,
+ struct AdbcError* error) {
+ Rprintf("LogConnectionSetOption()\n");
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogStatementBind(struct AdbcStatement* statement,
+ struct ArrowArray* values,
+ struct ArrowSchema* schema,
+ struct AdbcError* error) {
+ Rprintf("LogStatementBind()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+} // NOLINT(whitespace/indent)
+
+static AdbcStatusCode LogStatementBindStream(struct AdbcStatement* statement,
+ struct ArrowArrayStream* stream,
+ struct AdbcError* error) {
+ Rprintf("LogStatementBindStream()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogStatementExecutePartitions(struct AdbcStatement*
statement,
+ struct ArrowSchema* schema,
+ struct AdbcPartitions*
partitions,
+ int64_t* rows_affected,
+ struct AdbcError* error) {
+ Rprintf("LogStatementExecutePartitions()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+} // NOLINT(whitespace/indent)
+
+static AdbcStatusCode LogStatementExecuteQuery(struct AdbcStatement* statement,
+ struct ArrowArrayStream* out,
+ int64_t* rows_affected,
+ struct AdbcError* error) {
+ Rprintf("LogStatementExecuteQuery()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogStatementGetParameterSchema(struct AdbcStatement*
statement,
+ struct ArrowSchema*
schema,
+ struct AdbcError* error) {
+ Rprintf("LogStatementGetParameterSchema()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogStatementNew(struct AdbcConnection* connection,
+ struct AdbcStatement* statement,
+ struct AdbcError* error) {
+ Rprintf("LogStatementNew()\n");
+ struct LogStatementPrivate* statement_private =
+ (struct LogStatementPrivate*)malloc(sizeof(struct LogStatementPrivate));
+ if (statement_private == NULL) {
+ SetErrorConst(error, "failed to allocate LogStatementPrivate");
+ return ADBC_STATUS_INTERNAL;
+ }
+
+ memset(statement_private, 0, sizeof(struct LogStatementPrivate));
+ statement->private_data = statement_private;
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogStatementPrepare(struct AdbcStatement* statement,
+ struct AdbcError* error) {
+ Rprintf("LogStatementPrepare()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogStatementRelease(struct AdbcStatement* statement,
+ struct AdbcError* error) {
+ Rprintf("LogStatementRelease()\n");
+ if (statement->private_data == NULL) {
+ return ADBC_STATUS_OK;
+ }
+
+ free(statement->private_data);
+ statement->private_data = NULL;
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogStatementSetOption(struct AdbcStatement* statement,
+ const char* key, const char* value,
+ struct AdbcError* error) {
+ Rprintf("LogStatementSetOption()\n");
+ return ADBC_STATUS_OK;
+}
+
+static AdbcStatusCode LogStatementSetSqlQuery(struct AdbcStatement* statement,
+ const char* query,
+ struct AdbcError* error) {
+ Rprintf("LogStatementSetSqlQuery()\n");
+ return ADBC_STATUS_NOT_IMPLEMENTED;
+}
+
+static AdbcStatusCode LogDriverInitFunc(int version, void* raw_driver,
+ struct AdbcError* error) {
+ Rprintf("LogDriverInitFunc()\n");
+ if (version != ADBC_VERSION_1_0_0) return ADBC_STATUS_NOT_IMPLEMENTED;
+ struct AdbcDriver* driver = (struct AdbcDriver*)raw_driver;
+ memset(driver, 0, sizeof(struct AdbcDriver));
+
+ struct LogDriverPrivate* driver_private =
+ (struct LogDriverPrivate*)malloc(sizeof(struct LogDriverPrivate));
+ if (driver_private == NULL) {
+ SetErrorConst(error, "failed to allocate LogDriverPrivate");
+ return ADBC_STATUS_INTERNAL;
+ }
+
+ memset(driver_private, 0, sizeof(struct LogDriverPrivate));
+ driver->private_data = driver_private;
+
+ driver->DatabaseInit = &LogDatabaseInit;
+ driver->DatabaseNew = LogDatabaseNew;
+ driver->DatabaseRelease = LogDatabaseRelease;
+ driver->DatabaseSetOption = LogDatabaseSetOption;
+
+ driver->ConnectionCommit = LogConnectionCommit;
+ driver->ConnectionGetInfo = LogConnectionGetInfo;
+ driver->ConnectionGetObjects = LogConnectionGetObjects;
+ driver->ConnectionGetTableSchema = LogConnectionGetTableSchema;
+ driver->ConnectionGetTableTypes = LogConnectionGetTableTypes;
+ driver->ConnectionInit = LogConnectionInit;
+ driver->ConnectionNew = LogConnectionNew;
+ driver->ConnectionReadPartition = LogConnectionReadPartition;
+ driver->ConnectionRelease = LogConnectionRelease;
+ driver->ConnectionRollback = LogConnectionRollback;
+ driver->ConnectionSetOption = LogConnectionSetOption;
+
+ driver->StatementBind = LogStatementBind;
+ driver->StatementBindStream = LogStatementBindStream;
+ driver->StatementExecutePartitions = LogStatementExecutePartitions;
+ driver->StatementExecuteQuery = LogStatementExecuteQuery;
+ driver->StatementGetParameterSchema = LogStatementGetParameterSchema;
+ driver->StatementNew = LogStatementNew;
+ driver->StatementPrepare = LogStatementPrepare;
+ driver->StatementRelease = LogStatementRelease;
+ driver->StatementSetOption = LogStatementSetOption;
+ driver->StatementSetSqlQuery = LogStatementSetSqlQuery;
+
+ driver->release = LogDriverRelease;
+
+ return ADBC_STATUS_OK;
+}
+
+SEXP RAdbcLogDriverInitFunc() {
+ SEXP xptr =
+ PROTECT(R_MakeExternalPtrFn((DL_FUNC)LogDriverInitFunc, R_NilValue,
R_NilValue));
+ Rf_setAttrib(xptr, R_ClassSymbol, Rf_mkString("adbc_driver_init_func"));
+ UNPROTECT(1);
+ return xptr;
+}
diff --git a/r/adbcdrivermanager/src/init.c b/r/adbcdrivermanager/src/init.c
index 3ad706c..de2f95f 100644
--- a/r/adbcdrivermanager/src/init.c
+++ b/r/adbcdrivermanager/src/init.c
@@ -20,6 +20,7 @@
#include <Rinternals.h>
/* generated by tools/make-callentries.R */
+SEXP RAdbcLogDriverInitFunc();
SEXP RAdbcMonkeyDriverInitFunc();
SEXP RAdbcVoidDriverInitFunc();
SEXP RAdbcAllocateError(SEXP shelter_sexp);
@@ -27,7 +28,7 @@ SEXP RAdbcErrorProxy(SEXP error_xptr);
SEXP RAdbcStatusCodeMessage(SEXP status_sexp);
SEXP RAdbcLoadDriver(SEXP driver_name_sexp, SEXP entrypoint_sexp);
SEXP RAdbcLoadDriverFromInitFunc(SEXP driver_init_func_xptr);
-SEXP RAdbcDatabaseNew(SEXP driver_xptr);
+SEXP RAdbcDatabaseNew(SEXP driver_init_func_xptr);
SEXP RAdbcDatabaseSetOption(SEXP database_xptr, SEXP key_sexp, SEXP value_sexp,
SEXP error_xptr);
SEXP RAdbcDatabaseInit(SEXP database_xptr, SEXP error_xptr);
@@ -71,6 +72,7 @@ SEXP RAdbcStatementExecutePartitions(SEXP statement_xptr,
SEXP out_schema_xptr,
SEXP RAdbcXptrEnv(SEXP xptr);
static const R_CallMethodDef CallEntries[] = {
+ {"RAdbcLogDriverInitFunc", (DL_FUNC)&RAdbcLogDriverInitFunc, 0},
{"RAdbcMonkeyDriverInitFunc", (DL_FUNC)&RAdbcMonkeyDriverInitFunc, 0},
{"RAdbcVoidDriverInitFunc", (DL_FUNC)&RAdbcVoidDriverInitFunc, 0},
{"RAdbcAllocateError", (DL_FUNC)&RAdbcAllocateError, 1},
diff --git a/r/adbcdrivermanager/src/radbc.cc b/r/adbcdrivermanager/src/radbc.cc
index 70c3f60..1b977cf 100644
--- a/r/adbcdrivermanager/src/radbc.cc
+++ b/r/adbcdrivermanager/src/radbc.cc
@@ -44,6 +44,22 @@ static void adbc_error_stop(int code, AdbcError* error,
const char* context) {
}
}
+static void finalize_driver_xptr(SEXP driver_xptr) {
+ auto driver = reinterpret_cast<AdbcDriver*>(R_ExternalPtrAddr(driver_xptr));
+ if (driver == nullptr) {
+ return;
+ }
+
+ if (driver->release != nullptr) {
+ AdbcError error;
+ int status = driver->release(driver, &error);
+ adbc_error_warn(status, &error, "finalize_driver_xptr()");
+ }
+
+ adbc_xptr_default_finalize<AdbcDriver>(driver_xptr);
+ R_SetExternalPtrAddr(driver_xptr, nullptr);
+}
+
static void finalize_database_xptr(SEXP database_xptr) {
auto database =
reinterpret_cast<AdbcDatabase*>(R_ExternalPtrAddr(database_xptr));
if (database == nullptr) {
@@ -83,6 +99,7 @@ extern "C" SEXP RAdbcLoadDriverFromInitFunc(SEXP
driver_init_func_xptr) {
}
SEXP driver_xptr = PROTECT(adbc_allocate_xptr<AdbcDriver>());
+ R_RegisterCFinalizer(driver_xptr, &finalize_driver_xptr);
auto driver = adbc_from_xptr<AdbcDriver>(driver_xptr);
AdbcError error;
diff --git a/r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
b/r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
new file mode 100644
index 0000000..4658a3f
--- /dev/null
+++ b/r/adbcdrivermanager/tests/testthat/_snaps/driver_log.md
@@ -0,0 +1,41 @@
+# The log driver logs
+
+ Code
+ db <- adbc_database_init(adbc_driver_log(), key = "value")
+ Output
+ LogDriverInitFunc()
+ LogDriverInitFunc()
+ LogDatabaseNew()
+ LogDatabaseSetOption()
+ LogDatabaseInit()
+ Code
+ con <- adbc_connection_init(db, key = "value")
+ Output
+ LogConnectionNew()
+ LogConnectionInit()
+ LogConnectionSetOption()
+ Code
+ stmt <- adbc_statement_init(con, key = "value")
+ Output
+ LogStatementNew()
+ LogStatementSetOption()
+ Code
+ try(adbc_statement_execute_query(stmt))
+ Output
+ LogStatementExecuteQuery()
+ Error in stop_for_error(result$status, error) :
+ ADBC_STATUS_NOT_IMPLEMENTED (2)
+ Code
+ adbc_statement_release(stmt)
+ Output
+ LogStatementRelease()
+ Code
+ adbc_connection_release(con)
+ Output
+ LogConnectionRelease()
+ Code
+ adbc_database_release(db)
+ Output
+ LogDatabaseRelease()
+ LogDriverRelease()
+
diff --git a/r/adbcdrivermanager/tests/testthat/test-driver_log.R
b/r/adbcdrivermanager/tests/testthat/test-driver_log.R
new file mode 100644
index 0000000..9470443
--- /dev/null
+++ b/r/adbcdrivermanager/tests/testthat/test-driver_log.R
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+test_that("The log driver logs", {
+ expect_snapshot({
+ db <- adbc_database_init(adbc_driver_log(), key = "value")
+ con <- adbc_connection_init(db, key = "value")
+ stmt <- adbc_statement_init(con, key = "value")
+ try(adbc_statement_execute_query(stmt))
+ adbc_statement_release(stmt)
+ adbc_connection_release(con)
+ adbc_database_release(db)
+ })
+})