-
Notifications
You must be signed in to change notification settings - Fork 107
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
odbc segfaults when executing multiple queries since commit 5b36b47 #716
Comments
I have the exact same problem on both MacOS and Ubuntu. If the query yields zero rows then I do not get any problems. But a query yielding rows of data crashes the second time I run it. It does not seem to matter if it is parametrized or non-parametrized. Downgrading |
Thanks for the issue, yall. I'm not able to reproduce with SQL Server 2022 (same OS, architecture, pkg version and install method)—let me see if I can get a deployment of SQL Server 2016 up and running and test against that. @michael-dewar, could you provide your |
I am seeing a very similar problem since upgrading to ODBC 1.4.1, too. I hope this information is useful: SQL Server version: 14.00.3451 The error I am getting when running a query the second time is:
The session_info:
|
It looks like Microsoft no longer supports SQL server 2016 and 2017 (14.00.3451), and these are both over six years old. Given that this doesn't appear to be a problem with a recent SQL server, I think this means that this unfortunately something that we don't have the time/resources to fix. |
Closing this issue, but happy to reopen if we have evidence it affects supported SQL server versions. |
I have the problem with both SQL Server 2019 and 2022. con <- DBI::dbConnect(odbc::odbc(),
driver = "/opt/homebrew/lib/libtdsodbc.so",
server = configs2019$host,
port = configs2019$port,
uid = configs2019$user,
pwd = configs2019$pwd)
"select @@VERSION" |> DBI::dbGetQuery(con, statement = _)
#>
#> 1 Microsoft SQL Server 2019 (RTM-CU23) (KB5030333) - 15.0.4335.1 (X64) \n\tSep 21 2023 17:28:44 \n\tCopyright (C) 2019 Microsoft Corporation\n\tExpress Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 22631: ) (Hypervisor)\n
DBI::dbDisconnect(con)
#> Warning in connection_release(conn@ptr): There is a result object still in use.
#> The connection will be automatically released when it is closed
con <- DBI::dbConnect(odbc::odbc(),
driver = "/opt/homebrew/lib/libtdsodbc.so",
server = configs2022$host,
port = configs2022$port,
uid = configs2022$user,
pwd = configs2022$pwd)
"select @@VERSION" |> DBI::dbGetQuery(con, statement = _)
#>
#> 1 Microsoft SQL Server 2022 (RTM-GDR) (KB5029379) - 16.0.1105.1 (X64) \n\tAug 24 2023 02:40:55 \n\tCopyright (C) 2022 Microsoft Corporation\n\tExpress Edition (64-bit) on Windows 10 Enterprise 10.0 <X64> (Build 19045: ) (Hypervisor)\n
DBI::dbDisconnect(con)
#> Warning in connection_release(conn@ptr): There is a result object still in use.
#> The connection will be automatically released when it is closed Session infosessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#> setting value
#> version R version 4.3.2 (2023-10-31)
#> os macOS Sonoma 14.2.1
#> system aarch64, darwin20
#> ui X11
#> language (EN)
#> collate en_US.UTF-8
#> ctype en_US.UTF-8
#> tz Asia/Shanghai
#> date 2024-01-11
#> pandoc 3.1.1 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
#>
#> ─ Packages ───────────────────────────────────────────────────────────────────
#> package * version date (UTC) lib source
#> bit 4.0.5 2022-11-15 [1] CRAN (R 4.3.0)
#> bit64 4.0.5 2020-08-30 [1] CRAN (R 4.3.0)
#> blob 1.2.4 2023-03-17 [1] CRAN (R 4.3.0)
#> cli 3.6.2 2023-12-11 [1] CRAN (R 4.3.1)
#> config 0.3.2 2023-08-30 [1] CRAN (R 4.3.0)
#> DBI 1.2.0 2023-12-21 [1] CRAN (R 4.3.1)
#> digest 0.6.33 2023-07-07 [1] CRAN (R 4.3.0)
#> evaluate 0.23 2023-11-01 [1] CRAN (R 4.3.1)
#> fastmap 1.1.1 2023-02-24 [1] CRAN (R 4.3.0)
#> fs 1.6.3 2023-07-20 [1] CRAN (R 4.3.0)
#> glue 1.6.2 2022-02-24 [1] CRAN (R 4.3.0)
#> hms 1.1.3 2023-03-21 [1] CRAN (R 4.3.0)
#> htmltools 0.5.7 2023-11-03 [1] CRAN (R 4.3.1)
#> knitr 1.45 2023-10-30 [1] CRAN (R 4.3.1)
#> lifecycle 1.0.4 2023-11-07 [1] CRAN (R 4.3.1)
#> odbc 1.4.1 2023-12-21 [1] CRAN (R 4.3.1)
#> pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.3.0)
#> Rcpp 1.0.11 2023-07-06 [1] CRAN (R 4.3.0)
#> reprex 2.0.2 2022-08-17 [1] CRAN (R 4.3.0)
#> rlang 1.1.3 2024-01-10 [1] CRAN (R 4.3.1)
#> rmarkdown 2.25 2023-09-18 [1] CRAN (R 4.3.1)
#> rstudioapi 0.15.0 2023-07-07 [1] CRAN (R 4.3.0)
#> sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.3.0)
#> vctrs 0.6.5 2023-12-01 [1] CRAN (R 4.3.1)
#> withr 2.5.2 2023-10-30 [1] CRAN (R 4.3.1)
#> xfun 0.41 2023-11-01 [1] CRAN (R 4.3.1)
#> yaml 2.3.8 2023-12-11 [1] CRAN (R 4.3.1)
#>
#> [1] /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library
#>
#> ────────────────────────────────────────────────────────────────────────────── Here I'm getting a warning on disconnect. But if I check the version twice in a row I get the crash. |
Thanks for the extra info! Just tried out that |
I might have solved my problem. Before I was using the FreeTDS ODBC Driver from Homebrew ( Incidentally, I needed to faff around to get the MS driver to work. This StackOverflow answer had what I needed. |
Hmmm, if this is a problem with the freeTDS odbc driver we should take more of a look (and either fix or possibly just recommend against the freeTDS driver because I'm pretty sure we've seen other problems). @simonpcouch can you please see if you can reproduce with freeTDS? |
Ah, yup. I can reproduce. R 4.3.1, odbc 1.4.1, TDS 7.3, unixODBC, SQL Server 2022, aarch64 MacOS. To reproduce, work through the SQL Server setup instructions to boot up a SQL Server with Docker. (Replace the double quotes in In [FreeTDSSQLServer]
driver = FreeTDS Driver
Server = 127.0.0.1
port = 1433
Encrypt = no In [FreeTDS Driver]
Description=FreeTDS Driver for SQL server
Driver=/opt/homebrew/Cellar/freetds/1.4.10/lib/libtdsodbc.0.so Switch out the Driver directory with the one printed out in Then, in
In a fresh R session, the following crashes: library(odbc)
library(DBI)
con <- dbConnect(
odbc::odbc(),
dsn = "FreeTDSSQLServer",
uid = "SA",
pwd = "BoopBop123!"
)
dbWriteTable(con, "mtcars", mtcars, overwrite = TRUE)
dbGetQuery(con, "SELECT * FROM mtcars")
dbGetQuery(con, "SELECT * FROM mtcars") Standard output and error *** caught segfault ***
address 0x48000000013f9a39, cause 'invalid permissions'
Traceback:
1: new_result(p = connection@ptr, sql = statement, immediate = immediate)
2: OdbcResult(connection = conn, statement = statement, params = params, immediate = immediate)
3: .local(conn, statement, ...)
4: dbSendStatement(conn, statement, ...)
5: dbSendStatement(conn, statement, ...)
6: dbExecute(conn, sql, immediate = TRUE)
7: dbExecute(conn, sql, immediate = TRUE)
8: .local(conn, name, value, ...)
9: dbWriteTable(con, "mtcars", mtcars, overwrite = TRUE)
10: dbWriteTable(con, "mtcars", mtcars, overwrite = TRUE)
11: eval(expr, envir, enclos)
12: eval(expr, envir, enclos)
13: eval_with_user_handlers(expr, envir, enclos, user_handlers)
14: withVisible(eval_with_user_handlers(expr, envir, enclos, user_handlers))
15: withCallingHandlers(withVisible(eval_with_user_handlers(expr, envir, enclos, user_handlers)), warning = wHandler, error = eHandler, message = mHandler)
16: doTryCatch(return(expr), name, parentenv, handler)
17: tryCatchOne(expr, names, parentenv, handlers[[1L]])
18: tryCatchList(expr, classes, parentenv, handlers)
19: tryCatch(expr, error = function(e) { call <- conditionCall(e) if (!is.null(call)) { if (identical(call[[1L]], quote(doTryCatch))) call <- sys.call(-4L) dcall <- deparse(call, nlines = 1L) prefix <- paste("Error in", dcall, ": ") LONG <- 75L sm <- strsplit(conditionMessage(e), "\n")[[1L]] w <- 14L + nchar(dcall, type = "w") + nchar(sm[1L], type = "w") if (is.na(w)) w <- 14L + nchar(dcall, type = "b") + nchar(sm[1L], type = "b") if (w > LONG) prefix <- paste0(prefix, "\n ") } else prefix <- "Error : " msg <- paste0(prefix, conditionMessage(e), "\n") .Internal(seterrmessage(msg[1L])) if (!silent && isTRUE(getOption("show.error.messages"))) { cat(msg, file = outFile) .Internal(printDeferredWarnings()) } invisible(structure(msg, class = "try-error", condition = e))})
20: try(f, silent = TRUE)
21: handle(ev <- withCallingHandlers(withVisible(eval_with_user_handlers(expr, envir, enclos, user_handlers)), warning = wHandler, error = eHandler, message = mHandler))
22: timing_fn(handle(ev <- withCallingHandlers(withVisible(eval_with_user_handlers(expr, envir, enclos, user_handlers)), warning = wHandler, error = eHandler, message = mHandler)))
23: evaluate_call(expr, parsed$src[[i]], envir = envir, enclos = enclos, debug = debug, last = i == length(out), use_try = stop_on_error != 2L, keep_warning = keep_warning, keep_message = keep_message, log_echo = log_echo, log_warning = log_warning, output_handler = output_handler, include_timing = include_timing)
24: evaluate::evaluate(...)
25: evaluate(code, envir = env, new_device = FALSE, keep_warning = if (is.numeric(options$warning)) TRUE else options$warning, keep_message = if (is.numeric(options$message)) TRUE else options$message, stop_on_error = if (is.numeric(options$error)) options$error else { if (options$error && options$include) 0L else 2L }, output_handler = knit_handlers(options$render, options))
26: in_dir(input_dir(), expr)
27: in_input_dir(evaluate(code, envir = env, new_device = FALSE, keep_warning = if (is.numeric(options$warning)) TRUE else options$warning, keep_message = if (is.numeric(options$message)) TRUE else options$message, stop_on_error = if (is.numeric(options$error)) options$error else { if (options$error && options$include) 0L else 2L }, output_handler = knit_handlers(options$render, options)))
28: eng_r(options)
29: block_exec(params)
30: call_block(x)
31: process_group.block(group)
32: process_group(group)
33: withCallingHandlers(if (tangle) process_tangle(group) else process_group(group), error = function(e) if (xfun::pkg_available("rlang", "1.0.0")) rlang::entrace(e))
34: withCallingHandlers(expr, error = function(e) { loc = paste0(current_lines(), label, sprintf(" (%s)", knit_concord$get("infile"))) message(one_string(handler(e, loc)))})
35: handle_error(withCallingHandlers(if (tangle) process_tangle(group) else process_group(group), error = function(e) if (xfun::pkg_available("rlang", "1.0.0")) rlang::entrace(e)), function(e, loc) { setwd(wd) write_utf8(res, output %n% stdout()) paste0("\nQuitting from lines ", loc) }, if (labels[i] != "") sprintf(" [%s]", labels[i]))
36: process_file(text, output)
37: knitr::knit(knit_input, knit_output, envir = envir, quiet = quiet)
38: rmarkdown::render(input, quiet = TRUE, envir = globalenv(), encoding = "UTF-8")
39: (function (input) { rmarkdown::render(input, quiet = TRUE, envir = globalenv(), encoding = "UTF-8")})(input = base::quote("fine-bluet_reprex.R"))
40: (function (what, args, quote = FALSE, envir = parent.frame()) { if (!is.list(args)) stop("second argument must be a list") if (quote) args <- lapply(args, enquote) .Internal(do.call(what, args, envir))})(base::quote(function (input) { rmarkdown::render(input, quiet = TRUE, envir = globalenv(), encoding = "UTF-8")}), base::quote(list(input = "fine-bluet_reprex.R")), envir = base::quote(<environment>), quote = base::quote(TRUE))
41: do.call(do.call, c(readRDS("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-fun-cf59259313c1"), list(envir = .GlobalEnv, quote = TRUE)), envir = .GlobalEnv, quote = TRUE)
42: saveRDS(do.call(do.call, c(readRDS("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-fun-cf59259313c1"), list(envir = .GlobalEnv, quote = TRUE)), envir = .GlobalEnv, quote = TRUE), file = "/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-res-cf595af5f72c", compress = FALSE)
43: withCallingHandlers({ NULL saveRDS(do.call(do.call, c(readRDS("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-fun-cf59259313c1"), list(envir = .GlobalEnv, quote = TRUE)), envir = .GlobalEnv, quote = TRUE), file = "/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-res-cf595af5f72c", compress = FALSE) flush(stdout()) flush(stderr()) NULL invisible()}, error = function(e) { { callr_data <- as.environment("tools:callr")$`__callr_data__` err <- callr_data$err if (FALSE) { assign(".Traceback", .traceback(4), envir = callr_data) dump.frames("__callr_dump__") assign(".Last.dump", .GlobalEnv$`__callr_dump__`, envir = callr_data) rm("__callr_dump__", envir = .GlobalEnv) } e <- err$process_call(e) e2 <- err$new_error("error in callr subprocess") class(e2) <- c("callr_remote_error", class(e2)) e2 <- err$add_trace_back(e2) cut <- which(e2$trace$scope == "global")[1] if (!is.na(cut)) { e2$trace <- e2$trace[-(1:cut), ] } saveRDS(list("error", e2, e), file = paste0("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-res-cf595af5f72c", ".error")) }}, interrupt = function(e) { { callr_data <- as.environment("tools:callr")$`__callr_data__` err <- callr_data$err if (FALSE) { assign(".Traceback", .traceback(4), envir = callr_data) dump.frames("__callr_dump__") assign(".Last.dump", .GlobalEnv$`__callr_dump__`, envir = callr_data) rm("__callr_dump__", envir = .GlobalEnv) } e <- err$process_call(e) e2 <- err$new_error("error in callr subprocess") class(e2) <- c("callr_remote_error", class(e2)) e2 <- err$add_trace_back(e2) cut <- which(e2$trace$scope == "global")[1] if (!is.na(cut)) { e2$trace <- e2$trace[-(1:cut), ] } saveRDS(list("error", e2, e), file = paste0("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-res-cf595af5f72c", ".error")) }}, callr_message = function(e) { try(signalCondition(e))})
44: doTryCatch(return(expr), name, parentenv, handler)
45: tryCatchOne(expr, names, parentenv, handlers[[1L]])
46: tryCatchList(expr, names[-nh], parentenv, handlers[-nh])
47: doTryCatch(return(expr), name, parentenv, handler)
48: tryCatchOne(tryCatchList(expr, names[-nh], parentenv, handlers[-nh]), names[nh], parentenv, handlers[[nh]])
49: tryCatchList(expr, classes, parentenv, handlers)
50: tryCatch(withCallingHandlers({ NULL saveRDS(do.call(do.call, c(readRDS("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-fun-cf59259313c1"), list(envir = .GlobalEnv, quote = TRUE)), envir = .GlobalEnv, quote = TRUE), file = "/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-res-cf595af5f72c", compress = FALSE) flush(stdout()) flush(stderr()) NULL invisible()}, error = function(e) { { callr_data <- as.environment("tools:callr")$`__callr_data__` err <- callr_data$err if (FALSE) { assign(".Traceback", .traceback(4), envir = callr_data) dump.frames("__callr_dump__") assign(".Last.dump", .GlobalEnv$`__callr_dump__`, envir = callr_data) rm("__callr_dump__", envir = .GlobalEnv) } e <- err$process_call(e) e2 <- err$new_error("error in callr subprocess") class(e2) <- c("callr_remote_error", class(e2)) e2 <- err$add_trace_back(e2) cut <- which(e2$trace$scope == "global")[1] if (!is.na(cut)) { e2$trace <- e2$trace[-(1:cut), ] } saveRDS(list("error", e2, e), file = paste0("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-res-cf595af5f72c", ".error")) }}, interrupt = function(e) { { callr_data <- as.environment("tools:callr")$`__callr_data__` err <- callr_data$err if (FALSE) { assign(".Traceback", .traceback(4), envir = callr_data) dump.frames("__callr_dump__") assign(".Last.dump", .GlobalEnv$`__callr_dump__`, envir = callr_data) rm("__callr_dump__", envir = .GlobalEnv) } e <- err$process_call(e) e2 <- err$new_error("error in callr subprocess") class(e2) <- c("callr_remote_error", class(e2)) e2 <- err$add_trace_back(e2) cut <- which(e2$trace$scope == "global")[1] if (!is.na(cut)) { e2$trace <- e2$trace[-(1:cut), ] } saveRDS(list("error", e2, e), file = paste0("/var/folders/6c/w21prsj167b_x82q4_s45t340000gn/T//RtmpBN3ISF/callr-res-cf595af5f72c", ".error")) }}, callr_message = function(e) { try(signalCondition(e))}), error = function(e) { NULL if (TRUE) { try(stop(e)) } else { invisible() }}, interrupt = function(e) { NULL if (TRUE) { e } else { invisible() }})
An irrecoverable exception occurred. R is aborting now ... |
I can confirm that I was using the FreeTDS ODBC driver and after switching to the Microsoft ODBC Driver 18, the problem went away. Is this an issue of the FreeTDS driver then or the compatibility with it? |
@tgreger it will take us some time to figure that out, but I suspect that given this code works with all the other drivers we use, it's the FreeTDS at fault. If that's indeed the case, I think the best resolution will be to detect usage of the driver and suggest that the user switches to the MS version. |
Issue Description and Expected Result
Multiple
dbGetQuery
calls leads to segfault on macOS. I usedgit bisect
and found the problem was introduced in commit 5b36b47.Database
SQL Server 2016
Reproducible Example
Disconnecting after running a simple query will result in the following warning:
Session Info
The text was updated successfully, but these errors were encountered: