/ Check-in [ac84f106]
Login

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

Overview
Comment:Simplifications to btree.c to improve test coverage. (CVS 6150)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:ac84f106d572e881136adc3434d00d70564f57cb
User & Date: drh 2009-01-09 14:11:05
Context
2009-01-09
14:29
Fix two problems in test instrumentation that show up on some fulltests. (CVS 6151) check-in: c9179617 user: drh tags: trunk
14:11
Simplifications to btree.c to improve test coverage. (CVS 6150) check-in: ac84f106 user: drh tags: trunk
10:49
Add a couple of coverage tests. (CVS 6149) check-in: 6a64109d user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
....
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724

2725

2726
2727

2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
....
2743
2744
2745
2746
2747
2748
2749

2750
2751
2752
2753
2754
2755
2756
2757
....
2767
2768
2769
2770
2771
2772
2773

2774
2775
2776
2777
2778
2779
2780
2781
....
2853
2854
2855
2856
2857
2858
2859
2860

2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
....
3749
3750
3751
3752
3753
3754
3755

3756
3757

3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
....
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
....
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
....
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
....
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
....
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
....
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
....
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
....
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
6625
6626
6627
6628
6629
6630
6631
6632
6633
6634
6635
6636
6637
6638
6639
6640
....
6644
6645
6646
6647
6648
6649
6650

6651
6652
6653
6654
6655
6656
6657
6658
6659
....
6860
6861
6862
6863
6864
6865
6866
6867
6868
6869
6870
6871
6872
6873
6874
....
7087
7088
7089
7090
7091
7092
7093
7094


7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
....
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
....
7376
7377
7378
7379
7380
7381
7382

7383
7384
7385
7386
7387
7388
7389

7390
7391
7392
7393
7394
7395
7396
7397
7398
** 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.556 2009/01/06 18:21:09 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

................................................................................
#if 0
int sqlite3BtreeTrace=0;  /* True to enable tracing */
# define TRACE(X)  if(sqlite3BtreeTrace){printf X;fflush(stdout);}
#else
# define TRACE(X)
#endif

/*
** Sometimes we need a small amount of code such as a variable initialization
** to setup for a later assert() statement.  We do not want this code to
** appear when assert() is disabled.  The following macro is therefore
** used to contain that setup code.  The "VVA" acronym stands for
** "Verification, Validation, and Accreditation".  In other words, the
** code within VVA_ONLY() will only run during verification processes.
*/
#ifndef NDEBUG
# define VVA_ONLY(X)  X
#else
# define VVA_ONLY(X)
#endif



#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** A list of BtShared objects that are eligible for participation
** in shared cache.  This variable has file scope during normal builds,
** but the test harness needs to access it so we make it global for 
................................................................................
** can be rolled back without having to rollback the entire transaction.
*/
int sqlite3BtreeBeginStmt(Btree *p){
  int rc;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;
  if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){
    rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
  }else{
    assert( pBt->inTransaction==TRANS_WRITE );

    if( pBt->readOnly ){

      rc = SQLITE_OK;
    }else{

      /* At the pager level, a statement transaction is a savepoint with
      ** an index greater than all savepoints created explicitly using
      ** SQL statements. It is illegal to open, release or rollback any
      ** such savepoints while the statement transaction savepoint is active.
      */
      rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint+1);
    }
    pBt->inStmt = 1;
  }
  sqlite3BtreeLeave(p);
  return rc;
}

/*
................................................................................
** subtransaction is active, this is a no-op.
*/
int sqlite3BtreeCommitStmt(Btree *p){
  int rc;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;

  if( pBt->inStmt && !pBt->readOnly ){
    int iStmtpoint = p->db->nSavepoint;
    rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);
  }else{
    rc = SQLITE_OK;
  }
  pBt->inStmt = 0;
  sqlite3BtreeLeave(p);
................................................................................
** will result in an error.
*/
int sqlite3BtreeRollbackStmt(Btree *p){
  int rc = SQLITE_OK;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;

  if( pBt->inStmt && !pBt->readOnly ){
    int iStmtpoint = p->db->nSavepoint;
    rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_ROLLBACK, iStmtpoint);
    if( rc==SQLITE_OK ){
      rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);
    }
    pBt->inStmt = 0;
  }
................................................................................
  int rc;
  Pgno nPage;
  BtShared *pBt = p->pBt;

  assert( sqlite3BtreeHoldsMutex(p) );
  assert( wrFlag==0 || wrFlag==1 );
  if( wrFlag ){
    if( pBt->readOnly ){

      return SQLITE_READONLY;
    }
    if( checkReadLocks(p, iTable, 0, 0) ){
      return SQLITE_LOCKED;
    }
  }

  if( pBt->pPage1==0 ){
    rc = lockBtreeWithRetry(p);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    if( pBt->readOnly && wrFlag ){
      return SQLITE_READONLY;
    }
  }
  pCur->pgnoRoot = (Pgno)iTable;
  rc = sqlite3PagerPagecount(pBt->pPager, (int *)&nPage); 
  if( rc!=SQLITE_OK ){
    return rc;
  }
  if( iTable==1 && nPage==0 ){
................................................................................
** is ignored.
**
** If an exact match is not found, then the cursor is always
** left pointing at a leaf page which would hold the entry if it
** were present.  The cursor might point to an entry that comes
** before or after the key.
**

** The result of comparing the key with the entry to which the
** cursor is written to *pRes if pRes!=NULL.  The meaning of

** this value is as follows:
**
**     *pRes<0      The cursor is left pointing at an entry that
**                  is smaller than pKey or if the table is empty
**                  and the cursor is therefore left point to nothing.
**
**     *pRes==0     The cursor is left pointing at an entry that
**                  exactly matches pKey.
**
**     *pRes>0      The cursor is left pointing at an entry that
**                  is larger than pKey.
**
*/
int sqlite3BtreeMovetoUnpacked(
  BtCursor *pCur,          /* The cursor to be moved */
  UnpackedRecord *pIdxKey, /* Unpacked index key */
  i64 intKey,              /* The table key */
  int biasRight,           /* If true, bias the search to the high end */
................................................................................
  for(;;){
    int lwr, upr;
    Pgno chldPg;
    MemPage *pPage = pCur->apPage[pCur->iPage];
    int c = -1;  /* pRes return if table is empty must be -1 */
    lwr = 0;
    upr = pPage->nCell-1;
    if( !pPage->intKey && pIdxKey==0 ){
      rc = SQLITE_CORRUPT_BKPT;
      goto moveto_finish;
    }
    if( biasRight ){
      pCur->aiIdx[pCur->iPage] = (u16)upr;
    }else{
      pCur->aiIdx[pCur->iPage] = (u16)((upr+lwr)/2);
    }
    if( lwr<=upr ) for(;;){
      void *pCellKey;
      i64 nCellKey;
      int idx = pCur->aiIdx[pCur->iPage];
      pCur->info.nSize = 0;
      pCur->validNKey = 1;
      if( pPage->intKey ){
        u8 *pCell;
................................................................................
      if( c==0 ){
        pCur->info.nKey = nCellKey;
        if( pPage->intKey && !pPage->leaf ){
          lwr = idx;
          upr = lwr - 1;
          break;
        }else{
          if( pRes ) *pRes = 0;
          rc = SQLITE_OK;
          goto moveto_finish;
        }
      }
      if( c<0 ){
        lwr = idx+1;
      }else{
................................................................................
  MemPage *pPage;
  Btree *p = pCur->pBtree;
  BtShared *pBt = p->pBt;
  unsigned char *oldCell;
  unsigned char *newCell = 0;

  assert( cursorHoldsMutex(pCur) );
  if( pBt->inTransaction!=TRANS_WRITE ){
    /* Must start a transaction before doing an insert */
    rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
    return rc;
  }
  assert( !pBt->readOnly );
  if( !pCur->wrFlag ){
    return SQLITE_PERM;   /* Cursor not open for writing */
  }
  if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, nKey) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }
  if( pCur->eState==CURSOR_FAULT ){
    return pCur->skip;
  }

................................................................................
  int rc;
  Pgno pgnoChild = 0;
  Btree *p = pCur->pBtree;
  BtShared *pBt = p->pBt;

  assert( cursorHoldsMutex(pCur) );
  assert( pPage->isInit );
  if( pBt->inTransaction!=TRANS_WRITE ){
    /* Must start a transaction before doing a delete */
    rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
    return rc;
  }
  assert( !pBt->readOnly );
  if( pCur->eState==CURSOR_FAULT ){
    return pCur->skip;
  }
  if( pCur->aiIdx[pCur->iPage]>=pPage->nCell ){
    return SQLITE_ERROR;  /* The cursor is not pointing to anything */
  }
  if( !pCur->wrFlag ){
    return SQLITE_PERM;   /* Did not open this cursor for writing */
  }
  if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, pCur->info.nKey) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }

  /* Restore the current cursor position (a no-op if the cursor is not in 
  ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors 
  ** open on the same table. Then call sqlite3PagerWrite() on the page
................................................................................
static int btreeCreateTable(Btree *p, int *piTable, int flags){
  BtShared *pBt = p->pBt;
  MemPage *pRoot;
  Pgno pgnoRoot;
  int rc;

  assert( sqlite3BtreeHoldsMutex(p) );
  if( pBt->inTransaction!=TRANS_WRITE ){
    /* Must start a transaction first */
    rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
    return rc;
  }
  assert( !pBt->readOnly );

#ifdef SQLITE_OMIT_AUTOVACUUM
  rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
  if( rc ){
    return rc;
  }
................................................................................
** entries in the table.
*/
int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
  int rc;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;
  if( p->inTrans!=TRANS_WRITE ){
    rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
  }else if( (rc = checkReadLocks(p, iTable, 0, 1))!=SQLITE_OK ){
    /* nothing to do */
  }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
    /* nothing to do */
  }else{
    rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
  }
  sqlite3BtreeLeave(p);
................................................................................
*/
static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
  int rc;
  MemPage *pPage = 0;
  BtShared *pBt = p->pBt;

  assert( sqlite3BtreeHoldsMutex(p) );
  if( p->inTrans!=TRANS_WRITE ){
    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
  }

  /* It is illegal to drop a table if any cursors are open on the
  ** database. This is because in auto-vacuum mode the backend may
  ** need to move another root-page to fill a gap left by the deleted
  ** root page. If an open cursor was using this page a problem would 
  ** occur.
  */
................................................................................
int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
  BtShared *pBt = p->pBt;
  unsigned char *pP1;
  int rc;
  assert( idx>=1 && idx<=15 );
  sqlite3BtreeEnter(p);
  pBt->db = p->db;
  if( p->inTrans!=TRANS_WRITE ){
    rc = pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
  }else{
    assert( pBt->pPage1!=0 );
    pP1 = pBt->pPage1->aData;
    rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
    if( rc==SQLITE_OK ){
      put4byte(&pP1[36 + idx*4], iMeta);
#ifndef SQLITE_OMIT_AUTOVACUUM
      if( idx==7 ){
        assert( pBt->autoVacuum || iMeta==0 );
        assert( iMeta==0 || iMeta==1 );
        pBt->incrVacuum = (u8)iMeta;
      }
#endif
    }
  }
  sqlite3BtreeLeave(p);
  return rc;
}

/*
** Return the flag byte at the beginning of the page that the cursor
................................................................................
  /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call
  ** restoreCursorPosition() here.
  */
  MemPage *pPage;
  restoreCursorPosition(pCur);
  pPage = pCur->apPage[pCur->iPage];
  assert( cursorHoldsMutex(pCur) );

  assert( pPage->pBt==pCur->pBt );
  return pPage ? pPage->aData[pPage->hdrOffset] : 0;
}


/*
** Return the pager associated with a BTree.  This routine is used for
** testing and debugging only.
*/
................................................................................
  if( (rc = sqlite3BtreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
    if( rc==SQLITE_NOMEM ) pCheck->mallocFailed = 1;
    checkAppendMsg(pCheck, zContext,
       "unable to get the page. error code=%d", rc);
    return 0;
  }
  if( (rc = sqlite3BtreeInitPage(pPage))!=0 ){
    if( rc==SQLITE_NOMEM ) pCheck->mallocFailed = 1;
    checkAppendMsg(pCheck, zContext, 
                   "sqlite3BtreeInitPage() returns error code %d", rc);
    releasePage(pPage);
    return 0;
  }

  /* Check out all the cells.
................................................................................
    if( sCheck.anRef[i]!=0 && 
       (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
      checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
    }
#endif
  }

  /* Make sure this analysis did not leave any unref() pages


  */
  unlockBtreeIfUnused(pBt);
  if( nRef != sqlite3PagerRefcount(pBt->pPager) ){
    checkAppendMsg(&sCheck, 0, 
      "Outstanding page count goes from %d to %d during this analysis",
      nRef, sqlite3PagerRefcount(pBt->pPager)
    );
  }

  /* Clean  up and report errors.
................................................................................
  BtShared *pBtFrom = pFrom->pBt;
  pBtTo->db = pTo->db;
  pBtFrom->db = pFrom->db;

  nToPageSize = pBtTo->pageSize;
  nFromPageSize = pBtFrom->pageSize;

  if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){
    return SQLITE_ERROR;
  }
  if( pBtTo->pCursor ){
    return SQLITE_BUSY;
  }

  nToPage = pagerPagecount(pBtTo);
  nFromPage = pagerPagecount(pBtFrom);
  iSkip = PENDING_BYTE_PAGE(pBtTo);

................................................................................
}

/*
** Return non-zero if a statement transaction is active.
*/
int sqlite3BtreeIsInStmt(Btree *p){
  assert( sqlite3BtreeHoldsMutex(p) );

  return (p->pBt && p->pBt->inStmt);
}

/*
** Return non-zero if a read (or write) transaction is active.
*/
int sqlite3BtreeIsInReadTrans(Btree *p){

  assert( sqlite3_mutex_held(p->db->mutex) );
  return (p && (p->inTrans!=TRANS_NONE));
}

/*
** This function returns a pointer to a blob of memory associated with
** a single shared-btree. The memory is used by client code for its own
** purposes (for example, to store a high-level schema associated with 
** the shared-btree). The btree layer manages reference counting issues.







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







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







 







>
|







 







>
|







 







|
>












<
<
<







 







>
|
<
>
|


|



|


|







 







|








|







 







|







 







|
<
<
<
<

|
<
<







 







|
<
<
<
<




|


|
<
<







 







|
<
<
<
<







 







|
<
|







 







|
<
<







 







|
<
<
|
|
|
|
|

|
|
|
|
|

<







 







>

|







 







|







 







|
>
>


|







 







|
|
<
|







 







>
|






>

|







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
30
31
32
33
34
35
36














37
38
39
40
41
42
43
....
2700
2701
2702
2703
2704
2705
2706



2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719

2720
2721
2722
2723
2724
2725
2726
....
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
....
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
....
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860



2861
2862
2863
2864
2865
2866
2867
....
3734
3735
3736
3737
3738
3739
3740
3741
3742

3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
....
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
....
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
....
5859
5860
5861
5862
5863
5864
5865
5866




5867
5868


5869
5870
5871
5872
5873
5874
5875
....
5950
5951
5952
5953
5954
5955
5956
5957




5958
5959
5960
5961
5962
5963
5964
5965


5966
5967
5968
5969
5970
5971
5972
....
6153
6154
6155
6156
6157
6158
6159
6160




6161
6162
6163
6164
6165
6166
6167
....
6349
6350
6351
6352
6353
6354
6355
6356

6357
6358
6359
6360
6361
6362
6363
6364
....
6387
6388
6389
6390
6391
6392
6393
6394


6395
6396
6397
6398
6399
6400
6401
....
6578
6579
6580
6581
6582
6583
6584
6585


6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597

6598
6599
6600
6601
6602
6603
6604
....
6608
6609
6610
6611
6612
6613
6614
6615
6616
6617
6618
6619
6620
6621
6622
6623
6624
....
6825
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
....
7052
7053
7054
7055
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
....
7146
7147
7148
7149
7150
7151
7152
7153
7154

7155
7156
7157
7158
7159
7160
7161
7162
....
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
** 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.557 2009/01/09 14:11:05 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** See the header comment on "btreeInt.h" for additional information.
** Including a description of file format and an overview of operation.
*/
#include "btreeInt.h"

................................................................................
#if 0
int sqlite3BtreeTrace=0;  /* True to enable tracing */
# define TRACE(X)  if(sqlite3BtreeTrace){printf X;fflush(stdout);}
#else
# define TRACE(X)
#endif

















#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** A list of BtShared objects that are eligible for participation
** in shared cache.  This variable has file scope during normal builds,
** but the test harness needs to access it so we make it global for 
................................................................................
** can be rolled back without having to rollback the entire transaction.
*/
int sqlite3BtreeBeginStmt(Btree *p){
  int rc;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;



  assert( p->inTrans==TRANS_WRITE );
  assert( !pBt->inStmt );
  assert( pBt->readOnly==0 );
  if( NEVER(p->inTrans!=TRANS_WRITE || pBt->inStmt || pBt->readOnly) ){
    rc = SQLITE_INTERNAL;
  }else{
    assert( pBt->inTransaction==TRANS_WRITE );
    /* At the pager level, a statement transaction is a savepoint with
    ** an index greater than all savepoints created explicitly using
    ** SQL statements. It is illegal to open, release or rollback any
    ** such savepoints while the statement transaction savepoint is active.
    */
    rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint+1);

    pBt->inStmt = 1;
  }
  sqlite3BtreeLeave(p);
  return rc;
}

/*
................................................................................
** subtransaction is active, this is a no-op.
*/
int sqlite3BtreeCommitStmt(Btree *p){
  int rc;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;
  assert( pBt->readOnly==0 );
  if( pBt->inStmt ){
    int iStmtpoint = p->db->nSavepoint;
    rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);
  }else{
    rc = SQLITE_OK;
  }
  pBt->inStmt = 0;
  sqlite3BtreeLeave(p);
................................................................................
** will result in an error.
*/
int sqlite3BtreeRollbackStmt(Btree *p){
  int rc = SQLITE_OK;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;
  assert( pBt->readOnly==0 );
  if( pBt->inStmt ){
    int iStmtpoint = p->db->nSavepoint;
    rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_ROLLBACK, iStmtpoint);
    if( rc==SQLITE_OK ){
      rc = sqlite3PagerSavepoint(pBt->pPager, SAVEPOINT_RELEASE, iStmtpoint);
    }
    pBt->inStmt = 0;
  }
................................................................................
  int rc;
  Pgno nPage;
  BtShared *pBt = p->pBt;

  assert( sqlite3BtreeHoldsMutex(p) );
  assert( wrFlag==0 || wrFlag==1 );
  if( wrFlag ){
    assert( !pBt->readOnly );
    if( NEVER(pBt->readOnly) ){
      return SQLITE_READONLY;
    }
    if( checkReadLocks(p, iTable, 0, 0) ){
      return SQLITE_LOCKED;
    }
  }

  if( pBt->pPage1==0 ){
    rc = lockBtreeWithRetry(p);
    if( rc!=SQLITE_OK ){
      return rc;
    }



  }
  pCur->pgnoRoot = (Pgno)iTable;
  rc = sqlite3PagerPagecount(pBt->pPager, (int *)&nPage); 
  if( rc!=SQLITE_OK ){
    return rc;
  }
  if( iTable==1 && nPage==0 ){
................................................................................
** is ignored.
**
** If an exact match is not found, then the cursor is always
** left pointing at a leaf page which would hold the entry if it
** were present.  The cursor might point to an entry that comes
** before or after the key.
**
** An integer is written into *pRes which is the result of
** comparing the key with the entry to which the cursor is 

** pointing.  The meaning of the integer written into
** *pRes is as follows:
**
**     *pRes<0      The cursor is left pointing at an entry that
**                  is smaller than intKey/pIdxKey or if the table is empty
**                  and the cursor is therefore left point to nothing.
**
**     *pRes==0     The cursor is left pointing at an entry that
**                  exactly matches intKey/pIdxKey.
**
**     *pRes>0      The cursor is left pointing at an entry that
**                  is larger than intKey/pIdxKey.
**
*/
int sqlite3BtreeMovetoUnpacked(
  BtCursor *pCur,          /* The cursor to be moved */
  UnpackedRecord *pIdxKey, /* Unpacked index key */
  i64 intKey,              /* The table key */
  int biasRight,           /* If true, bias the search to the high end */
................................................................................
  for(;;){
    int lwr, upr;
    Pgno chldPg;
    MemPage *pPage = pCur->apPage[pCur->iPage];
    int c = -1;  /* pRes return if table is empty must be -1 */
    lwr = 0;
    upr = pPage->nCell-1;
    if( (!pPage->intKey && pIdxKey==0) || upr<0 ){
      rc = SQLITE_CORRUPT_BKPT;
      goto moveto_finish;
    }
    if( biasRight ){
      pCur->aiIdx[pCur->iPage] = (u16)upr;
    }else{
      pCur->aiIdx[pCur->iPage] = (u16)((upr+lwr)/2);
    }
    for(;;){
      void *pCellKey;
      i64 nCellKey;
      int idx = pCur->aiIdx[pCur->iPage];
      pCur->info.nSize = 0;
      pCur->validNKey = 1;
      if( pPage->intKey ){
        u8 *pCell;
................................................................................
      if( c==0 ){
        pCur->info.nKey = nCellKey;
        if( pPage->intKey && !pPage->leaf ){
          lwr = idx;
          upr = lwr - 1;
          break;
        }else{
          *pRes = 0;
          rc = SQLITE_OK;
          goto moveto_finish;
        }
      }
      if( c<0 ){
        lwr = idx+1;
      }else{
................................................................................
  MemPage *pPage;
  Btree *p = pCur->pBtree;
  BtShared *pBt = p->pBt;
  unsigned char *oldCell;
  unsigned char *newCell = 0;

  assert( cursorHoldsMutex(pCur) );
  assert( pBt->inTransaction==TRANS_WRITE );




  assert( !pBt->readOnly );
  assert( pCur->wrFlag );


  if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, nKey) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }
  if( pCur->eState==CURSOR_FAULT ){
    return pCur->skip;
  }

................................................................................
  int rc;
  Pgno pgnoChild = 0;
  Btree *p = pCur->pBtree;
  BtShared *pBt = p->pBt;

  assert( cursorHoldsMutex(pCur) );
  assert( pPage->isInit );
  assert( pBt->inTransaction==TRANS_WRITE );




  assert( !pBt->readOnly );
  if( pCur->eState==CURSOR_FAULT ){
    return pCur->skip;
  }
  if( NEVER(pCur->aiIdx[pCur->iPage]>=pPage->nCell) ){
    return SQLITE_ERROR;  /* The cursor is not pointing to anything */
  }
  assert( pCur->wrFlag );


  if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur, pCur->info.nKey) ){
    return SQLITE_LOCKED; /* The table pCur points to has a read lock */
  }

  /* Restore the current cursor position (a no-op if the cursor is not in 
  ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors 
  ** open on the same table. Then call sqlite3PagerWrite() on the page
................................................................................
static int btreeCreateTable(Btree *p, int *piTable, int flags){
  BtShared *pBt = p->pBt;
  MemPage *pRoot;
  Pgno pgnoRoot;
  int rc;

  assert( sqlite3BtreeHoldsMutex(p) );
  assert( pBt->inTransaction==TRANS_WRITE );




  assert( !pBt->readOnly );

#ifdef SQLITE_OMIT_AUTOVACUUM
  rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
  if( rc ){
    return rc;
  }
................................................................................
** entries in the table.
*/
int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
  int rc;
  BtShared *pBt = p->pBt;
  sqlite3BtreeEnter(p);
  pBt->db = p->db;
  assert( p->inTrans==TRANS_WRITE );

  if( (rc = checkReadLocks(p, iTable, 0, 1))!=SQLITE_OK ){
    /* nothing to do */
  }else if( SQLITE_OK!=(rc = saveAllCursors(pBt, iTable, 0)) ){
    /* nothing to do */
  }else{
    rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
  }
  sqlite3BtreeLeave(p);
................................................................................
*/
static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
  int rc;
  MemPage *pPage = 0;
  BtShared *pBt = p->pBt;

  assert( sqlite3BtreeHoldsMutex(p) );
  assert( p->inTrans==TRANS_WRITE );



  /* It is illegal to drop a table if any cursors are open on the
  ** database. This is because in auto-vacuum mode the backend may
  ** need to move another root-page to fill a gap left by the deleted
  ** root page. If an open cursor was using this page a problem would 
  ** occur.
  */
................................................................................
int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
  BtShared *pBt = p->pBt;
  unsigned char *pP1;
  int rc;
  assert( idx>=1 && idx<=15 );
  sqlite3BtreeEnter(p);
  pBt->db = p->db;
  assert( p->inTrans==TRANS_WRITE );


  assert( pBt->pPage1!=0 );
  pP1 = pBt->pPage1->aData;
  rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
  if( rc==SQLITE_OK ){
    put4byte(&pP1[36 + idx*4], iMeta);
#ifndef SQLITE_OMIT_AUTOVACUUM
    if( idx==7 ){
      assert( pBt->autoVacuum || iMeta==0 );
      assert( iMeta==0 || iMeta==1 );
      pBt->incrVacuum = (u8)iMeta;
    }
#endif

  }
  sqlite3BtreeLeave(p);
  return rc;
}

/*
** Return the flag byte at the beginning of the page that the cursor
................................................................................
  /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call
  ** restoreCursorPosition() here.
  */
  MemPage *pPage;
  restoreCursorPosition(pCur);
  pPage = pCur->apPage[pCur->iPage];
  assert( cursorHoldsMutex(pCur) );
  assert( pPage!=0 );
  assert( pPage->pBt==pCur->pBt );
  return pPage->aData[pPage->hdrOffset];
}


/*
** Return the pager associated with a BTree.  This routine is used for
** testing and debugging only.
*/
................................................................................
  if( (rc = sqlite3BtreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
    if( rc==SQLITE_NOMEM ) pCheck->mallocFailed = 1;
    checkAppendMsg(pCheck, zContext,
       "unable to get the page. error code=%d", rc);
    return 0;
  }
  if( (rc = sqlite3BtreeInitPage(pPage))!=0 ){
    assert( rc==SQLITE_CORRUPT );  /* The only possible error from InitPage */
    checkAppendMsg(pCheck, zContext, 
                   "sqlite3BtreeInitPage() returns error code %d", rc);
    releasePage(pPage);
    return 0;
  }

  /* Check out all the cells.
................................................................................
    if( sCheck.anRef[i]!=0 && 
       (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
      checkAppendMsg(&sCheck, 0, "Pointer map page %d is referenced", i);
    }
#endif
  }

  /* Make sure this analysis did not leave any unref() pages.
  ** This is an internal consistency check; an integrity check
  ** of the integrity check.
  */
  unlockBtreeIfUnused(pBt);
  if( NEVER(nRef != sqlite3PagerRefcount(pBt->pPager)) ){
    checkAppendMsg(&sCheck, 0, 
      "Outstanding page count goes from %d to %d during this analysis",
      nRef, sqlite3PagerRefcount(pBt->pPager)
    );
  }

  /* Clean  up and report errors.
................................................................................
  BtShared *pBtFrom = pFrom->pBt;
  pBtTo->db = pTo->db;
  pBtFrom->db = pFrom->db;

  nToPageSize = pBtTo->pageSize;
  nFromPageSize = pBtFrom->pageSize;

  assert( pTo->inTrans==TRANS_WRITE );
  assert( pFrom->inTrans==TRANS_WRITE );

  if( NEVER(pBtTo->pCursor) ){
    return SQLITE_BUSY;
  }

  nToPage = pagerPagecount(pBtTo);
  nFromPage = pagerPagecount(pBtFrom);
  iSkip = PENDING_BYTE_PAGE(pBtTo);

................................................................................
}

/*
** Return non-zero if a statement transaction is active.
*/
int sqlite3BtreeIsInStmt(Btree *p){
  assert( sqlite3BtreeHoldsMutex(p) );
  assert( p->pBt );
  return ALWAYS(p->pBt) && p->pBt->inStmt;
}

/*
** Return non-zero if a read (or write) transaction is active.
*/
int sqlite3BtreeIsInReadTrans(Btree *p){
  assert( p );
  assert( sqlite3_mutex_held(p->db->mutex) );
  return p->inTrans!=TRANS_NONE;
}

/*
** This function returns a pointer to a blob of memory associated with
** a single shared-btree. The memory is used by client code for its own
** purposes (for example, to store a high-level schema associated with 
** the shared-btree). The btree layer manages reference counting issues.

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
234
235
236
237
238
239
240














241
242
243
244
245
246
247
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.820 2009/01/03 14:04:39 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
** option is set.  Thus NDEBUG becomes an opt-in rather than an opt-out
** feature.
*/
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
# define NDEBUG 1
#endif















#include "sqlite3.h"
#include "hash.h"
#include "parse.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.821 2009/01/09 14:11:05 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** Include the configuration header output by 'configure' if we're using the
** autoconf-based build
................................................................................
** option is set.  Thus NDEBUG becomes an opt-in rather than an opt-out
** feature.
*/
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG) 
# define NDEBUG 1
#endif

/*
** Sometimes we need a small amount of code such as a variable initialization
** to setup for a later assert() statement.  We do not want this code to
** appear when assert() is disabled.  The following macro is therefore
** used to contain that setup code.  The "VVA" acronym stands for
** "Verification, Validation, and Accreditation".  In other words, the
** code within VVA_ONLY() will only run during verification processes.
*/
#ifndef NDEBUG
# define VVA_ONLY(X)  X
#else
# define VVA_ONLY(X)
#endif

#include "sqlite3.h"
#include "hash.h"
#include "parse.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>