从R获取C变量?

时间:2018-03-20 10:14:55

标签: r rodbc

这是我的问题。我想知道我在R会话中有多少个开放的RODBC连接。也许这个问题与Show all open RODBC connections有关。

问题是,如果我没有将连接分配给变量,我将无法使用此功能,即我执行odbcConnect()而不是channel<-odbcConnect(),因为不会创建环境变量。

我查看了RODBC包的C代码,似乎有一个变量nChannels,其中包含int个打开的连接数。我可以从R调用此变量,甚至使用C函数吗?

R环境如何在这里发挥作用?还是完全无关?任何解释都将受到赞赏,因为我在这个领域非常新。如果我接近这一点的逻辑也是错误的,请提供建议。

1 个答案:

答案 0 :(得分:1)

如果用户提交自己的代码,解决方案很简单:提供自己的函数odbcConnect,该函数在内部记录调用,然后发送到{RODBC}包。也就是说,不要让用户直接访问RODBC包。

只要您为用户提供设置(即用户永远不会呼叫library(RODBC),也不会RODBC::odbcConnect),此功能就可以使用。

但如果不是这样,即如果用户直接与RODBC包进行交互,则需要更进一步:您需要自己修改RODBC包。您可以通过在运行时修补函数来完成此操作,但这是相当高级的(并且很脆弱;如果RODBC升级并更改其实现,它会中断)。这是一个最小的例子:

log_connect_expr = quote(assign('.odbc_connections', .GlobalEnv$.odbc_connections + 1, .GlobalEnv))
log_close_expr = quote(assign('.odbc_connections', .GlobalEnv$.odbc_connections - 1, .GlobalEnv))

# Inject expression into a function body at a given position, counting either
# from the beginning or from the end (if `pos` < 0).
insert_in_body = function (body, expr, pos) {
    body = as.list(body)
    if (pos < 0) pos = length(body) + pos + 1
    all_indices = seq_along(body)
    before_indices = all_indices < pos
    after_indices = all_indices >= pos
    as.call(c(body[before_indices], expr, body[after_indices]))
}

# Insert log calls into function bodies, after any error checking.

local({
    odbcDriverConnect = RODBC::odbcDriverConnect
    body(odbcDriverConnect) = insert_in_body(body(odbcDriverConnect), log_connect_expr, -1)
    odbcClose = RODBC::odbcClose
    body(odbcClose) = insert_in_body(body(odbcClose), log_close_expr, 4)

    assignInNamespace('odbcDriverConnect', odbcDriverConnect, getNamespace('RODBC'))
    assignInNamespace('odbcClose', odbcClose, getNamespace('RODBC'))
})

# Initialize counter
.GlobalEnv$.odbc_connections = 0

替代方案,只需下载RODBC源代码,修改它,构建软件包并在本地安装。所有这些解决方案都是hacky,但比在RODBC的C内部搜索更好。

读取内部RODBC连接状态不切实际。首先,变量nChannels似乎不是打开连接数的准确计数;它更像是一个上限,关闭连接不会减少计数器。

但即使它是准确的,你无论如何都无法阅读,因为变量被声明为static,因此不会被导出。