Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Invert the meaning of the regBignull flag so that it is 1 when doing the normal scan and 1 when scanning nulls. This enables the re-do jump at the bottom of the loop to be coded with a single OP_IfNotZero opcode, rather than a sequence of OP_If, OP_Integer, OP_Goto. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | nulls-last |
Files: | files | file ages | folders |
SHA3-256: |
bf875e1a259a4167694e06349458452d |
User & Date: | drh 2019-08-23 13:32:03.306 |
Context
2019-08-23
| ||
16:12 | Simplification of the WHERE loop code generator for NULLS LAST saves a few CPU cycles and about a hundred bytes of code space. (check-in: e3ed2f496f user: drh tags: nulls-last) | |
13:32 | Invert the meaning of the regBignull flag so that it is 1 when doing the normal scan and 1 when scanning nulls. This enables the re-do jump at the bottom of the loop to be coded with a single OP_IfNotZero opcode, rather than a sequence of OP_If, OP_Integer, OP_Goto. (check-in: bf875e1a25 user: drh tags: nulls-last) | |
13:08 | Extra VDBE comments in the NULLS LAST logic provide landmarks to help understand the EXPLAIN output. (check-in: 649b08ead5 user: drh tags: nulls-last) | |
Changes
Changes to src/where.c.
︙ | ︙ | |||
5214 5215 5216 5217 5218 5219 5220 | sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); if( pLevel->regBignull ){ sqlite3VdbeResolveLabel(v, pLevel->addrBignull); | < < < < | < < | 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 | sqlite3VdbeChangeP5(v, pLevel->p5); VdbeCoverage(v); VdbeCoverageIf(v, pLevel->op==OP_Next); VdbeCoverageIf(v, pLevel->op==OP_Prev); VdbeCoverageIf(v, pLevel->op==OP_VNext); if( pLevel->regBignull ){ sqlite3VdbeResolveLabel(v, pLevel->addrBignull); sqlite3VdbeAddOp2(v, OP_IfNotZero, pLevel->regBignull, pLevel->p2-1); } #ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek); #endif }else{ sqlite3VdbeResolveLabel(v, pLevel->addrCont); } |
︙ | ︙ |
Changes to src/whereInt.h.
︙ | ︙ | |||
67 68 69 70 71 72 73 | int iIdxCur; /* The VDBE cursor used to access pIdx */ int addrBrk; /* Jump here to break out of the loop */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | int iIdxCur; /* The VDBE cursor used to access pIdx */ int addrBrk; /* Jump here to break out of the loop */ int addrNxt; /* Jump here to start the next IN combination */ int addrSkip; /* Jump here for next iteration of skip-scan */ int addrCont; /* Jump here to continue with the next loop cycle */ int addrFirst; /* First instruction of interior of the loop */ int addrBody; /* Beginning of the body of this loop */ int regBignull; /* big-null flag reg. True if a NULL-scan is needed */ int addrBignull; /* Jump here for next part of big-null scan */ #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */ int addrLikeRep; /* LIKE range processing address */ #endif u8 iFrom; /* Which entry in the FROM clause */ u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */ |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
1686 1687 1688 1689 1690 1691 1692 | ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur); } if( regBignull ){ | | | | 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 | ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){ sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur); } if( regBignull ){ sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull); VdbeComment((v, "NULL-scan needed flag")); } op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); VdbeCoverage(v); VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); |
︙ | ︙ | |||
1772 1773 1774 1775 1776 1777 1778 | /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ if( regBignull ){ | | | | | | 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 | /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ if( regBignull ){ sqlite3VdbeAddOp2(v, OP_IfNot, regBignull, sqlite3VdbeCurrentAddr(v)+3); VdbeComment((v, "If NULL-scan active")); VdbeCoverage(v); } op = aEndOp[bRev*2 + endEq]; sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); } if( regBignull ){ sqlite3VdbeAddOp2(v, OP_If, regBignull, sqlite3VdbeCurrentAddr(v)+2); VdbeComment((v, "If NULL-scan pending")); VdbeCoverage(v); if( bStopAtNull ){ op = aEndOp[bRev*2 + 0]; assert( op==OP_IdxGE || op==OP_IdxLE ); sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); |
︙ | ︙ |