Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | If the SQLITE_ENABLE_CURSOR_HINTS macro is defined, then invoke the sqlite3BtreeCursorHint() interface to provide hints to the storage engine about rows that need not be returned. Hints can be disabled using SQLITE_TESTCTRL_OPTIMIZATIONS with SQLITE_CursorHints (0x2000). Cursor hints are not used by the built-in storage engine of SQLite but might be useful to applications that provide their own storage engine. The current code is work-in-progrss and contains bugs. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | cursor-hints |
Files: | files | file ages | folders |
SHA1: |
3a9bec524ef2de44028b4058e67dc962 |
User & Date: | drh 2013-12-07 20:39:19.762 |
Context
2013-12-07
| ||
23:35 | Do not allow cursor hints to use expressions containing subqueries. This change fixes the problem seen in the previous check-in. (check-in: bfefc57554 user: drh tags: cursor-hints) | |
20:39 | If the SQLITE_ENABLE_CURSOR_HINTS macro is defined, then invoke the sqlite3BtreeCursorHint() interface to provide hints to the storage engine about rows that need not be returned. Hints can be disabled using SQLITE_TESTCTRL_OPTIMIZATIONS with SQLITE_CursorHints (0x2000). Cursor hints are not used by the built-in storage engine of SQLite but might be useful to applications that provide their own storage engine. The current code is work-in-progrss and contains bugs. (check-in: 3a9bec524e user: drh tags: cursor-hints) | |
17:01 | Increase the version number to 3.8.3. (check-in: 23d00f2287 user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
︙ | ︙ | |||
760 761 762 763 764 765 766 767 768 769 770 771 772 773 | *pHasMoved = 1; }else{ *pHasMoved = 0; } return SQLITE_OK; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Given a page number of a regular database page, return the page ** number for the pointer-map page that contains the entry for the ** input page number. ** ** Return 0 (not a valid page) for pgno==1 since there is | > > > > > > > > > > > > > > > | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 | *pHasMoved = 1; }else{ *pHasMoved = 0; } return SQLITE_OK; } #ifdef SQLITE_ENABLE_CURSOR_HINTS /* ** Give a hint to the cursor that it only has to deliver rows for which ** the expression pExpr is true. Within this expression, rows of the ** cursor are identified by Expr.op==TK_COLUMN with Expr.iTable==iTable. ** ** This interfaces is not used by the standard storage engine of SQLite. ** It is only useful to application that replace SQLite's built-in storage ** engine with their own. */ void sqlite3BtreeCursorHint(BtCursor *pCur, int iTable, const Expr *pExpr){ /* Alternative storage engines might use this. */ } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Given a page number of a regular database page, return the page ** number for the pointer-map page that contains the entry for the ** input page number. ** ** Return 0 (not a valid page) for pgno==1 since there is |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
163 164 165 166 167 168 169 170 171 172 173 174 175 176 | BtCursor*, UnpackedRecord *pUnKey, i64 intKey, int bias, int *pRes ); int sqlite3BtreeCursorHasMoved(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, const void *pData, int nData, int nZero, int bias, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes); | > > > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | BtCursor*, UnpackedRecord *pUnKey, i64 intKey, int bias, int *pRes ); int sqlite3BtreeCursorHasMoved(BtCursor*, int*); #ifdef SQLITE_ENABLE_CURSOR_HINTS void sqlite3BtreeCursorHint(BtCursor*, int, const Expr*); #endif int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, const void *pData, int nData, int nZero, int bias, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes); |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 | #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ #define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */ #define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #ifndef SQLITE_OMIT_BUILTIN_TEST #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) | > | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ #define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */ #define SQLITE_AdjustOutEst 0x1000 /* Adjust output estimates using WHERE */ #define SQLITE_CursorHints 0x2000 /* Add OP_CursorHint opcodes */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #ifndef SQLITE_OMIT_BUILTIN_TEST #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 | sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE_DEBUG */ break; } #endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* | > > > > > > > > > > > > > > > > > > | 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 | sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE_DEBUG */ break; } #endif #ifdef SQLITE_ENABLE_CURSOR_HINTS /* Opcode: CursorHint P1 P2 * P4 * ** ** Provide a hint to cursor P1 that it only needs to return rows that ** satisfy the Expr tree given in P4. P2 is the table number of cursor P1 ** such that references to cursor P1 in the Expr tree are given by ** Expr.iTable==P2. */ case OP_CursorHint: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p4type==P4_EXPR ); pC = p->apCsr[pOp->p1]; if( pC ) sqlite3BtreeCursorHint(pC->pCursor, pOp->p2, pOp->p4.pExpr); break; } #endif /* SQLITE_ENABLE_CURSOR_HINTS */ /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 | FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE int cnt; /* Number of times this instruction was executed */ | > > > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ #ifdef SQLITE_ENABLE_CURSOR_HINTS Expr *pExpr; /* Used when p4type is P4_EXPR */ #endif int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE int cnt; /* Number of times this instruction was executed */ |
︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 | */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P4_STATIC (-2) /* Pointer to a static string */ #define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ | > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P4_STATIC (-2) /* Pointer to a static string */ #define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ #define P4_EXPR (-7) /* P4 is a pointer to an Expr tree */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
635 636 637 638 639 640 641 642 643 644 645 646 647 648 | sqlite3DbFree(db, p4); break; } case P4_KEYINFO: { if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); break; } case P4_MPRINTF: { if( db->pnBytesFreed==0 ) sqlite3_free(p4); break; } case P4_FUNCDEF: { freeEphemeralFunction(db, (FuncDef*)p4); break; | > > > > > > | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | sqlite3DbFree(db, p4); break; } case P4_KEYINFO: { if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS case P4_EXPR: { sqlite3ExprDelete(db, (Expr*)p4); break; } #endif case P4_MPRINTF: { if( db->pnBytesFreed==0 ) sqlite3_free(p4); break; } case P4_FUNCDEF: { freeEphemeralFunction(db, (FuncDef*)p4); break; |
︙ | ︙ | |||
752 753 754 755 756 757 758 759 760 761 762 763 764 765 | pOp->p4type = P4_INT32; }else if( zP4==0 ){ pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; }else if( n==P4_KEYINFO ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_KEYINFO; }else if( n==P4_VTAB ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_VTAB; sqlite3VtabLock((VTable *)zP4); assert( ((VTable *)zP4)->db==p->db ); }else if( n<0 ){ pOp->p4.p = (void*)zP4; | > > > > > > > > > | 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 | pOp->p4type = P4_INT32; }else if( zP4==0 ){ pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; }else if( n==P4_KEYINFO ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_KEYINFO; #ifdef SQLITE_ENABLE_CURSOR_HINTS }else if( n==P4_EXPR ){ /* Responsibility for deleting the Expr tree is handed over to the ** VDBE by this operation. The caller should have already invoked ** sqlite3ExprDup() or whatever other routine is needed to make a ** private copy of the tree. */ pOp->p4.pExpr = (Expr*)zP4; pOp->p4type = P4_EXPR; #endif }else if( n==P4_VTAB ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_VTAB; sqlite3VtabLock((VTable *)zP4); assert( ((VTable *)zP4)->db==p->db ); }else if( n<0 ){ pOp->p4.p = (void*)zP4; |
︙ | ︙ | |||
969 970 971 972 973 974 975 976 977 978 979 980 981 982 | i += n; } zTemp[i++] = ')'; zTemp[i] = 0; assert( i<nTemp ); break; } case P4_COLLSEQ: { CollSeq *pColl = pOp->p4.pColl; sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; | > > > > > > | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 | i += n; } zTemp[i++] = ')'; zTemp[i] = 0; assert( i<nTemp ); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS case P4_EXPR: { sqlite3_snprintf(nTemp, zTemp, "(expr)"); break; } #endif case P4_COLLSEQ: { CollSeq *pColl = pOp->p4.pColl; sqlite3_snprintf(nTemp, zTemp, "(%.20s)", pColl->zName); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 | sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } } #else # define explainOneScan(u,v,w,x,y,z) #endif /* SQLITE_OMIT_EXPLAIN */ /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ static Bitmask codeOneLoopStart( WhereInfo *pWInfo, /* Complete information about the WHERE clause */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 | sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC); } } #else # define explainOneScan(u,v,w,x,y,z) #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_CURSOR_HINTS /* ** Insert an OP_CursorHint instruction if it is appropriate to do so. */ static void codeCursorHint( WhereInfo *pWInfo, int iLevel ){ Parse *pParse = pWInfo->pParse; sqlite3 *db = pParse->db; Vdbe *v = pParse->pVdbe; WhereLevel *pLevel; Expr *pExpr = 0; int iCur; Bitmask msk; WhereClause *pWC; WhereTerm *pTerm; WhereLoop *pWLoop; int i, j; if( OptimizationDisabled(db, SQLITE_CursorHints) ) return; pLevel = &pWInfo->a[iLevel]; pWLoop = pLevel->pWLoop; iCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; msk = ~getMask(&pWInfo->sMaskSet, iCur); pWC = &pWInfo->sWC; for(i=0; i<pWC->nTerm; i++){ pTerm = &pWC->a[i]; if( pTerm->prereqAll & msk ) continue; if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; for(j=0; j<pWLoop->nLTerm && pWLoop->aLTerm[j]!=pTerm; j++){} if( j<pWLoop->nLTerm ) continue; pExpr = sqlite3ExprAnd(db, pExpr, sqlite3ExprDup(db, pTerm->pExpr, 0)); } if( pExpr!=0 ){ sqlite3VdbeAddOp4(v, OP_CursorHint, pLevel->iTabCur, iCur, 0, (const char*)pExpr, P4_EXPR); } } #else # define codeCursorHint(A,B) /* No-op */ #endif /* SQLITE_ENABLE_CURSOR_HINTS */ /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ static Bitmask codeOneLoopStart( WhereInfo *pWInfo, /* Complete information about the WHERE clause */ |
︙ | ︙ | |||
2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; pStart = pEnd; pEnd = pTerm; } if( pStart ){ Expr *pX; /* The expression that defines the start bound */ int r1, rTemp; /* Registers for holding the start boundary */ /* The following constant maps TK_xx codes into corresponding ** seek opcodes. It depends on a particular ordering of TK_xx */ | > | 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 | if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; assert( pStart!=0 || pEnd!=0 ); if( bRev ){ pTerm = pStart; pStart = pEnd; pEnd = pTerm; } codeCursorHint(pWInfo, iLevel); if( pStart ){ Expr *pX; /* The expression that defines the start bound */ int r1, rTemp; /* Registers for holding the start boundary */ /* The following constant maps TK_xx codes into corresponding ** seek opcodes. It depends on a particular ordering of TK_xx */ |
︙ | ︙ | |||
3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 | testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); start_constraints = pRangeStart || nEq>0; /* Seek the index cursor to the start of the range. */ nConstraint = nEq; if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; sqlite3ExprCode(pParse, pRight, regBase+nEq); if( (pRangeStart->wtFlags & TERM_VNULL)==0 ){ sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt); } | > | 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 | testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); start_constraints = pRangeStart || nEq>0; /* Seek the index cursor to the start of the range. */ codeCursorHint(pWInfo, iLevel); nConstraint = nEq; if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; sqlite3ExprCode(pParse, pRight, regBase+nEq); if( (pRangeStart->wtFlags & TERM_VNULL)==0 ){ sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt); } |
︙ | ︙ | |||
3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 | { /* Case 6: There is no usable index. We must do a complete ** scan of the entire table. */ static const u8 aStep[] = { OP_Next, OP_Prev }; static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } /* Insert code to test every subexpression that can be completely | > | 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 | { /* Case 6: There is no usable index. We must do a complete ** scan of the entire table. */ static const u8 aStep[] = { OP_Next, OP_Prev }; static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); codeCursorHint(pWInfo, iLevel); pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } /* Insert code to test every subexpression that can be completely |
︙ | ︙ |