-C Sync\sw/trunk
-D 2021-09-29T16:35:14.868
+C Fixes\sto\sthe\sversion\sof\s"varsep"\sgroup_concat\sso\sthat\s(1)\sit\sbuilds\sunder\nseparate\scompilation\sand\s(2)\somits\stabs\sin\ssource\scode\sand\s(3)\sruns\sfaster\nthan\strunk.\s\sThis\svariant\sof\sthe\sgroup_concat_varsep\sbranch\smight\sbe\spreferred\nover\sthe\stip\sbecause\sit\spreserves\s(undocumented)\slegacy\sbehavior\sabout\sthe\nposition\sof\sseparators\srelative\sto\sterms.
+D 2021-10-01T00:25:06.629
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F src/expr.c f2e0f5dd07d1b202f700f26b0851f2ea485e36ec8f335b05aec2cd91cd08853f
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 1905af1821b88321e1bb9d6a69e704495b6844a9b6c29398d40117cc251e893c
-F src/func.c c852d68d0a984263f969e3b84d602c6d821147a32905fecca65b1d86098367b4
+F src/func.c 35e0beafdbd8e9d7050577668ab3f515b86d8aff18bb81603d961d9152955b16
F src/global.c 612ea60c9acbcb45754c2ed659b4a56936a06814718e969636fedc7e3b889808
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
F src/pragma.c 4a473feae3646063996ce3bfae78032009fa950765908d97424f7578b202813c
F src/pragma.h b33c7a542ae7965c471f0d3c0565ce4d340c3f32cc162f44133539b6b0edb927
F src/prepare.c 8f07616db04337057b8498b72d051ee90f73c54615c2e908c05404cef1e060b7
-F src/printf.c 78fabb49b9ac9a12dd1c89d744abdc9b67fd3205e62967e158f78b965a29ec4b
+F src/printf.c 1ce574bf02b503b0e031a70d3453324a9f4a0eb1ad379f3324ced73b918ed20b
F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
F src/resolve.c b9e60afa56d0484ee573aba54d9e73603736236df33d2ae3421b4cd0367d907d
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/sqlite.h.in 4e977a5e2ed1a9e8987ff65a2cab5f99a4298ebf040ea5ff636e1753339ff45a
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h e97f4e9b509408fea4c4e9bef5a41608dfac343b4d3c7a990dedde1e19af9510
-F src/sqliteInt.h 06a8f97a644388b28c0a9428a6b2cdf40e8b51b1cf38064f41baba5fd810be49
+F src/sqliteInt.h 90aabdfc427a6356f0ff1ed77c886f823d10e08f100e992816dec1033c225079
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 3d148615f9d9c6a3d63d8eb015f3d70f453a66de49b28e665831254387c700b9 df0d7e36dbf98ab5405d8366ce92fb85176d4388b47a57b0ca1aa1ba6ae5212e
-R 4764117e20f212be49211212953ddad0
-U larrybr
-Z 559da611469829addf62248db5ff3864
+P a4c18b2f0ce4a0f4d0c4f4c25dc69fbed4cb4876d2b69e3e5e0e756410892d74
+R 247138f3b5e489fa491f98b9cd97dbe7
+T *branch * group_concat-fix-legacy
+T *sym-group_concat-fix-legacy *
+T -sym-group_concat_varsep *
+U drh
+Z 89839e6f88669e9a8e94fe2639f687c4
-a4c18b2f0ce4a0f4d0c4f4c25dc69fbed4cb4876d2b69e3e5e0e756410892d74
\ No newline at end of file
+04399cf9645e04b171090ff8a3c27752929c10d2cd8778e26f8f3337aa902ab6
\ No newline at end of file
/*
** group_concat(EXPR, ?SEPARATOR?)
+**
+** The SEPARATOR goes before the EXPR string. This is tragic. The
+** groupConcatInverse() implementation would have been easier if the
+** SEPARATOR were appended after EXPR. And the order is undocumented,
+** so we could change it, in theory. But the old behavior has been
+** around for so long that we dare not, for fear of breaking something.
*/
typedef struct {
StrAccum str; /* The accumulated concatenation */
#ifndef SQLITE_OMIT_WINDOWFUNC
int nAccum; /* Number of strings presently concatenated */
- int nFirstSepLength; /* Used to detect separator length change */
+ int nFirstSepLength; /* Used to detect separator length change */
/* If pnSepLengths!=0, refs an array of inter-string separator lengths,
- * stored as actually incorporated into presently accumulated result.
- * (Hence, its slots in use number nAccum-1 between method calls.)
- * If pnSepLengths==0, nFirstSepLength is the length used throughout.
- */
+ ** stored as actually incorporated into presently accumulated result.
+ ** (Hence, its slots in use number nAccum-1 between method calls.)
+ ** If pnSepLengths==0, nFirstSepLength is the length used throughout.
+ */
int *pnSepLengths;
#endif
} GroupConcatCtx;
sqlite3 *db = sqlite3_context_db_handle(context);
int firstTerm = pGCC->str.mxAlloc==0;
pGCC->str.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( argc==1 ){
+ if( !firstTerm ){
+ sqlite3_str_appendchar(&pGCC->str, 1, ',');
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ else{
+ pGCC->nFirstSepLength = 1;
+ }
+#endif
+ }else if( !firstTerm ){
+ zSep = (char*)sqlite3_value_text(argv[1]);
+ nSep = sqlite3_value_bytes(argv[1]);
+ if( zSep ){
+ sqlite3_str_append(&pGCC->str, zSep, nSep);
}
- if( zSep )
- sqlite3_str_append(&pGCC->str, zSep, nSep);
#ifndef SQLITE_OMIT_WINDOWFUNC
- else
- nSep = 0;
+ else{
+ nSep = 0;
+ }
if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){
- int * pnsl = pGCC->pnSepLengths;
- if( pnsl == 0 ){
- /* First separator length variation seen, start tracking them. */
- pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int));
- if( pnsl!=0 ){
- int i = 0, nA = pGCC->nAccum-1;
- while( i<nA ) pnsl[i++] = pGCC->nFirstSepLength;
- }
- }else{
- pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int));
- }
- if( pnsl!=0 ){
- if( pGCC->nAccum>0 )
- pnsl[pGCC->nAccum-1] = nSep;
- pGCC->pnSepLengths = pnsl;
- }else{
- setStrAccumError(&pGCC->str, SQLITE_NOMEM);
- }
+ int *pnsl = pGCC->pnSepLengths;
+ if( pnsl == 0 ){
+ /* First separator length variation seen, start tracking them. */
+ pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int));
+ if( pnsl!=0 ){
+ int i = 0, nA = pGCC->nAccum-1;
+ while( i<nA ) pnsl[i++] = pGCC->nFirstSepLength;
+ }
+ }else{
+ pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int));
+ }
+ if( pnsl!=0 ){
+ if( pGCC->nAccum>0 ){
+ pnsl[pGCC->nAccum-1] = nSep;
+ }
+ pGCC->pnSepLengths = pnsl;
+ }else{
+ sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM);
+ }
}
#endif
}
if( pGCC->pnSepLengths!=0 ){
assert(pGCC->nAccum >= 0);
if( pGCC->nAccum>0 ){
- nVS += *pGCC->pnSepLengths;
- memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1,
- (pGCC->nAccum-1)*sizeof(int));
+ nVS += *pGCC->pnSepLengths;
+ memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1,
+ (pGCC->nAccum-1)*sizeof(int));
}
}else{
/* If removing single accumulated string, harmlessly over-do. */
sqlite3_result_error_toobig(context);
}else if( pAccum->accError==SQLITE_NOMEM ){
sqlite3_result_error_nomem(context);
- }else{
- sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
+ }else{
+ int n = pAccum->nChar;
+ sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), n,
sqlite3_free);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
sqlite3_result_error_nomem(context);
}else{
const char *zText = sqlite3_str_value(pAccum);
- sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
}
}
}
/*
** Set the StrAccum object to an error mode.
*/
-static void setStrAccumError(StrAccum *p, u8 eError){
+void sqlite3StrAccumSetError(StrAccum *p, u8 eError){
assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
p->accError = eError;
if( p->mxAlloc ) sqlite3_str_reset(p);
char *z;
if( pAccum->accError ) return 0;
if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){
- setStrAccumError(pAccum, SQLITE_TOOBIG);
+ sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG);
return 0;
}
z = sqlite3DbMallocRaw(pAccum->db, n);
if( z==0 ){
- setStrAccumError(pAccum, SQLITE_NOMEM);
+ sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
}
return z;
}
return 0;
}
if( p->mxAlloc==0 ){
- setStrAccumError(p, SQLITE_TOOBIG);
+ sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
return p->nAlloc - p->nChar - 1;
}else{
char *zOld = isMalloced(p) ? p->zText : 0;
}
if( szNew > p->mxAlloc ){
sqlite3_str_reset(p);
- setStrAccumError(p, SQLITE_TOOBIG);
+ sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
return 0;
}else{
p->nAlloc = (int)szNew;
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
sqlite3_str_reset(p);
- setStrAccumError(p, SQLITE_NOMEM);
+ sqlite3StrAccumSetError(p, SQLITE_NOMEM);
return 0;
}
}
memcpy(zText, p->zText, p->nChar+1);
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
}else{
- setStrAccumError(p, SQLITE_NOMEM);
+ sqlite3StrAccumSetError(p, SQLITE_NOMEM);
}
p->zText = zText;
return zText;
void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
char *sqlite3StrAccumFinish(StrAccum*);
+void sqlite3StrAccumSetError(StrAccum*, u8);
void sqlite3SelectDestInit(SelectDest*,int,int);
Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);