SQLite4
Check-in [f10991c423]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix an issue with using a bt cursor after sqlite4BtCsrDelete() has been called on it.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f10991c423496070e1b49ad805a7afe152362f41
User & Date: dan 2013-11-13 15:21:46
Context
2013-11-13
16:34
Fix a problem in the VM code generated for a CREATE INDEX statement. check-in: e42f8bb1c2 user: dan tags: trunk
15:21
Fix an issue with using a bt cursor after sqlite4BtCsrDelete() has been called on it. check-in: f10991c423 user: dan tags: trunk
2013-11-11
20:27
Add the BT_CONTROL_MULTIPROC option. check-in: 7343be21c9 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/bt_main.c.

    33     33     bt_cursor *pAllCsr;             /* List of all open cursors */
    34     34   };
    35     35   
    36     36   typedef struct BtOvfl BtOvfl;
    37     37   struct BtOvfl {
    38     38     int nKey;
    39     39     int nVal;
    40         -  u8 *pBuf;
    41         -  int nBuf;
           40  +  sqlite4_buffer buf;
    42     41   };
    43     42   
    44     43   /*
    45     44   ** Database cursor handle.
    46     45   */
    47     46   struct bt_cursor {
    48     47     bt_db *pDb;                     /* Database that owns this cursor */
    49     48     int nPg;                        /* Number of valid entries in apPage[] */
    50     49     int aiCell[BT_MAX_DEPTH];       /* Current cell of each apPage[] entry */
    51     50     BtPage *apPage[BT_MAX_DEPTH];   /* All pages from root to current leaf */
    52     51     BtOvfl ovfl;                    /* Overflow cache (see above) */
    53     52     bt_cursor *pNextCsr;            /* Next cursor opened by same db handle */
           53  +
           54  +  int bRequireReseek;
           55  +  int bSkipNext;
           56  +  int bSkipPrev;
    54     57   };
    55     58   
    56     59   #ifndef btErrorBkpt
    57     60   int btErrorBkpt(int rc){
    58     61     static int error_cnt = 0;
    59     62     error_cnt++;
    60     63     return rc;
................................................................................
   186    189   
   187    190   int sqlite4BtTransactionLevel(bt_db *db){
   188    191     return sqlite4BtPagerTransactionLevel(db->pPager);
   189    192   }
   190    193   
   191    194   static void btCsrSetup(bt_db *db, bt_cursor *pCsr){
   192    195     memset(pCsr, 0, sizeof(bt_cursor));
          196  +  sqlite4_env_config(db->pEnv, SQLITE4_ENVCONFIG_GETMM, &pCsr->ovfl.buf.pMM);
   193    197     pCsr->pDb = db;
   194    198   }
   195    199   
   196    200   int sqlite4BtCsrOpen(bt_db *db, int nExtra, bt_cursor **ppCsr){
   197    201     int rc = SQLITE4_OK;            /* Return Code */
   198    202     int nByte;                      /* Total bytes of space to allocate */
   199    203     bt_cursor *pCsr;                /* New cursor object */
................................................................................
   208    212       db->pAllCsr = pCsr;
   209    213     }
   210    214   
   211    215     btCheckPageRefs(db);
   212    216     return rc;
   213    217   }
   214    218   
   215         -static void btCsrReset(bt_cursor *pCsr, int bFreeBuffer){
          219  +static void btCsrReleaseAll(bt_cursor *pCsr){
   216    220     int i;
   217    221     for(i=0; i<pCsr->nPg; i++){
   218    222       sqlite4BtPageRelease(pCsr->apPage[i]);
   219    223     }
   220         -  if( bFreeBuffer ) sqlite4_free(pCsr->pDb->pEnv, pCsr->ovfl.pBuf);
   221    224     pCsr->nPg = 0;
   222    225   }
   223    226   
          227  +
          228  +static void btCsrReset(bt_cursor *pCsr, int bFreeBuffer){
          229  +  btCsrReleaseAll(pCsr);
          230  +  if( bFreeBuffer ){
          231  +    sqlite4_buffer_clear(&pCsr->ovfl.buf);
          232  +  }
          233  +  pCsr->bSkipNext = 0;
          234  +  pCsr->bSkipPrev = 0;
          235  +  pCsr->bRequireReseek = 0;
          236  +}
          237  +
   224    238   int sqlite4BtCsrClose(bt_cursor *pCsr){
   225    239     if( pCsr ){
   226    240       bt_db *pDb = pCsr->pDb;
   227    241       bt_cursor **pp;
   228    242       btCheckPageRefs(pDb);
   229    243       btCsrReset(pCsr, 1);
   230    244       for(pp=&pDb->pAllCsr; *pp!=pCsr; pp=&(*pp)->pNextCsr);
................................................................................
   476    490     }
   477    491   
   478    492     btCsrAscend(pCsr, nAscend);
   479    493     *piRes = res;
   480    494     return rc;
   481    495   }
   482    496   
          497  +#define BT_CSRSEEK_SEEK   0
          498  +#define BT_CSRSEEK_UPDATE 1
          499  +#define BT_CSRSEEK_RESEEK 2
          500  +
   483    501   static int btCsrSeek(
   484    502     bt_cursor *pCsr, 
   485    503     const void *pK,                 /* Key to seek for */
   486    504     int nK,                         /* Size of key pK in bytes */
   487    505     int eSeek,                      /* Seek mode (a BT_SEEK_XXX constant) */
   488         -  int bUpdate
          506  +  int eCsrseek
   489    507   ){
   490    508     const int pgsz = sqlite4BtPagerPagesize(pCsr->pDb->pPager);
   491    509     u32 pgno;                       /* Page number for next page to load */
   492    510     int rc = SQLITE4_OK;            /* Return Code */
          511  +
          512  +  assert( eSeek==BT_SEEK_EQ || eCsrseek!=BT_CSRSEEK_RESEEK );
          513  +  assert( eSeek==BT_SEEK_GE || eCsrseek!=BT_CSRSEEK_UPDATE );
   493    514   
   494    515     /* Reset the cursor */
   495    516     btCsrReset(pCsr, 0);
   496    517   
   497    518     /* Figure out the root page number */
   498    519     assert( pCsr->nPg==0 );
   499    520     pgno = sqlite4BtPagerRootpgno(pCsr->pDb->pPager);
................................................................................
   538    559         pCsr->aiCell[pCsr->nPg-1] = iHi;
   539    560         if( bLeaf==0 ){
   540    561           pgno = btChildPgno(aData, pgsz, iHi);
   541    562         }else{
   542    563           pgno = 0;
   543    564   
   544    565           if( res!=0 ){
   545         -          assert( BT_SEEK_LEFAST<0 && BT_SEEK_LE<0 );
   546         -          if( eSeek<0 ){
   547         -            rc = sqlite4BtCsrPrev(pCsr);
   548         -          }else if( eSeek==BT_SEEK_EQ ){
   549         -            rc = SQLITE4_NOTFOUND;
   550         -          }else if( iHi==nCell ){
   551         -            if( bUpdate ){
   552         -              rc = SQLITE4_NOTFOUND;
          566  +          if( eSeek==BT_SEEK_EQ ){
          567  +            if( eCsrseek==BT_CSRSEEK_RESEEK ){
          568  +              rc = SQLITE4_OK;
          569  +              if( iHi==nCell ){
          570  +                assert( pCsr->aiCell[pCsr->nPg-1]>0 );
          571  +                pCsr->aiCell[pCsr->nPg-1]--;
          572  +                pCsr->bSkipPrev = 1;
          573  +              }else{
          574  +                pCsr->bSkipNext = 1;
          575  +              }
   553    576               }else{
   554         -              rc = sqlite4BtCsrNext(pCsr);
          577  +              rc = SQLITE4_NOTFOUND;
   555    578               }
   556    579             }else{
   557         -            rc = SQLITE4_INEXACT;
          580  +            assert( BT_SEEK_LEFAST<0 && BT_SEEK_LE<0 );
          581  +            if( eSeek<0 ){
          582  +              rc = sqlite4BtCsrPrev(pCsr);
          583  +            }else{
          584  +              if( iHi==nCell ){
          585  +                if( eCsrseek==BT_CSRSEEK_UPDATE ){
          586  +                  rc = SQLITE4_NOTFOUND;
          587  +                }else{
          588  +                  rc = sqlite4BtCsrNext(pCsr);
          589  +                }
          590  +              }
          591  +            }
          592  +            if( rc==SQLITE4_OK ) rc = SQLITE4_INEXACT;
   558    593             }
   559         -          if( rc==SQLITE4_OK ) rc = SQLITE4_INEXACT;
   560    594           }
   561    595         }
   562    596       }
   563    597     }
   564    598   
   565    599     return rc;
   566    600   }
................................................................................
   569    603     bt_cursor *pCsr, 
   570    604     const void *pK,                 /* Key to seek for */
   571    605     int nK,                         /* Size of key pK in bytes */
   572    606     int eSeek                       /* Seek mode (a BT_SEEK_XXX constant) */
   573    607   ){
   574    608     int rc;
   575    609     btCheckPageRefs(pCsr->pDb);
   576         -  rc = btCsrSeek(pCsr, pK, nK, eSeek, 0);
          610  +  rc = btCsrSeek(pCsr, pK, nK, eSeek, BT_CSRSEEK_SEEK);
   577    611     btCheckPageRefs(pCsr->pDb);
   578    612     return rc;
   579    613   }
   580    614   
   581    615   /*
   582    616   ** This function seeks the cursor as required for either sqlite4BtCsrFirst()
   583    617   ** (if parameter bLast is false) or sqlite4BtCsrLast() (if bLast is true).
................................................................................
   633    667   /*
   634    668   ** Position cursor pCsr to point to the largest key in the database.
   635    669   */
   636    670   int sqlite4BtCsrLast(bt_cursor *pCsr){
   637    671     return btCsrEnd(pCsr, 1);
   638    672   }
   639    673   
          674  +static int btCsrReseek(bt_cursor *pCsr){
          675  +  int rc = SQLITE4_OK;
          676  +  if( pCsr->bRequireReseek ){
          677  +    BtOvfl ovfl;
          678  +    memcpy(&ovfl, &pCsr->ovfl, sizeof(BtOvfl));
          679  +
          680  +    pCsr->ovfl.buf.n = 0;
          681  +    pCsr->ovfl.buf.p = 0;
          682  +    pCsr->bSkipNext = 0;
          683  +    pCsr->bRequireReseek = 0;
          684  +
          685  +    rc = btCsrSeek(pCsr, ovfl.buf.p, ovfl.nKey, BT_SEEK_EQ, BT_CSRSEEK_RESEEK);
          686  +    assert( rc!=SQLITE4_INEXACT );
          687  +    if( pCsr->ovfl.buf.p==0 ){
          688  +      pCsr->ovfl.buf.p = ovfl.buf.p;
          689  +    }else{
          690  +      sqlite4_buffer_clear(&ovfl.buf);
          691  +    }
          692  +  }
          693  +  return rc;
          694  +}
          695  +
   640    696   
   641    697   /*
   642    698   ** This function does the work of both sqlite4BtCsrNext() (if parameter
   643    699   ** bNext is true) and Pref() (if bNext is false).
   644    700   */
   645    701   static int btCsrStep(bt_cursor *pCsr, int bNext){
   646    702     const int pgsz = sqlite4BtPagerPagesize(pCsr->pDb->pPager);
   647    703     int rc = SQLITE4_OK;
   648    704     int bRequireDescent = 0;
   649    705   
          706  +  rc = btCsrReseek(pCsr);
          707  +  if( (pCsr->bSkipNext && bNext) || (pCsr->bSkipPrev && bNext==0) ){
          708  +    pCsr->bSkipPrev = pCsr->bSkipNext = 0;
          709  +    return rc;
          710  +  }
          711  +  pCsr->bSkipPrev = pCsr->bSkipNext = 0;
          712  +
   650    713     while( rc==SQLITE4_OK ){
   651    714       int iPg = pCsr->nPg-1;
   652    715       int iCell = pCsr->aiCell[iPg];
   653    716   
   654    717       if( bNext ){
   655    718         u8 *aData = (u8*)sqlite4BtPageData(pCsr->apPage[iPg]);
   656    719         int nCell = btCellCount(aData, pgsz);
................................................................................
   709    772   /*
   710    773   ** Retreat to the previous entry in the tree.
   711    774   */
   712    775   int sqlite4BtCsrPrev(bt_cursor *pCsr){
   713    776     return btCsrStep(pCsr, 0);
   714    777   }
   715    778   
   716         -static int btGrowBuffer(bt_db *db, int nReq, u8 **ppVal, int *pnVal){
   717         -  if( nReq>*pnVal ){
   718         -    u8 *pNew = sqlite4_malloc(db->pEnv, nReq*2);
   719         -    if( pNew==0 ) return btErrorBkpt(SQLITE4_NOMEM);
   720         -    sqlite4_free(db->pEnv, *ppVal);
   721         -    *ppVal = pNew;
   722         -    *pnVal = nReq*2;
   723         -  }
   724         -  return SQLITE4_OK;
   725         -}
   726         -
   727    779   static int btOverflowArrayRead(
   728    780     bt_db *db,
   729    781     u8 *pOvfl,
   730    782     u8 *aOut,
   731    783     int nOut
   732    784   ){
   733    785     const int pgsz = sqlite4BtPagerPagesize(db->pPager);
................................................................................
   824    876       }
   825    877     }
   826    878   
   827    879     return rc;
   828    880   }
   829    881   
   830    882   /*
   831         -** If the current cell is a type (c) leaf cell, load the entire key
   832         -** into the pCsr->ovfl buffer. If bVal is true, then also load the
   833         -** entries value into the buffer.
          883  +** Buffer the key and value belonging to the current cursor position
          884  +** in pCsr->ovfl.
   834    885   */
   835         -static int btOverflowBuffer(bt_cursor *pCsr, int bVal){
          886  +static int btCsrBuffer(bt_cursor *pCsr, int bVal){
   836    887     const int pgsz = sqlite4BtPagerPagesize(pCsr->pDb->pPager);
   837         -  int rc = SQLITE4_OK;
   838         -  u8 *aData;
   839         -  u8 *pCell;
   840         -  int iCell = pCsr->aiCell[pCsr->nPg-1];
   841         -
   842         -  int nK;
   843         -  int nReq;
   844         -  u8 *pLocal;                     /* Pointer to local data within leaf page */
   845         -  u8 *aOut;                       /* Output buffer for overflow data */
   846         -  int nLocal = 0;
   847         -  int nOvfl1 = 0;
   848         -  int nOvfl2 = 0;
          888  +  int rc = SQLITE4_OK;            /* Return code */
          889  +  u8 *aData;                      /* Page data */
          890  +  u8 *pCell;                      /* Pointer to cell within aData[] */
          891  +  int nReq;                       /* Total required space */
          892  +  u8 *aOut;                       /* Output buffer */
          893  +  u8 *pKLocal = 0;                /* Pointer to local part of key */
          894  +  u8 *pVLocal = 0;                /* Pointer to local part of value (if any) */
          895  +  int nKLocal = 0;                /* Bytes of key on page */
          896  +  int nVLocal = 0;                /* Bytes of value on page */
          897  +  int nKOvfl = 0;                 /* Bytes of key on overflow pages */
          898  +  int nVOvfl = 0;                 /* Bytes of value on overflow pages */
   849    899   
   850    900     aData = (u8*)sqlite4BtPageData(pCsr->apPage[pCsr->nPg-1]);
   851         -  pCell = btCellFind(aData, pgsz, iCell);
   852         -  pCell += sqlite4BtVarintGet32(pCell, &nK);
   853         -  if( nK==0 ){
   854         -    /* type (c) leaf cell */
   855         -    pCell += sqlite4BtVarintGet32(pCell, &nLocal);
   856         -    pLocal = pCell;
   857         -    pCell += nLocal;
   858         -    pCell += sqlite4BtVarintGet32(pCell, &nOvfl1);
   859         -    pCell += sqlite4BtVarintGet32(pCell, &nOvfl2);
   860         -
   861         -    pCsr->ovfl.nKey = nLocal + nOvfl1;
   862         -    pCsr->ovfl.nVal = nOvfl2;
   863         -  }else{
   864         -    /* type (b) leaf cell */
   865         -    pCell += nK;
   866         -    assert( pCell[0]==0x00 );
   867         -    pCell++;
   868         -
   869         -    pCell += sqlite4BtVarintGet32(pCell, &nLocal);
   870         -    pLocal = pCell;
   871         -    pCell += nLocal;
   872         -    pCell += sqlite4BtVarintGet32(pCell, &nOvfl1);
   873         -
   874         -    pCsr->ovfl.nKey = 0;
   875         -    pCsr->ovfl.nVal = nLocal + nOvfl1;
   876         -  }
   877         -
   878         -  nReq = nLocal + nOvfl1 + nOvfl2;
   879         -  rc = btGrowBuffer(pCsr->pDb, nReq, &pCsr->ovfl.pBuf, &pCsr->ovfl.nBuf);
          901  +  pCell = btCellFind(aData, pgsz, pCsr->aiCell[pCsr->nPg-1]);
          902  +  pCell += sqlite4BtVarintGet32(pCell, &nKLocal);
          903  +  if( nKLocal==0 ){
          904  +    /* Type (c) leaf cell. */
          905  +    pCell += sqlite4BtVarintGet32(pCell, &nKLocal);
          906  +    pKLocal = pCell;
          907  +    pCell += nKLocal;
          908  +    pCell += sqlite4BtVarintGet32(pCell, &nKOvfl);
          909  +    pCell += sqlite4BtVarintGet32(pCell, &nVOvfl);
          910  +
          911  +  }else{
          912  +    pKLocal = pCell;
          913  +    pCell += nKLocal;
          914  +    pCell += sqlite4BtVarintGet32(pCell, &nVLocal);
          915  +    if( nVLocal==0 ){
          916  +      /* Type (b) */
          917  +      pCell += sqlite4BtVarintGet32(pCell, &nVLocal);
          918  +      pVLocal = pCell;
          919  +      pCell += nVLocal;
          920  +      pCell += sqlite4BtVarintGet32(pCell, &nVOvfl);
          921  +    }else{
          922  +      /* Type (a) */
          923  +      pVLocal = pCell;
          924  +    }
          925  +  }
          926  +
          927  +  pCsr->ovfl.nKey = nKLocal + nKOvfl;
          928  +  pCsr->ovfl.nVal = nVLocal + nVOvfl;
          929  +
          930  +  nReq = pCsr->ovfl.nKey + pCsr->ovfl.nVal;
          931  +  rc = sqlite4_buffer_resize(&pCsr->ovfl.buf, nReq);
   880    932     if( rc!=SQLITE4_OK ) return rc;
   881    933   
   882    934     /* Copy in local data */
   883         -  memcpy(pCsr->ovfl.pBuf, pLocal, nLocal);
          935  +  aOut = (u8*)pCsr->ovfl.buf.p;
          936  +  memcpy(aOut, pKLocal, nKLocal);
          937  +  memcpy(&aOut[nKLocal], pVLocal, nVLocal);
   884    938   
   885    939     /* Load in overflow data */
   886         -  aOut = &pCsr->ovfl.pBuf[nLocal];
   887         -  rc = btOverflowArrayRead(pCsr->pDb, pCell, aOut, nOvfl1 + nOvfl2);
          940  +  if( nKOvfl || nVOvfl ){
          941  +    rc = btOverflowArrayRead(
          942  +        pCsr->pDb, pCell, &aOut[nKLocal + nVLocal], nKOvfl + nVOvfl
          943  +    );
          944  +  }
   888    945   
   889    946     return rc;
   890    947   }
          948  +
   891    949   
   892    950   /*
   893    951   ** Helper function for btOverflowDelete(). 
   894    952   **
   895    953   ** TODO: This uses recursion. Which is almost certainly not a problem 
   896    954   ** here, but makes some people nervous, so should probably be changed.
   897    955   */
................................................................................
   999   1057     aData = (u8*)sqlite4BtPageData(pCsr->apPage[pCsr->nPg-1]);
  1000   1058     assert( btCellCount(aData, pgsz)>iCell );
  1001   1059     pCell = btCellFind(aData, pgsz, iCell);
  1002   1060     pCell += sqlite4BtVarintGet32(pCell, &nK);
  1003   1061   
  1004   1062     if( nK==0 ){
  1005   1063       /* type (c) leaf cell */
  1006         -    rc = btOverflowBuffer(pCsr, 0);
         1064  +    rc = btCsrBuffer(pCsr, 0);
  1007   1065       if( rc==SQLITE4_OK ){
  1008         -      *ppK = pCsr->ovfl.pBuf;
         1066  +      *ppK = pCsr->ovfl.buf.p;
  1009   1067         *pnK = pCsr->ovfl.nKey;
  1010   1068       }
  1011   1069     }else{
  1012   1070       *ppK = pCell;
  1013   1071       *pnK = nK;
  1014   1072     }
  1015   1073   
................................................................................
  1036   1094     pCell += sqlite4BtVarintGet32(pCell, &nK);
  1037   1095     if( nK>0 ){
  1038   1096       pCell += nK;
  1039   1097       pCell += sqlite4BtVarintGet32(pCell, &nV);
  1040   1098     }
  1041   1099   
  1042   1100     if( nV==0 ){
  1043         -    rc = btOverflowBuffer(pCsr, 1);
         1101  +    rc = btCsrBuffer(pCsr, 1);
  1044   1102       if( rc==SQLITE4_OK ){
  1045         -      *ppV = &pCsr->ovfl.pBuf[pCsr->ovfl.nKey];
         1103  +      u8 *aBuf = (u8*)pCsr->ovfl.buf.p;
         1104  +      *ppV = &aBuf[pCsr->ovfl.nKey];
  1046   1105         *pnV = pCsr->ovfl.nVal;
  1047   1106       }
  1048   1107     }else{
  1049   1108       *ppV = pCell;
  1050   1109       *pnV = (nV-1);
  1051   1110     }
  1052   1111   
................................................................................
  2297   2356     int rc = SQLITE4_OK;
  2298   2357     bt_cursor csr;
  2299   2358   
  2300   2359     sqlite4BtDebugKV((BtLock*)db->pPager, "replace", (u8*)pK, nK, (u8*)pV, nV);
  2301   2360   
  2302   2361     btCheckPageRefs(db);
  2303   2362     btCsrSetup(db, &csr);
  2304         -  rc = btCsrSeek(&csr, pK, nK, BT_SEEK_GE, 1);
         2363  +  rc = btCsrSeek(&csr, pK, nK, BT_SEEK_GE, BT_CSRSEEK_UPDATE);
  2305   2364     if( rc==SQLITE4_OK ){
  2306   2365       /* The cursor currently points to an entry with key pK/nK. This call
  2307   2366       ** should therefore replace that entry. So delete it and then re-seek
  2308   2367       ** the cursor.  */
  2309   2368       rc = sqlite4BtDelete(&csr);
  2310   2369   
  2311   2370       if( rc==SQLITE4_OK && nV>=0 ){
  2312         -      rc = btCsrSeek(&csr, pK, nK, BT_SEEK_GE, 1);
         2371  +      rc = btCsrSeek(&csr, pK, nK, BT_SEEK_GE, BT_CSRSEEK_UPDATE);
  2313   2372         if( rc==SQLITE4_OK ) rc = btErrorBkpt(SQLITE4_CORRUPT);
  2314   2373       }
  2315   2374     }
  2316   2375   
  2317   2376     if( nV>=0 && (rc==SQLITE4_NOTFOUND || rc==SQLITE4_INEXACT) ){
  2318   2377       /* Insert the new KV pair into the current leaf. */
  2319   2378       KeyValue kv;
................................................................................
  2332   2391     }
  2333   2392     btCsrReset(&csr, 1);
  2334   2393   
  2335   2394     btCheckPageRefs(db);
  2336   2395     return rc;
  2337   2396   }
  2338   2397   
         2398  +static int btSaveAllCursor(bt_cursor *pCsr){
         2399  +  int rc = SQLITE4_OK;            /* Return code */
         2400  +  bt_db *pDb = pCsr->pDb;         /* Database handle */
         2401  +  bt_cursor *p;                   /* Used to iterate through cursors */
         2402  +
         2403  +  for(p=pDb->pAllCsr; rc==SQLITE4_OK && p; p=p->pNextCsr){
         2404  +    rc = btCsrBuffer(p, 0);
         2405  +    if( rc==SQLITE4_OK ){
         2406  +      assert( p->ovfl.buf.p );
         2407  +      p->bRequireReseek = 1;
         2408  +      if( p!=pCsr ) btCsrReleaseAll(p);
         2409  +    }
         2410  +  }
         2411  +
         2412  +  return rc;
         2413  +}
         2414  +
         2415  +
         2416  +/*
         2417  +** Delete the entry that the cursor currently points to.
         2418  +*/
  2339   2419   int sqlite4BtDelete(bt_cursor *pCsr){
  2340   2420     int rc;
  2341         -  rc = btOverflowDelete(pCsr);
         2421  +  rc = btSaveAllCursor(pCsr);
         2422  +  if( rc==SQLITE4_OK ){
         2423  +    rc = btOverflowDelete(pCsr);
         2424  +  }
  2342   2425     if( rc==SQLITE4_OK ){
  2343   2426       rc =  btDeleteFromPage(pCsr, 1);
  2344   2427     }
  2345   2428     if( rc==SQLITE4_OK ){
  2346   2429       rc = btBalanceIfUnderfull(pCsr);
  2347   2430     }
         2431  +
         2432  +  btCsrReleaseAll(pCsr);
  2348   2433     return rc;
  2349   2434   }
  2350   2435   
  2351   2436   int sqlite4BtSetCookie(bt_db *db, unsigned int iVal){
  2352   2437     return sqlite4BtPagerSetCookie(db->pPager, iVal);
  2353   2438   }
  2354   2439   

Changes to test/permutations.test.

   121    121   # Start of tests
   122    122   #
   123    123   
   124    124   #-------------------------------------------------------------------------
   125    125   # Define the generic test suites:
   126    126   #
   127    127   #   src4
          128  +#   bt
   128    129   #   veryquick
   129    130   #   quick
   130    131   #   full
   131    132   #
   132    133   lappend ::testsuitelist xxx
          134  +
          135  +test_suite "bt" -prefix "" -description {
          136  +} -files {
          137  +  select1.test select2.test
          138  +} -initialize {
          139  +  kv_default bt
          140  +}
   133    141   
   134    142   test_suite "src4" -prefix "" -description {
   135    143   } -files {
   136    144     simple.test simple2.test
   137    145     lsm1.test lsm2.test lsm3.test lsm4.test lsm5.test
   138    146     csr1.test
   139    147     ckpt1.test

Changes to test/test_kv2.c.

   397    397     );
   398    398     if( rc==TCL_OK ){
   399    399       rc = aSub[iSub].xCmd(interp, objc, (Tcl_Obj **)objv); 
   400    400     }
   401    401   
   402    402     return rc;
   403    403   }
          404  +
          405  +/*
          406  +** TCLCMD:    kv_default DEFAULT
          407  +*/
          408  +static int kv_default_cmd(
          409  +  void * clientData,
          410  +  Tcl_Interp *interp,
          411  +  int objc,
          412  +  Tcl_Obj *CONST objv[]
          413  +){
          414  +  sqlite4_kvfactory factory = 0;
          415  +  const char *zDflt;
          416  +
          417  +  if( objc!=2 ){
          418  +    Tcl_WrongNumArgs(interp, 1, objv, "DEFAULT");
          419  +    return TCL_ERROR;
          420  +  }
          421  +
          422  +  zDflt = Tcl_GetString(objv[1]);
          423  +
          424  +  sqlite4_env_config(0, SQLITE4_ENVCONFIG_KVSTORE_GET, zDflt, &factory);
          425  +  if( factory==0 ){
          426  +    Tcl_ResetResult(interp);
          427  +    Tcl_AppendResult(interp, "no such factory: ", zDflt, 0);
          428  +    return TCL_ERROR;
          429  +  }
          430  +  sqlite4_env_config(0, SQLITE4_ENVCONFIG_KVSTORE_PUSH, "main", factory);
          431  +  return TCL_OK;
          432  +}
   404    433   
   405    434   /*
   406    435   ** Register the TCL commands defined above with the TCL interpreter.
   407    436   **
   408    437   ** This routine should be the only externally visible symbol in this
   409    438   ** source code file.
   410    439   */
   411    440   int Sqliteteststorage2_Init(Tcl_Interp *interp){
   412    441     Tcl_CreateObjCommand(interp, "kvwrap", kvwrap_command, 0, 0);
          442  +  Tcl_CreateObjCommand(interp, "kv_default", kv_default_cmd, 0, 0);
   413    443     return TCL_OK;
   414    444   }

Changes to test/tester.tcl.

   866    866     puts "----  ------------  ------  ------  ------  ---------------  --  -"
   867    867     $db eval "explain $sql" {} {
   868    868       puts [format {%-4d  %-12.12s  %-6d  %-6d  %-6d  % -17s %s  %s} \
   869    869         $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment
   870    870       ]
   871    871     }
   872    872   }
          873  +
          874  +proc explain_i {sql {db db}} {
          875  +  puts ""
          876  +  puts "addr  opcode        p1      p2      p3      p4                p5  #"
          877  +  puts "----  ------------  ------  ------  ------  ----------------  --  -"
          878  +
          879  +
          880  +  # Set up colors for the different opcodes. Scheme is as follows:
          881  +  #
          882  +  #   Red:   Opcodes that write to a b-tree.
          883  +  #   Blue:  Opcodes that reposition or seek a cursor. 
          884  +  #   Green: The ResultRow opcode.
          885  +  #
          886  +  set R "\033\[31;1m"        ;# Red fg
          887  +  set G "\033\[32;1m"        ;# Green fg
          888  +  set B "\033\[34;1m"        ;# Red fg
          889  +  set D "\033\[39;0m"        ;# Default fg
          890  +  foreach opcode {
          891  +      Seek SeekGe SeekGt SeekLe SeekLt NotFound Last Rewind
          892  +      NoConflict Next Prev VNext VPrev VFilter
          893  +  } {
          894  +    set color($opcode) $B
          895  +  }
          896  +  foreach opcode {ResultRow} {
          897  +    set color($opcode) $G
          898  +  }
          899  +  foreach opcode {IdxInsert Insert Delete IdxDelete} {
          900  +    set color($opcode) $R
          901  +  }
          902  +
          903  +  set bSeenGoto 0
          904  +  $db eval "explain $sql" {} {
          905  +    set x($addr) 0
          906  +    set op($addr) $opcode
          907  +
          908  +    if {$opcode == "Goto" && ($bSeenGoto==0 || ($p2 > $addr+10))} {
          909  +      set linebreak($p2) 1
          910  +      set bSeenGoto 1
          911  +    }
          912  +
          913  +    if {$opcode=="Next"  || $opcode=="Prev" 
          914  +     || $opcode=="VNext" || $opcode=="VPrev"
          915  +    } {
          916  +      for {set i $p2} {$i<$addr} {incr i} {
          917  +        incr x($i) 2
          918  +      }
          919  +    }
          920  +
          921  +    if {$opcode == "Goto" && $p2<$addr && $op($p2)=="Yield"} {
          922  +      for {set i [expr $p2+1]} {$i<$addr} {incr i} {
          923  +        incr x($i) 2
          924  +      }
          925  +    }
          926  +
          927  +    if {$opcode == "Halt" && $comment == "End of coroutine"} {
          928  +      set linebreak([expr $addr+1]) 1
          929  +    }
          930  +  }
          931  +
          932  +  $db eval "explain $sql" {} {
          933  +    if {[info exists linebreak($addr)]} {
          934  +      puts ""
          935  +    }
          936  +    set I [string repeat " " $x($addr)]
          937  +
          938  +    set col ""
          939  +    catch { set col $color($opcode) }
          940  +
          941  +    puts [format {%-4d  %s%s%-12.12s%s  %-6d  %-6d  %-6d  % -17s %s  %s} \
          942  +      $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment
          943  +    ]
          944  +  }
          945  +  puts "----  ------------  ------  ------  ------  ----------------  --  -"
          946  +}
   873    947   
   874    948   # Show the VDBE program for an SQL statement but omit the Trace
   875    949   # opcode at the beginning.  This procedure can be used to prove
   876    950   # that different SQL statements generate exactly the same VDBE code.
   877    951   #
   878    952   proc explain_no_trace {sql} {
   879    953     set tr [db eval "EXPLAIN $sql"]