Compare commits

...

5 Commits

Author SHA1 Message Date
larrybr 7f1c89cbf6 Adjust 3 query result expectations to reflect changed group_concat() behavior with varying separator.
FossilOrigin-Name: 86f9c07a4fbbba1efb413f84f337d4b80539f3909913b2f5d9c4b86654e8fac4
2021-09-30 21:42:56 +00:00
larrybr ed2bfb4d76 Simplify windowed group_concat() by allowing a change in undocumented behavior (fails some new tests)
FossilOrigin-Name: 9d8e6167380cdb8520e4893e36862450b8bbe990f33668b5546dec32eab41df9
2021-09-30 17:20:23 +00:00
larrybr 34896c6855 Sync w/trunk
FossilOrigin-Name: a4c18b2f0ce4a0f4d0c4f4c25dc69fbed4cb4876d2b69e3e5e0e756410892d74
2021-09-29 16:35:14 +00:00
dan a92f9586e0 Add extra tests for the group_concat() fix on this branch.
FossilOrigin-Name: 3d148615f9d9c6a3d63d8eb015f3d70f453a66de49b28e665831254387c700b9
2021-09-29 14:14:16 +00:00
larrybr dde13e6f88 Get group_concat() to handle varying separator lengths when windowing
FossilOrigin-Name: 98e0f2bf67cdee1da1edadeb54ff8564728b3f28fc821e46e8de201247c3fc87
2021-09-29 00:32:13 +00:00
8 changed files with 188 additions and 60 deletions
+12 -11
View File
@@ -1,5 +1,5 @@
C Update\sa\stest\scase\sin\srtreedoc.test\sto\saccount\sfor\sthe\sfact\sthat\srelease\sbuilds\sgenerate\sfewer\sVM\sinstructions\sthan\sdebug\sbuilds.
D 2021-09-30T10:47:10.633
C Adjust\s3\squery\sresult\sexpectations\sto\sreflect\schanged\sgroup_concat()\sbehavior\swith\svarying\sseparator.
D 2021-09-30T21:42:56.551
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -504,7 +504,7 @@ F src/delete.c 3ce6af6b64c8b476de51ccc32da0cb3142d42e65754e1d8118addf65b8bcba15
F src/expr.c 82797e5d82422d34ede9a95ba459f40c317b2daadb21109a21abfd42f84e3ed8
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 1905af1821b88321e1bb9d6a69e704495b6844a9b6c29398d40117cc251e893c
F src/func.c 812ac5383067bed7150d8597e83c47b714d73db0e62af55811d1a145243e58e1
F src/func.c 0fc0672cc663e31aab57c2d42e820c394f3a987a296734821583adecd7dab108
F src/global.c 612ea60c9acbcb45754c2ed659b4a56936a06814718e969636fedc7e3b889808
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
@@ -645,7 +645,7 @@ F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test cc47afa5e11e0d6771a85a4993fa6ff721480ddb53ea538ec3fdbafb720bd505
F test/aggnested.test a755b9e42c9ab151cb037b2a8e75bfd6e561b9bfbfc6dc36bb4988d1aac7d94a
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
F test/alter.test f53d8a4ecd35f051c07e54a36beec5d0a30d30a9d98bc723f6cde6afbfb3c5ca
@@ -1040,7 +1040,7 @@ F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f75
F test/fts4unicode.test 82a9c16b68ba2f358a856226bb2ee02f81583797bc4744061c54401bf1a0f4c9
F test/fts4upfrom.test f25835162c989dffd5e2ef91ec24c4848cc9973093e2d492d1c7b32afac1b49d
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test 77f6ea02c97d9ea64074461d347276a75df22d2cf51045a40f90857569e985f0
F test/func.test 2d84a919fe063b50ebe28ffc0a2b2b845692349007ba73f40d9568254bb13dcc
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab6a
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
@@ -1799,10 +1799,11 @@ F test/window8.tcl 5e02e41d9d9a80f597063aed1a381eb19d1d0ef677a4f0df352c5365cf23f
F test/window8.test 4ab16817414af0c904abe2ebdf88eb6c2b00058b84f9748c6174ff11fc45f1ed
F test/window9.test 349c71eab4288a1ffc19e2f65872ec2c37e6cf8a1dda2ad300364b7450ae4836
F test/windowA.test 6d63dc1260daa17141a55007600581778523a8b420629f1282d2acfc36af23be
F test/windowB.test 6e601f8178ba8ba28b2f19e74fe613815084bb4a8d2ad942defc7d42e191e521
F test/windowB.test cb96e42def6fb00a5d74a49079e756a106678ef0f09bae4753944338e60627cb
F test/windowC.test 1e290a18ffaf406b6da7a7be90a4ec17cc39624413055274406b4a4dece019fb
F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387019e0
F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b
F test/windowfault.test 21919e601f20b976ea2a73aa401220c89ed0e8d203c4f69476ea55bce3726496
F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c
F test/windowpushd.test d8895d08870b7226f7693665bd292eb177e62ca06799184957b3ca7dc03067df
F test/with1.test 7bc5abfe4c80c0cef8a90f5a66d60b9982e8ccd7350c8eb70611323a3b8e07ba
F test/with2.test f803743b2c746ecdd0b638783c7235654b947b0f1c4bb551ca10e1d813317153
@@ -1928,7 +1929,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 5d771f3554f3c98872cd0c9f12f415e685f26fcb923e3fb7f1a7a760c7a53255
R 7836a39a0844715bc15a7a735276f745
U dan
Z 6f61e641e71e433b9c88547a5dd22a12
P 9d8e6167380cdb8520e4893e36862450b8bbe990f33668b5546dec32eab41df9
R 13a6ced210d825c6aadf5b9a5a0f5baf
U larrybr
Z ea3c08c26ece7b1db5af199831ae8aee
+1 -1
View File
@@ -1 +1 @@
7d16b302826fec3606dbc6e20df0d2182f6946a2ed4076d2412d1df30c552ecb
86f9c07a4fbbba1efb413f84f337d4b80539f3909913b2f5d9c4b86654e8fac4
+60 -46
View File
@@ -1716,96 +1716,110 @@ static void minMaxFinalize(sqlite3_context *context){
/*
** group_concat(EXPR, ?SEPARATOR?)
*/
typedef struct {
StrAccum str; /* The accumulated concatenation */
int nLastSepLength; /* Length of last-appended separator*/
} GroupConcatCtx;
static void groupConcatStep(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zVal;
StrAccum *pAccum;
GroupConcatCtx *pGCC;
const char *zSep;
int nVal, nSep;
assert( argc==1 || argc==2 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
if( pAccum ){
sqlite3 *db = sqlite3_context_db_handle(context);
int firstTerm = pAccum->mxAlloc==0;
pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
if( !firstTerm ){
if( argc==2 ){
zSep = (char*)sqlite3_value_text(argv[1]);
nSep = sqlite3_value_bytes(argv[1]);
}else{
zSep = ",";
nSep = 1;
}
if( zSep ) sqlite3_str_append(pAccum, zSep, nSep);
pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
if( pGCC ){
if( argc==2 ){
zSep = (char*)sqlite3_value_text(argv[1]);
nSep = sqlite3_value_bytes(argv[1]);
}else{
zSep = ",";
nSep = 1;
}
zVal = (char*)sqlite3_value_text(argv[0]);
nVal = sqlite3_value_bytes(argv[0]);
if( zVal ) sqlite3_str_append(pAccum, zVal, nVal);
if( pGCC->str.mxAlloc==0 ){
sqlite3 *db = sqlite3_context_db_handle(context);
pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
}
if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal);
if( zSep ) sqlite3_str_append(&pGCC->str, zSep, nSep);
else nSep = 0;
pGCC->nLastSepLength = nSep;
}
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatInverse(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int n;
StrAccum *pAccum;
GroupConcatCtx *pGCC;
assert( argc==1 || argc==2 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
/* pAccum is always non-NULL since groupConcatStep() will have always
pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
/* pGCC is always non-NULL since groupConcatStep() will have always
** run frist to initialize it */
if( ALWAYS(pAccum) ){
n = sqlite3_value_bytes(argv[0]);
if( argc==2 ){
n += sqlite3_value_bytes(argv[1]);
if( ALWAYS(pGCC) ){
int nVS = sqlite3_value_bytes(argv[0]);
nVS += (argc==2)? sqlite3_value_bytes(argv[1]) : 1;
if( nVS>=(int)pGCC->str.nChar ){
pGCC->str.nChar = 0;
}else{
n++;
pGCC->str.nChar -= nVS;
memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar);
}
if( n>=(int)pAccum->nChar ){
pAccum->nChar = 0;
}else{
pAccum->nChar -= n;
memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar);
if( pGCC->str.nChar==0 ){
pGCC->str.mxAlloc = 0;
pGCC->nLastSepLength = 0;
}
if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;
}
}
#else
# define groupConcatInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void groupConcatFinalize(sqlite3_context *context){
StrAccum *pAccum;
pAccum = sqlite3_aggregate_context(context, 0);
if( pAccum ){
if( pAccum->accError==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(context);
}else if( pAccum->accError==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
}else{
sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
sqlite3_free);
GroupConcatCtx *pGCC
= (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
if( pGCC ){
switch( pGCC->str.accError ){
case SQLITE_TOOBIG:
sqlite3_result_error_toobig(context);
break;
case SQLITE_NOMEM:
sqlite3_result_error_nomem(context);
break;
default:{
int nc = pGCC->str.nChar - pGCC->nLastSepLength;
assert(nc >= 0);
pGCC->str.nChar = nc;
sqlite3_result_text(context, sqlite3StrAccumFinish(&pGCC->str),
nc, sqlite3_free);
}
}
}
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void groupConcatValue(sqlite3_context *context){
sqlite3_str *pAccum;
pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0);
if( pAccum ){
GroupConcatCtx *pGCC
= (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
if( pGCC ){
StrAccum *pAccum = &pGCC->str;
if( pAccum->accError==SQLITE_TOOBIG ){
sqlite3_result_error_toobig(context);
}else if( pAccum->accError==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
}else{
const char *zText = sqlite3_str_value(pAccum);
sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
int nc = pGCC->str.nChar - pGCC->nLastSepLength;
assert(nc >= 0);
sqlite3_result_text(context, zText, nc, SQLITE_TRANSIENT);
}
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ do_test aggnested-1.4 {
db eval {
SELECT (SELECT group_concat(a1,b1) FROM t2) FROM t1;
}
} {151 252 353}
} {141 242 343}
# This test case is a copy of the one in
+1 -1
View File
@@ -1145,7 +1145,7 @@ do_test func-24.3 {
execsql {
SELECT group_concat(t1,' ' || rowid || ' ') FROM tbl1
}
} {{this 2 program 3 is 4 free 5 software}}
} {{this 1 program 2 is 3 free 4 software}}
do_test func-24.4 {
execsql {
SELECT group_concat(NULL,t1) FROM tbl1
+8
View File
@@ -9,6 +9,7 @@
#
#***********************************************************************
# Test cases for RANGE BETWEEN and especially with NULLS LAST
# and for varying separator handling by group_concat().
#
set testdir [file dirname $argv0]
@@ -356,5 +357,12 @@ do_execsql_test 8.1 {
FROM t1;
} {111 660 938 979}
do_execsql_test 9.0 {
CREATE TABLE seps(x);
INSERT INTO seps(x) VALUES ('1'), ('22'), ('333'), ('4444');
SELECT group_concat('-', x)
OVER ( ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING )
FROM seps;
} {-1- -1-22- -22-333- -333-}
finish_test
+66
View File
@@ -0,0 +1,66 @@
# 2021-09-29
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# Test cases for varying separator handling by group_concat().
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix windowC
ifcapable !windowfunc {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE x1(i INTEGER PRIMARY KEY, x);
}
foreach {tn bBlob seps} {
1 0 {a b c def g}
2 0 {abcdefg {} {} abcdefg}
3 0 {a bc def ghij klmno pqrstu}
4 1 {a bc def ghij klmno pqrstu}
5 1 {, , , , , , , , , , , , ....... , ,}
} {
foreach type {text blob} {
do_test 1.$type.$tn.1 {
execsql { DELETE FROM x1 }
foreach s $seps {
if {$type=="text"} {
execsql {INSERT INTO x1 VALUES(NULL, $s)}
} else {
execsql {INSERT INTO x1 VALUES(NULL, CAST ($s AS blob))}
}
}
} {}
foreach {tn2 win} {
1 "ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"
2 "ROWS BETWEEN 2 PRECEDING AND CURRENT ROW"
3 "ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING"
} {
do_test 1.$type.$tn.2.$tn2 {
db eval "
SELECT group_concat('val', x) OVER ( ORDER BY i $win ) AS val FROM x1
" {
if {[string range $val 0 2]!="val"
|| [string range $val end-2 end]!="val"
} {
error "unexpected return value: $val"
}
}
} {}
}
}
}
finish_test
+39
View File
@@ -292,4 +292,43 @@ do_faultsim_test 12 -faults oom* -prep {
faultsim_test_result {0 {}}
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 13.0 {
CREATE TABLE t1(id INTEGER PRIMARY KEY, a, b);
INSERT INTO t1 VALUES(1, '1', 'a');
INSERT INTO t1 VALUES(2, '22', 'b');
INSERT INTO t1 VALUES(3, '333', 'c');
INSERT INTO t1 VALUES(4, '4444', 'dddd');
INSERT INTO t1 VALUES(5, '55555', 'e');
INSERT INTO t1 VALUES(6, '666666', 'f');
INSERT INTO t1 VALUES(7, '7777777', 'gggggggggg');
} {}
set queryres [list {*}{
1b22
1b22c333
22c333dddd4444
333dddd4444e55555
4444e55555f666666
55555f666666gggggggggg7777777
666666gggggggggg7777777
}]
do_execsql_test 13.1 {
SELECT group_concat(a, b) OVER (
ORDER BY id RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING
) FROM t1
} $queryres
do_faultsim_test 13 -faults oom* -prep {
} -body {
execsql {
SELECT group_concat(a, b) OVER (
ORDER BY id RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING
) FROM t1
}
} -test {
faultsim_test_result [list 0 $::queryres]
}
finish_test