Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add helper to locate configuration files #680

Merged
merged 13 commits into from
Dec 19, 2023
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export(odbcConnectionColumns)
export(odbcConnectionIcon)
export(odbcDataType)
export(odbcListColumns)
export(odbcListConfig)
export(odbcListDataSources)
export(odbcListDrivers)
export(odbcListObjectTypes)
Expand Down
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# odbc (development version)

* Added a function `odbcListConfig()` to help locate configuration files on
macOS and Linux (@simonpcouch, #565).

* `dbGetQuery()` and `dbSendQuery()` now set `immediate = TRUE` if you are
not using a parameterised query. That should yield a small speed boost in
many cases (#633).
Expand Down
50 changes: 50 additions & 0 deletions R/Connection.R
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,56 @@ setMethod(
invisible(TRUE)
})

#' List Locations of ODBC Configuration Files
#'
#' @description
#' On MacOS and Linux, odbc uses the unixODBC driver manager to manage
#' information about driver and data sources. This helper returns the filepaths
#' where the driver manager will look for that information.
#'
#' @details
#' This function is a wrapper around the command line call `odbcinst -j`.
#'
#' Windows now uses the ODBC Data Source Administrator application to manage
#' drivers and thus does not use `.ini` files; this function will return a
#' 0-row data frame on Windows.
#'
#' @seealso
#' The [odbcListDrivers()] and [odbcListDataSources()] helpers return
#' information on the contents of `odbcinst.ini` and `odbc.ini` files,
#' respectively.
#'
#' Learn more about unixODBC and the `odbcinst` utility
#' [here](https://www.unixodbc.org/odbcinst.html).
#'
#' @examplesIf FALSE
#' configs <- odbcListConfig()
#'
#' file.edit(configs$location[1])
#' @export
odbcListConfig <- function() {
if (identical(.Platform$OS.type, "windows")) {
return(data.frame(name = character(0), location = character(0)))
}

if (identical(unname(Sys.which("odbcinst")), "")) {
stop(
c("The unixODBC driver manager is not available. ",
"Please install and try again.")
)
}

res <- system("odbcinst -j", intern = TRUE)
res <- res[grepl("\\.ini", res)]
res <- strsplit(res, "\\:")
res <- data.frame(name = vapply(res, `[[`, character(1), 1),
location = vapply(res, `[[`, character(1), 2))
res$name <- gsub("\\.", "", res$name)
res$location <- trimws(res$location)

res
}

#' List Configured ODBC Drivers
#'
#' @description
Expand Down
Binary file modified inst/diagrams.key
Binary file not shown.
Binary file modified man/figures/r-interface.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions man/odbcListConfig.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions tests/testthat/test-Connection.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,35 @@ test_that("build_connection_string automatically escapes if needed", {
# Respects AsIs
expect_equal(build_connection_string(list(foo = I("*"))), "foo=*")
})

test_that("odbcListConfig returns appropriate data frame", {
skip_on_os(c("windows", "solaris"))
skip_if(identical(unname(Sys.which("odbcinst")), ""), "odbcinst not available.")

res <- odbcListConfig()

expect_s3_class(res, "data.frame")
expect_length(res, 2)
expect_named(res, c("name", "location"))
expect_contains(res$name, c("DRIVERS", "SYSTEM DATA SOURCES"))
expect_match(res$location, "\\.ini")
})

test_that("odbcListConfig returns a 0-row data frame on Windows", {
skip_on_os(c("mac", "linux", "solaris"))
skip_if(identical(unname(Sys.which("odbcinst")), ""), "odbcinst not available.")

res <- odbcListConfig()

expect_equal(res, data.frame(name = character(0), location = character(0)))
})

test_that("odbcListConfig errors informatively when unixODBC isn't available", {
skip_on_os(c("windows", "solaris"))
skip_if(!identical(unname(Sys.which("odbcinst")), ""), "odbcinst is available")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this test will ever be run on our CI as currently configured. Ran on a fresh RStudio Pro instance and checks were fine.


expect_error(
odbcListConfig(),
"driver manager is not available"
)
})