/ Check-in [45cbd3b4]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Simplify the window function code generator some more.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | window-functions
Files: files | file ages | folders
SHA3-256: 45cbd3b4498cea8856f189e9d0a192556d4f15212055b8328a1beca6083fc47a
User & Date: dan 2019-03-06 21:04:11
Wiki:window-functions
Context
2019-03-07
19:26
Modify new window functions function so that cursors are stepped immediately after each operation, instead of immediately before. check-in: 093d2b25 user: dan tags: window-functions
2019-03-06
21:04
Simplify the window function code generator some more. check-in: 45cbd3b4 user: dan tags: window-functions
17:12
Improvements to the way built-in window functions are handled. check-in: e8eee566 user: dan tags: window-functions
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/window.c.

  1840   1840     VdbeComment((v, "end flush_partition subroutine"));
  1841   1841   
  1842   1842     /* Jump to here to skip over flush_partition */
  1843   1843     sqlite3VdbeJumpHere(v, addrGoto);
  1844   1844   }
  1845   1845   
  1846   1846   /* 
  1847         -** Return true if the entire partition should be cached in the temp
  1848         -** table before processing.
         1847  +** Return true if the entire partition should be cached in the ephemeral
         1848  +** table before processing any rows.
  1849   1849   */
  1850   1850   static int windowCachePartition(Window *pMWin){
  1851   1851     Window *pWin;
  1852   1852     for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
  1853   1853       FuncDef *pFunc = pWin->pFunc;
  1854   1854       if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
  1855   1855        || (pFunc->zName==nth_valueName)
................................................................................
  1859   1859       ){
  1860   1860         return 1;
  1861   1861       }
  1862   1862     }
  1863   1863     return 0;
  1864   1864   }
  1865   1865   
         1866  +typedef struct WindowCodeArg WindowCodeArg;
         1867  +struct WindowCodeArg {
         1868  +  Parse *pParse;
         1869  +  Window *pMWin;
         1870  +  Vdbe *pVdbe;
         1871  +  int regGosub;
         1872  +  int addrGosub;
         1873  +  int regArg;
         1874  +};
         1875  +
         1876  +#define WINDOW_RETURN_ROW 1
         1877  +#define WINDOW_AGGINVERSE 2
         1878  +#define WINDOW_AGGSTEP    3
         1879  +
         1880  +static int windowCodeOp(
         1881  + WindowCodeArg *p,
         1882  + int op,
         1883  + int csr,
         1884  + int regCountdown,
         1885  + int jumpOnEof
         1886  +){
         1887  +  int ret = 0;
         1888  +  Vdbe *v = p->pVdbe;
         1889  +  int addrIf = 0; 
         1890  +
         1891  +  if( regCountdown>0 ){
         1892  +    addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1);
         1893  +  }
         1894  +
         1895  +  if( jumpOnEof ){
         1896  +    sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2);
         1897  +    ret = sqlite3VdbeAddOp0(v, OP_Goto);
         1898  +  }else{
         1899  +    sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+1);
         1900  +  }
         1901  +
         1902  +  switch( op ){
         1903  +    case WINDOW_RETURN_ROW:
         1904  +      windowAggFinal(p->pParse, p->pMWin, 0);
         1905  +      windowReturnOneRow(p->pParse, p->pMWin, p->regGosub, p->addrGosub);
         1906  +      break;
         1907  +
         1908  +    case WINDOW_AGGINVERSE:
         1909  +      windowAggStep(p->pParse, p->pMWin, csr, 1, p->regArg, p->pMWin->regSize);
         1910  +      break;
         1911  +
         1912  +    case WINDOW_AGGSTEP:
         1913  +      windowAggStep(p->pParse, p->pMWin, csr, 0, p->regArg, p->pMWin->regSize);
         1914  +      break;
         1915  +  }
         1916  +
         1917  +  if( ret ){
         1918  +    sqlite3VdbeJumpHere(v, ret);
         1919  +  }
         1920  +  if( regCountdown>0 ){
         1921  +    sqlite3VdbeJumpHere(v, addrIf);
         1922  +  }
         1923  +  return ret;
         1924  +}
         1925  +
         1926  +
         1927  +
         1928  +/*
         1929  +** This function - windowCodeStep() - generates the VM code that reads data
         1930  +** from the sub-select and returns rows to the consumer. For the simplest
         1931  +** case:
         1932  +**
         1933  +**     ROWS BETWEEN <expr1> PRECEDING AND <expr2> FOLLOWING
         1934  +**
         1935  +** The VM code generated is equivalent in spirit to the following:
         1936  +**
         1937  +**     while( !eof ){
         1938  +**       if( new partition ){
         1939  +**         Gosub flush
         1940  +**       }    
         1941  +**       Insert new row into eph table.
         1942  +**     
         1943  +**       if( first row of partition ){
         1944  +**         Rewind(csrEnd, skipNext=1)
         1945  +**         Rewind(csrStart, skipNext=1)
         1946  +**         Rewind(csrCurrent, skipNext=1)
         1947  +**     
         1948  +**         regEnd = <expr2>          // FOLLOWING expression
         1949  +**         regStart = <expr1>        // PRECEDING expression
         1950  +**       }else{
         1951  +**         if( (regEnd--)<=0 ){
         1952  +**           Next(csrCurrent)
         1953  +**           Return one row.
         1954  +**           if( (regStart--)<0 ){
         1955  +**             Next(csrStart)
         1956  +**             AggInverse(csrStart)
         1957  +**           }
         1958  +**         }
         1959  +**       }    
         1960  +**     
         1961  +**       Next(csrEnd)
         1962  +**       AggStep(csrEnd)
         1963  +**     }    
         1964  +**     flush:
         1965  +**       while( 1 ){ 
         1966  +**         Next(csrCurrent)
         1967  +**         if( eof ) break
         1968  +**         Return one row.
         1969  +**         if( (regStart--)<0 ){
         1970  +**           Next(csrStart)
         1971  +**           AggInverse(csrStart)
         1972  +**         }
         1973  +**       }    
         1974  +**       Empty eph table.
         1975  +**
         1976  +** More generally, the pattern used for all window types is:
         1977  +**
         1978  +**     while( !eof ){
         1979  +**       if( new partition ){
         1980  +**         Gosub flush
         1981  +**       }    
         1982  +**       Insert new row into eph table.
         1983  +**       if( first row of partition ){
         1984  +**         FIRST_ROW_CODE
         1985  +**       }else{
         1986  +**         SECOND_ROW_CODE
         1987  +**       }    
         1988  +**       ALL_ROW_CODE
         1989  +**     }    
         1990  +**     flush:
         1991  +**       FLUSH_CODE
         1992  +**       Empty eph table.
         1993  +**
         1994  +*/
  1866   1995   static void windowCodeStep(
  1867   1996     Parse *pParse, 
  1868   1997     Select *p,
  1869   1998     WhereInfo *pWInfo,
  1870   1999     int regGosub, 
  1871   2000     int addrGosub
  1872   2001   ){
................................................................................
  1879   2008     int csrWrite = csrCurrent+1;
  1880   2009     int csrStart = csrCurrent+2;
  1881   2010     int csrEnd = csrCurrent+3;
  1882   2011   
  1883   2012     int regStart;                    /* Value of <expr> PRECEDING */
  1884   2013     int regEnd;                      /* Value of <expr> FOLLOWING */
  1885   2014   
  1886         -  int iSubCsr = p->pSrc->a[0].iCursor;
  1887         -  int nSub = p->pSrc->a[0].pTab->nCol;
  1888         -  int k;
         2015  +  int iSubCsr = p->pSrc->a[0].iCursor;      /* Cursor of sub-select */
         2016  +  int nSub = p->pSrc->a[0].pTab->nCol;      /* Number of cols returned by sub */
         2017  +  int iCol;                                 /* To iterate through sub cols */
  1889   2018   
  1890   2019     int addrGoto;
  1891   2020     int addrIf;
  1892         -  int addrIfEnd;
  1893         -  int addrIfStart;
  1894   2021     int addrGosubFlush;
  1895   2022     int addrInteger;
  1896   2023     int addrCacheRewind;
  1897   2024     int addrCacheNext;
  1898   2025   
  1899   2026     int addrShortcut = 0;
  1900   2027   
  1901   2028     int bCache = windowCachePartition(pMWin);
  1902   2029   
  1903   2030     int reg = pParse->nMem+1;
  1904   2031     int regRecord = reg+nSub;
  1905   2032     int regRowid = regRecord+1;
         2033  +  WindowCodeArg s;
  1906   2034   
  1907         -  bCache = 1;
         2035  +  memset(&s, 0, sizeof(WindowCodeArg));
         2036  +  s.pParse = pParse;
         2037  +  s.pMWin = pMWin;
         2038  +  s.pVdbe = v;
         2039  +  s.regGosub = regGosub;
         2040  +  s.addrGosub = addrGosub;
  1908   2041   
  1909   2042     pParse->nMem += 1 + nSub + 1;
  1910   2043   
  1911   2044     regFlushPart = ++pParse->nMem;
  1912   2045     regStart = ++pParse->nMem;
  1913   2046     regEnd = ++pParse->nMem;
  1914   2047   
................................................................................
  1918   2051          || pMWin->eStart==TK_UNBOUNDED 
  1919   2052     );
  1920   2053     assert( pMWin->eEnd==TK_FOLLOWING 
  1921   2054          || pMWin->eEnd==TK_CURRENT 
  1922   2055          || pMWin->eEnd==TK_UNBOUNDED 
  1923   2056          || pMWin->eEnd==TK_PRECEDING 
  1924   2057     );
         2058  +
  1925   2059   
  1926   2060     /* Load the column values for the row returned by the sub-select
  1927   2061     ** into an array of registers starting at reg. Assemble them into
  1928   2062     ** a record in register regRecord. TODO: An optimization here? */
  1929         -  for(k=0; k<nSub; k++){
  1930         -    sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
         2063  +  for(iCol=0; iCol<nSub; iCol++){
         2064  +    sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, iCol, reg+iCol);
  1931   2065     }
  1932   2066     sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, nSub, regRecord);
  1933   2067   
  1934   2068     /* An input row has just been read into an array of registers starting
  1935   2069     ** at reg. If the window has a PARTITION clause, this block generates 
  1936   2070     ** VM code to check if the input row is the start of a new partition.
  1937   2071     ** If so, it does an OP_Gosub to an address to be filled in later. The
................................................................................
  1969   2103       }
  1970   2104       addrCacheRewind = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite);
  1971   2105     }else{
  1972   2106       addrIf = sqlite3VdbeAddOp1(v, OP_IfNot, pMWin->regFirst);
  1973   2107     }
  1974   2108   
  1975   2109     /* This block is run for the first row of each partition */
  1976         -  regArg = windowInitAccum(pParse, pMWin);
         2110  +  s.regArg = regArg = windowInitAccum(pParse, pMWin);
  1977   2111   
  1978   2112     sqlite3ExprCode(pParse, pMWin->pStart, regStart);
  1979   2113     windowCheckIntValue(pParse, regStart, 0);
  1980   2114     sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
  1981   2115     windowCheckIntValue(pParse, regEnd, 1);
  1982   2116   
  1983         -  if( pMWin->eStart==TK_FOLLOWING || pMWin->eEnd==TK_PRECEDING ){
         2117  +  if( pMWin->eStart==pMWin->eEnd 
         2118  +   && pMWin->eStart!=TK_CURRENT && pMWin->eStart!=TK_UNBOUNDED 
         2119  +  ){
  1984   2120       int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
  1985   2121       int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
  1986   2122       windowAggFinal(pParse, pMWin, 0);
  1987   2123       if( bCache ){
  1988   2124         sqlite3VdbeAddOp2(v, OP_Rowid, csrWrite, regRowid);
  1989   2125         sqlite3VdbeAddOp3(v, OP_NotExists, csrCurrent, 0, regRowid);
  1990   2126         windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
................................................................................
  2004   2140     sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, 1);   sqlite3VdbeChangeP5(v, 1);
  2005   2141     sqlite3VdbeAddOp2(v, OP_Rewind, csrCurrent, 1); sqlite3VdbeChangeP5(v, 1);
  2006   2142     sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, 1); sqlite3VdbeChangeP5(v, 1);
  2007   2143   
  2008   2144     sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regFirst);
  2009   2145     addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
  2010   2146   
  2011         -  /* This block is run for the second and subsequent rows of each partition */
         2147  +  /* Begin generating SECOND_ROW_CODE */
         2148  +  VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep.SECOND_ROW_CODE"));
  2012   2149     if( bCache ){
  2013   2150       addrCacheNext = sqlite3VdbeCurrentAddr(v);
  2014   2151     }else{
  2015   2152       sqlite3VdbeJumpHere(v, addrIf);
  2016   2153     }
  2017         -
  2018   2154     if( pMWin->eStart==TK_FOLLOWING ){
  2019         -    addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
  2020         -    windowAggFinal(pParse, pMWin, 0);
  2021         -    sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+1);
  2022         -    windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
  2023         -    sqlite3VdbeJumpHere(v, addrIfEnd);
  2024         -
  2025         -    addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
  2026         -    sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
  2027         -    windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
  2028         -    sqlite3VdbeJumpHere(v, addrIfStart);
         2155  +    windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 0);
         2156  +    windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
  2029   2157     }else
  2030   2158     if( pMWin->eEnd==TK_PRECEDING ){
  2031         -    addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
  2032         -    sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+1);
  2033         -    windowAggStep(pParse, pMWin, csrEnd, 0, regArg, pMWin->regSize);
  2034         -    sqlite3VdbeJumpHere(v, addrIfEnd);
  2035         -
  2036         -    windowAggFinal(pParse, pMWin, 0);
  2037         -    sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+1);
  2038         -    windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
  2039         -
  2040         -    addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
  2041         -    sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
  2042         -    windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
  2043         -    sqlite3VdbeJumpHere(v, addrIfStart);
         2159  +    windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, regEnd, 0);
         2160  +    windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0);
         2161  +    windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
  2044   2162     }else{
  2045         -    addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
  2046         -    windowAggFinal(pParse, pMWin, 0);
  2047         -    sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+1);
  2048         -    windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
  2049         -    addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
  2050         -    sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
  2051         -    windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
  2052         -    sqlite3VdbeJumpHere(v, addrIfStart);
  2053         -    sqlite3VdbeJumpHere(v, addrIfEnd);
         2163  +    int addr = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
         2164  +    windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0);
         2165  +    windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
         2166  +    sqlite3VdbeJumpHere(v, addr);
  2054   2167     }
         2168  +  VdbeModuleComment((pParse->pVdbe, "End windowCodeStep.SECOND_ROW_CODE"));
  2055   2169   
         2170  +  VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep.ALL_ROW_CODE"));
  2056   2171     sqlite3VdbeJumpHere(v, addrGoto);
  2057   2172     if( pMWin->eEnd!=TK_PRECEDING ){
  2058         -    sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+1);
  2059         -    windowAggStep(pParse, pMWin, csrEnd, 0, regArg, pMWin->regSize);
         2173  +    windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0);
  2060   2174     }
         2175  +  VdbeModuleComment((pParse->pVdbe, "End windowCodeStep.ALL_ROW_CODE"));
  2061   2176   
  2062   2177     /* End of the main input loop */
  2063   2178     if( bCache ){
  2064   2179       sqlite3VdbeAddOp2(v, OP_Next, csrWrite, addrCacheNext);
  2065   2180       sqlite3VdbeJumpHere(v, addrCacheRewind); 
  2066   2181     }else{
  2067   2182       if( addrShortcut>0 ) sqlite3VdbeJumpHere(v, addrShortcut);
  2068   2183       sqlite3WhereEnd(pWInfo);
  2069   2184     }
  2070   2185   
  2071   2186     /* Fall through */
  2072   2187   
         2188  +  VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep.FLUSH_CODE"));
  2073   2189     if( pMWin->pPartition && bCache==0 ){
  2074   2190       addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart);
  2075   2191       sqlite3VdbeJumpHere(v, addrGosubFlush);
  2076   2192     }
  2077   2193   
  2078         -  if( pMWin->eStart==TK_FOLLOWING ){
         2194  +  if( pMWin->eEnd==TK_PRECEDING ){
         2195  +    windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, regEnd, 1);
         2196  +    windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 1);
         2197  +  }else{
  2079   2198       int addrBreak;
  2080         -    addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
  2081         -    sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+2);
  2082         -    addrBreak = sqlite3VdbeAddOp0(v, OP_Goto);
  2083         -    windowAggFinal(pParse, pMWin, 0);
  2084         -    windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
  2085         -    sqlite3VdbeJumpHere(v, addrIfEnd);
  2086         -
  2087         -    addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
  2088         -    sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2);
  2089         -    sqlite3VdbeAddOp0(v, OP_Goto);
  2090         -    windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
  2091         -    sqlite3VdbeJumpHere(v, addrIfStart);
  2092         -    sqlite3VdbeJumpHere(v, addrIfStart+2);
  2093         -
  2094         -    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrIfEnd);
         2199  +    int addrStart = sqlite3VdbeCurrentAddr(v);
         2200  +    if( pMWin->eStart==TK_FOLLOWING ){
         2201  +      addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, regEnd, 1);
         2202  +      windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 1);
         2203  +    }else{
         2204  +      addrBreak = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 1);
         2205  +      windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0);
         2206  +    }
         2207  +    sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart);
  2095   2208       sqlite3VdbeJumpHere(v, addrBreak);
  2096         -  }else{
  2097         -    sqlite3VdbeAddOp2(v, OP_Next, csrCurrent, sqlite3VdbeCurrentAddr(v)+2);
  2098         -    addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
  2099         -    if( pMWin->eEnd==TK_PRECEDING ){
  2100         -      addrIfEnd = sqlite3VdbeAddOp3(v, OP_IfPos, regEnd, 0, 1);
  2101         -      sqlite3VdbeAddOp2(v, OP_Next, csrEnd, sqlite3VdbeCurrentAddr(v)+1);
  2102         -      windowAggStep(pParse, pMWin, csrEnd, 0, regArg, pMWin->regSize);
  2103         -      sqlite3VdbeJumpHere(v, addrIfEnd);
  2104         -      windowAggFinal(pParse, pMWin, 0);
  2105         -      windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
  2106         -    }else{
  2107         -      windowAggFinal(pParse, pMWin, 0);
  2108         -      windowReturnOneRow(pParse, pMWin, regGosub, addrGosub);
  2109         -      addrIfStart = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0, 1);
  2110         -      sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
  2111         -      windowAggStep(pParse, pMWin, csrStart, 1, regArg, pMWin->regSize);
  2112         -      sqlite3VdbeJumpHere(v, addrIfStart);
  2113         -      sqlite3VdbeAddOp2(v, OP_Goto, 0, addrGoto-1);
  2114         -    }
  2115         -    sqlite3VdbeJumpHere(v, addrGoto);
  2116   2209     }
  2117         -
  2118   2210   
  2119   2211     if( bCache && addrShortcut>0 ) sqlite3VdbeJumpHere(v, addrShortcut);
  2120   2212     sqlite3VdbeAddOp1(v, OP_ResetSorter, csrCurrent);
  2121   2213     sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regSize);
  2122   2214     if( bCache==0 ) sqlite3VdbeAddOp2(v, OP_Integer, 1, pMWin->regFirst);
         2215  +  VdbeModuleComment((pParse->pVdbe, "End windowCodeStep.FLUSH_CODE"));
  2123   2216     if( pMWin->pPartition ){
  2124   2217       sqlite3VdbeChangeP1(v, addrInteger, sqlite3VdbeCurrentAddr(v));
  2125   2218       sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
  2126   2219     }
  2127   2220   }
  2128   2221   
  2129   2222   /*