diff --git a/R/data.table.R b/R/data.table.R index 7d3acef2fa..f225855a3c 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -756,7 +756,14 @@ replace_dot_alias = function(e) { bysub = parse(text=paste0("list(",paste(bysub,collapse=","),")"))[[1L]] bysubl = as.list.default(bysub) } - allbyvars = intersect(all.vars(bysub), names_x) + # Fix 4981: when the 'by' expression includes get/mget/eval, all.vars + # cannot be trusted to infer all used columns + bysub.elems <- rapply(as.list(bysub), as.character) + if (any(c("eval","evalq","eval.parent","local","get","mget","dynGet") %chin% bysub.elems)) + allbyvars = NULL + else + allbyvars = intersect(all.vars(bysub), names_x) + orderedirows = .Call(CisOrderedSubset, irows, nrow(x)) # TRUE when irows is NULL (i.e. no i clause). Similar but better than is.sorted(f__) bysameorder = byindex = FALSE if (!bysub %iscall% ":" && ##Fix #4285 diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 819c1ba0ca..2610c22724 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -17515,3 +17515,14 @@ test(2183.79, melt(DTid, measure.vars=measure(letter, number, pattern=as.integer test(2183.80, melt(DTid, measure.vars=measure(letter, number, sep=as.integer)), error="sep must be character string") ##melt(DTid, measure.vars=measure(letter, number, sep=NA_character_) ##melt(DTid, measure.vars=measure(letter, number, sep=character()) + +# `keyby` allows mixing eval/get with direct columns, #4981 +dt <- data.table(a=c(1,2), b=c(3,4), c=c(1,0)) +dt2 <- dt[,.(suma=sum(a)), keyby=.(b=get("b"),c)] +test(2184.1, dt2[1, suma], 1) +dt2 <- dt[2,.(suma=sum(a)), keyby=.(b=b,c)] +test(2184.2, dt2[1, suma], 2) +dt2 <- dt[2,.(suma=sum(a)), keyby=.(b=get("b"))] +test(2184.3, dt2[1, suma], 2) +dt2 <- dt[2,.(suma=sum(a)), keyby=.(b=get("b"),c)] +test(2184.4, dt2[1, suma], 2) \ No newline at end of file