-C Merge\slatest\strunk\schanges\sinto\sthis\sbranch.
-D 2018-05-22T20:36:12.808
+C Add\ssupport\sfor\s"ROWS\sBETWEEN\s<expr>\sPRECEDING\sAND\s<expr>\sFOLLOWING"\swindow\nframes.
+D 2018-05-23T20:55:37.621
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c 8270813c8f0ca91b2802e88ded3755d04ee962a923d431c13bcb6cf3e0c18f63
-F src/btree.h 448f15b98ea85dcf7e4eb76f731cadb89636c676ad25dfaac6de77cd66556598
+F src/btree.c b8fc4fcf851316fc0b84d4aa46899d127df952c39cfeb067bc97036060df1138
+F src/btree.h d46a8e31a4bd15572cdb6f2c940966f57b605b865628028c5eccf7d1bed83bac
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
F src/build.c 50ff3e0fa07646b4d797aae0f773efcdb7602f6a5e2f5da27856503f35200889
F src/callback.c fe677cb5f5abb02f7a772a62a98c2f516426081df68856e8f2d5f950929b966a
F src/expr.c bb57b0b5ba1351335091ce4ec43b40968746f03afd65c9e2920d7cbe4dc98133
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
-F src/func.c b1a5122c69ef13c7bf0100e792ca539a36034c1b50476233ded6d2f72afcfbfc
+F src/func.c eff9c15696cda3485df3ae52ce3663692a2cd506fba63a5f49f56cb204831021
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 446f60b2e0d2440bb233d6a69a4ed0f2ad030a4e63ac4b3cfc0e98cf73d9c5a3
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
-F src/select.c 1ebe775c0651bf357ab83b4c9b9139194149cfe1277dfa3e16f3ed73669b6b04
+F src/select.c 8a7f842a049a3407079e0b0748de916dcd91c00377394b2e8b1aefc5972a0b2f
F src/shell.c.in 51c100206f4b7f86cd9affd80b764825e0edc36ca0190c442e4ca7994611bfe2
F src/sqlite.h.in 34be2d0d18bf4726538793bdc9854cd87f689fda4b3789515134cdbd68188cf4
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
-F src/sqliteInt.h a3f0edb26ebfee6107fa99f3c300e71018ad23addeeba0746a4ac62425e36f3f
+F src/sqliteInt.h 735b04170551a899e8703421c376f98c19503b8210ad4cd2e0f35b85b6af595d
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
F src/vacuum.c 37730af7540033135909ecaee3667dddec043293428d8718546d0d64ba4a5025
-F src/vdbe.c d83cfec9ebf523d5b2a8a3756ba8f23e39723725334a2e2e947e602ef6e6b278
+F src/vdbe.c 89c76c95a24e2561f5f94ef8530bd0127d512ed56b62932047ef89076d58fa91
F src/vdbe.h d970d9738efdd09cb2df73e3a40856e7df13e88a3486789c49fcdd322c9eb8a2
F src/vdbeInt.h 3878856fab3a8e64d27d472909e391db9d82f4f8b902a1737a1f7f351299ff52
F src/vdbeapi.c 29d2baf9c1233131ec467d7bed1b7c8a03c27579048d768c4b04acf427838858
F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53
F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
-F src/window.c 37eb02c2af935f207ba902ef25ec27d635b68bb1567f9e5994a6720bac1c093e
+F src/window.c 1313e941d1e50a44594e6f3e12bc7d0fe6f092ea35c1f3884c31bd224ba66d29
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test 5705337783d220b47f6fb4432264543b7557a05be8013d772f57d71f2fded271
-F test/window2.tcl 7e0b692974a18ae0992dd2e76be83d8e1c6c5cac3190d84fa62911ab0e5c7896
-F test/window2.test e1453371b605e54eeb2264fc3a4a23c5eba93e95f6c7f3230fce9d34b4b5e8a4
+F test/window2.tcl 29e9bb16a52eb1e9e8f376519185af5c64eed88a8e6f0bee54237ba2971803a7
+F test/window2.test f580e1cc96d1ccb6bb220d1e338525ee5541e45e2206ed9ca74417ba862d8a62
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 16168146b202915252f9375aef38e65ca20c5d4aa906e851d4d3a484db57562d c6071ac99cfa4b6272ac4d739fc61a85acb544f6c1c2ae67b31e92aadcc995bd
-R a9163894154abe7467dbbc7b918577f5
+P cdb68d2c64e453fdcd29437d5915c5c5ab6fbc7b5ffac52f4cb393f35b4a0124
+R 20d653691e285483f3e3bdb0b082aa4b
U dan
-Z 671adb87a45ec21df0f125088181e31d
+Z e628ea8085262c078f67c7957c5a3c95
Window *sqlite3WindowAlloc(
Parse *pParse,
int eType,
- int eEnd, Expr *pEnd,
- int eStart, Expr *pStart
+ int eStart, Expr *pStart,
+ int eEnd, Expr *pEnd
){
Window *pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
}
}
+static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
+ static const char *azErr[] = {
+ "frame starting offset must be a non-negative integer",
+ "frame ending offset must be a non-negative integer"
+ };
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ int regZero = ++pParse->nMem;
+
+
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
+ sqlite3VdbeAddOp3(v, OP_Ge, regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
+ sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
+ sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
+}
+
+static void windowCodeRowExprStep(
+ Parse *pParse,
+ Select *p,
+ WhereInfo *pWInfo,
+ int regGosub,
+ int addrGosub
+){
+ Window *pMWin = p->pWin;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ Window *pWin;
+ int k;
+ int iSubCsr = p->pSrc->a[0].iCursor;
+ int nSub = p->pSrc->a[0].pTab->nCol;
+ int regFlushPart; /* Register for "Gosub flush_partition" */
+ int addrFlushPart; /* Label for "Gosub flush_partition" */
+ int addrDone; /* Label for "Gosub flush_partition_done" */
+
+ int reg = pParse->nMem+1;
+ int regRecord = reg+nSub;
+ int regRowid = regRecord+1;
+ int addr;
+ int csrPrec = pParse->nTab++;
+ int csrFollow = pParse->nTab++;
+ int regPrec; /* Value of <expr> PRECEDING */
+ int regFollow; /* Value of <expr> FOLLOWING */
+ int addrNext;
+ int addrGoto;
+ int addrIfPos1;
+ int addrIfPos2;
+
+ pParse->nMem += nSub + 2;
+
+ /* Allocate register and label for the "flush_partition" sub-routine. */
+ regFlushPart = ++pParse->nMem;
+ addrFlushPart = sqlite3VdbeMakeLabel(v);
+ addrDone = sqlite3VdbeMakeLabel(v);
+
+ regPrec = ++pParse->nMem;
+ regFollow = ++pParse->nMem;
+
+ /* Martial the row returned by the sub-select into an array of
+ ** registers. */
+ for(k=0; k<nSub; k++){
+ sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
+ }
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
+
+ /* Check if this is the start of a new partition. If so, call the
+ ** flush_partition sub-routine. */
+ if( pMWin->pPartition ){
+ ExprList *pPart = pMWin->pPartition;
+ int nPart = (pPart ? pPart->nExpr : 0);
+ int addrJump = 0;
+ int regNewPart = reg + pMWin->nBufferCol;
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
+
+ addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
+ sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+ addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
+ sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
+ sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart);
+ }
+
+ /* Buffer the current row in the ephemeral table. */
+ sqlite3VdbeAddOp2(v, OP_NewRowid, pMWin->iEphCsr, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
+
+ /* End of the input loop */
+ sqlite3WhereEnd(pWInfo);
+
+ /* Invoke "flush_partition" to deal with the final (or only) partition */
+ sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
+ addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
+
+ /* flush_partition: */
+ sqlite3VdbeResolveLabel(v, addrFlushPart);
+ sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, csrPrec, pMWin->iEphCsr);
+ sqlite3VdbeAddOp2(v, OP_OpenDup, csrFollow, pMWin->iEphCsr);
+
+ sqlite3ExprCode(pParse, pMWin->pStart, regPrec);
+ sqlite3ExprCode(pParse, pMWin->pEnd, regFollow);
+
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regResult);
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regAccum);
+
+ /* If either regPrec or regFollow are not non-negative integers, throw an
+ ** exception. */
+ windowCheckFrameValue(pParse, regPrec, 0);
+ windowCheckFrameValue(pParse, regFollow, 1);
+
+ sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, addrDone);
+ sqlite3VdbeAddOp2(v, OP_Rewind, csrPrec, addrDone);
+ sqlite3VdbeChangeP5(v, 1);
+ sqlite3VdbeAddOp2(v, OP_Rewind, csrFollow, addrDone);
+ sqlite3VdbeChangeP5(v, 1);
+
+ /* Invoke AggStep function for each window function using the row that
+ ** csrFollow currently points to. Or, if csrFollow is already at EOF,
+ ** do nothing. */
+ addrNext = sqlite3VdbeCurrentAddr(v);
+ sqlite3VdbeAddOp2(v, OP_Next, csrFollow, addrNext+2);
+ sqlite3VdbeAddOp0(v, OP_Goto);
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ int i;
+ for(i=0; i<pWin->nArg; i++){
+ sqlite3VdbeAddOp3(v, OP_Column, csrFollow, pWin->iArgCol+i, reg+i);
+ }
+ sqlite3VdbeAddOp3(v, OP_AggStep0, 0, reg, pWin->regAccum);
+ sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
+ }
+ sqlite3VdbeJumpHere(v, addrNext+1);
+
+ addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regFollow, 0 , 1);
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ sqlite3VdbeAddOp3(v,
+ OP_AggFinal, pWin->regAccum, pWin->nArg, pWin->regResult
+ );
+ sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+ }
+ sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
+ sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
+
+ addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regPrec, 0 , 1);
+ sqlite3VdbeAddOp2(v, OP_Next, csrPrec, sqlite3VdbeCurrentAddr(v)+1);
+ for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
+ int i;
+ for(i=0; i<pWin->nArg; i++){
+ sqlite3VdbeAddOp3(v, OP_Column, csrPrec, pWin->iArgCol+i, reg+i);
+ }
+ sqlite3VdbeAddOp3(v, OP_AggStep0, 1, reg, pWin->regAccum);
+ sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
+ }
+ sqlite3VdbeJumpHere(v, addrIfPos2);
+
+ sqlite3VdbeJumpHere(v, addrIfPos1);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
+
+ /* flush_partition_done: */
+ sqlite3VdbeResolveLabel(v, addrDone);
+ sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
+ sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
+
+ /* Jump to here to skip over flush_partition */
+ sqlite3VdbeJumpHere(v, addrGoto);
+}
+
+static void windowCodeDefaultStep(
+ Parse *pParse,
+ Select *p,
+ WhereInfo *pWInfo,
+ int regGosub,
+ int addrGosub
+){
+ Window *pMWin = p->pWin;
+ Vdbe *v = sqlite3GetVdbe(pParse);
+ Window *pWin;
+ int k;
+ int iSubCsr = p->pSrc->a[0].iCursor;
+ int nSub = p->pSrc->a[0].pTab->nCol;
+ int reg = pParse->nMem+1;
+ int regRecord = reg+nSub;
+ int regRowid = regRecord+1;
+ int addr;
+
+ pParse->nMem += nSub + 2;
+
+ /* Martial the row returned by the sub-select into an array of
+ ** registers. */
+ for(k=0; k<nSub; k++){
+ sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
+ }
+
+ /* Check if this is the start of a new partition or peer group. */
+ if( pMWin->regPart ){
+ ExprList *pPart = pMWin->pPartition;
+ int nPart = (pPart ? pPart->nExpr : 0);
+ ExprList *pOrderBy = pMWin->pOrderBy;
+ int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
+ int addrGoto = 0;
+ int addrJump = 0;
+
+ if( pPart ){
+ int regNewPart = reg + pMWin->nBufferCol;
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
+ addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
+ sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+ addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
+ 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 + pMWin->nBufferCol + nPart;
+ int regPeer = pMWin->regPart + nPart;
+
+ KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
+ if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
+ addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
+ sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
+ addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
+ 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);
+ }
+
+ sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
+ sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
+ sqlite3VdbeAddOp3(
+ v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1
+ );
+
+ sqlite3VdbeJumpHere(v, addrJump);
+ }
+
+ /* Invoke step function for window functions */
+ 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( 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, pMWin->iEphCsr, regRowid);
+ sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
+
+ /* End the database scan loop. */
+ sqlite3WhereEnd(pWInfo);
+
+ 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, addrGosub);
+}
+
+
/*
** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
**
Select *p,
WhereInfo *pWInfo,
int regGosub,
- int addrGosub
+ int addrGosub,
+ int *pbLoop
){
- Vdbe *v = sqlite3GetVdbe(pParse);
- Window *pWin;
Window *pMWin = p->pWin;
- int k;
- int iSubCsr = p->pSrc->a[0].iCursor;
- int nSub = p->pSrc->a[0].pTab->nCol;
- int reg = pParse->nMem+1;
- int regRecord = reg+nSub;
- int regRowid = regRecord+1;
- int addr;
-
- pParse->nMem += nSub + 2;
- /* Martial the row returned by the sub-select into an array of
- ** registers. */
- for(k=0; k<nSub; k++){
- sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
+ if( pMWin->eType==TK_ROWS
+ && pMWin->eStart==TK_PRECEDING
+ && pMWin->eEnd==TK_FOLLOWING
+ ){
+ *pbLoop = 0;
+ windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
+ return;
}
- /* Check if this is the start of a new partition or peer group. */
- if( pMWin->regPart ){
- ExprList *pPart = pMWin->pPartition;
- int nPart = (pPart ? pPart->nExpr : 0);
- ExprList *pOrderBy = pMWin->pOrderBy;
- int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
- int addrGoto = 0;
- int addrJump = 0;
-
- if( pPart ){
- int regNewPart = reg + pMWin->nBufferCol;
- KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pPart, 0, 0);
- addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
- sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
- addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
- 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 + pMWin->nBufferCol + nPart;
- int regPeer = pMWin->regPart + nPart;
-
- KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
- if( addrJump ) sqlite3VdbeJumpHere(v, addrJump);
- addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPeer, regPeer, nPeer);
- sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
- addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
- 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);
- }
-
- sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
- sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
- sqlite3VdbeAddOp3(
- v, OP_Copy, reg+pMWin->nBufferCol, pMWin->regPart, nPart+nPeer-1
- );
-
- sqlite3VdbeJumpHere(v, addrJump);
- }
-
- /* Invoke step function for window functions */
- 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( 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, pMWin->iEphCsr, regRowid);
- sqlite3VdbeAddOp3(v, OP_Insert, pMWin->iEphCsr, regRecord, regRowid);
-
- /* End the database scan loop. */
- sqlite3WhereEnd(pWInfo);
-
- 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, addrGosub);
+ *pbLoop = 1;
+ windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
}