Skip to content

Commit

Permalink
Merge branch 'master' into rchk-gha
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-schwen authored Jul 25, 2024
2 parents c965eb5 + 1600b51 commit b62c2da
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ source(".dev/cc.R")
Developer helper script providing `cc` function. If one starts R session in `data.table` project root directory `.dev/cc.R` file should be automatically sourced (due to local `.Rprofile` file) making `cc()` (and `dd()`) function available straightaway.

```r
cc(test=FALSE, clean=FALSE, debug=FALSE, omp=!debug, cc_dir, path=Sys.getenv("PROJ_PATH"), CC="gcc")
cc(test=FALSE, clean=FALSE, debug=FALSE, omp=!debug, path=Sys.getenv("PROJ_PATH", unset=normalizePath(".")), CC="gcc", quiet=FALSE)
```

Use `cc()` to re-compile all C sources and attach all `data.table` R functions (including non-exported ones).
Expand Down
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@

14. `fread` loads `.bgz` files directly, [#5461](https://github.com/Rdatatable/data.table/issues/5461). Thanks to @TMRHarrison for the request with proposed fix, and Benjamin Schwendinger for the PR.

15. `rbindlist(l, use.names=TRUE)` and `rbind` now works correctly on columns with different class attributes for certain classes such as `Date`, `IDate`, `ITime`, `POSIXct` and `AsIs` with other columns of similar classes, e.g., `IDate` and `Date`. The conversion is done automatically and the class attribute of the final column is determined by the first encountered class attribute in the binding list, [#5309](https://github.com/Rdatatable/data.table/issues/5309), [#4934](https://github.com/Rdatatable/data.table/issues/4934), [#5391](https://github.com/Rdatatable/data.table/issues/5391).

`rbindlist(l, ignore.attr=TRUE)` and `rbind` also gains argument `ignore.attr` to manually deactivate the safety-net of binding columns with different column classes, [#3911](https://github.com/Rdatatable/data.table/issues/3911), [#5542](https://github.com/Rdatatable/data.table/issues/5542). Thanks to @dcaseykc, @fox34, @adrian-quintario, @berg-michael, @arunsrinivasan, @statquant, @pkress, @jrausch12, @therosko, @OfekShilon, @iMissile, @tdhock for the request and @ben-schwen for the PR.

## BUG FIXES

1. `unique()` returns a copy the case when `nrows(x) <= 1` instead of a mutable alias, [#5932](https://github.com/Rdatatable/data.table/pull/5932). This is consistent with existing `unique()` behavior when the input has no duplicates but more than one row. Thanks to @brookslogan for the report and @dshemetov for the fix.
Expand Down Expand Up @@ -70,6 +74,8 @@

14. `fread(x, colClasses="POSIXct")` now also works for columns containing only NA values, [#6208](https://github.com/Rdatatable/data.table/issues/6208). Thanks to @markus-schaffer for the report, and Benjamin Schwendinger for the fix.

15. `fread()` is more careful about detecting that a file is compressed in bzip2 format, [#6304](https://github.com/Rdatatable/data.table/issues/6304). In particular, we also check the 4th byte is a digit; in rare cases, a legitimate uncompressed CSV file could match 'BZh' as the first 3 bytes. We think an uncompressed CSV file matching 'BZh[1-9]' is all the more rare and unlikely to be encountered in "real" examples. Other formats (zip, gzip) are friendly enough to use non-printable characters in their magic numbers. Thanks @grainnemcguire for the report and @MichaelChirico for the fix.

## NOTES

1. `transform` method for data.table sped up substantially when creating new columns on large tables. Thanks to @OfekShilon for the report and PR. The implemented solution was proposed by @ColeMiller1.
Expand Down
8 changes: 4 additions & 4 deletions R/data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -2735,14 +2735,14 @@ chgroup = function(x) {
}

# plain rbind and cbind methods are registered using S3method() in NAMESPACE only from R>=4.0.0; #3948
rbind.data.table = function(..., use.names=TRUE, fill=FALSE, idcol=NULL) {
rbind.data.table = function(..., use.names=TRUE, fill=FALSE, idcol=NULL, ignore.attr=FALSE) {
l = lapply(list(...), function(x) if (is.list(x)) x else as.data.table(x)) #1626; e.g. psych binds a data.frame|table with a matrix
rbindlist(l, use.names, fill, idcol)
rbindlist(l, use.names, fill, idcol, ignore.attr)
}
cbind.data.table = data.table
.rbind.data.table = rbind.data.table # the workaround using this in FAQ 2.24 is still applied to support R < 4.0.0

rbindlist = function(l, use.names="check", fill=FALSE, idcol=NULL) {
rbindlist = function(l, use.names="check", fill=FALSE, idcol=NULL, ignore.attr=FALSE) {
if (is.null(l)) return(null.data.table())
if (!is.list(l) || is.data.frame(l)) stopf("Input is %s but should be a plain list of items to be stacked", class(l)[1L])
if (isFALSE(idcol)) { idcol = NULL }
Expand All @@ -2758,7 +2758,7 @@ rbindlist = function(l, use.names="check", fill=FALSE, idcol=NULL) {
if (!miss) stopf("use.names='check' cannot be used explicitly because the value 'check' is new in v1.12.2 and subject to change. It is just meant to convey default behavior. See ?rbindlist.")
use.names = NA
}
ans = .Call(Crbindlist, l, use.names, fill, idcol)
ans = .Call(Crbindlist, l, use.names, fill, idcol, ignore.attr)
if (!length(ans)) return(null.data.table())
setDT(ans)[]
}
Expand Down
33 changes: 27 additions & 6 deletions R/fread.R
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,9 @@ yaml=FALSE, autostart=NA, tmpdir=tempdir(), tz="UTC")
}

# support zip and tar files #3834
zip_signature = charToRaw("PK\x03\x04")
file_signature = readBin(file, raw(), 8L)

if ((w <- endsWithAny(file, c(".zip", ".tar"))) || identical(head(file_signature, 4L), zip_signature)) {
if ((w <- endsWithAny(file, c(".zip", ".tar"))) || is_zip(file_signature)) {
FUN = if (w==2L) untar else unzip
fnames = FUN(file, list=TRUE)
if (is.data.frame(fnames)) fnames = fnames[,1L]
Expand All @@ -110,12 +109,10 @@ yaml=FALSE, autostart=NA, tmpdir=tempdir(), tz="UTC")
on.exit(unlink(decompFile), add=TRUE)
}

gz_signature = as.raw(c(0x1F, 0x8B))
bz2_signature = as.raw(c(0x42, 0x5A, 0x68))
gzsig = FALSE
if ((w <- endsWithAny(file, c(".gz", ".bgz",".bz2"))) || (gzsig <- identical(head(file_signature, 2L), gz_signature)) || identical(head(file_signature, 3L), bz2_signature)) {
if ((w <- endsWithAny(file, c(".gz", ".bgz",".bz2"))) || (gzsig <- is_gzip(file_signature)) || is_bzip(file_signature)) {
if (!requireNamespace("R.utils", quietly = TRUE))
stopf("To read gz and bz2 files directly, fread() requires 'R.utils' package which cannot be found. Please install 'R.utils' using 'install.packages('R.utils')'.") # nocov
stopf("To read %s files directly, fread() requires 'R.utils' package which cannot be found. Please install 'R.utils' using 'install.packages('R.utils')'.", if (w<=2L || gzsig) "gz" else "bz2") # nocov
FUN = if (w<=2L || gzsig) gzfile else bzfile
R.utils::decompressFile(file, decompFile<-tempfile(tmpdir=tmpdir), ext=NULL, FUN=FUN, remove=FALSE) # ext is not used by decompressFile when destname is supplied, but isn't optional
file = decompFile # don't use 'tmpFile' symbol again, as tmpFile might be the http://domain.org/file.csv.gz download
Expand Down Expand Up @@ -361,6 +358,30 @@ yaml=FALSE, autostart=NA, tmpdir=tempdir(), tz="UTC")
ans
}

known_signatures = list(
zip = as.raw(c(0x50, 0x4b, 0x03, 0x04)), # charToRaw("PK\x03\x04")
gzip = as.raw(c(0x1F, 0x8B)),
bzip = as.raw(c(0x42, 0x5A, 0x68))
)

# https://en.wikipedia.org/wiki/ZIP_(file_format)#File_headers
# not checked: what's a valid 'version' entry to check the 5th+6th bytes
is_zip = function(file_signature) {
identical(file_signature[1:4], known_signatures$zip)
}

# https://en.wikipedia.org/wiki/Gzip#File_format
# not checked: remaining 8 bytes of header
is_gzip = function(file_signature) {
identical(file_signature[1:2], known_signatures$gzip)
}

# https://en.wikipedia.org/wiki/Bzip2#File_format
is_bzip = function(file_signature) {
identical(file_signature[1:3], known_signatures$bzip) &&
isTRUE(file_signature[4L] %in% charToRaw('123456789')) # for #6304
}

# simplified but faster version of `factor()` for internal use.
as_factor = function(x) {
lev = forderv(x, retGrp = TRUE, na.last = NA)
Expand Down
16 changes: 1 addition & 15 deletions R/merge.R
Original file line number Diff line number Diff line change
Expand Up @@ -96,21 +96,7 @@ merge.data.table = function(x, y, by = NULL, by.x = NULL, by.y = NULL, all = FAL
if (all.y && nrow(y)) { # If y does not have any rows, no need to proceed
# Perhaps not very commonly used, so not a huge deal that the join is redone here.
missingyidx = y[!x, which=TRUE, on=by, allow.cartesian=allow.cartesian]
# TO DO: replace by following once #5446 is merged
# if (length(missingyidx)) dt = rbind(dt, y[missingyidx], use.names=FALSE, fill=TRUE, ignore.attr=TRUE)
if (length(missingyidx)) {
yy = y[missingyidx]
othercolsx = setdiff(nm_x, by)
if (length(othercolsx)) {
# create NA rectangle with correct types and attributes of x to cbind to y
tmp = rep.int(NA_integer_, length(missingyidx))
# TO DO: use set() here instead..
yy = cbind(yy, x[tmp, othercolsx, with = FALSE])
}
# empty data.tables (nrow =0, ncol>0) doesn't skip names anymore in new rbindlist
# takes care of #24 without having to save names. This is how it should be, IMHO.
dt = rbind(dt, yy, use.names=FALSE)
}
if (length(missingyidx)) dt = rbind(dt, y[missingyidx], use.names=FALSE, fill=TRUE, ignore.attr=TRUE)
}
# X[Y] syntax puts JIS i columns at the end, merge likes them alongside i.
newend = setdiff(nm_y, by.y)
Expand Down
2 changes: 1 addition & 1 deletion R/test.data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test.data.table = function(script="tests.Rraw", verbose=FALSE, pkg=".", silent=F
# nocov start
dev = TRUE
if ("package:data.table" %chin% search()) stopf("data.table package is loaded. Unload or start a fresh R session.")
rootdir = if (pkg!="." && pkg %chin% dir()) file.path(getwd(), pkg) else Sys.getenv("PROJ_PATH")
rootdir = if (pkg!="." && pkg %chin% dir()) file.path(getwd(), pkg) else Sys.getenv("PROJ_PATH", normalizePath("."))
subdir = file.path("inst","tests")
env = new.env(parent=.GlobalEnv) # in dev cc() sources all functions in .GlobalEnv
# nocov end
Expand Down
8 changes: 8 additions & 0 deletions inst/tests/other.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,14 @@ if (loaded[["nanotime"]]) {
DT = data.table(time=nanotime(c(1,NA,3)))
test(27, na.omit(DT), DT[c(1,3)])

# rbind with vectors with class attributes #5309
x = data.table(a=1L, b=as.nanotime(0))
y = data.table(a=2L, b=NA)
test(27.01, rbind(x,y), data.table(a = c(1L, 2L), b=as.nanotime(c(0, NA))))
test(27.02, rbind(y,x), data.table(a = c(2L, 1L), b=as.nanotime(c(NA, 0))))
y[, b := NULL]
test(27.03, rbind(x,y, fill = TRUE), data.table(a = c(1L, 2L), b=as.nanotime(c(0, NA))))
test(27.04, rbind(y,x, fill = TRUE), data.table(a = c(2L, 1L), b=as.nanotime(c(NA, 0))))
}

# that plot works; moved from tests.Rraw 167 to here to save ram of loading graphics package and possible screen device issues on overloaded servers, #5517
Expand Down
62 changes: 62 additions & 0 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -14435,6 +14435,8 @@ test(2003.81, rbind(x, y, fill=TRUE, use.names=TRUE), ans)
test(2003.82, rbind(y, x, fill=TRUE, use.names=TRUE), ans[2:1,])
test(2003.83, rbind(x, y, fill=TRUE, use.names=FALSE), ans)
test(2003.84, rbind(y, x, fill=TRUE, use.names=FALSE), ans[2:1,])
# rbindlist ignore attributes #3911
test(2003.85, rbindlist(list(), ignore.attr=1), error="ignore.attr should be TRUE or FALSE")

# chmatch coverage for two different non-ascii encodings matching; issues mentioned in comments in chmatch.c #69 #2538 #111
x1 = "fa\xE7ile"
Expand Down Expand Up @@ -18752,3 +18754,63 @@ test(2271, options=c(datatable.verbose=TRUE), copy(DT1)[DT2, on='a', v := 4], co
# shift of many elements accumulated PROTECT() for the fill values instead of releasing as soon as possible. Spotted by rchk in #6257.
l = as.list(seq_len(2e4))
test(2272, shift(l), as.list(rep(NA_integer_, 2e4)))

# false positive detecting the bz2 header in some rare cases, #6304
tmp = tempfile()
fwrite(data.table(c1 = "BZh"), tmp, col.names=FALSE)
test(2273.1, fread(tmp), data.table(BZh = logical()))
test(2273.2, fread(tmp, header=FALSE), data.table(V1="BZh"))
fwrite(ans<-data.table(BZh=1L, CZi=2L), tmp)
test(2273.3, fread(tmp), ans)
if (test_R.utils) {
DT = data.table(a=1L, b=2L)
fwrite(DT, tmp)
R.utils::bzip2(tmp, tmp2 <- tempfile(), remove=FALSE) # _not_ with .bz2 extension
test(2273.4, fread(tmp2), DT)
}
file.remove(tmp, tmp2)

# rbind with vectors with class attributes #5309
x = data.table(a = 1L, b = as.Date("2020-01-01"))
y = data.table(a = 2L, b = as.IDate("2021-01-01"))
z = data.table(a = 3L, b = NA)
test(2274.01, rbind(x, y), data.table(a=c(1L, 2L), b= as.Date(c("2020-01-01", "2021-01-01"))))
test(2274.02, rbind(y, x), data.table(a=c(2L, 1L), b=as.IDate(c("2021-01-01", "2020-01-01"))))
test(2274.03, rbind(x, z), data.table(a=c(1L, 3L), b= as.Date(c("2020-01-01", NA))))
test(2274.04, rbind(z, x), data.table(a=c(3L, 1L), b= as.Date(c(NA, "2020-01-01"))))
test(2274.05, rbind(y, z), data.table(a=c(2L, 3L), b=as.IDate(c("2021-01-01", NA))))
test(2274.06, rbind(z, y), data.table(a=c(3L, 2L), b=as.IDate(c(NA, "2021-01-01"))))
z[, b := NULL]
test(2274.07, rbind(x, z, fill=TRUE), data.table(a=c(1L, 3L), b= as.Date(c("2020-01-01", NA))))
test(2274.08, rbind(z, x, fill=TRUE), data.table(a=c(3L, 1L), b= as.Date(c(NA, "2020-01-01"))))
test(2274.09, rbind(y, z, fill=TRUE), data.table(a=c(2L, 3L), b=as.IDate(c("2021-01-01", NA))))
test(2274.10, rbind(z, y, fill=TRUE), data.table(a=c(3L, 2L), b=as.IDate(c(NA, "2021-01-01"))))
x = data.table(a=1L, b=as.POSIXct("2021-10-06 13:58:00 UTC"))
test(2274.11, rbind(x, z, fill=TRUE), data.table(a=c(1L, 3L), b=as.POSIXct(c("2021-10-06 13:58:00 UTC", NA))))
test(2274.12, rbind(z, x, fill=TRUE), data.table(a=c(3L, 1L), b=as.POSIXct(c(NA, "2021-10-06 13:58:00 UTC"))))
x = data.table(c=1L, d=as.POSIXct("2021-10-06 13:58:00 UTC"))
test(2274.13, rbind(x, z, fill=TRUE, use.names=FALSE), data.table(c = c(1L, 3L), d=as.POSIXct(c("2021-10-06 13:58:00 UTC", NA))))
test(2274.14, rbind(z, x, fill=TRUE, use.names=FALSE), data.table(a=c(3L, 1L), d=as.POSIXct(c(NA, "2021-10-06 13:58:00 UTC"))))
x = data.table(a=1L, b=as.ITime(0))
y = data.table(a=2L, b=NA)
test(2274.15, rbind(x,y), data.table(a = c(1L, 2L), b=as.ITime(c(0, NA))))
test(2274.16, rbind(y,x), data.table(a = c(2L, 1L), b=as.ITime(c(NA, 0))))
y[, b := NULL]
test(2274.17, rbind(x,y, fill = TRUE), data.table(a = c(1L, 2L), b=as.ITime(c(0, NA))))
test(2274.18, rbind(y,x, fill = TRUE), data.table(a = c(2L, 1L), b=as.ITime(c(NA, 0))))
# follow up to #5263 to simplify merge logic
x = data.table(a = 1L, b = as.Date("2020-01-01"))
y = data.table(a = 2L, b = NA)
test(2274.19, merge(x, y, by="a", all=TRUE), data.table(a=1:2, b.x=as.Date(c("2020-01-01", NA)), b.y=NA, key="a"))
test(2274.20, merge(y, x, by="a", all=TRUE), data.table(a=1:2, b.x=NA, key="a", b.y=as.Date(c("2020-01-01", NA))))
# rbindlist with AsIs
x = data.table(a = 1L, b=I(3L))
y = data.table(a = 2L, b=4)
test(2274.21, rbindlist(list(x,y)), data.table(a = c(1L, 2L), b=I(c(3L, 4))))
test(2274.22, rbindlist(list(y,x)), data.table(a = c(2L, 1L), b=c(4, 3)))
# rbind ignore attributes #3911
x = data.table(a = structure(1:2, class=c("a", "integer")), key="a")
y = data.table(a = 2:3, key="a")
test(2274.31, merge(x,y, all.y=TRUE), data.table(a=structure(2:3, class=c("a", "integer")), key="a"))
test(2274.32, rbind(x,y), error="Class attribute .* does not match with .*")
test(2274.33, rbind(x,y, ignore.attr=TRUE), data.table(a=structure(c(1L, 2L, 2L, 3L), class=c("a", "integer"))))
8 changes: 7 additions & 1 deletion man/rbindlist.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
Same as \code{do.call(rbind, l)} on \code{data.frame}s, but much faster.
}
\usage{
rbindlist(l, use.names="check", fill=FALSE, idcol=NULL)
rbindlist(l, use.names="check", fill=FALSE, idcol=NULL, ignore.attr=FALSE)
# rbind(..., use.names=TRUE, fill=FALSE, idcol=NULL)
}
\arguments{
\item{l}{ A list containing \code{data.table}, \code{data.frame} or \code{list} objects. \code{\dots} is the same but you pass the objects by name separately. }
\item{use.names}{\code{TRUE} binds by matching column name, \code{FALSE} by position. `check` (default) warns if all items don't have the same names in the same order and then currently proceeds as if `use.names=FALSE` for backwards compatibility (\code{TRUE} in future); see news for v1.12.2.}
\item{fill}{\code{TRUE} fills missing columns with NAs, or NULL for missing list columns. By default \code{FALSE}.}
\item{idcol}{Creates a column in the result showing which list item those rows came from. \code{TRUE} names this column \code{".id"}. \code{idcol="file"} names this column \code{"file"}. If the input list has names, those names are the values placed in this id column, otherwise the values are an integer vector \code{1:length(l)}. See \code{examples}.}
\item{ignore.attr}{Logical, default \code{FALSE}. When \code{TRUE}, allows binding columns with different attributes (e.g. class).}
}
\details{
Each item of \code{l} can be a \code{data.table}, \code{data.frame} or \code{list}, including \code{NULL} (skipped) or an empty object (0 rows). \code{rbindlist} is most useful when there are an unknown number of (potentially many) objects to stack, such as returned by \code{lapply(fileNames, fread)}. \code{rbind} is most useful to stack two or three objects which you know in advance. \code{\dots} should contain at least one \code{data.table} for \code{rbind(\dots)} to call the fast method and return a \code{data.table}, whereas \code{rbindlist(l)} always returns a \code{data.table} even when stacking a plain \code{list} with a \code{data.frame}, for example.
Expand Down Expand Up @@ -54,6 +55,11 @@ rbindlist(l, use.names=TRUE, fill=TRUE, idcol=TRUE)
setattr(l, 'names', c("a", "b"))
rbindlist(l, use.names=TRUE, fill=TRUE, idcol="ID")

# bind different classes
DT1 = data.table(A=1:3,B=letters[1:3])
DT2 = data.table(A=4:5,B=letters[4:5])
setattr(DT1[["A"]], "class", c("a", "integer"))
rbind(DT1, DT2, ignore.attr=TRUE)
}
\keyword{ data }

3 changes: 2 additions & 1 deletion src/data.table.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ extern SEXP char_datatable;
extern SEXP char_dataframe;
extern SEXP char_NULL;
extern SEXP char_maxString;
extern SEXP char_AsIs;
extern SEXP sym_sorted;
extern SEXP sym_index;
extern SEXP sym_BY;
Expand Down Expand Up @@ -286,7 +287,7 @@ SEXP chmatchdup_R(SEXP, SEXP, SEXP);
SEXP chin_R(SEXP, SEXP);
SEXP freadR(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
SEXP fwriteR(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
SEXP rbindlist(SEXP, SEXP, SEXP, SEXP);
SEXP rbindlist(SEXP, SEXP, SEXP, SEXP, SEXP);
SEXP setlistelt(SEXP, SEXP, SEXP);
SEXP address(SEXP);
SEXP expandAltRep(SEXP);
Expand Down
3 changes: 2 additions & 1 deletion src/gsumm.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,8 @@ SEXP gmean(SEXP x, SEXP narmArg)
case REALSXP: {
if (INHERITS(x, char_integer64)) {
SEXP as = PROTECT(ScalarReal(1));
x = PROTECT(coerceAs(x, as, /*copyArg=*/ScalarLogical(TRUE))); protecti+=2;
x = PROTECT(coerceAs(x, as, /*copyArg=*/ScalarLogical(TRUE))); protecti++;
UNPROTECT(2); PROTECT(x); // PROTECT() is stack-based, UNPROTECT() back to 'as' then PROTECT() 'x' again
}
const double *restrict gx = gather(x, &anyNA);
ans = PROTECT(allocVector(REALSXP, ngrp)); protecti++;
Expand Down
2 changes: 2 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ SEXP char_datatable;
SEXP char_dataframe;
SEXP char_NULL;
SEXP char_maxString;
SEXP char_AsIs;
SEXP sym_sorted;
SEXP sym_index;
SEXP sym_BY;
Expand Down Expand Up @@ -260,6 +261,7 @@ void attribute_visible R_init_data_table(DllInfo *info)
char_dataframe = PRINTNAME(install("data.frame"));
char_NULL = PRINTNAME(install("NULL"));
char_maxString = PRINTNAME(install("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"));
char_AsIs = PRINTNAME(install("AsIs"));

if (TYPEOF(char_integer64) != CHARSXP) {
// checking one is enough in case of any R-devel changes
Expand Down
Loading

0 comments on commit b62c2da

Please sign in to comment.