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

📄 btree.c

📁 sqlite数据库管理系统开放源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  pP1 = pBt->page1;  rc = sqlitepager_write(pBt->page1);  if( rc ) return rc;  rc = sqlitepager_get(pBt->pPager, 2, (void**)&pRoot);  if( rc ) return rc;  rc = sqlitepager_write(pRoot);  if( rc ){    sqlitepager_unref(pRoot);    return rc;  }  strcpy(pP1->zMagic, zMagicHeader);  if( btree_native_byte_order ){    pP1->iMagic = MAGIC;    pBt->needSwab = 0;  }else{    pP1->iMagic = swab32(MAGIC);    pBt->needSwab = 1;  }  zeroPage(pBt, pRoot);  sqlitepager_unref(pRoot);  return SQLITE_OK;}/*** Attempt to start a new transaction.**** A transaction must be started before attempting any changes** to the database.  None of the following routines will work** unless a transaction is started first:****      sqliteBtreeCreateTable()**      sqliteBtreeCreateIndex()**      sqliteBtreeClearTable()**      sqliteBtreeDropTable()**      sqliteBtreeInsert()**      sqliteBtreeDelete()**      sqliteBtreeUpdateMeta()*/static int fileBtreeBeginTrans(Btree *pBt){  int rc;  if( pBt->inTrans ) return SQLITE_ERROR;  if( pBt->readOnly ) return SQLITE_READONLY;  if( pBt->page1==0 ){    rc = lockBtree(pBt);    if( rc!=SQLITE_OK ){      return rc;    }  }  rc = sqlitepager_begin(pBt->page1);  if( rc==SQLITE_OK ){    rc = newDatabase(pBt);  }  if( rc==SQLITE_OK ){    pBt->inTrans = 1;    pBt->inCkpt = 0;  }else{    unlockBtreeIfUnused(pBt);  }  return rc;}/*** Commit the transaction currently in progress.**** This will release the write lock on the database file.  If there** are no active cursors, it also releases the read lock.*/static int fileBtreeCommit(Btree *pBt){  int rc;  rc = pBt->readOnly ? SQLITE_OK : sqlitepager_commit(pBt->pPager);  pBt->inTrans = 0;  pBt->inCkpt = 0;  unlockBtreeIfUnused(pBt);  return rc;}/*** Rollback the transaction in progress.  All cursors will be** invalided by this operation.  Any attempt to use a cursor** that was open at the beginning of this operation will result** in an error.**** This will release the write lock on the database file.  If there** are no active cursors, it also releases the read lock.*/static int fileBtreeRollback(Btree *pBt){  int rc;  BtCursor *pCur;  if( pBt->inTrans==0 ) return SQLITE_OK;  pBt->inTrans = 0;  pBt->inCkpt = 0;  rc = pBt->readOnly ? SQLITE_OK : sqlitepager_rollback(pBt->pPager);  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){    if( pCur->pPage && pCur->pPage->isInit==0 ){      sqlitepager_unref(pCur->pPage);      pCur->pPage = 0;    }  }  unlockBtreeIfUnused(pBt);  return rc;}/*** Set the checkpoint for the current transaction.  The checkpoint serves** as a sub-transaction that can be rolled back independently of the** main transaction.  You must start a transaction before starting a** checkpoint.  The checkpoint is ended automatically if the transaction** commits or rolls back.**** Only one checkpoint may be active at a time.  It is an error to try** to start a new checkpoint if another checkpoint is already active.*/static int fileBtreeBeginCkpt(Btree *pBt){  int rc;  if( !pBt->inTrans || pBt->inCkpt ){    return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;  }  rc = pBt->readOnly ? SQLITE_OK : sqlitepager_ckpt_begin(pBt->pPager);  pBt->inCkpt = 1;  return rc;}/*** Commit a checkpoint to transaction currently in progress.  If no** checkpoint is active, this is a no-op.*/static int fileBtreeCommitCkpt(Btree *pBt){  int rc;  if( pBt->inCkpt && !pBt->readOnly ){    rc = sqlitepager_ckpt_commit(pBt->pPager);  }else{    rc = SQLITE_OK;  }  pBt->inCkpt = 0;  return rc;}/*** Rollback the checkpoint to the current transaction.  If there** is no active checkpoint or transaction, this routine is a no-op.**** All cursors will be invalided by this operation.  Any attempt** to use a cursor that was open at the beginning of this operation** will result in an error.*/static int fileBtreeRollbackCkpt(Btree *pBt){  int rc;  BtCursor *pCur;  if( pBt->inCkpt==0 || pBt->readOnly ) return SQLITE_OK;  rc = sqlitepager_ckpt_rollback(pBt->pPager);  for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){    if( pCur->pPage && pCur->pPage->isInit==0 ){      sqlitepager_unref(pCur->pPage);      pCur->pPage = 0;    }  }  pBt->inCkpt = 0;  return rc;}/*** Create a new cursor for the BTree whose root is on the page** iTable.  The act of acquiring a cursor gets a read lock on ** the database file.**** If wrFlag==0, then the cursor can only be used for reading.** If wrFlag==1, then the cursor can be used for reading or for** writing if other conditions for writing are also met.  These** are the conditions that must be met in order for writing to** be allowed:**** 1:  The cursor must have been opened with wrFlag==1**** 2:  No other cursors may be open with wrFlag==0 on the same table**** 3:  The database must be writable (not on read-only media)**** 4:  There must be an active transaction.**** Condition 2 warrants further discussion.  If any cursor is opened** on a table with wrFlag==0, that prevents all other cursors from** writing to that table.  This is a kind of "read-lock".  When a cursor** is opened with wrFlag==0 it is guaranteed that the table will not** change as long as the cursor is open.  This allows the cursor to** do a sequential scan of the table without having to worry about** entries being inserted or deleted during the scan.  Cursors should** be opened with wrFlag==0 only if this read-lock property is needed.** That is to say, cursors should be opened with wrFlag==0 only if they** intend to use the sqliteBtreeNext() system call.  All other cursors** should be opened with wrFlag==1 even if they never really intend** to write.** ** No checking is done to make sure that page iTable really is the** root page of a b-tree.  If it is not, then the cursor acquired** will not work correctly.*/static int fileBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){  int rc;  BtCursor *pCur, *pRing;  if( pBt->readOnly && wrFlag ){    *ppCur = 0;    return SQLITE_READONLY;  }  if( pBt->page1==0 ){    rc = lockBtree(pBt);    if( rc!=SQLITE_OK ){      *ppCur = 0;      return rc;    }  }  pCur = sqliteMalloc( sizeof(*pCur) );  if( pCur==0 ){    rc = SQLITE_NOMEM;    goto create_cursor_exception;  }  pCur->pgnoRoot = (Pgno)iTable;  rc = sqlitepager_get(pBt->pPager, pCur->pgnoRoot, (void**)&pCur->pPage);  if( rc!=SQLITE_OK ){    goto create_cursor_exception;  }  rc = initPage(pBt, pCur->pPage, pCur->pgnoRoot, 0);  if( rc!=SQLITE_OK ){    goto create_cursor_exception;  }  pCur->pOps = &sqliteBtreeCursorOps;  pCur->pBt = pBt;  pCur->wrFlag = wrFlag;  pCur->idx = 0;  pCur->eSkip = SKIP_INVALID;  pCur->pNext = pBt->pCursor;  if( pCur->pNext ){    pCur->pNext->pPrev = pCur;  }  pCur->pPrev = 0;  pRing = pBt->pCursor;  while( pRing && pRing->pgnoRoot!=pCur->pgnoRoot ){ pRing = pRing->pNext; }  if( pRing ){    pCur->pShared = pRing->pShared;    pRing->pShared = pCur;  }else{    pCur->pShared = pCur;  }  pBt->pCursor = pCur;  *ppCur = pCur;  return SQLITE_OK;create_cursor_exception:  *ppCur = 0;  if( pCur ){    if( pCur->pPage ) sqlitepager_unref(pCur->pPage);    sqliteFree(pCur);  }  unlockBtreeIfUnused(pBt);  return rc;}/*** Close a cursor.  The read lock on the database file is released** when the last cursor is closed.*/static int fileBtreeCloseCursor(BtCursor *pCur){  Btree *pBt = pCur->pBt;  if( pCur->pPrev ){    pCur->pPrev->pNext = pCur->pNext;  }else{    pBt->pCursor = pCur->pNext;  }  if( pCur->pNext ){    pCur->pNext->pPrev = pCur->pPrev;  }  if( pCur->pPage ){    sqlitepager_unref(pCur->pPage);  }  if( pCur->pShared!=pCur ){    BtCursor *pRing = pCur->pShared;    while( pRing->pShared!=pCur ){ pRing = pRing->pShared; }    pRing->pShared = pCur->pShared;  }  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.*/static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){  memcpy(pTempCur, pCur, sizeof(*pCur));  pTempCur->pNext = 0;  pTempCur->pPrev = 0;  if( pTempCur->pPage ){    sqlitepager_ref(pTempCur->pPage);  }}/*** Delete a temporary cursor such as was made by the CreateTemporaryCursor()** function above.*/static void releaseTempCursor(BtCursor *pCur){  if( pCur->pPage ){    sqlitepager_unref(pCur->pPage);  }}/*** Set *pSize to the number of bytes of key in the entry the** cursor currently points to.  Always return SQLITE_OK.** Failure is not possible.  If the cursor is not currently** pointing to an entry (which can happen, for example, if** the database is empty) then *pSize is set to 0.*/static int fileBtreeKeySize(BtCursor *pCur, int *pSize){  Cell *pCell;  MemPage *pPage;  pPage = pCur->pPage;  assert( pPage!=0 );  if( pCur->idx >= pPage->nCell ){    *pSize = 0;  }else{    pCell = pPage->apCell[pCur->idx];    *pSize = NKEY(pCur->pBt, pCell->h);  }  return SQLITE_OK;}/*** 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.*/static int getPayload(BtCursor *pCur, int offset, int amt, char *zBuf){  char *aPayload;  Pgno nextPage;  int rc;  Btree *pBt = pCur->pBt;  assert( pCur!=0 && pCur->pPage!=0 );  assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );  aPayload = pCur->pPage->apCell[pCur->idx]->aPayload;  if( offset<MX_LOCAL_PAYLOAD ){    int a = amt;    if( a+offset>MX_LOCAL_PAYLOAD ){      a = MX_LOCAL_PAYLOAD - offset;    }    memcpy(zBuf, &aPayload[offset], a);    if( a==amt ){      return SQLITE_OK;    }    offset = 0;    zBuf += a;    amt -= a;  }else{    offset -= MX_LOCAL_PAYLOAD;  }  if( amt>0 ){    nextPage = SWAB32(pBt, pCur->pPage->apCell[pCur->idx]->ovfl);  }  while( amt>0 && nextPage ){    OverflowPage *pOvfl;    rc = sqlitepager_get(pBt->pPager, nextPage, (void**)&pOvfl);    if( rc!=0 ){      return rc;    }    nextPage = SWAB32(pBt, pOvfl->iNext);    if( offset<OVERFLOW_SIZE ){      int a = amt;      if( a + offset > OVERFLOW_SIZE ){        a = OVERFLOW_SIZE - offset;      }      memcpy(zBuf, &pOvfl->aPayload[offset], a);      offset = 0;      amt -= a;      zBuf += a;    }else{      offset -= OVERFLOW_SIZE;    }    sqlitepager_unref(pOvfl);  }  if( amt>0 ){    return SQLITE_CORRUPT;  }  return SQLITE_OK;}/*** Read part of the key associated with cursor pCur.  A maximum** of "amt" bytes will be transfered into zBuf[].  The transfer** begins at "offset".  The number of bytes actually read is** returned. **** Change:  It used to be that the amount returned will be smaller** than the amount requested if there are not enough bytes in the key** to satisfy the request.  But now, it must be the case that there** is enough data available to satisfy the request.  If not, an exception** is raised.  The change was made in an effort to boost performance** by eliminating unneeded tests.*/static int fileBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){  MemPage *pPage;  assert( amt>=0 );  assert( offset>=0 );  assert( pCur->pPage!=0 );  pPage = pCur->pPage;  if( pCur->idx >= pPage->nCell ){    return 0;  }  assert( amt+offset <= NKEY(pCur->pBt, pPage->apCell[pCur->idx]->h) );  getPayload(pCur, offset, amt, zBuf);  return amt;

⌨️ 快捷键说明

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