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:
parent
2e362f9775
commit
e2f781b9d1
24
manifest
24
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
35af0b750e70dcf0f343b115f4bbd0860a7e8064be204d4dfba1a43c22ff07b1
|
||||
c9f0f140941660ff368e5bb5752d54feb1964b7a9eac986d4bfb8f24a1c20d86
|
@ -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;
|
||||
|
28
src/func.c
28
src/func.c
@ -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
|
||||
|
@ -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;
|
||||
|
126
src/select.c
126
src/select.c
@ -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 */
|
||||
|
@ -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,
|
||||
|
16
src/window.c
16
src/window.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user