Evaluate multiple window functions in a single pass if they use the same

window definition. Add xValue callbacks for other built-in aggregate
functions.

FossilOrigin-Name: c9f0f140941660ff368e5bb5752d54feb1964b7a9eac986d4bfb8f24a1c20d86
This commit is contained in:
dan 2018-05-17 19:24:08 +00:00
parent 2e362f9775
commit e2f781b9d1
9 changed files with 173 additions and 87 deletions

View File

@ -1,5 +1,5 @@
C Handle\smultiple\swindow-functions\sin\sa\ssingle\squery.
D 2018-05-17T14:26:27.790
C Evaluate\smultiple\swindow\sfunctions\sin\sa\ssingle\spass\sif\sthey\suse\sthe\ssame\nwindow\sdefinition.\sAdd\sxValue\scallbacks\sfor\sother\sbuilt-in\saggregate\nfunctions.
D 2018-05-17T19:24:08.904
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
@ -445,10 +445,10 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
F src/delete.c b0f90749e22d5e41a12dbf940f4811138cf97da54b46b737089b93eb64a2896f
F src/expr.c af55e984d86b29f9cc1fbb785fd665ac254806d9ad5f791c668414dcb8ddcf0b
F src/expr.c 75cef2e9fa3318c284faeea2c259100b7538776ca47573bf45b7b45c06ba0825
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
F src/func.c 03c99a50c69f7d565e13179aad26af703b9df7752a4d690af1540c5e04ababc2
F src/func.c b1a5122c69ef13c7bf0100e792ca539a36034c1b50476233ded6d2f72afcfbfc
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
@ -491,14 +491,14 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
F src/prepare.c 95a9dba7a5d032039a77775188cb3b6fb17f2fa1a0b7cd915b30b4b823383ffa
F src/printf.c 1d1b4a568a58d0f32a5ff26c6b98db8a6e1883467f343a6406263cacd2e60c21
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 8feaf2039bd1b17dd5021e0c5731cde741694b59032d0faf5c73df499c880ebf
F src/resolve.c 446f60b2e0d2440bb233d6a69a4ed0f2ad030a4e63ac4b3cfc0e98cf73d9c5a3
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 0b9d051a0b97d9ae20947e74f341dde248f15bbfda1834932b3d21097f4e080c
F src/select.c 2b4bc6bb66b85a9ba8bd4ad4161d0d6b32fcfdf6d472229a08364d3f0c407fe5
F src/shell.c.in 53affa90711f280342f7238f9c9aa9dcaed321ec6218a18043cf92154ef8a704
F src/sqlite.h.in 34be2d0d18bf4726538793bdc9854cd87f689fda4b3789515134cdbd68188cf4
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
F src/sqliteInt.h ecb9f7d12a22f557d66cafd7a3ea1c2bbfb6773c4b274eb7410ac017c3e18472
F src/sqliteInt.h 6b3400a90f179542045ed318c780bf73675b19b3de437506859adf998a41e125
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@ -581,7 +581,7 @@ F src/where.c 60ec752fcbe9f9e0271ac60548d159a540a1ee47a4f9fedc85e88a3d0e392dd1
F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53
F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
F src/window.c 33cc7de721edb12ddae639b96f537535e237edcd576c8d946e4a0b66d912a5db
F src/window.c 33d3751eb1442ce8a7e428e028cbc6c220359446a7ab2a9514244c3edfea1b63
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@ -1613,7 +1613,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test c088fff1b97ec6dc51bc6c6df936e7d2fd2d4b2708fa9738fe13aa175a7e47c4
F test/window1.test 5278e1578b55867e69e050376daef1eb6f6b4557fd728e5babb610c086af9f08
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
@ -1730,7 +1730,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 3781e520854808fe02ad3fe77dd11fc917448c58ff1fd79123289dd91937decd
R ab1ec0d66b6e5c3f79bc48c2607263f7
P 35af0b750e70dcf0f343b115f4bbd0860a7e8064be204d4dfba1a43c22ff07b1
R e0e67ced56bb91a58c4c8146b7d7e3b8
U dan
Z dc655b7af30130730642201f8ff47123
Z b68147f44c001ca2d08d81bf2dc7bdbf

View File

@ -1 +1 @@
35af0b750e70dcf0f343b115f4bbd0860a7e8064be204d4dfba1a43c22ff07b1
c9f0f140941660ff368e5bb5752d54feb1964b7a9eac986d4bfb8f24a1c20d86

View File

@ -1286,7 +1286,11 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
*pzBuffer = zAlloc;
}
}else{
pNew->pWin = winDup(db, p->pWin);
if( ExprHasProperty(p, EP_Reduced|EP_TokenOnly) ){
pNew->pWin = 0;
}else{
pNew->pWin = winDup(db, p->pWin);
}
if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
if( pNew->op==TK_SELECT_COLUMN ){
pNew->pLeft = p->pLeft;

View File

@ -1675,6 +1675,20 @@ static void groupConcatFinalize(sqlite3_context *context){
}
}
}
static void groupConcatValue(sqlite3_context *context){
sqlite3_str *pAccum;
pAccum = (sqlite3_str*)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{
const char *zText = sqlite3_str_value(pAccum);
sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
}
}
}
/*
** This routine does per-connection function registration. Most
@ -1859,14 +1873,16 @@ void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
WFUNCTION(sum, 1, 0, sumStep, sumFinalize, sumFinalize, 0),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
WAGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize),
WAGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
WAGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
AGGREGATE2(count, 0, 0, 0, countStep, countFinalize,
SQLITE_FUNC_COUNT ),
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
WAGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize,
groupConcatValue),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize,
groupConcatValue),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE

View File

@ -776,13 +776,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
if( pExpr->pWin ){
pExpr->pWin->pNextWin = pNC->pWin;
pNC->pWin = pExpr->pWin;
if( 0==pNC->pWin
|| 0==sqlite3WindowCompare(pParse, pNC->pWin, pExpr->pWin)
){
pExpr->pWin->pNextWin = pNC->pWin;
pNC->pWin = pExpr->pWin;
}
pExpr->pWin->pFunc = pDef;
pExpr->pWin->nArg = pExpr->x.pList->nExpr;
}
else
{
pExpr->pWin->nArg = (pExpr->x.pList ? pExpr->x.pList->nExpr : 0);
}else{
NameContext *pNC2 = pNC;
pExpr->op = TK_AGG_FUNCTION;
pExpr->op2 = 0;

View File

@ -5415,17 +5415,20 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
struct WindowRewrite *p = pWalker->u.pRewrite;
Parse *pParse = pWalker->pParse;
int rc = WRC_Continue;
switch( pExpr->op ){
case TK_FUNCTION:
if( pExpr->pWin==0 ){
break;
}else if( pExpr->pWin==p->pWin ){
rc = WRC_Prune;
pExpr->pWin->pOwner = pExpr;
break;
}else{
Window *pWin;
for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){
if( pExpr->pWin==pWin ){
pExpr->pWin->pOwner = pExpr;
return WRC_Prune;
}
}
}
/* Fall through. */
@ -5451,7 +5454,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
break;
}
return rc;
return WRC_Continue;
}
static int selectWindowRewriteEList(
@ -5532,41 +5535,46 @@ static int selectWindowRewrite(Parse *pParse, Select *p){
ExprList *pSort = 0;
ExprList *pSublist = 0; /* Expression list for sub-query */
Window *pWin = p->pWin;
Window *pMWin = p->pWin; /* Master window object */
Window *pWin; /* Window object iterator */
p->pSrc = 0;
p->pWhere = 0;
p->pGroupBy = 0;
p->pHaving = 0;
pWin->regAccum = ++pParse->nMem;
pWin->regResult = ++pParse->nMem;
/* Assign a cursor number for the ephemeral table used to buffer rows.
** The OpenEphemeral instruction is coded later, after it is known how
** many columns the table will have. */
pWin->iEphCsr = pParse->nTab++;
pMWin->iEphCsr = pParse->nTab++;
rc = selectWindowRewriteEList(pParse, pWin, p->pEList, &pSublist);
rc = selectWindowRewriteEList(pParse, pMWin, p->pEList, &pSublist);
if( rc ) return rc;
rc = selectWindowRewriteEList(pParse, pWin, p->pOrderBy, &pSublist);
rc = selectWindowRewriteEList(pParse, pMWin, p->pOrderBy, &pSublist);
if( rc ) return rc;
pWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
/* Create the ORDER BY clause for the sub-select. This is the concatenation
** of the window PARTITION and ORDER BY clauses. Append the same
** expressions to the sub-select expression list. They are required to
** figure out where boundaries for partitions and sets of peer rows. */
pSort = sqlite3ExprListDup(db, pWin->pPartition, 0);
if( pWin->pOrderBy ){
pSort = exprListAppendList(pParse, pSort, pWin->pOrderBy);
pSort = sqlite3ExprListDup(db, pMWin->pPartition, 0);
if( pMWin->pOrderBy ){
pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy);
}
pSublist = exprListAppendList(pParse, pSublist, pSort);
/* Also append the arguments passed to the window function to the
** sub-select expression list. */
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList);
/* Append the arguments passed to each window function to the
** sub-select expression list. Also allocate two registers for each
** window function - one for the accumulator, another for interim
** results. */
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList);
pWin->regAccum = ++pParse->nMem;
pWin->regResult = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
}
pSub = sqlite3SelectNew(
pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
@ -5582,7 +5590,6 @@ static int selectWindowRewrite(Parse *pParse, Select *p){
}else{
pSub->selFlags |= SF_Expanded;
}
pWin->pNextWin = 0;
}
#if SELECTTRACE_ENABLED
@ -5592,8 +5599,7 @@ static int selectWindowRewrite(Parse *pParse, Select *p){
}
#endif
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pWin->iEphCsr, pWin->nBufferCol);
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pMWin->nBufferCol);
}
return rc;
@ -6061,7 +6067,7 @@ int sqlite3Select(
}
if( !isAgg && pGroupBy==0 ){
Window *pWin = p->pWin;
Window *pMWin = p->pWin; /* Master window object (or NULL) */
int regPart = 0;
/* No aggregate functions and no GROUP BY clause */
@ -6069,9 +6075,9 @@ int sqlite3Select(
assert( WHERE_USE_LIMIT==SF_FixedLimit );
wctrlFlags |= p->selFlags & SF_FixedLimit;
if( pWin ){
int nPart = (pWin->pPartition ? pWin->pPartition->nExpr : 0);
nPart += (pWin->pOrderBy ? pWin->pOrderBy->nExpr : 0);
if( pMWin ){
int nPart = (pMWin->pPartition ? pMWin->pPartition->nExpr : 0);
nPart += (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0);
if( nPart ){
regPart = pParse->nMem+1;
pParse->nMem += nPart;
@ -6107,7 +6113,8 @@ int sqlite3Select(
}
assert( p->pEList==pEList );
if( p->pWin ){
if( pMWin ){
Window *pWin;
int k;
int iSubCsr = p->pSrc->a[0].iCursor;
int nSub = p->pSrc->a[0].pTab->nCol;
@ -6128,29 +6135,31 @@ int sqlite3Select(
/* Check if this is the start of a new partition or peer group. */
if( regPart ){
ExprList *pPart = pWin->pPartition;
ExprList *pPart = pMWin->pPartition;
int nPart = (pPart ? pPart->nExpr : 0);
ExprList *pOrderBy = pWin->pOrderBy;
ExprList *pOrderBy = pMWin->pOrderBy;
int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
int addrGoto = 0;
int addrJump = 0;
if( pPart ){
int regNewPart = reg + pWin->nBufferCol;
int regNewPart = reg + pMWin->nBufferCol;
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pPart, 0, 0);
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, regPart, nPart);
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
}
if( pOrderBy ){
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
}
}
if( pOrderBy ){
int regNewPeer = reg + pWin->nBufferCol + nPart;
int regNewPeer = reg + pMWin->nBufferCol + nPart;
int regPeer = regPart + nPart;
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0, 0);
@ -6158,51 +6167,58 @@ int sqlite3Select(
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
sqlite3VdbeAddOp3(v,
OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
sqlite3VdbeAddOp3(v,
OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
}
if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto);
}
addrGosub = sqlite3VdbeAddOp1(v, OP_Gosub, regGosub);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pWin->iEphCsr);
sqlite3VdbeAddOp3(v,OP_Copy,reg+pWin->nBufferCol,regPart,nPart+nPeer-1);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
sqlite3VdbeAddOp3(
v, OP_Copy, reg+pMWin->nBufferCol, regPart, nPart+nPeer-1
);
sqlite3VdbeJumpHere(v, addrJump);
}
/* Invoke step function for window functions */
sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg+pWin->iArgCol, pWin->regAccum);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg+pWin->iArgCol, pWin->regAccum);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
}
/* Buffer the current row in the ephemeral table. */
if( pWin->nBufferCol>0 ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pWin->nBufferCol, regRecord);
if( pMWin->nBufferCol>0 ){
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, pMWin->nBufferCol, regRecord);
}else{
sqlite3VdbeAddOp2(v, OP_Blob, 0, regRecord);
sqlite3VdbeAppendP4(v, (void*)"", 0);
}
sqlite3VdbeAddOp2(v, OP_NewRowid, pWin->iEphCsr, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, pWin->iEphCsr, regRecord, regRowid);
sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
/* End the database scan loop. */
sqlite3WhereEnd(pWInfo);
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, pWin->nArg);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
}
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, sqlite3VdbeCurrentAddr(v)+2);
sqlite3VdbeAddOp0(v, OP_Goto);
if( regPart ){
sqlite3VdbeJumpHere(v, addrGosub);
}
addr = sqlite3VdbeAddOp1(v, OP_Rewind, pWin->iEphCsr);
addr = sqlite3VdbeAddOp1(v, OP_Rewind, pMWin->iEphCsr);
selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, addr+1, 0);
sqlite3VdbeAddOp2(v, OP_Next, pWin->iEphCsr, addr+1);
sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, addr+1);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp1(v, OP_Return, regGosub);
sqlite3VdbeJumpHere(v, addr-1); /* OP_Goto jumps here */

View File

@ -1716,16 +1716,16 @@ struct FuncDestructor {
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
(void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} }
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,0,0,#zName, {0}}
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,0,#zName, {0}}
#define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,0,0,#zName, {0}}
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}}
#define WFUNCTION(zName, nArg, arg, xStep, xFinal, xValue, xInverse) \
{nArg, SQLITE_UTF8, \
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}}
#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}}
/*
** All current savepoints are stored in a linked list starting at
@ -3493,6 +3493,7 @@ struct Window {
void sqlite3WindowDelete(sqlite3*, Window*);
Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*);
void sqlite3WindowAttach(Parse*, Expr*, Window*);
int sqlite3WindowCompare(Parse*, Window*, Window*);
/*
** Assuming zIn points to the first byte of a UTF-8 character,

View File

@ -51,3 +51,19 @@ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
sqlite3WindowDelete(pParse->db, pWin);
}
}
/*
** Return 0 if the two window objects are identical, or non-zero otherwise.
*/
int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){
if( p1->eType!=p2->eType ) return 1;
if( p1->eStart!=p2->eStart ) return 1;
if( p1->eEnd!=p2->eEnd ) return 1;
if( sqlite3ExprCompare(pParse, p1->pStart, p2->pStart, -1) ) return 1;
if( sqlite3ExprCompare(pParse, p1->pEnd, p2->pEnd, -1) ) return 1;
if( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1;
if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1;
return 0;
}

View File

@ -136,4 +136,35 @@ do_execsql_test 4.8 {
6 6 9
}
do_execsql_test 4.9 {
SELECT a,
sum(a) OVER (ORDER BY a),
avg(a) OVER (ORDER BY a)
FROM t2 ORDER BY a
} {
0 0 0.0
1 1 0.5
2 3 1.0
3 6 1.5
4 10 2.0
5 15 2.5
6 21 3.0
}
do_execsql_test 4.10 {
SELECT a,
count() OVER (ORDER BY a DESC),
group_concat(a, '.') OVER (ORDER BY a DESC)
FROM t2 ORDER BY a DESC
} {
6 1 6
5 2 6.5
4 3 6.5.4
3 4 6.5.4.3
2 5 6.5.4.3.2
1 6 6.5.4.3.2.1
0 7 6.5.4.3.2.1.0
}
finish_test