mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Simplify the window function code generator some more.
FossilOrigin-Name: 45cbd3b4498cea8856f189e9d0a192556d4f15212055b8328a1beca6083fc47a
This commit is contained in:
12
manifest
12
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Improvements\sto\sthe\sway\sbuilt-in\swindow\sfunctions\sare\shandled.
|
C Simplify\sthe\swindow\sfunction\scode\sgenerator\ssome\smore.
|
||||||
D 2019-03-06T17:12:32.566
|
D 2019-03-06T21:04:11.725
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in 1ad7263f38329c0ecea543c80f30af839ee714ea77fc391bf1a3fbb919a5b6b5
|
F Makefile.in 1ad7263f38329c0ecea543c80f30af839ee714ea77fc391bf1a3fbb919a5b6b5
|
||||||
@@ -604,7 +604,7 @@ F src/where.c 8a207cb2ca6b99e1edb1e4bbff9b0504385a759cbf66180d1deb34d80ca4b799
|
|||||||
F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
|
F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
|
||||||
F src/wherecode.c ce7b21e1be2b981d62683fc59c4ca73a04a7ff2f1ebec23d41baf2da2349afd6
|
F src/wherecode.c ce7b21e1be2b981d62683fc59c4ca73a04a7ff2f1ebec23d41baf2da2349afd6
|
||||||
F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
|
F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
|
||||||
F src/window.c 607664ea225c3a9c2a7f55795741444bd6a95be37d1681ecf962cd5cb1618dba
|
F src/window.c 06257715857cb9c6fe51b5a6f9558701821d431b85313d27e1b96d1a81e1f8eb
|
||||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||||
@@ -1809,7 +1809,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P af0ea1363548461b2aad8fd54ee3f2f616111dcae2d6480f5294da44c87a0a5d
|
P e8eee566dfca6f4c8af074731dfe91f7fbcd9ca72f0303235b52e4e2e80d5b71
|
||||||
R 43bbe25e5bcdc3ad86ad389fa7d11dcc
|
R 10fe6da0769422f36eeeb42d0ed4992d
|
||||||
U dan
|
U dan
|
||||||
Z 3a11921edb0dd283221790b71f6938eb
|
Z 42de440ac1d651cb610f16495ca5b34a
|
||||||
|
@@ -1 +1 @@
|
|||||||
e8eee566dfca6f4c8af074731dfe91f7fbcd9ca72f0303235b52e4e2e80d5b71
|
45cbd3b4498cea8856f189e9d0a192556d4f15212055b8328a1beca6083fc47a
|
261
src/window.c
261
src/window.c
@@ -1844,8 +1844,8 @@ static void windowCodeRowExprStep(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return true if the entire partition should be cached in the temp
|
** Return true if the entire partition should be cached in the ephemeral
|
||||||
** table before processing.
|
** table before processing any rows.
|
||||||
*/
|
*/
|
||||||
static int windowCachePartition(Window *pMWin){
|
static int windowCachePartition(Window *pMWin){
|
||||||
Window *pWin;
|
Window *pWin;
|
||||||
@@ -1863,6 +1863,135 @@ static int windowCachePartition(Window *pMWin){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct WindowCodeArg WindowCodeArg;
|
||||||
|
struct WindowCodeArg {
|
||||||
|
Parse *pParse;
|
||||||
|
Window *pMWin;
|
||||||
|
Vdbe *pVdbe;
|
||||||
|
int regGosub;
|
||||||
|
int addrGosub;
|
||||||
|
int regArg;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WINDOW_RETURN_ROW 1
|
||||||
|
#define WINDOW_AGGINVERSE 2
|
||||||
|
#define WINDOW_AGGSTEP 3
|
||||||
|
|
||||||
|
static int windowCodeOp(
|
||||||
|
WindowCodeArg *p,
|
||||||
|
int op,
|
||||||
|
int csr,
|
||||||
|
int regCountdown,
|
||||||
|
int jumpOnEof
|
||||||
|
){
|
||||||
|
int ret = 0;
|
||||||
|
Vdbe *v = p->pVdbe;
|
||||||
|
int addrIf = 0;
|
||||||
|
|
||||||
|
if( regCountdown>0 ){
|
||||||
|
addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( jumpOnEof ){
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2);
|
||||||
|
ret = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
|
}else{
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( op ){
|
||||||
|
case WINDOW_RETURN_ROW:
|
||||||
|
windowAggFinal(p->pParse, p->pMWin, 0);
|
||||||
|
windowReturnOneRow(p->pParse, p->pMWin, p->regGosub, p->addrGosub);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WINDOW_AGGINVERSE:
|
||||||
|
windowAggStep(p->pParse, p->pMWin, csr, 1, p->regArg, p->pMWin->regSize);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WINDOW_AGGSTEP:
|
||||||
|
windowAggStep(p->pParse, p->pMWin, csr, 0, p->regArg, p->pMWin->regSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ret ){
|
||||||
|
sqlite3VdbeJumpHere(v, ret);
|
||||||
|
}
|
||||||
|
if( regCountdown>0 ){
|
||||||
|
sqlite3VdbeJumpHere(v, addrIf);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function - windowCodeStep() - generates the VM code that reads data
|
||||||
|
** from the sub-select and returns rows to the consumer. For the simplest
|
||||||
|
** case:
|
||||||
|
**
|
||||||
|
** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
|
||||||
|
**
|
||||||
|
** The VM code generated is equivalent in spirit to the following:
|
||||||
|
**
|
||||||
|
** while( !eof ){
|
||||||
|
** if( new partition ){
|
||||||
|
** Gosub flush
|
||||||
|
** }
|
||||||
|
** Insert new row into eph table.
|
||||||
|
**
|
||||||
|
** if( first row of partition ){
|
||||||
|
** Rewind(csrEnd, skipNext=1)
|
||||||
|
** Rewind(csrStart, skipNext=1)
|
||||||
|
** Rewind(csrCurrent, skipNext=1)
|
||||||
|
**
|
||||||
|
** regEnd = <expr2> // FOLLOWING expression
|
||||||
|
** regStart = <expr1> // PRECEDING expression
|
||||||
|
** }else{
|
||||||
|
** if( (regEnd--)<=0 ){
|
||||||
|
** Next(csrCurrent)
|
||||||
|
** Return one row.
|
||||||
|
** if( (regStart--)<0 ){
|
||||||
|
** Next(csrStart)
|
||||||
|
** AggInverse(csrStart)
|
||||||
|
** }
|
||||||
|
** }
|
||||||
|
** }
|
||||||
|
**
|
||||||
|
** Next(csrEnd)
|
||||||
|
** AggStep(csrEnd)
|
||||||
|
** }
|
||||||
|
** flush:
|
||||||
|
** while( 1 ){
|
||||||
|
** Next(csrCurrent)
|
||||||
|
** if( eof ) break
|
||||||
|
** Return one row.
|
||||||
|
** if( (regStart--)<0 ){
|
||||||
|
** Next(csrStart)
|
||||||
|
** AggInverse(csrStart)
|
||||||
|
** }
|
||||||
|
** }
|
||||||
|
** Empty eph table.
|
||||||
|
**
|
||||||
|
** More generally, the pattern used for all window types is:
|
||||||
|
**
|
||||||
|
** while( !eof ){
|
||||||
|
** if( new partition ){
|
||||||
|
** Gosub flush
|
||||||
|
** }
|
||||||
|
** Insert new row into eph table.
|
||||||
|
** if( first row of partition ){
|
||||||
|
** FIRST_ROW_CODE
|
||||||
|
** }else{
|
||||||
|
** SECOND_ROW_CODE
|
||||||
|
** }
|
||||||
|
** ALL_ROW_CODE
|
||||||
|
** }
|
||||||
|
** flush:
|
||||||
|
** FLUSH_CODE
|
||||||
|
** Empty eph table.
|
||||||
|
**
|
||||||
|
*/
|
||||||
static void windowCodeStep(
|
static void windowCodeStep(
|
||||||
Parse *pParse,
|
Parse *pParse,
|
||||||
Select *p,
|
Select *p,
|
||||||
@@ -1883,14 +2012,12 @@ static void windowCodeStep(
|
|||||||
int regStart; /* Value of <expr> PRECEDING */
|
int regStart; /* Value of <expr> PRECEDING */
|
||||||
int regEnd; /* Value of <expr> FOLLOWING */
|
int regEnd; /* Value of <expr> FOLLOWING */
|
||||||
|
|
||||||
int iSubCsr = p->pSrc->a[0].iCursor;
|
int iSubCsr = p->pSrc->a[0].iCursor; /* Cursor of sub-select */
|
||||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
int nSub = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */
|
||||||
int k;
|
int iCol; /* To iterate through sub cols */
|
||||||
|
|
||||||
int addrGoto;
|
int addrGoto;
|
||||||
int addrIf;
|
int addrIf;
|
||||||
int addrIfEnd;
|
|
||||||
int addrIfStart;
|
|
||||||
int addrGosubFlush;
|
int addrGosubFlush;
|
||||||
int addrInteger;
|
int addrInteger;
|
||||||
int addrCacheRewind;
|
int addrCacheRewind;
|
||||||
@@ -1903,8 +2030,14 @@ static void windowCodeStep(
|
|||||||
int reg = pParse->nMem+1;
|
int reg = pParse->nMem+1;
|
||||||
int regRecord = reg+nSub;
|
int regRecord = reg+nSub;
|
||||||
int regRowid = regRecord+1;
|
int regRowid = regRecord+1;
|
||||||
|
WindowCodeArg s;
|
||||||
|
|
||||||
bCache = 1;
|
memset(&s, 0, sizeof(WindowCodeArg));
|
||||||
|
s.pParse = pParse;
|
||||||
|
s.pMWin = pMWin;
|
||||||
|
s.pVdbe = v;
|
||||||
|
s.regGosub = regGosub;
|
||||||
|
s.addrGosub = addrGosub;
|
||||||
|
|
||||||
pParse->nMem += 1 + nSub + 1;
|
pParse->nMem += 1 + nSub + 1;
|
||||||
|
|
||||||
@@ -1923,11 +2056,12 @@ static void windowCodeStep(
|
|||||||
|| pMWin->eEnd==TK_PRECEDING
|
|| pMWin->eEnd==TK_PRECEDING
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/* Load the column values for the row returned by the sub-select
|
/* Load the column values for the row returned by the sub-select
|
||||||
** into an array of registers starting at reg. Assemble them into
|
** into an array of registers starting at reg. Assemble them into
|
||||||
** a record in register regRecord. TODO: An optimization here? */
|
** a record in register regRecord. TODO: An optimization here? */
|
||||||
for(k=0; k<nSub; k++){
|
for(iCol=0; iCol<nSub; iCol++){
|
||||||
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
|
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, iCol, reg+iCol);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
|
||||||
|
|
||||||
@@ -1973,14 +2107,16 @@ static void windowCodeStep(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This block is run for the first row of each partition */
|
/* This block is run for the first row of each partition */
|
||||||
regArg = windowInitAccum(pParse, pMWin);
|
s.regArg = regArg = windowInitAccum(pParse, pMWin);
|
||||||
|
|
||||||
sqlite3ExprCode(pParse, pMWin->pStart, regStart);
|
sqlite3ExprCode(pParse, pMWin->pStart, regStart);
|
||||||
windowCheckIntValue(pParse, regStart, 0);
|
windowCheckIntValue(pParse, regStart, 0);
|
||||||
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
|
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
|
||||||
windowCheckIntValue(pParse, regEnd, 1);
|
windowCheckIntValue(pParse, regEnd, 1);
|
||||||
|
|
||||||
if( pMWin->eStart==TK_FOLLOWING || pMWin->eEnd==TK_PRECEDING ){
|
if( pMWin->eStart==pMWin->eEnd
|
||||||
|
&& pMWin->eStart!=TK_CURRENT && pMWin->eStart!=TK_UNBOUNDED
|
||||||
|
){
|
||||||
int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
|
int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
|
||||||
int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
|
int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
|
||||||
windowAggFinal(pParse, pMWin, 0);
|
windowAggFinal(pParse, pMWin, 0);
|
||||||
@@ -2008,56 +2144,35 @@ static void windowCodeStep(
|
|||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regFirst);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regFirst);
|
||||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
|
|
||||||
/* This block is run for the second and subsequent rows of each partition */
|
/* Begin generating SECOND_ROW_CODE */
|
||||||
|
VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep.SECOND_ROW_CODE"));
|
||||||
if( bCache ){
|
if( bCache ){
|
||||||
addrCacheNext = sqlite3VdbeCurrentAddr(v);
|
addrCacheNext = sqlite3VdbeCurrentAddr(v);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeJumpHere(v, addrIf);
|
sqlite3VdbeJumpHere(v, addrIf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pMWin->eStart==TK_FOLLOWING ){
|
if( pMWin->eStart==TK_FOLLOWING ){
|
||||||
addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
|
windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 0);
|
||||||
windowAggFinal(pParse, pMWin, 0);
|
windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+1);
|
|
||||||
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfEnd);
|
|
||||||
|
|
||||||
addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
|
|
||||||
windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfStart);
|
|
||||||
}else
|
}else
|
||||||
if( pMWin->eEnd==TK_PRECEDING ){
|
if( pMWin->eEnd==TK_PRECEDING ){
|
||||||
addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
|
windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, regEnd, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+1);
|
windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0);
|
||||||
windowAggStep(pParse, pMWin, csrEnd, 0, regArg, pMWin->regSize);
|
windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
|
||||||
sqlite3VdbeJumpHere(v, addrIfEnd);
|
|
||||||
|
|
||||||
windowAggFinal(pParse, pMWin, 0);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+1);
|
|
||||||
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
|
|
||||||
|
|
||||||
addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
|
|
||||||
windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfStart);
|
|
||||||
}else{
|
}else{
|
||||||
addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
|
int addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
|
||||||
windowAggFinal(pParse, pMWin, 0);
|
windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+1);
|
windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
|
||||||
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
|
|
||||||
windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfStart);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfEnd);
|
|
||||||
}
|
}
|
||||||
|
VdbeModuleComment((pParse->pVdbe, "End windowCodeStep.SECOND_ROW_CODE"));
|
||||||
|
|
||||||
|
VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep.ALL_ROW_CODE"));
|
||||||
sqlite3VdbeJumpHere(v, addrGoto);
|
sqlite3VdbeJumpHere(v, addrGoto);
|
||||||
if( pMWin->eEnd!=TK_PRECEDING ){
|
if( pMWin->eEnd!=TK_PRECEDING ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+1);
|
windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0);
|
||||||
windowAggStep(pParse, pMWin, csrEnd, 0, regArg, pMWin->regSize);
|
|
||||||
}
|
}
|
||||||
|
VdbeModuleComment((pParse->pVdbe, "End windowCodeStep.ALL_ROW_CODE"));
|
||||||
|
|
||||||
/* End of the main input loop */
|
/* End of the main input loop */
|
||||||
if( bCache ){
|
if( bCache ){
|
||||||
@@ -2070,56 +2185,34 @@ static void windowCodeStep(
|
|||||||
|
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
|
|
||||||
|
VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep.FLUSH_CODE"));
|
||||||
if( pMWin->pPartition && bCache==0 ){
|
if( pMWin->pPartition && bCache==0 ){
|
||||||
addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart);
|
addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart);
|
||||||
sqlite3VdbeJumpHere(v, addrGosubFlush);
|
sqlite3VdbeJumpHere(v, addrGosubFlush);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pMWin->eStart==TK_FOLLOWING ){
|
|
||||||
int addrBreak;
|
|
||||||
addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+2);
|
|
||||||
addrBreak = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
||||||
windowAggFinal(pParse, pMWin, 0);
|
|
||||||
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfEnd);
|
|
||||||
|
|
||||||
addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2);
|
|
||||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
|
||||||
windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfStart);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfStart+2);
|
|
||||||
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrIfEnd);
|
|
||||||
sqlite3VdbeJumpHere(v, addrBreak);
|
|
||||||
}else{
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+2);
|
|
||||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
||||||
if( pMWin->eEnd==TK_PRECEDING ){
|
if( pMWin->eEnd==TK_PRECEDING ){
|
||||||
addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
|
windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, regEnd, 1);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+1);
|
windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 1);
|
||||||
windowAggStep(pParse, pMWin, csrEnd, 0, regArg, pMWin->regSize);
|
|
||||||
sqlite3VdbeJumpHere(v, addrIfEnd);
|
|
||||||
windowAggFinal(pParse, pMWin, 0);
|
|
||||||
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
|
|
||||||
}else{
|
}else{
|
||||||
windowAggFinal(pParse, pMWin, 0);
|
int addrBreak;
|
||||||
windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
|
int addrStart = sqlite3VdbeCurrentAddr(v);
|
||||||
addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
|
if( pMWin->eStart==TK_FOLLOWING ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
|
addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 1);
|
||||||
windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
|
windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 1);
|
||||||
sqlite3VdbeJumpHere(v, addrIfStart);
|
}else{
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrGoto-1);
|
addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 1);
|
||||||
|
windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
|
||||||
}
|
}
|
||||||
sqlite3VdbeJumpHere(v, addrGoto);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart);
|
||||||
|
sqlite3VdbeJumpHere(v, addrBreak);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( bCache && addrShortcut>0 ) sqlite3VdbeJumpHere(v, addrShortcut);
|
if( bCache && addrShortcut>0 ) sqlite3VdbeJumpHere(v, addrShortcut);
|
||||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, csrCurrent);
|
sqlite3VdbeAddOp1(v, OP_ResetSorter, csrCurrent);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regSize);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regSize);
|
||||||
if( bCache==0 ) sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regFirst);
|
if( bCache==0 ) sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regFirst);
|
||||||
|
VdbeModuleComment((pParse->pVdbe, "End windowCodeStep.FLUSH_CODE"));
|
||||||
if( pMWin->pPartition ){
|
if( pMWin->pPartition ){
|
||||||
sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v));
|
||||||
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
|
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
|
||||||
|
Reference in New Issue
Block a user