Skip to content

Commit d854986

Browse files
authored
use type checkers in backend-*.R files (#1556)
1 parent b1e8bab commit d854986

File tree

13 files changed

+80
-96
lines changed

13 files changed

+80
-96
lines changed

NEWS.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# dbplyr (development version)
22

3-
* Tightened argument checks for Snowflake SQL translations. These changes should
4-
result in more informative errors in cases where code already failed; if you
5-
see errors with code that used to run without issue, please report them to
6-
the package authors (@simonpcouch, #1554).
3+
* Tightened argument checks for SQL translations. These changes should
4+
result in more informative errors in cases where code already failed, possibly
5+
silently; if you see errors with code that used to run correctly, please report
6+
them to the package authors (@simonpcouch, #1554, #1555).
77

88
* `clock::add_years()` translates to correct SQL on Spark (@ablack3, #1510).
99

R/backend-.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ base_scalar <- sql_translator(
252252
# base R
253253
nchar = sql_prefix("LENGTH", 1),
254254
nzchar = function(x, keepNA = FALSE) {
255+
check_bool(keepNA)
255256
if (keepNA) {
256257
exp <- expr(!!x != "")
257258
translate_sql(!!exp, con = sql_current_con())
@@ -281,6 +282,7 @@ base_scalar <- sql_translator(
281282
str_c = sql_paste(""),
282283
str_sub = sql_str_sub("SUBSTR"),
283284
str_like = function(string, pattern, ignore_case = TRUE) {
285+
check_bool(ignore_case)
284286
if (isTRUE(ignore_case)) {
285287
sql_expr(!!string %LIKE% !!pattern)
286288
} else {

R/backend-hive.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ sql_table_analyze.Hive <- function(con, table, ...) {
9494

9595
#' @export
9696
sql_query_set_op.Hive <- function(con, x, y, method, ..., all = FALSE, lvl = 0) {
97+
check_bool(all)
9798
# parentheses are not allowed
9899
method <- paste0(method, if (all) " ALL")
99100
glue_sql2(

R/backend-mssql.R

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,15 @@ simulate_mssql <- function(version = "15.0") {
107107
conflict = c("error", "ignore"),
108108
returning_cols = NULL,
109109
method = NULL) {
110-
method <- method %||% "where_not_exists"
111-
arg_match(method, "where_not_exists", error_arg = "method")
112110
# https://stackoverflow.com/questions/25969/insert-into-values-select-from
113111
conflict <- rows_check_conflict(conflict)
114112

113+
check_character(returning_cols, allow_null = TRUE)
114+
115+
check_string(method, allow_null = TRUE)
116+
method <- method %||% "where_not_exists"
117+
arg_match(method, "where_not_exists", error_arg = "method")
118+
115119
parts <- rows_insert_prep(con, table, from, insert_cols, by, lvl = 0)
116120

117121
clauses <- list2(
@@ -177,6 +181,7 @@ simulate_mssql <- function(version = "15.0") {
177181
...,
178182
returning_cols = NULL,
179183
method = NULL) {
184+
check_string(method, allow_null = TRUE)
180185
method <- method %||% "merge"
181186
arg_match(method, "merge", error_arg = "method")
182187

@@ -333,6 +338,7 @@ simulate_mssql <- function(version = "15.0") {
333338
second = function(x) sql_expr(DATEPART(SECOND, !!x)),
334339

335340
month = function(x, label = FALSE, abbr = TRUE) {
341+
check_bool(label)
336342
if (!label) {
337343
sql_expr(DATEPART(MONTH, !!x))
338344
} else {
@@ -342,6 +348,7 @@ simulate_mssql <- function(version = "15.0") {
342348
},
343349

344350
quarter = function(x, with_year = FALSE, fiscal_start = 1) {
351+
check_bool(with_year)
345352
check_unsupported_arg(fiscal_start, 1, backend = "SQL Server")
346353

347354
if (with_year) {
@@ -361,6 +368,7 @@ simulate_mssql <- function(version = "15.0") {
361368
sql_expr(DATEADD(YEAR, !!n, !!x))
362369
},
363370
date_build = function(year, month = 1L, day = 1L, ..., invalid = NULL) {
371+
check_unsupported_arg(invalid, allow_null = TRUE)
364372
sql_expr(DATEFROMPARTS(!!year, !!month, !!day))
365373
},
366374
get_year = function(x) {
@@ -373,27 +381,16 @@ simulate_mssql <- function(version = "15.0") {
373381
sql_expr(DATEPART(DAY, !!x))
374382
},
375383
date_count_between = function(start, end, precision, ..., n = 1L){
376-
377384
check_dots_empty()
378-
if (precision != "day") {
379-
cli_abort("{.arg precision} must be {.val day} on SQL backends.")
380-
}
381-
if (n != 1) {
382-
cli_abort("{.arg n} must be {.val 1} on SQL backends.")
383-
}
385+
check_unsupported_arg(precision, allowed = "day")
386+
check_unsupported_arg(n, allowed = 1L)
384387

385388
sql_expr(DATEDIFF(DAY, !!start, !!end))
386389
},
387390

388391
difftime = function(time1, time2, tz, units = "days") {
389-
390-
if (!missing(tz)) {
391-
cli::cli_abort("The {.arg tz} argument is not supported for SQL backends.")
392-
}
393-
394-
if (units[1] != "days") {
395-
cli::cli_abort('The only supported value for {.arg units} on SQL backends is "days"')
396-
}
392+
check_unsupported_arg(tz)
393+
check_unsupported_arg(units, allowed = "days")
397394

398395
sql_expr(DATEDIFF(DAY, !!time2, !!time1))
399396
}
@@ -545,7 +542,7 @@ mssql_version <- function(con) {
545542

546543
#' @export
547544
`sql_returning_cols.Microsoft SQL Server` <- function(con, cols, table, ...) {
548-
stopifnot(table %in% c("DELETED", "INSERTED"))
545+
arg_match(table, values = c("DELETED", "INSERTED"))
549546
returning_cols <- sql_named_cols(con, cols, table = table)
550547

551548
sql_clause("OUTPUT", returning_cols)

R/backend-postgres.R

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ postgres_grepl <- function(pattern,
5757
check_unsupported_arg(perl, FALSE, backend = "PostgreSQL")
5858
check_unsupported_arg(fixed, FALSE, backend = "PostgreSQL")
5959
check_unsupported_arg(useBytes, FALSE, backend = "PostgreSQL")
60+
check_bool(ignore.case)
6061

6162
if (ignore.case) {
6263
sql_expr(((!!x)) %~*% ((!!pattern)))
@@ -123,6 +124,7 @@ sql_translation.PqConnection <- function(con) {
123124
},
124125
# https://www.postgresql.org/docs/current/functions-matching.html
125126
str_like = function(string, pattern, ignore_case = TRUE) {
127+
check_bool(ignore_case)
126128
if (isTRUE(ignore_case)) {
127129
sql_expr(!!string %ILIKE% !!pattern)
128130
} else {
@@ -162,6 +164,9 @@ sql_translation.PqConnection <- function(con) {
162164
sql_expr(EXTRACT(DAY %FROM% !!x))
163165
},
164166
wday = function(x, label = FALSE, abbr = TRUE, week_start = NULL) {
167+
check_bool(label)
168+
check_bool(abbr)
169+
check_number_whole(week_start, allow_null = TRUE)
165170
if (!label) {
166171
week_start <- week_start %||% getOption("lubridate.week.start", 7)
167172
offset <- as.integer(7 - week_start)
@@ -182,6 +187,8 @@ sql_translation.PqConnection <- function(con) {
182187
sql_expr(EXTRACT(WEEK %FROM% !!x))
183188
},
184189
month = function(x, label = FALSE, abbr = TRUE) {
190+
check_bool(label)
191+
check_bool(abbr)
185192
if (!label) {
186193
sql_expr(EXTRACT(MONTH %FROM% !!x))
187194
} else {
@@ -193,6 +200,7 @@ sql_translation.PqConnection <- function(con) {
193200
}
194201
},
195202
quarter = function(x, with_year = FALSE, fiscal_start = 1) {
203+
check_bool(with_year)
196204
check_unsupported_arg(fiscal_start, 1, backend = "PostgreSQL")
197205

198206
if (with_year) {
@@ -246,17 +254,14 @@ sql_translation.PqConnection <- function(con) {
246254
glue_sql2(sql_current_con(), "({.col x} + {.val n}*INTERVAL'1 year')")
247255
},
248256
date_build = function(year, month = 1L, day = 1L, ..., invalid = NULL) {
257+
check_unsupported_arg(invalid, allow_null = TRUE)
249258
sql_expr(make_date(!!year, !!month, !!day))
250259
},
251260
date_count_between = function(start, end, precision, ..., n = 1L){
252261

253262
check_dots_empty()
254-
if (precision != "day") {
255-
cli_abort("{.arg precision} must be {.val day} on SQL backends.")
256-
}
257-
if (n != 1) {
258-
cli_abort("{.arg n} must be {.val 1} on SQL backends.")
259-
}
263+
check_unsupported_arg(precision, allowed = "day")
264+
check_unsupported_arg(n, allowed = 1L)
260265

261266
sql_expr(!!end - !!start)
262267
},
@@ -272,13 +277,8 @@ sql_translation.PqConnection <- function(con) {
272277

273278
difftime = function(time1, time2, tz, units = "days") {
274279

275-
if (!missing(tz)) {
276-
cli::cli_abort("The {.arg tz} argument is not supported for SQL backends.")
277-
}
278-
279-
if (units[1] != "days") {
280-
cli::cli_abort('The only supported value for {.arg units} on SQL backends is "days"')
281-
}
280+
check_unsupported_arg(tz)
281+
check_unsupported_arg(units, allowed = "days")
282282

283283
sql_expr((CAST(!!time1 %AS% DATE) - CAST(!!time2 %AS% DATE)))
284284
},
@@ -344,6 +344,7 @@ sql_query_insert.PqConnection <- function(con,
344344
...,
345345
returning_cols = NULL,
346346
method = NULL) {
347+
check_string(method, allow_null = TRUE)
347348
method <- method %||% "on_conflict"
348349
arg_match(method, c("on_conflict", "where_not_exists"), error_arg = "method")
349350
if (method == "where_not_exists") {
@@ -379,6 +380,7 @@ sql_query_upsert.PqConnection <- function(con,
379380
...,
380381
returning_cols = NULL,
381382
method = NULL) {
383+
check_string(method, allow_null = TRUE)
382384
method <- method %||% "on_conflict"
383385
arg_match(method, c("cte_update", "on_conflict"), error_arg = "method")
384386

R/backend-redshift.R

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ sql_translation.RedshiftConnection <- function(con) {
7272
sql_expr(DATEADD(YEAR, !!n, !!x))
7373
},
7474
date_build = function(year, month = 1L, day = 1L, ..., invalid = NULL) {
75+
check_unsupported_arg(invalid, allow_null = TRUE)
7576
glue_sql2(sql_current_con(), "TO_DATE(CAST({.val year} AS TEXT) || '-' CAST({.val month} AS TEXT) || '-' || CAST({.val day} AS TEXT)), 'YYYY-MM-DD')")
7677
},
7778
get_year = function(x) {
@@ -84,27 +85,16 @@ sql_translation.RedshiftConnection <- function(con) {
8485
sql_expr(DATE_PART('day', !!x))
8586
},
8687
date_count_between = function(start, end, precision, ..., n = 1L){
87-
8888
check_dots_empty()
89-
if (precision != "day") {
90-
cli_abort("{.arg precision} must be {.val day} on SQL backends.")
91-
}
92-
if (n != 1) {
93-
cli_abort("{.arg n} must be {.val 1} on SQL backends.")
94-
}
89+
check_unsupported_arg(precision, allowed = "day")
90+
check_unsupported_arg(n, allowed = 1L)
9591

9692
sql_expr(DATEDIFF(DAY, !!start, !!end))
9793
},
9894

9995
difftime = function(time1, time2, tz, units = "days") {
100-
101-
if (!missing(tz)) {
102-
cli::cli_abort("The {.arg tz} argument is not supported for SQL backends.")
103-
}
104-
105-
if (units[1] != "days") {
106-
cli::cli_abort('The only supported value for {.arg units} on SQL backends is "days"')
107-
}
96+
check_unsupported_arg(tz)
97+
check_unsupported_arg(units, allowed = "days")
10898

10999
sql_expr(DATEDIFF(DAY, !!time2, !!time1))
110100
}

R/backend-spark-sql.R

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ simulate_spark_sql <- function() simulate_dbi("Spark SQL")
4747
sql_expr(add_months(!!x, !!n*12))
4848
},
4949
date_build = function(year, month = 1L, day = 1L, ..., invalid = NULL) {
50+
check_unsupported_arg(invalid, allow_null = TRUE)
5051
sql_expr(make_date(!!year, !!month, !!day))
5152
},
5253
get_year = function(x) {
@@ -59,27 +60,16 @@ simulate_spark_sql <- function() simulate_dbi("Spark SQL")
5960
sql_expr(date_part('DAY', !!x))
6061
},
6162
date_count_between = function(start, end, precision, ..., n = 1L){
62-
6363
check_dots_empty()
64-
if (precision != "day") {
65-
cli_abort("{.arg precision} must be {.val day} on SQL backends.")
66-
}
67-
if (n != 1) {
68-
cli_abort("{.arg n} must be {.val 1} on SQL backends.")
69-
}
64+
check_unsupported_arg(precision, allowed = "day")
65+
check_unsupported_arg(n, allowed = 1L)
7066

7167
sql_expr(datediff(!!end, !!start))
7268
},
7369

7470
difftime = function(time1, time2, tz, units = "days") {
75-
76-
if (!missing(tz)) {
77-
cli::cli_abort("The {.arg tz} argument is not supported for SQL backends.")
78-
}
79-
80-
if (units[1] != "days") {
81-
cli::cli_abort('The only supported value for {.arg units} on SQL backends is "days"')
82-
}
71+
check_unsupported_arg(tz)
72+
check_unsupported_arg(units, allowed = "days")
8373

8474
sql_expr(datediff(!!time2, !!time1))
8575
}
@@ -153,7 +143,8 @@ simulate_spark_sql <- function() simulate_dbi("Spark SQL")
153143
indexes = list(),
154144
analyze = TRUE,
155145
in_transaction = FALSE) {
156-
146+
check_bool(overwrite)
147+
check_bool(temporary)
157148
sql <- glue_sql2(
158149
con,
159150
"CREATE ", if (overwrite) "OR REPLACE ",

R/backend-teradata.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ sql_translation.Teradata <- function(con) {
153153
row_number = win_rank("ROW_NUMBER", empty_order = TRUE),
154154
weighted.mean = function(x, w, na.rm = T) {
155155
# nocov start
156+
check_unsupported_arg(na.rm, allowed = TRUE)
156157
win_over(
157158
sql_expr(SUM((!!x * !!w))/SUM(!!w)),
158159
win_current_group(),
@@ -191,6 +192,7 @@ sql_translation.Teradata <- function(con) {
191192
},
192193
weighted.mean = function(x, w, na.rm = T) {
193194
# nocov start
195+
check_unsupported_arg(na.rm, allowed = TRUE)
194196
win_over(
195197
sql_expr(SUM((!!x * !!w))/SUM(!!w)),
196198
win_current_group(),

R/utils.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ res_warn_incomplete <- function(res, hint = "n = -1") {
8383
}
8484

8585
add_temporary_prefix <- function(con, table, temporary = TRUE) {
86+
check_bool(temporary)
8687
check_table_path(table)
8788

8889
if (!temporary) {

tests/testthat/_snaps/backend-mssql.md

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,31 +47,34 @@
4747
test_translate_sql(date_count_between(date_column_1, date_column_2, "year"))
4848
Condition
4949
Error in `date_count_between()`:
50-
! `precision` must be "day" on SQL backends.
50+
! `precision = "year"` isn't supported on database backends.
51+
i It must be "day" instead.
5152

5253
---
5354

5455
Code
5556
test_translate_sql(date_count_between(date_column_1, date_column_2, "day", n = 5))
5657
Condition
5758
Error in `date_count_between()`:
58-
! `n` must be "1" on SQL backends.
59+
! `n = 5` isn't supported on database backends.
60+
i It must be 1 instead.
5961

6062
# difftime is translated correctly
6163

6264
Code
6365
test_translate_sql(difftime(start_date, end_date, units = "auto"))
6466
Condition
6567
Error in `difftime()`:
66-
! The only supported value for `units` on SQL backends is "days"
68+
! `units = "auto"` isn't supported on database backends.
69+
i It must be "days" instead.
6770

6871
---
6972

7073
Code
7174
test_translate_sql(difftime(start_date, end_date, tz = "UTC", units = "days"))
7275
Condition
7376
Error in `difftime()`:
74-
! The `tz` argument is not supported for SQL backends.
77+
! Argument `tz` isn't supported on database backends.
7578

7679
# convert between bit and boolean as needed
7780

@@ -494,20 +497,6 @@
494497
FROM `df`
495498
ORDER BY `y`
496499

497-
# can copy_to() and compute() with temporary tables (#438)
498-
499-
Code
500-
db <- copy_to(con, df, name = unique_table_name(), temporary = TRUE)
501-
Message
502-
Created a temporary table named #dbplyr_{tmp}
503-
504-
---
505-
506-
Code
507-
db2 <- db %>% mutate(y = x + 1) %>% compute()
508-
Message
509-
Created a temporary table named #dbplyr_{tmp}
510-
511500
# add prefix to temporary table
512501

513502
Code

0 commit comments

Comments
 (0)