⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 btree.c

📁 sqlite 3.3.8 支持加密的版本
💻 C
📖 第 1 页 / 共 5 页
字号:
  pPage->idxShift = 0;
  pPage->nCell = 0;
  pPage->isInit = 1;
  pageIntegrity(pPage);
}

/*
** Get a page from the pager.  Initialize the MemPage.pBt and
** MemPage.aData elements if needed.
*/
static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){
  int rc;
  unsigned char *aData;
  MemPage *pPage;
  rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData);
  if( rc ) return rc;
  pPage = (MemPage*)&aData[pBt->pageSize];
  pPage->aData = aData;
  pPage->pBt = pBt;
  pPage->pgno = pgno;
  pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
  *ppPage = pPage;
  return SQLITE_OK;
}

/*
** Get a page from the pager and initialize it.  This routine
** is just a convenience wrapper around separate calls to
** getPage() and initPage().
*/
static int getAndInitPage(
  BtShared *pBt,          /* The database file */
  Pgno pgno,           /* Number of the page to get */
  MemPage **ppPage,    /* Write the page pointer here */
  MemPage *pParent     /* Parent of the page */
){
  int rc;
  if( pgno==0 ){
    return SQLITE_CORRUPT_BKPT; 
  }
  rc = getPage(pBt, pgno, ppPage);
  if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
    rc = initPage(*ppPage, pParent);
  }
  return rc;
}

/*
** Release a MemPage.  This should be called once for each prior
** call to getPage.
*/
static void releasePage(MemPage *pPage){
  if( pPage ){
    assert( pPage->aData );
    assert( pPage->pBt );
    assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );
    sqlite3pager_unref(pPage->aData);
  }
}

/*
** This routine is called when the reference count for a page
** reaches zero.  We need to unref the pParent pointer when that
** happens.
*/
static void pageDestructor(void *pData, int pageSize){
  MemPage *pPage;
  assert( (pageSize & 7)==0 );
  pPage = (MemPage*)&((char*)pData)[pageSize];
  if( pPage->pParent ){
    MemPage *pParent = pPage->pParent;
    pPage->pParent = 0;
    releasePage(pParent);
  }
  pPage->isInit = 0;
}

/*
** During a rollback, when the pager reloads information into the cache
** so that the cache is restored to its original state at the start of
** the transaction, for each page restored this routine is called.
**
** This routine needs to reset the extra data section at the end of the
** page to agree with the restored data.
*/
static void pageReinit(void *pData, int pageSize){
  MemPage *pPage;
  assert( (pageSize & 7)==0 );
  pPage = (MemPage*)&((char*)pData)[pageSize];
  if( pPage->isInit ){
    pPage->isInit = 0;
    initPage(pPage, pPage->pParent);
  }
}

/*
** Open a database file.
** 
** zFilename is the name of the database file.  If zFilename is NULL
** a new database with a random name is created.  This randomly named
** database file will be deleted when sqlite3BtreeClose() is called.
*/
int sqlite3BtreeOpen(
  const char *zFilename,  /* Name of the file containing the BTree database */
  sqlite3 *pSqlite,       /* Associated database handle */
  Btree **ppBtree,        /* Pointer to new Btree object written here */
  int flags               /* Options */
){
  BtShared *pBt;          /* Shared part of btree structure */
  Btree *p;               /* Handle to return */
  int rc;
  int nReserve;
  unsigned char zDbHeader[100];
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
  const ThreadData *pTsdro;
#endif

  /* Set the variable isMemdb to true for an in-memory database, or 
  ** false for a file-based database. This symbol is only required if
  ** either of the shared-data or autovacuum features are compiled 
  ** into the library.
  */
#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
  #ifdef SQLITE_OMIT_MEMORYDB
    const int isMemdb = 0;
  #else
    const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
  #endif
#endif

  p = sqliteMalloc(sizeof(Btree));
  if( !p ){
    return SQLITE_NOMEM;
  }
  p->inTrans = TRANS_NONE;
  p->pSqlite = pSqlite;

  /* Try to find an existing Btree structure opened on zFilename. */
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
  pTsdro = sqlite3ThreadDataReadOnly();
  if( pTsdro->useSharedData && zFilename && !isMemdb ){
    char *zFullPathname = sqlite3OsFullPathname(zFilename);
    if( !zFullPathname ){
      sqliteFree(p);
      return SQLITE_NOMEM;
    }
    for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){
      assert( pBt->nRef>0 );
      if( 0==strcmp(zFullPathname, sqlite3pager_filename(pBt->pPager)) ){
        p->pBt = pBt;
        *ppBtree = p;
        pBt->nRef++;
        sqliteFree(zFullPathname);
        return SQLITE_OK;
      }
    }
    sqliteFree(zFullPathname);
  }
#endif

  /*
  ** The following asserts make sure that structures used by the btree are
  ** the right size.  This is to guard against size changes that result
  ** when compiling on a different architecture.
  */
  assert( sizeof(i64)==8 || sizeof(i64)==4 );
  assert( sizeof(u64)==8 || sizeof(u64)==4 );
  assert( sizeof(u32)==4 );
  assert( sizeof(u16)==2 );
  assert( sizeof(Pgno)==4 );

  pBt = sqliteMalloc( sizeof(*pBt) );
  if( pBt==0 ){
    *ppBtree = 0;
    sqliteFree(p);
    return SQLITE_NOMEM;
  }
  rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
  if( rc!=SQLITE_OK ){
    if( pBt->pPager ) sqlite3pager_close(pBt->pPager);
    sqliteFree(pBt);
    sqliteFree(p);
    *ppBtree = 0;
    return rc;
  }
  p->pBt = pBt;

  sqlite3pager_set_destructor(pBt->pPager, pageDestructor);
  sqlite3pager_set_reiniter(pBt->pPager, pageReinit);
  pBt->pCursor = 0;
  pBt->pPage1 = 0;
  pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
  sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader);
  pBt->pageSize = get2byte(&zDbHeader[16]);
  if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
       || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
    pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE;
    pBt->maxEmbedFrac = 64;   /* 25% */
    pBt->minEmbedFrac = 32;   /* 12.5% */
    pBt->minLeafFrac = 32;    /* 12.5% */
#ifndef SQLITE_OMIT_AUTOVACUUM
    /* If the magic name ":memory:" will create an in-memory database, then
    ** do not set the auto-vacuum flag, even if SQLITE_DEFAULT_AUTOVACUUM
    ** is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined,
    ** then ":memory:" is just a regular file-name. Respect the auto-vacuum
    ** default in this case.
    */
    if( zFilename && !isMemdb ){
      pBt->autoVacuum = SQLITE_DEFAULT_AUTOVACUUM;
    }
#endif
    nReserve = 0;
  }else{
    nReserve = zDbHeader[20];
    pBt->maxEmbedFrac = zDbHeader[21];
    pBt->minEmbedFrac = zDbHeader[22];
    pBt->minLeafFrac = zDbHeader[23];
    pBt->pageSizeFixed = 1;
#ifndef SQLITE_OMIT_AUTOVACUUM
    pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);
#endif
  }
  pBt->usableSize = pBt->pageSize - nReserve;
  assert( (pBt->pageSize & 7)==0 );  /* 8-byte alignment of pageSize */
  sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);

#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
  /* Add the new btree to the linked list starting at ThreadData.pBtree.
  ** There is no chance that a malloc() may fail inside of the 
  ** sqlite3ThreadData() call, as the ThreadData structure must have already
  ** been allocated for pTsdro->useSharedData to be non-zero.
  */
  if( pTsdro->useSharedData && zFilename && !isMemdb ){
    pBt->pNext = pTsdro->pBtree;
    sqlite3ThreadData()->pBtree = pBt;
  }
#endif
  pBt->nRef = 1;
  *ppBtree = p;
  return SQLITE_OK;
}

/*
** Close an open database and invalidate all cursors.
*/
int sqlite3BtreeClose(Btree *p){
  BtShared *pBt = p->pBt;
  BtCursor *pCur;

#ifndef SQLITE_OMIT_SHARED_CACHE
  ThreadData *pTsd;
#endif

  /* Close all cursors opened via this handle.  */
  pCur = pBt->pCursor;
  while( pCur ){
    BtCursor *pTmp = pCur;
    pCur = pCur->pNext;
    if( pTmp->pBtree==p ){
      sqlite3BtreeCloseCursor(pTmp);
    }
  }

  /* Rollback any active transaction and free the handle structure.
  ** The call to sqlite3BtreeRollback() drops any table-locks held by
  ** this handle.
  */
  sqlite3BtreeRollback(p);
  sqliteFree(p);

#ifndef SQLITE_OMIT_SHARED_CACHE
  /* If there are still other outstanding references to the shared-btree
  ** structure, return now. The remainder of this procedure cleans 
  ** up the shared-btree.
  */
  assert( pBt->nRef>0 );
  pBt->nRef--;
  if( pBt->nRef ){
    return SQLITE_OK;
  }

  /* Remove the shared-btree from the thread wide list. Call 
  ** ThreadDataReadOnly() and then cast away the const property of the 
  ** pointer to avoid allocating thread data if it is not really required.
  */
  pTsd = (ThreadData *)sqlite3ThreadDataReadOnly();
  if( pTsd->pBtree==pBt ){
    assert( pTsd==sqlite3ThreadData() );
    pTsd->pBtree = pBt->pNext;
  }else{
    BtShared *pPrev;
    for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext){}
    if( pPrev ){
      assert( pTsd==sqlite3ThreadData() );
      pPrev->pNext = pBt->pNext;
    }
  }
#endif

  /* Close the pager and free the shared-btree structure */
  assert( !pBt->pCursor );
  sqlite3pager_close(pBt->pPager);
  if( pBt->xFreeSchema && pBt->pSchema ){
    pBt->xFreeSchema(pBt->pSchema);
  }
  sqliteFree(pBt->pSchema);
  sqliteFree(pBt);
  return SQLITE_OK;
}

/*
** Change the busy handler callback function.
*/
int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
  BtShared *pBt = p->pBt;
  pBt->pBusyHandler = pHandler;
  sqlite3pager_set_busyhandler(pBt->pPager, pHandler);
  return SQLITE_OK;
}

/*
** Change the limit on the number of pages allowed in the cache.
**
** The maximum number of cache pages is set to the absolute
** value of mxPage.  If mxPage is negative, the pager will
** operate asynchronously - it will not stop to do fsync()s
** to insure data is written to the disk surface before
** continuing.  Transactions still work if synchronous is off,
** and the database cannot be corrupted if this program
** crashes.  But if the operating system crashes or there is
** an abrupt power failure when synchronous is off, the database
** could be left in an inconsistent and unrecoverable state.
** Synchronous is on by default so database corruption is not
** normally a worry.
*/
int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
  BtShared *pBt = p->pBt;
  sqlite3pager_set_cachesize(pBt->pPager, mxPage);
  return SQLITE_OK;
}

/*
** Change the way data is synced to disk in order to increase or decrease
** how well the database resists damage due to OS crashes and power
** failures.  Level 1 is the same as asynchronous (no syncs() occur and
** there is a high probability of damage)  Level 2 is the default.  There
** is a very low but non-zero probability of damage.  Level 3 reduces the
** probability of damage to near zero but with a write performance reduction.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
  BtShared *pBt = p->pBt;
  sqlite3pager_set_safety_level(pBt->pPager, level, fullSync);
  return SQLITE_OK;
}
#endif

/*
** Return TRUE if the given btree is set to safety level 1.  In other
** words, return TRUE if no sync() occurs on the disk files.
*/
int sqlite3BtreeSyncDisabled(Btree *p){
  BtShared *pBt = p->pBt;
  assert( pBt && pBt->pPager );
  return sqlite3pager_nosync(pBt->p

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -