diff --git a/.aviator/config.yml b/.aviator/config.yml index 283f4f6dc..968c74b0c 100644 --- a/.aviator/config.yml +++ b/.aviator/config.yml @@ -27,7 +27,7 @@ merge_rules: type: default auto_update: enabled: true - label: '' + label: 'mergequeue' max_runs_for_update: 0 merge_commit: use_title_and_body: false diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 921c120d5..7ad1cd6d9 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -51,7 +51,7 @@ jobs: install-r: false cache-version: rcc-smoke-2 needs: check - extra-packages: any::rcmdcheck any::roxygen2 r-lib/styler + extra-packages: any::rcmdcheck krlmlr/roxygen2 r-lib/styler - uses: ./.github/workflows/custom/after-install if: hashFiles('.github/workflows/custom/after-install/action.yml') != '' diff --git a/.github/workflows/backends.yaml b/.github/workflows/backends.yaml index 9045eb891..c5383847c 100644 --- a/.github/workflows/backends.yaml +++ b/.github/workflows/backends.yaml @@ -49,6 +49,7 @@ jobs: backend: needs: matrix + # Need Ubuntu 20.04 for remotes::system_requirements() runs-on: ubuntu-20.04 strategy: @@ -70,35 +71,21 @@ jobs: - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v2 - - - name: Install remotes - run: | - if (!requireNamespace("curl", quietly = TRUE)) install.packages("curl") - if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") - shell: Rscript {0} + - uses: ./.github/workflows/install + with: + install-r: false + cache-version: backends-${{ matrix.package }} + needs: check + extra-packages: "any::pkgbuild any::remotes decor ." + token: ${{ secrets.GITHUB_TOKEN }} - name: Clone backend run: | make -C revdep-dev ${{ matrix.package }} - - name: Prepare cache keys - if: runner.os != 'Windows' - run: | - saveRDS(remotes::dev_package_deps("revdep-dev/${{ matrix.package }}", dependencies = TRUE, type = .Platform$pkgType), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Cache R packages - if: runner.os != 'Windows' - uses: actions/cache@v3 - with: - path: ${{ env.R_LIBS_USER }} - key: backends-${{ hashFiles('.github/R-version') }}-2-${{ hashFiles('.github/depends.Rds') }} - restore-keys: backends-${{ hashFiles('.github/R-version') }}-2- - - name: Install system dependencies if: runner.os == 'Linux' + # "22.04" fails here run: | while read -r cmd do @@ -109,7 +96,6 @@ jobs: run: | remotes::install_local("revdep-dev/${{ matrix.package }}", dependencies = TRUE, type = .Platform$pkgType) remotes::install_local(".", type = .Platform$pkgType, force = TRUE) - remotes::install_cran("pkgbuild") shell: Rscript {0} - name: Session info diff --git a/.github/workflows/odbc.yaml b/.github/workflows/odbc.yaml index 7f2d8da31..d3e9b14ea 100644 --- a/.github/workflows/odbc.yaml +++ b/.github/workflows/odbc.yaml @@ -15,7 +15,7 @@ name: backends odbc jobs: matrix: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -90,33 +90,18 @@ jobs: - uses: actions/checkout@v3 - - uses: r-lib/actions/setup-r@v2 - - - name: Install remotes - run: | - if (!requireNamespace("curl", quietly = TRUE)) install.packages("curl") - if (!requireNamespace("remotes", quietly = TRUE)) install.packages("remotes") - shell: Rscript {0} + - uses: ./.github/workflows/install + with: + install-r: false + cache-version: backends-${{ matrix.package }} + needs: check + extra-packages: "any::pkgbuild any::remotes decor ." + token: ${{ secrets.GITHUB_TOKEN }} - name: Clone backend run: | make -C revdep-dev ${{ matrix.package }} - - name: Prepare cache keys - if: runner.os != 'Windows' - run: | - saveRDS(remotes::dev_package_deps("revdep-dev/${{ matrix.package }}", dependencies = TRUE, type = .Platform$pkgType), ".github/depends.Rds", version = 2) - writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") - shell: Rscript {0} - - - name: Cache R packages - if: runner.os != 'Windows' - uses: actions/cache@v3 - with: - path: ${{ env.R_LIBS_USER }} - key: backends-${{ hashFiles('.github/R-version') }}-2-${{ hashFiles('.github/depends.Rds') }} - restore-keys: backends-${{ hashFiles('.github/R-version') }}-2- - - name: Install system dependencies if: runner.os == 'Linux' # "22.04" fails here @@ -130,7 +115,6 @@ jobs: run: | remotes::install_local("revdep-dev/${{ matrix.package }}", dependencies = TRUE, type = .Platform$pkgType) remotes::install_local(".", type = .Platform$pkgType, force = TRUE) - remotes::install_cran("pkgbuild") shell: Rscript {0} - name: Session info diff --git a/DESCRIPTION b/DESCRIPTION index 7e9329e1c..33537fc7f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: DBItest Title: Testing DBI Backends -Version: 1.7.3.9014 -Date: 2023-12-18 +Version: 1.8.0.9009 +Date: 2024-01-23 Authors@R: c( person("Kirill", "Müller", , "kirill@cynkra.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-1416-3412")), @@ -18,7 +18,7 @@ Depends: Imports: blob (>= 1.2.0), callr, - DBI (>= 1.1.3.9004), + DBI (>= 1.2.1), desc, hms (>= 0.5.0), lubridate, @@ -29,12 +29,10 @@ Imports: rlang (>= 0.2.0), testthat (>= 2.0.0), utils, - vctrs, withr Suggests: clipr, constructive, - dblog (>= 0.0.0.9008), debugme, devtools, dplyr, @@ -46,16 +44,18 @@ Suggests: VignetteBuilder: knitr Remotes: - r-dbi/DBI -Additional_repositories: https://r-dbi.r-universe.dev + r-dbi/DBI, + r-dbi/RSQLite +Config/Needs/website: + r-dbi/dbitemplate Config/autostyle/scope: line_breaks Config/autostyle/strict: false -Config/gha/extra-packages: r-dbi/dblog Config/testthat/edition: 3 +Config/Needs/check: decor Encoding: UTF-8 KeepSource: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.0.9000 Collate: 'DBItest.R' 'compat-purrr.R' diff --git a/NAMESPACE b/NAMESPACE index d975f4860..7072713db 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -20,7 +20,8 @@ export(test_stress) export(test_transaction) export(tweaks) import(DBI) -import(testthat) +import(rlang) +import(testthat, except = c(is_null, is_false, is_true)) importFrom(callr,r) importFrom(lubridate,with_tz) importFrom(magrittr,"%>%") @@ -31,36 +32,6 @@ importFrom(methods,getClasses) importFrom(methods,hasMethod) importFrom(methods,is) importFrom(methods,new) -importFrom(rlang,"%||%") -importFrom(rlang,":=") -importFrom(rlang,abort) -importFrom(rlang,arg_match) -importFrom(rlang,as_function) -importFrom(rlang,call2) -importFrom(rlang,caller_env) -importFrom(rlang,check_dots_empty) -importFrom(rlang,enexpr) -importFrom(rlang,enquo) -importFrom(rlang,enquos) -importFrom(rlang,eval_tidy) -importFrom(rlang,exec) -importFrom(rlang,expr) -importFrom(rlang,global_env) -importFrom(rlang,has_length) -importFrom(rlang,is_installed) -importFrom(rlang,is_interactive) -importFrom(rlang,is_logical) -importFrom(rlang,is_missing) -importFrom(rlang,list2) -importFrom(rlang,local_options) -importFrom(rlang,new_function) -importFrom(rlang,pairlist2) -importFrom(rlang,parse_expr) -importFrom(rlang,quo) -importFrom(rlang,quo_get_expr) -importFrom(rlang,quo_is_null) -importFrom(rlang,seq2) -importFrom(rlang,set_names) importFrom(stats,setNames) importFrom(utils,head) importFrom(withr,with_output_sink) diff --git a/NEWS.md b/NEWS.md index 227269355..7a6c8e534 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,206 +1,176 @@ -# DBItest 1.7.3.9014 (2023-12-18) +# DBItest 1.8.0.9009 (2024-01-23) -## Features - -- Specify `dbFetchChunk()` (#331). - -- Inline all tests for `dbBind()` (#326). - -## Chore +## Documentation -- Remove rlang qualification (#332). +- Use dbitemplate (@maelle, #360). -- Remove double `as.data.frame()` (#330). -- Test for `dbBindArrow()` (#328). +# DBItest 1.8.0.9008 (2024-01-21) -- Work around constructive problem (#327). +## Chore -- Inlining (#325). +- Bump DBI dependency to fix tests (#359). -- Inlining (#324). -- Towards inlining bind tests (#323). +# DBItest 1.8.0.9007 (2024-01-15) +## Chore -# DBItest 1.7.3.9013 (2023-12-17) +- Add comments to generated code (#358). -## Bug fixes -- Fix two binding tests (#321). +# DBItest 1.8.0.9006 (2024-01-12) ## Features -- Require support for `dbFetch(n = NA)` (#296, #316). +- Fix specification for Arrow tests (#357). -- New `allow_na_rows_affected` tweak to support `NA` values returned from `dbGetRowsAffected()` (#297, #312). - -- Add adbi to check matrix (#314). +- Show DBItest function in backtrace (#349, #354). ## Chore -- Towards generating expressions for bind checks (#320). - -- Avoid R6 for testing `dbBind()` (#319). +- Prefer `map_*()` over `vapply()` (#356). -- Consistent use of `skip_if_not_dbitest()` (#317). +- Make test names unique, with a numeric suffix (#355). -- Disable Arrow skips (#303). +- Align with RSQLite (#351). -- Slightly better code generated for `tweaks()` (#313). - -## Testing +- Document sources for autogenerated files (#353). -- Run DBItest for SQLite as part of the checks here (#318). - -- Enable remaining Arrow tests (#307). - -## Uncategorized - -- Merge pull request #315 from r-dbi/b-odbc. +## Documentation - Fix compatibility with odbc +- Mention `dbBindArrow()` in documentation (#350). -# DBItest 1.7.3.9012 (2023-11-22) +# DBItest 1.8.0.9005 (2023-12-27) ## Chore -- No longer need `as.data.frame()` twice for Arrow (#302). - -- Breadcrumbs (#305). +- Replace unconditional skip with versioned skip (#347). -- Align paths to duckdb in `Makefile` (#306). -- Modernize `sql_union()` (#304). - -- Add new `dbFetchArrowChunk()` generic (#301). +# DBItest 1.8.0.9004 (2023-12-26) +## Features -# DBItest 1.7.3.9011 (2023-11-09) +- Specify `value` argument for `dbCreateTable()` and `dbCreateTableArrow()` (#345). ## Chore -- Add Aviator configuration. +- Consistent use of `skip_if_not_dbitest()` (#346). -## Documentation +- Stabilize test. -- Avoid error if RSQLite is not installed. - -## Testing +## Documentation -- Fix checks without suggested packages (#300). +- Minor specification fixes (#344). -# DBItest 1.7.3.9010 (2023-10-30) +# DBItest 1.8.0.9003 (2023-12-25) -## Bug fixes +## Features -- Typo. +- Relax `dbListObjects()` spec (#339, #341). ## Chore -- Adapt to changed duckdb directory. - - -# DBItest 1.7.3.9009 (2023-10-09) - -## Bug fixes - -- Skip test if dplyr is not installed. +- Enable two tests for `dbGetQueryArrow()` (#342). +- Add Aviator configuration. -# DBItest 1.7.3.9008 (2023-09-25) +- Install decor. -## Chore +## Continuous integration -- Simplify workflow. +- Avoid RMariaDB for now, #343. +- Install decor from CRAN. -# DBItest 1.7.3.9007 (2023-09-01) +- Omit more checks, #343. -## Features +- Modernize backends checks. -- Switch to nanoarrow (#291). -## Chore +# DBItest 1.8.0.9002 (2023-12-21) -- Fix CI/CD (#295). +- Merge branch 'cran-1.8.0'. -# DBItest 1.7.3.9006 (2023-08-30) +# DBItest 1.8.0.9001 (2023-12-21) -## Chore +- Merge branch 'cran-1.8.0'. -- Try fixing odbc workflows. -- Bump dependencies in GitHub actions. +# DBItest 1.8.0.9000 (2023-12-21) +- Merge branch 'cran-1.8.0'. -# DBItest 1.7.3.9005 (2023-03-24) -- Internal changes only. +# DBItest 1.8.0 (2023-12-21) +## Bug fixes -# DBItest 1.7.3.9004 (2023-03-21) +- Fix `create_roundtrip_keywords` and `create_roundtrip_quotes` tests (#283). -- Internal changes only. +## Features +- Relax specification of `dbUnquoteIdentifier()`, character vectors are now allowed too. -# DBItest 1.7.3.9003 (2022-12-30) +- Specify `dbFetchChunk()` (#331), `dbFetchArrowChunk()` (#301) and `dbBindArrow()` (#328). -- Internal changes only. +- Inline all tests for `dbBind()` (#326). +- Require support for `dbFetch(n = NA)` (#296, #316). -# DBItest 1.7.3.9002 (2022-12-26) +- New `allow_na_rows_affected` tweak to support `NA` values returned from `dbGetRowsAffected()` (#297, #312). -## Features +- Switch to nanoarrow (#291). - Basic tests for the new `db*Arrow()` interface (#287). +- New `skip_if_not_dbitest()` (#289). -# DBItest 1.7.3.9001 (2022-12-24) +- `reexport` test uses interface for dev DBI if the backend is compatible with DBItest \> 1.7.3. -## Bug fixes +- Slightly better code generated for `tweaks()` (#313). -- Fix `create_roundtrip_keywords` and `create_roundtrip_quotes` tests (#283). +- Remove interface to dblog in the CRAN version. -## Features +## CI/CD -- New `skip_if_not_dbitest()` (#289). +- Add adbi to check matrix (#314). - Reenable ODBC MySQL tests (#288). -- Tweak read_table_missing test (#285). - -- `reexport` test uses interface for dev DBI if the backend is compatible with DBItest > 1.7.3. - -This reverts commit bbb444486d0b663a89e66dd61c8b5a97c8e18651. +- Tweak `read_table_missing` test (#285). ## Chore -- Refactor: Prefer functions over constants (#270). - -- Make better use of `trivial_df()` (#284). +- Remove rlang qualification (#332). -## Uncategorized +- No longer need `as.data.frame()` twice for Arrow (#302, #330). -- Merge pull request #280 from r-dbi/f-ref-3. +- Consistent use of `skip_if_not_dbitest()` (#317). +- Disable Arrow skips (#303). +- Modernize `sql_union()` (#304). -- Merge remote-tracking branch 'refs/remotes/origin/main'. +- Make better use of `trivial_df()` (#284). +## Documentation -- Merged cran-1.7.3 into main. +- Avoid error if RSQLite is not installed. +## Testing +- Run DBItest for SQLite as part of the checks here (#318). -# DBItest 1.7.3.9000 (2022-10-18) +- Enable remaining Arrow tests (#307). -- Internal changes only. +- Fix checks without suggested packages (#300). # DBItest 1.7.3 (2022-10-18) diff --git a/R/expectations.R b/R/expectations.R index be65d2d57..70b18b1e4 100644 --- a/R/expectations.R +++ b/R/expectations.R @@ -13,7 +13,7 @@ expect_all_args_have_default_values <- function(object) { act <- quasi_label(enquo(object), arg = "object") act$args <- formals(act$val) act$args <- act$args[names(act$args) != "..."] - act$char_args <- vapply(act$args, as.character, character(1L)) + act$char_args <- map_chr(act$args, as.character) expect( all(nzchar(act$char_args, keepNA = FALSE)), sprintf("%s has arguments without default values", act$lab) @@ -47,13 +47,13 @@ expect_invisible_true <- function(code) { } expect_equal_df <- function(actual, expected) { - factor_cols <- vapply(expected, is.factor, logical(1L)) + factor_cols <- map_lgl(expected, is.factor) expected[factor_cols] <- lapply(expected[factor_cols], as.character) - asis_cols <- vapply(expected, inherits, "AsIs", FUN.VALUE = logical(1L)) + asis_cols <- map_lgl(expected, inherits, "AsIs") expected[asis_cols] <- lapply(expected[asis_cols], unclass) - list_cols <- vapply(expected, is.list, logical(1L)) + list_cols <- map_lgl(expected, is.list) if (!any(list_cols)) { order_actual <- do.call(order, actual) diff --git a/R/import-testthat.R b/R/import-testthat.R index 56d2835d1..9cce83773 100644 --- a/R/import-testthat.R +++ b/R/import-testthat.R @@ -1,17 +1,5 @@ -#' @import testthat -#' @importFrom rlang quo enquo enquos expr enexpr eval_tidy list2 has_length := -#' @importFrom rlang abort is_interactive as_function local_options seq2 set_names -#' @importFrom rlang %||% global_env is_logical is_installed quo_is_null -#' @importFrom rlang call2 -#' @importFrom rlang caller_env -#' @importFrom rlang exec -#' @importFrom rlang pairlist2 -#' @importFrom rlang new_function -#' @importFrom rlang check_dots_empty -#' @importFrom rlang parse_expr -#' @importFrom rlang quo_get_expr -#' @importFrom rlang arg_match -#' @importFrom rlang is_missing +#' @rawNamespace import(testthat, except = c(is_null, is_false, is_true)) +#' @import rlang NULL #' @importFrom methods findMethod getClasses getClass extends diff --git a/R/run.R b/R/run.R index 1340425f8..8eeccf23b 100644 --- a/R/run.R +++ b/R/run.R @@ -1,4 +1,8 @@ run_tests <- function(ctx, tests, skip, run_only, test_suite) { + tests_sym <- enexpr(tests) + stopifnot(is_symbol(tests_sym)) + tests_qual <- call2(":::", sym("DBItest"), tests_sym) + "!DEBUG run_tests(`test_suite`)" if (is.null(ctx)) { @@ -13,14 +17,14 @@ run_tests <- function(ctx, tests, skip, run_only, test_suite) { ": ", test_suite ) - tests <- tests[!vapply(tests, is.null, logical(1L))] + tests <- compact(tests) tests <- get_run_only_tests(tests, run_only) if (is.null(skip)) { skip <- ctx$default_skip } - test_names <- vctrs::vec_names2(tests, repair = "unique", quiet = TRUE) + test_names <- names(tests) skipped <- get_skip_names(skip) skip_flag <- names(tests) %in% skipped @@ -36,32 +40,32 @@ run_tests <- function(ctx, tests, skip, run_only, test_suite) { if (skip_flag[[test_idx]]) { FALSE } else { - test_fun <- patch_test_fun(tests[[test_idx]]) + test_fun <- tests[[test_idx]] fmls <- formals(test_fun) test_that(paste0(test_context, ": ", test_name), { args <- list() if ("ctx" %in% names(fmls)) { - args <- c(args, list(ctx = ctx)) + args <- c(args, list(ctx = expr(ctx))) } if ("con" %in% names(fmls)) { - args <- c(args, list(con = global_con)) + args <- c(args, list(con = expr(global_con))) } if ("local_con" %in% names(fmls)) { local_con <- local_connection(ctx) - args <- c(args, list(local_con = local_con)) + args <- c(args, list(local_con = expr(local_con))) } if ("closed_con" %in% names(fmls)) { closed_con <- local_closed_connection(ctx) - args <- c(args, list(closed_con = closed_con)) + args <- c(args, list(closed_con = expr(closed_con))) } if ("invalid_con" %in% names(fmls)) { invalid_con <- local_invalid_connection(ctx) - args <- c(args, list(invalid_con = invalid_con)) + args <- c(args, list(invalid_con = expr(invalid_con))) } if ("table_name" %in% names(fmls)) { @@ -74,7 +78,12 @@ run_tests <- function(ctx, tests, skip, run_only, test_suite) { args <- c(args, list(table_name = table_name)) } - exec(test_fun, !!!args) + # Example of generated expression: + # DBItest:::spec_arrow$arrow_append_table_arrow_roundtrip_64_bit_roundtrip(...) + test_fun_expr <- expr(`$`(!!tests_qual, !!test_name)(!!!args)) + expect_warning( + eval(test_fun_expr), NA + ) }) } }, @@ -99,8 +108,8 @@ get_skip_names <- function(skip) { } names_all <- names(spec_all) names_all <- names_all[names_all != ""] - skip_flags_all <- lapply(paste0("(?:^(?:", skip, ")$)"), grepl, names_all, perl = TRUE) - skip_used <- vapply(skip_flags_all, any, logical(1L)) + skip_flags_all <- lapply(paste0("(?:^(?:", skip, ")(?:|_[0-9]+)$)"), grepl, names_all, perl = TRUE) + skip_used <- map_lgl(skip_flags_all, any) if (!all(skip_used)) { warning("Unused skip expressions: ", paste(skip[!skip_used], collapse = ", "), call. = FALSE @@ -126,14 +135,3 @@ get_run_only_tests <- function(tests, run_only) { tests[run_only_tests] } - -patch_test_fun <- function(test_fun) { - body(test_fun) <- wrap_all_statements_with_expect_no_warning(body(test_fun)) - test_fun -} - -wrap_all_statements_with_expect_no_warning <- function(block) { - stopifnot(identical(block[[1]], quote(`{`))) - block[-1] <- lapply(block[-1], function(x) expr(expect_warning(!!x, NA))) - block -} diff --git a/R/spec-arrow-append-table-arrow.R b/R/spec-arrow-append-table-arrow.R index 62be50ef7..6ae90ddd2 100644 --- a/R/spec-arrow-append-table-arrow.R +++ b/R/spec-arrow-append-table-arrow.R @@ -9,8 +9,8 @@ spec_arrow_append_table_arrow <- list( expect_equal(names(formals(dbAppendTableArrow)), c("conn", "name", "value", "...")) }, - arrow_append_table_arrow_return = function(con, table_name) { - skip("Failed in SQLite") + arrow_append_table_arrow_return = function(ctx, con, table_name) { + skip_if_not_dbitest(ctx, "1.8.0.50") #' @return #' `dbAppendTableArrow()` returns a @@ -67,15 +67,15 @@ spec_arrow_append_table_arrow <- list( arrow_append_table_arrow_error = function(con, table_name) { #' An error is also raised test_in <- stream_frame(a = 1L) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbAppendTableArrow(con, NA, test_in)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbAppendTableArrow(con, c("test", "test"), test_in)) }, #' - arrow_append_table_arrow_roundtrip_keywords = function(con) { - skip("Requires dbBind() on RMariaDB") + arrow_append_table_arrow_roundtrip_keywords = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.49") #' @section Specification: #' SQL keywords can be used freely in table names, column names, and data. @@ -87,7 +87,7 @@ spec_arrow_append_table_arrow <- list( }, arrow_append_table_arrow_roundtrip_quotes = function(ctx, con, table_name) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.48") #' Quotes, commas, spaces, and other special characters such as newlines and tabs, #' can also be used in the data, @@ -184,6 +184,8 @@ spec_arrow_append_table_arrow <- list( #' - 64-bit values (using `"bigint"` as field type); the result can be arrow_append_table_arrow_roundtrip_64_bit_numeric = function(ctx, con) { + skip("Internal: Need to enhance test_arrow_roundtrip()") + tbl_in <- data.frame(a = c(-1e14, 1e15)) test_arrow_roundtrip( use_append = TRUE, @@ -197,7 +199,7 @@ spec_arrow_append_table_arrow <- list( }, # arrow_append_table_arrow_roundtrip_64_bit_character = function(ctx, con) { - skip("Failed in SQLite") + skip("Internal: Need to enhance test_arrow_roundtrip()") tbl_in <- data.frame(a = c(-1e14, 1e15)) tbl_exp <- tbl_in @@ -214,8 +216,8 @@ spec_arrow_append_table_arrow <- list( ) }, # - arrow_append_table_arrow_roundtrip_64_bit_roundtrip = function(con, table_name) { - skip("Requires dbBind() on RMariaDB") + arrow_append_table_arrow_roundtrip_64_bit_roundtrip = function(ctx, con, table_name) { + skip("Internal: Need to enhance test_arrow_roundtrip()") tbl_in <- data.frame(a = c(-1e14, 1e15)) dbWriteTable(con, table_name, tbl_in, field.types = c(a = "BIGINT")) @@ -224,8 +226,8 @@ spec_arrow_append_table_arrow <- list( test_arrow_roundtrip(use_append = TRUE, con, tbl_out, tbl_expected = tbl_out) }, - arrow_append_table_arrow_roundtrip_character = function(con) { - skip("Requires dbBind() on RMariaDB") + arrow_append_table_arrow_roundtrip_character = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.45") #' - character (in both UTF-8 tbl_in <- data.frame( @@ -236,8 +238,8 @@ spec_arrow_append_table_arrow <- list( test_arrow_roundtrip(use_append = TRUE, con, tbl_in) }, - arrow_append_table_arrow_roundtrip_character_native = function(con) { - skip("Requires dbBind() on RMariaDB") + arrow_append_table_arrow_roundtrip_character_native = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.44") #' and native encodings), tbl_in <- data.frame( @@ -265,47 +267,29 @@ spec_arrow_append_table_arrow <- list( test_arrow_roundtrip(use_append = TRUE, con, tbl_in) }, - arrow_append_table_arrow_roundtrip_factor = function(con) { - skip("Failed in SQLite") + arrow_append_table_arrow_roundtrip_factor = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.43") - #' - factor (returned as character, + #' - factor (possibly returned as character) tbl_in <- data.frame( a = factor(get_texts()) ) tbl_exp <- tbl_in tbl_exp$a <- as.character(tbl_exp$a) - #' with a warning) - suppressWarnings( - expect_warning( - test_arrow_roundtrip(use_append = TRUE, con, tbl_in, tbl_exp) - ) - ) - }, - - arrow_append_table_arrow_roundtrip_raw = function(ctx, con) { - skip("Failed in SQLite") - - #' - list of raw - #' (if supported by the database) - if (isTRUE(ctx$tweaks$omit_blob_tests)) { - skip("tweak: omit_blob_tests") - } - - tbl_in <- data.frame(id = 1L, a = I(list(as.raw(0:10)))) - tbl_exp <- tbl_in - tbl_exp$a <- blob::as_blob(unclass(tbl_in$a)) test_arrow_roundtrip( use_append = TRUE, - con, tbl_in, tbl_exp, + con, + tbl_in, + tbl_exp, transform = function(tbl_out) { - tbl_out$a <- blob::as_blob(tbl_out$a) + tbl_out$a <- as.character(tbl_out$a) tbl_out } ) }, arrow_append_table_arrow_roundtrip_blob = function(ctx, con) { - skip("Failed in SQLite") + skip_if_not_dbitest(ctx, "1.8.0.41") #' - objects of type [blob::blob] #' (if supported by the database) @@ -425,7 +409,7 @@ spec_arrow_append_table_arrow <- list( use_append = TRUE, con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) @@ -435,7 +419,7 @@ spec_arrow_append_table_arrow <- list( }, arrow_append_table_arrow_roundtrip_timestamp_extended = function(ctx, con) { - skip("Fails in RPostgres and RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.40") #' also for timestamps prior to 1970 or 1900 or after 2038 if (!isTRUE(ctx$tweaks$timestamp_typed)) { @@ -468,7 +452,7 @@ spec_arrow_append_table_arrow <- list( use_append = TRUE, con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) diff --git a/R/spec-arrow-create-table-arrow.R b/R/spec-arrow-create-table-arrow.R index 0a88c3a01..985b29e6e 100644 --- a/R/spec-arrow-create-table-arrow.R +++ b/R/spec-arrow-create-table-arrow.R @@ -4,8 +4,8 @@ #' @format NULL #' @keywords NULL spec_arrow_create_table_arrow <- list( - arrow_create_table_arrow_formals = function() { - skip("Failed in SQLite") + arrow_create_table_arrow_formals = function(ctx) { + skip_if_not_dbitest(ctx, "1.8.0.13") # expect_equal(names(formals(dbCreateTableArrow)), c("conn", "name", "value", "...", "temporary")) @@ -45,9 +45,9 @@ spec_arrow_create_table_arrow <- list( arrow_create_table_arrow_error = function(ctx, con, table_name) { #' An error is also raised test_in <- stream_frame(a = 1L) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbCreateTableArrow(con, NA, test_in)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbCreateTableArrow(con, c(table_name, table_name), test_in)) #' Invalid values for the `temporary` argument @@ -118,8 +118,58 @@ spec_arrow_create_table_arrow <- list( } }, + arrow_create_table_arrow_value_df = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.5") + + #' + #' The `value` argument can be: + #' - a data frame, + table_name <- "act_df" + local_remove_test_table(con, table_name) + df <- data.frame(a = 1) + dbCreateTableArrow(con, table_name, df) + expect_equal_df(dbReadTable(con, table_name), data.frame(a = numeric())) + }, + + arrow_create_table_arrow_value_array = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.6") + + #' - a nanoarrow array + table_name <- "act_array" + local_remove_test_table(con, table_name) + array <- nanoarrow::as_nanoarrow_array(data.frame(a = 1)) + dbCreateTableArrow(con, table_name, array) + expect_equal_df(dbReadTable(con, table_name), data.frame(a = numeric())) + }, + + arrow_create_table_arrow_value_stream = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.7") + + #' - a nanoarrow array stream + table_name <- "act_stream" + local_remove_test_table(con, table_name) + stream <- stream_frame(a = 1) + dbCreateTableArrow(con, table_name, stream) + expect_equal(as.data.frame(stream), data.frame(a = 1)) + #' (which will still contain the data after the call) + expect_equal_df(dbReadTable(con, table_name), data.frame(a = numeric())) + }, + + arrow_create_table_arrow_value_schema = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.8") + + #' - a nanoarrow schema + table_name <- "act_schema" + local_remove_test_table(con, table_name) + schema <- nanoarrow::infer_nanoarrow_schema(stream_frame(a = 1)) + dbCreateTableArrow(con, table_name, schema) + expect_equal_df(dbReadTable(con, table_name), data.frame(a = numeric())) + }, + #' - create_temporary_table = function(ctx, con, table_name = "dbit03") { + arrow_create_table_arrow_temporary_1 = function(ctx, con, table_name = "dbit03") { + skip_if_not_dbitest(ctx, "1.8.0.4") + #' If the `temporary` argument is `TRUE`, the table is not available in a #' second connection and is gone after reconnecting. #' Not all backends support this argument. @@ -136,17 +186,23 @@ spec_arrow_create_table_arrow <- list( expect_error(dbReadTable(con2, table_name)) }, # second stage - create_temporary_table = function(con) { + arrow_create_table_arrow_temporary_2 = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.4") + + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit03" expect_error(dbReadTable(con, table_name)) }, - arrow_create_table_arrow_visible_in_other_connection = function(ctx, local_con) { - skip("Fails in adbc") + arrow_create_table_arrow_visible_in_other_connection_1 = function(ctx, local_con) { + skip_if_not_dbitest(ctx, "1.8.0.3") #' A regular, non-temporary table is visible in a second connection, penguins <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit04" dbCreateTableArrow(local_con, table_name, stream_frame(penguins)) penguins_out <- check_df(dbReadTable(local_con, table_name)) @@ -156,19 +212,21 @@ spec_arrow_create_table_arrow <- list( expect_equal_df(dbReadTable(con2, table_name), penguins[0, , drop = FALSE]) }, # second stage - arrow_create_table_arrow_visible_in_other_connection = function(ctx, con) { - skip("Fails in adbc") + arrow_create_table_arrow_visible_in_other_connection_2 = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.3") penguins <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit04" #' in a pre-existing connection, expect_equal_df(check_df(dbReadTable(con, table_name)), penguins[0, , drop = FALSE]) }, # third stage - arrow_create_table_arrow_visible_in_other_connection = function(ctx, local_con, table_name = "dbit04") { - skip("Fails in adbc") + arrow_create_table_arrow_visible_in_other_connection_3 = function(ctx, local_con, table_name = "dbit04") { + skip_if_not_dbitest(ctx, "1.8.0.3") penguins <- get_penguins(ctx) diff --git a/R/spec-arrow-fetch-arrow-chunk.R b/R/spec-arrow-fetch-arrow-chunk.R index 64418d101..6f0aa5b74 100644 --- a/R/spec-arrow-fetch-arrow-chunk.R +++ b/R/spec-arrow-fetch-arrow-chunk.R @@ -11,8 +11,8 @@ spec_arrow_fetch_arrow_chunk <- list( arrow_fetch_arrow_chunk_atomic = function(con) { #' @return - #' `dbFetchArrowChunk()` always returns an object coercible to a [data.frame] - #' with as many rows as records were fetched and as many + #' `dbFetchArrowChunk()` always returns an object coercible to a [data.frame] with + #' as many rows as records were fetched and as many #' columns as fields in the result set, #' even if the result is a single value query <- trivial_query() @@ -40,8 +40,8 @@ spec_arrow_fetch_arrow_chunk <- list( }, #' - arrow_fetch_arrow_chunk_closed = function(con) { - skip("Fails in adbc") + arrow_fetch_arrow_chunk_closed = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.11") #' @section Failure modes: #' An attempt to fetch from a closed result set raises an error. diff --git a/R/spec-arrow-fetch-arrow.R b/R/spec-arrow-fetch-arrow.R index 8353b2f03..4cd822332 100644 --- a/R/spec-arrow-fetch-arrow.R +++ b/R/spec-arrow-fetch-arrow.R @@ -11,8 +11,8 @@ spec_arrow_fetch_arrow <- list( arrow_fetch_arrow_atomic = function(con) { #' @return - #' `dbFetchArrow()` always returns an object coercible to a [data.frame] - #' with as many rows as records were fetched and as many + #' `dbFetchArrow()` always returns an object coercible to a [data.frame] with + #' as many rows as records were fetched and as many #' columns as fields in the result set, #' even if the result is a single value query <- trivial_query() @@ -40,8 +40,8 @@ spec_arrow_fetch_arrow <- list( }, #' - arrow_fetch_arrow_closed = function(con) { - skip("Fails in adbc") + arrow_fetch_arrow_closed = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.15") #' @section Failure modes: #' An attempt to fetch from a closed result set raises an error. diff --git a/R/spec-arrow-get-query-arrow.R b/R/spec-arrow-get-query-arrow.R index 81f1f49a5..6eeb1d5c7 100644 --- a/R/spec-arrow-get-query-arrow.R +++ b/R/spec-arrow-get-query-arrow.R @@ -11,8 +11,8 @@ spec_arrow_get_query_arrow <- list( arrow_get_query_arrow_atomic = function(con) { #' @return - #' `dbGetQueryArrow()` always returns an object coercible to a [data.frame] - #' with as many rows as records were fetched and as many + #' `dbGetQueryArrow()` always returns an object coercible to a [data.frame], with + #' as many rows as records were fetched and as many #' columns as fields in the result set, #' even if the result is a single value query <- trivial_query() @@ -30,8 +30,8 @@ spec_arrow_get_query_arrow <- list( expect_identical(rows, result) }, - arrow_get_query_arrow_zero_rows = function(con) { - skip("Causes segfault in adbc") + arrow_get_query_arrow_zero_rows = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.12") #' or zero rows. # Not all SQL dialects seem to support the query used here. @@ -84,62 +84,65 @@ spec_arrow_get_query_arrow <- list( expect_equal(out, head(result, nrow(out))) }, - # #' @section Additional arguments: - # #' The following arguments are not part of the `dbGetQueryArrow()` generic - # #' (to improve compatibility across backends) - # #' but are part of the DBI specification: - # #' - `params` (default: `NULL`) - # #' - `immediate` (default: `NULL`) - # #' - # #' They must be provided as named arguments. - # #' See the "Specification" and "Value" sections for details on their usage. - # - # #' - # arrow_get_query_arrow_params = function(ctx, con) { - # #' The `param` argument allows passing query parameters, see [dbBind()] for details. - # placeholder_funs <- get_placeholder_funs(ctx) - # - # for (placeholder_fun in placeholder_funs) { - # placeholder <- placeholder_fun(1) - # query <- paste0("SELECT ", placeholder, " + 1.0 AS a") - # values <- trivial_values(3) - 1 - # params <- stats::setNames(list(values), names(placeholder)) - # ret <- dbGetQueryArrow(con, query, params = params) - # expect_equal(ret, trivial_df(3), info = placeholder) - # } - # }, + #' @section Additional arguments: + #' The following arguments are not part of the `dbGetQueryArrow()` generic + #' (to improve compatibility across backends) + #' but are part of the DBI specification: + #' - `params` (default: `NULL`) + #' - `immediate` (default: `NULL`) + #' + #' They must be provided as named arguments. + #' See the "Specification" and "Value" sections for details on their usage. + #' + arrow_get_query_arrow_params = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.1") + + #' The `param` argument allows passing query parameters, see [dbBind()] for details. + placeholder_funs <- get_placeholder_funs(ctx) + + for (placeholder_fun in placeholder_funs) { + placeholder <- placeholder_fun(1) + query <- paste0("SELECT ", placeholder, " + 1.0 AS a") + values <- trivial_values(3) - 1 + params <- stats::setNames(list(values), names(placeholder)) + ret <- dbGetQueryArrow(con, query, params = params) + expect_equal(as.data.frame(ret), trivial_df(3), info = placeholder) + } + }, # - # arrow_get_query_arrow_immediate = function(con, table_name) { - # #' @section Specification for the `immediate` argument: - # #' - # #' The `immediate` argument supports distinguishing between "direct" - # #' and "prepared" APIs offered by many database drivers. - # #' Passing `immediate = TRUE` leads to immediate execution of the - # #' query or statement, via the "direct" API (if supported by the driver). - # #' The default `NULL` means that the backend should choose whatever API - # #' makes the most sense for the database, and (if relevant) tries the - # #' other API if the first attempt fails. A successful second attempt - # #' should result in a message that suggests passing the correct - # #' `immediate` argument. - # #' Examples for possible behaviors: - # #' 1. DBI backend defaults to `immediate = TRUE` internally - # #' 1. A query without parameters is passed: query is executed - # #' 1. A query with parameters is passed: - # #' 1. `params` not given: rejected immediately by the database - # #' because of a syntax error in the query, the backend tries - # #' `immediate = FALSE` (and gives a message) - # #' 1. `params` given: query is executed using `immediate = FALSE` - # #' 1. DBI backend defaults to `immediate = FALSE` internally - # #' 1. A query without parameters is passed: - # #' 1. simple query: query is executed - # #' 1. "special" query (such as setting a config options): fails, - # #' the backend tries `immediate = TRUE` (and gives a message) - # #' 1. A query with parameters is passed: - # #' 1. `params` not given: waiting for parameters via [dbBind()] - # #' 1. `params` given: query is executed - # res <- expect_visible(dbGetQueryArrow(con, trivial_query(), immediate = TRUE)) - # expect_s3_class(res, "data.frame") - # }, + arrow_get_query_arrow_immediate = function(ctx, con, table_name) { + skip_if_not_dbitest(ctx, "1.8.0.2") + + #' @section Specification for the `immediate` argument: + #' + #' The `immediate` argument supports distinguishing between "direct" + #' and "prepared" APIs offered by many database drivers. + #' Passing `immediate = TRUE` leads to immediate execution of the + #' query or statement, via the "direct" API (if supported by the driver). + #' The default `NULL` means that the backend should choose whatever API + #' makes the most sense for the database, and (if relevant) tries the + #' other API if the first attempt fails. A successful second attempt + #' should result in a message that suggests passing the correct + #' `immediate` argument. + #' Examples for possible behaviors: + #' 1. DBI backend defaults to `immediate = TRUE` internally + #' 1. A query without parameters is passed: query is executed + #' 1. A query with parameters is passed: + #' 1. `params` not given: rejected immediately by the database + #' because of a syntax error in the query, the backend tries + #' `immediate = FALSE` (and gives a message) + #' 1. `params` given: query is executed using `immediate = FALSE` + #' 1. DBI backend defaults to `immediate = FALSE` internally + #' 1. A query without parameters is passed: + #' 1. simple query: query is executed + #' 1. "special" query (such as setting a config options): fails, + #' the backend tries `immediate = TRUE` (and gives a message) + #' 1. A query with parameters is passed: + #' 1. `params` not given: waiting for parameters via [dbBind()] + #' 1. `params` given: query is executed + res <- expect_visible(dbGetQueryArrow(con, trivial_query(), immediate = TRUE)) + check_arrow(res) + }, # NULL ) diff --git a/R/spec-arrow-read-table-arrow.R b/R/spec-arrow-read-table-arrow.R index 710611735..b0914aebc 100644 --- a/R/spec-arrow-read-table-arrow.R +++ b/R/spec-arrow-read-table-arrow.R @@ -14,9 +14,9 @@ spec_arrow_read_table_arrow <- list( skip_if_not_dbitest(ctx, "1.7.99.2") #' @return - #' `dbReadTableArrow()` returns a data frame that contains the complete data - #' from the remote table, effectively the result of calling [dbGetQuery()] - #' with `SELECT * FROM `. + #' `dbReadTableArrow()` returns an Arrow object that contains the complete data + #' from the remote table, effectively the result of calling [dbGetQueryArrow()] with + #' `SELECT * FROM `. penguins_in <- get_penguins(ctx) dbWriteTable(con, table_name, penguins_in) penguins_out <- check_arrow(dbReadTableArrow(con, table_name)) @@ -32,10 +32,10 @@ spec_arrow_read_table_arrow <- list( }, arrow_read_table_arrow_empty = function(ctx, con, table_name) { - skip("Causes segfault in adbc and duckdb") + skip_if_not_dbitest(ctx, "1.8.0.14") #' @return - #' An empty table is returned as a data frame with zero rows. + #' An empty table is returned as an Arrow object with zero rows. penguins_in <- get_penguins(ctx)[integer(), ] dbWriteTable(con, table_name, penguins_in) penguins_out <- check_arrow(dbReadTableArrow(con, table_name)) @@ -63,9 +63,9 @@ spec_arrow_read_table_arrow <- list( arrow_read_table_arrow_error = function(ctx, con, table_name) { #' An error is raised dbWriteTable(con, table_name, data.frame(a = 1.5)) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbReadTableArrow(con, NA)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbReadTableArrow(con, c(table_name, table_name))) }, diff --git a/R/spec-arrow-write-table-arrow.R b/R/spec-arrow-write-table-arrow.R index fa5e59012..f9417233f 100644 --- a/R/spec-arrow-write-table-arrow.R +++ b/R/spec-arrow-write-table-arrow.R @@ -17,8 +17,8 @@ spec_arrow_write_table_arrow <- list( }, #' - arrow_write_table_arrow_error_overwrite = function(con, table_name) { - skip("Failed in SQLite") + arrow_write_table_arrow_error_overwrite = function(ctx, con, table_name) { + skip_if_not_dbitest(ctx, "1.8.0.39") #' @section Failure modes: #' If the table exists, and both `append` and `overwrite` arguments are unset, @@ -54,13 +54,13 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_error = function(ctx, con, table_name) { - skip("Failed in SQLite") + skip_if_not_dbitest(ctx, "1.8.0.38") #' An error is also raised - test_in <- stream_frame(a = 1L) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + test_in <- data.frame(a = 1L) + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbWriteTableArrow(con, NA, test_in %>% stream_frame())) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbWriteTableArrow(con, c(table_name, table_name), test_in %>% stream_frame())) #' Invalid values for the additional arguments @@ -79,11 +79,6 @@ spec_arrow_write_table_arrow <- list( expect_error(dbWriteTableArrow(con, table_name, test_in %>% stream_frame(), temporary = NA)) #' incompatible values, expect_error(dbWriteTableArrow(con, table_name, test_in %>% stream_frame(), overwrite = TRUE, append = TRUE)) - expect_error(dbWriteTableArrow(con, table_name, test_in %>% stream_frame(), append = TRUE)) - #' duplicate - expect_error(dbWriteTableArrow(con, table_name, test_in %>% stream_frame())) - #' or missing names, - expect_error(dbWriteTableArrow(con, table_name, test_in %>% stream_frame())) #' incompatible columns) dbWriteTableArrow(con, table_name, test_in %>% stream_frame()) @@ -190,7 +185,7 @@ spec_arrow_write_table_arrow <- list( #' arrow_write_table_arrow_overwrite = function(ctx, con, table_name) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.37") #' If the `overwrite` argument is `TRUE`, an existing table of the same name #' will be overwritten. @@ -205,7 +200,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_overwrite_missing = function(ctx, con, table_name) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.36") #' This argument doesn't change behavior if the table does not exist yet. penguins_in <- get_penguins(ctx) @@ -219,7 +214,7 @@ spec_arrow_write_table_arrow <- list( #' arrow_write_table_arrow_append = function(ctx, con, table_name) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.35") #' If the `append` argument is `TRUE`, the rows in an existing table are #' preserved, and the new data are appended. @@ -231,7 +226,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_append_new = function(ctx, con, table_name) { - skip("Failed in SQLite") + skip_if_not_dbitest(ctx, "1.8.0.34") #' If the table doesn't exist yet, it is created. penguins <- get_penguins(ctx) @@ -241,8 +236,8 @@ spec_arrow_write_table_arrow <- list( }, #' - arrow_write_table_arrow_temporary = function(ctx, con, table_name = "dbit08") { - skip("Failed in SQLite") + arrow_write_table_arrow_temporary_1 = function(ctx, con, table_name = "dbit08") { + skip_if_not_dbitest(ctx, "1.8.0.33") #' If the `temporary` argument is `TRUE`, the table is not available in a #' second connection and is gone after reconnecting. @@ -260,23 +255,27 @@ spec_arrow_write_table_arrow <- list( expect_error(dbReadTable(con2, table_name)) }, # second stage - arrow_write_table_arrow_temporary = function(ctx, con) { - skip("Failed in SQLite") + arrow_write_table_arrow_temporary_2 = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.33") if (!isTRUE(ctx$tweaks$temporary_tables)) { skip("tweak: temporary_tables") } + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit08" expect_error(dbReadTable(con, table_name)) }, - arrow_write_table_arrow_visible_in_other_connection = function(ctx, local_con) { - skip("Failed in SQLite") + arrow_write_table_arrow_visible_in_other_connection_1 = function(ctx, local_con) { + skip_if_not_dbitest(ctx, "1.8.0.31") #' A regular, non-temporary table is visible in a second connection, penguins30 <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit09" dbWriteTableArrow(local_con, table_name, penguins30 %>% stream_frame()) @@ -287,19 +286,21 @@ spec_arrow_write_table_arrow <- list( expect_equal_df(dbReadTable(con2, table_name), penguins30) }, # second stage - arrow_write_table_arrow_visible_in_other_connection = function(ctx, con) { - skip("Failed in SQLite") + arrow_write_table_arrow_visible_in_other_connection_2 = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.31") #' in a pre-existing connection, penguins30 <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit09" expect_equal_df(check_df(dbReadTable(con, table_name)), penguins30) }, # third stage - arrow_write_table_arrow_visible_in_other_connection = function(ctx, local_con, table_name = "dbit09") { - skip("Failed in SQLite") + arrow_write_table_arrow_visible_in_other_connection_3 = function(ctx, local_con, table_name = "dbit09") { + skip_if_not_dbitest(ctx, "1.8.0.31") #' and after reconnecting to the database. penguins30 <- get_penguins(ctx) @@ -309,7 +310,7 @@ spec_arrow_write_table_arrow <- list( #' arrow_write_table_arrow_roundtrip_keywords = function(ctx, con) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.28") #' SQL keywords can be used freely in table names, column names, and data. tbl_in <- data.frame( @@ -320,7 +321,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_quotes = function(ctx, con, table_name) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.27") #' Quotes, commas, spaces, and other special characters such as newlines and tabs, #' can also be used in the data, @@ -360,7 +361,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_quotes_column_names = function(ctx, con) { - skip("Failed in SQLite") + skip_if_not_dbitest(ctx, "1.8.0.26") #' and column names. skip_if_not_dbitest(ctx, "1.7.2") @@ -399,7 +400,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_logical = function(ctx, con) { - skip("Fails in adbc") + skip_if_not_dbitest(ctx, "1.8.0.25") #' - logical tbl_in <- data.frame(a = c(TRUE, FALSE, NA)) @@ -422,6 +423,8 @@ spec_arrow_write_table_arrow <- list( #' - 64-bit values (using `"bigint"` as field type); the result can be arrow_write_table_arrow_roundtrip_64_bit_numeric = function(ctx, con) { + skip("Internal: Need to enhance test_arrow_roundtrip()") + tbl_in <- data.frame(a = c(-1e14, 1e15)) test_arrow_roundtrip( con, tbl_in, @@ -434,7 +437,7 @@ spec_arrow_write_table_arrow <- list( }, # arrow_write_table_arrow_roundtrip_64_bit_character = function(ctx, con) { - skip("Failed in SQLite") + skip("Internal: Need to enhance test_arrow_roundtrip()") tbl_in <- data.frame(a = c(-1e14, 1e15)) tbl_exp <- tbl_in @@ -450,8 +453,8 @@ spec_arrow_write_table_arrow <- list( ) }, # - arrow_write_table_arrow_roundtrip_64_bit_roundtrip = function(con, table_name) { - skip("Failed in SQLite") + arrow_write_table_arrow_roundtrip_64_bit_roundtrip = function(ctx, con, table_name) { + skip("Internal: Need to enhance test_arrow_roundtrip()") tbl_in <- data.frame(a = c(-1e14, 1e15)) dbWriteTableArrow(con, table_name, tbl_in, field.types = c(a = "BIGINT")) @@ -461,7 +464,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_character = function(ctx, con) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.22") #' - character (in both UTF-8 tbl_in <- data.frame( @@ -473,7 +476,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_character_native = function(ctx, con) { - skip("Requires dbBind() on RMariaDB") + skip_if_not_dbitest(ctx, "1.8.0.21") #' and native encodings), tbl_in <- data.frame( @@ -502,40 +505,27 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_factor = function(ctx, con) { - skip("Failed in SQLite") + skip_if_not_dbitest(ctx, "1.8.0.20") - #' - factor (returned as character) + #' - factor (possibly returned as character) tbl_in <- data.frame( a = factor(get_texts()) ) tbl_exp <- tbl_in tbl_exp$a <- as.character(tbl_exp$a) - test_arrow_roundtrip(con, tbl_in, tbl_exp) - }, - - arrow_write_table_arrow_roundtrip_raw = function(ctx, con) { - skip("Failed in SQLite") - - #' - list of raw - #' (if supported by the database) - if (isTRUE(ctx$tweaks$omit_blob_tests)) { - skip("tweak: omit_blob_tests") - } - - tbl_in <- data.frame(id = 1L, a = I(list(as.raw(0:10)))) - tbl_exp <- tbl_in - tbl_exp$a <- blob::as_blob(unclass(tbl_in$a)) test_arrow_roundtrip( - con, tbl_in, tbl_exp, + con, + tbl_in, + tbl_exp, transform = function(tbl_out) { - tbl_out$a <- blob::as_blob(tbl_out$a) + tbl_out$a <- as.character(tbl_out$a) tbl_out } ) }, arrow_write_table_arrow_roundtrip_blob = function(ctx, con) { - skip("Failed in SQLite") + skip_if_not_dbitest(ctx, "1.8.0.18") #' - objects of type [blob::blob] #' (if supported by the database) @@ -626,7 +616,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_timestamp = function(ctx, con) { - skip("Fails in adbc") + skip_if_not_dbitest(ctx, "1.8.0.17") #' - timestamp #' (if supported by the database; @@ -653,7 +643,7 @@ spec_arrow_write_table_arrow <- list( test_arrow_roundtrip( con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) @@ -663,7 +653,7 @@ spec_arrow_write_table_arrow <- list( }, arrow_write_table_arrow_roundtrip_timestamp_extended = function(ctx, con) { - skip("Fails in adbc") + skip_if_not_dbitest(ctx, "1.8.0.16") #' also for timestamps prior to 1970 or 1900 or after 2038 if (!isTRUE(ctx$tweaks$timestamp_typed)) { @@ -695,7 +685,7 @@ spec_arrow_write_table_arrow <- list( test_arrow_roundtrip( con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) @@ -758,8 +748,8 @@ test_arrow_roundtrip_one <- function(con, tbl_in, tbl_expected = tbl_in, transfo dbWriteTableArrow(con, name, tbl_in %>% stream_frame()) } - tbl_read <- check_df(dbReadTable(con, name, check.names = FALSE)) - tbl_out <- transform(tbl_read) + stream <- dbReadTableArrow(con, name) + tbl_out <- check_arrow(stream, transform) expect_equal_df(tbl_out, tbl_expected) } diff --git a/R/spec-arrow.R b/R/spec-arrow.R index 8af3af403..a7bea3c02 100644 --- a/R/spec-arrow.R +++ b/R/spec-arrow.R @@ -21,7 +21,12 @@ stream_frame <- function(..., .select = NULL) { skip("dplyr is not installed") } - data <- data.frame(..., stringsAsFactors = FALSE) + data <- data.frame(..., stringsAsFactors = FALSE, check.names = FALSE) + as_is <- map_lgl(data, inherits, "AsIs") + data[as_is] <- map(data[as_is], function(.x) { + class(.x) <- setdiff(class(.x), "AsIs") + .x + }) select <- enquo(.select) diff --git a/R/spec-driver-constructor.R b/R/spec-driver-constructor.R index 3fd1a1c2f..7f1b97e06 100644 --- a/R/spec-driver-constructor.R +++ b/R/spec-driver-constructor.R @@ -8,8 +8,7 @@ spec_driver_constructor <- list( constructor = function(ctx) { pkg_name <- package_name(ctx) - #' The backend must support creation of an instance of its [DBIDriver-class] - #' subclass + #' The backend must support creation of an instance of its [DBIDriver-class] subclass #' with a \dfn{constructor function}. #' By default, its name is the package name without the leading \sQuote{R} #' (if it exists), e.g., `SQLite` for the \pkg{RSQLite} package. diff --git a/R/spec-driver-data-type.R b/R/spec-driver-data-type.R index 2271f6167..1b03d26c2 100644 --- a/R/spec-driver-data-type.R +++ b/R/spec-driver-data-type.R @@ -113,12 +113,12 @@ test_data_type <- function(ctx, dbObj) { } ) - #' The SQL data type for [factor] + #' The SQL data type for [factor] and expect_identical( dbDataType(dbObj, letters), dbDataType(dbObj, factor(letters)) ) - #' and [ordered] is the same as for character. + #' [ordered] is the same as for character. expect_identical( dbDataType(dbObj, letters), dbDataType(dbObj, ordered(letters)) diff --git a/R/spec-meta-bind-.R b/R/spec-meta-bind-.R index 24dc4de61..e44ab6fc5 100644 --- a/R/spec-meta-bind-.R +++ b/R/spec-meta-bind-.R @@ -8,12 +8,22 @@ test_select_bind_expr <- function( bind, query = TRUE, skip_fun = NULL, + dbitest_version = NULL, cast_fun = NULL, requires_names = NULL) { force(bind_values) force(arrow) force(bind) + caller <- sys.function(-1) + caller_src <- utils::getSrcref(caller) + caller_ref <- paste0("") + + roxygen_bits <- grep("#' .*$", as.character(caller_src), value = TRUE) + docstring <- gsub("^ +#' *", "", roxygen_bits) + + header <- c(caller_ref, docstring) + cast_fun <- enquo(cast_fun) has_cast_fun <- !quo_is_null(cast_fun) cast_fun_expr <- if (has_cast_fun) expr({ @@ -29,6 +39,10 @@ test_select_bind_expr <- function( has_cast_fun = has_cast_fun ) + skip_dbitest_expr <- if (!is.null(dbitest_version)) expr({ + skip_if_not_dbitest(ctx, !!dbitest_version) + }) + skip_expr <- if (!is.null(skip_fun)) expr({ skip_if(!!body(skip_fun)) }) @@ -44,6 +58,9 @@ test_select_bind_expr <- function( }) expr({ + !!!header + + !!skip_dbitest_expr !!skip_expr placeholder_funs <- !!placeholder_funs_expr diff --git a/R/spec-meta-bind-arrow-stream.R b/R/spec-meta-bind-arrow-stream.R index dffd22024..e60f01439 100644 --- a/R/spec-meta-bind-arrow-stream.R +++ b/R/spec-meta-bind-arrow-stream.R @@ -1,9 +1,15 @@ # Generated by helper-dev.R, do not edit by hand +# Sources: R/spec-meta-bind-.R, R/spec-meta-bind-expr.R, R/spec-meta-bind-runner.R -# This file is generated during load_all() if it's older than the input files +# This file is generated during load_all() if it's older than the sources spec_meta_arrow_stream_bind <- list( arrow_stream_bind_return_value = function(ctx, con) { + # + # @return + # `dbBind()` returns the result set, + # invisibly, + # for queries issued by [dbSendQuery()] or [dbSendQueryArrow()] and placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -32,6 +38,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_too_many = function(ctx, con) { + # + # @section Failure modes: + # Binding too many placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -55,6 +64,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_not_enough = function(ctx, con) { + # + # or not enough values, placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -75,6 +86,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_wrong_name = function(ctx, con) { + # + # or parameters with wrong names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -94,6 +107,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_named_param_unnamed_placeholders = function(ctx, con) { + # + # If the placeholders in the query are named, + # all parameter values must have names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -113,6 +129,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_named_param_empty_placeholders = function(ctx, con) { + # + # (which must not be empty placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -136,6 +154,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_unnamed_param_named_placeholders = function(ctx, con) { + # + # and vice versa, + # otherwise an error is raised. placeholder_funs <- get_placeholder_funs(ctx, requires_names = FALSE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -155,6 +176,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_premature_clear = function(ctx, con) { + # + # Calling `dbBind()` on a result set already cleared by [dbClearResult()] + # also raises an error. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -171,6 +195,10 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_multi_row = function(ctx, con) { + # + # @section Specification: + # The elements of the `params` argument do not need to be scalars, + # vectors of arbitrary length placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -193,7 +221,13 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_multi_row_zero_length = function(ctx, con) { - skip_if(ctx$tweaks$dbitest_version < "1.7.99.12") + # + # (including length 0) + # are supported. + # For queries, calling `dbFetch()` binding such parameters returns + # concatenated results, equivalent to binding and fetching for each set + # of values and connecting via [rbind()]. + skip_if_not_dbitest(ctx, "1.7.99.12") placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -215,6 +249,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_repeated = function(ctx, con) { + # + # `dbBind()` also accepts repeated calls on the same result set + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -242,6 +279,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_repeated_untouched = function(ctx, con) { + # + # even if no results are fetched between calls to `dbBind()`, + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -265,6 +305,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_named_param_shuffle = function(ctx, con) { + # + # If the placeholders in the query are named, + # their order in the `params` argument is not important. placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -288,6 +331,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_integer = function(ctx, con) { + # + # At least the following data types are accepted on input (including [NA]): + # - [integer] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -314,6 +360,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_numeric = function(ctx, con) { + # + # - [numeric] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -340,6 +388,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_logical = function(ctx, con) { + # + # - [logical] for Boolean values placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -365,6 +415,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_character = function(ctx, con) { + # + # - [character] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -396,6 +448,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_character_escape = function(ctx, con) { + # + # (also with special characters such as spaces, newlines, quotes, and backslashes) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -431,6 +485,9 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_factor = function(ctx, con) { + # + # - [factor] (bound as character, + # with warning) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -462,6 +519,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_date = function(ctx, con) { + # + # - [Date] skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -492,6 +551,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_date_integer = function(ctx, con) { + # + # (also when stored internally as integer) skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -522,6 +583,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_timestamp = function(ctx, con) { + # + # - [POSIXct] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -552,6 +615,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_timestamp_lt = function(ctx, con) { + # + # - [POSIXlt] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -582,6 +647,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_time_seconds = function(ctx, con) { + # + # - [difftime] values skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -612,6 +679,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_time_hours = function(ctx, con) { + # + # (also with units other than seconds skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -642,6 +711,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_time_minutes_integer = function(ctx, con) { + # + # and with the value stored as integer) skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -672,6 +743,8 @@ spec_meta_arrow_stream_bind <- list( } }, arrow_stream_bind_blob = function(ctx, con) { + # + # - objects of type [blob::blob] skip_if(isTRUE(ctx$tweaks$omit_blob_tests)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check diff --git a/R/spec-meta-bind-arrow.R b/R/spec-meta-bind-arrow.R index 21df08fb4..44c1b0d60 100644 --- a/R/spec-meta-bind-arrow.R +++ b/R/spec-meta-bind-arrow.R @@ -1,9 +1,15 @@ # Generated by helper-dev.R, do not edit by hand +# Sources: R/spec-meta-bind-.R, R/spec-meta-bind-expr.R, R/spec-meta-bind-runner.R -# This file is generated during load_all() if it's older than the input files +# This file is generated during load_all() if it's older than the sources spec_meta_arrow_bind <- list( arrow_bind_return_value = function(ctx, con) { + # + # @return + # `dbBind()` returns the result set, + # invisibly, + # for queries issued by [dbSendQuery()] or [dbSendQueryArrow()] and placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -32,6 +38,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_too_many = function(ctx, con) { + # + # @section Failure modes: + # Binding too many placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -55,6 +64,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_not_enough = function(ctx, con) { + # + # or not enough values, placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -75,6 +86,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_wrong_name = function(ctx, con) { + # + # or parameters with wrong names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -94,6 +107,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_multi_row_unequal_length = function(ctx, con) { + # + # or unequal length, + # also raises an error. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -119,6 +135,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_named_param_unnamed_placeholders = function(ctx, con) { + # + # If the placeholders in the query are named, + # all parameter values must have names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -138,6 +157,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_named_param_empty_placeholders = function(ctx, con) { + # + # (which must not be empty placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -161,6 +182,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_unnamed_param_named_placeholders = function(ctx, con) { + # + # and vice versa, + # otherwise an error is raised. placeholder_funs <- get_placeholder_funs(ctx, requires_names = FALSE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -180,6 +204,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_premature_clear = function(ctx, con) { + # + # Calling `dbBind()` on a result set already cleared by [dbClearResult()] + # also raises an error. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -196,6 +223,10 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_multi_row = function(ctx, con) { + # + # @section Specification: + # The elements of the `params` argument do not need to be scalars, + # vectors of arbitrary length placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -218,7 +249,13 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_multi_row_zero_length = function(ctx, con) { - skip_if(ctx$tweaks$dbitest_version < "1.7.99.12") + # + # (including length 0) + # are supported. + # For queries, calling `dbFetch()` binding such parameters returns + # concatenated results, equivalent to binding and fetching for each set + # of values and connecting via [rbind()]. + skip_if_not_dbitest(ctx, "1.7.99.12") placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -240,6 +277,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_repeated = function(ctx, con) { + # + # `dbBind()` also accepts repeated calls on the same result set + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -267,6 +307,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_repeated_untouched = function(ctx, con) { + # + # even if no results are fetched between calls to `dbBind()`, + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -290,6 +333,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_named_param_shuffle = function(ctx, con) { + # + # If the placeholders in the query are named, + # their order in the `params` argument is not important. placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -313,6 +359,9 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_integer = function(ctx, con) { + # + # At least the following data types are accepted on input (including [NA]): + # - [integer] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -339,6 +388,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_numeric = function(ctx, con) { + # + # - [numeric] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -365,6 +416,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_logical = function(ctx, con) { + # + # - [logical] for Boolean values placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -390,6 +443,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_character = function(ctx, con) { + # + # - [character] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -418,6 +473,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_character_escape = function(ctx, con) { + # + # (also with special characters such as spaces, newlines, quotes, and backslashes) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -450,7 +507,10 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_factor = function(ctx, con) { - skip_if(ctx$tweaks$dbitest_version < "1.7.99.13") + # + # - [factor] (bound as character, + # with warning) + skip_if_not_dbitest(ctx, "1.7.99.13") placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -479,6 +539,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_date = function(ctx, con) { + # + # - [Date] skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -506,6 +568,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_date_integer = function(ctx, con) { + # + # (also when stored internally as integer) skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -533,6 +597,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_timestamp = function(ctx, con) { + # + # - [POSIXct] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -560,6 +626,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_timestamp_lt = function(ctx, con) { + # + # - [POSIXlt] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -587,6 +655,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_time_seconds = function(ctx, con) { + # + # - [difftime] values skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -614,6 +684,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_time_hours = function(ctx, con) { + # + # (also with units other than seconds skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -641,6 +713,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_time_minutes_integer = function(ctx, con) { + # + # and with the value stored as integer) skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -668,7 +742,10 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_raw = function(ctx, con) { - skip_if(isTRUE(ctx$tweaks$omit_blob_tests) || ctx$tweaks$dbitest_version < "1.7.99.14") + # + # - lists of [raw] for blobs (with `NULL` entries for SQL NULL values) + skip_if_not_dbitest(ctx, "1.7.99.14") + skip_if(isTRUE(ctx$tweaks$omit_blob_tests)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check cast_fun <- ctx$tweaks$blob_cast @@ -695,6 +772,8 @@ spec_meta_arrow_bind <- list( } }, arrow_bind_blob = function(ctx, con) { + # + # - objects of type [blob::blob] skip_if(isTRUE(ctx$tweaks$omit_blob_tests)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check diff --git a/R/spec-meta-bind-expr.R b/R/spec-meta-bind-expr.R index 4a7ad0292..f9290c58e 100644 --- a/R/spec-meta-bind-expr.R +++ b/R/spec-meta-bind-expr.R @@ -24,7 +24,7 @@ spec_meta_bind_expr <- function( expect_false(bind_res$visible) } - #' for queries issued by [dbSendQuery()] or [dbSendQueryArrow()] + #' for queries issued by [dbSendQuery()] or [dbSendQueryArrow()] and test_select_bind_expr( arrow = arrow, bind = bind, @@ -39,7 +39,7 @@ spec_meta_bind_expr <- function( expect_false(bind_res$visible) } - #' and also for data manipulation statements issued by + #' also for data manipulation statements issued by #' [dbSendStatement()]. test_select_bind_expr( arrow = arrow, @@ -214,7 +214,7 @@ spec_meta_bind_expr <- function( arrow = arrow, bind = bind, list(integer(), integer()), - skip_fun = if (arrow == "query" || bind == "stream") function() ctx$tweaks$dbitest_version < "1.7.99.12" + dbitest_version = if (arrow == "query" || bind == "stream") "1.7.99.12" ) #' are supported. @@ -363,7 +363,7 @@ spec_meta_bind_expr <- function( bind = bind, lapply(c(get_texts(), NA_character_), factor), warn = if (bind == "df") TRUE, - skip_fun = if (arrow == "query" && bind == "df") function() ctx$tweaks$dbitest_version < "1.7.99.13" + dbitest_version = if (arrow == "query" && bind == "df") "1.7.99.13" ) }, @@ -372,7 +372,7 @@ spec_meta_bind_expr <- function( test_select_bind_expr( arrow = arrow, bind = bind, - c(Sys.Date() + 0:2, NA), + c(as.Date("2023-12-17") + 0:2, NA), skip_fun = function() !isTRUE(ctx$tweaks$date_typed) ) }, @@ -458,11 +458,8 @@ spec_meta_bind_expr <- function( arrow = arrow, bind = bind, list(list(as.raw(1:10)), list(raw(3)), list(NULL)), - skip_fun = if (arrow == "query" && bind == "df") { - function() isTRUE(ctx$tweaks$omit_blob_tests) || ctx$tweaks$dbitest_version < "1.7.99.14" - } else { - function() isTRUE(ctx$tweaks$omit_blob_tests) - }, + skip_fun = function() isTRUE(ctx$tweaks$omit_blob_tests), + dbitest_version = if (arrow == "query" && bind == "df") "1.7.99.14", cast_fun = ctx$tweaks$blob_cast ) }, diff --git a/R/spec-meta-bind-runner.R b/R/spec-meta-bind-runner.R index fb4072cfe..a8aad1196 100644 --- a/R/spec-meta-bind-runner.R +++ b/R/spec-meta-bind-runner.R @@ -52,12 +52,6 @@ test_select_bind_expr_one$fun <- function( bind_values_patched }) - bind_values_patched_expr <- if (bind == "stream") expr({ - dbBindArrow(res, nanoarrow::as_nanoarrow_array_stream(!!bind_values_patched_expr_base)) - }) else expr({ - dbBind(res, !!bind_values_patched_expr_base) - }) - cast_fun_placeholder_expr <- if (has_cast_fun) expr({ cast_fun(placeholder) }) else expr({ @@ -127,12 +121,12 @@ test_select_bind_expr_one$fun <- function( }) else expr({ on.exit(if (!is.null(res)) expect_error(dbClearResult(res), NA)) !!if (!is.null(check_return_value)) expr({ - #' Until `dbBind()` has been called, the returned result set object has the - #' following behavior: + #' Until [dbBind()] or [dbBindArrow()] have been called, + #' the returned result set object has the following behavior: !!if (query) expr({ - #' - [dbFetch()] raises an error (for `dbSendQuery()`) + #' - [dbFetch()] raises an error (for `dbSendQuery()` and `dbSendQueryArrow()`) expect_error(dbFetch(res)) - #' - [dbGetRowCount()] returns zero (for `dbSendQuery()`) + #' - [dbGetRowCount()] returns zero (for `dbSendQuery()` and `dbSendQueryArrow()`) expect_equal(dbGetRowCount(res), 0) }) else expr({ #' - [dbGetRowsAffected()] returns an integer `NA` (for `dbSendStatement()`) @@ -146,22 +140,23 @@ test_select_bind_expr_one$fun <- function( }) }) - #' 1. Construct a list with parameters - #' that specify actual values for the placeholders. - #' The list must be named or unnamed, - #' depending on the kind of placeholders used. - #' Named values are matched to named parameters, unnamed values - #' are matched by position in the list of parameters. + #' 1. Call [dbBind()] or [dbBindArrow()]: + bind_values_patched_expr <- if (bind == "df") expr({ + #' - For [dbBind()], the `params` argument must be a list where all elements + #' have the same lengths and contain values supported by the backend. + #' A [data.frame] is internally stored as such a list. + dbBind(res, !!bind_values_patched_expr_base) + }) else expr({ + #' - For [dbBindArrow()], the `params` argument must be a + #' nanoarrow array stream, with one column per query parameter. + dbBindArrow(res, nanoarrow::as_nanoarrow_array_stream(!!bind_values_patched_expr_base)) + }) + name_values_expr <- expr({ placeholder <- placeholder_fun(!!length(bind_values)) names(bind_values) <- names(placeholder) }) - #' All elements in this list must have the same lengths and contain values - #' supported by the backend; a [data.frame] is internally stored as such - #' a list. - #' The parameter list is passed to a call to `dbBind()` on the `DBIResult` - #' object. bind_expr <- if (!is.null(check_return_value)) expr({ bind_res <- withVisible(!!bind_values_patched_expr) !!body(check_return_value) @@ -174,8 +169,7 @@ test_select_bind_expr_one$fun <- function( }) #' 1. Retrieve the data or the number of affected rows from the `DBIResult` object. - #' - For queries issued by `dbSendQuery()`, - #' call [dbFetch()]. + #' - For queries issued by `dbSendQuery()` or `dbSendQueryArrow()`, call [dbFetch()]. retrieve_expr <- if (query) expr({ rows <- check_df(dbFetch(res)) expect_equal(nrow(rows), !!length(bind_values[[1]])) @@ -193,7 +187,7 @@ test_select_bind_expr_one$fun <- function( }) else expr({ #' - For statements issued by `dbSendStatements()`, #' call [dbGetRowsAffected()]. - #' (Execution begins immediately after the `dbBind()` call, + #' (Execution begins immediately after the [dbBind()] call, #' the statement is processed entirely before the function returns.) rows_affected <- dbGetRowsAffected(res) # Allow NA value for dbGetRowsAffected(), #297 diff --git a/R/spec-meta-bind-stream.R b/R/spec-meta-bind-stream.R index a2b368221..e1572b0da 100644 --- a/R/spec-meta-bind-stream.R +++ b/R/spec-meta-bind-stream.R @@ -1,9 +1,15 @@ # Generated by helper-dev.R, do not edit by hand +# Sources: R/spec-meta-bind-.R, R/spec-meta-bind-expr.R, R/spec-meta-bind-runner.R -# This file is generated during load_all() if it's older than the input files +# This file is generated during load_all() if it's older than the sources spec_meta_stream_bind <- list( stream_bind_return_value = function(ctx, con) { + # + # @return + # `dbBind()` returns the result set, + # invisibly, + # for queries issued by [dbSendQuery()] or [dbSendQueryArrow()] and placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -32,6 +38,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_return_value_statement = function(ctx, con) { + # + # also for data manipulation statements issued by + # [dbSendStatement()]. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -61,6 +70,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_too_many = function(ctx, con) { + # + # @section Failure modes: + # Binding too many placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -84,6 +96,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_not_enough = function(ctx, con) { + # + # or not enough values, placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -104,6 +118,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_wrong_name = function(ctx, con) { + # + # or parameters with wrong names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -123,6 +139,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_named_param_unnamed_placeholders = function(ctx, con) { + # + # If the placeholders in the query are named, + # all parameter values must have names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -142,6 +161,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_named_param_empty_placeholders = function(ctx, con) { + # + # (which must not be empty placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -165,6 +186,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_named_param_na_placeholders = function(ctx, con) { + # + # or `NA`), placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -188,6 +211,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_unnamed_param_named_placeholders = function(ctx, con) { + # + # and vice versa, + # otherwise an error is raised. placeholder_funs <- get_placeholder_funs(ctx, requires_names = FALSE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -207,6 +233,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_premature_clear = function(ctx, con) { + # + # Calling `dbBind()` on a result set already cleared by [dbClearResult()] + # also raises an error. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -223,6 +252,10 @@ spec_meta_stream_bind <- list( } }, stream_bind_multi_row = function(ctx, con) { + # + # @section Specification: + # The elements of the `params` argument do not need to be scalars, + # vectors of arbitrary length placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -245,7 +278,13 @@ spec_meta_stream_bind <- list( } }, stream_bind_multi_row_zero_length = function(ctx, con) { - skip_if(ctx$tweaks$dbitest_version < "1.7.99.12") + # + # (including length 0) + # are supported. + # For queries, calling `dbFetch()` binding such parameters returns + # concatenated results, equivalent to binding and fetching for each set + # of values and connecting via [rbind()]. + skip_if_not_dbitest(ctx, "1.7.99.12") placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -267,6 +306,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_multi_row_statement = function(ctx, con) { + # + # For data manipulation statements, `dbGetRowsAffected()` returns the + # total number of rows affected if binding non-scalar parameters. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -291,6 +333,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_repeated = function(ctx, con) { + # + # `dbBind()` also accepts repeated calls on the same result set + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -318,6 +363,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_repeated_statement = function(ctx, con) { + # + # and data manipulation statements, placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -347,6 +394,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_repeated_untouched = function(ctx, con) { + # + # even if no results are fetched between calls to `dbBind()`, + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -370,6 +420,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_repeated_untouched_statement = function(ctx, con) { + # + # and data manipulation statements. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -395,6 +447,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_named_param_shuffle = function(ctx, con) { + # + # If the placeholders in the query are named, + # their order in the `params` argument is not important. placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -418,6 +473,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_integer = function(ctx, con) { + # + # At least the following data types are accepted on input (including [NA]): + # - [integer] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -444,6 +502,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_numeric = function(ctx, con) { + # + # - [numeric] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -470,6 +530,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_logical = function(ctx, con) { + # + # - [logical] for Boolean values placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -495,6 +557,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_character = function(ctx, con) { + # + # - [character] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -526,6 +590,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_character_escape = function(ctx, con) { + # + # (also with special characters such as spaces, newlines, quotes, and backslashes) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -561,6 +627,9 @@ spec_meta_stream_bind <- list( } }, stream_bind_factor = function(ctx, con) { + # + # - [factor] (bound as character, + # with warning) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -592,6 +661,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_date = function(ctx, con) { + # + # - [Date] skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -622,6 +693,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_date_integer = function(ctx, con) { + # + # (also when stored internally as integer) skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -652,6 +725,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_timestamp = function(ctx, con) { + # + # - [POSIXct] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -682,6 +757,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_timestamp_lt = function(ctx, con) { + # + # - [POSIXlt] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -712,6 +789,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_time_seconds = function(ctx, con) { + # + # - [difftime] values skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -742,6 +821,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_time_hours = function(ctx, con) { + # + # (also with units other than seconds skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -772,6 +853,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_time_minutes_integer = function(ctx, con) { + # + # and with the value stored as integer) skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -802,6 +885,8 @@ spec_meta_stream_bind <- list( } }, stream_bind_blob = function(ctx, con) { + # + # - objects of type [blob::blob] skip_if(isTRUE(ctx$tweaks$omit_blob_tests)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check diff --git a/R/spec-meta-bind.R b/R/spec-meta-bind.R index db104a451..ce0b4a266 100644 --- a/R/spec-meta-bind.R +++ b/R/spec-meta-bind.R @@ -1,9 +1,15 @@ # Generated by helper-dev.R, do not edit by hand +# Sources: R/spec-meta-bind-.R, R/spec-meta-bind-expr.R, R/spec-meta-bind-runner.R -# This file is generated during load_all() if it's older than the input files +# This file is generated during load_all() if it's older than the sources spec_meta_bind <- list( bind_return_value = function(ctx, con) { + # + # @return + # `dbBind()` returns the result set, + # invisibly, + # for queries issued by [dbSendQuery()] or [dbSendQueryArrow()] and placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -32,6 +38,9 @@ spec_meta_bind <- list( } }, bind_return_value_statement = function(ctx, con) { + # + # also for data manipulation statements issued by + # [dbSendStatement()]. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -61,6 +70,9 @@ spec_meta_bind <- list( } }, bind_too_many = function(ctx, con) { + # + # @section Failure modes: + # Binding too many placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -84,6 +96,8 @@ spec_meta_bind <- list( } }, bind_not_enough = function(ctx, con) { + # + # or not enough values, placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -104,6 +118,8 @@ spec_meta_bind <- list( } }, bind_wrong_name = function(ctx, con) { + # + # or parameters with wrong names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -123,6 +139,9 @@ spec_meta_bind <- list( } }, bind_multi_row_unequal_length = function(ctx, con) { + # + # or unequal length, + # also raises an error. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -148,6 +167,9 @@ spec_meta_bind <- list( } }, bind_named_param_unnamed_placeholders = function(ctx, con) { + # + # If the placeholders in the query are named, + # all parameter values must have names placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -167,6 +189,8 @@ spec_meta_bind <- list( } }, bind_named_param_empty_placeholders = function(ctx, con) { + # + # (which must not be empty placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -190,6 +214,8 @@ spec_meta_bind <- list( } }, bind_named_param_na_placeholders = function(ctx, con) { + # + # or `NA`), placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -213,6 +239,9 @@ spec_meta_bind <- list( } }, bind_unnamed_param_named_placeholders = function(ctx, con) { + # + # and vice versa, + # otherwise an error is raised. placeholder_funs <- get_placeholder_funs(ctx, requires_names = FALSE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -232,6 +261,9 @@ spec_meta_bind <- list( } }, bind_premature_clear = function(ctx, con) { + # + # Calling `dbBind()` on a result set already cleared by [dbClearResult()] + # also raises an error. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -248,6 +280,10 @@ spec_meta_bind <- list( } }, bind_multi_row = function(ctx, con) { + # + # @section Specification: + # The elements of the `params` argument do not need to be scalars, + # vectors of arbitrary length placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -270,6 +306,12 @@ spec_meta_bind <- list( } }, bind_multi_row_zero_length = function(ctx, con) { + # + # (including length 0) + # are supported. + # For queries, calling `dbFetch()` binding such parameters returns + # concatenated results, equivalent to binding and fetching for each set + # of values and connecting via [rbind()]. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -291,6 +333,9 @@ spec_meta_bind <- list( } }, bind_multi_row_statement = function(ctx, con) { + # + # For data manipulation statements, `dbGetRowsAffected()` returns the + # total number of rows affected if binding non-scalar parameters. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -315,6 +360,9 @@ spec_meta_bind <- list( } }, bind_repeated = function(ctx, con) { + # + # `dbBind()` also accepts repeated calls on the same result set + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -342,6 +390,8 @@ spec_meta_bind <- list( } }, bind_repeated_statement = function(ctx, con) { + # + # and data manipulation statements, placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -371,6 +421,9 @@ spec_meta_bind <- list( } }, bind_repeated_untouched = function(ctx, con) { + # + # even if no results are fetched between calls to `dbBind()`, + # for both queries placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -394,6 +447,8 @@ spec_meta_bind <- list( } }, bind_repeated_untouched_statement = function(ctx, con) { + # + # and data manipulation statements. placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check allow_na_rows_affected <- ctx$tweaks$allow_na_rows_affected @@ -419,6 +474,9 @@ spec_meta_bind <- list( } }, bind_named_param_shuffle = function(ctx, con) { + # + # If the placeholders in the query are named, + # their order in the `params` argument is not important. placeholder_funs <- get_placeholder_funs(ctx, requires_names = TRUE) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -442,6 +500,9 @@ spec_meta_bind <- list( } }, bind_integer = function(ctx, con) { + # + # At least the following data types are accepted on input (including [NA]): + # - [integer] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -468,6 +529,8 @@ spec_meta_bind <- list( } }, bind_numeric = function(ctx, con) { + # + # - [numeric] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -494,6 +557,8 @@ spec_meta_bind <- list( } }, bind_logical = function(ctx, con) { + # + # - [logical] for Boolean values placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -519,6 +584,8 @@ spec_meta_bind <- list( } }, bind_character = function(ctx, con) { + # + # - [character] placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -547,6 +614,8 @@ spec_meta_bind <- list( } }, bind_character_escape = function(ctx, con) { + # + # (also with special characters such as spaces, newlines, quotes, and backslashes) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -579,6 +648,9 @@ spec_meta_bind <- list( } }, bind_factor = function(ctx, con) { + # + # - [factor] (bound as character, + # with warning) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check for (placeholder_fun in placeholder_funs) { @@ -607,6 +679,8 @@ spec_meta_bind <- list( } }, bind_date = function(ctx, con) { + # + # - [Date] skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -634,6 +708,8 @@ spec_meta_bind <- list( } }, bind_date_integer = function(ctx, con) { + # + # (also when stored internally as integer) skip_if(!isTRUE(ctx$tweaks$date_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -661,6 +737,8 @@ spec_meta_bind <- list( } }, bind_timestamp = function(ctx, con) { + # + # - [POSIXct] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -688,6 +766,8 @@ spec_meta_bind <- list( } }, bind_timestamp_lt = function(ctx, con) { + # + # - [POSIXlt] timestamps skip_if(!isTRUE(ctx$tweaks$timestamp_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -715,6 +795,8 @@ spec_meta_bind <- list( } }, bind_time_seconds = function(ctx, con) { + # + # - [difftime] values skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -742,6 +824,8 @@ spec_meta_bind <- list( } }, bind_time_hours = function(ctx, con) { + # + # (also with units other than seconds skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -769,6 +853,8 @@ spec_meta_bind <- list( } }, bind_time_minutes_integer = function(ctx, con) { + # + # and with the value stored as integer) skip_if(!isTRUE(ctx$tweaks$time_typed)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -796,6 +882,8 @@ spec_meta_bind <- list( } }, bind_raw = function(ctx, con) { + # + # - lists of [raw] for blobs (with `NULL` entries for SQL NULL values) skip_if(isTRUE(ctx$tweaks$omit_blob_tests)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check @@ -823,6 +911,8 @@ spec_meta_bind <- list( } }, bind_blob = function(ctx, con) { + # + # - objects of type [blob::blob] skip_if(isTRUE(ctx$tweaks$omit_blob_tests)) placeholder_funs <- get_placeholder_funs(ctx) is_null_check <- ctx$tweaks$is_null_check diff --git a/R/spec-meta-get-statement.R b/R/spec-meta-get-statement.R index da4a01003..9a471eae6 100644 --- a/R/spec-meta-get-statement.R +++ b/R/spec-meta-get-statement.R @@ -13,7 +13,7 @@ spec_meta_get_statement <- list( #' @return #' `dbGetStatement()` returns a string, the query used in query <- trivial_query() - #' either [dbSendQuery()] + #' either [dbSendQuery()] or res <- local_result(dbSendQuery(con, query)) s <- dbGetStatement(res) expect_type(s, "character") @@ -22,7 +22,7 @@ spec_meta_get_statement <- list( # get_statement_statement = function(con, table_name) { query <- paste0("CREATE TABLE ", table_name, " (a integer)") - #' or [dbSendStatement()]. + #' [dbSendStatement()]. res <- local_result(dbSendStatement(con, query)) s <- dbGetStatement(res) expect_type(s, "character") diff --git a/R/spec-result-fetch.R b/R/spec-result-fetch.R index 3cbcc1bbf..0b434f1c3 100644 --- a/R/spec-result-fetch.R +++ b/R/spec-result-fetch.R @@ -11,8 +11,8 @@ spec_result_fetch <- list( fetch_atomic = function(con) { #' @return - #' `dbFetch()` always returns a [data.frame] - #' with as many rows as records were fetched and as many + #' `dbFetch()` always returns a [data.frame] with + #' as many rows as records were fetched and as many #' columns as fields in the result set, #' even if the result is a single value query <- trivial_query() @@ -87,8 +87,8 @@ spec_result_fetch <- list( fetch_no_return_value = function(con, table_name) { #' #' Calling `dbFetch()` on a result set from a data manipulation query - #' created by [dbSendStatement()] - #' can be fetched and return an empty data frame, with a warning. + #' created by [dbSendStatement()] can + #' be fetched and return an empty data frame, with a warning. query <- paste0("CREATE TABLE ", table_name, " (a integer)") res <- local_result(dbSendStatement(con, query)) @@ -124,11 +124,11 @@ spec_result_fetch <- list( result <- trivial_df(25) res <- local_result(dbSendQuery(con, query)) - #' by passing a whole number ([integer] + #' by passing a whole number ([integer] or rows <- check_df(dbFetch(res, 10L)) expect_identical(rows, unrowname(result[1:10, , drop = FALSE])) - #' or [numeric]) + #' [numeric]) rows <- check_df(dbFetch(res, 10)) expect_identical(rows, unrowname(result[11:20, , drop = FALSE])) diff --git a/R/spec-result-get-query.R b/R/spec-result-get-query.R index 5c28d2889..546e11fef 100644 --- a/R/spec-result-get-query.R +++ b/R/spec-result-get-query.R @@ -11,8 +11,8 @@ spec_result_get_query <- list( get_query_atomic = function(con) { #' @return - #' `dbGetQuery()` always returns a [data.frame] - #' with as many rows as records were fetched and as many + #' `dbGetQuery()` always returns a [data.frame], with + #' as many rows as records were fetched and as many #' columns as fields in the result set, #' even if the result is a single value query <- trivial_query() @@ -211,7 +211,7 @@ spec_result_get_query <- list( #' 1. `params` not given: waiting for parameters via [dbBind()] #' 1. `params` given: query is executed res <- expect_visible(dbGetQuery(con, trivial_query(), immediate = TRUE)) - expect_s3_class(res, "data.frame") + check_df(res) }, # NULL diff --git a/R/spec-result-roundtrip.R b/R/spec-result-roundtrip.R index 1ff19a547..b826b8f36 100644 --- a/R/spec-result-roundtrip.R +++ b/R/spec-result-roundtrip.R @@ -365,7 +365,7 @@ equals_minus_100 <- function(x) { } all_have_utf8_or_ascii_encoding <- function(x) { - all(vapply(x, has_utf8_or_ascii_encoding, logical(1L))) + all(map_lgl(x, has_utf8_or_ascii_encoding)) } has_utf8_or_ascii_encoding <- function(x) { diff --git a/R/spec-sql-append-table.R b/R/spec-sql-append-table.R index 6442b91c6..037410bdb 100644 --- a/R/spec-sql-append-table.R +++ b/R/spec-sql-append-table.R @@ -64,9 +64,9 @@ spec_sql_append_table <- list( append_table_error = function(con, table_name) { #' An error is also raised test_in <- data.frame(a = 1L) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbAppendTable(con, NA, test_in)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbAppendTable(con, c("test", "test"), test_in)) #' Invalid values for the `row.names` argument @@ -416,7 +416,7 @@ spec_sql_append_table <- list( use_append = TRUE, con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) @@ -457,7 +457,7 @@ spec_sql_append_table <- list( use_append = TRUE, con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) diff --git a/R/spec-sql-create-table.R b/R/spec-sql-create-table.R index b67c10910..ba4295556 100644 --- a/R/spec-sql-create-table.R +++ b/R/spec-sql-create-table.R @@ -43,9 +43,9 @@ spec_sql_create_table <- list( create_table_error = function(ctx, con, table_name) { #' An error is also raised test_in <- data.frame(a = 1L) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbCreateTable(con, NA, test_in)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbCreateTable(con, c(table_name, table_name), test_in)) #' Invalid values for the `row.names` and `temporary` arguments @@ -119,8 +119,32 @@ spec_sql_create_table <- list( } }, + create_table_value_df = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.9") + + #' + #' The `value` argument can be: + #' - a data frame, + table_name <- "ct_df" + local_remove_test_table(con, table_name) + df <- data.frame(a = 1) + dbCreateTable(con, table_name, df) + expect_equal_df(dbReadTable(con, table_name), data.frame(a = numeric())) + }, + + create_table_value_array = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.8.0.10") + + #' - a named list of SQL types + table_name <- "ct_array" + local_remove_test_table(con, table_name) + array <- list(a = "NUMERIC") + dbCreateTable(con, table_name, array) + expect_equal_df(dbReadTable(con, table_name), data.frame(a = numeric())) + }, + #' - create_temporary_table = function(ctx, con, table_name = "dbit03") { + create_table_temporary_1 = function(ctx, con, table_name = "dbit03") { #' If the `temporary` argument is `TRUE`, the table is not available in a #' second connection and is gone after reconnecting. #' Not all backends support this argument. @@ -137,15 +161,24 @@ spec_sql_create_table <- list( expect_error(dbReadTable(con2, table_name)) }, # second stage - create_temporary_table = function(con) { + create_table_temporary_2 = function(ctx, con) { + if (!isTRUE(ctx$tweaks$temporary_tables)) { + skip("tweak: temporary_tables") + } + + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit03" + expect_error(dbReadTable(con, table_name)) }, - create_table_visible_in_other_connection = function(ctx, local_con) { + create_table_visible_in_other_connection_1 = function(ctx, local_con) { #' A regular, non-temporary table is visible in a second connection, penguins <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit04" dbCreateTable(local_con, table_name, penguins) penguins_out <- check_df(dbReadTable(local_con, table_name)) @@ -155,16 +188,18 @@ spec_sql_create_table <- list( expect_equal_df(dbReadTable(con2, table_name), penguins[0, , drop = FALSE]) }, # second stage - create_table_visible_in_other_connection = function(ctx, con) { + create_table_visible_in_other_connection_2 = function(ctx, con) { penguins <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit04" #' in a pre-existing connection, expect_equal_df(check_df(dbReadTable(con, table_name)), penguins[0, , drop = FALSE]) }, # third stage - create_table_visible_in_other_connection = function(ctx, local_con, table_name = "dbit04") { + create_table_visible_in_other_connection_3 = function(ctx, local_con, table_name = "dbit04") { penguins <- get_penguins(ctx) #' and after reconnecting to the database. diff --git a/R/spec-sql-exists-table.R b/R/spec-sql-exists-table.R index 587cf6ead..9bd197dda 100644 --- a/R/spec-sql-exists-table.R +++ b/R/spec-sql-exists-table.R @@ -9,7 +9,7 @@ spec_sql_exists_table <- list( expect_equal(names(formals(dbExistsTable)), c("conn", "name", "...")) }, - exists_table = function(ctx, con, table_name = "dbit05") { + exists_table_1 = function(ctx, con, table_name = "dbit05") { #' @return #' `dbExistsTable()` returns a logical scalar, `TRUE` if the table or view #' specified by the `name` argument exists, `FALSE` otherwise. @@ -20,7 +20,9 @@ spec_sql_exists_table <- list( expect_true(expect_visible(dbExistsTable(con, table_name))) }, # second stage - exists_table = function(ctx, con) { + exists_table_2 = function(ctx, con) { + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit05" expect_false(expect_visible(dbExistsTable(con, table_name))) }, @@ -51,9 +53,9 @@ spec_sql_exists_table <- list( exists_table_error = function(con, table_name) { #' An error is also raised dbWriteTable(con, table_name, data.frame(a = 1L)) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbExistsTable(con, NA)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbExistsTable(con, c(table_name, table_name))) }, diff --git a/R/spec-sql-list-objects.R b/R/spec-sql-list-objects.R index 22a2a90a6..aa4ce1c95 100644 --- a/R/spec-sql-list-objects.R +++ b/R/spec-sql-list-objects.R @@ -9,7 +9,7 @@ spec_sql_list_objects <- list( expect_equal(names(formals(dbListObjects)), c("conn", "prefix", "...")) }, - list_objects = function(ctx, con, table_name = "dbit06") { + list_objects_1 = function(ctx, con, table_name = "dbit06") { #' @return #' `dbListObjects()` objects <- dbListObjects(con) @@ -37,23 +37,25 @@ spec_sql_list_objects <- list( #' accessible from the prefix (if passed) or from the global namespace #' (if prefix is omitted). - #' Tables added with [dbWriteTable()] + #' Tables added with [dbWriteTable()] are penguins <- get_penguins(ctx) dbWriteTable(con, table_name, penguins) - #' are part of the data frame. + #' part of the data frame. objects <- dbListObjects(con) - quoted_tables <- vapply(objects$table, dbQuoteIdentifier, conn = con, character(1)) + quoted_tables <- map_chr(objects$table, dbQuoteIdentifier, conn = con) expect_true(dbQuoteIdentifier(con, table_name) %in% quoted_tables) }, # second stage - list_objects = function(ctx, con) { - #' As soon a table is removed from the database, - #' it is also removed from the data frame of database objects. + list_objects_2 = function(ctx, con) { + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit06" + #' As soon a table is removed from the database, + #' it is also removed from the data frame of database objects. objects <- dbListObjects(con) - quoted_tables <- vapply(objects$table, dbQuoteIdentifier, conn = con, character(1)) + quoted_tables <- map_chr(objects$table, dbQuoteIdentifier, conn = con) expect_false(dbQuoteIdentifier(con, table_name) %in% quoted_tables) }, @@ -64,7 +66,7 @@ spec_sql_list_objects <- list( dbWriteTable(con, table_name, data.frame(a = 1L), temporary = TRUE) objects <- dbListObjects(con) - quoted_tables <- vapply(objects$table, dbQuoteIdentifier, conn = con, character(1)) + quoted_tables <- map_chr(objects$table, dbQuoteIdentifier, conn = con) expect_true(dbQuoteIdentifier(con, table_name) %in% quoted_tables) } }, @@ -82,7 +84,7 @@ spec_sql_list_objects <- list( local_remove_test_table(con, table_name) dbWriteTable(con, dbQuoteIdentifier(con, table_name), data.frame(a = 2L)) objects <- dbListObjects(con) - quoted_tables <- vapply(objects$table, dbQuoteIdentifier, conn = con, character(1)) + quoted_tables <- map_chr(objects$table, dbQuoteIdentifier, conn = con) expect_true(dbQuoteIdentifier(con, table_name) %in% quoted_tables) } }, @@ -108,27 +110,19 @@ spec_sql_list_objects <- list( #' For a call with the default `prefix = NULL`, the `table` #' values that have `is_prefix == FALSE` correspond to the tables #' returned from [dbListTables()], - non_prefix_objects <- vapply( + non_prefix_objects <- map_chr( objects$table[!objects$is_prefix], dbQuoteIdentifier, - conn = con, - character(1) + conn = con ) all_tables <- dbQuoteIdentifier(con, dbListTables(con)) expect_equal(sort(non_prefix_objects), sort(as.character(all_tables))) #' #' The `table` object can be quoted with [dbQuoteIdentifier()]. - sql <- lapply(objects$table[!objects$is_prefix], dbQuoteIdentifier, conn = con) + sql <- map(objects$table[!objects$is_prefix], dbQuoteIdentifier, conn = con) #' The result of quoting can be passed to [dbUnquoteIdentifier()]. - #' (We have to assume that the resulting identifier is a table, because one - #' cannot always tell from a quoted identifier alone whether it is a table - #' or a schema for example. As a consequence, the quote-unquote roundtrip - #' only works for tables (possibly schema-qualified), but not for other - #' database objects like schemata or columns.) - unquoted <- vapply(sql, dbUnquoteIdentifier, conn = con, list(1)) - #' The unquoted results are equal to the original `table` object. - expect_equal(unquoted, unclass(objects$table[!objects$is_prefix])) + expect_error(walk(sql, dbUnquoteIdentifier, conn = con), NA) #' (For backends it may be convenient to use the [Id] class, but this is #' not required.) diff --git a/R/spec-sql-list-tables.R b/R/spec-sql-list-tables.R index 3f89b678a..4a0914854 100644 --- a/R/spec-sql-list-tables.R +++ b/R/spec-sql-list-tables.R @@ -9,7 +9,7 @@ spec_sql_list_tables <- list( expect_equal(names(formals(dbListTables)), c("conn", "...")) }, - list_tables = function(ctx, con, table_name = "dbit07") { + list_tables_1 = function(ctx, con, table_name = "dbit07") { #' @return #' `dbListTables()` tables <- dbListTables(con) @@ -22,19 +22,22 @@ spec_sql_list_tables <- list( # TODO #' in the database. - #' Tables added with [dbWriteTable()] + #' Tables added with [dbWriteTable()] are penguins <- get_penguins(ctx) dbWriteTable(con, table_name, penguins) - #' are part of the list. + #' part of the list. tables <- dbListTables(con) expect_true(table_name %in% tables) }, # second stage - list_tables = function(ctx, con) { + list_tables_2 = function(ctx, con) { + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test + table_name <- "dbit07" + #' As soon a table is removed from the database, #' it is also removed from the list of database tables. - table_name <- "dbit07" tables <- dbListTables(con) expect_false(table_name %in% tables) }, diff --git a/R/spec-sql-quote-literal.R b/R/spec-sql-quote-literal.R index 8e5b800b2..7f1baf4d0 100644 --- a/R/spec-sql-quote-literal.R +++ b/R/spec-sql-quote-literal.R @@ -75,7 +75,7 @@ spec_sql_quote_literal <- list( #' @section Specification: do_test_literal <- function(x) { #' The returned expression can be used in a `SELECT ...` query, - literals <- vapply(x, dbQuoteLiteral, conn = con, character(1)) + literals <- map_chr(x, dbQuoteLiteral, conn = con) query <- paste0("SELECT ", paste(literals, collapse = ", ")) #' and the value of #' \code{dbGetQuery(paste0("SELECT ", dbQuoteLiteral(x)))[[1]]} @@ -83,9 +83,9 @@ spec_sql_quote_literal <- list( x_out <- check_df(dbGetQuery(con, query)) expect_equal(nrow(x_out), 1L) - is_logical <- vapply(x, is.logical, FUN.VALUE = logical(1)) + is_logical <- map_lgl(x, is.logical) x_out[is_logical] <- lapply(x_out[is_logical], as.logical) - is_numeric <- vapply(x, is.numeric, FUN.VALUE = logical(1)) + is_numeric <- map_lgl(x, is.numeric) x_out[is_numeric] <- lapply(x_out[is_numeric], as.numeric) expect_equal(as.list(unname(x_out)), x) } diff --git a/R/spec-sql-read-table.R b/R/spec-sql-read-table.R index ad5b9ffb8..9bbe43f46 100644 --- a/R/spec-sql-read-table.R +++ b/R/spec-sql-read-table.R @@ -12,8 +12,8 @@ spec_sql_read_table <- list( read_table = function(ctx, con, table_name) { #' @return #' `dbReadTable()` returns a data frame that contains the complete data - #' from the remote table, effectively the result of calling [dbGetQuery()] - #' with `SELECT * FROM `. + #' from the remote table, effectively the result of calling [dbGetQuery()] with + #' `SELECT * FROM `. penguins_in <- get_penguins(ctx) dbWriteTable(con, table_name, penguins_in) penguins_out <- check_df(dbReadTable(con, table_name)) diff --git a/R/spec-sql-remove-table.R b/R/spec-sql-remove-table.R index b0682c188..8310d36f5 100644 --- a/R/spec-sql-remove-table.R +++ b/R/spec-sql-remove-table.R @@ -45,9 +45,9 @@ spec_sql_remove_table <- list( remove_table_error = function(con, table_name) { #' An error is also raised dbWriteTable(con, table_name, data.frame(a = 1L)) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbRemoveTable(con, NA)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbRemoveTable(con, c(table_name, table_name))) }, diff --git a/R/spec-sql-unquote-identifier.R b/R/spec-sql-unquote-identifier.R index 4f86dd1c7..301fc5b13 100644 --- a/R/spec-sql-unquote-identifier.R +++ b/R/spec-sql-unquote-identifier.R @@ -27,12 +27,16 @@ spec_sql_unquote_identifier <- list( letters_out <- dbUnquoteIdentifier(con, letters_in) expect_equal(length(letters_out), length(letters_in)) - #' For an empty character vector this function returns a length-0 object. + #' For an empty vector, this function returns a length-0 object. empty <- character() empty_in <- dbQuoteIdentifier(con, empty) empty_out <- dbUnquoteIdentifier(con, empty_in) expect_equal(length(empty_out), 0) + empty_in <- character() + empty_out <- dbUnquoteIdentifier(con, empty_in) + expect_equal(length(empty_out), 0) + #' The names of the input argument are preserved in the output. unnamed_in <- dbQuoteIdentifier(con, letters) unnamed_out <- dbUnquoteIdentifier(con, unnamed_in) @@ -41,29 +45,39 @@ spec_sql_unquote_identifier <- list( named_out <- dbUnquoteIdentifier(con, named_in) expect_equal(names(named_out), letters[1:3]) - #' When passing the first element of a returned object again to - #' `dbUnquoteIdentifier()` as `x` - #' argument, it is returned unchanged (but wrapped in a list). + #' If `x` is a value returned by `dbUnquoteIdentifier()`, + #' calling `dbUnquoteIdentifier(..., dbQuoteIdentifier(..., x))` + #' returns `list(x)`. expect_identical(dbUnquoteIdentifier(con, simple_out[[1]]), simple_out) expect_identical(dbUnquoteIdentifier(con, letters_out[[1]]), letters_out[1]) - #' Passing objects of class [Id] should also return them unchanged (but wrapped in a list). + #' If `x` is an object of class [Id], + #' calling `dbUnquoteIdentifier(..., x)` returns `list(x)`. expect_identical(dbUnquoteIdentifier(con, Id(table = "simple")), list(Id(table = "simple"))) #' (For backends it may be most convenient to return [Id] objects #' to achieve this behavior, but this is not required.) }, #' - unquote_identifier_error = function(ctx, con) { + unquote_identifier_plain = function(ctx, con) { + skip_if_not_dbitest(ctx, "1.7.99.15") + + #' Plain character vectors can also be passed to `dbUnquoteIdentifier()`. + expect_identical(dbUnquoteIdentifier(con, "a"), list(Id("a"))) + expect_identical(dbUnquoteIdentifier(con, "a.b"), list(Id("a", "b"))) + expect_identical(dbUnquoteIdentifier(con, "a.b.c"), list(Id("a", "b", "c"))) + expect_identical(dbUnquoteIdentifier(con, "a.b.c.d"), list(Id("a", "b", "c", "d"))) + }, + #' + unquote_identifier_error = function(con) { #' @section Failure modes: #' - #' An error is raised if plain character vectors are passed as the `x` - #' argument. + #' An error is raised if a character vectors with a missing value is passed + #' as the `x` argument. expect_error(dbUnquoteIdentifier(con, NA_character_)) expect_error(dbUnquoteIdentifier(con, c("a", NA_character_))) - expect_error(dbUnquoteIdentifier(con, character())) }, - unquote_identifier_roundtrip = function(ctx, con) { + unquote_identifier_roundtrip = function(con) { #' @section Specification: #' For any character vector of length one, quoting (with [dbQuoteIdentifier()]) #' then unquoting then quoting the first element is identical to just quoting. @@ -124,9 +138,9 @@ spec_sql_unquote_identifier <- list( }, #' - unquote_identifier_simple = function(ctx, con) { - #' Unquoting simple strings (consisting of only letters) wrapped with [SQL()] - #' and then quoting via [dbQuoteIdentifier()] gives the same result as just + unquote_identifier_simple = function(con) { + #' Unquoting simple strings (consisting of only letters) wrapped with [SQL()] and + #' then quoting via [dbQuoteIdentifier()] gives the same result as just #' quoting the string. simple_in <- "simple" simple_quoted <- dbQuoteIdentifier(con, simple_in) @@ -138,10 +152,10 @@ spec_sql_unquote_identifier <- list( unquote_identifier_table_schema = function(ctx, con) { #' Similarly, unquoting expressions of the form `SQL("schema.table")` #' and then quoting gives the same result as quoting the identifier - #' constructed by `Id(schema = "schema", table = "table")`. + #' constructed by `Id("schema", "table")`. schema_in <- "schema" table_in <- "table" - simple_quoted <- dbQuoteIdentifier(con, Id(schema = schema_in, table = table_in)) + simple_quoted <- dbQuoteIdentifier(con, Id(schema_in, table_in)) simple_out <- dbUnquoteIdentifier(con, SQL(paste0(schema_in, ".", table_in))) simple_roundtrip <- dbQuoteIdentifier(con, simple_out[[1]]) expect_identical(simple_roundtrip, simple_quoted) diff --git a/R/spec-sql-write-table.R b/R/spec-sql-write-table.R index d11c32d44..9ac23c793 100644 --- a/R/spec-sql-write-table.R +++ b/R/spec-sql-write-table.R @@ -54,9 +54,9 @@ spec_sql_write_table <- list( write_table_error = function(ctx, con, table_name) { #' An error is also raised test_in <- data.frame(a = 1L) - #' if `name` cannot be processed with [dbQuoteIdentifier()] + #' if `name` cannot be processed with [dbQuoteIdentifier()] or expect_error(dbWriteTable(con, NA, test_in)) - #' or if this results in a non-scalar. + #' if this results in a non-scalar. expect_error(dbWriteTable(con, c(table_name, table_name), test_in)) #' Invalid values for the additional arguments `row.names`, @@ -237,7 +237,7 @@ spec_sql_write_table <- list( }, #' - temporary_table = function(ctx, con, table_name = "dbit08") { + temporary_table_1 = function(ctx, con, table_name = "dbit08") { #' If the `temporary` argument is `TRUE`, the table is not available in a #' second connection and is gone after reconnecting. #' Not all backends support this argument. @@ -254,19 +254,23 @@ spec_sql_write_table <- list( expect_error(dbReadTable(con2, table_name)) }, # second stage - temporary_table = function(ctx, con) { + temporary_table_2 = function(ctx, con) { if (!isTRUE(ctx$tweaks$temporary_tables)) { skip("tweak: temporary_tables") } + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit08" expect_error(dbReadTable(con, table_name)) }, - table_visible_in_other_connection = function(ctx, local_con) { + table_visible_in_other_connection_1 = function(ctx, local_con) { #' A regular, non-temporary table is visible in a second connection, penguins30 <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit09" dbWriteTable(local_con, table_name, penguins30) @@ -277,16 +281,18 @@ spec_sql_write_table <- list( expect_equal_df(dbReadTable(con2, table_name), penguins30) }, # second stage - table_visible_in_other_connection = function(ctx, con) { + table_visible_in_other_connection_2 = function(ctx, con) { #' in a pre-existing connection, penguins30 <- get_penguins(ctx) + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit09" expect_equal_df(check_df(dbReadTable(con, table_name)), penguins30) }, # third stage - table_visible_in_other_connection = function(ctx, local_con, table_name = "dbit09") { + table_visible_in_other_connection_3 = function(ctx, local_con, table_name = "dbit09") { #' and after reconnecting to the database. penguins30 <- get_penguins(ctx) @@ -617,7 +623,7 @@ spec_sql_write_table <- list( test_table_roundtrip( con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) @@ -657,7 +663,7 @@ spec_sql_write_table <- list( test_table_roundtrip( con, tbl_in, transform = function(out) { - dates <- vapply(out, inherits, "POSIXt", FUN.VALUE = logical(1L)) + dates <- map_lgl(out, inherits, "POSIXt") tz <- toupper(names(out)) tz[tz == "LOCAL"] <- "" out[dates] <- Map(lubridate::with_tz, out[dates], tz[dates]) diff --git a/R/spec-stress-connection.R b/R/spec-stress-connection.R index b324a0aee..b2a70ad6d 100644 --- a/R/spec-stress-connection.R +++ b/R/spec-stress-connection.R @@ -12,7 +12,7 @@ spec_stress_connection <- list( } inherit_from_connection <- - vapply(cons, is, class2 = "DBIConnection", logical(1)) + map_lgl(cons, is, class2 = "DBIConnection") expect_true(all(inherit_from_connection)) }, diff --git a/R/spec-transaction-begin-commit-rollback.R b/R/spec-transaction-begin-commit-rollback.R index bfaea5439..b1fd485e2 100644 --- a/R/spec-transaction-begin-commit-rollback.R +++ b/R/spec-transaction-begin-commit-rollback.R @@ -94,10 +94,12 @@ spec_transaction_begin_commit_rollback <- list( if (!success) dbRollback(con) }, - begin_write_commit = function(con) { + begin_write_commit_1 = function(con) { #' Data written in a transaction must persist after the transaction is committed. #' For example, a record that is missing when the transaction is started + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit00" dbWriteTable(con, table_name, data.frame(a = 0L), overwrite = TRUE) @@ -120,7 +122,7 @@ spec_transaction_begin_commit_rollback <- list( expect_equal(check_df(dbReadTable(con, table_name)), data.frame(a = 0:1)) }, # second stage - begin_write_commit = function(con, table_name = "dbit00") { + begin_write_commit_2 = function(con, table_name = "dbit00") { #' and also in a new connection. expect_true(dbExistsTable(con, table_name)) expect_equal(check_df(dbReadTable(con, table_name)), data.frame(a = 0:1)) @@ -150,7 +152,9 @@ spec_transaction_begin_commit_rollback <- list( expect_equal(check_df(dbReadTable(con, table_name)), data.frame(a = 0L)) }, # - begin_write_disconnect = function(local_con) { + begin_write_disconnect_1 = function(local_con) { + # table_name not in formals on purpose: this means that this table won't be + # removed at the end of the test table_name <- "dbit01" #' #' Disconnection from a connection with an open transaction @@ -161,7 +165,7 @@ spec_transaction_begin_commit_rollback <- list( dbWriteTable(local_con, table_name, data.frame(a = 1L), append = TRUE) }, # - begin_write_disconnect = function(local_con, table_name = "dbit01") { + begin_write_disconnect_2 = function(local_con, table_name = "dbit01") { #' effectively rolls back the transaction. #' All data written in such a transaction must be removed after the #' transaction is rolled back. diff --git a/R/test-all.R b/R/test-all.R index ad90223ab..ed13a08a5 100644 --- a/R/test-all.R +++ b/R/test-all.R @@ -13,7 +13,10 @@ #' #' @param skip `[character()]`\cr A vector of regular expressions to match #' against test names; skip test if matching any. -#' The regular expressions are matched against the entire test name. +#' The regular expressions are matched against the entire test name +#' minus a possible suffix `_N` where `N` is a number. +#' For example, `skip = "exists_table"` will skip both +#' `"exists_table_1"` and `"exists_table_2"`. #' @param run_only `[character()]`\cr A vector of regular expressions to match #' against test names; run only these tests. #' The regular expressions are matched against the entire test name. @@ -42,21 +45,8 @@ test_all <- function(skip = NULL, run_only = NULL, ctx = get_default_context()) #' A character vector of regular expressions #' describing the tests to run. #' The regular expressions are matched against the entire test name. -#' @param dblog `[logical(1)]`\cr -#' Set to `FALSE` to disable dblog integration. #' @export -test_some <- function(test, ctx = get_default_context(), dblog = TRUE) { - if (dblog) { - logger <- dblog::make_collect_logger(display = TRUE) - - ctx$cnr <- dblog::dblog_cnr(ctx$cnr, logger) - ctx$drv <- ctx$cnr@.drv - } - +test_some <- function(test, ctx = get_default_context()) { test_all(run_only = test, skip = character(), ctx = ctx) - - if (dblog && is_interactive()) { - clipr::write_clip(logger$retrieve()) - message("DBI calls written to clipboard.") - } + invisible() } diff --git a/R/tweaks.R b/R/tweaks.R index fee0308cc..e6aad6050 100644 --- a/R/tweaks.R +++ b/R/tweaks.R @@ -145,7 +145,7 @@ make_tweaks <- function(envir = parent.frame()) { } } ret <- .(list_call) - ret <- ret[!vapply(ret, is.null, logical(1L))] + ret <- compact(ret) structure(ret, class = "DBItest_tweaks") }, as.environment(list(list_call = list_call)) diff --git a/R/utils.R b/R/utils.R index 7b4ebc551..b7793d007 100644 --- a/R/utils.R +++ b/R/utils.R @@ -68,11 +68,6 @@ random_table_name <- function(n = 10) { paste0("dbit", paste(sample(letters, n, replace = TRUE), collapse = "")) } -compact <- function(x) { - x[!vapply(x, is.null, logical(1L))] -} - - try_silent <- function(code) { tryCatch( code, @@ -83,7 +78,7 @@ try_silent <- function(code) { check_df <- function(df) { expect_s3_class(df, "data.frame") if (length(df) >= 1L) { - lengths <- vapply(df, length, integer(1L), USE.NAMES = FALSE) + lengths <- unname(lengths(df)) expect_equal(diff(lengths), rep(0L, length(lengths) - 1L)) expect_equal(nrow(df), lengths[[1]]) } @@ -95,6 +90,16 @@ check_df <- function(df) { df } -check_arrow <- function(stream) { - check_df(as.data.frame(stream)) +check_arrow <- function(stream, transform = identity) { + to <- function(schema, ptype) transform(ptype) + if (inherits(stream, "nanoarrow_array_stream")) { + on.exit(stream$release()) + df <- nanoarrow::convert_array_stream(stream, to) + } else if (inherits(stream, "nanoarrow_array")) { + df <- nanoarrow::convert_array(stream, to) + } else { + stop("Unexpected conversion of type ", class(stream), ".", call. = FALSE) + } + + check_df(df) } diff --git a/README.md b/README.md index b3b0e814f..75f9fcaeb 100644 --- a/README.md +++ b/README.md @@ -59,5 +59,5 @@ Further reading: --- Please note that the 'DBItest' project is released with a -[Contributor Code of Conduct](https://dbitest.r-dbi.org/code_of_conduct). +[Contributor Code of Conduct](https://dbitest.r-dbi.org/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. diff --git a/_pkgdown.yml b/_pkgdown.yml index c76fbb5e9..e1c2d5f63 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,8 +1,7 @@ url: https://dbitest.r-dbi.org template: - params: - bootswatch: flatly # https://bootswatch.com/flatly/ + package: dbitemplate home: links: diff --git a/cran-comments.md b/cran-comments.md index 93fcdfe72..43896f747 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,6 +1,17 @@ -DBItest 1.7.3 +Resubmission. + +Resubmission. + +DBItest 1.8.0 + +## R CMD check results + +- [x] Checked locally, R 4.3.2 +- [x] Checked on CI system, R 4.3.2 +- [x] Checked on win-builder, R devel ## Current CRAN check results -- [x] Checked on 2022-10-18, problems found: https://cran.r-project.org/web/checks/check_results_DBItest.html -- [x] NOTE: r-devel-linux-x86_64-debian-clang, r-devel-linux-x86_64-debian-gcc, r-devel-linux-x86_64-fedora-clang, r-devel-linux-x86_64-fedora-gcc, r-devel-windows-x86_64, r-patched-linux-x86_64, r-release-linux-x86_64, r-release-macos-arm64, r-release-macos-x86_64, r-release-windows-x86_64, r-oldrel-macos-arm64, r-oldrel-macos-x86_64, r-oldrel-windows-ix86+x86_64: available in Additional_dependencies +- [x] Checked on 2023-12-21, problems found: https://cran.r-project.org/web/checks/check_results_DBItest.html +- [x] NOTE: r-devel-linux-x86_64-debian-clang, r-devel-linux-x86_64-debian-gcc, r-devel-linux-x86_64-fedora-clang, r-devel-linux-x86_64-fedora-gcc, r-devel-windows-x86_64, r-patched-linux-x86_64, r-release-linux-x86_64, r-release-macos-arm64, r-release-macos-x86_64, r-release-windows-x86_64, r-oldrel-macos-arm64, r-oldrel-windows-x86_64: Additional_repositories + Package suggested but not available for checking: ‘dblog’: Fixed diff --git a/man/spec_arrow_append_table_arrow.Rd b/man/spec_arrow_append_table_arrow.Rd index f4b156185..3db16cfb2 100644 --- a/man/spec_arrow_append_table_arrow.Rd +++ b/man/spec_arrow_append_table_arrow.Rd @@ -21,8 +21,8 @@ an error is raised; the remote table remains unchanged. An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. } \section{Specification}{ @@ -53,10 +53,7 @@ representation and native encodings), supporting empty strings (before and after non-empty strings) -\item factor (returned as character, -with a warning) -\item list of raw -(if supported by the database) +\item factor (possibly returned as character) \item objects of type \link[blob:blob]{blob::blob} (if supported by the database) \item date @@ -97,8 +94,8 @@ The order of the columns does not matter. \seealso{ Other Arrow specifications: \code{\link{spec_arrow_create_table_arrow}}, -\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_fetch_arrow}}, +\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_get_query_arrow}}, \code{\link{spec_arrow_read_table_arrow}}, \code{\link{spec_arrow_send_query_arrow}}, diff --git a/man/spec_arrow_create_table_arrow.Rd b/man/spec_arrow_create_table_arrow.Rd index 7c97845de..b566b9e70 100644 --- a/man/spec_arrow_create_table_arrow.Rd +++ b/man/spec_arrow_create_table_arrow.Rd @@ -17,8 +17,8 @@ If the table exists, an error is raised; the remote table remains unchanged. An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. Invalid values for the \code{temporary} argument (non-scalars, unsupported data types, @@ -51,6 +51,15 @@ perhaps by calling \code{dbQuoteIdentifier(conn, x = name)} \item If the result of a call to \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}}: no more quoting is done } +The \code{value} argument can be: +\itemize{ +\item a data frame, +\item a nanoarrow array +\item a nanoarrow array stream +(which will still contain the data after the call) +\item a nanoarrow schema +} + If the \code{temporary} argument is \code{TRUE}, the table is not available in a second connection and is gone after reconnecting. Not all backends support this argument. @@ -66,8 +75,8 @@ if the database supports non-syntactic identifiers. \seealso{ Other Arrow specifications: \code{\link{spec_arrow_append_table_arrow}}, -\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_fetch_arrow}}, +\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_get_query_arrow}}, \code{\link{spec_arrow_read_table_arrow}}, \code{\link{spec_arrow_send_query_arrow}}, diff --git a/man/spec_arrow_fetch_arrow.Rd b/man/spec_arrow_fetch_arrow.Rd index e770fc2da..b5b2b07af 100644 --- a/man/spec_arrow_fetch_arrow.Rd +++ b/man/spec_arrow_fetch_arrow.Rd @@ -5,8 +5,8 @@ \alias{spec_arrow_fetch_arrow} \title{spec_arrow_fetch_arrow} \value{ -\code{dbFetchArrow()} always returns an object coercible to a \link{data.frame} -with as many rows as records were fetched and as many +\code{dbFetchArrow()} always returns an object coercible to a \link{data.frame} with +as many rows as records were fetched and as many columns as fields in the result set, even if the result is a single value or has one diff --git a/man/spec_arrow_fetch_arrow_chunk.Rd b/man/spec_arrow_fetch_arrow_chunk.Rd index c91c31637..58fe76a8d 100644 --- a/man/spec_arrow_fetch_arrow_chunk.Rd +++ b/man/spec_arrow_fetch_arrow_chunk.Rd @@ -5,8 +5,8 @@ \alias{spec_arrow_fetch_arrow_chunk} \title{spec_arrow_fetch_arrow_chunk} \value{ -\code{dbFetchArrowChunk()} always returns an object coercible to a \link{data.frame} -with as many rows as records were fetched and as many +\code{dbFetchArrowChunk()} always returns an object coercible to a \link{data.frame} with +as many rows as records were fetched and as many columns as fields in the result set, even if the result is a single value or has one diff --git a/man/spec_arrow_get_query_arrow.Rd b/man/spec_arrow_get_query_arrow.Rd index a23ec155c..9ca08a479 100644 --- a/man/spec_arrow_get_query_arrow.Rd +++ b/man/spec_arrow_get_query_arrow.Rd @@ -5,8 +5,8 @@ \alias{spec_arrow_get_query_arrow} \title{spec_arrow_get_query_arrow} \value{ -\code{dbGetQueryArrow()} always returns an object coercible to a \link{data.frame} -with as many rows as records were fetched and as many +\code{dbGetQueryArrow()} always returns an object coercible to a \link{data.frame}, with +as many rows as records were fetched and as many columns as fields in the result set, even if the result is a single value or has one @@ -28,12 +28,70 @@ in batches. The chunk size is implementation-specific. } +\section{Additional arguments}{ + +The following arguments are not part of the \code{dbGetQueryArrow()} generic +(to improve compatibility across backends) +but are part of the DBI specification: +\itemize{ +\item \code{params} (default: \code{NULL}) +\item \code{immediate} (default: \code{NULL}) +} + +They must be provided as named arguments. +See the "Specification" and "Value" sections for details on their usage. + +The \code{param} argument allows passing query parameters, see \code{\link[=dbBind]{dbBind()}} for details. +} + +\section{Specification for the \code{immediate} argument}{ + + +The \code{immediate} argument supports distinguishing between "direct" +and "prepared" APIs offered by many database drivers. +Passing \code{immediate = TRUE} leads to immediate execution of the +query or statement, via the "direct" API (if supported by the driver). +The default \code{NULL} means that the backend should choose whatever API +makes the most sense for the database, and (if relevant) tries the +other API if the first attempt fails. A successful second attempt +should result in a message that suggests passing the correct +\code{immediate} argument. +Examples for possible behaviors: +\enumerate{ +\item DBI backend defaults to \code{immediate = TRUE} internally +\enumerate{ +\item A query without parameters is passed: query is executed +\item A query with parameters is passed: +\enumerate{ +\item \code{params} not given: rejected immediately by the database +because of a syntax error in the query, the backend tries +\code{immediate = FALSE} (and gives a message) +\item \code{params} given: query is executed using \code{immediate = FALSE} +} +} +\item DBI backend defaults to \code{immediate = FALSE} internally +\enumerate{ +\item A query without parameters is passed: +\enumerate{ +\item simple query: query is executed +\item "special" query (such as setting a config options): fails, +the backend tries \code{immediate = TRUE} (and gives a message) +} +\item A query with parameters is passed: +\enumerate{ +\item \code{params} not given: waiting for parameters via \code{\link[=dbBind]{dbBind()}} +\item \code{params} given: query is executed +} +} +} +} + \seealso{ Other Arrow specifications: \code{\link{spec_arrow_append_table_arrow}}, \code{\link{spec_arrow_create_table_arrow}}, -\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_fetch_arrow}}, +\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_read_table_arrow}}, \code{\link{spec_arrow_send_query_arrow}}, \code{\link{spec_arrow_write_table_arrow}}, diff --git a/man/spec_arrow_read_table_arrow.Rd b/man/spec_arrow_read_table_arrow.Rd index 9f185d457..f2c66da84 100644 --- a/man/spec_arrow_read_table_arrow.Rd +++ b/man/spec_arrow_read_table_arrow.Rd @@ -5,11 +5,11 @@ \alias{spec_arrow_read_table_arrow} \title{spec_arrow_read_table_arrow} \value{ -\code{dbReadTableArrow()} returns a data frame that contains the complete data -from the remote table, effectively the result of calling \code{\link[=dbGetQuery]{dbGetQuery()}} -with \verb{SELECT * FROM }. +\code{dbReadTableArrow()} returns an Arrow object that contains the complete data +from the remote table, effectively the result of calling \code{\link[=dbGetQueryArrow]{dbGetQueryArrow()}} with +\verb{SELECT * FROM }. -An empty table is returned as a data frame with zero rows. +An empty table is returned as an Arrow object with zero rows. } \description{ spec_arrow_read_table_arrow @@ -22,8 +22,8 @@ An error is raised if the table does not exist. An error is raised when calling this method for a closed or invalid connection. An error is raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. } \section{Specification}{ @@ -42,8 +42,8 @@ perhaps by calling \code{dbQuoteIdentifier(conn, x = name)} Other Arrow specifications: \code{\link{spec_arrow_append_table_arrow}}, \code{\link{spec_arrow_create_table_arrow}}, -\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_fetch_arrow}}, +\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_get_query_arrow}}, \code{\link{spec_arrow_send_query_arrow}}, \code{\link{spec_arrow_write_table_arrow}}, diff --git a/man/spec_arrow_send_query_arrow.Rd b/man/spec_arrow_send_query_arrow.Rd index 26b90f4c2..40ca7bbbd 100644 --- a/man/spec_arrow_send_query_arrow.Rd +++ b/man/spec_arrow_send_query_arrow.Rd @@ -103,8 +103,8 @@ the backend tries \code{immediate = TRUE} (and gives a message) Other Arrow specifications: \code{\link{spec_arrow_append_table_arrow}}, \code{\link{spec_arrow_create_table_arrow}}, -\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_fetch_arrow}}, +\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_get_query_arrow}}, \code{\link{spec_arrow_read_table_arrow}}, \code{\link{spec_arrow_write_table_arrow}}, diff --git a/man/spec_arrow_write_table_arrow.Rd b/man/spec_arrow_write_table_arrow.Rd index 97c757295..1d0daa553 100644 --- a/man/spec_arrow_write_table_arrow.Rd +++ b/man/spec_arrow_write_table_arrow.Rd @@ -20,16 +20,14 @@ an error is raised; the remote table remains unchanged. An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. Invalid values for the additional arguments \code{overwrite}, \code{append}, and \code{temporary} (non-scalars, unsupported data types, \code{NA}, incompatible values, -duplicate -or missing names, incompatible columns) also raise an error. } @@ -104,9 +102,7 @@ representation and native encodings), supporting empty strings before and after a non-empty string -\item factor (returned as character) -\item list of raw -(if supported by the database) +\item factor (possibly returned as character) \item objects of type \link[blob:blob]{blob::blob} (if supported by the database) \item date @@ -133,8 +129,8 @@ Mixing column types in the same table is supported. Other Arrow specifications: \code{\link{spec_arrow_append_table_arrow}}, \code{\link{spec_arrow_create_table_arrow}}, -\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_fetch_arrow}}, +\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_get_query_arrow}}, \code{\link{spec_arrow_read_table_arrow}}, \code{\link{spec_arrow_send_query_arrow}}, diff --git a/man/spec_driver_constructor.Rd b/man/spec_driver_constructor.Rd index bffe394f1..d5ff91fd8 100644 --- a/man/spec_driver_constructor.Rd +++ b/man/spec_driver_constructor.Rd @@ -9,8 +9,7 @@ spec_driver_constructor } \section{Construction of the DBIDriver object}{ -The backend must support creation of an instance of its \linkS4class{DBIDriver} -subclass +The backend must support creation of an instance of its \linkS4class{DBIDriver} subclass with a \dfn{constructor function}. By default, its name is the package name without the leading \sQuote{R} (if it exists), e.g., \code{SQLite} for the \pkg{RSQLite} package. diff --git a/man/spec_driver_data_type.Rd b/man/spec_driver_data_type.Rd index 48b9bb557..0202d43a7 100644 --- a/man/spec_driver_data_type.Rd +++ b/man/spec_driver_data_type.Rd @@ -42,8 +42,8 @@ this method also must accept lists of \link{raw} vectors, and \link[blob:blob]{blob::blob} objects. As-is objects (i.e., wrapped by \code{\link[=I]{I()}}) must be supported and return the same results as their unwrapped counterparts. -The SQL data type for \link{factor} -and \link{ordered} is the same as for character. +The SQL data type for \link{factor} and +\link{ordered} is the same as for character. The behavior for other object types is not specified. } diff --git a/man/spec_meta_bind.Rd b/man/spec_meta_bind.Rd index aa1654d79..cfcbed0eb 100644 --- a/man/spec_meta_bind.Rd +++ b/man/spec_meta_bind.Rd @@ -8,8 +8,8 @@ \value{ \code{dbBind()} returns the result set, invisibly, -for queries issued by \code{\link[=dbSendQuery]{dbSendQuery()}} or \code{\link[=dbSendQueryArrow]{dbSendQueryArrow()}} -and also for data manipulation statements issued by +for queries issued by \code{\link[=dbSendQuery]{dbSendQuery()}} or \code{\link[=dbSendQueryArrow]{dbSendQueryArrow()}} and +also for data manipulation statements issued by \code{\link[=dbSendStatement]{dbSendStatement()}}. } \description{ @@ -31,33 +31,29 @@ recommended. It is good practice to register a call to \code{\link[=dbClearResult]{dbClearResult()}} via \code{\link[=on.exit]{on.exit()}} right after calling \code{dbSendQuery()} or \code{dbSendStatement()} (see the last enumeration item). -Until \code{dbBind()} has been called, the returned result set object has the -following behavior: +Until \code{\link[=dbBind]{dbBind()}} or \code{\link[=dbBindArrow]{dbBindArrow()}} have been called, +the returned result set object has the following behavior: \itemize{ -\item \code{\link[=dbFetch]{dbFetch()}} raises an error (for \code{dbSendQuery()}) -\item \code{\link[=dbGetRowCount]{dbGetRowCount()}} returns zero (for \code{dbSendQuery()}) +\item \code{\link[=dbFetch]{dbFetch()}} raises an error (for \code{dbSendQuery()} and \code{dbSendQueryArrow()}) +\item \code{\link[=dbGetRowCount]{dbGetRowCount()}} returns zero (for \code{dbSendQuery()} and \code{dbSendQueryArrow()}) \item \code{\link[=dbGetRowsAffected]{dbGetRowsAffected()}} returns an integer \code{NA} (for \code{dbSendStatement()}) \item \code{\link[=dbIsValid]{dbIsValid()}} returns \code{TRUE} \item \code{\link[=dbHasCompleted]{dbHasCompleted()}} returns \code{FALSE} } -\item Construct a list with parameters -that specify actual values for the placeholders. -The list must be named or unnamed, -depending on the kind of placeholders used. -Named values are matched to named parameters, unnamed values -are matched by position in the list of parameters. -All elements in this list must have the same lengths and contain values -supported by the backend; a \link{data.frame} is internally stored as such -a list. -The parameter list is passed to a call to \code{dbBind()} on the \code{DBIResult} -object. +\item Call \code{\link[=dbBind]{dbBind()}} or \code{\link[=dbBindArrow]{dbBindArrow()}}: +\itemize{ +\item For \code{\link[=dbBind]{dbBind()}}, the \code{params} argument must be a list where all elements +have the same lengths and contain values supported by the backend. +A \link{data.frame} is internally stored as such a list. +\item For \code{\link[=dbBindArrow]{dbBindArrow()}}, the \code{params} argument must be a +nanoarrow array stream, with one column per query parameter. +} \item Retrieve the data or the number of affected rows from the \code{DBIResult} object. \itemize{ -\item For queries issued by \code{dbSendQuery()}, -call \code{\link[=dbFetch]{dbFetch()}}. +\item For queries issued by \code{dbSendQuery()} or \code{dbSendQueryArrow()}, call \code{\link[=dbFetch]{dbFetch()}}. \item For statements issued by \code{dbSendStatements()}, call \code{\link[=dbGetRowsAffected]{dbGetRowsAffected()}}. -(Execution begins immediately after the \code{dbBind()} call, +(Execution begins immediately after the \code{\link[=dbBind]{dbBind()}} call, the statement is processed entirely before the function returns.) } \item Repeat 2. and 3. as necessary. diff --git a/man/spec_meta_get_statement.Rd b/man/spec_meta_get_statement.Rd index 9af26860a..c5916fa86 100644 --- a/man/spec_meta_get_statement.Rd +++ b/man/spec_meta_get_statement.Rd @@ -6,8 +6,8 @@ \title{spec_meta_get_statement} \value{ \code{dbGetStatement()} returns a string, the query used in -either \code{\link[=dbSendQuery]{dbSendQuery()}} -or \code{\link[=dbSendStatement]{dbSendStatement()}}. +either \code{\link[=dbSendQuery]{dbSendQuery()}} or +\code{\link[=dbSendStatement]{dbSendStatement()}}. } \description{ spec_meta_get_statement diff --git a/man/spec_result_clear_result.Rd b/man/spec_result_clear_result.Rd index 89e8b50ed..244151c54 100644 --- a/man/spec_result_clear_result.Rd +++ b/man/spec_result_clear_result.Rd @@ -42,8 +42,8 @@ Other result specifications: Other Arrow specifications: \code{\link{spec_arrow_append_table_arrow}}, \code{\link{spec_arrow_create_table_arrow}}, -\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_fetch_arrow}}, +\code{\link{spec_arrow_fetch_arrow_chunk}}, \code{\link{spec_arrow_get_query_arrow}}, \code{\link{spec_arrow_read_table_arrow}}, \code{\link{spec_arrow_send_query_arrow}}, diff --git a/man/spec_result_fetch.Rd b/man/spec_result_fetch.Rd index 96ffd66a3..99b6e237e 100644 --- a/man/spec_result_fetch.Rd +++ b/man/spec_result_fetch.Rd @@ -5,8 +5,8 @@ \alias{spec_result_fetch} \title{spec_result_fetch} \value{ -\code{dbFetch()} always returns a \link{data.frame} -with as many rows as records were fetched and as many +\code{dbFetch()} always returns a \link{data.frame} with +as many rows as records were fetched and as many columns as fields in the result set, even if the result is a single value or has one @@ -25,8 +25,8 @@ greater or equal to -1 or Inf, an error is raised, but a subsequent call to \code{dbFetch()} with proper \code{n} argument succeeds. Calling \code{dbFetch()} on a result set from a data manipulation query -created by \code{\link[=dbSendStatement]{dbSendStatement()}} -can be fetched and return an empty data frame, with a warning. +created by \code{\link[=dbSendStatement]{dbSendStatement()}} can +be fetched and return an empty data frame, with a warning. } \section{Specification}{ @@ -34,8 +34,8 @@ can be fetched and return an empty data frame, with a warning. Fetching multi-row queries with one or more columns by default returns the entire result. Multi-row queries can also be fetched progressively -by passing a whole number (\link{integer} -or \link{numeric}) +by passing a whole number (\link{integer} or +\link{numeric}) as the \code{n} argument. A value of \link{Inf} for the \code{n} argument is supported and also returns the full result. diff --git a/man/spec_result_get_query.Rd b/man/spec_result_get_query.Rd index 7f9fdd2ee..56dbb0a4b 100644 --- a/man/spec_result_get_query.Rd +++ b/man/spec_result_get_query.Rd @@ -5,8 +5,8 @@ \alias{spec_result_get_query} \title{spec_result_get_query} \value{ -\code{dbGetQuery()} always returns a \link{data.frame} -with as many rows as records were fetched and as many +\code{dbGetQuery()} always returns a \link{data.frame}, with +as many rows as records were fetched and as many columns as fields in the result set, even if the result is a single value or has one diff --git a/man/spec_sql_append_table.Rd b/man/spec_sql_append_table.Rd index 7bf370b79..564b45ef2 100644 --- a/man/spec_sql_append_table.Rd +++ b/man/spec_sql_append_table.Rd @@ -21,8 +21,8 @@ an error is raised; the remote table remains unchanged. An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. Invalid values for the \code{row.names} argument (non-scalars, unsupported data types, diff --git a/man/spec_sql_create_table.Rd b/man/spec_sql_create_table.Rd index fef0398a3..4a0c27d70 100644 --- a/man/spec_sql_create_table.Rd +++ b/man/spec_sql_create_table.Rd @@ -17,8 +17,8 @@ If the table exists, an error is raised; the remote table remains unchanged. An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. Invalid values for the \code{row.names} and \code{temporary} arguments (non-scalars, unsupported data types, @@ -51,6 +51,12 @@ perhaps by calling \code{dbQuoteIdentifier(conn, x = name)} \item If the result of a call to \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}}: no more quoting is done } +The \code{value} argument can be: +\itemize{ +\item a data frame, +\item a named list of SQL types +} + If the \code{temporary} argument is \code{TRUE}, the table is not available in a second connection and is gone after reconnecting. Not all backends support this argument. diff --git a/man/spec_sql_exists_table.Rd b/man/spec_sql_exists_table.Rd index c5e319363..8c9e1f737 100644 --- a/man/spec_sql_exists_table.Rd +++ b/man/spec_sql_exists_table.Rd @@ -18,8 +18,8 @@ spec_sql_exists_table An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. } \section{Specification}{ diff --git a/man/spec_sql_list_objects.Rd b/man/spec_sql_list_objects.Rd index 14c08a0ea..69441a166 100644 --- a/man/spec_sql_list_objects.Rd +++ b/man/spec_sql_list_objects.Rd @@ -17,8 +17,8 @@ This data frame contains one row for each object (schema, table and view) accessible from the prefix (if passed) or from the global namespace (if prefix is omitted). -Tables added with \code{\link[=dbWriteTable]{dbWriteTable()}} -are part of the data frame. +Tables added with \code{\link[=dbWriteTable]{dbWriteTable()}} are +part of the data frame. As soon a table is removed from the database, it is also removed from the data frame of database objects. @@ -45,12 +45,6 @@ returned from \code{\link[=dbListTables]{dbListTables()}}, The \code{table} object can be quoted with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}}. The result of quoting can be passed to \code{\link[=dbUnquoteIdentifier]{dbUnquoteIdentifier()}}. -(We have to assume that the resulting identifier is a table, because one -cannot always tell from a quoted identifier alone whether it is a table -or a schema for example. As a consequence, the quote-unquote roundtrip -only works for tables (possibly schema-qualified), but not for other -database objects like schemata or columns.) -The unquoted results are equal to the original \code{table} object. (For backends it may be convenient to use the \link{Id} class, but this is not required.) diff --git a/man/spec_sql_list_tables.Rd b/man/spec_sql_list_tables.Rd index 1b98295c3..8267fe92c 100644 --- a/man/spec_sql_list_tables.Rd +++ b/man/spec_sql_list_tables.Rd @@ -10,8 +10,8 @@ returns a character vector that enumerates all tables and views in the database. -Tables added with \code{\link[=dbWriteTable]{dbWriteTable()}} -are part of the list. +Tables added with \code{\link[=dbWriteTable]{dbWriteTable()}} are +part of the list. As soon a table is removed from the database, it is also removed from the list of database tables. diff --git a/man/spec_sql_read_table.Rd b/man/spec_sql_read_table.Rd index e588a1a8a..d06bbd104 100644 --- a/man/spec_sql_read_table.Rd +++ b/man/spec_sql_read_table.Rd @@ -6,8 +6,8 @@ \title{spec_sql_read_table} \value{ \code{dbReadTable()} returns a data frame that contains the complete data -from the remote table, effectively the result of calling \code{\link[=dbGetQuery]{dbGetQuery()}} -with \verb{SELECT * FROM }. +from the remote table, effectively the result of calling \code{\link[=dbGetQuery]{dbGetQuery()}} with +\verb{SELECT * FROM }. An empty table is returned as a data frame with zero rows. diff --git a/man/spec_sql_remove_table.Rd b/man/spec_sql_remove_table.Rd index 97116b04a..e56d1bac9 100644 --- a/man/spec_sql_remove_table.Rd +++ b/man/spec_sql_remove_table.Rd @@ -18,8 +18,8 @@ An attempt to remove a view with this function may result in an error. An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. } \section{Additional arguments}{ diff --git a/man/spec_sql_unquote_identifier.Rd b/man/spec_sql_unquote_identifier.Rd index 17d1084e2..35f327706 100644 --- a/man/spec_sql_unquote_identifier.Rd +++ b/man/spec_sql_unquote_identifier.Rd @@ -7,14 +7,17 @@ \value{ \code{dbUnquoteIdentifier()} returns a list of objects of the same length as the input. -For an empty character vector this function returns a length-0 object. +For an empty vector, this function returns a length-0 object. The names of the input argument are preserved in the output. -When passing the first element of a returned object again to -\code{dbUnquoteIdentifier()} as \code{x} -argument, it is returned unchanged (but wrapped in a list). -Passing objects of class \link{Id} should also return them unchanged (but wrapped in a list). +If \code{x} is a value returned by \code{dbUnquoteIdentifier()}, +calling \code{dbUnquoteIdentifier(..., dbQuoteIdentifier(..., x))} +returns \code{list(x)}. +If \code{x} is an object of class \link{Id}, +calling \code{dbUnquoteIdentifier(..., x)} returns \code{list(x)}. (For backends it may be most convenient to return \link{Id} objects to achieve this behavior, but this is not required.) + +Plain character vectors can also be passed to \code{dbUnquoteIdentifier()}. } \description{ spec_sql_unquote_identifier @@ -22,8 +25,8 @@ spec_sql_unquote_identifier \section{Failure modes}{ -An error is raised if plain character vectors are passed as the \code{x} -argument. +An error is raised if a character vectors with a missing value is passed +as the \code{x} argument. } \section{Specification}{ @@ -38,12 +41,12 @@ or quotes used to mark strings or identifiers, if the database supports this. -Unquoting simple strings (consisting of only letters) wrapped with \code{\link[=SQL]{SQL()}} -and then quoting via \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} gives the same result as just +Unquoting simple strings (consisting of only letters) wrapped with \code{\link[=SQL]{SQL()}} and +then quoting via \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} gives the same result as just quoting the string. Similarly, unquoting expressions of the form \code{SQL("schema.table")} and then quoting gives the same result as quoting the identifier -constructed by \code{Id(schema = "schema", table = "table")}. +constructed by \code{Id("schema", "table")}. } \seealso{ diff --git a/man/spec_sql_write_table.Rd b/man/spec_sql_write_table.Rd index 6974e8ca9..44e60bd8a 100644 --- a/man/spec_sql_write_table.Rd +++ b/man/spec_sql_write_table.Rd @@ -20,8 +20,8 @@ an error is raised; the remote table remains unchanged. An error is raised when calling this method for a closed or invalid connection. An error is also raised -if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} -or if this results in a non-scalar. +if \code{name} cannot be processed with \code{\link[=dbQuoteIdentifier]{dbQuoteIdentifier()}} or +if this results in a non-scalar. Invalid values for the additional arguments \code{row.names}, \code{overwrite}, \code{append}, \code{field.types}, and \code{temporary} (non-scalars, diff --git a/man/test_all.Rd b/man/test_all.Rd index 58087679c..85a4e12e1 100644 --- a/man/test_all.Rd +++ b/man/test_all.Rd @@ -10,12 +10,15 @@ \usage{ test_all(skip = NULL, run_only = NULL, ctx = get_default_context()) -test_some(test, ctx = get_default_context(), dblog = TRUE) +test_some(test, ctx = get_default_context()) } \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. @@ -28,9 +31,6 @@ The regular expressions are matched against the entire test name.} A character vector of regular expressions describing the tests to run. The regular expressions are matched against the entire test name.} - -\item{dblog}{\verb{[logical(1)]}\cr -Set to \code{FALSE} to disable dblog integration.} } \description{ \code{test_all()} calls all tests defined in this package (see the section diff --git a/man/test_arrow.Rd b/man/test_arrow.Rd index 1f35521d3..dbd032acd 100644 --- a/man/test_arrow.Rd +++ b/man/test_arrow.Rd @@ -9,7 +9,10 @@ test_arrow(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_compliance.Rd b/man/test_compliance.Rd index 20b579ff6..f0055c365 100644 --- a/man/test_compliance.Rd +++ b/man/test_compliance.Rd @@ -9,7 +9,10 @@ test_compliance(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_connection.Rd b/man/test_connection.Rd index 92638b251..a59aaeed6 100644 --- a/man/test_connection.Rd +++ b/man/test_connection.Rd @@ -9,7 +9,10 @@ test_connection(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_data_type.Rd b/man/test_data_type.Rd index a23703c1c..ae8d39a91 100644 --- a/man/test_data_type.Rd +++ b/man/test_data_type.Rd @@ -47,8 +47,8 @@ this method also must accept lists of \link{raw} vectors, and \link[blob:blob]{blob::blob} objects. As-is objects (i.e., wrapped by \code{\link[=I]{I()}}) must be supported and return the same results as their unwrapped counterparts. -The SQL data type for \link{factor} -and \link{ordered} is the same as for character. +The SQL data type for \link{factor} and +\link{ordered} is the same as for character. The behavior for other object types is not specified. } diff --git a/man/test_driver.Rd b/man/test_driver.Rd index f19ea02e6..d05a1410b 100644 --- a/man/test_driver.Rd +++ b/man/test_driver.Rd @@ -9,7 +9,10 @@ test_driver(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_getting_started.Rd b/man/test_getting_started.Rd index 2417173eb..b09de0fe4 100644 --- a/man/test_getting_started.Rd +++ b/man/test_getting_started.Rd @@ -9,7 +9,10 @@ test_getting_started(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_meta.Rd b/man/test_meta.Rd index 9aec163d6..c24048e0e 100644 --- a/man/test_meta.Rd +++ b/man/test_meta.Rd @@ -9,7 +9,10 @@ test_meta(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_result.Rd b/man/test_result.Rd index 4fc3f87e6..326346264 100644 --- a/man/test_result.Rd +++ b/man/test_result.Rd @@ -9,7 +9,10 @@ test_result(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_sql.Rd b/man/test_sql.Rd index b872ecac2..76d867596 100644 --- a/man/test_sql.Rd +++ b/man/test_sql.Rd @@ -9,7 +9,10 @@ test_sql(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/man/test_stress.Rd b/man/test_stress.Rd index 510464dbe..874c5505f 100644 --- a/man/test_stress.Rd +++ b/man/test_stress.Rd @@ -9,7 +9,10 @@ test_stress(skip = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{ctx}{\verb{[DBItest_context]}\cr A test context as created by \code{\link[=make_context]{make_context()}}.} diff --git a/man/test_transaction.Rd b/man/test_transaction.Rd index 3848f98b0..9ad345af8 100644 --- a/man/test_transaction.Rd +++ b/man/test_transaction.Rd @@ -9,7 +9,10 @@ test_transaction(skip = NULL, run_only = NULL, ctx = get_default_context()) \arguments{ \item{skip}{\verb{[character()]}\cr A vector of regular expressions to match against test names; skip test if matching any. -The regular expressions are matched against the entire test name.} +The regular expressions are matched against the entire test name +minus a possible suffix \verb{_N} where \code{N} is a number. +For example, \code{skip = "exists_table"} will skip both +\code{"exists_table_1"} and \code{"exists_table_2"}.} \item{run_only}{\verb{[character()]}\cr A vector of regular expressions to match against test names; run only these tests. diff --git a/revdep-dev/Makefile b/revdep-dev/Makefile index 54af2ad9d..946d20e8b 100644 --- a/revdep-dev/Makefile +++ b/revdep-dev/Makefile @@ -5,7 +5,8 @@ TESTTHAT_REPORTER ?= testthat::ProgressReporter\$$new(max_failures = Inf, update # The REVDEP definition also decides what is run on GitHub Actions in backends.yaml # FIXME: Re-add duckdb, very slow on GitHub Actions # FIXME: Re-add odbc-postgres and odbc-sqlite, broken with new Arrow tests -REVDEP := RMariaDB RSQLite RPostgres RKazam adbi odbc-sql-server odbc-mysql +# FIXME: Re-add RMariaDB RPostgres adbi odbc-sql-server, #343 +REVDEP := RSQLite RKazam odbc-mysql TEST_TARGETS := $(patsubst %,test-%,${REVDEP}) LIB_DIR := $(shell Rscript -e "cat(.libPaths()[1])") diff --git a/revdep/.gitignore b/revdep/.gitignore index 63d0aaae1..3f1eff0b6 100644 --- a/revdep/.gitignore +++ b/revdep/.gitignore @@ -2,3 +2,4 @@ /data.sqlite /library/ /libs/ +/cloud.noindex/ diff --git a/revdep/README.md b/revdep/README.md index 3e0540fbc..52e12c714 100644 --- a/revdep/README.md +++ b/revdep/README.md @@ -1,58 +1,2 @@ -# Platform - -|field |value | -|:--------|:----------------------------| -|version |R version 3.4.3 (2017-11-30) | -|os |Ubuntu 17.10 | -|system |x86_64, linux-gnu | -|ui |X11 | -|language |en_US | -|collate |en_US.UTF-8 | -|tz |Europe/Busingen | -|date |2017-12-10 | - -# Dependencies - -|package |old |new |Δ | -|:----------|:-------|:-------|:--| -|DBItest |1.5 |1.5 |NA | -|assertthat |0.2.0 |0.2.0 |NA | -|backports |1.1.1 |1.1.1 |NA | -|blob |1.1.0 |1.1.0 |NA | -|crayon |1.3.4 |1.3.4 |NA | -|DBI |0.7 |0.7 |NA | -|desc |1.1.1 |1.1.1 |NA | -|digest |0.6.12 |0.6.12 |NA | -|hms |0.4.0 |0.4.0 |NA | -|magrittr |1.5 |1.5 |NA | -|pkgconfig |2.0.1 |2.0.1 |NA | -|praise |1.0.0 |1.0.0 |NA | -|R6 |2.2.2 |2.2.2 |NA | -|Rcpp |0.12.14 |0.12.14 |NA | -|rlang |0.1.4 |0.1.4 |NA | -|rprojroot |1.2 |1.2 |NA | -|testthat |1.0.2 |1.0.2 |NA | -|tibble |1.3.4 |1.3.4 |NA | -|withr |2.1.0 |2.1.0 |NA | - # Revdeps -## Couldn't check (1) - -|package |version |error |warning |note | -|:--------------------------------------|:-------|:-----|:-------|:----| -|[MonetDBLite](problems.md#monetdblite) |0.5.0 |1 | | | - -## All (8) - -|package |version |error |warning |note | -|:--------------------------------------|:-------|:-----|:-------|:----| -|bigrquery |0.4.1 | | | | -|civis |1.1.1 | | | | -|[MonetDBLite](problems.md#monetdblite) |0.5.0 |1 | | | -|[odbc](problems.md#odbc) |1.1.3 | | |1 | -|RMariaDB |1.0-2 | | | | -|[RPostgres](problems.md#rpostgres) |1.0-3 | | |1 -1 | -|[RSQLite](problems.md#rsqlite) |2.0 |-1 | |2 | -|[RSQLServer](problems.md#rsqlserver) |0.3.0 |1 | | | - diff --git a/revdep/cran.md b/revdep/cran.md new file mode 100644 index 000000000..e0bfc1b65 --- /dev/null +++ b/revdep/cran.md @@ -0,0 +1,7 @@ +## revdepcheck results + +We checked 11 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. + + * We saw 0 new problems + * We failed to check 0 packages + diff --git a/revdep/failures.md b/revdep/failures.md new file mode 100644 index 000000000..9a2073633 --- /dev/null +++ b/revdep/failures.md @@ -0,0 +1 @@ +*Wow, no problems at all. :)* \ No newline at end of file diff --git a/revdep/problems.md b/revdep/problems.md index c6644d3d9..9a2073633 100644 --- a/revdep/problems.md +++ b/revdep/problems.md @@ -1,207 +1 @@ -# MonetDBLite - -Version: 0.5.0 - -## In both - -* checking whether package ‘MonetDBLite’ can be installed ... ERROR - ``` - Installation failed. - See ‘/home/muelleki/git/R/DBItest/revdep/checks/MonetDBLite/new/MonetDBLite.Rcheck/00install.out’ for details. - ``` - -## Installation - -### Devel - -``` -* installing *source* package ‘MonetDBLite’ ... -** package ‘MonetDBLite’ successfully unpacked and MD5 sums checked -** libs -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/common/mutils.d -c monetdblite/src/common/mutils.c -o build/objects/monetdblite/common/mutils.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/common/mutils.o' failed -make: *** [build/objects/monetdblite/common/mutils.o] Error 1 -make: *** Waiting for unfinished jobs.... -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_align.d -c monetdblite/src/gdk/gdk_align.c -o build/objects/monetdblite/gdk/gdk_align.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_align.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_align.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_atoms.d -c monetdblite/src/gdk/gdk_atoms.c -o build/objects/monetdblite/gdk/gdk_atoms.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_atoms.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_atoms.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/common/stream.d -c monetdblite/src/common/stream.c -o build/objects/monetdblite/common/stream.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/common/stream.o' failed -make: *** [build/objects/monetdblite/common/stream.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/embedded/embedded.d -c monetdblite/src/embedded/embedded.c -o build/objects/monetdblite/embedded/embedded.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/embedded/embedded.o' failed -make: *** [build/objects/monetdblite/embedded/embedded.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_bat.d -c monetdblite/src/gdk/gdk_bat.c -o build/objects/monetdblite/gdk/gdk_bat.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_bat.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_bat.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_batop.d -c monetdblite/src/gdk/gdk_batop.c -o build/objects/monetdblite/gdk/gdk_batop.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_batop.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_batop.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_aggr.d -c monetdblite/src/gdk/gdk_aggr.c -o build/objects/monetdblite/gdk/gdk_aggr.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_aggr.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_aggr.o] Error 1 -ERROR: compilation failed for package ‘MonetDBLite’ -* removing ‘/home/muelleki/git/R/DBItest/revdep/checks/MonetDBLite/new/MonetDBLite.Rcheck/MonetDBLite’ - -``` -### CRAN - -``` -* installing *source* package ‘MonetDBLite’ ... -** package ‘MonetDBLite’ successfully unpacked and MD5 sums checked -** libs -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/common/mutils.d -c monetdblite/src/common/mutils.c -o build/objects/monetdblite/common/mutils.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/common/mutils.o' failed -make: *** [build/objects/monetdblite/common/mutils.o] Error 1 -make: *** Waiting for unfinished jobs.... -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_align.d -c monetdblite/src/gdk/gdk_align.c -o build/objects/monetdblite/gdk/gdk_align.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_align.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_align.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_atoms.d -c monetdblite/src/gdk/gdk_atoms.c -o build/objects/monetdblite/gdk/gdk_atoms.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_atoms.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_atoms.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/common/stream.d -c monetdblite/src/common/stream.c -o build/objects/monetdblite/common/stream.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/common/stream.o' failed -make: *** [build/objects/monetdblite/common/stream.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_bat.d -c monetdblite/src/gdk/gdk_bat.c -o build/objects/monetdblite/gdk/gdk_bat.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_bat.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_bat.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/embedded/embedded.d -c monetdblite/src/embedded/embedded.c -o build/objects/monetdblite/embedded/embedded.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/embedded/embedded.o' failed -make: *** [build/objects/monetdblite/embedded/embedded.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_batop.d -c monetdblite/src/gdk/gdk_batop.c -o build/objects/monetdblite/gdk/gdk_batop.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_batop.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_batop.o] Error 1 -gcc -std=gnu99 -Wall -pedantic -g -O2 -fdebug-prefix-map=/build/r-base-fCgT8l/r-base-3.4.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -I/usr/share/R/include -DNDEBUG -fpic -Wno-format -DLIBGDK -DLIBMAL -DLIBOPTIMIZER -DLIBSTREAM -DHAVE_EMBEDDED_R -DMONETDBLITE_COMPILE -Imonetdblite/src/ -Imonetdblite/src/common -Imonetdblite/src/embedded -Imonetdblite/src/gdk -Imonetdblite/src/mal/mal -Imonetdblite/src/mal/modules -Imonetdblite/src/mal/optimizer -Imonetdblite/src/mal/sqlbackend -Imonetdblite/src/sql/include -Imonetdblite/src/sql/common -Imonetdblite/src/sql/server -Imonetdblite/src/sql/storage -Imonetdblite/src/sql/storage/bat -MMD -MF build/deps/monetdblite/gdk/gdk_aggr.d -c monetdblite/src/gdk/gdk_aggr.c -o build/objects/monetdblite/gdk/gdk_aggr.o -cc1: error: -Wformat-security ignored without -Wformat [-Werror=format-security] -cc1: some warnings being treated as errors -Makevars:194: recipe for target 'build/objects/monetdblite/gdk/gdk_aggr.o' failed -make: *** [build/objects/monetdblite/gdk/gdk_aggr.o] Error 1 -ERROR: compilation failed for package ‘MonetDBLite’ -* removing ‘/home/muelleki/git/R/DBItest/revdep/checks/MonetDBLite/old/MonetDBLite.Rcheck/MonetDBLite’ - -``` -# odbc - -Version: 1.1.3 - -## In both - -* checking installed package size ... NOTE - ``` - installed size is 6.2Mb - sub-directories of 1Mb or more: - libs 5.9Mb - ``` - -# RPostgres - -Version: 1.0-3 - -## Newly fixed - -* checking installed package size ... NOTE - ``` - installed size is 5.0Mb - sub-directories of 1Mb or more: - libs 4.7Mb - ``` - -## In both - -* checking dependencies in R code ... NOTE - ``` - Namespace in Imports field not imported from: ‘withr’ - All declared Imports should be used. - ``` - -# RSQLite - -Version: 2.0 - -## Newly fixed - -* checking tests ... - ``` - ERROR - Running the tests in ‘tests/testthat.R’ failed. - Last 13 lines of output: - > library(RSQLite) - > - > test_check("RSQLite") - 1. Failure: DBItest[RSQLite]: Connection: cannot_forget_disconnect (@spec-connection-disconnect.R#24) - gc() showed 0 warnings - - - testthat results ================================================================ - OK: 4255 SKIPPED: 15 FAILED: 1 - 1. Failure: DBItest[RSQLite]: Connection: cannot_forget_disconnect (@spec-connection-disconnect.R#24) - - Error: testthat unit tests failed - In addition: Warning message: - call dbDisconnect() when finished working with a connection - Execution halted - ``` - -## In both - -* checking installed package size ... NOTE - ``` - installed size is 9.4Mb - sub-directories of 1Mb or more: - libs 8.8Mb - ``` - -* checking dependencies in R code ... NOTE - ``` - Namespace in Imports field not imported from: ‘pkgconfig’ - All declared Imports should be used. - ``` - -# RSQLServer - -Version: 0.3.0 - -## In both - -* checking package dependencies ... ERROR - ``` - Package required but not available: ‘rJava’ - - See section ‘The DESCRIPTION file’ in the ‘Writing R Extensions’ - manual. - ``` - +*Wow, no problems at all. :)* \ No newline at end of file diff --git a/tests/testthat/helper-dev.R b/tests/testthat/helper-dev.R index 956beea36..1b05d0d52 100644 --- a/tests/testthat/helper-dev.R +++ b/tests/testthat/helper-dev.R @@ -1,7 +1,8 @@ if (Sys.getenv("CI") == "" && dir.exists("../../../RSQLite")) { writeLines( c( - "# Generated by helper-dev.R, do not edit by hand", + # Avoid warning + paste0("# Generated by helper-dev.R, do not edit", " by hand"), "", "skip_if_not_installed(\"RSQLite\")", "skip_if_not_installed(\"nanoarrow\")", @@ -64,10 +65,12 @@ inline_meta_tests <- function(arrow, bind, path) { text[[1]] <- paste0("spec_meta_", infix, "bind <- ", text[[1]]) # FIXME: Why does constructive not handle this? text <- gsub('r"[\\]"', '"\\\\"', text, fixed = TRUE) + text <- gsub('^( *)"(.*)"$', "\\1# \\2", text) text <- c( "# Generated by helper-dev.R, do not edit by hand", + "# Sources: R/spec-meta-bind-.R, R/spec-meta-bind-expr.R, R/spec-meta-bind-runner.R", "", - "# This file is generated during load_all() if it's older than the input files", + "# This file is generated during load_all() if it's older than the sources", "", text ) @@ -83,8 +86,9 @@ times <- file.mtime(c( "../../R/spec-meta-bind-arrow-stream.R", # Sources - "../../R/spec-meta-bind-expr.R", "../../R/spec-meta-bind-.R", + # Reason for two input files: order of topics in the generated help file + "../../R/spec-meta-bind-expr.R", "../../R/spec-meta-bind-runner.R", "helper-dev.R", NULL diff --git a/tests/testthat/test-DBItest.R b/tests/testthat/test-DBItest.R index 4a0ac1696..9604e68e5 100644 --- a/tests/testthat/test-DBItest.R +++ b/tests/testthat/test-DBItest.R @@ -13,7 +13,7 @@ tryCatch(skip = function(e) message(conditionMessage(e)), { RSQLite::SQLite(), list(dbname = tempfile("DBItest", fileext = ".sqlite")), tweaks = DBItest::tweaks( - dbitest_version = "1.7.2", + dbitest_version = "1.8.0.50", constructor_relax_args = TRUE, placeholder_pattern = c("?", "$1", "$name", ":name"), date_cast = function(x) paste0("'", x, "'"), @@ -33,7 +33,11 @@ tryCatch(skip = function(e) message(conditionMessage(e)), { skip_on_cran() skip_if_not_installed("DBItest") -DBItest::test_all() +DBItest::test_all( + skip = c( + if (getRversion() < "4.0") "stream_bind_too_many" + ) +) # Cleanup set_default_context(NULL) diff --git a/tests/testthat/test-consistency.R b/tests/testthat/test-consistency.R index d36e64d38..c62c3e2f1 100644 --- a/tests/testthat/test-consistency.R +++ b/tests/testthat/test-consistency.R @@ -1,5 +1,5 @@ test_that("no unnamed specs", { - tests <- spec_all[!vapply(spec_all, is.null, logical(1L))] + tests <- compact(spec_all) vicinity <- NULL if (any(names(tests) == "")) { vicinity <- sort(unique(unlist( @@ -13,22 +13,6 @@ test_that("no unnamed specs", { test_that("no duplicate spec names expect known exceptions", { all_names <- names(spec_all) - all_names <- all_names[!(all_names %in% c( - "create_temporary_table", - "create_table_visible_in_other_connection", - "list_tables", - "exists_table", - "temporary_table", - "list_objects", - "table_visible_in_other_connection", - "arrow_write_table_arrow_temporary", - "arrow_write_table_arrow_visible_in_other_connection", - "arrow_create_table_arrow_visible_in_other_connection", - "begin_write_disconnect", - "begin_write_commit", - NULL - ))] - dupe_names <- unique(all_names[duplicated(all_names)]) expect_equal(dupe_names, rep("", length(dupe_names))) }) diff --git a/vignettes/DBItest.Rmd b/vignettes/DBItest.Rmd index 0ff060327..847b307bd 100644 --- a/vignettes/DBItest.Rmd +++ b/vignettes/DBItest.Rmd @@ -162,7 +162,7 @@ For interactive use, the "progress" reporter gives good results. In the example below, the "location" and "stop" reporters are combined. Review `?testthat::Reporter` for a list of reporters. -```{r simple, error = (getRversion() < "3.5") || !rlang::is_installed(c("dblog", "RSQLite"))} +```{r simple, error = !rlang::is_installed("RSQLite")} DBItest::test_some("get_query_atomic") ``` @@ -173,7 +173,7 @@ It prints the DBI code that is executed as the tests are run, as seen above. Another way to scout for the reason of the problem is to review the sources of DBItest and relate the test name (that is printed with each failure) with the human-readable specification embedded with the test code. -```{r location, error = (getRversion() < "3.5") || !rlang::is_installed(c("dblog", "RSQLite"))} +```{r location, error = !rlang::is_installed("RSQLite")} testthat::with_reporter( c("location", "fail"), DBItest::test_some("get_query_atomic")