-C Add\ssupport\sfor\s"ROWS\sBETWEEN\s<expr>\sPRECEDING\sAND\s<expr>\sFOLLOWING"\swindow\nframes.
-D 2018-05-23T20:55:37.621
+C Support\sother\sframe\stypes\sthat\suse\s"<expr>\sPRECEDING"\sor\s"<expr>\sFOLLOWING"\sas\nstart\sor\send\sconditions.
+D 2018-05-24T17:49:14.994
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53
F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
-F src/window.c 1313e941d1e50a44594e6f3e12bc7d0fe6f092ea35c1f3884c31bd224ba66d29
+F src/window.c dc58ad62f2bb06d2e289ce65375b7d0047646b73c11a09fb0325febac0aebba7
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 29e9bb16a52eb1e9e8f376519185af5c64eed88a8e6f0bee54237ba2971803a7
-F test/window2.test f580e1cc96d1ccb6bb220d1e338525ee5541e45e2206ed9ca74417ba862d8a62
+F test/window2.tcl 798cfc8bef0f08a27a0ba64e147d8c72e9409c1673cc4ccff2ee7f150aa084e4
+F test/window2.test ca65b0818ddc948a7b0b07ee16a3c489dafcb958203bf8b75356eacd4696a206
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 cdb68d2c64e453fdcd29437d5915c5c5ab6fbc7b5ffac52f4cb393f35b4a0124
-R 20d653691e285483f3e3bdb0b082aa4b
+P 3a203660f1e4da3b8d2d605c494f4843f6e00752f28042b49e11d7d6550dd406
+R 91a6e47e9aa2b2bca4e7ec8da35f9bee
U dan
-Z e628ea8085262c078f67c7957c5a3c95
+Z 468858d850092ff66af7324bc283099f
sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
}
+/*
+** ROWS BETWEEN <expr> PRECEDING AND <expr> FOLLOWING
+**
+** ...
+** if( new partition ){
+** Gosub flush_partition
+** }
+** Insert (record in eph-table)
+** sqlite3WhereEnd()
+** Gosub flush_partition
+**
+** flush_partition:
+** OpenDup (csr -> csr2)
+** OpenDup (csr -> csr3)
+** regPrec = <expr1> // PRECEDING expression
+** regFollow = <expr2> // FOLLOWING expression
+** if( regPrec<0 || regFollow<0 ) throw exception!
+** Rewind (csr,csr2,csr3) // if EOF goto flush_partition_done
+** Aggstep (csr3)
+** Next(csr3) // if EOF fall-through
+** if( (regFollow--)<=0 ){
+** AggFinal (xValue)
+** Gosub addrGosub
+** Next(csr) // if EOF goto flush_partition_done
+** if( (regPrec--)<=0 ){
+** AggStep (csr2, xInverse)
+** Next(csr2)
+** }
+** }
+** flush_partition_done:
+** Close (csr2)
+** Close (csr3)
+** ResetSorter (csr)
+** Return
+**
+** ROWS BETWEEN <expr> PRECEDING AND CURRENT ROW
+** ROWS BETWEEN CURRENT ROW AND <expr> FOLLOWING
+** ROWS BETWEEN <expr> PRECEDING AND UNBOUNDED FOLLOWING
+** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> FOLLOWING
+**
+** These are similar to the above. For "CURRENT ROW", intialize the
+** register to 0. For "UNBOUNDED ..." to infinity.
+**
+*/
static void windowCodeRowExprStep(
Parse *pParse,
Select *p,
int addrIfPos1;
int addrIfPos2;
+ assert( pMWin->eStart==TK_PRECEDING
+ || pMWin->eStart==TK_CURRENT
+ || pMWin->eStart==TK_UNBOUNDED
+ );
+ assert( pMWin->eEnd==TK_FOLLOWING
+ || pMWin->eEnd==TK_CURRENT
+ || pMWin->eEnd==TK_UNBOUNDED
+ );
+
pParse->nMem += nSub + 2;
/* Allocate register and label for the "flush_partition" sub-routine. */
sqlite3VdbeAddOp2(v, OP_OpenDup, csrPrec, pMWin->iEphCsr);
sqlite3VdbeAddOp2(v, OP_OpenDup, csrFollow, pMWin->iEphCsr);
- sqlite3ExprCode(pParse, pMWin->pStart, regPrec);
- sqlite3ExprCode(pParse, pMWin->pEnd, regFollow);
+ /* If either regPrec or regFollow are not non-negative integers, throw
+ ** an exception. */
+ if( pMWin->pStart ){
+ assert( pMWin->eStart==TK_PRECEDING );
+ sqlite3ExprCode(pParse, pMWin->pStart, regPrec);
+ windowCheckFrameValue(pParse, regPrec, 0);
+ }
+ if( pMWin->pEnd ){
+ assert( pMWin->eEnd==TK_FOLLOWING );
+ sqlite3ExprCode(pParse, pMWin->pEnd, regFollow);
+ windowCheckFrameValue(pParse, regFollow, 1);
+ }
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);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)pWin->nArg);
}
- sqlite3VdbeJumpHere(v, addrNext+1);
+ if( pMWin->eEnd==TK_UNBOUNDED ){
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
+ sqlite3VdbeJumpHere(v, addrNext+1);
+ addrNext = sqlite3VdbeCurrentAddr(v);
+ }else{
+ sqlite3VdbeJumpHere(v, addrNext+1);
+ }
- addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regFollow, 0 , 1);
+ if( pMWin->eEnd==TK_FOLLOWING ){
+ 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
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);
+ if( pMWin->eStart==TK_CURRENT || pMWin->eStart==TK_PRECEDING ){
+ if( pMWin->eStart==TK_PRECEDING ){
+ 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);
+ }
+ if( pMWin->eStart==TK_PRECEDING ){
+ sqlite3VdbeJumpHere(v, addrIfPos2);
}
- 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);
+ if( pMWin->eEnd==TK_FOLLOWING ){
+ sqlite3VdbeJumpHere(v, addrIfPos1);
+ }
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext);
/* flush_partition_done: */
**
**========================================================================
**
-** ROWS BETWEEN <expr> PRECEDING AND <expr> FOLLOWING
-**
-** ...
-** if( new partition ){
-** Gosub flush_partition
-** }
-** Insert (record in eph-table)
-** sqlite3WhereEnd()
-** Gosub flush_partition
-**
-** flush_partition:
-** OpenDup (csr -> csr2)
-** OpenDup (csr -> csr3)
-** regPrec = <expr1> // PRECEDING expression
-** regFollow = <expr2> // FOLLOWING expression
-** if( regPrec<0 || regFollow<0 ) throw exception!
-** Rewind (csr,csr2,csr3) // if EOF goto flush_partition_done
-** Aggstep (csr3)
-** Next(csr3) // if EOF fall-through
-** if( (regFollow--)<=0 ){
-** AggFinal (xValue)
-** Gosub addrGosub
-** Next(csr) // if EOF goto flush_partition_done
-** if( (regPrec--)<=0 ){
-** AggStep (csr2, xInverse)
-** Next(csr2)
-** }
-** }
-** flush_partition_done:
-** Close (csr2)
-** Close (csr3)
-** ResetSorter (csr)
-** Return
-**
-** ROWS BETWEEN <expr> PRECEDING AND CURRENT ROW
-** ROWS BETWEEN CURRENT ROW AND <expr> FOLLOWING
-** ROWS BETWEEN <expr> PRECEDING AND UNBOUNDED FOLLOWING
-** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> FOLLOWING
-**
-** These are similar to the above. For "CURRENT ROW", intialize the
-** register to 0. For "UNBOUNDED ..." to infinity.
-**
** ROWS BETWEEN <expr> PRECEDING AND <expr> PRECEDING
**
** Replace the bit after "Rewind" in the above with:
Window *pMWin = p->pWin;
if( pMWin->eType==TK_ROWS
- && pMWin->eStart==TK_PRECEDING
- && pMWin->eEnd==TK_FOLLOWING
+ && (pMWin->eStart==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING)
+ && (pMWin->eStart!=TK_FOLLOWING || pMWin->eEnd==TK_PRECEDING)
){
*pbLoop = 0;
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);