diff --git a/.gitignore b/.gitignore index 51cc13cd69..04c838d16c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,10 @@ src/Makevars .emacs.desktop .emacs.desktop.lock +# Sublime Text IDE files +*.sublime-project +*.sublime-workspace + # RStudio IDE files .Rproj.user data.table.Rproj diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index d26f7ff509..f873c85f7f 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -6996,6 +6996,8 @@ DT1 = data.table(date=as.POSIXct("2014-06-22", format="%Y-%m-%d", tz="GMT")) DT2 = data.table(date=as.Date("2014-06-23")) test(1494.1, rbind(DT1, DT2), error="Class attribute on column") test(1494.2, rbind(DT2, DT1), error="Class attribute on column") +test(1494.3, rbind(DT1, DT2), error="Class attribute on column 1 (Date) of item 2 does not match with column 1 (POSIXct, POSIXt) of item 1") +test(1494.4, rbind(DT2, DT1), error="Class attribute on column 1 (POSIXct, POSIXt) of item 2 does not match with column 1 (Date) of item 1") # test 1495 has been added to melt's test section (fix for #1055) diff --git a/po/data.table.pot b/po/data.table.pot index cea9c55a58..60a4977d45 100644 --- a/po/data.table.pot +++ b/po/data.table.pot @@ -4066,34 +4066,34 @@ msgid "" "'message'|'warning'|'error'|'none'. See news item 5 in v1.12.2." msgstr "" -#: rbindlist.c:298 +#: rbindlist.c:300 #, c-format msgid "" "Column %d of item %d has type 'factor' but has no levels; i.e. malformed." msgstr "" -#: rbindlist.c:316 +#: rbindlist.c:320 #, c-format msgid "" -"Class attribute on column %d of item %d does not match with column %d of " -"item %d." +"Class attribute on column %d (%s) of item %d does not match with column %d " +"(%s) of item %d." msgstr "" -#: rbindlist.c:326 +#: rbindlist.c:332 #, c-format msgid "" "Internal error: column %d of result is determined to be integer64 but " "maxType=='%s' != REALSXP" msgstr "" -#: rbindlist.c:362 +#: rbindlist.c:368 #, c-format msgid "" "Failed to allocate working memory for %d ordered factor levels of result " "column %d" msgstr "" -#: rbindlist.c:383 +#: rbindlist.c:389 #, c-format msgid "" "Column %d of item %d is an ordered factor but level %d ['%s'] is missing " @@ -4102,7 +4102,7 @@ msgid "" "factor will be created for this column." msgstr "" -#: rbindlist.c:388 +#: rbindlist.c:394 #, c-format msgid "" "Column %d of item %d is an ordered factor with '%s'<'%s' in its levels. But " @@ -4110,14 +4110,14 @@ msgid "" "will be created for this column due to this ambiguity." msgstr "" -#: rbindlist.c:433 +#: rbindlist.c:439 #, c-format msgid "" "Failed to allocate working memory for %d factor levels of result column %d " "when reading item %d of item %d" msgstr "" -#: rbindlist.c:523 +#: rbindlist.c:529 #, c-format msgid "Column %d of item %d: %s" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index d9b54a4435..819b098fa6 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -4397,7 +4397,7 @@ msgstr "" "options()$datatable.rbindlist.check=='%s' 不" "是'message'|'warning'|'error'|'none'。参见 v1.12.2 更新信息中的第 5 项。" -#: rbindlist.c:298 +#: rbindlist.c:300 #, c-format msgid "" "Column %d of item %d has type 'factor' but has no levels; i.e. malformed." @@ -4405,14 +4405,15 @@ msgstr "" "第%2$d 项的第 %1$d 列为因子('factor')类型却没有因子水平(levels),格式错" "误。" -#: rbindlist.c:316 +#: rbindlist.c:320 #, c-format msgid "" -"Class attribute on column %d of item %d does not match with column %d of " -"item %d." -msgstr "第 %2$d 项的第 %1$d 列的类属性与第 %4$d 项的第 %3$d列的不匹配。" +"Class attribute on column %d (%s) of item %d does not match with column %d " +"(%s) of item %d." +msgstr "第 %3$d 项的第 %1$d (%2$s) 列的类属性与第 %6$d 项的第 %4$d (%5$d) " +"列的不匹配。" -#: rbindlist.c:326 +#: rbindlist.c:332 #, c-format msgid "" "Internal error: column %d of result is determined to be integer64 but " @@ -4420,14 +4421,14 @@ msgid "" msgstr "" "内部错误:结果中的第 %d 列应为 integer64 类型,但maxType=='%s' != REALSXP" -#: rbindlist.c:362 +#: rbindlist.c:368 #, c-format msgid "" "Failed to allocate working memory for %d ordered factor levels of result " "column %d" msgstr "未能为结果中第 %d 列的 %d 个有序因子水平分配工作内存" -#: rbindlist.c:383 +#: rbindlist.c:389 #, c-format msgid "" "Column %d of item %d is an ordered factor but level %d ['%s'] is missing " @@ -4439,7 +4440,7 @@ msgstr "" "(level)['%4$s']在第 %6$d 项第 %5$d 列的有序因子水平中缺失。每组有序因子水平" "应为其中最长有序因子水平的子集。该列将被创建为一非有序因子列。" -#: rbindlist.c:388 +#: rbindlist.c:394 #, c-format msgid "" "Column %d of item %d is an ordered factor with '%s'<'%s' in its levels. But " @@ -4450,7 +4451,7 @@ msgstr "" "的有序因子水平中却 '%5$s'<'%6$s'。由于这种模糊性,该列将被创建为一非有序因子" "列。" -#: rbindlist.c:433 +#: rbindlist.c:439 #, c-format msgid "" "Failed to allocate working memory for %d factor levels of result column %d " @@ -4458,7 +4459,7 @@ msgid "" msgstr "" "当读取第%4$d项的第%3$d个子项时,无法为第%2$d列的%1$d个因素水平分配工作内存" -#: rbindlist.c:523 +#: rbindlist.c:529 #, c-format msgid "Column %d of item %d: %s" msgstr "第 %2$d 项的第 %1$d 列: %3$s" diff --git a/src/data.table.h b/src/data.table.h index d045d50f44..8daa04812e 100644 --- a/src/data.table.h +++ b/src/data.table.h @@ -241,6 +241,7 @@ bool islocked(SEXP x); SEXP islockedR(SEXP x); bool need2utf8(SEXP x); SEXP coerceUtf8IfNeeded(SEXP x); +SEXP concatCharVec(SEXP x, const char *sep); // types.c char *end(char *start); diff --git a/src/rbindlist.c b/src/rbindlist.c index bb42502be6..467f08176a 100644 --- a/src/rbindlist.c +++ b/src/rbindlist.c @@ -310,10 +310,11 @@ SEXP rbindlist(SEXP l, SEXP usenamesArg, SEXP fillArg, SEXP idcolArg) if (firsti==-1) { firsti=i; firstw=w; firstCol=thisCol; } else { if (!factor && !int64) { - if (!R_compute_identical(PROTECT(getAttrib(thisCol, R_ClassSymbol)), - PROTECT(getAttrib(firstCol, R_ClassSymbol)), - 0)) { - error(_("Class attribute on column %d of item %d does not match with column %d of item %d."), w+1, i+1, firstw+1, firsti+1); + SEXP thisClass = PROTECT(getAttrib(thisCol, R_ClassSymbol)); + SEXP firstClass = PROTECT(getAttrib(firstCol, R_ClassSymbol)); + if (!R_compute_identical(thisClass, firstClass, 0)) { + error(_("Class attribute on column %d (%s) of item %d does not match with column %d (%s) of item %d."), + w+1, CHAR(concatCharVec(thisClass, ", ")), i+1, firstw+1, CHAR(concatCharVec(firstClass, ", ")), firsti+1); } UNPROTECT(2); } diff --git a/src/utils.c b/src/utils.c index 8a3598f575..68ade8425d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -381,3 +381,38 @@ SEXP dt_zlib_version() { return ScalarString(mkChar(out)); } +// Concatenate a character vector into a single CHARSXP, e.g. for printing error messages +// adapted from https://stackoverflow.com/a/58163237 +// make sure to *UNPROTECT* the returned CHARSXP after use +SEXP concatCharVec (SEXP x, const char *sep) +{ + char *concatenated = NULL; /* pointer to concatenated string w/sep */ + size_t lensep = strlen (sep), /* length of separator */ + sz = 0; /* current stored size */ + int first = 1; /* flag whether first term */ + + /* check that a character vector has been passed */ + if (TYPEOF(x) != STRSXP) + error(_("Internal error: unsupported type '%s' passed to concatCharVec()"), type2char(TYPEOF(x))); // # nocov + + for (R_xlen_t i=0; i