Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix other "ROWS BETWEEN" cases on this branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | window-functions |
Files: | files | file ages | folders |
SHA3-256: |
a5f68f66472610b5beb4fe28669fbbfe |
User & Date: | dan 2019-03-07 20:47:46.020 |
Context
2019-03-08
| ||
20:02 | Finish consolidation of window frame code. Add untested support for GROUPS frames. (check-in: 954bf36993 user: dan tags: window-functions) | |
2019-03-07
| ||
20:47 | Fix other "ROWS BETWEEN" cases on this branch. (check-in: a5f68f6647 user: dan tags: window-functions) | |
19:26 | Modify new window functions function so that cursors are stepped immediately after each operation, instead of immediately before. (check-in: 093d2b25f1 user: dan tags: window-functions) | |
Changes
Changes to src/window.c.
︙ | ︙ | |||
1538 1539 1540 1541 1542 1543 1544 | } } regArg = pParse->nMem+1; pParse->nMem += nArg; return regArg; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 | } } regArg = pParse->nMem+1; pParse->nMem += nArg; return regArg; } /* ** Return true if the entire partition should be cached in the ephemeral ** table before processing any rows. */ static int windowCachePartition(Window *pMWin){ Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ |
︙ | ︙ | |||
1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 | static int windowCodeOp( WindowCodeArg *p, int op, int csr, int regCountdown, int jumpOnEof ){ int ret = 0; Vdbe *v = p->pVdbe; int addrIf = 0; if( regCountdown>0 ){ addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1); } switch( op ){ case WINDOW_RETURN_ROW: | > > > > > > > > | | | | | 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 | static int windowCodeOp( WindowCodeArg *p, int op, int csr, 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, pMWin, 0); windowReturnOneRow(p->pParse, pMWin, p->regGosub, p->addrGosub); break; case WINDOW_AGGINVERSE: windowAggStep(p->pParse, pMWin, csr, 1, p->regArg, pMWin->regSize); break; case WINDOW_AGGSTEP: windowAggStep(p->pParse, pMWin, csr, 0, p->regArg, pMWin->regSize); break; } if( jumpOnEof ){ sqlite3VdbeAddOp2(v, OP_Next, csr, sqlite3VdbeCurrentAddr(v)+2); ret = sqlite3VdbeAddOp0(v, OP_Goto); }else{ |
︙ | ︙ | |||
2002 2003 2004 2005 2006 2007 2008 | int regArg; int csrCurrent = pMWin->iEphCsr; int csrWrite = csrCurrent+1; int csrStart = csrCurrent+2; int csrEnd = csrCurrent+3; | < < > > > > > | > > | > | 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | int regArg; int csrCurrent = pMWin->iEphCsr; int csrWrite = csrCurrent+1; int csrStart = csrCurrent+2; int csrEnd = csrCurrent+3; 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 */ int iCol; /* To iterate through sub cols */ int addrGoto; int addrIf; int addrGosubFlush; int addrInteger; int addrCacheRewind; int addrCacheNext; int addrShortcut = 0; int addrEmpty = 0; 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; WindowCodeArg s; memset(&s, 0, sizeof(WindowCodeArg)); s.pParse = pParse; s.pMWin = pMWin; s.pVdbe = v; s.regGosub = regGosub; s.addrGosub = addrGosub; pParse->nMem += 1 + nSub + 1; regFlushPart = ++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 || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED ); assert( pMWin->eEnd==TK_FOLLOWING |
︙ | ︙ | |||
2103 2104 2105 2106 2107 2108 2109 | }else{ addrIf = sqlite3VdbeAddOp1(v, OP_IfNot, pMWin->regFirst); } /* This block is run for the first row of each partition */ s.regArg = regArg = windowInitAccum(pParse, pMWin); | > | | > > | | | > | < < | > > | > > | | > > | | | | > | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 | }else{ addrIf = sqlite3VdbeAddOp1(v, OP_IfNot, pMWin->regFirst); } /* This block is run for the first row of each partition */ s.regArg = regArg = windowInitAccum(pParse, pMWin); 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 && regStart && regEnd ){ int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le); int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd); windowAggFinal(pParse, pMWin, 0); if( bCache ){ sqlite3VdbeAddOp2(v, OP_Rowid, csrWrite, regRowid); sqlite3VdbeAddOp3(v, OP_NotExists, csrCurrent, 0, regRowid); windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); sqlite3VdbeAddOp2(v, OP_Next, csrWrite, addrCacheRewind+1); }else{ sqlite3VdbeAddOp2(v, OP_Rewind, csrCurrent, 1); windowReturnOneRow(pParse, pMWin, regGosub, addrGosub); sqlite3VdbeAddOp1(v, OP_ResetSorter, csrCurrent); } addrShortcut = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, addrGe); } if( pMWin->eStart==TK_FOLLOWING && regEnd ){ assert( pMWin->eEnd==TK_FOLLOWING ); sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regStart); } if( pMWin->eStart!=TK_UNBOUNDED ){ sqlite3VdbeAddOp2(v, OP_Rewind, csrStart, 1); } sqlite3VdbeAddOp2(v, OP_Rewind, csrCurrent, 1); sqlite3VdbeAddOp2(v, OP_Rewind, csrEnd, 1); sqlite3VdbeAddOp2(v, OP_Integer, 0, pMWin->regFirst); addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); /* Begin generating SECOND_ROW_CODE */ VdbeModuleComment((pParse->pVdbe, "Begin windowCodeStep.SECOND_ROW_CODE")); if( bCache ){ addrCacheNext = sqlite3VdbeCurrentAddr(v); }else{ sqlite3VdbeJumpHere(v, addrIf); } if( pMWin->eStart==TK_FOLLOWING ){ windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 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); windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0); windowCodeOp(&s, WINDOW_AGGINVERSE, csrStart, regStart, 0); }else{ int addr; windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0); 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")); /* End of the main input loop */ sqlite3VdbeJumpHere(v, addrGoto); if( bCache ){ sqlite3VdbeAddOp2(v, OP_Next, csrWrite, addrCacheNext); |
︙ | ︙ | |||
2191 2192 2193 2194 2195 2196 2197 | windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0); }else if( pMWin->eStart==TK_FOLLOWING ){ int addrStart; int addrBreak1; int addrBreak2; int addrBreak3; windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0); | > | > > > > > | | > | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 | windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 0); }else if( pMWin->eStart==TK_FOLLOWING ){ int addrStart; int addrBreak1; int addrBreak2; int addrBreak3; windowCodeOp(&s, WINDOW_AGGSTEP, csrEnd, 0, 0); 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); addrBreak3 = windowCodeOp(&s, WINDOW_RETURN_ROW, csrCurrent, 0, 1); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrStart); sqlite3VdbeJumpHere(v, addrBreak1); sqlite3VdbeJumpHere(v, addrBreak3); |
︙ | ︙ | |||
2684 2685 2686 2687 2688 2689 2690 | ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ** ** windowCodeDefaultStep() is the only one of the three functions that ** does not cache each partition in a temp table before beginning to ** return rows. */ | | < < < < < < < < < < | | | < | 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 | ** RANGE BETWEEN CURRENT ROW AND CURRENT ROW ** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ** ** windowCodeDefaultStep() is the only one of the three functions that ** does not cache each partition in a temp table before beginning to ** return rows. */ 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() */ if( pMWin->eStart==TK_CURRENT && pMWin->eEnd==TK_UNBOUNDED ){ bCache = 1; }else{ |
︙ | ︙ |