Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Speed up in the handling of VDBE cursors. (CVS 1578) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
e42316f5708de6f639b7b54e08d4be73 |
User & Date: | drh 2004-06-12 20:12:51.000 |
Context
2004-06-12
| ||
20:42 | The VDBE aggregate functions use an in-memory btree instead of a disk-based btree for improved performance. (CVS 1579) (check-in: 8029f1e465 user: drh tags: trunk) | |
20:12 | Speed up in the handling of VDBE cursors. (CVS 1578) (check-in: e42316f570 user: drh tags: trunk) | |
18:12 | Improve the speed of OP_Column through better caching. (CVS 1577) (check-in: f687977a28 user: drh tags: trunk) | |
Changes
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 | ** ** 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.370 2004/06/12 20:12:51 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
267 268 269 270 271 272 273 | }else if( pRight ){ pTail->pNext = pRight; } return sHead.pNext; } /* | < < | | < < | > | > | | | > > | | < > > > > | | 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | }else if( pRight ){ pTail->pNext = pRight; } return sHead.pNext; } /* ** Allocate cursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ static Cursor *allocateCursor(Vdbe *p, int iCur){ Cursor *pCx; if( iCur>=p->nCursor ){ int i; p->apCsr = sqliteRealloc( p->apCsr, (iCur+1)*sizeof(Cursor*) ); if( p->apCsr==0 ){ p->nCursor = 0; return 0; } for(i=p->nCursor; i<iCur; i++){ p->apCsr[i] = 0; } p->nCursor = iCur+1; }else if( p->apCsr[iCur] ){ sqlite3VdbeFreeCursor(p->apCsr[iCur]); } p->apCsr[iCur] = pCx = sqliteMalloc( sizeof(Cursor) ); return pCx; } /* ** Apply any conversion required by the supplied column affinity to ** memory cell pRec. affinity may be one of: ** ** SQLITE_AFF_NUMERIC |
︙ | ︙ | |||
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 | ** Before the OP_Column opcode can be executed on a cursor, this ** opcode must be called to set the number of fields in the table. ** ** This opcode sets the number of columns for cursor P1 to P2. */ case OP_SetNumColumns: { assert( (pOp->p1)<p->nCursor ); p->apCsr[pOp->p1]->nField = pOp->p2; break; } /* Opcode: IdxColumn P1 * * ** ** P1 is a cursor opened on an index. Push the first field from the | > | 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 | ** Before the OP_Column opcode can be executed on a cursor, this ** opcode must be called to set the number of fields in the table. ** ** This opcode sets the number of columns for cursor P1 to P2. */ case OP_SetNumColumns: { assert( (pOp->p1)<p->nCursor ); assert( p->apCsr[pOp->p1]!=0 ); p->apCsr[pOp->p1]->nField = pOp->p2; break; } /* Opcode: IdxColumn P1 * * ** ** P1 is a cursor opened on an index. Push the first field from the |
︙ | ︙ | |||
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 | ** zRec is set to NULL. ** ** We also compute the number of columns in the record. For cursors, ** the number of columns is stored in the Cursor.nField element. For ** records on the stack, the next entry down on the stack is an integer ** which is the number of records. */ if( p1<0 ){ /* Take the record off of the stack */ Mem *pRec = &pTos[p1]; Mem *pCnt = &pRec[-1]; assert( pRec>=p->aStack ); assert( pRec->flags & MEM_Blob ); payloadSize = pRec->n; | > | 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 | ** zRec is set to NULL. ** ** We also compute the number of columns in the record. For cursors, ** the number of columns is stored in the Cursor.nField element. For ** records on the stack, the next entry down on the stack is an integer ** which is the number of records. */ assert( p1<0 || p->apCsr[p1]!=0 ); if( p1<0 ){ /* Take the record off of the stack */ Mem *pRec = &pTos[p1]; Mem *pCnt = &pRec[-1]; assert( pRec>=p->aStack ); assert( pRec->flags & MEM_Blob ); payloadSize = pRec->n; |
︙ | ︙ | |||
2568 2569 2570 2571 2572 2573 2574 | if( p2<2 ){ sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0); rc = SQLITE_INTERNAL; break; } } assert( i>=0 ); | < | | | 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 | if( p2<2 ){ sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0); rc = SQLITE_INTERNAL; break; } } assert( i>=0 ); pCur = allocateCursor(p, i); if( pCur==0 ) goto no_mem; pCur->nullRow = 1; if( pX==0 ) break; /* We always provide a key comparison function. If the table being ** opened is of type INTKEY, the comparision function will be ignored. */ rc = sqlite3BtreeCursor(pX, p2, wrFlag, sqlite3VdbeRecordCompare, pOp->p3, &pCur->pCursor); |
︙ | ︙ | |||
2631 2632 2633 2634 2635 2636 2637 | ** whereas "Temporary" in the context of CREATE TABLE means for the duration ** of the connection to the database. Same word; different meanings. */ case OP_OpenTemp: { int i = pOp->p1; Cursor *pCx; assert( i>=0 ); | > | < < < | 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 | ** whereas "Temporary" in the context of CREATE TABLE means for the duration ** of the connection to the database. Same word; different meanings. */ case OP_OpenTemp: { int i = pOp->p1; Cursor *pCx; assert( i>=0 ); pCx = allocateCursor(p, i); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; rc = sqlite3BtreeFactory(db, 0, 1, TEMP_PAGES, &pCx->pBt); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginTrans(pCx->pBt, 1, 0); } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 | ** A pseudo-table created by this opcode is useful for holding the ** NEW or OLD tables in a trigger. */ case OP_OpenPseudo: { int i = pOp->p1; Cursor *pCx; assert( i>=0 ); | > | < < < | > | 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 | ** A pseudo-table created by this opcode is useful for holding the ** NEW or OLD tables in a trigger. */ case OP_OpenPseudo: { int i = pOp->p1; Cursor *pCx; assert( i>=0 ); pCx = allocateCursor(p, i); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->pseudoTable = 1; pCx->pIncrKey = &pCx->bogusIncrKey; break; } /* Opcode: Close P1 * * ** ** Close a cursor previously opened as P1. If P1 is not ** currently open, this instruction is a no-op. */ case OP_Close: { int i = pOp->p1; if( i>=0 && i<p->nCursor ){ sqlite3VdbeFreeCursor(p->apCsr[i]); p->apCsr[i] = 0; } break; } /* Opcode: MoveGe P1 P2 * ** ** Pop the top of the stack and use its value as a key. Reposition |
︙ | ︙ | |||
2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 | 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->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe; if( pC->intKey ){ i64 iKey; | > | 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 | case OP_MoveGt: { int i = pOp->p1; Cursor *pC; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); if( pC->pCursor!=0 ){ int res, oc; oc = pOp->opcode; pC->nullRow = 0; *pC->pIncrKey = oc==OP_MoveGt || oc==OP_MoveLe; if( pC->intKey ){ i64 iKey; |
︙ | ︙ | |||
2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 | case OP_NotFound: case OP_Found: { int i = pOp->p1; int alreadyExists = 0; Cursor *pC; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); if( (pC = p->apCsr[i])->pCursor!=0 ){ int res, rx; assert( pC->intKey==0 ); Stringify(pTos, db->enc); rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); alreadyExists = rx==SQLITE_OK && res==0; pC->deferredMoveto = 0; | > | 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 | case OP_NotFound: case OP_Found: { int i = pOp->p1; int alreadyExists = 0; Cursor *pC; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( (pC = p->apCsr[i])->pCursor!=0 ){ int res, rx; assert( pC->intKey==0 ); Stringify(pTos, db->enc); rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); alreadyExists = rx==SQLITE_OK && res==0; pC->deferredMoveto = 0; |
︙ | ︙ | |||
2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 | */ assert( pNos>=p->aStack ); Integerify(pTos, db->enc); R = pTos->i; pTos--; assert( i>=0 && i<=p->nCursor ); pCx = p->apCsr[i]; pCrsr = pCx->pCursor; if( pCrsr!=0 ){ int res, rc; i64 v; /* The record number on the P1 entry that matches K */ char *zKey; /* The value of K */ int nKey; /* Number of bytes in K */ int len; /* Number of bytes in K without the rowid at the end */ | > | 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 | */ assert( pNos>=p->aStack ); Integerify(pTos, db->enc); R = pTos->i; pTos--; assert( i>=0 && i<=p->nCursor ); pCx = p->apCsr[i]; assert( pCx!=0 ); pCrsr = pCx->pCursor; if( pCrsr!=0 ){ int res, rc; i64 v; /* The record number on the P1 entry that matches K */ char *zKey; /* The value of K */ int nKey; /* Number of bytes in K */ int len; /* Number of bytes in K without the rowid at the end */ |
︙ | ︙ | |||
2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 | */ case OP_NotExists: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rx; u64 iKey; assert( pTos->flags & MEM_Int ); assert( p->apCsr[i]->intKey ); iKey = intToKey(pTos->i); rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); | > | 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 | */ case OP_NotExists: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rx; u64 iKey; assert( pTos->flags & MEM_Int ); assert( p->apCsr[i]->intKey ); iKey = intToKey(pTos->i); rx = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res); |
︙ | ︙ | |||
3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 | ** onto the stack. */ case OP_NewRecno: { int i = pOp->p1; i64 v = 0; Cursor *pC; assert( i>=0 && i<p->nCursor ); if( (pC = p->apCsr[i])->pCursor==0 ){ /* The zero initialization above is all that is needed */ }else{ /* The next rowid or record number (different terms for the same ** thing) is obtained in a two-step algorithm. ** ** First we attempt to find the largest existing rowid and add one | > | 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 | ** onto the stack. */ case OP_NewRecno: { int i = pOp->p1; i64 v = 0; Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( (pC = p->apCsr[i])->pCursor==0 ){ /* The zero initialization above is all that is needed */ }else{ /* The next rowid or record number (different terms for the same ** thing) is obtained in a two-step algorithm. ** ** First we attempt to find the largest existing rowid and add one |
︙ | ︙ | |||
3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 | case OP_PutIntKey: case OP_PutStrKey: { Mem *pNos = &pTos[-1]; int i = pOp->p1; Cursor *pC; assert( pNos>=p->aStack ); assert( i>=0 && i<p->nCursor ); if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){ char *zKey; i64 nKey; i64 iKey; if( pOp->opcode==OP_PutStrKey ){ Stringify(pNos, db->enc); nKey = pNos->n; | > | 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 | case OP_PutIntKey: case OP_PutStrKey: { Mem *pNos = &pTos[-1]; int i = pOp->p1; Cursor *pC; assert( pNos>=p->aStack ); assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( ((pC = p->apCsr[i])->pCursor!=0 || pC->pseudoTable) ){ char *zKey; i64 nKey; i64 iKey; if( pOp->opcode==OP_PutStrKey ){ Stringify(pNos, db->enc); nKey = pNos->n; |
︙ | ︙ | |||
3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 | ** If P1 is a pseudo-table, then this instruction is a no-op. */ case OP_Delete: { int i = pOp->p1; Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; if( pC->pCursor!=0 ){ sqlite3VdbeCursorMoveto(pC); rc = sqlite3BtreeDelete(pC->pCursor); pC->nextRowidValid = 0; pC->cacheValid = 0; } if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; | > | 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 | ** If P1 is a pseudo-table, then this instruction is a no-op. */ case OP_Delete: { int i = pOp->p1; Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); if( pC->pCursor!=0 ){ sqlite3VdbeCursorMoveto(pC); rc = sqlite3BtreeDelete(pC->pCursor); pC->nextRowidValid = 0; pC->cacheValid = 0; } if( pOp->p2 & OPFLAG_NCHANGE ) db->nChange++; |
︙ | ︙ | |||
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 | ** processing compound selects. */ case OP_KeyAsData: { int i = pOp->p1; Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; pC->keyAsData = pOp->p2; break; } /* Opcode: RowData P1 * * ** ** Push onto the stack the complete row data for cursor P1. | > | 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 | ** processing compound selects. */ case OP_KeyAsData: { int i = pOp->p1; Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); pC->keyAsData = pOp->p2; break; } /* Opcode: RowData P1 * * ** ** Push onto the stack the complete row data for cursor P1. |
︙ | ︙ | |||
3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 | int i = pOp->p1; Cursor *pC; int n; pTos++; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; if( pC->nullRow ){ pTos->flags = MEM_Null; }else if( pC->pCursor!=0 ){ BtCursor *pCrsr = pC->pCursor; sqlite3VdbeCursorMoveto(pC); if( pC->nullRow ){ pTos->flags = MEM_Null; | > | 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 | int i = pOp->p1; Cursor *pC; int n; pTos++; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); if( pC->nullRow ){ pTos->flags = MEM_Null; }else if( pC->pCursor!=0 ){ BtCursor *pCrsr = pC->pCursor; sqlite3VdbeCursorMoveto(pC); if( pC->nullRow ){ pTos->flags = MEM_Null; |
︙ | ︙ | |||
3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 | case OP_Recno: { int i = pOp->p1; Cursor *pC; i64 v; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; sqlite3VdbeCursorMoveto(pC); pTos++; if( pC->recnoIsValid ){ v = pC->lastRecno; }else if( pC->pseudoTable ){ v = keyToInt(pC->iKey); }else if( pC->nullRow || pC->pCursor==0 ){ | > | 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 | case OP_Recno: { int i = pOp->p1; Cursor *pC; i64 v; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); sqlite3VdbeCursorMoveto(pC); pTos++; if( pC->recnoIsValid ){ v = pC->lastRecno; }else if( pC->pseudoTable ){ v = keyToInt(pC->iKey); }else if( pC->nullRow || pC->pCursor==0 ){ |
︙ | ︙ | |||
3401 3402 3403 3404 3405 3406 3407 3408 3409 | ** This opcode may not be used on a pseudo-table. */ case OP_FullKey: { int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( p->apCsr[i]->keyAsData ); assert( !p->apCsr[i]->pseudoTable ); | > > < | 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 | ** This opcode may not be used on a pseudo-table. */ case OP_FullKey: { int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]->keyAsData ); assert( !p->apCsr[i]->pseudoTable ); pTos++; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ u64 amt; char *z; sqlite3VdbeCursorMoveto(pC); assert( pC->intKey==0 ); |
︙ | ︙ | |||
3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 | */ case OP_NullRow: { int i = pOp->p1; Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; pC->nullRow = 1; pC->recnoIsValid = 0; break; } /* Opcode: Last P1 P2 * ** ** The next use of the Recno or Column or Next instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. */ case OP_Last: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ int res; rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = res; pC->deferredMoveto = 0; pC->cacheValid = 0; if( res && pOp->p2>0 ){ | > > | 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 | */ case OP_NullRow: { int i = pOp->p1; Cursor *pC; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); pC->nullRow = 1; pC->recnoIsValid = 0; break; } /* Opcode: Last P1 P2 * ** ** The next use of the Recno or Column or Next instruction for P1 ** will refer to the last entry in the database table or index. ** If the table or index is empty and P2>0, then jump immediately to P2. ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. */ case OP_Last: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); if( (pCrsr = pC->pCursor)!=0 ){ int res; rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = res; pC->deferredMoveto = 0; pC->cacheValid = 0; if( res && pOp->p2>0 ){ |
︙ | ︙ | |||
3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 | int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; int res; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; if( (pCrsr = pC->pCursor)!=0 ){ rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->deferredMoveto = 0; pC->cacheValid = 0; }else{ res = 1; | > | 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 | int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; int res; assert( i>=0 && i<p->nCursor ); pC = p->apCsr[i]; assert( pC!=0 ); if( (pCrsr = pC->pCursor)!=0 ){ rc = sqlite3BtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->deferredMoveto = 0; pC->cacheValid = 0; }else{ res = 1; |
︙ | ︙ | |||
3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 | case OP_Next: { Cursor *pC; BtCursor *pCrsr; CHECK_FOR_INTERRUPT; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; if( (pCrsr = pC->pCursor)!=0 ){ int res; if( pC->nullRow ){ res = 1; }else{ assert( pC->deferredMoveto==0 ); rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : | > | 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 | case OP_Next: { Cursor *pC; BtCursor *pCrsr; CHECK_FOR_INTERRUPT; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( (pCrsr = pC->pCursor)!=0 ){ int res; if( pC->nullRow ){ res = 1; }else{ assert( pC->deferredMoveto==0 ); rc = pOp->opcode==OP_Next ? sqlite3BtreeNext(pCrsr, &res) : |
︙ | ︙ | |||
3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 | */ case OP_IdxPut: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); assert( pTos->flags & MEM_Blob ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int nKey = pTos->n; const char *zKey = pTos->z; if( pOp->p2 ){ int res; int len; | > | 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 | */ case OP_IdxPut: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); assert( pTos->flags & MEM_Blob ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int nKey = pTos->n; const char *zKey = pTos->z; if( pOp->p2 ){ int res; int len; |
︙ | ︙ | |||
3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 | case OP_IdxDelete: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( pTos->flags & MEM_Blob ); assert( i>=0 && i<p->nCursor ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int rx, res; rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); if( rx==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } assert( pC->deferredMoveto==0 ); | > | 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 | case OP_IdxDelete: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; assert( pTos>=p->aStack ); assert( pTos->flags & MEM_Blob ); assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int rx, res; rx = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res); if( rx==SQLITE_OK && res==0 ){ rc = sqlite3BtreeDelete(pCrsr); } assert( pC->deferredMoveto==0 ); |
︙ | ︙ | |||
3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 | */ case OP_IdxRecno: { int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && i<p->nCursor ); pTos++; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 rowid; assert( pC->deferredMoveto==0 ); assert( pC->intKey==0 ); if( pC->nullRow ){ | > | 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 | */ case OP_IdxRecno: { int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); pTos++; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 rowid; assert( pC->deferredMoveto==0 ); assert( pC->intKey==0 ); if( pC->nullRow ){ |
︙ | ︙ | |||
3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 | 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; assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */ Stringify(pTos, db->enc); assert( pC->deferredMoveto==0 ); | > | 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 | case OP_IdxGT: case OP_IdxGE: { int i= pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); assert( pTos>=p->aStack ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rc; assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */ Stringify(pTos, db->enc); assert( pC->deferredMoveto==0 ); |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ** a row trigger. The data for the row is stored in Cursor.pData and ** the rowid is in Cursor.iKey. */ struct Cursor { BtCursor *pCursor; /* The cursor structure of the backend */ i64 lastRecno; /* Last recno from a Next or NextIdx operation */ i64 nextRowid; /* Next rowid returned by OP_NewRowid */ Bool recnoIsValid; /* True if lastRecno is valid */ Bool keyAsData; /* The OP_Column command works on key instead of data */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ Bool nextRowidValid; /* True if the nextRowid field is valid */ Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ | > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | ** a row trigger. The data for the row is stored in Cursor.pData and ** the rowid is in Cursor.iKey. */ struct Cursor { BtCursor *pCursor; /* The cursor structure of the backend */ i64 lastRecno; /* Last recno from a Next or NextIdx operation */ i64 nextRowid; /* Next rowid returned by OP_NewRowid */ Bool zeroed; /* True if zeroed out and ready for reuse */ Bool recnoIsValid; /* True if lastRecno is valid */ Bool keyAsData; /* The OP_Column command works on key instead of data */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ Bool nextRowidValid; /* True if the nextRowid field is valid */ Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ |
︙ | ︙ | |||
348 349 350 351 352 353 354 | #define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ #define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */ #define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ /* ** Function prototypes */ | | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | #define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ #define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */ #define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */ /* ** Function prototypes */ void sqlite3VdbeFreeCursor(Cursor*); void sqlite3VdbeSorterReset(Vdbe*); int sqlite3VdbeAggReset(sqlite *, Agg *, KeyInfo *); void sqlite3VdbeKeylistFree(Keylist*); void sqliteVdbePopStack(Vdbe*,int); int sqlite3VdbeCursorMoveto(Cursor*); #if !defined(NDEBUG) || defined(VDBE_PROFILE) void sqlite3VdbePrintOp(FILE*, int, Op*); |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
822 823 824 825 826 827 828 | } } /* ** Close a cursor and release all the resources that cursor happens ** to hold. */ | | > > > | | < < | 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 851 852 853 854 855 856 857 | } } /* ** Close a cursor and release all the resources that cursor happens ** to hold. */ void sqlite3VdbeFreeCursor(Cursor *pCx){ if( pCx==0 ){ return; } if( pCx->pCursor ){ sqlite3BtreeCloseCursor(pCx->pCursor); } if( pCx->pBt ){ sqlite3BtreeClose(pCx->pBt); } sqliteFree(pCx->pData); sqliteFree(pCx->aType); sqliteFree(pCx); } /* ** Close all cursors */ static void closeAllCursors(Vdbe *p){ int i; for(i=0; i<p->nCursor; i++){ sqlite3VdbeFreeCursor(p->apCsr[i]); } sqliteFree(p->apCsr); p->apCsr = 0; p->nCursor = 0; } /* |
︙ | ︙ |