Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Change opcode names and comments to better describe the operation of the incrKey flag. OP_MoveTo becomes OP_MoveGe. (CVS 1407) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8f249c45cbc77f4320798ff1a830b55e |
User & Date: | drh 2004-05-19 14:56:56.000 |
Context
2004-05-19
| ||
20:41 | Correctly handle 64-bit integers in SQL statements. (CVS 1408) (check-in: 34f03ba6a9 user: drh tags: trunk) | |
14:56 | Change opcode names and comments to better describe the operation of the incrKey flag. OP_MoveTo becomes OP_MoveGe. (CVS 1407) (check-in: 8f249c45cb user: drh tags: trunk) | |
13:13 | Bug fixes in where.c. The where.test test works again. (CVS 1406) (check-in: 7c31e257e2 user: drh tags: trunk) | |
Changes
Changes to src/delete.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** ** $Id: delete.c,v 1.68 2004/05/19 14:56:56 drh Exp $ */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
230 231 232 233 234 235 236 | addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); sqlite3VdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } | | < | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); sqlite3VdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } |
︙ | ︙ | |||
390 391 392 393 394 395 396 | } } sqlite3VdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); sqlite3IndexAffinityStr(v, pIdx); sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0); } } | < < < | 389 390 391 392 393 394 395 | } } sqlite3VdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0); sqlite3IndexAffinityStr(v, pIdx); sqlite3VdbeAddOp(v, OP_IdxDelete, iCur+i, 0); } } |
Changes to src/insert.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.103 2004/05/19 14:56:56 drh Exp $ */ #include "sqliteInt.h" /* ** Set P3 of the most recently inserted opcode to a column affinity ** string for index pIdx. A column affinity string has one character ** for each column in the table, according to the affinity of the column: |
︙ | ︙ | |||
819 820 821 822 823 824 825 | "PRIMARY KEY must be unique", P3_STATIC); break; } case OE_Replace: { sqlite3GenerateRowIndexDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1); | | | | 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | "PRIMARY KEY must be unique", P3_STATIC); break; } case OE_Replace: { sqlite3GenerateRowIndexDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRecnos, 1); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRecnos, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } } contAddr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeChangeP2(v, jumpInst2, contAddr); if( isUpdate ){ sqlite3VdbeChangeP2(v, jumpInst1, contAddr); sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ |
︙ | ︙ | |||
922 923 924 925 926 927 928 | sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3GenerateRowDelete(pParse->db, v, pTab, base, 0); if( isUpdate ){ sqlite3VdbeAddOp(v, OP_Dup, nCol+extra+1+hasTwoRecnos, 1); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } default: assert(0); } contAddr = sqlite3VdbeCurrentAddr(v); |
︙ | ︙ | |||
1006 1007 1008 1009 1010 1011 1012 | sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqlite3VdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC); } return i; } | < < < | 1006 1007 1008 1009 1010 1011 1012 | sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqlite3VdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC); } return i; } |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.169 2004/05/19 14:56:56 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. |
︙ | ︙ | |||
2019 2020 2021 2022 2023 2024 2025 | sqlite3VdbeAddOp(v, seekOp, base, 0); }else{ sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqlite3VdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, pIdx->zName, P3_STATIC); sqlite3VdbeAddOp(v, seekOp, base+1, 0); sqlite3VdbeAddOp(v, OP_IdxRecno, base+1, 0); sqlite3VdbeAddOp(v, OP_Close, base+1, 0); | | | 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 | sqlite3VdbeAddOp(v, seekOp, base, 0); }else{ sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); sqlite3VdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, pIdx->zName, P3_STATIC); sqlite3VdbeAddOp(v, seekOp, base+1, 0); sqlite3VdbeAddOp(v, OP_IdxRecno, base+1, 0); sqlite3VdbeAddOp(v, OP_Close, base+1, 0); sqlite3VdbeAddOp(v, OP_MoveGe, base, 0); } eList.nExpr = 1; memset(&eListItem, 0, sizeof(eListItem)); eList.a = &eListItem; eList.a[0].pExpr = pExpr; selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0); sqlite3VdbeResolveLabel(v, cont); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.77 2004/05/19 14:56:57 drh Exp $ */ #include "sqliteInt.h" /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; |
︙ | ︙ | |||
258 259 260 261 262 263 264 | */ sqlite3VdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | */ sqlite3VdbeAddOp(v, OP_Dup, 0, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); /* Generate the OLD table */ sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0); |
︙ | ︙ | |||
454 455 456 457 458 459 460 | sqliteFree(apIdx); sqliteFree(aXRef); sqlite3SrcListDelete(pTabList); sqlite3ExprListDelete(pChanges); sqlite3ExprDelete(pWhere); return; } | < < < | 454 455 456 457 458 459 460 | sqliteFree(apIdx); sqliteFree(aXRef); sqlite3SrcListDelete(pTabList); sqlite3ExprListDelete(pChanges); sqlite3ExprDelete(pWhere); return; } |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.304 2004/05/19 14:56:57 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_MoveXX, OP_Next, or OP_Prev opcodes. The test ** procedures use this information to make sure that indices are ** working correctly. This variable has no function other than to ** help verify the correct operation of the library. */ int sqlite3_search_count = 0; /* |
︙ | ︙ | |||
2753 2754 2755 2756 2757 2758 2759 | int i = pOp->p1; if( i>=0 && i<p->nCursor ){ sqlite3VdbeCleanupCursor(p->apCsr[i]); } break; } | | | | < | | > | > > | | > | < | | | | | | | > > > | | | | | | | > > > > | | 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 | int i = pOp->p1; if( i>=0 && i<p->nCursor ){ sqlite3VdbeCleanupCursor(p->apCsr[i]); } break; } /* Opcode: MoveGe P1 P2 * ** ** Pop the top of the stack and use its value as a key. Reposition ** cursor P1 so that it points to the smallest entry that is greater ** than or equal to the key that was popped ffrom the stack. ** If there are no records greater than or equal to the key and P2 ** is not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe */ /* Opcode: MoveGt P1 P2 * ** ** Pop the top of the stack and use its value as a key. Reposition ** cursor P1 so that it points to the smallest entry that is greater ** than the key from the stack. ** If there are no records greater than the key and P2 is not zero, ** then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe */ /* Opcode: MoveLt P1 P2 * ** ** Pop the top of the stack and use its value as a key. Reposition ** cursor P1 so that it points to the largest entry that is less ** than the key from the stack. ** If there are no records less than the key and P2 is not zero, ** then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe */ /* Opcode: MoveLe P1 P2 * ** ** Pop the top of the stack and use its value as a key. Reposition ** cursor P1 so that it points to the largest entry that is less than ** or equal to the key that was popped from the stack. ** If there are no records less than or eqal to the key and P2 is not zero, ** then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt */ case OP_MoveLt: case OP_MoveLe: case OP_MoveGe: case OP_MoveGt: { int i = pOp->p1; Cursor *pC; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; if( pC->pCursor!=0 ){ int res, oc; oc = pOp->opcode; pC->nullRow = 0; pC->incrKey = oc==OP_MoveGt || oc==OP_MoveLe; if( pC->intKey ){ i64 iKey; assert( !pOp->p3 ); Integerify(pTos); iKey = intToKey(pTos->i); if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){ pC->movetoTarget = iKey; pC->deferredMoveto = 1; Release(pTos); pTos--; break; } sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res); |
︙ | ︙ | |||
2827 2828 2829 2830 2831 2832 2833 | pC->incrKey = 0; pC->recnoIsValid = 0; } pC->deferredMoveto = 0; pC->cacheValid = 0; pC->incrKey = 0; sqlite3_search_count++; | < | > | | | | | > > | | 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 | pC->incrKey = 0; pC->recnoIsValid = 0; } pC->deferredMoveto = 0; pC->cacheValid = 0; pC->incrKey = 0; sqlite3_search_count++; if( oc==OP_MoveGe || oc==OP_MoveGt ){ if( res<0 ){ sqlite3BtreeNext(pC->pCursor, &res); pC->recnoIsValid = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } } }else{ assert( oc==OP_MoveLt || oc==OP_MoveLe ); if( res>=0 ){ sqlite3BtreePrevious(pC->pCursor, &res); pC->recnoIsValid = 0; }else{ /* res might be negative because the table is empty. Check to ** see if this is the case. */ |
︙ | ︙ | |||
2923 2924 2925 2926 2927 2928 2929 | /* Opcode: IsUnique P1 P2 * ** ** The top of the stack is an integer record number. Call this ** record number R. The next on the stack is an index key created ** using MakeIdxKey. Call it K. This instruction pops R from the ** stack but it leaves K unchanged. ** | | | > | | | 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 | /* Opcode: IsUnique P1 P2 * ** ** The top of the stack is an integer record number. Call this ** record number R. The next on the stack is an index key created ** using MakeIdxKey. Call it K. This instruction pops R from the ** stack but it leaves K unchanged. ** ** P1 is an index. So it has no data and its key consists of a ** record generated by OP_MakeIdxKey. This key contains one or more ** fields followed by a varint ROWID. ** ** This instruction asks if there is an entry in P1 where the ** fields matches K but the rowid is different from R. ** If there is no such entry, then there is an immediate ** jump to P2. If any entry does exist where the index string ** matches K but the record number is not R, then the record ** number for that entry is pushed onto the stack and control ** falls through to the next instruction. ** ** See also: Distinct, NotFound, NotExists, Found */ |
︙ | ︙ | |||
2983 2984 2985 2986 2987 2988 2989 | if( res<0 ){ rc = sqlite3BtreeNext(pCrsr, &res); if( res ){ pc = pOp->p2 - 1; break; } } | | | 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 | if( res<0 ){ rc = sqlite3BtreeNext(pCrsr, &res); if( res ){ pc = pOp->p2 - 1; break; } } rc = sqlite3VdbeIdxKeyCompare(pCx, len, zKey, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res>0 ){ pc = pOp->p2 - 1; break; } /* At this point, pCrsr is pointing to an entry in P1 where all but |
︙ | ︙ | |||
3681 3682 3683 3684 3685 3686 3687 | rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; while( res!=0 ){ int c; sqlite3BtreeKeySize(pCrsr, &n); if( n==nKey && | | | 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 | rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; while( res!=0 ){ int c; sqlite3BtreeKeySize(pCrsr, &n); if( n==nKey && sqlite3VdbeIdxKeyCompare(pC, len, zKey, &c)==SQLITE_OK && c==0 ){ rc = SQLITE_CONSTRAINT; if( pOp->p3 && pOp->p3[0] ){ sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0); } goto abort_due_to_error; |
︙ | ︙ | |||
3798 3799 3800 3801 3802 3803 3804 | #endif }else{ pTos->flags = MEM_Null; } break; } | | < < < < | | | > > > | | > < | < > | | 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 | #endif }else{ pTos->flags = MEM_Null; } break; } /* Opcode: IdxGT P1 P2 * ** ** Compare the top of the stack against the key on the index entry that ** cursor P1 is currently pointing to. Ignore the ROWID of the ** index entry. If the index entry is greater than the top of the stack ** then jump to P2. Otherwise fall through to the next instruction. ** In either case, the stack is popped once. */ /* Opcode: IdxGE P1 P2 P3 ** ** Compare the top of the stack against the key on the index entry that ** cursor P1 is currently pointing to. Ignore the ROWID of the ** index entry. If the index in the cursor is greater than or equal to ** the top of the stack ** then jump to P2. Otherwise fall through to the next instruction. ** In either case, the stack is popped once. ** ** If P3 is the "+" string (or any other non-NULL string) then the ** index taken from the top of the stack is temporarily increased by ** an epsilon prior to the comparison. This make the opcode work ** like IdxGT except that if the key from the stack is a prefix of ** the key in the cursor, the result is false whereas it would be ** true with IdxGT. */ /* Opcode: IdxLT P1 P2 P3 ** ** Compare the top of the stack against the key on the index entry that ** cursor P1 is currently pointing to. Ignore the ROWID of the ** index entry. If the index entry is less than the top of the stack ** then jump to P2. Otherwise fall through to the next instruction. ** In either case, the stack is popped once. ** ** If P3 is the "+" string (or any other non-NULL string) then the ** index taken from the top of the stack is temporarily increased by ** an epsilon prior to the comparison. This makes the opcode work ** like IdxLE. */ case OP_IdxLT: case OP_IdxGT: case OP_IdxGE: { int i= pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( pTos>=p->aStack ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rc; Stringify(pTos); assert( pC->deferredMoveto==0 ); pC->incrKey = pOp->p3!=0; assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT ); rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, pTos->z, &res); pC->incrKey = 0; if( rc!=SQLITE_OK ){ break; } if( pOp->opcode==OP_IdxLT ){ res = -res; }else if( pOp->opcode==OP_IdxGE ){ |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
324 325 326 327 328 329 330 | #endif int sqlite3VdbeSerialTypeLen(u64); u64 sqlite3VdbeSerialType(const Mem *); int sqlite3VdbeSerialPut(unsigned char *, const Mem *); int sqlite3VdbeSerialGet(const unsigned char *, u64, Mem *); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); | | | 324 325 326 327 328 329 330 331 332 333 334 335 | #endif int sqlite3VdbeSerialTypeLen(u64); u64 sqlite3VdbeSerialType(const Mem *); int sqlite3VdbeSerialPut(unsigned char *, const Mem *); int sqlite3VdbeSerialGet(const unsigned char *, u64, Mem *); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*); int sqlite3VdbeIdxRowid(BtCursor *, i64 *); int sqlite3MemCompare(Mem *, Mem *); int sqlite3VdbeKeyCompare(void*,int,const void*,int, const void*); int sqlite3VdbeRowCompare(void*,int,const void*,int, const void*); |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
1622 1623 1624 1625 1626 1627 1628 1629 | while( buf[len-1] && --len ); sqlite3GetVarint(&buf[len], &r); *rowid = r; return SQLITE_OK; } int sqlite3VdbeIdxKeyCompare( | > > > > > > | | < | | 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 | while( buf[len-1] && --len ); sqlite3GetVarint(&buf[len], &r); *rowid = r; return SQLITE_OK; } /* ** Compare the key of index entry that cursor pC is point to against ** the key string in pKey (of length nKey). Write into *pRes a number ** that is negative, zero, or positive if pC is less than, equal to, ** or greater than pKey. Return SQLITE_OK on success. */ int sqlite3VdbeIdxKeyCompare( Cursor *pC, /* The cursor to compare against */ int nKey, const u8 *pKey, /* The key to compare */ int *res /* Write the comparison result here */ ){ unsigned char *pCellKey; u64 nCellKey; int freeCellKey = 0; int rc; int len; BtCursor *pCur = pC->pCursor; |
︙ | ︙ | |||
1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 | return rc; } } len = nCellKey-2; while( pCellKey[len] && --len ); if( ignorerowid ){ nKey--; while( pKey[nKey] && --nKey ); } *res = sqlite3VdbeKeyCompare(pC, len, pCellKey, nKey, pKey); if( freeCellKey ){ sqliteFree(pCellKey); } return SQLITE_OK; } | > > | 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | return rc; } } len = nCellKey-2; while( pCellKey[len] && --len ); #if 0 if( ignorerowid ){ nKey--; while( pKey[nKey] && --nKey ); } #endif *res = sqlite3VdbeKeyCompare(pC, len, pCellKey, nKey, pKey); if( freeCellKey ){ sqliteFree(pCellKey); } return SQLITE_OK; } |
Changes to src/where.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** ** $Id: where.c,v 1.98 2004/05/19 14:56:57 drh Exp $ */ #include "sqliteInt.h" /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by an AND operator. |
︙ | ︙ | |||
805 806 807 808 809 810 811 | sqlite3VdbeAddOp(v, OP_Goto, 0, brk); /* Generate an index key from the top nColumn elements of the stack */ sqlite3VdbeAddOp(v, OP_MakeKey, nColumn, 0); sqlite3IndexAffinityStr(v, pIdx); sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0); | < < < < < < < < < | < | > | < > | | | 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 | sqlite3VdbeAddOp(v, OP_Goto, 0, brk); /* Generate an index key from the top nColumn elements of the stack */ sqlite3VdbeAddOp(v, OP_MakeKey, nColumn, 0); sqlite3IndexAffinityStr(v, pIdx); sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0); /* Generate code (1) to move to the first matching element of the table. ** Then generate code (2) that jumps to "brk" after the cursor is past ** the last matching element of the table. The code (1) is executed ** once to initialize the search, the code (2) is executed before each ** iteration of the scan to see if the scan has finished. */ if( pLevel->bRev ){ /* Scan in reverse order */ sqlite3VdbeAddOp(v, OP_MoveLe, pLevel->iCur, brk); start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); sqlite3VdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk); pLevel->op = OP_Prev; }else{ /* Scan in the forward order */ sqlite3VdbeAddOp(v, OP_MoveGe, pLevel->iCur, brk); start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); if( nColumn==pIdx->nColumn || 0 ){ sqlite3VdbeAddOp(v, OP_IdxGT, pLevel->iCur, brk); }else{ sqlite3VdbeOp3(v, OP_IdxGE, pLevel->iCur, brk, "+", P3_STATIC); } pLevel->op = OP_Next; } sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0); sqlite3VdbeAddOp(v, OP_IdxIsNull, nColumn, cont); sqlite3VdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); if( i==pTabList->nSrc-1 && pushKey ){ haveKey = 1; }else{ sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); haveKey = 0; } pLevel->p1 = pLevel->iCur; pLevel->p2 = start; }else if( i<ARRAYSIZE(iDirectLt) && (iDirectLt[i]>=0 || iDirectGt[i]>=0) ){ /* Case 3: We have an inequality comparison against the ROWID field. */ |
︙ | ︙ | |||
867 868 869 870 871 872 873 | if( aExpr[k].idxLeft==iCur ){ sqlite3ExprCode(pParse, aExpr[k].p->pRight); }else{ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); } sqlite3VdbeAddOp(v, OP_ForceInt, aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT, brk); | | | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 | if( aExpr[k].idxLeft==iCur ){ sqlite3ExprCode(pParse, aExpr[k].p->pRight); }else{ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); } sqlite3VdbeAddOp(v, OP_ForceInt, aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT, brk); sqlite3VdbeAddOp(v, OP_MoveGe, iCur, brk); aExpr[k].p = 0; }else{ sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk); } if( iDirectLt[i]>=0 ){ k = iDirectLt[i]; assert( k<nExpr ); |
︙ | ︙ | |||
1019 1020 1021 1022 1023 1024 1025 | pLevel->iMem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_NotNull, -nCol, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, nCol, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, brk); sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0); sqlite3IndexAffinityStr(v, pIdx); if( pLevel->bRev ){ | < | | < | 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 | pLevel->iMem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_NotNull, -nCol, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, nCol, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, brk); sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0); sqlite3IndexAffinityStr(v, pIdx); if( pLevel->bRev ){ int op = leFlag ? OP_MoveLe : OP_MoveLt; sqlite3VdbeAddOp(v, op, pLevel->iCur, brk); }else{ sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); } }else if( pLevel->bRev ){ sqlite3VdbeAddOp(v, OP_Last, pLevel->iCur, brk); } |
︙ | ︙ | |||
1079 1080 1081 1082 1083 1084 1085 | sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0); sqlite3IndexAffinityStr(v, pIdx); if( pLevel->bRev ){ pLevel->iMem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); testOp = OP_IdxLT; }else{ | < | | < | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 | sqlite3VdbeAddOp(v, OP_MakeKey, nCol, 0); sqlite3IndexAffinityStr(v, pIdx); if( pLevel->bRev ){ pLevel->iMem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); testOp = OP_IdxLT; }else{ int op = geFlag ? OP_MoveGe : OP_MoveGt; sqlite3VdbeAddOp(v, op, pLevel->iCur, brk); } }else if( pLevel->bRev ){ testOp = OP_Noop; }else{ sqlite3VdbeAddOp(v, OP_Rewind, pLevel->iCur, brk); } |
︙ | ︙ | |||
1108 1109 1110 1111 1112 1113 1114 | } sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0); sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont); sqlite3VdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); if( i==pTabList->nSrc-1 && pushKey ){ haveKey = 1; }else{ | | | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 | } sqlite3VdbeAddOp(v, OP_RowKey, pLevel->iCur, 0); sqlite3VdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont); sqlite3VdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); if( i==pTabList->nSrc-1 && pushKey ){ haveKey = 1; }else{ sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); haveKey = 0; } /* Record the instruction used to terminate the loop. */ pLevel->op = pLevel->bRev ? OP_Prev : OP_Next; pLevel->p1 = pLevel->iCur; |
︙ | ︙ | |||
1131 1132 1133 1134 1135 1136 1137 | if( aExpr[j].p==0 ) continue; if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue; if( pLevel->iLeftJoin && !ExprHasProperty(aExpr[j].p,EP_FromJoin) ){ continue; } if( haveKey ){ haveKey = 0; | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | if( aExpr[j].p==0 ) continue; if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue; if( pLevel->iLeftJoin && !ExprHasProperty(aExpr[j].p,EP_FromJoin) ){ continue; } if( haveKey ){ haveKey = 0; sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); } sqlite3ExprIfFalse(pParse, aExpr[j].p, cont, 1); aExpr[j].p = 0; } brk = cont; /* For a LEFT OUTER JOIN, generate code that will record the fact that |
︙ | ︙ | |||
1154 1155 1156 1157 1158 1159 1160 | if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue; if( haveKey ){ /* Cannot happen. "haveKey" can only be true if pushKey is true ** an pushKey can only be true for DELETE and UPDATE and there are ** no outer joins with DELETE and UPDATE. */ haveKey = 0; | | | 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 | if( (aExpr[j].prereqAll & loopMask)!=aExpr[j].prereqAll ) continue; if( haveKey ){ /* Cannot happen. "haveKey" can only be true if pushKey is true ** an pushKey can only be true for DELETE and UPDATE and there are ** no outer joins with DELETE and UPDATE. */ haveKey = 0; sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); } sqlite3ExprIfFalse(pParse, aExpr[j].p, cont, 1); aExpr[j].p = 0; } } } pWInfo->iContinue = cont; |
︙ | ︙ |
Changes to test/where.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the use of indices in WHERE clases. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the use of indices in WHERE clases. # # $Id: where.test,v 1.19 2004/05/19 14:56:57 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # do_test where-1.0 { |
︙ | ︙ | |||
136 137 138 139 140 141 142 143 144 145 146 147 148 149 | # do_test where-1.26 { # count {SELECT w FROM t1 WHERE x=3 AND y BETWEEN 121 AND 196} # } {10 11 12 13 9} do_test where-1.27 { count {SELECT w FROM t1 WHERE x=3 AND y+1==122} } {10 17} do_test where-1.28 { count {SELECT w FROM t1 WHERE x+1=4 AND y+1==122} } {10 99} do_test where-1.29 { count {SELECT w FROM t1 WHERE y==121} } {10 99} | > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | # do_test where-1.26 { # count {SELECT w FROM t1 WHERE x=3 AND y BETWEEN 121 AND 196} # } {10 11 12 13 9} do_test where-1.27 { count {SELECT w FROM t1 WHERE x=3 AND y+1==122} } {10 17} do_test where-1.28 { count {SELECT w FROM t1 WHERE x+1=4 AND y+1==122} } {10 99} do_test where-1.29 { count {SELECT w FROM t1 WHERE y==121} } {10 99} |
︙ | ︙ |