SQLite

Check-in [349f1ea789]
Login

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

Overview
Comment:Cache the location of overflow pages in cursors used for incremental blob IO. (CVS 3899)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 349f1ea7895f06c40affc985a13aa6686dfdea07
User & Date: danielk1977 2007-05-02 16:48:37.000
Context
2007-05-02
16:51
More fixes and improvements to the zeroblob() mechanism. (CVS 3900) (check-in: 83ab25014e user: drh tags: trunk)
16:48
Cache the location of overflow pages in cursors used for incremental blob IO. (CVS 3899) (check-in: 349f1ea789 user: danielk1977 tags: trunk)
15:36
Fix an invalid UTF8 encoding in the tests for the trim function. (CVS 3898) (check-in: 4dbbfff4a7 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/btree.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
** 2004 April 6
**
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.365 2007/05/02 13:16:30 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
** 2004 April 6
**
** 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.
**
*************************************************************************
** $Id: btree.c,v 1.366 2007/05/02 16:48:37 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
**     "Sorting And Searching", pages 473-480. Addison-Wesley
**     Publishing Company, Reading, Massachusetts.
390
391
392
393
394
395
396




397
398
399
400
401
402
403
  int idx;                  /* Index of the entry in pPage->aCell[] */
  CellInfo info;            /* A parse of the cell we are pointing at */
  u8 wrFlag;                /* True if writable */
  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
  void *pKey;      /* Saved key that was cursor's last known position */
  i64 nKey;        /* Size of pKey, or last integer key */
  int skip;        /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */




};

/*
** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
**   Cursor points to a valid entry. getPayload() etc. may be called.







>
>
>
>







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  int idx;                  /* Index of the entry in pPage->aCell[] */
  CellInfo info;            /* A parse of the cell we are pointing at */
  u8 wrFlag;                /* True if writable */
  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
  void *pKey;      /* Saved key that was cursor's last known position */
  i64 nKey;        /* Size of pKey, or last integer key */
  int skip;        /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#ifndef SQLITE_OMIT_INCRBLOB
  u8 cacheOverflow;         /* True to use aOverflow */
  Pgno *aOverflow;          /* Cache of overflow page locations */
#endif
};

/*
** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
**   Cursor points to a valid entry. getPayload() etc. may be called.
686
687
688
689
690
691
692






693
694
695
696
697
698
699
  assert( !pCur->pPage->intKey || !pCur->pKey );

  if( rc==SQLITE_OK ){
    releasePage(pCur->pPage);
    pCur->pPage = 0;
    pCur->eState = CURSOR_REQUIRESEEK;
  }







  return rc;
}

/*
** Save the positions of all cursors except pExcept open on the table 
** with root-page iRoot. Usually, this is called just before cursor







>
>
>
>
>
>







690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
  assert( !pCur->pPage->intKey || !pCur->pKey );

  if( rc==SQLITE_OK ){
    releasePage(pCur->pPage);
    pCur->pPage = 0;
    pCur->eState = CURSOR_REQUIRESEEK;
  }

#ifndef SQLITE_OMIT_INCRBLOB
  /* Delete the cache of overflow page numbers. */
  sqliteFree(pCur->aOverflow);
  pCur->aOverflow = 0;
#endif

  return rc;
}

/*
** Save the positions of all cursors except pExcept open on the table 
** with root-page iRoot. Usually, this is called just before cursor
2409
2410
2411
2412
2413
2414
2415

2416
2417
2418
2419
2420





2421

2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439









2440
2441
2442
2443
2444
2445
2446
**
** If the incremental vacuum is finished after this function has run,
** SQLITE_DONE is returned. If it is not finished, but no error occured,
** SQLITE_OK is returned. Otherwise an SQLite error code. 
*/
int sqlite3BtreeIncrVacuum(Btree *p){
  BtShared *pBt = p->pBt;


  assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
  if( !pBt->autoVacuum ){
    return SQLITE_DONE;
  }







  return incrVacuumStep(p->pBt, 0);
}

/*
** This routine is called prior to sqlite3PagerCommit when a transaction
** is commited for an auto-vacuum database.
**
** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages
** the database file should be truncated to during the commit process. 
** i.e. the database has been reorganized so that only the first *pnTrunc
** pages are in use.
*/
static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
  int rc = SQLITE_OK;
  Pager *pPager = pBt->pPager;
#ifndef NDEBUG
  int nRef = sqlite3PagerRefcount(pPager);
#endif










  assert(pBt->autoVacuum);
  if( !pBt->incrVacuum ){
    Pgno nFin = 0;

    if( pBt->nTrunc==0 ){
      Pgno nFree;







>





>
>
>
>
>
|
>
|

















>
>
>
>
>
>
>
>
>







2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
**
** If the incremental vacuum is finished after this function has run,
** SQLITE_DONE is returned. If it is not finished, but no error occured,
** SQLITE_OK is returned. Otherwise an SQLite error code. 
*/
int sqlite3BtreeIncrVacuum(Btree *p){
  BtShared *pBt = p->pBt;
  BtCursor *pCur;

  assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
  if( !pBt->autoVacuum ){
    return SQLITE_DONE;
  }
#ifndef SQLITE_OMIT_INCRBLOB
  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
    /* Delete the cache of overflow page numbers. */
    sqliteFree(pCur->aOverflow);
    pCur->aOverflow = 0;
  }
#endif
  return incrVacuumStep(pBt, 0);
}

/*
** This routine is called prior to sqlite3PagerCommit when a transaction
** is commited for an auto-vacuum database.
**
** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages
** the database file should be truncated to during the commit process. 
** i.e. the database has been reorganized so that only the first *pnTrunc
** pages are in use.
*/
static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
  int rc = SQLITE_OK;
  Pager *pPager = pBt->pPager;
#ifndef NDEBUG
  int nRef = sqlite3PagerRefcount(pPager);
#endif

#ifndef SQLITE_OMIT_INCRBLOB
  BtCursor *pCur;
  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
    /* Delete the cache of overflow page numbers. */
    sqliteFree(pCur->aOverflow);
    pCur->aOverflow = 0;
  }
#endif

  assert(pBt->autoVacuum);
  if( !pBt->incrVacuum ){
    Pgno nFin = 0;

    if( pBt->nTrunc==0 ){
      Pgno nFree;
2929
2930
2931
2932
2933
2934
2935



2936
2937
2938
2939
2940
2941
2942
    pBt->pCursor = pCur->pNext;
  }
  if( pCur->pNext ){
    pCur->pNext->pPrev = pCur->pPrev;
  }
  releasePage(pCur->pPage);
  unlockBtreeIfUnused(pBt);



  sqliteFree(pCur);
  return SQLITE_OK;
}

/*
** Make a temporary cursor by filling in the fields of pTempCur.
** The temporary cursor is not on the cursor list for the Btree.







>
>
>







2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
    pBt->pCursor = pCur->pNext;
  }
  if( pCur->pNext ){
    pCur->pNext->pPrev = pCur->pPrev;
  }
  releasePage(pCur->pPage);
  unlockBtreeIfUnused(pBt);
#ifndef SQLITE_OMIT_INCRBLOB
  sqliteFree(pCur->aOverflow);
#endif
  sqliteFree(pCur);
  return SQLITE_OK;
}

/*
** Make a temporary cursor by filling in the fields of pTempCur.
** The temporary cursor is not on the cursor list for the Btree.
3128
3129
3130
3131
3132
3133
3134

3135
3136
3137
3138
3139
3140
3141
  unsigned char *aPayload;
  Pgno nextPage;
  int rc;
  MemPage *pPage;
  BtShared *pBt;
  int ovflSize;
  u32 nKey;


  assert( pCur!=0 && pCur->pPage!=0 );
  assert( pCur->eState==CURSOR_VALID );
  pBt = pCur->pBtree->pBt;
  pPage = pCur->pPage;
  assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
  getCellInfo(pCur);







>







3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
  unsigned char *aPayload;
  Pgno nextPage;
  int rc;
  MemPage *pPage;
  BtShared *pBt;
  int ovflSize;
  u32 nKey;
  int iIdx = 0;

  assert( pCur!=0 && pCur->pPage!=0 );
  assert( pCur->eState==CURSOR_VALID );
  pBt = pCur->pBtree->pBt;
  pPage = pCur->pPage;
  assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
  getCellInfo(pCur);
3166
3167
3168
3169
3170
3171
3172














3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183






3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203





3204
3205
3206
3207
3208
3209
3210
    amt -= a;
  }else{
    offset -= pCur->info.nLocal;
  }
  ovflSize = pBt->usableSize - 4;
  if( amt>0 ){
    nextPage = get4byte(&aPayload[pCur->info.nLocal]);














    while( amt>0 && nextPage ){
      if( offset>=ovflSize ){
        /* The only reason to read this page is to obtain the page
        ** number for the next page in the overflow chain. So try
        ** the getOverflowPage() shortcut.
        */
        rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        offset -= ovflSize;






      }else{
        /* Need to read this page properly, to obtain data to copy into
        ** the caller's buffer.
        */
        DbPage *pDbPage;
        int a = amt;
        rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
        if( rc!=0 ){
          return rc;
        }
        aPayload = sqlite3PagerGetData(pDbPage);
        nextPage = get4byte(aPayload);
        if( a + offset > ovflSize ){
          a = ovflSize - offset;
        }
        memcpy(pBuf, &aPayload[offset+4], a);
        offset = 0;
        amt -= a;
        pBuf += a;
        sqlite3PagerUnref(pDbPage);





      }
    }
  }

  if( amt>0 ){
    return SQLITE_CORRUPT_BKPT;
  }







>
>
>
>
>
>
>
>
>
>
>
>
>
>
|










>
>
>
>
>
>




















>
>
>
>
>







3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
    amt -= a;
  }else{
    offset -= pCur->info.nLocal;
  }
  ovflSize = pBt->usableSize - 4;
  if( amt>0 ){
    nextPage = get4byte(&aPayload[pCur->info.nLocal]);
#ifndef SQLITE_OMIT_INCRBLOB
    if( pCur->cacheOverflow && !pCur->aOverflow ){
      int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize;
      pCur->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOvfl);
      if( nOvfl && !pCur->aOverflow ){
        return SQLITE_NOMEM;
      }
    }
    if( pCur->aOverflow && pCur->aOverflow[offset/ovflSize] ){
      iIdx = (offset/ovflSize);
      nextPage = pCur->aOverflow[iIdx];
      offset = (offset%ovflSize);
    }
#endif
    for(iIdx++; amt>0 && nextPage; iIdx++){
      if( offset>=ovflSize ){
        /* The only reason to read this page is to obtain the page
        ** number for the next page in the overflow chain. So try
        ** the getOverflowPage() shortcut.
        */
        rc = getOverflowPage(pBt, nextPage, 0, &nextPage);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        offset -= ovflSize;
#ifndef SQLITE_OMIT_INCRBLOB
        if( pCur->aOverflow ){
          assert(nextPage);
          pCur->aOverflow[iIdx] = nextPage;
        }
#endif
      }else{
        /* Need to read this page properly, to obtain data to copy into
        ** the caller's buffer.
        */
        DbPage *pDbPage;
        int a = amt;
        rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
        if( rc!=0 ){
          return rc;
        }
        aPayload = sqlite3PagerGetData(pDbPage);
        nextPage = get4byte(aPayload);
        if( a + offset > ovflSize ){
          a = ovflSize - offset;
        }
        memcpy(pBuf, &aPayload[offset+4], a);
        offset = 0;
        amt -= a;
        pBuf += a;
        sqlite3PagerUnref(pDbPage);
#ifndef SQLITE_OMIT_INCRBLOB
        if( pCur->aOverflow && nextPage ){
          pCur->aOverflow[iIdx] = nextPage;
        }
#endif
      }
    }
  }

  if( amt>0 ){
    return SQLITE_CORRUPT_BKPT;
  }
6870
6871
6872
6873
6874
6875
6876

6877
6878
6879
6880
6881
6882
6883
  BtShared *pBt = pCsr->pBtree->pBt;
  int rc;

  u32 iRem = amt;        /* Remaining bytes to write */
  u8 *zRem = (u8 *)z;    /* Pointer to data not yet written */
  u32 iOffset = offset;  /* Offset from traversal point to start of write */


  Pgno iOvfl;            /* Page number for next overflow page */
  int ovflSize;          /* Bytes of data per overflow page. */

  CellInfo *pInfo;

  /* Check some preconditions: 
  **   (a) a write-transaction is open, 







>







6925
6926
6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
6937
6938
6939
  BtShared *pBt = pCsr->pBtree->pBt;
  int rc;

  u32 iRem = amt;        /* Remaining bytes to write */
  u8 *zRem = (u8 *)z;    /* Pointer to data not yet written */
  u32 iOffset = offset;  /* Offset from traversal point to start of write */

  Pgno iIdx = 0;         /* Index of overflow page in pCsr->aOverflow */
  Pgno iOvfl;            /* Page number for next overflow page */
  int ovflSize;          /* Bytes of data per overflow page. */

  CellInfo *pInfo;

  /* Check some preconditions: 
  **   (a) a write-transaction is open, 
6904
6905
6906
6907
6908
6909
6910










6911
6912
6913
6914
6915
6916
6917
6918
6919
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929
6930
6931
6932

6933
6934
6935
6936
6937
6938
6939
6940
6941
6942














6943
6944
6945
6946
6947
6948
6949
6950
6951
6952
6953
6954
6955
6956
6957
6958

6959
6960
6961
6962
6963
6964
6965
6966
6967

6968
6969
6970
6971
6972










6973
6974
6975
6976
6977
6978
6979
  ** enough for the proposed write operation.
  */
  getCellInfo(pCsr);
  pInfo = &pCsr->info;
  if( pInfo->nData<(offset+amt) ){
    return SQLITE_ERROR;
  }











  if( pInfo->nLocal>iOffset ){
    /* In this case data must be written to the b-tree page. */
    int iWrite = pInfo->nLocal - offset;
    if( iWrite>iRem ){
      iWrite = iRem;
    }
    rc = sqlite3PagerWrite(pCsr->pPage->pDbPage);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    memcpy(&pInfo->pCell[iOffset+pInfo->nHeader], zRem, iWrite);

    zRem += iWrite;
    iRem -= iWrite;
  }
  iOffset = ((iOffset<pInfo->nLocal)?0:(iOffset-pInfo->nLocal));

  ovflSize = pBt->usableSize - 4;
  assert(pInfo->iOverflow>0 || iRem==0);
  iOvfl = get4byte(&pInfo->pCell[pInfo->iOverflow]);
  while( iRem>0 ){

    if( iOffset>ovflSize ){
      /* The only reason to read this page is to obtain the page
      ** number for the next page in the overflow chain. So try
      ** the getOverflowPage() shortcut.  */
      rc = getOverflowPage(pBt, iOvfl, 0, &iOvfl);
      if( rc!=SQLITE_OK ){
        return rc;
      }
      iOffset -= ovflSize;
    }else{














      int iWrite = ovflSize - iOffset;
      DbPage *pOvfl;          /* The overflow page. */
      u8 *aData;              /* Page data */

      rc = sqlite3PagerGet(pBt->pPager, iOvfl, &pOvfl);
      if( rc!=SQLITE_OK ){
        return rc;
      }
      rc = sqlite3PagerWrite(pOvfl);
      if( rc!=SQLITE_OK ){
        sqlite3PagerUnref(pOvfl);
        return rc;
      }

      aData = sqlite3PagerGetData(pOvfl);
      iOvfl = get4byte(aData);

      if( iWrite>iRem ){
        iWrite = iRem;
      }
      memcpy(&aData[iOffset+4], zRem, iWrite);
      sqlite3PagerUnref(pOvfl);

      zRem += iWrite;
      iRem -= iWrite;
      iOffset = ((iOffset<ovflSize)?0:(iOffset-ovflSize));

    }
  }

  return SQLITE_OK;
}










#endif

/*
** The following debugging interface has to be in this file (rather
** than in, for example, test1.c) so that it can get access to
** the definition of BtShared.
*/







>
>
>
>
>
>
>
>
>
>


















<

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

>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
|
>





>
>
>
>
>
>
>
>
>
>







6960
6961
6962
6963
6964
6965
6966
6967
6968
6969
6970
6971
6972
6973
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
6989
6990
6991
6992
6993
6994

6995

6996
6997
6998


6999




7000
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
7028
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
  ** enough for the proposed write operation.
  */
  getCellInfo(pCsr);
  pInfo = &pCsr->info;
  if( pInfo->nData<(offset+amt) ){
    return SQLITE_ERROR;
  }
  ovflSize = pBt->usableSize - 4;

  assert(pCsr->cacheOverflow);
  if( !pCsr->aOverflow ){
    int nOverflow = (pInfo->nPayload - pInfo->nLocal + ovflSize - 1)/ovflSize;
    pCsr->aOverflow = (Pgno *)sqliteMalloc(sizeof(Pgno)*nOverflow);
    if( nOverflow && !pCsr->aOverflow ){
      return SQLITE_NOMEM;
    }
  }

  if( pInfo->nLocal>iOffset ){
    /* In this case data must be written to the b-tree page. */
    int iWrite = pInfo->nLocal - offset;
    if( iWrite>iRem ){
      iWrite = iRem;
    }
    rc = sqlite3PagerWrite(pCsr->pPage->pDbPage);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    memcpy(&pInfo->pCell[iOffset+pInfo->nHeader], zRem, iWrite);

    zRem += iWrite;
    iRem -= iWrite;
  }
  iOffset = ((iOffset<pInfo->nLocal)?0:(iOffset-pInfo->nLocal));


  assert(pInfo->iOverflow>0 || iRem==0);

  if( iRem>0 ){
    if( pCsr->aOverflow[iOffset/ovflSize] ){
      iIdx = iOffset/ovflSize;


      iOvfl = pCsr->aOverflow[iIdx];




      iOffset = iOffset%ovflSize;
    }else{
      iOvfl = get4byte(&pInfo->pCell[pInfo->iOverflow]);
    }
    for(iIdx++; iRem>0; iIdx++){
      if( iOffset>ovflSize ){
        /* The only reason to read this page is to obtain the page
        ** number for the next page in the overflow chain. So try
        ** the getOverflowPage() shortcut.  */
        rc = getOverflowPage(pBt, iOvfl, 0, &iOvfl);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        iOffset -= ovflSize;
        pCsr->aOverflow[iIdx] = iOvfl;
      }else{
        int iWrite = ovflSize - iOffset;
        DbPage *pOvfl;          /* The overflow page. */
        u8 *aData;              /* Page data */
  
        rc = sqlite3PagerGet(pBt->pPager, iOvfl, &pOvfl);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        rc = sqlite3PagerWrite(pOvfl);
        if( rc!=SQLITE_OK ){
          sqlite3PagerUnref(pOvfl);
          return rc;
        }
  
        aData = sqlite3PagerGetData(pOvfl);
        iOvfl = get4byte(aData);
        pCsr->aOverflow[iIdx] = iOvfl;
        if( iWrite>iRem ){
          iWrite = iRem;
        }
        memcpy(&aData[iOffset+4], zRem, iWrite);
        sqlite3PagerUnref(pOvfl);
  
        zRem += iWrite;
        iRem -= iWrite;
        iOffset = ((iOffset<ovflSize)?0:(iOffset-ovflSize));
      }
    }
  }

  return SQLITE_OK;
}

/* 
** Set a flag on this cursor to cache the locations of pages from the 
** overflow list for the current row.
*/
void sqlite3BtreeCacheOverflow(BtCursor *pCur){
  assert(!pCur->cacheOverflow);
  assert(!pCur->aOverflow);
  pCur->cacheOverflow = 1;
}
#endif

/*
** The following debugging interface has to be in this file (rather
** than in, for example, test1.c) so that it can get access to
** the definition of BtShared.
*/
Changes to src/btree.h.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite B-Tree file
** subsystem.  See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.77 2007/05/02 01:34:31 drh Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_

/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite B-Tree file
** subsystem.  See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.78 2007/05/02 16:48:37 danielk1977 Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_

/* TODO: This definition is just included so other modules compile. It
** needs to be revisited.
*/
139
140
141
142
143
144
145

146
147
148
149
150
151
152
153
154
155
156
157
158
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);

char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);

int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, const void*);


#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*);
#endif

#ifdef SQLITE_DEBUG
int sqlite3BtreePageDump(Btree*, int, int recursive);
#else
#define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK
#endif

#endif /* _BTREE_H_ */







>













139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);

char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);

int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, const void*);
void sqlite3BtreeCacheOverflow(BtCursor *);

#ifdef SQLITE_TEST
int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
void sqlite3BtreeCursorList(Btree*);
#endif

#ifdef SQLITE_DEBUG
int sqlite3BtreePageDump(Btree*, int, int recursive);
#else
#define sqlite3BtreePageDump(X,Y,Z) SQLITE_OK
#endif

#endif /* _BTREE_H_ */
Changes to src/vdbeblob.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
** 2007 May 1
**
** 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.
**
*************************************************************************
**
** $Id: vdbeblob.c,v 1.1 2007/05/01 17:49:49 danielk1977 Exp $
*/

#include "sqliteInt.h"
#include "vdbeInt.h"

#ifndef SQLITE_OMIT_INCRBLOB













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
** 2007 May 1
**
** 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.
**
*************************************************************************
**
** $Id: vdbeblob.c,v 1.2 2007/05/02 16:48:37 danielk1977 Exp $
*/

#include "sqliteInt.h"
#include "vdbeInt.h"

#ifndef SQLITE_OMIT_INCRBLOB

169
170
171
172
173
174
175

176
177
178
179
180
181
182
    pBlob = (Incrblob *)sqliteMalloc(sizeof(Incrblob));
    if( sqlite3MallocFailed() ){
      sqliteFree(pBlob);
      goto blob_open_out;
    }
    pBlob->flags = flags;
    pBlob->pCsr =  v->apCsr[0]->pCursor;

    pBlob->pStmt = (sqlite3_stmt *)v;
    pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
    pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
    *ppBlob = (sqlite3_blob *)pBlob;
    rc = SQLITE_OK;
  }else{
    if( rc==SQLITE_DONE ){







>







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    pBlob = (Incrblob *)sqliteMalloc(sizeof(Incrblob));
    if( sqlite3MallocFailed() ){
      sqliteFree(pBlob);
      goto blob_open_out;
    }
    pBlob->flags = flags;
    pBlob->pCsr =  v->apCsr[0]->pCursor;
    sqlite3BtreeCacheOverflow(pBlob->pCsr);
    pBlob->pStmt = (sqlite3_stmt *)v;
    pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
    pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
    *ppBlob = (sqlite3_blob *)pBlob;
    rc = SQLITE_OK;
  }else{
    if( rc==SQLITE_DONE ){