]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix other "ROWS BETWEEN" cases on this branch.
authordan <dan@noemail.net>
Thu, 7 Mar 2019 20:47:46 +0000 (20:47 +0000)
committerdan <dan@noemail.net>
Thu, 7 Mar 2019 20:47:46 +0000 (20:47 +0000)
FossilOrigin-Name: a5f68f66472610b5beb4fe28669fbbfe83a32742be73cecad9b2ae28f8a17b30

manifest
manifest.uuid
src/window.c

index 20f066a065bdf3c269cae65dc5ddaf87aa9f9dc4..2d96c2ceb1ee661cc156c48562c91bb60409400f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Modify\snew\swindow\sfunctions\sfunction\sso\sthat\scursors\sare\sstepped\simmediately\safter\seach\soperation,\sinstead\sof\simmediately\sbefore.
-D 2019-03-07T19:26:17.600
+C Fix\sother\s"ROWS\sBETWEEN"\scases\son\sthis\sbranch.
+D 2019-03-07T20:47:46.020
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 1ad7263f38329c0ecea543c80f30af839ee714ea77fc391bf1a3fbb919a5b6b5
@@ -604,7 +604,7 @@ F src/where.c 8a207cb2ca6b99e1edb1e4bbff9b0504385a759cbf66180d1deb34d80ca4b799
 F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
 F src/wherecode.c ce7b21e1be2b981d62683fc59c4ca73a04a7ff2f1ebec23d41baf2da2349afd6
 F src/whereexpr.c 36b47f7261d6b6f1a72d774c113b74beddf6745aba1018e64b196e29db233442
-F src/window.c 00962a6b3434fd44a1c6e0446faaa27a0715b9234d9467e2b2f0516cc22d3ced
+F src/window.c fd7eae2b523f47c114f689f213407c218b737b45a29ed0a5b8ad6e3377f49594
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
 F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -1809,7 +1809,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 45cbd3b4498cea8856f189e9d0a192556d4f15212055b8328a1beca6083fc47a
-R 8a700321d1f21bd34463dfe3468362b4
+P 093d2b25f1b656bba57d665aac68109436861b157a5769432b612176dae3f6eb
+R bc65bb166c813f4264e0cac9b9ddcfde
 U dan
-Z 66270c88444ad4957a492203232c2b1a
+Z 787ed5434e794ce48cb312b7f3a2a9d5
index 9b064598e11adf1f647e49bd6a06972ca19fa097..eac4a67e3990a83ebf977fe660d0e461c24f8123 100644 (file)
@@ -1 +1 @@
-093d2b25f1b656bba57d665aac68109436861b157a5769432b612176dae3f6eb
\ No newline at end of file
+a5f68f66472610b5beb4fe28669fbbfe83a32742be73cecad9b2ae28f8a17b30
\ No newline at end of file
index 24f7451548636ad05834c08c11bfd5ffae91c5eb..6faa464d2a42ebe4560addcdd3ec1fad9113f3f4 100644 (file)
@@ -1542,307 +1542,6 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
   return regArg;
 }
 
-
-/*
-** This function does the work of sqlite3WindowCodeStep() for all "ROWS"
-** window frame types except for "BETWEEN UNBOUNDED PRECEDING AND CURRENT
-** ROW". Pseudo-code for each follows.
-**
-** ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
-**
-**     ...
-**       if( new partition ){
-**         Gosub flush_partition
-**       }
-**       Insert (record in eph-table)
-**     sqlite3WhereEnd()
-**     Gosub flush_partition
-**  
-**   flush_partition:
-**     Once {
-**       OpenDup (iEphCsr -> csrStart)
-**       OpenDup (iEphCsr -> csrEnd)
-**     }
-**     regStart = <expr1>                // PRECEDING expression
-**     regEnd = <expr2>                  // FOLLOWING expression
-**     if( regStart<0 || regEnd<0 ){ error! }
-**     Rewind (csr,csrStart,csrEnd)      // if EOF goto flush_partition_done
-**       Next(csrEnd)                    // if EOF skip Aggstep
-**       Aggstep (csrEnd)
-**       if( (regEnd--)<=0 ){
-**         AggFinal (xValue)
-**         Gosub addrGosub
-**         Next(csr)                // if EOF goto flush_partition_done
-**         if( (regStart--)<=0 ){
-**           AggInverse (csrStart)
-**           Next(csrStart)
-**         }
-**       }
-**   flush_partition_done:
-**     ResetSorter (csr)
-**     Return
-**
-** ROWS BETWEEN <expr> PRECEDING    AND CURRENT ROW
-** ROWS BETWEEN CURRENT ROW         AND <expr> FOLLOWING
-** ROWS BETWEEN UNBOUNDED PRECEDING AND <expr> FOLLOWING
-**
-**   These are similar to the above. For "CURRENT ROW", intialize the
-**   register to 0. For "UNBOUNDED PRECEDING" to infinity.
-**
-** ROWS BETWEEN <expr> PRECEDING    AND UNBOUNDED FOLLOWING
-** ROWS BETWEEN CURRENT ROW         AND UNBOUNDED FOLLOWING
-**
-**     Rewind (csr,csrStart,csrEnd)    // if EOF goto flush_partition_done
-**     while( 1 ){
-**       Next(csrEnd)                  // Exit while(1) at EOF
-**       Aggstep (csrEnd)
-**     }
-**     while( 1 ){
-**       AggFinal (xValue)
-**       Gosub addrGosub
-**       Next(csr)                     // if EOF goto flush_partition_done
-**       if( (regStart--)<=0 ){
-**         AggInverse (csrStart)
-**         Next(csrStart)
-**       }
-**     }
-**
-**   For the "CURRENT ROW AND UNBOUNDED FOLLOWING" case, the final if() 
-**   condition is always true (as if regStart were initialized to 0).
-**
-** RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
-** 
-**   This is the only RANGE case handled by this routine. It modifies the
-**   second while( 1 ) loop in "ROWS BETWEEN CURRENT ... UNBOUNDED..." to
-**   be:
-**
-**     while( 1 ){
-**       AggFinal (xValue)
-**       while( 1 ){
-**         regPeer++
-**         Gosub addrGosub
-**         Next(csr)                     // if EOF goto flush_partition_done
-**         if( new peer ) break;
-**       }
-**       while( (regPeer--)>0 ){
-**         AggInverse (csrStart)
-**         Next(csrStart)
-**       }
-**     }
-**
-** 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 ){
-**       if( (regStart--)<=0 ){
-**         AggFinal (xValue)
-**         Gosub addrGosub
-**         Next(csr)              // if EOF goto flush_partition_done
-**       }
-**       AggInverse (csrStart)
-**       Next (csrStart)
-**     }
-**
-** 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 ){
-**       AggInverse (csr2)
-**       Next (csr2)
-**     }
-**
-*/
-static void windowCodeRowExprStep(
-  Parse *pParse, 
-  Select *p,
-  WhereInfo *pWInfo,
-  int regGosub, 
-  int addrGosub
-){
-  Window *pMWin = p->pWin;
-  Vdbe *v = sqlite3GetVdbe(pParse);
-  int regFlushPart;               /* Register for "Gosub flush_partition" */
-  int lblFlushPart;               /* Label for "Gosub flush_partition" */
-  int lblFlushDone;               /* Label for "Gosub flush_partition_done" */
-
-  int regArg;
-  int addr;
-  int csrStart = pParse->nTab++;
-  int csrEnd = pParse->nTab++;
-  int regStart;                    /* Value of <expr> PRECEDING */
-  int regEnd;                      /* Value of <expr> FOLLOWING */
-  int addrGoto;
-  int addrTop;
-  int addrIfPos1 = 0;
-  int addrIfPos2 = 0;
-  int regSize = 0;
-
-  assert( pMWin->eStart==TK_PRECEDING 
-       || pMWin->eStart==TK_CURRENT 
-       || pMWin->eStart==TK_FOLLOWING 
-       || pMWin->eStart==TK_UNBOUNDED 
-  );
-  assert( pMWin->eEnd==TK_FOLLOWING 
-       || pMWin->eEnd==TK_CURRENT 
-       || pMWin->eEnd==TK_UNBOUNDED 
-       || pMWin->eEnd==TK_PRECEDING 
-  );
-
-  /* Allocate register and label for the "flush_partition" sub-routine. */
-  regFlushPart = ++pParse->nMem;
-  lblFlushPart = sqlite3VdbeMakeLabel(pParse);
-  lblFlushDone = sqlite3VdbeMakeLabel(pParse);
-
-  regStart = ++pParse->nMem;
-  regEnd = ++pParse->nMem;
-
-  windowPartitionCache(pParse, p, pWInfo, regFlushPart, lblFlushPart, &regSize);
-
-  addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
-
-  /* Start of "flush_partition" */
-  sqlite3VdbeResolveLabel(v, lblFlushPart);
-  sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
-  VdbeCoverage(v);
-  VdbeComment((v, "Flush_partition subroutine"));
-  sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr);
-  sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr);
-
-  /* If either regStart or regEnd are not non-negative integers, throw 
-  ** an exception.  */
-  if( pMWin->pStart ){
-    sqlite3ExprCode(pParse, pMWin->pStart, regStart);
-    windowCheckIntValue(pParse, regStart, 0);
-  }
-  if( pMWin->pEnd ){
-    sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
-    windowCheckIntValue(pParse, regEnd, 1);
-  }
-
-  /* If this is "ROWS <expr1> FOLLOWING AND ROWS <expr2> FOLLOWING", do:
-  **
-  **   if( regEnd<regStart ){
-  **     // The frame always consists of 0 rows
-  **     regStart = regSize;
-  **   }
-  **   regEnd = regEnd - regStart;
-  */
-  if( pMWin->pEnd && pMWin->eStart==TK_FOLLOWING ){
-    assert( pMWin->pStart!=0 );
-    assert( pMWin->eEnd==TK_FOLLOWING );
-    sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd);
-    VdbeCoverageNeverNull(v);
-    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
-    sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd);
-  }
-
-  if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){
-    assert( pMWin->pEnd!=0 );
-    assert( pMWin->eStart==TK_PRECEDING );
-    sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd);
-    VdbeCoverageNeverNull(v);
-    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
-    sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd);
-  }
-
-  /* Initialize the accumulator register for each window function to NULL */
-  regArg = windowInitAccum(pParse, pMWin);
-
-  sqlite3VdbeAddOp2(v, OP_Rewind, pMWin->iEphCsr, lblFlushDone);
-  VdbeCoverage(v);
-  sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, lblFlushDone);
-  VdbeCoverageNeverTaken(v);
-  sqlite3VdbeChangeP5(v, 1);
-  sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, lblFlushDone);
-  VdbeCoverageNeverTaken(v);
-  sqlite3VdbeChangeP5(v, 1);
-
-  /* Invoke AggStep function for each window function using the row that
-  ** csrEnd currently points to. Or, if csrEnd is already at EOF,
-  ** do nothing.  */
-  addrTop = sqlite3VdbeCurrentAddr(v);
-  if( pMWin->eEnd==TK_PRECEDING ){
-    addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1);
-    VdbeCoverage(v);
-  }
-  sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+2);
-  VdbeCoverage(v);
-  addr = sqlite3VdbeAddOp0(v, OP_Goto);
-  windowAggStep(pParse, pMWin, csrEnd, 0, regArg, regSize);
-  if( pMWin->eEnd==TK_UNBOUNDED ){
-    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
-    sqlite3VdbeJumpHere(v, addr);
-    addrTop = sqlite3VdbeCurrentAddr(v);
-  }else{
-    sqlite3VdbeJumpHere(v, addr);
-    if( pMWin->eEnd==TK_PRECEDING ){
-      sqlite3VdbeJumpHere(v, addrIfPos1);
-    }
-  }
-
-  if( pMWin->eEnd==TK_FOLLOWING ){
-    addrIfPos1 = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0 , 1);
-    VdbeCoverage(v);
-  }
-  if( pMWin->eStart==TK_FOLLOWING ){
-    addrIfPos2 = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0 , 1);
-    VdbeCoverage(v);
-  }
-  windowAggFinal(pParse, pMWin, 0);
-  windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
-  sqlite3VdbeAddOp2(v, OP_Next, pMWin->iEphCsr, sqlite3VdbeCurrentAddr(v)+2);
-  VdbeCoverage(v);
-  sqlite3VdbeAddOp2(v, OP_Goto, 0, lblFlushDone);
-  if( pMWin->eStart==TK_FOLLOWING ){
-    sqlite3VdbeJumpHere(v, addrIfPos2);
-  }
-
-  if( pMWin->eStart==TK_CURRENT 
-   || pMWin->eStart==TK_PRECEDING 
-   || pMWin->eStart==TK_FOLLOWING 
-  ){
-    int lblSkipInverse = sqlite3VdbeMakeLabel(pParse);;
-    if( pMWin->eStart==TK_PRECEDING ){
-      sqlite3VdbeAddOp3(v, OP_IfPos, regStart, lblSkipInverse, 1);
-      VdbeCoverage(v);
-    }
-    if( pMWin->eStart==TK_FOLLOWING ){
-      sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2);
-      VdbeCoverage(v);
-      sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse);
-    }else{
-      sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
-      VdbeCoverageAlwaysTaken(v);
-    }
-    windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize);
-    sqlite3VdbeResolveLabel(v, lblSkipInverse);
-  }
-  if( pMWin->eEnd==TK_FOLLOWING ){
-    sqlite3VdbeJumpHere(v, addrIfPos1);
-  }
-  sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
-
-  /* flush_partition_done: */
-  sqlite3VdbeResolveLabel(v, lblFlushDone);
-  sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
-  sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
-  VdbeComment((v, "end flush_partition subroutine"));
-
-  /* Jump to here to skip over flush_partition */
-  sqlite3VdbeJumpHere(v, addrGoto);
-}
-
 /* 
 ** Return true if the entire partition should be cached in the ephemeral
 ** table before processing any rows.
@@ -1884,26 +1583,34 @@ static int windowCodeOp(
  int regCountdown,
  int jumpOnEof
 ){
+  Window *pMWin = p->pMWin;
   int ret = 0;
   Vdbe *v = p->pVdbe;
   int addrIf = 0; 
 
+  /* Special case - WINDOW_AGGINVERSE is always a no-op if the frame
+  ** starts with UNBOUNDED PRECEDING. */
+  if( op==WINDOW_AGGINVERSE && pMWin->eStart==TK_UNBOUNDED ){
+    assert( regCountdown==0 && jumpOnEof==0 );
+    return 0;
+  }
+
   if( regCountdown>0 ){
     addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1);
   }
 
   switch( op ){
     case WINDOW_RETURN_ROW:
-      windowAggFinal(p->pParse, p->pMWin, 0);
-      windowReturnOneRow(p->pParse, p->pMWin, p->regGosub, p->addrGosub);
+      windowAggFinal(p->pParse, pMWin, 0);
+      windowReturnOneRow(p->pParse, pMWin, p->regGosub, p->addrGosub);
       break;
 
     case WINDOW_AGGINVERSE:
-      windowAggStep(p->pParse, p->pMWin, csr, 1, p->regArg, p->pMWin->regSize);
+      windowAggStep(p->pParse, pMWin, csr, 1, p->regArg, pMWin->regSize);
       break;
 
     case WINDOW_AGGSTEP:
-      windowAggStep(p->pParse, p->pMWin, csr, 0, p->regArg, p->pMWin->regSize);
+      windowAggStep(p->pParse, pMWin, csr, 0, p->regArg, pMWin->regSize);
       break;
   }
 
@@ -2006,8 +1713,6 @@ static void windowCodeStep(
   int csrStart = csrCurrent+2;
   int csrEnd = csrCurrent+3;
 
-  int regStart;                    /* Value of <expr> PRECEDING */
-  int regEnd;                      /* Value of <expr> FOLLOWING */
 
   int iSubCsr = p->pSrc->a[0].iCursor;      /* Cursor of sub-select */
   int nSub = p->pSrc->a[0].pTab->nCol;      /* Number of cols returned by sub */
@@ -2025,6 +1730,9 @@ static void windowCodeStep(
 
   int bCache = windowCachePartition(pMWin);
 
+  int regStart = 0;               /* Value of <expr> PRECEDING */
+  int regEnd = 0;                 /* Value of <expr> FOLLOWING */
+
   int reg = pParse->nMem+1;
   int regRecord = reg+nSub;
   int regRowid = regRecord+1;
@@ -2040,8 +1748,13 @@ static void windowCodeStep(
   pParse->nMem += 1 + nSub + 1;
 
   regFlushPart = ++pParse->nMem;
-  regStart = ++pParse->nMem;
-  regEnd = ++pParse->nMem;
+
+  if( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING ){
+    regStart = ++pParse->nMem;
+  }
+  if( pMWin->eEnd==TK_PRECEDING || pMWin->eEnd==TK_FOLLOWING ){
+    regEnd = ++pParse->nMem;
+  }
 
   assert( pMWin->eStart==TK_PRECEDING 
        || pMWin->eStart==TK_CURRENT 
@@ -2107,14 +1820,16 @@ static void windowCodeStep(
   /* This block is run for the first row of each partition */
   s.regArg = regArg = windowInitAccum(pParse, pMWin);
 
-  sqlite3ExprCode(pParse, pMWin->pStart, regStart);
-  windowCheckIntValue(pParse, regStart, 0);
-  sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
-  windowCheckIntValue(pParse, regEnd, 1);
+  if( regStart ){
+    sqlite3ExprCode(pParse, pMWin->pStart, regStart);
+    windowCheckIntValue(pParse, regStart, 0);
+  }
+  if( regEnd ){
+    sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
+    windowCheckIntValue(pParse, regEnd, 1);
+  }
 
-  if( pMWin->eStart==pMWin->eEnd 
-   && pMWin->eStart!=TK_CURRENT && pMWin->eStart!=TK_UNBOUNDED 
-  ){
+  if( pMWin->eStart==pMWin->eEnd && regStart && regEnd ){
     int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
     int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
     windowAggFinal(pParse, pMWin, 0);
@@ -2131,11 +1846,14 @@ static void windowCodeStep(
     addrShortcut = sqlite3VdbeAddOp0(v, OP_Goto);
     sqlite3VdbeJumpHere(v, addrGe);
   }
-  if( pMWin->eStart==TK_FOLLOWING ){
+  if( pMWin->eStart==TK_FOLLOWING && regEnd ){
+    assert( pMWin->eEnd==TK_FOLLOWING );
     sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart);
   }
 
-  sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, 1);
+  if( pMWin->eStart!=TK_UNBOUNDED ){
+    sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, 1);
+  }
   sqlite3VdbeAddOp2(v, OP_Rewind, csrCurrent, 1);
   sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, 1);
 
@@ -2151,8 +1869,10 @@ static void windowCodeStep(
   }
   if( pMWin->eStart==TK_FOLLOWING ){
     windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0);
-    windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 0);
-    windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
+    if( pMWin->eEnd!=TK_UNBOUNDED ){
+      windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 0);
+      windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
+    }
   }else
   if( pMWin->eEnd==TK_PRECEDING ){
     windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, regEnd, 0);
@@ -2161,10 +1881,12 @@ static void windowCodeStep(
   }else{
     int addr;
     windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0);
-    addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
-    windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0);
-    windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
-    sqlite3VdbeJumpHere(v, addr);
+    if( pMWin->eEnd!=TK_UNBOUNDED ){
+      if( regEnd ) addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
+      windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0);
+      windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
+      if( regEnd ) sqlite3VdbeJumpHere(v, addr);
+    }
   }
   VdbeModuleComment((pParse->pVdbe, "End windowCodeStep.SECOND_ROW_CODE"));
 
@@ -2195,9 +1917,16 @@ static void windowCodeStep(
     int addrBreak2;
     int addrBreak3;
     windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0);
-    addrStart = sqlite3VdbeCurrentAddr(v);
-    addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 1);
-    addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 1);
+    if( pMWin->eEnd==TK_UNBOUNDED ){
+      addrStart = sqlite3VdbeCurrentAddr(v);
+      addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regStart, 1);
+      addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, 0, 1);
+    }else{
+      assert( pMWin->eEnd==TK_FOLLOWING );
+      addrStart = sqlite3VdbeCurrentAddr(v);
+      addrBreak1 = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 1);
+      addrBreak2 = windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 1);
+    }
     sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart);
     sqlite3VdbeJumpHere(v, addrBreak2);
     addrStart = sqlite3VdbeCurrentAddr(v);
@@ -2688,21 +2417,10 @@ void sqlite3WindowCodeStep(
   ** does not cache each partition in a temp table before beginning to
   ** return rows.
   */
-  if( pMWin->eType==TK_ROWS 
-   && (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy)
-  ){
-    int bCache = windowCachePartition(pMWin);
-    if( (pMWin->eEnd!=TK_FOLLOWING   && pMWin->eEnd!=TK_PRECEDING) 
-     || (pMWin->eStart!=TK_FOLLOWING && pMWin->eStart!=TK_PRECEDING) 
-    ){
-      VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()"));
-      windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
-      VdbeModuleComment((pParse->pVdbe, "End RowExprStep()"));
-    }else{
-      VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep()"));
-      windowCodeStep(pParse, p, pWInfo, regGosub, addrGosub);
-      VdbeModuleComment((pParse->pVdbe, "End windowCodeStep()"));
-    }
+  if( pMWin->eType==TK_ROWS ){
+    VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep()"));
+    windowCodeStep(pParse, p, pWInfo, regGosub, addrGosub);
+    VdbeModuleComment((pParse->pVdbe, "End windowCodeStep()"));
   }else{
     Window *pWin;
     int bCache = 0;               /* True to use CacheStep() */