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

📄 btree.c

📁 嵌入式数据库Sqlite,SQLlite小型数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
** MemPage.aCell[] of the entry.*/struct BtCursor {  Btree *pBtree;            /* The Btree to which this cursor belongs */  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */  int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */  void *pArg;               /* First arg to xCompare() */  Pgno pgnoRoot;            /* The root page of this tree */  MemPage *pPage;           /* Page that contains the entry */  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) */#ifndef SQLITE_OMIT_SHARED_CACHE  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 */#endif};/*** Potential values for BtCursor.eState. The first two values (VALID and ** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur ** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined.**** CURSOR_VALID:**   Cursor points to a valid entry. getPayload() etc. may be called.**** CURSOR_INVALID:**   Cursor does not point to a valid entry. This can happen (for example) **   because the table is empty or because BtreeCursorFirst() has not been**   called.**** CURSOR_REQUIRESEEK:**   The table that this cursor was opened on still exists, but has been **   modified since the cursor was last used. The cursor position is saved**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in **   this state, restoreOrClearCursorPosition() can be called to attempt to**   seek the cursor to the saved position.*/#define CURSOR_INVALID           0#define CURSOR_VALID             1#define CURSOR_REQUIRESEEK       2/*** The TRACE macro will print high-level status information about the** btree operation when the global variable sqlite3_btree_trace is** enabled.*/#if SQLITE_TEST# define TRACE(X)   if( sqlite3_btree_trace )\                        { sqlite3DebugPrintf X; fflush(stdout); }#else# define TRACE(X)#endifint sqlite3_btree_trace=0;  /* True to enable tracing *//*** Forward declaration*/static int checkReadLocks(BtShared*,Pgno,BtCursor*);/*** Read or write a two- and four-byte big-endian integer values.*/static u32 get2byte(unsigned char *p){  return (p[0]<<8) | p[1];}static u32 get4byte(unsigned char *p){  return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];}static void put2byte(unsigned char *p, u32 v){  p[0] = v>>8;  p[1] = v;}static void put4byte(unsigned char *p, u32 v){  p[0] = v>>24;  p[1] = v>>16;  p[2] = v>>8;  p[3] = v;}/*** Routines to read and write variable-length integers.  These used to** be defined locally, but now we use the varint routines in the util.c** file.*/#define getVarint    sqlite3GetVarint/* #define getVarint32  sqlite3GetVarint32 */#define getVarint32(A,B)  ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))#define putVarint    sqlite3PutVarint/* The database page the PENDING_BYTE occupies. This page is never used.** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They** should possibly be consolidated (presumably in pager.h).**** If disk I/O is omitted (meaning that the database is stored purely** in memory) then there is no pending byte.*/#ifdef SQLITE_OMIT_DISKIO# define PENDING_BYTE_PAGE(pBt)  0x7fffffff#else# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)#endif/*** A linked list of the following structures is stored at BtShared.pLock.** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor ** is opened on the table with root page BtShared.iTable. Locks are removed** from this list when a transaction is committed or rolled back, or when** a btree handle is closed.*/struct BtLock {  Btree *pBtree;        /* Btree handle holding this lock */  Pgno iTable;          /* Root page of table */  u8 eLock;             /* READ_LOCK or WRITE_LOCK */  BtLock *pNext;        /* Next in BtShared.pLock list */};/* Candidate values for BtLock.eLock */#define READ_LOCK     1#define WRITE_LOCK    2#ifdef SQLITE_OMIT_SHARED_CACHE  /*  ** The functions queryTableLock(), lockTable() and unlockAllTables()  ** manipulate entries in the BtShared.pLock linked list used to store  ** shared-cache table level locks. If the library is compiled with the  ** shared-cache feature disabled, then there is only ever one user  ** of each BtShared structure and so this locking is not necessary.   ** So define the lock related functions as no-ops.  */  #define queryTableLock(a,b,c) SQLITE_OK  #define lockTable(a,b,c) SQLITE_OK  #define unlockAllTables(a)  #define restoreOrClearCursorPosition(a,b) SQLITE_OK  #define saveAllCursors(a,b,c) SQLITE_OK#elsestatic void releasePage(MemPage *pPage);/*** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.*/static int saveCursorPosition(BtCursor *pCur){  int rc;  assert( CURSOR_VALID==pCur->eState );  assert( 0==pCur->pKey );  rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);  /* If this is an intKey table, then the above call to BtreeKeySize()  ** stores the integer key in pCur->nKey. In this case this value is  ** all that is required. Otherwise, if pCur is not open on an intKey  ** table, then malloc space for and store the pCur->nKey bytes of key   ** data.  */  if( rc==SQLITE_OK && 0==pCur->pPage->intKey){    void *pKey = sqliteMalloc(pCur->nKey);    if( pKey ){      rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);      if( rc==SQLITE_OK ){        pCur->pKey = pKey;      }else{        sqliteFree(pKey);      }    }else{      rc = SQLITE_NOMEM;    }  }  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** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).*/static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){  BtCursor *p;  if( sqlite3ThreadDataReadOnly()->useSharedData ){    for(p=pBt->pCursor; p; p=p->pNext){      if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&           p->eState==CURSOR_VALID ){        int rc = saveCursorPosition(p);        if( SQLITE_OK!=rc ){          return rc;        }      }    }  }  return SQLITE_OK;}/*** Restore the cursor to the position it was in (or as close to as possible)** when saveCursorPosition() was called. Note that this call deletes the ** saved position info stored by saveCursorPosition(), so there can be** at most one effective restoreOrClearCursorPosition() call after each ** saveCursorPosition().**** If the second argument argument - doSeek - is false, then instead of ** returning the cursor to it's saved position, any saved position is deleted** and the cursor state set to CURSOR_INVALID.*/static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){  int rc = SQLITE_OK;  assert( sqlite3ThreadDataReadOnly()->useSharedData );  assert( pCur->eState==CURSOR_REQUIRESEEK );  pCur->eState = CURSOR_INVALID;  if( doSeek ){    rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);  }  if( rc==SQLITE_OK ){    sqliteFree(pCur->pKey);    pCur->pKey = 0;    assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );  }  return rc;}#define restoreOrClearCursorPosition(p,x) \  (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)/*** Query to see if btree handle p may obtain a lock of type eLock ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return** SQLITE_OK if the lock may be obtained (by calling lockTable()), or** SQLITE_LOCKED if not.*/static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){  BtShared *pBt = p->pBt;  BtLock *pIter;  /* This is a no-op if the shared-cache is not enabled */  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){    return SQLITE_OK;  }  /* This (along with lockTable()) is where the ReadUncommitted flag is  ** dealt with. If the caller is querying for a read-lock and the flag is  ** set, it is unconditionally granted - even if there are write-locks  ** on the table. If a write-lock is requested, the ReadUncommitted flag  ** is not considered.  **  ** In function lockTable(), if a read-lock is demanded and the   ** ReadUncommitted flag is set, no entry is added to the locks list   ** (BtShared.pLock).  **  ** To summarize: If the ReadUncommitted flag is set, then read cursors do  ** not create or respect table locks. The locking procedure for a   ** write-cursor does not change.  */  if(     !p->pSqlite ||     0==(p->pSqlite->flags&SQLITE_ReadUncommitted) ||     eLock==WRITE_LOCK ||    iTab==MASTER_ROOT  ){    for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){      if( pIter->pBtree!=p && pIter->iTable==iTab &&           (pIter->eLock!=eLock || eLock!=READ_LOCK) ){        return SQLITE_LOCKED;      }    }  }  return SQLITE_OK;}/*** Add a lock on the table with root-page iTable to the shared-btree used** by Btree handle p. Parameter eLock must be either READ_LOCK or ** WRITE_LOCK.**** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and** SQLITE_NOMEM may also be returned.*/static int lockTable(Btree *p, Pgno iTable, u8 eLock){  BtShared *pBt = p->pBt;  BtLock *pLock = 0;  BtLock *pIter;  /* This is a no-op if the shared-cache is not enabled */  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){    return SQLITE_OK;  }  assert( SQLITE_OK==queryTableLock(p, iTable, eLock) );  /* If the read-uncommitted flag is set and a read-lock is requested,  ** return early without adding an entry to the BtShared.pLock list. See  ** comment in function queryTableLock() for more info on handling   ** the ReadUncommitted flag.  */  if(     (p->pSqlite) &&     (p->pSqlite->flags&SQLITE_ReadUncommitted) &&     (eLock==READ_LOCK) &&    iTable!=MASTER_ROOT  ){    return SQLITE_OK;  }  /* First search the list for an existing lock on this table. */  for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){    if( pIter->iTable==iTable && pIter->pBtree==p ){      pLock = pIter;      break;    }  }  /* If the above search did not find a BtLock struct associating Btree p  ** with table iTable, allocate one and link it into the list.  */  if( !pLock ){    pLock = (BtLock *)sqliteMalloc(sizeof(BtLock));    if( !pLock ){      return SQLITE_NOMEM;    }    pLock->iTable = iTable;    pLock->pBtree = p;    pLock->pNext = pBt->pLock;    pBt->pLock = pLock;  }  /* Set the BtLock.eLock variable to the maximum of the current lock  ** and the requested lock. This means if a write-lock was already held  ** and a read-lock requested, we don't incorrectly downgrade the lock.  */  assert( WRITE_LOCK>READ_LOCK );  if( eLock>pLock->eLock ){    pLock->eLock = eLock;  }  return SQLITE_OK;}/*** Release all the table locks (locks obtained via calls to the lockTable()** procedure) held by Btree handle p.*/static void unlockAllTables(Btree *p){  BtLock **ppIter = &p->pBt->pLock;  /* If the shared-cache extension is not enabled, there should be no  ** locks in the BtShared.pLock list, making this procedure a no-op. Assert  ** that this is the case.  */  assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter );  while( *ppIter ){    BtLock *pLock = *ppIter;    if( pLock->pBtree==p ){      *ppIter = pLock->pNext;      sqliteFree(pLock);    }else{      ppIter = &pLock->pNext;    }  }}#endif /* SQLITE_OMIT_SHARED_CACHE */#ifndef SQLITE_OMIT_AUTOVACUUM/*** These macros define the location of the pointer-map entry for a 

⌨️ 快捷键说明

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