SQLite

Check-in [a100a5304b]
Login

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

Overview
Comment:Combine the internal btree functions BtreePutData() and getPayload(). (CVS 3901)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a100a5304b0e7cbbdb6dac71a39c78eb71d44a03
User & Date: danielk1977 2007-05-02 17:48:46.000
Context
2007-05-02
17:54
Allow CREATE TABLE to occur while other queries are running. DROP TABLE is still prohibited, however, since we do not want to delete a table out from under an running query. (CVS 3902) (check-in: 5b4bf1fce4 user: drh tags: trunk)
17:48
Combine the internal btree functions BtreePutData() and getPayload(). (CVS 3901) (check-in: a100a5304b user: danielk1977 tags: trunk)
16:51
More fixes and improvements to the zeroblob() mechanism. (CVS 3900) (check-in: 83ab25014e 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.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.











|







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.367 2007/05/02 17:48:46 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.
3135
3136
3137
3138
3139
3140
3141

3142
3143




3144

3145
3146
3147
3148

3149

3150
3151
3152
3153
3154
3155

3156
3157
3158
3159
3160
3161
3162
  *pPgnoNext = next;

  return rc;
}


/*

** Read payload information from the entry that the pCur cursor is
** pointing to.  Begin reading the payload at "offset" and read




** a total of "amt" bytes.  Put the result in zBuf.

**
** This routine does not make a distinction between key and data.
** It just reads bytes from the payload area.  Data might appear
** on the main page or be scattered out on multiple overflow pages.

*/

static int getPayload(
  BtCursor *pCur,      /* Cursor pointing to entry to read from */
  int offset,          /* Begin reading this far into payload */
  int amt,             /* Read this many bytes */
  unsigned char *pBuf, /* Write the bytes into this buffer */ 
  int skipKey          /* offset begins at data if this is true */

){
  unsigned char *aPayload;
  Pgno nextPage;
  int rc;
  MemPage *pPage;
  BtShared *pBt;
  int ovflSize;







>
|
<
>
>
>
>
|
>


|
|
>

>
|




|
>







3135
3136
3137
3138
3139
3140
3141
3142
3143

3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
  *pPgnoNext = next;

  return rc;
}


/*
** This function is used to read or overwrite payload information
** for the entry that the pCur cursor is pointing to. If the eOp

** parameter is 0, this is a read operation (data copied into
** buffer pBuf). If it is non-zero, a write (data copied from
** buffer pBuf).
**
** A total of "amt" bytes are read or written beginning at "offset".
** Data is read to or from the buffer pBuf.
**
** This routine does not make a distinction between key and data.
** It just reads or writes bytes from the payload area.  Data might 
** appear on the main page or be scattered out on multiple overflow 
** pages.
*/
#define getPayload(a,b,c,d,e) accessPayload(a,b,c,d,e,0)
static int accessPayload(
  BtCursor *pCur,      /* Cursor pointing to entry to read from */
  int offset,          /* Begin reading this far into payload */
  int amt,             /* Read this many bytes */
  unsigned char *pBuf, /* Write the bytes into this buffer */ 
  int skipKey,         /* offset begins at data if this is true */
  int eOp              /* zero to read. non-zero to write. */
){
  unsigned char *aPayload;
  Pgno nextPage;
  int rc;
  MemPage *pPage;
  BtShared *pBt;
  int ovflSize;
3183
3184
3185
3186
3187
3188
3189









3190

3191
3192
3193
3194
3195
3196
3197
    return SQLITE_ERROR;
  }
  if( offset<pCur->info.nLocal ){
    int a = amt;
    if( a+offset>pCur->info.nLocal ){
      a = pCur->info.nLocal - offset;
    }









    memcpy(pBuf, &aPayload[offset], a);

    if( a==amt ){
      return SQLITE_OK;
    }
    offset = 0;
    pBuf += a;
    amt -= a;
  }else{







>
>
>
>
>
>
>
>
>
|
>







3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
    return SQLITE_ERROR;
  }
  if( offset<pCur->info.nLocal ){
    int a = amt;
    if( a+offset>pCur->info.nLocal ){
      a = pCur->info.nLocal - offset;
    }
    if( eOp ){
      /* A write operation. */
      rc = sqlite3PagerWrite(pPage->pDbPage);
      if( rc!=SQLITE_OK ){
        return rc;
      }
      memcpy(&aPayload[offset], pBuf, a);
    }else{
      /* A read operation */
      memcpy(pBuf, &aPayload[offset], a);
    }
    if( a==amt ){
      return SQLITE_OK;
    }
    offset = 0;
    pBuf += a;
    amt -= a;
  }else{
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
#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;







|
|












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







3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
#ifndef SQLITE_OMIT_INCRBLOB
        if( pCur->aOverflow ){
          assert(nextPage);
          pCur->aOverflow[iIdx] = nextPage;
        }
#endif
      }else{
        /* Need to read this page properly. It contains some of the
        ** range of data that is being read (eOp==0) or written (eOp!=0).
        */
        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;
        }
        if( eOp ){
          /* A write operation. */
          rc = sqlite3PagerWrite(pPage->pDbPage);
          if( rc!=SQLITE_OK ){
            sqlite3PagerUnref(pDbPage);
            return rc;
          }
          memcpy(&aPayload[offset+4], pBuf, a);
        }else{
          /* A read operation */
          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;
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
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
  /* Check some preconditions: 
  **   (a) a write-transaction is open, 
  **   (b) the cursor is open for writing,
  **   (c) there is no read-lock on the table being modified and
  **   (d) the cursor points at a valid row of an intKey table.
  */
  if( pBt->inTransaction!=TRANS_WRITE ){
    /* Must start a transaction before doing an insert */
    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
  }
  assert( !pBt->readOnly );
  if( !pCsr->wrFlag ){
    return SQLITE_PERM;   /* Cursor not open for writing */
  }
  if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }
  if( pCsr->eState==CURSOR_INVALID || !pCsr->pPage->intKey ){
    return SQLITE_ERROR;
  }

  /* Parse the cell-info. Check that the cell-data area is large
  ** 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){







|













<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







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
  /* Check some preconditions: 
  **   (a) a write-transaction is open, 
  **   (b) the cursor is open for writing,
  **   (c) there is no read-lock on the table being modified and
  **   (d) the cursor points at a valid row of an intKey table.
  */
  if( pBt->inTransaction!=TRANS_WRITE ){
    /* Must start a transaction before writing to a blob */
    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
  }
  assert( !pBt->readOnly );
  if( !pCsr->wrFlag ){
    return SQLITE_PERM;   /* Cursor not open for writing */
  }
  if( checkReadLocks(pCsr->pBtree, pCsr->pgnoRoot, pCsr) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }
  if( pCsr->eState==CURSOR_INVALID || !pCsr->pPage->intKey ){
    return SQLITE_ERROR;
  }










  return accessPayload(pCsr, offset, amt, (unsigned char *)z, 0, 1);














































































}

/* 
** Set a flag on this cursor to cache the locations of pages from the 
** overflow list for the current row.
*/
void sqlite3BtreeCacheOverflow(BtCursor *pCur){