SQLite

Check-in [e42316f570]
Login

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: e42316f5708de6f639b7b54e08d4be73b45367e9
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
Unified Diff Ignore Whitespace Patch
Changes to src/vdbe.c.
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.369 2004/06/12 18:12:16 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*







|







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
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
  }else if( pRight ){
    pTail->pNext = pRight;
  }
  return sHead.pNext;
}

/*
** Make sure there is space in the Vdbe structure to hold at least
** mxCursor cursors.  If there is not currently enough space, then
** allocate more.
**
** If a memory allocation error occurs, return 1.  Return 0 if
** everything works.
*/
static int expandCursorArraySize(Vdbe *p, int mxCursor){

  if( mxCursor>=p->nCursor ){

    p->apCsr = sqliteRealloc( p->apCsr, (mxCursor+1)*sizeof(Cursor*) );
    if( p->apCsr==0 ) return 1;
    while( p->nCursor<=mxCursor ){


      Cursor *pC;
      p->apCsr[p->nCursor++] = pC = sqliteMalloc( sizeof(Cursor) );
      if( pC==0 ) return 1;
    }



  }

  return 0;
}

/*
** Apply any conversion required by the supplied column affinity to
** memory cell pRec. affinity may be one of:
**
** SQLITE_AFF_NUMERIC







<
<
|
|
<
<

|
>
|
>
|
|
|
>
>
|
|
<

>
>
>

>
|







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
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
    if( p2<2 ){
      sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0);
      rc = SQLITE_INTERNAL;
      break;
    }
  }
  assert( i>=0 );
  if( expandCursorArraySize(p, i) ) goto no_mem;
  pCur = p->apCsr[i];
  sqlite3VdbeCleanupCursor(pCur);
  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);







<
|
|







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

2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
** 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 );

  if( expandCursorArraySize(p, i) ) goto no_mem;
  pCx = p->apCsr[i];
  sqlite3VdbeCleanupCursor(pCx);
  memset(pCx, 0, sizeof(*pCx));
  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 ){







>
|
<
<
<







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

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
** 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 );

  if( expandCursorArraySize(p, i) ) goto no_mem;
  pCx = p->apCsr[i];
  sqlite3VdbeCleanupCursor(pCx);
  memset(pCx, 0, sizeof(*pCx));
  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 ){
    sqlite3VdbeCleanupCursor(p->apCsr[i]);

  }
  break;
}

/* Opcode: MoveGe P1 P2 *
**
** Pop the top of the stack and use its value as a key.  Reposition







>
|
<
<
<














|
>







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
3410
3411
3412
3413
3414
3415
3416
3417
** 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 );
  assert( i>=0 && i<p->nCursor );
  pTos++;
  if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
    u64 amt;
    char *z;

    sqlite3VdbeCursorMoveto(pC);
    assert( pC->intKey==0 );







>
>


<







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
355
356
357
358
359
360
361
362
#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 sqlite3VdbeCleanupCursor(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*);







|







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
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
  }
}

/*
** Close a cursor and release all the resources that cursor happens
** to hold.
*/
void sqlite3VdbeCleanupCursor(Cursor *pCx){



  if( pCx->pCursor ){
    sqlite3BtreeCloseCursor(pCx->pCursor);
  }
  if( pCx->pBt ){
    sqlite3BtreeClose(pCx->pBt);
  }
  sqliteFree(pCx->pData);
  sqliteFree(pCx->aType);
  memset(pCx, 0, sizeof(*pCx));
}

/*
** Close all cursors
*/
static void closeAllCursors(Vdbe *p){
  int i;
  for(i=0; i<p->nCursor; i++){
    Cursor *pC = p->apCsr[i];
    sqlite3VdbeCleanupCursor(pC);
    sqliteFree(pC);
  }
  sqliteFree(p->apCsr);
  p->apCsr = 0;
  p->nCursor = 0;
}

/*







|
>
>
>








|








|
<
<







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;
}

/*