Skip to content

Commit 38a39a5

Browse files
zacdav-dbZac Davies
andauthored
Add DBI show_progress connection default (#223)
Co-authored-by: Zac Davies <zachary.davies+data@databricks.com>
1 parent 7ff5ec3 commit 38a39a5

16 files changed

Lines changed: 253 additions & 65 deletions

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# brickster 0.2.13
22

33
- Enabled `db_request()` retries for transient low-level HTTP request failures, improving resilience to intermittent curl/HTTP2 framing errors (#215)
4+
- Added `show_progress` to `dbConnect()` for the DBI backend; `dbGetQuery()`, `dbFetch()`, `dbWriteTable()`, and dbplyr `collect()` now use the connection default while preserving per-call `show_progress` overrides
45
- Added a DBI connection-level `disposition` setting so `dbSendQuery()` and default `dbGetQuery()` calls can use `INLINE` results when direct cloud-storage downloads are blocked (#205)
56
- Added Azure AD service principal OAuth M2M support (`ARM_CLIENT_ID`, `ARM_CLIENT_SECRET`, `ARM_TENANT_ID`) with optional `DATABRICKS_AUTH_TYPE` override (`oauth-m2m`, `azure-client-secret`, `oauth-u2m`); default auth resolution now prefers Azure M2M over U2M when ARM credentials are present (#185)
67
- Marked DBFS REST wrappers (`db_dbfs_*`) as deprecated and moved them to internal-only, guiding users towards using volumes (`db_volume_*`)

R/databricks-dbi.R

Lines changed: 70 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ setClass(
3030
staging_volume = "character",
3131
disposition = "character",
3232
max_active_connections = "numeric",
33-
fetch_timeout = "numeric"
34-
)
33+
fetch_timeout = "numeric",
34+
show_progress = "logical"
35+
),
36+
prototype = list(show_progress = TRUE)
3537
)
3638

3739
#' DBI Result for Databricks
@@ -91,6 +93,8 @@ setMethod("show", "DatabricksDriver", function(object) {
9193
#' connections when fetching query results (default: 30)
9294
#' @param fetch_timeout Timeout in seconds for downloading each result chunk
9395
#' (default: 300)
96+
#' @param show_progress If `TRUE`, show progress updates by default for DBI
97+
#' queries, dbplyr collection, and table writes (default: `TRUE`)
9498
#' @param token Authentication token (defaults to db_token())
9599
#' @param host Databricks workspace host (defaults to db_host())
96100
#' @param ... Additional arguments (ignored)
@@ -109,6 +113,7 @@ setMethod(
109113
disposition = c("EXTERNAL_LINKS", "INLINE"),
110114
max_active_connections = 30,
111115
fetch_timeout = 300,
116+
show_progress = TRUE,
112117
token = db_token(),
113118
host = db_host(),
114119
...
@@ -143,6 +148,8 @@ setMethod(
143148
cli::cli_abort("{.arg fetch_timeout} must be a positive numeric value")
144149
}
145150

151+
db_assert_show_progress(show_progress)
152+
146153
# Validate connection by testing a simple query
147154
tryCatch(
148155
{
@@ -177,7 +184,8 @@ setMethod(
177184
staging_volume = staging_volume %||% "",
178185
disposition = disposition,
179186
max_active_connections = max_active_connections,
180-
fetch_timeout = fetch_timeout
187+
fetch_timeout = fetch_timeout,
188+
show_progress = show_progress
181189
)
182190

183191
dbi_connection_opened(con)
@@ -229,6 +237,7 @@ setMethod("show", "DatabricksConnection", function(object) {
229237
cat(" Disposition:", object@disposition, "\n")
230238
cat(" Max Active Connections:", object@max_active_connections, "\n")
231239
cat(" Fetch Timeout (s):", object@fetch_timeout, "\n")
240+
cat(" Show Progress:", object@show_progress, "\n")
232241
})
233242

234243
# Query Methods ----------------------------------------------------------------
@@ -279,7 +288,8 @@ setMethod(
279288
#' @param statement SQL statement to execute
280289
#' @param disposition Query disposition mode. Defaults to the connection's
281290
#' `disposition` setting.
282-
#' @param show_progress If `TRUE`, show progress updates during query execution (default: `TRUE`)
291+
#' @param show_progress If `TRUE`, show progress updates during query execution.
292+
#' Defaults to the connection's `show_progress` setting.
283293
#' @param ... Additional arguments passed to underlying query execution
284294
#' @returns A data.frame with query results
285295
#' @export
@@ -290,10 +300,11 @@ setMethod(
290300
conn,
291301
statement,
292302
disposition = conn@disposition,
293-
show_progress = TRUE,
303+
show_progress = conn@show_progress,
294304
...
295305
) {
296306
disposition <- match.arg(disposition, c("EXTERNAL_LINKS", "INLINE"))
307+
db_assert_show_progress(show_progress)
297308

298309
# Detect schema discovery queries (LIMIT 0) and optimize them
299310
if (endsWith(trimws(statement), "LIMIT 0")) {
@@ -401,10 +412,19 @@ setMethod(
401412
#' Fetch results from Databricks query
402413
#' @param res A DatabricksResult object
403414
#' @param n Maximum number of rows to fetch (-1 for all rows)
415+
#' @param show_progress If `TRUE`, show progress updates during result fetching.
416+
#' Defaults to the connection's `show_progress` setting.
404417
#' @param ... Additional arguments (ignored)
405418
#' @returns A data.frame with query results
406419
#' @export
407-
setMethod("dbFetch", "DatabricksResult", function(res, n = -1, ...) {
420+
setMethod("dbFetch", "DatabricksResult", function(
421+
res,
422+
n = -1,
423+
show_progress = res@connection@show_progress,
424+
...
425+
) {
426+
db_assert_show_progress(show_progress)
427+
408428
if (res@completed) {
409429
# Return empty data frame if already completed
410430
return(data.frame())
@@ -417,7 +437,9 @@ setMethod("dbFetch", "DatabricksResult", function(res, n = -1, ...) {
417437
token = res@connection@token
418438
)
419439
if (initial_status$status$state %in% c("RUNNING", "PENDING")) {
420-
cli::cli_progress_step("Executing query")
440+
if (show_progress) {
441+
cli::cli_progress_step("Executing query")
442+
}
421443
status <- db_sql_exec_poll_for_success(
422444
res@statement_id,
423445
show_progress = FALSE,
@@ -452,7 +474,7 @@ setMethod("dbFetch", "DatabricksResult", function(res, n = -1, ...) {
452474
row_limit = if (n > 0) n else NULL,
453475
host = res@connection@host,
454476
token = res@connection@token,
455-
show_progress = TRUE
477+
show_progress = show_progress
456478
)
457479
}
458480

@@ -899,7 +921,8 @@ setMethod("dbGetInfo", "DatabricksConnection", function(dbObj, ...) {
899921
host = dbObj@host,
900922
port = NA_integer_,
901923
warehouse_id = dbObj@warehouse_id,
902-
disposition = dbObj@disposition
924+
disposition = dbObj@disposition,
925+
show_progress = dbObj@show_progress
903926
)
904927
})
905928

@@ -1010,6 +1033,18 @@ db_assert_statement <- function(statement) {
10101033
}
10111034
}
10121035

1036+
#' Assert that a progress flag is valid
1037+
#' @keywords internal
1038+
db_assert_show_progress <- function(show_progress) {
1039+
if (
1040+
!is.logical(show_progress) ||
1041+
length(show_progress) != 1L ||
1042+
is.na(show_progress)
1043+
) {
1044+
cli::cli_abort("{.arg show_progress} must be `TRUE` or `FALSE`.")
1045+
}
1046+
}
1047+
10131048
#' Extract warehouse ID from an http_path
10141049
#' @keywords internal
10151050
warehouse_id_from_http_path <- function(http_path) {
@@ -1164,7 +1199,8 @@ setMethod(
11641199
#' @param temporary If `TRUE`, create temporary table (NOT SUPPORTED - will error)
11651200
#' @param field.types Named character vector of SQL types for columns
11661201
#' @param staging_volume Optional volume path for large dataset staging
1167-
#' @param show_progress If `TRUE`, show progress bar for file uploads (default: `TRUE`)
1202+
#' @param show_progress If `TRUE`, show progress updates while writing.
1203+
#' Defaults to the connection's `show_progress` setting.
11681204
#' @param ... Additional arguments.
11691205
#' @returns `TRUE` invisibly on success
11701206
#' @export
@@ -1181,16 +1217,14 @@ setMethod(
11811217
temporary = FALSE,
11821218
field.types = NULL,
11831219
staging_volume = NULL,
1184-
show_progress = TRUE,
1220+
show_progress = conn@show_progress,
11851221
...
11861222
) {
11871223
dots <- list(...)
11881224
if ("progress" %in% names(dots)) {
11891225
cli::cli_abort("Argument {.arg progress} is not supported; use {.arg show_progress}.")
11901226
}
1191-
if (!is.logical(show_progress) || length(show_progress) != 1L || is.na(show_progress)) {
1192-
cli::cli_abort("{.arg show_progress} must be `TRUE` or `FALSE`.")
1193-
}
1227+
db_assert_show_progress(show_progress)
11941228

11951229
# Validate inputs
11961230
if (overwrite && append) {
@@ -1268,7 +1302,8 @@ setMethod(
12681302
overwrite,
12691303
append,
12701304
field.types,
1271-
temporary
1305+
temporary,
1306+
show_progress = show_progress
12721307
)
12731308
}
12741309

@@ -1286,7 +1321,8 @@ setMethod(
12861321
#' @param temporary If `TRUE`, create temporary table (NOT SUPPORTED - will error)
12871322
#' @param field.types Named character vector of SQL types for columns
12881323
#' @param staging_volume Optional volume path for large dataset staging
1289-
#' @param show_progress If `TRUE`, show progress bar for file uploads (default: `TRUE`)
1324+
#' @param show_progress If `TRUE`, show progress updates while writing.
1325+
#' Defaults to the connection's `show_progress` setting.
12901326
#' @param ... Additional arguments.
12911327
#' @returns `TRUE` invisibly on success
12921328
#' @export
@@ -1303,16 +1339,14 @@ setMethod(
13031339
temporary = FALSE,
13041340
field.types = NULL,
13051341
staging_volume = NULL,
1306-
show_progress = TRUE,
1342+
show_progress = conn@show_progress,
13071343
...
13081344
) {
13091345
dots <- list(...)
13101346
if ("progress" %in% names(dots)) {
13111347
cli::cli_abort("Argument {.arg progress} is not supported; use {.arg show_progress}.")
13121348
}
1313-
if (!is.logical(show_progress) || length(show_progress) != 1L || is.na(show_progress)) {
1314-
cli::cli_abort("{.arg show_progress} must be `TRUE` or `FALSE`.")
1315-
}
1349+
db_assert_show_progress(show_progress)
13161350

13171351
# Handle Id object by implementing the logic directly instead of delegating
13181352
# This avoids double-quoting issues
@@ -1395,7 +1429,8 @@ setMethod(
13951429
overwrite,
13961430
append,
13971431
field.types,
1398-
temporary
1432+
temporary,
1433+
show_progress = show_progress
13991434
)
14001435
}
14011436

@@ -1413,7 +1448,8 @@ setMethod(
14131448
#' @param temporary If `TRUE`, create temporary table (NOT SUPPORTED - will error)
14141449
#' @param field.types Named character vector of SQL types for columns
14151450
#' @param staging_volume Optional volume path for large dataset staging
1416-
#' @param show_progress If `TRUE`, show progress bar for file uploads (default: `TRUE`)
1451+
#' @param show_progress If `TRUE`, show progress updates while writing.
1452+
#' Defaults to the connection's `show_progress` setting.
14171453
#' @param ... Additional arguments.
14181454
#' @returns `TRUE` invisibly on success
14191455
#' @export
@@ -1430,7 +1466,7 @@ setMethod(
14301466
temporary = FALSE,
14311467
field.types = NULL,
14321468
staging_volume = NULL,
1433-
show_progress = TRUE,
1469+
show_progress = conn@show_progress,
14341470
...
14351471
) {
14361472
# Convert AsIs to character and delegate to character method
@@ -1460,7 +1496,8 @@ db_write_table_standard <- function(
14601496
overwrite,
14611497
append,
14621498
field.types,
1463-
temporary = FALSE
1499+
temporary = FALSE,
1500+
show_progress = TRUE
14641501
) {
14651502
if (temporary) {
14661503
cli::cli_abort(
@@ -1469,9 +1506,11 @@ db_write_table_standard <- function(
14691506
}
14701507

14711508
# Show progress for table creation
1472-
cli::cli_progress_step(
1473-
if (append) "Appending data to table" else "Creating table"
1474-
)
1509+
if (show_progress) {
1510+
cli::cli_progress_step(
1511+
if (append) "Appending data to table" else "Creating table"
1512+
)
1513+
}
14751514

14761515
if (append) {
14771516
# For append, use atomic INSERT INTO with SELECT VALUES
@@ -1490,7 +1529,9 @@ db_write_table_standard <- function(
14901529
)
14911530
}
14921531

1493-
cli::cli_progress_done()
1532+
if (show_progress) {
1533+
cli::cli_progress_done()
1534+
}
14941535
}
14951536

14961537
#' Create table from data frame structure
@@ -1706,9 +1747,7 @@ db_write_table_volume <- function(
17061747
append = FALSE,
17071748
show_progress = TRUE
17081749
) {
1709-
if (!is.logical(show_progress) || length(show_progress) != 1L || is.na(show_progress)) {
1710-
cli::cli_abort("{.arg show_progress} must be `TRUE` or `FALSE`.")
1711-
}
1750+
db_assert_show_progress(show_progress)
17121751

17131752
# Validate volume path
17141753
staging_volume <- is_valid_volume_path(staging_volume)

R/databricks-dbplyr.R

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,13 +542,24 @@ spark_sql_translation <- function(con) {
542542
#' @param sql SQL query to execute
543543
#' @param n Maximum number of rows to collect (-1 for all)
544544
#' @param warn_incomplete Whether to warn if results were truncated
545+
#' @param show_progress If `TRUE`, show progress updates during collection.
546+
#' Defaults to the connection's `show_progress` setting.
545547
#' @param ... Additional arguments
546548
#' @returns A data frame with query results
547549
#' @export
548550
#' @method db_collect DatabricksConnection
549-
db_collect.DatabricksConnection <- function(con, sql, n = -1, warn_incomplete = TRUE, ...) {
551+
db_collect.DatabricksConnection <- function(
552+
con,
553+
sql,
554+
n = -1,
555+
warn_incomplete = TRUE,
556+
show_progress = con@show_progress,
557+
...
558+
) {
559+
db_assert_show_progress(show_progress)
560+
550561
# Use dbGetQuery which already has proper progress handling
551-
out <- dbGetQuery(con, sql, show_progress = TRUE)
562+
out <- dbGetQuery(con, sql, show_progress = show_progress)
552563

553564
# Apply row limit if specified
554565
if (n > 0 && nrow(out) > n) {

R/sql-query-execution.R

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,9 @@ db_sql_fetch_results_fast <- function(
568568
results <- tibble::as_tibble(nanoarrow::read_nanoarrow(ipc_resp$body))
569569
}
570570

571-
cli::cli_progress_done()
571+
if (show_progress) {
572+
cli::cli_progress_done()
573+
}
572574

573575
if (!is.null(row_limit) && row_limit > 0 && nrow(results) > row_limit) {
574576
results <- results[1:row_limit, ]
@@ -632,12 +634,16 @@ db_sql_fetch_results_parallel <- function(
632634
ipc_data <- httr2::req_perform_parallel(
633635
links,
634636
max_active = max_active_connections,
635-
progress = list(
636-
clear = TRUE,
637-
format = "Downloading {cli::pb_bar} {cli::pb_percent} [{cli::pb_elapsed}]",
638-
format_failed = "Download failed [{cli::pb_elapsed}]",
639-
type = "iterator"
640-
)
637+
progress = if (show_progress) {
638+
list(
639+
clear = TRUE,
640+
format = "Downloading {cli::pb_bar} {cli::pb_percent} [{cli::pb_elapsed}]",
641+
format_failed = "Download failed [{cli::pb_elapsed}]",
642+
type = "iterator"
643+
)
644+
} else {
645+
FALSE
646+
}
641647
)
642648

643649
if (show_progress) {
@@ -665,7 +671,9 @@ db_sql_fetch_results_parallel <- function(
665671
) |>
666672
purrr::list_rbind()
667673
}
668-
cli::cli_progress_done()
674+
if (show_progress) {
675+
cli::cli_progress_done()
676+
}
669677

670678
# Apply row limit if specified
671679
if (!is.null(row_limit) && row_limit > 0 && nrow(results) > row_limit) {

man/dbConnect-DatabricksDriver-method.Rd

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)