diff --git a/manifest b/manifest index 4b50211203..3a161e7fea 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssupport\sfor\s"ROWS\sBETWEEN\s\sPRECEDING\sAND\s\sFOLLOWING"\swindow\nframes. -D 2018-05-23T20:55:37.621 +C Support\sother\sframe\stypes\sthat\suse\s"\sPRECEDING"\sor\s"\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 @@ -582,7 +582,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 1313e941d1e50a44594e6f3e12bc7d0fe6f092ea35c1f3884c31bd224ba66d29 +F src/window.c dc58ad62f2bb06d2e289ce65375b7d0047646b73c11a09fb0325febac0aebba7 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d @@ -1615,8 +1615,8 @@ F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 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 @@ -1733,7 +1733,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 cdb68d2c64e453fdcd29437d5915c5c5ab6fbc7b5ffac52f4cb393f35b4a0124 -R 20d653691e285483f3e3bdb0b082aa4b +P 3a203660f1e4da3b8d2d605c494f4843f6e00752f28042b49e11d7d6550dd406 +R 91a6e47e9aa2b2bca4e7ec8da35f9bee U dan -Z e628ea8085262c078f67c7957c5a3c95 +Z 468858d850092ff66af7324bc283099f diff --git a/manifest.uuid b/manifest.uuid index 8f6226467b..09eb988a9c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3a203660f1e4da3b8d2d605c494f4843f6e00752f28042b49e11d7d6550dd406 \ No newline at end of file +ec7b648c7f0ee266653561bbb9daa45b9be0d8a1a14f11dc93bce467c35154e6 \ No newline at end of file diff --git a/src/window.c b/src/window.c index 6af6d4c7ce..47e4181915 100644 --- a/src/window.c +++ b/src/window.c @@ -93,6 +93,50 @@ static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){ sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC); } +/* +** ROWS BETWEEN PRECEDING AND 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 = // PRECEDING expression +** regFollow = // 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 PRECEDING AND CURRENT ROW +** ROWS BETWEEN CURRENT ROW AND FOLLOWING +** ROWS BETWEEN PRECEDING AND UNBOUNDED FOLLOWING +** ROWS BETWEEN UNBOUNDED PRECEDING AND 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, @@ -123,6 +167,15 @@ static void windowCodeRowExprStep( 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. */ @@ -173,17 +226,22 @@ static void windowCodeRowExprStep( 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); @@ -205,9 +263,17 @@ static void windowCodeRowExprStep( 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 @@ -218,20 +284,27 @@ static void windowCodeRowExprStep( 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; inArg; 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; inArg; 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: */ @@ -428,48 +501,6 @@ static void windowCodeDefaultStep( ** **======================================================================== ** -** ROWS BETWEEN PRECEDING AND 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 = // PRECEDING expression -** regFollow = // 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 PRECEDING AND CURRENT ROW -** ROWS BETWEEN CURRENT ROW AND FOLLOWING -** ROWS BETWEEN PRECEDING AND UNBOUNDED FOLLOWING -** ROWS BETWEEN UNBOUNDED PRECEDING AND FOLLOWING -** -** These are similar to the above. For "CURRENT ROW", intialize the -** register to 0. For "UNBOUNDED ..." to infinity. -** ** ROWS BETWEEN PRECEDING AND PRECEDING ** ** Replace the bit after "Rewind" in the above with: @@ -522,8 +553,8 @@ void sqlite3WindowCodeStep( 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); diff --git a/test/window2.tcl b/test/window2.tcl index 4d2503715b..44a13cbf54 100644 --- a/test/window2.tcl +++ b/test/window2.tcl @@ -184,6 +184,44 @@ execsql_test 2.7 { ) FROM t1 } +execsql_test 2.8 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING + ) FROM t1 +} + +execsql_test 2.9 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN UNBOUNDED PRECEDING AND 2 FOLLOWING + ) FROM t1 +} + +execsql_test 2.10 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING + ) FROM t1 +} + +execsql_test 2.11 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN 2 PRECEDING AND CURRENT ROW + ) FROM t1 +} + +execsql_test 2.13 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING + ) FROM t1 +} + + +========== + puts $::fd finish_test ========== diff --git a/test/window2.test b/test/window2.test index db4eb44dc7..a5d4ee853e 100644 --- a/test/window2.test +++ b/test/window2.test @@ -95,42 +95,65 @@ do_execsql_test 2.7 { ) FROM t1 } {2 2 4 4 6 6 1 1 3 3 5 5} +do_execsql_test 2.8 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING + ) FROM t1 +} {1 6 2 9 3 12 4 15 5 11 6 6} + +do_execsql_test 2.9 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN UNBOUNDED PRECEDING AND 2 FOLLOWING + ) FROM t1 +} {1 6 2 10 3 15 4 21 5 21 6 21} + +do_execsql_test 2.10 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING + ) FROM t1 +} {1 6 2 9 3 12 4 15 5 11 6 6} + +do_execsql_test 2.11 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN 2 PRECEDING AND CURRENT ROW + ) FROM t1 +} {1 1 2 3 3 6 4 9 5 12 6 15} + +do_execsql_test 2.13 { + SELECT a, sum(d) OVER ( + ORDER BY d + ROWS BETWEEN 2 PRECEDING AND UNBOUNDED FOLLOWING + ) FROM t1 +} {1 21 2 21 3 21 4 20 5 18 6 15} + +#========================================================================== + finish_test #========================================================================== -do_execsql_test 2.1 { +do_execsql_test 3.1 { SELECT a, sum(d) OVER ( PARTITION BY b ORDER BY d RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t1 } {2 12 4 10 6 6 1 9 3 8 5 5} -do_execsql_test 2.2 { +do_execsql_test 3.2 { SELECT a, sum(d) OVER ( ORDER BY b RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) FROM t1 } {2 21 4 21 6 21 1 9 3 9 5 9} -do_execsql_test 2.3 { +do_execsql_test 3.3 { SELECT a, sum(d) OVER ( ORDER BY d ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) FROM t1 } {1 21 2 21 3 21 4 21 5 21 6 21} -do_execsql_test 2.4 { - SELECT a, sum(d) OVER ( - ORDER BY d - ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING - ) FROM t1 -} {1 3 2 6 3 9 4 12 5 15 6 11} - -do_execsql_test 2.5 { - SELECT a, sum(d) OVER ( - ORDER BY d - ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING - ) FROM t1 -} {1 {} 2 1 3 2 4 3 5 4 6 5} - finish_test