mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Allow "<expr> PRECEDING" to be used to specify the end of a window frame.
FossilOrigin-Name: 7b709a989c188dbcf429989a0785294b36c8a7e89b5de8cefc25decf1f5b7f5a
This commit is contained in:
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Support\sother\sframe\stypes\sthat\suse\s"<expr>\sPRECEDING"\sor\s"<expr>\sFOLLOWING"\sas\nstart\sor\send\sconditions.
|
C Allow\s"<expr>\sPRECEDING"\sto\sbe\sused\sto\sspecify\sthe\send\sof\sa\swindow\sframe.
|
||||||
D 2018-05-24T17:49:14.994
|
D 2018-05-24T21:10:57.618
|
||||||
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 bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
|
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
|
||||||
@@ -582,7 +582,7 @@ F src/where.c 60ec752fcbe9f9e0271ac60548d159a540a1ee47a4f9fedc85e88a3d0e392dd1
|
|||||||
F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53
|
F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53
|
||||||
F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8
|
F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8
|
||||||
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
|
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
|
||||||
F src/window.c dc58ad62f2bb06d2e289ce65375b7d0047646b73c11a09fb0325febac0aebba7
|
F src/window.c e4441e8ee3f83df85ff542048d3eed1c199ce6f90f3edcfeb1c4c1f53991b125
|
||||||
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
|
||||||
@@ -1615,8 +1615,8 @@ F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
|
|||||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||||
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
|
||||||
F test/window1.test 5705337783d220b47f6fb4432264543b7557a05be8013d772f57d71f2fded271
|
F test/window1.test 5705337783d220b47f6fb4432264543b7557a05be8013d772f57d71f2fded271
|
||||||
F test/window2.tcl 798cfc8bef0f08a27a0ba64e147d8c72e9409c1673cc4ccff2ee7f150aa084e4
|
F test/window2.tcl 6df00293e3691a0d17624de339ce91632252e160701d9be663c21e3706f1dfd0
|
||||||
F test/window2.test ca65b0818ddc948a7b0b07ee16a3c489dafcb958203bf8b75356eacd4696a206
|
F test/window2.test ee542c30bf8502f6df6f1a7304c2ca1d44143dfdd82dfad331f0b3b287de414c
|
||||||
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
|
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
|
||||||
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
|
||||||
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
|
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
|
||||||
@@ -1733,7 +1733,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 3a203660f1e4da3b8d2d605c494f4843f6e00752f28042b49e11d7d6550dd406
|
P ec7b648c7f0ee266653561bbb9daa45b9be0d8a1a14f11dc93bce467c35154e6
|
||||||
R 91a6e47e9aa2b2bca4e7ec8da35f9bee
|
R cae23b80a7b926c27766da973f4ae9e5
|
||||||
U dan
|
U dan
|
||||||
Z 468858d850092ff66af7324bc283099f
|
Z 6786b4d33cda910bcdf7493ef1afdc20
|
||||||
|
@@ -1 +1 @@
|
|||||||
ec7b648c7f0ee266653561bbb9daa45b9be0d8a1a14f11dc93bce467c35154e6
|
7b709a989c188dbcf429989a0785294b36c8a7e89b5de8cefc25decf1f5b7f5a
|
205
src/window.c
205
src/window.c
@@ -93,6 +93,26 @@ static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
|
|||||||
sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
|
sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void windowAggStep(
|
||||||
|
Parse *pParse,
|
||||||
|
Window *pMWin,
|
||||||
|
int csr,
|
||||||
|
int bInverse,
|
||||||
|
int reg
|
||||||
|
){
|
||||||
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||||
|
Window *pWin;
|
||||||
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||||
|
int i;
|
||||||
|
for(i=0; i<pWin->nArg; i++){
|
||||||
|
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+i, reg+i);
|
||||||
|
}
|
||||||
|
sqlite3VdbeAddOp3(v, OP_AggStep0, bInverse, reg, pWin->regAccum);
|
||||||
|
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
||||||
|
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** ROWS BETWEEN <expr> PRECEDING AND <expr> FOLLOWING
|
** ROWS BETWEEN <expr> PRECEDING AND <expr> FOLLOWING
|
||||||
**
|
**
|
||||||
@@ -105,26 +125,26 @@ static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
|
|||||||
** Gosub flush_partition
|
** Gosub flush_partition
|
||||||
**
|
**
|
||||||
** flush_partition:
|
** flush_partition:
|
||||||
** OpenDup (csr -> csr2)
|
** Once {
|
||||||
** OpenDup (csr -> csr3)
|
** OpenDup (iEphCsr -> csrStart)
|
||||||
** regPrec = <expr1> // PRECEDING expression
|
** OpenDup (iEphCsr -> csrEnd)
|
||||||
** regFollow = <expr2> // FOLLOWING expression
|
** }
|
||||||
** if( regPrec<0 || regFollow<0 ) throw exception!
|
** regStart = <expr1> // PRECEDING expression
|
||||||
** Rewind (csr,csr2,csr3) // if EOF goto flush_partition_done
|
** regEnd = <expr2> // FOLLOWING expression
|
||||||
** Aggstep (csr3)
|
** if( regStart<0 || regEnd<0 ) throw exception!
|
||||||
** Next(csr3) // if EOF fall-through
|
** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done
|
||||||
** if( (regFollow--)<=0 ){
|
** Aggstep (csrEnd)
|
||||||
|
** Next(csrEnd) // if EOF fall-through
|
||||||
|
** if( (regEnd--)<=0 ){
|
||||||
** AggFinal (xValue)
|
** AggFinal (xValue)
|
||||||
** Gosub addrGosub
|
** Gosub addrGosub
|
||||||
** Next(csr) // if EOF goto flush_partition_done
|
** Next(csr) // if EOF goto flush_partition_done
|
||||||
** if( (regPrec--)<=0 ){
|
** if( (regStart--)<=0 ){
|
||||||
** AggStep (csr2, xInverse)
|
** AggStep (csrStart, xInverse)
|
||||||
** Next(csr2)
|
** Next(csrStart)
|
||||||
** }
|
** }
|
||||||
** }
|
** }
|
||||||
** flush_partition_done:
|
** flush_partition_done:
|
||||||
** Close (csr2)
|
|
||||||
** Close (csr3)
|
|
||||||
** ResetSorter (csr)
|
** ResetSorter (csr)
|
||||||
** Return
|
** Return
|
||||||
**
|
**
|
||||||
@@ -136,6 +156,38 @@ static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
|
|||||||
** These are similar to the above. For "CURRENT ROW", intialize the
|
** These are similar to the above. For "CURRENT ROW", intialize the
|
||||||
** register to 0. For "UNBOUNDED ..." to infinity.
|
** register to 0. For "UNBOUNDED ..." to infinity.
|
||||||
**
|
**
|
||||||
|
** ROWS BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING
|
||||||
|
**
|
||||||
|
** regEnd = regEnd - regStart
|
||||||
|
** Rewind (csr,csrStart,csrEnd) // if EOF goto flush_partition_done
|
||||||
|
** Aggstep (csrEnd)
|
||||||
|
** Next(csrEnd) // if EOF fall-through
|
||||||
|
** if( (regEnd--)<=0 ){
|
||||||
|
** AggStep (csrStart, xInverse)
|
||||||
|
** Next (csrStart)
|
||||||
|
** if( (regStart--)<=0 ){
|
||||||
|
** AggFinal (xValue)
|
||||||
|
** Gosub addrGosub
|
||||||
|
** Next(csr) // if EOF goto flush_partition_done
|
||||||
|
** }
|
||||||
|
** }
|
||||||
|
**
|
||||||
|
** ROWS BETWEEN <expr> PRECEDING AND <expr> PRECEDING
|
||||||
|
**
|
||||||
|
** Replace the bit after "Rewind" in the above with:
|
||||||
|
**
|
||||||
|
** if( (regEnd--)<=0 ){
|
||||||
|
** AggStep (csrEnd)
|
||||||
|
** Next (csrEnd)
|
||||||
|
** }
|
||||||
|
** AggFinal (xValue)
|
||||||
|
** Gosub addrGosub
|
||||||
|
** Next(csr) // if EOF goto flush_partition_done
|
||||||
|
** if( (regStart--)<=0 ){
|
||||||
|
** AggStep (csr2, xInverse)
|
||||||
|
** Next (csr2)
|
||||||
|
** }
|
||||||
|
**
|
||||||
*/
|
*/
|
||||||
static void windowCodeRowExprStep(
|
static void windowCodeRowExprStep(
|
||||||
Parse *pParse,
|
Parse *pParse,
|
||||||
@@ -151,19 +203,20 @@ static void windowCodeRowExprStep(
|
|||||||
int iSubCsr = p->pSrc->a[0].iCursor;
|
int iSubCsr = p->pSrc->a[0].iCursor;
|
||||||
int nSub = p->pSrc->a[0].pTab->nCol;
|
int nSub = p->pSrc->a[0].pTab->nCol;
|
||||||
int regFlushPart; /* Register for "Gosub flush_partition" */
|
int regFlushPart; /* Register for "Gosub flush_partition" */
|
||||||
int addrFlushPart; /* Label for "Gosub flush_partition" */
|
int lblFlushPart; /* Label for "Gosub flush_partition" */
|
||||||
int addrDone; /* Label for "Gosub flush_partition_done" */
|
int lblFlushDone; /* Label for "Gosub flush_partition_done" */
|
||||||
|
|
||||||
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;
|
||||||
int addr;
|
int addr;
|
||||||
int csrPrec = pParse->nTab++;
|
int csrStart = pParse->nTab++;
|
||||||
int csrFollow = pParse->nTab++;
|
int csrEnd = pParse->nTab++;
|
||||||
int regPrec; /* Value of <expr> PRECEDING */
|
int regStart; /* Value of <expr> PRECEDING */
|
||||||
int regFollow; /* Value of <expr> FOLLOWING */
|
int regEnd; /* Value of <expr> FOLLOWING */
|
||||||
int addrNext;
|
int addrNext;
|
||||||
int addrGoto;
|
int addrGoto;
|
||||||
|
int addrTop;
|
||||||
int addrIfPos1;
|
int addrIfPos1;
|
||||||
int addrIfPos2;
|
int addrIfPos2;
|
||||||
|
|
||||||
@@ -174,17 +227,18 @@ static void windowCodeRowExprStep(
|
|||||||
assert( pMWin->eEnd==TK_FOLLOWING
|
assert( pMWin->eEnd==TK_FOLLOWING
|
||||||
|| pMWin->eEnd==TK_CURRENT
|
|| pMWin->eEnd==TK_CURRENT
|
||||||
|| pMWin->eEnd==TK_UNBOUNDED
|
|| pMWin->eEnd==TK_UNBOUNDED
|
||||||
|
|| pMWin->eEnd==TK_PRECEDING
|
||||||
);
|
);
|
||||||
|
|
||||||
pParse->nMem += nSub + 2;
|
pParse->nMem += nSub + 2;
|
||||||
|
|
||||||
/* Allocate register and label for the "flush_partition" sub-routine. */
|
/* Allocate register and label for the "flush_partition" sub-routine. */
|
||||||
regFlushPart = ++pParse->nMem;
|
regFlushPart = ++pParse->nMem;
|
||||||
addrFlushPart = sqlite3VdbeMakeLabel(v);
|
lblFlushPart = sqlite3VdbeMakeLabel(v);
|
||||||
addrDone = sqlite3VdbeMakeLabel(v);
|
lblFlushDone = sqlite3VdbeMakeLabel(v);
|
||||||
|
|
||||||
regPrec = ++pParse->nMem;
|
regStart = ++pParse->nMem;
|
||||||
regFollow = ++pParse->nMem;
|
regEnd = ++pParse->nMem;
|
||||||
|
|
||||||
/* Martial the row returned by the sub-select into an array of
|
/* Martial the row returned by the sub-select into an array of
|
||||||
** registers. */
|
** registers. */
|
||||||
@@ -205,7 +259,7 @@ static void windowCodeRowExprStep(
|
|||||||
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
|
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
|
||||||
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
||||||
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
|
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
|
||||||
sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart);
|
sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,62 +271,61 @@ static void windowCodeRowExprStep(
|
|||||||
sqlite3WhereEnd(pWInfo);
|
sqlite3WhereEnd(pWInfo);
|
||||||
|
|
||||||
/* Invoke "flush_partition" to deal with the final (or only) partition */
|
/* Invoke "flush_partition" to deal with the final (or only) partition */
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, addrFlushPart);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
|
||||||
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
|
|
||||||
/* flush_partition: */
|
/* flush_partition: */
|
||||||
sqlite3VdbeResolveLabel(v, addrFlushPart);
|
sqlite3VdbeResolveLabel(v, lblFlushPart);
|
||||||
sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
|
sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
|
||||||
sqlite3VdbeAddOp2(v, OP_OpenDup, csrPrec, pMWin->iEphCsr);
|
sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr);
|
||||||
sqlite3VdbeAddOp2(v, OP_OpenDup, csrFollow, pMWin->iEphCsr);
|
sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr);
|
||||||
|
|
||||||
/* If either regPrec or regFollow are not non-negative integers, throw
|
/* If either regStart or regEnd are not non-negative integers, throw
|
||||||
** an exception. */
|
** an exception. */
|
||||||
if( pMWin->pStart ){
|
if( pMWin->pStart ){
|
||||||
assert( pMWin->eStart==TK_PRECEDING );
|
assert( pMWin->eStart==TK_PRECEDING );
|
||||||
sqlite3ExprCode(pParse, pMWin->pStart, regPrec);
|
sqlite3ExprCode(pParse, pMWin->pStart, regStart);
|
||||||
windowCheckFrameValue(pParse, regPrec, 0);
|
windowCheckFrameValue(pParse, regStart, 0);
|
||||||
}
|
}
|
||||||
if( pMWin->pEnd ){
|
if( pMWin->pEnd ){
|
||||||
assert( pMWin->eEnd==TK_FOLLOWING );
|
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
|
||||||
sqlite3ExprCode(pParse, pMWin->pEnd, regFollow);
|
windowCheckFrameValue(pParse, regEnd, 1);
|
||||||
windowCheckFrameValue(pParse, regFollow, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regResult);
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||||
sqlite3VdbeAddOp2(v, OP_Null, 0, pMWin->regAccum);
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
|
||||||
|
}
|
||||||
|
|
||||||
sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, addrDone);
|
sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblFlushDone);
|
||||||
sqlite3VdbeAddOp2(v, OP_Rewind, csrPrec, addrDone);
|
sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, lblFlushDone);
|
||||||
sqlite3VdbeChangeP5(v, 1);
|
sqlite3VdbeChangeP5(v, 1);
|
||||||
sqlite3VdbeAddOp2(v, OP_Rewind, csrFollow, addrDone);
|
sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, lblFlushDone);
|
||||||
sqlite3VdbeChangeP5(v, 1);
|
sqlite3VdbeChangeP5(v, 1);
|
||||||
|
|
||||||
/* Invoke AggStep function for each window function using the row that
|
/* Invoke AggStep function for each window function using the row that
|
||||||
** csrFollow currently points to. Or, if csrFollow is already at EOF,
|
** csrEnd currently points to. Or, if csrEnd is already at EOF,
|
||||||
** do nothing. */
|
** do nothing. */
|
||||||
addrNext = sqlite3VdbeCurrentAddr(v);
|
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, csrFollow, addrNext+2);
|
if( pMWin->eEnd==TK_PRECEDING ){
|
||||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+2);
|
||||||
|
addr = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||||
|
windowAggStep(pParse, pMWin, csrEnd, 0, reg);
|
||||||
if( pMWin->eEnd==TK_UNBOUNDED ){
|
if( pMWin->eEnd==TK_UNBOUNDED ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
|
||||||
sqlite3VdbeJumpHere(v, addrNext+1);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
addrNext = sqlite3VdbeCurrentAddr(v);
|
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeJumpHere(v, addrNext+1);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
|
if( pMWin->eEnd==TK_PRECEDING ){
|
||||||
|
sqlite3VdbeJumpHere(v, addrIfPos1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pMWin->eEnd==TK_FOLLOWING ){
|
if( pMWin->eEnd==TK_FOLLOWING ){
|
||||||
addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regFollow, 0 , 1);
|
addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1);
|
||||||
}
|
}
|
||||||
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
||||||
sqlite3VdbeAddOp3(v,
|
sqlite3VdbeAddOp3(v,
|
||||||
@@ -282,22 +335,14 @@ static void windowCodeRowExprStep(
|
|||||||
}
|
}
|
||||||
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
|
sqlite3VdbeAddOp2(v, OP_Gosub, regGosub, addrGosub);
|
||||||
sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2);
|
sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2);
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, lblFlushDone);
|
||||||
|
|
||||||
if( pMWin->eStart==TK_CURRENT || pMWin->eStart==TK_PRECEDING ){
|
if( pMWin->eStart==TK_CURRENT || pMWin->eStart==TK_PRECEDING ){
|
||||||
if( pMWin->eStart==TK_PRECEDING ){
|
if( pMWin->eStart==TK_PRECEDING ){
|
||||||
addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regPrec, 0 , 1);
|
addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 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);
|
|
||||||
}
|
}
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
|
||||||
|
windowAggStep(pParse, pMWin, csrStart, 1, reg);
|
||||||
if( pMWin->eStart==TK_PRECEDING ){
|
if( pMWin->eStart==TK_PRECEDING ){
|
||||||
sqlite3VdbeJumpHere(v, addrIfPos2);
|
sqlite3VdbeJumpHere(v, addrIfPos2);
|
||||||
}
|
}
|
||||||
@@ -305,10 +350,10 @@ static void windowCodeRowExprStep(
|
|||||||
if( pMWin->eEnd==TK_FOLLOWING ){
|
if( pMWin->eEnd==TK_FOLLOWING ){
|
||||||
sqlite3VdbeJumpHere(v, addrIfPos1);
|
sqlite3VdbeJumpHere(v, addrIfPos1);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
|
||||||
|
|
||||||
/* flush_partition_done: */
|
/* flush_partition_done: */
|
||||||
sqlite3VdbeResolveLabel(v, addrDone);
|
sqlite3VdbeResolveLabel(v, lblFlushDone);
|
||||||
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
|
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
|
||||||
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
|
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
|
||||||
|
|
||||||
@@ -505,28 +550,28 @@ static void windowCodeDefaultStep(
|
|||||||
**
|
**
|
||||||
** Replace the bit after "Rewind" in the above with:
|
** Replace the bit after "Rewind" in the above with:
|
||||||
**
|
**
|
||||||
** if( (regFollow--)<=0 ){
|
** if( (regEnd--)<=0 ){
|
||||||
** AggStep (csr3)
|
** AggStep (csr3)
|
||||||
** Next (csr3)
|
** Next (csr3)
|
||||||
** }
|
** }
|
||||||
** AggFinal (xValue)
|
** AggFinal (xValue)
|
||||||
** Gosub addrGosub
|
** Gosub addrGosub
|
||||||
** Next(csr) // if EOF goto flush_partition_done
|
** Next(csr) // if EOF goto flush_partition_done
|
||||||
** if( (regPrec--)<=0 ){
|
** if( (regStart--)<=0 ){
|
||||||
** AggStep (csr2, xInverse)
|
** AggStep (csr2, xInverse)
|
||||||
** Next (csr2)
|
** Next (csr2)
|
||||||
** }
|
** }
|
||||||
**
|
**
|
||||||
** ROWS BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING
|
** ROWS BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING
|
||||||
**
|
**
|
||||||
** regFollow = regFollow - regPrec
|
** regEnd = regEnd - regStart
|
||||||
** Rewind (csr,csr2,csr3) // if EOF goto flush_partition_done
|
** Rewind (csr,csr2,csr3) // if EOF goto flush_partition_done
|
||||||
** Aggstep (csr3)
|
** Aggstep (csr3)
|
||||||
** Next(csr3) // if EOF fall-through
|
** Next(csr3) // if EOF fall-through
|
||||||
** if( (regFollow--)<=0 ){
|
** if( (regEnd--)<=0 ){
|
||||||
** AggStep (csr2, xInverse)
|
** AggStep (csr2, xInverse)
|
||||||
** Next (csr2)
|
** Next (csr2)
|
||||||
** if( (regPrec--)<=0 ){
|
** if( (regStart--)<=0 ){
|
||||||
** AggFinal (xValue)
|
** AggFinal (xValue)
|
||||||
** Gosub addrGosub
|
** Gosub addrGosub
|
||||||
** Next(csr) // if EOF goto flush_partition_done
|
** Next(csr) // if EOF goto flush_partition_done
|
||||||
@@ -536,7 +581,7 @@ static void windowCodeDefaultStep(
|
|||||||
** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> PRECEDING
|
** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> PRECEDING
|
||||||
** ROWS BETWEEN <expr> FOLLOWING AND UNBOUNDED FOLLOWING
|
** ROWS BETWEEN <expr> FOLLOWING AND UNBOUNDED FOLLOWING
|
||||||
**
|
**
|
||||||
** Similar to the above, except with regPrec or regFollow set to infinity,
|
** Similar to the above, except with regStart or regEnd set to infinity,
|
||||||
** as appropriate.
|
** as appropriate.
|
||||||
**
|
**
|
||||||
**
|
**
|
||||||
@@ -552,10 +597,8 @@ void sqlite3WindowCodeStep(
|
|||||||
){
|
){
|
||||||
Window *pMWin = p->pWin;
|
Window *pMWin = p->pWin;
|
||||||
|
|
||||||
if( pMWin->eType==TK_ROWS
|
if( pMWin->pStart || pMWin->pEnd ){
|
||||||
&& (pMWin->eStart==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING)
|
assert( pMWin->eType==TK_ROWS );
|
||||||
&& (pMWin->eStart!=TK_FOLLOWING || pMWin->eEnd==TK_PRECEDING)
|
|
||||||
){
|
|
||||||
*pbLoop = 0;
|
*pbLoop = 0;
|
||||||
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
|
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
|
||||||
return;
|
return;
|
||||||
|
@@ -219,6 +219,45 @@ execsql_test 2.13 {
|
|||||||
) FROM t1
|
) FROM t1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
execsql_test 2.14 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
}
|
||||||
|
|
||||||
|
execsql_test 2.15 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 1 PRECEDING AND 0 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
}
|
||||||
|
|
||||||
|
execsql_test 2.16 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
}
|
||||||
|
|
||||||
|
execsql_test 2.17 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 1 PRECEDING AND 2 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
}
|
||||||
|
|
||||||
|
execsql_test 2.18 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN UNBOUNDED PRECEDING AND 2 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
@@ -130,6 +130,45 @@ do_execsql_test 2.13 {
|
|||||||
) FROM t1
|
) FROM t1
|
||||||
} {1 21 2 21 3 21 4 20 5 18 6 15}
|
} {1 21 2 21 3 21 4 20 5 18 6 15}
|
||||||
|
|
||||||
|
do_execsql_test 2.14 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
} {1 {} 2 1 3 3 4 6 5 9 6 12}
|
||||||
|
|
||||||
|
do_execsql_test 2.15 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 1 PRECEDING AND 0 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
} {2 2 4 6 6 10 1 1 3 4 5 8}
|
||||||
|
|
||||||
|
do_execsql_test 2.16 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
} {2 {} 4 2 6 4 1 {} 3 1 5 3}
|
||||||
|
|
||||||
|
do_execsql_test 2.17 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN 1 PRECEDING AND 2 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
} {2 {} 4 {} 6 {} 1 {} 3 {} 5 {}}
|
||||||
|
|
||||||
|
do_execsql_test 2.18 {
|
||||||
|
SELECT a, sum(d) OVER (
|
||||||
|
PARTITION BY b
|
||||||
|
ORDER BY d
|
||||||
|
ROWS BETWEEN UNBOUNDED PRECEDING AND 2 PRECEDING
|
||||||
|
) FROM t1
|
||||||
|
} {2 {} 4 {} 6 2 1 {} 3 {} 5 1}
|
||||||
|
|
||||||
#==========================================================================
|
#==========================================================================
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
Reference in New Issue
Block a user