Changeset: d10aa7212852 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=d10aa7212852 Added Files: sql/test/group-concat/Tests/groupconcat05.sql sql/test/group-concat/Tests/groupconcat05.stable.err sql/test/group-concat/Tests/groupconcat05.stable.out Modified Files: clients/Tests/MAL-signatures.stable.out clients/Tests/MAL-signatures.stable.out.int128 clients/Tests/exports.stable.out gdk/gdk_aggr.c gdk/gdk_calc.h monetdb5/modules/kernel/aggr.c monetdb5/modules/kernel/aggr.mal monetdb5/modules/kernel/aggr.mal.sh monetdb5/modules/mal/01_calc.mal monetdb5/modules/mal/01_calc.mal.sh monetdb5/modules/mal/calc.c sql/ChangeLog sql/backends/monet5/sql_statement.c sql/backends/monet5/sql_upgrades.c sql/scripts/51_sys_schema_extension.sql sql/test/Tests/systemfunctions.stable.out sql/test/Tests/systemfunctions.stable.out.int128 sql/test/group-concat/Tests/All sql/test/group-concat/Tests/groupconcat01.stable.out sql/test/group-concat/Tests/groupconcat02.stable.out sql/test/group-concat/Tests/groupconcat03.sql sql/test/group-concat/Tests/groupconcat03.stable.out sql/test/group-concat/Tests/groupconcat04.stable.out Branch: default Log Message:
Implemented group_concat(X,Y) where Y is a string to be used as the separator in the result. Also fixed the implementation for empty strings. diffs (truncated from 1314 to 300 lines): diff --git a/clients/Tests/MAL-signatures.stable.out b/clients/Tests/MAL-signatures.stable.out --- a/clients/Tests/MAL-signatures.stable.out +++ b/clients/Tests/MAL-signatures.stable.out @@ -205,10 +205,15 @@ Ready. [ "aggr", "stdevp", "command aggr.stdevp(b:bat[:sht], g:bat[:oid], e:bat[:any_1]):bat[:dbl] ", "AGGRstdevp3_dbl;", "Grouped tail standard deviation (population/biased) on sht" ] [ "aggr", "stdevp", "command aggr.stdevp(b:bat[:any_2]):dbl ", "ALGstdevp;", "Gives the standard deviation of all tail values" ] [ "aggr", "str_group_concat", "command aggr.str_group_concat(b:bat[:str], g:bat[:oid], e:bat[:any_1]):bat[:str] ", "AGGRstr_group_concat;", "Grouped string tail concat" ] +[ "aggr", "str_group_concat", "command aggr.str_group_concat(b:bat[:str], sep:bat[:str], g:bat[:oid], e:bat[:any_1]):bat[:str] ", "AGGRstr_group_concat_sep;", "Grouped string tail concat with custom separator" ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B." ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B." ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], s:bat[:oid]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list." ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], s:bat[:oid], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with separator SEP." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with separator SEP." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str], s:bat[:oid]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list and separator SEP." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str], s:bat[:oid], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list and separator SEP." ] [ "aggr", "subavg", "command aggr.subavg(b:bat[:bte], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubavg1_dbl;", "Grouped average aggregate" ] [ "aggr", "subavg", "command aggr.subavg(b:bat[:dbl], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubavg1_dbl;", "Grouped average aggregate" ] [ "aggr", "subavg", "command aggr.subavg(b:bat[:flt], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubavg1_dbl;", "Grouped average aggregate" ] @@ -316,7 +321,9 @@ Ready. [ "aggr", "substdevp", "command aggr.substdevp(b:bat[:lng], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubstdevpcand_dbl;", "Grouped standard deviation (population/biased) aggregate with candidates list" ] [ "aggr", "substdevp", "command aggr.substdevp(b:bat[:sht], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubstdevpcand_dbl;", "Grouped standard deviation (population/biased) aggregate with candidates list" ] [ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concat;", "Grouped string concat" ] +[ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], sep:bat[:str], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concat_sep;", "Grouped string concat with custom separator" ] [ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concatcand;", "Grouped string concat with candidates list" ] +[ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], sep:bat[:str], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concatcand_sep;", "Grouped string concat with candidates list with custom separator" ] [ "aggr", "subsum", "command aggr.subsum(b:bat[:bte], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:bte] ", "AGGRsubsum_bte;", "Grouped sum aggregate" ] [ "aggr", "subsum", "command aggr.subsum(b:bat[:dbl], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubsum_dbl;", "Grouped sum aggregate" ] [ "aggr", "subsum", "command aggr.subsum(b:bat[:flt], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubsum_dbl;", "Grouped sum aggregate" ] diff --git a/clients/Tests/MAL-signatures.stable.out.int128 b/clients/Tests/MAL-signatures.stable.out.int128 --- a/clients/Tests/MAL-signatures.stable.out.int128 +++ b/clients/Tests/MAL-signatures.stable.out.int128 @@ -244,10 +244,15 @@ Ready. [ "aggr", "stdevp", "command aggr.stdevp(b:bat[:sht], g:bat[:oid], e:bat[:any_1]):bat[:dbl] ", "AGGRstdevp3_dbl;", "Grouped tail standard deviation (population/biased) on sht" ] [ "aggr", "stdevp", "command aggr.stdevp(b:bat[:any_2]):dbl ", "ALGstdevp;", "Gives the standard deviation of all tail values" ] [ "aggr", "str_group_concat", "command aggr.str_group_concat(b:bat[:str], g:bat[:oid], e:bat[:any_1]):bat[:str] ", "AGGRstr_group_concat;", "Grouped string tail concat" ] +[ "aggr", "str_group_concat", "command aggr.str_group_concat(b:bat[:str], sep:bat[:str], g:bat[:oid], e:bat[:any_1]):bat[:str] ", "AGGRstr_group_concat_sep;", "Grouped string tail concat with custom separator" ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B." ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B." ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], s:bat[:oid]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list." ] [ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], s:bat[:oid], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with separator SEP." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with separator SEP." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str], s:bat[:oid]):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list and separator SEP." ] +[ "aggr", "str_group_concat", "pattern aggr.str_group_concat(b:bat[:str], sep:bat[:str], s:bat[:oid], nil_if_empty:bit):str ", "CMDBATstr_group_concat;", "Calculate aggregate string concatenate of B with candidate list and separator SEP." ] [ "aggr", "subavg", "command aggr.subavg(b:bat[:bte], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubavg1_dbl;", "Grouped average aggregate" ] [ "aggr", "subavg", "command aggr.subavg(b:bat[:dbl], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubavg1_dbl;", "Grouped average aggregate" ] [ "aggr", "subavg", "command aggr.subavg(b:bat[:flt], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubavg1_dbl;", "Grouped average aggregate" ] @@ -375,7 +380,9 @@ Ready. [ "aggr", "substdevp", "command aggr.substdevp(b:bat[:lng], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubstdevpcand_dbl;", "Grouped standard deviation (population/biased) aggregate with candidates list" ] [ "aggr", "substdevp", "command aggr.substdevp(b:bat[:sht], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubstdevpcand_dbl;", "Grouped standard deviation (population/biased) aggregate with candidates list" ] [ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concat;", "Grouped string concat" ] +[ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], sep:bat[:str], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concat_sep;", "Grouped string concat with custom separator" ] [ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concatcand;", "Grouped string concat with candidates list" ] +[ "aggr", "substr_group_concat", "command aggr.substr_group_concat(b:bat[:str], sep:bat[:str], g:bat[:oid], e:bat[:any_1], s:bat[:oid], skip_nils:bit, abort_on_error:bit):bat[:str] ", "AGGRsubstr_group_concatcand_sep;", "Grouped string concat with candidates list with custom separator" ] [ "aggr", "subsum", "command aggr.subsum(b:bat[:bte], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:bte] ", "AGGRsubsum_bte;", "Grouped sum aggregate" ] [ "aggr", "subsum", "command aggr.subsum(b:bat[:dbl], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubsum_dbl;", "Grouped sum aggregate" ] [ "aggr", "subsum", "command aggr.subsum(b:bat[:flt], g:bat[:oid], e:bat[:any_1], skip_nils:bit, abort_on_error:bit):bat[:dbl] ", "AGGRsubsum_dbl;", "Grouped sum aggregate" ] diff --git a/clients/Tests/exports.stable.out b/clients/Tests/exports.stable.out --- a/clients/Tests/exports.stable.out +++ b/clients/Tests/exports.stable.out @@ -131,7 +131,7 @@ BAT *BATgroupquantile(BAT *b, BAT *g, BA BAT *BATgroupsize(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int abort_on_error); BAT *BATgroupstdev_population(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int abort_on_error); BAT *BATgroupstdev_sample(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int abort_on_error); -BAT *BATgroupstr_group_concat(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int abort_on_error); +BAT *BATgroupstr_group_concat(BAT *b, BAT *g, BAT *e, BAT *s, int skip_nils, int abort_on_error, const str separator); BAT *BATgroupsum(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int abort_on_error); BAT *BATgroupvariance_population(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int abort_on_error); BAT *BATgroupvariance_sample(BAT *b, BAT *g, BAT *e, BAT *s, int tp, int skip_nils, int abort_on_error); @@ -170,7 +170,7 @@ void BATsetcount(BAT *b, BUN cnt); void BATsetprop(BAT *b, int idx, int type, void *v); BAT *BATslice(BAT *b, BUN low, BUN high); gdk_return BATsort(BAT **sorted, BAT **order, BAT **groups, BAT *b, BAT *o, BAT *g, int reverse, int stable) __attribute__((__warn_unused_result__)); -gdk_return BATstr_group_concat(ValPtr res, BAT *b, BAT *s, int skip_nils, int abort_on_error, int nil_if_empty); +gdk_return BATstr_group_concat(ValPtr res, BAT *b, BAT *s, int skip_nils, int abort_on_error, int nil_if_empty, const str separator); gdk_return BATsubcross(BAT **r1p, BAT **r2p, BAT *l, BAT *r, BAT *sl, BAT *sr) __attribute__((__warn_unused_result__)); gdk_return BATsum(void *res, int tp, BAT *b, BAT *s, int skip_nils, int abort_on_error, int nil_if_empty); gdk_return BATthetajoin(BAT **r1p, BAT **r2p, BAT *l, BAT *r, BAT *sl, BAT *sr, int op, int nil_matches, BUN estimate) __attribute__((__warn_unused_result__)); @@ -608,6 +608,7 @@ str AGGRquantile3(bat *retval, const bat str AGGRstdev3_dbl(bat *retval, const bat *bid, const bat *gid, const bat *eid); str AGGRstdevp3_dbl(bat *retval, const bat *bid, const bat *gid, const bat *eid); str AGGRstr_group_concat(bat *retval, const bat *bid, const bat *gid, const bat *eid); +str AGGRstr_group_concat_sep(bat *retval, const bat *bid, const bat *sepp, const bat *gid, const bat *eid); str AGGRsubavg1_dbl(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubavg1cand_dbl(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bat *sid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubavg2_dbl(bat *retval1, bat *retval2, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); @@ -645,7 +646,9 @@ str AGGRsubstdevcand_dbl(bat *retval, co str AGGRsubstdevp_dbl(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubstdevpcand_dbl(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bat *sid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubstr_group_concat(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); +str AGGRsubstr_group_concat_sep(bat *retval, const bat *bid, const bat *sepp, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubstr_group_concatcand(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bat *sid, const bit *skip_nils, const bit *abort_on_error); +str AGGRsubstr_group_concatcand_sep(bat *retval, const bat *bid, const bat *sepp, const bat *gid, const bat *eid, const bat *sid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubsum_bte(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubsum_dbl(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); str AGGRsubsum_flt(bat *retval, const bat *bid, const bat *gid, const bat *eid, const bit *skip_nils, const bit *abort_on_error); diff --git a/gdk/gdk_aggr.c b/gdk/gdk_aggr.c --- a/gdk/gdk_aggr.c +++ b/gdk/gdk_aggr.c @@ -3265,13 +3265,12 @@ BATgroupvariance_population(BAT *b, BAT static gdk_return concat_strings(void *res, int what, BAT* b, int nonil, oid seqb, BUN start, BUN end, BUN ngrp, const oid *restrict cand, - const oid *candend, const oid *restrict gids, oid min, oid max, int skip_nils, const char *func, - BUN *has_nils) + const oid *candend, const oid *restrict gids, oid min, oid max, int skip_nils, const str separator, + const char *func, BUN *has_nils) { oid gid; BUN i, p, q, nils = 0; const oid *aux; - const char *separator = ","; size_t* lengths = NULL, separator_length = strlen(separator), next_length; oid *lastoid = NULL; str* astrings = NULL, s, single_str = NULL; @@ -3296,20 +3295,16 @@ concat_strings(void *res, int what, BAT* BATloop(b,p,q) { s = BUNtail(bi, p); next_length = strlen(s); - if(next_length) { - single_length += next_length + separator_length; - single_oid = p; - } + single_length += next_length + separator_length; + single_oid = p; } } else { BATloop(b,p,q) { s = BUNtail(bi, p); if (strcmp(s, str_nil)) { next_length = strlen(s); - if(next_length) { - single_length += next_length + separator_length; - single_oid = p; - } + single_length += next_length + separator_length; + single_oid = p; } else { single_oid = BUN_NONE; nils = 1; @@ -3318,50 +3313,32 @@ concat_strings(void *res, int what, BAT* } } if(!nils) { - if(single_length > 0) { - if ((single_str = GDKmalloc((single_length + 1 - separator_length) * sizeof(str))) == NULL) { - GDKerror("%s: malloc failure\n", func); - rres = GDK_FAIL; - goto finish; - } - BATloop(b,p,q){ - s = BUNtail(bi, p); - next_length = strlen(s); - if(next_length) { - memcpy(single_str + offset, s, next_length); - offset += next_length; - if(p != single_oid) { - memcpy(single_str + offset, separator, separator_length); - offset += separator_length; - } - } + if ((single_str = GDKmalloc((single_length + 1 - separator_length) * sizeof(str))) == NULL) { + GDKerror("%s: malloc failure\n", func); + rres = GDK_FAIL; + goto finish; + } + BATloop(b,p,q){ + s = BUNtail(bi, p); + next_length = strlen(s); + memcpy(single_str + offset, s, next_length); + offset += next_length; + if(p != single_oid) { + memcpy(single_str + offset, separator, separator_length); + offset += separator_length; } - single_str[offset] = '\0'; - if(what == IS_A_BAT) { - if(BUNappend(bn, single_str, FALSE) != GDK_SUCCEED) { - GDKerror("%s: malloc failure\n", func); - rres = GDK_FAIL; - goto finish; - } - } else { - ValPtr pt = (ValPtr) res; - pt->len = single_str[offset]; - if((pt->val.sval = GDKstrdup(single_str)) == NULL) { - GDKerror("%s: malloc failure\n", func); - rres = GDK_FAIL; - goto finish; - } - } - } else if(what == IS_A_BAT) { - if(BUNappend(bn, "", FALSE) != GDK_SUCCEED) { + } + single_str[offset] = '\0'; + if(what == IS_A_BAT) { + if(BUNappend(bn, single_str, FALSE) != GDK_SUCCEED) { GDKerror("%s: malloc failure\n", func); rres = GDK_FAIL; goto finish; } } else { ValPtr pt = (ValPtr) res; - pt->len = 0; - if((pt->val.sval = GDKstrdup("")) == NULL) { + pt->len = single_str[offset]; + if((pt->val.sval = GDKstrdup(single_str)) == NULL) { GDKerror("%s: malloc failure\n", func); rres = GDK_FAIL; goto finish; @@ -3391,10 +3368,8 @@ concat_strings(void *res, int what, BAT* break; s = BUNtail(bi, i); next_length = strlen(s); - if(next_length > 0) { - single_length += next_length + separator_length; - single_oid = i; - } + single_length += next_length + separator_length; + single_oid = i; } } else { while (cand < candend && nils == 0) { @@ -3404,10 +3379,8 @@ concat_strings(void *res, int what, BAT* s = BUNtail(bi, i); if (strcmp(s, str_nil)) { next_length = strlen(s); - if(next_length > 0) { - single_length += next_length + separator_length; - single_oid = i; - } + single_length += next_length + separator_length; + single_oid = i; } else { single_oid = BUN_NONE; nils = 1; @@ -3416,35 +3389,27 @@ concat_strings(void *res, int what, BAT* } } if (!nils) { - if(single_length > 0) { - if ((single_str = GDKmalloc((single_length + 1 - separator_length) * sizeof(str))) == NULL) { - GDKerror("%s: malloc failure\n", func); - rres = GDK_FAIL; - goto finish; + if ((single_str = GDKmalloc((single_length + 1 - separator_length) * sizeof(str))) == NULL) { + GDKerror("%s: malloc failure\n", func); + rres = GDK_FAIL; + goto finish; + } + cand = aux; + while (cand < candend) { + i = *cand++ - seqb; + if (i >= end) + break; + s = BUNtail(bi, i); + next_length = strlen(s); + memcpy(single_str + offset, s, next_length); + offset += next_length; + if (i != single_oid) { + memcpy(single_str + offset, separator, separator_length); + offset += separator_length; } - cand = aux; - while (cand < candend) { - i = *cand++ - seqb; - if (i >= end) - break; - s = BUNtail(bi, i); - next_length = strlen(s); - if(next_length > 0) { - memcpy(single_str + offset, s, next_length); - offset += next_length; - if (i != single_oid) { - memcpy(single_str + offset, separator, separator_length); - offset += separator_length; - } - } - } - single_str[offset] = '\0'; - if (BUNappend(bn, single_str, FALSE) != GDK_SUCCEED) { - GDKerror("%s: malloc failure\n", func); - rres = GDK_FAIL; - goto finish; - } - } else if (BUNappend(bn, "", FALSE) != GDK_SUCCEED) { + } + single_str[offset] = '\0'; + if (BUNappend(bn, single_str, FALSE) != GDK_SUCCEED) { GDKerror("%s: malloc failure\n", func); rres = GDK_FAIL; goto finish; @@ -3476,10 +3441,8 @@ concat_strings(void *res, int what, BAT* s = BUNtail(bi, i); if (strcmp(s, str_nil)) { next_length = strlen(s); - if(next_length > 0) { - lengths[gid] += next_length + separator_length; - lastoid[gid] = i; _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list