diff --git a/include/sqlite3.h b/include/sqlite3.h
index 445640f4740f6a93ce7323c37761e930c4b8fa41..e383b927b2cd41c578f4232af4fbc066679eca64 100644
--- a/include/sqlite3.h
+++ b/include/sqlite3.h
@@ -2120,6 +2120,21 @@ struct sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_CORRUPTION]]
SQLITE_CONFIG_CORRUPTION
+** The SQLITE_CONFIG_CORRUPTION option is used to configure the SQLite
+** global [ corruption error].
+** (^The SQLITE_CONFIG_CORRUPTION option takes two arguments: a pointer to a
+** function with a call signature of void(*)(void*,const void*),
+** and a pointer to void. ^If the function pointer is not NULL, it is
+** invoked to process each data corruption event. ^If the
+** function pointer is NULL, no=op will do when corruption detect.
+** ^The void pointer that is the second argument to SQLITE_CONFIG_CORRUPTION is
+** passed through as the first parameter to the application-defined corruption
+** function whenever that function is invoked. ^The second parameter to
+** the corruption function is a corruption message after formatting via [sqlite3_snprintf()].
+** In a multi-threaded application, the application-defined corruption
+** function must be threadsafe.
**
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2151,6 +2166,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
+#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */
/*
** CAPI3REF: Database Connection Configuration Options
diff --git a/src/sqlite3.c b/src/sqlite3.c
index dedbd85ba209a50e2259e59a285591b3c6d592e8..d377a63db8029e0775bfd107211ce0cc8e34dbd5 100644
--- a/src/sqlite3.c
+++ b/src/sqlite3.c
@@ -874,6 +874,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
+#define SQLITE_WARNING_DUMP (SQLITE_WARNING | (2<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */
@@ -2430,6 +2431,21 @@ struct sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_CORRUPTION]] SQLITE_CONFIG_CORRUPTION
+** The SQLITE_CONFIG_CORRUPTION option is used to configure the SQLite
+** global [ corruption error].
+** (^The SQLITE_CONFIG_CORRUPTION option takes two arguments: a pointer to a
+** function with a call signature of void(*)(void*,const void*),
+** and a pointer to void. ^If the function pointer is not NULL, it is
+** invoked to process each data corruption event. ^If the
+** function pointer is NULL, no=op will do when corruption detect.
+** ^The void pointer that is the second argument to SQLITE_CONFIG_CORRUPTION is
+** passed through as the first parameter to the application-defined corruption
+** function whenever that function is invoked. ^The second parameter to
+** the corruption function is a corruption message after formatting via [sqlite3_snprintf()].
+** In a multi-threaded application, the application-defined corruption
+** function must be threadsafe.
**
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -2461,6 +2477,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
+#define SQLITE_CONFIG_CORRUPTION 30 /* xCorruption */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -19541,6 +19558,8 @@ struct Sqlite3Config {
int iOnceResetThreshold; /* When to reset OP_Once counters */
u32 szSorterRef; /* Min size in bytes to use sorter-refs */
unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */
+ void (*xCorruption)(void *, const void *);
+ void *pCorruptionArg;
/* vvvv--- must be last ---vvv */
#ifdef SQLITE_DEBUG
sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */
@@ -19792,6 +19811,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis
} \
}
+#define SQLITE_PRINT_CORRUPT_SIZE (SQLITE_PRINT_BUF_SIZE * 5)
+
+#define SQLITE_CORRUPT_CONTEXT(N,P,T,O,S,M,R) \
+ { .nPage=(N), .pgno=(P), .type=(T), \
+ .zoneRange={(O),(S)}, .zMsg=(M), .reservedArgs=(R) }
+
+typedef struct {
+ int offset;
+ size_t size;
+}sqlite3CorruptRange;
+
+typedef enum {
+ CORRUPT_TYPE_PAGE_BTREE_LEAF,
+ CORRUPT_TYPE_PAGE_BTREE_INTERIOR,
+ CORRUPT_TYPE_PAGE_INDEX_LEAF,
+ CORRUPT_TYPE_PAGE_INDEX_INTERIOR,
+ CORRUPT_TYPE_PAGE_OVERFLOW,
+ CORRUPT_TYPE_PAGE_PTR_MAP,
+ CORRUPT_TYPE_PAGE_FREE_LIST,
+ CORRUPT_TYPE_FRAME_WAL,
+ CORRUPT_TYPE_ENTRY_JOURNAL,
+ CORRUPT_TYPE_VDBE,
+ CORRUPT_TYPE_FILE_HEADER,
+ CORRUPT_TYPE_UNKOWN,
+} CorruptType;
+
+typedef struct {
+ size_t nPage; /* Number of pages */
+ unsigned int pgno; /* Page number for corrupted page */
+ CorruptType type;
+ sqlite3CorruptRange zoneRange;
+ const char *zMsg;
+ void *reservedArgs;
+}sqlite3CorruptContext;
+
+// Encode buffer with base16, return size after encode
+static size_t sqlite3base16Encode(const unsigned char *buffer, size_t bufSize, char *encodeBuf, size_t encodeBufSize)
+{
+ if (buffer == NULL || bufSize == 0 || encodeBuf == NULL || encodeBufSize == 0) {
+ return 0;
+ }
+ static const char base16Code[] = "0123456789ABCDEF";
+ size_t i = 0;
+ for (; i < bufSize && (i * 2 < encodeBufSize - 1); i++) {
+ *encodeBuf++ = base16Code[(buffer[i] >> 4) & 0x0F];
+ *encodeBuf++ = base16Code[buffer[i] & 0x0F];
+ }
+ *encodeBuf = '\0';
+ return i * 2;
+}
+
/*
** The SQLITE_*_BKPT macros are substitutes for the error codes with
** the same name but without the _BKPT suffix. These macros invoke
@@ -19800,10 +19870,11 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis
** to set a debugger breakpoint.
*/
SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType);
-SQLITE_PRIVATE int sqlite3CorruptError(int);
+SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context);
SQLITE_PRIVATE int sqlite3MisuseError(int);
SQLITE_PRIVATE int sqlite3CantopenError(int);
-#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__)
+#define SQLITE_CORRUPT_REPORT(context) sqlite3CorruptError(__LINE__,(context))
+#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__,NULL)
#define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__)
#define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__)
#ifdef SQLITE_DEBUG
@@ -19817,10 +19888,11 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
-# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
+# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptPgnoError(__LINE__,(P),(context))
#else
-# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
+# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptError(__LINE__,(context))
#endif
+# define SQLITE_CORRUPT_REPORT_PGNO(context) SQLITE_CORRUPT_PGNO((context)->pgno,(context))
/*
** FTS3 and FTS4 both require virtual table support
@@ -36784,6 +36856,44 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
#endif
/************** End of os_kv.c ***********************************************/
+/************** Define dump function *****************************************/
+#if SQLITE_OS_UNIX
+#define DB_LOCK_NUM 3
+#define WAL_LOCK_NUM 9
+// 8 wal lock, 1 SHM_DMS lock, 1 TRX lock
+#define MAX_LOCK_NUM (WAL_LOCK_NUM + 1)
+#define SHM_DMS_IDX (WAL_LOCK_NUM - 1)
+#define TRX_LOCK_IDX WAL_LOCK_NUM
+#define LOCK_BY_PROCESS 1
+#define LOCK_BY_THREAD 0
+#define DUMP_BUF_MAX_LEN 180
+#define DUMP_MAX_STR_LEN 21
+
+typedef struct LocalLockStatus {
+ u8 busyLockIdx;
+ u8 busyLockType;
+ u8 lockByProcess;
+ u8 reserved;
+ u32 lockLen;
+ u32 busyLine;
+ u8 lockStatus[MAX_LOCK_NUM]; // last index is trx lock
+} LocalLockStatus;
+__thread LocalLockStatus g_lockStatus = {0};
+
+#define MARK_LAST_BUSY_LINE(rc) {if ((rc)==SQLITE_BUSY || (rc) == SQLITE_LOCKED) g_lockStatus.busyLine = __LINE__;}
+static void ResetLockStatus(void);
+static void TryRecordTid(int *tidBuf, int ofs, int lockLen);
+static void TryClearTid(int *tidBuf, int ofs, int lockLen);
+static void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess);
+static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType);
+static void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess);
+#else
+#define MARK_LAST_BUSY_LINE(rc)
+#define ResetLockStatus(void)
+#define MarkLockBusy(A, B, C, D)
+#define MarkLockStatusByRc(A, B, C, D, E)
+#endif
+/************** End define dump function *************************************/
/************** Begin file os_unix.c *****************************************/
/*
** 2004 May 22
@@ -38558,6 +38668,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
if( pFile->eFileLock>=eFileLock ){
OSTRACE(("LOCK %d %s ok (already held) (unix)\n", pFile->h,
azFileLock(eFileLock)));
+ MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock);
return SQLITE_OK;
}
@@ -38582,6 +38693,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
(pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
){
rc = SQLITE_BUSY;
+ MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD);
goto end_lock;
}
@@ -38597,6 +38709,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
pFile->eFileLock = SHARED_LOCK;
pInode->nShared++;
pInode->nLock++;
+ MarkLockStatus(TRX_LOCK_IDX, 1, eFileLock);
goto end_lock;
}
@@ -38618,11 +38731,11 @@ static int unixLock(sqlite3_file *id, int eFileLock){
if( rc!=SQLITE_BUSY ){
storeLastErrno(pFile, tErrno);
}
+ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS);
goto end_lock;
}
}
-
/* If control gets to this point, then actually go ahead and make
** operating system calls for the specified lock.
*/
@@ -38638,7 +38751,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
tErrno = errno;
rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
}
-
+ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS);
/* Drop the temporary PENDING lock */
lock.l_start = PENDING_BYTE;
lock.l_len = 1L;
@@ -38663,6 +38776,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
/* We are trying for an exclusive lock but another thread in this
** same process is still holding a shared lock. */
rc = SQLITE_BUSY;
+ MarkLockBusy(TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_THREAD);
}else{
/* The request was for a RESERVED or EXCLUSIVE lock. It is
** assumed that there is a SHARED or greater lock on the file
@@ -38687,6 +38801,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
storeLastErrno(pFile, tErrno);
}
}
+ MarkLockStatusByRc(rc, TRX_LOCK_IDX, 1, eFileLock, LOCK_BY_PROCESS);
}
@@ -38884,7 +38999,6 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
pFile->eFileLock = NO_LOCK;
}
}
-
/* Decrement the count of locks against this same file. When the
** count reaches zero, close any other file descriptors whose close
** was deferred because of outstanding locks.
@@ -41196,6 +41310,7 @@ struct unixShmNode {
int nRef; /* Number of unixShm objects pointing to this */
unixShm *pFirst; /* All unixShm objects pointing to this */
int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
+ int aLockTid[SQLITE_SHM_NLOCK];
#ifdef SQLITE_DEBUG
u8 exclMask; /* Mask of exclusive locks held */
u8 sharedMask; /* Mask of shared locks held */
@@ -41438,6 +41553,8 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
rc = SQLITE_READONLY_CANTINIT;
}else{
rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
+ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, EXCLUSIVE_LOCK, LOCK_BY_PROCESS);
+ MARK_LAST_BUSY_LINE(rc);
/* The first connection to attach must truncate the -shm file. We
** truncate to 3 bytes (an arbitrary small number, less than the
** -shm header size) rather than 0 as a system debugging aid, to
@@ -41449,11 +41566,15 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
}
}else if( lock.l_type==F_WRLCK ){
rc = SQLITE_BUSY;
+ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS);
+ MARK_LAST_BUSY_LINE(rc);
}
if( rc==SQLITE_OK ){
assert( lock.l_type==F_UNLCK || lock.l_type==F_RDLCK );
rc = unixShmSystemLock(pDbFd, F_RDLCK, UNIX_SHM_DMS, 1);
+ MarkLockStatusByRc(rc, SHM_DMS_IDX, 1, SHARED_LOCK, LOCK_BY_PROCESS);
+ MARK_LAST_BUSY_LINE(rc);
}
return rc;
}
@@ -41838,7 +41959,7 @@ static int unixShmLock(
return SQLITE_IOERR_SHMLOCK;
}
aLock = pShmNode->aLock;
-
+ int *aLockTid = pShmNode->aLockTid;
assert( pShmNode==pDbFd->pInode->pShmNode );
assert( pShmNode->pInode==pDbFd->pInode );
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
@@ -41877,6 +41998,7 @@ static int unixShmLock(
assert( n>1 || mask==(1<pShmMutex);
assert( assertLockingArrayOk(pShmNode) );
+ u8 useProcessLock = LOCK_BY_THREAD;
if( flags & SQLITE_SHM_UNLOCK ){
if( (p->exclMask|p->sharedMask) & mask ){
int ii;
@@ -41887,21 +42009,22 @@ static int unixShmLock(
bUnlock = 0;
}
}
-
if( bUnlock ){
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
memset(&aLock[ofst], 0, sizeof(int)*n);
}
+ useProcessLock = LOCK_BY_PROCESS;
}else if( ALWAYS(p->sharedMask & (1<1 );
aLock[ofst]--;
}
-
+ MarkLockStatusByRc(rc, ofst, n, NO_LOCK, useProcessLock);
/* Undo the local locks */
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
+ TryClearTid(aLockTid, ofst, n);
}
}
}else if( flags & SQLITE_SHM_SHARED ){
@@ -41912,12 +42035,14 @@ static int unixShmLock(
rc = SQLITE_BUSY;
}else if( aLock[ofst]==0 ){
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ useProcessLock = LOCK_BY_PROCESS;
}
-
+ MarkLockStatusByRc(rc, ofst, n, SHARED_LOCK, useProcessLock);
/* Get the local shared locks */
if( rc==SQLITE_OK ){
p->sharedMask |= mask;
aLock[ofst]++;
+ TryRecordTid(aLockTid, ofst, n);
}
}
}else{
@@ -41936,14 +42061,17 @@ static int unixShmLock(
** also update the in-memory values. */
if( rc==SQLITE_OK ){
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ useProcessLock = LOCK_BY_PROCESS;
if( rc==SQLITE_OK ){
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
for(ii=ofst; iipShmMutex);
@@ -58554,7 +58682,7 @@ static int readDbPage(PgHdr *pPg){
assert( isOpen(pPager->fd) );
if( pagerUseWal(pPager) ){
- rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
+ rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame); // find in wal-index
if( rc ) return rc;
}
if( iFrame ){
@@ -59811,6 +59939,7 @@ static int syncJournal(Pager *pPager, int newHdr){
assert( !pagerUseWal(pPager) );
rc = sqlite3PagerExclusiveLock(pPager);
+ MARK_LAST_BUSY_LINE(rc);
if( rc!=SQLITE_OK ) return rc;
if( !pPager->noSync ){
@@ -60720,6 +60849,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
sqlite3OsDelete(pVfs, pPager->zJournal, 0);
if( !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK);
}
+ MARK_LAST_BUSY_LINE(rc);
sqlite3EndBenignMalloc();
}else{
/* The journal file exists and no other connection has a reserved
@@ -60809,6 +60939,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK );
rc = pager_wait_on_lock(pPager, SHARED_LOCK);
+ MARK_LAST_BUSY_LINE(rc);
if( rc!=SQLITE_OK ){
assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
goto failed;
@@ -60845,6 +60976,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
** downgraded to SHARED_LOCK before this function returns.
*/
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+ MARK_LAST_BUSY_LINE(rc);
if( rc!=SQLITE_OK ){
goto failed;
}
@@ -61087,7 +61219,12 @@ static int getPageNormal(
assert( assert_pager_state(pPager) );
assert( pPager->hasHeldSharedLock==1 );
- if( pgno==0 ) return SQLITE_CORRUPT_BKPT;
+ if( pgno==0 ) {
+ const char *zMsg = "pgno should not be 0";
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN,
+ -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
+ }
pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3);
if( pBase==0 ){
pPg = 0;
@@ -61119,7 +61256,11 @@ static int getPageNormal(
** (2) Never try to fetch the locking page
*/
if( pgno==PAGER_SJ_PGNO(pPager) ){
- rc = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "try fetching the locking page(%u)", pgno);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN,
+ -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT(&context);
goto pager_acquire_err;
}
@@ -61201,7 +61342,10 @@ static int getPageMMap(
** test in the previous statement, and avoid testing pgno==0 in the
** common case where pgno is large. */
if( pgno<=1 && pgno==0 ){
- return SQLITE_CORRUPT_BKPT;
+ const char *zMsg = "pgno should not be 0";
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN,
+ -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) );
@@ -61459,6 +61603,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
*/
if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
+ MARK_LAST_BUSY_LINE(rc);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -61471,6 +61616,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
** holds the write-lock. If possible, the upper layer will call it.
*/
rc = sqlite3WalBeginWriteTransaction(pPager->pWal);
+ MARK_LAST_BUSY_LINE(rc);
}else{
/* Obtain a RESERVED lock on the database file. If the exFlag parameter
** is true, then immediately upgrade this to an EXCLUSIVE lock. The
@@ -61478,8 +61624,10 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
** lock, but not when obtaining the RESERVED lock.
*/
rc = pagerLockDb(pPager, RESERVED_LOCK);
+ MARK_LAST_BUSY_LINE(rc);
if( rc==SQLITE_OK && exFlag ){
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
+ MARK_LAST_BUSY_LINE(rc);
}
}
@@ -62784,7 +62932,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
if( pPgOld ){
if( NEVER(pPgOld->nRef>1) ){
sqlite3PagerUnrefNotNull(pPgOld);
- return SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) should be no references, ref cnt:%lld", pgno, pPgOld->nRef);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN,
+ -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
if( pPager->tempFile ){
@@ -62980,6 +63132,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
if( pPager->eState==PAGER_READER ){
assert( rc==SQLITE_OK );
rc = pagerLockDb(pPager, RESERVED_LOCK);
+ MARK_LAST_BUSY_LINE(rc);
}
if( rc==SQLITE_OK ){
sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
@@ -63144,6 +63297,7 @@ static int pagerOpenWal(Pager *pPager){
*/
if( pPager->exclusiveMode ){
rc = pagerExclusiveLock(pPager);
+ MARK_LAST_BUSY_LINE(rc);
}
/* Open the connection to the log file. If this operation fails,
@@ -63227,6 +63381,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
if( !pPager->pWal ){
int logexists = 0;
rc = pagerLockDb(pPager, SHARED_LOCK);
+ MARK_LAST_BUSY_LINE(rc);
if( rc==SQLITE_OK ){
rc = sqlite3OsAccess(
pPager->pVfs, pPager->zWal, SQLITE_ACCESS_EXISTS, &logexists
@@ -63242,6 +63397,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
*/
if( rc==SQLITE_OK && pPager->pWal ){
rc = pagerExclusiveLock(pPager);
+ MARK_LAST_BUSY_LINE(rc);
if( rc==SQLITE_OK ){
rc = sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace);
@@ -64548,7 +64704,13 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
/* Write the aPgno[] array entry and the hash-table slot. */
nCollide = idx;
for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
- if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
+ if( (nCollide--)==0 ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "no place for page(%u) to map into WAL, idx:%d", iPage, idx);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, iPage, CORRUPT_TYPE_FRAME_WAL,
+ -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
+ }
}
sLoc.aPgno[idx-1] = iPage;
AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx);
@@ -64616,6 +64778,7 @@ static int walIndexRecover(Wal *pWal){
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
if( rc ){
+ MARK_LAST_BUSY_LINE(rc);
return rc;
}
@@ -65453,6 +65616,7 @@ static int walCheckpoint(
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+ MARK_LAST_BUSY_LINE(rc);
if( rc==SQLITE_OK ){
u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
AtomicStore(pInfo->aReadMark+i, iMark);
@@ -65496,7 +65660,12 @@ static int walCheckpoint(
** database plus the amount of data in the wal file, plus the
** maximum size of the pending-byte page (65536 bytes), then
** must be corruption somewhere. */
- rc = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "final db size unexpected,nSize=%lld,mxFrame=%u,pageSize=%d, nReq=%lld",
+ nSize, pWal->hdr.mxFrame, szPage, nReq);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 0, CORRUPT_TYPE_FRAME_WAL,
+ -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT(&context);
}else{
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq);
}
@@ -65545,6 +65714,8 @@ static int walCheckpoint(
/* Release the reader lock held while backfilling */
walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+ } else {
+ MARK_LAST_BUSY_LINE(rc);
}
if( rc==SQLITE_BUSY ){
@@ -65563,11 +65734,13 @@ static int walCheckpoint(
assert( pWal->writeLock );
if( pInfo->nBackfillhdr.mxFrame ){
rc = SQLITE_BUSY;
+ MARK_LAST_BUSY_LINE(rc);
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
u32 salt1;
sqlite3_randomness(4, &salt1);
assert( pInfo->nBackfill==pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
+ MARK_LAST_BUSY_LINE(rc);
if( rc==SQLITE_OK ){
if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
/* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
@@ -65665,8 +65838,9 @@ SQLITE_PRIVATE int sqlite3WalClose(
walLimitSize(pWal, 0);
}
}
+ } else {
+ MARK_LAST_BUSY_LINE(rc);
}
-
walIndexClose(pWal, isDelete);
sqlite3OsClose(pWal->pWalFd);
if( isDelete ){
@@ -65819,6 +65993,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
walUnlockShared(pWal, WAL_WRITE_LOCK);
rc = SQLITE_READONLY_RECOVERY;
}
+ MARK_LAST_BUSY_LINE(rc);
}else{
int bWriteLock = pWal->writeLock;
if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
@@ -65839,6 +66014,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
}
}
+ MARK_LAST_BUSY_LINE(rc);
}
}
@@ -65858,6 +66034,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
** writer truncated the WAL out from under it. If that happens, it
** indicates that a writer has fixed the SHM file for us, so retry */
if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY;
+ MARK_LAST_BUSY_LINE(rc);
}
pWal->exclusiveMode = WAL_NORMAL_MODE;
}
@@ -66089,7 +66266,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
** so it takes care to hold an exclusive lock on the corresponding
** WAL_READ_LOCK() while changing values.
*/
-static void printLockInfoUsingWal(Wal *pWal);
+static void DumpLocksByWal(Wal *pWal);
static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
u32 mxReadMark; /* Largest aReadMark[] value */
@@ -66128,7 +66305,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
#if SQLITE_OS_UNIX
- if( cnt>=15 ) printLockInfoUsingWal(pWal);
+ if( cnt>=15 ) DumpLocksByWal(pWal);
#endif /* SQLITE_OS_UNIX */
sqlite3OsSleep(pWal->pVfs, nDelay);
}
@@ -66156,11 +66333,14 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** must be zeroed before the requested page is returned.
*/
rc = WAL_RETRY;
+ MARK_LAST_BUSY_LINE(SQLITE_BUSY);
}else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){
walUnlockShared(pWal, WAL_RECOVER_LOCK);
rc = WAL_RETRY;
+ MARK_LAST_BUSY_LINE(SQLITE_BUSY);
}else if( rc==SQLITE_BUSY ){
rc = SQLITE_BUSY_RECOVERY;
+ MARK_LAST_BUSY_LINE(SQLITE_BUSY);
}
}
if( rc!=SQLITE_OK ){
@@ -66183,6 +66363,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** and can be safely ignored.
*/
rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ MARK_LAST_BUSY_LINE(SQLITE_BUSY);
walShmBarrier(pWal);
if( rc==SQLITE_OK ){
if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
@@ -66200,6 +66381,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** it finished. Leaving a corrupt image in the database file.
*/
walUnlockShared(pWal, WAL_READ_LOCK(0));
+ MARK_LAST_BUSY_LINE(SQLITE_BUSY);
return WAL_RETRY;
}
pWal->readLock = 0;
@@ -66244,6 +66426,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}else if( rc!=SQLITE_BUSY ){
return rc;
}
+ MARK_LAST_BUSY_LINE(rc);
}
}
if( mxI==0 ){
@@ -66253,6 +66436,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
if( rc ){
+ MARK_LAST_BUSY_LINE(rc);
return rc==SQLITE_BUSY ? WAL_RETRY : rc;
}
/* Now that the read-lock has been obtained, check that neither the
@@ -66295,6 +66479,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
){
walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ MARK_LAST_BUSY_LINE(rc);
return WAL_RETRY;
}else{
assert( mxReadMark<=pWal->hdr.mxFrame );
@@ -66421,7 +66606,7 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
(void)walEnableBlocking(pWal);
rc = walLockShared(pWal, WAL_CKPT_LOCK);
walDisableBlocking(pWal);
-
+ MARK_LAST_BUSY_LINE(rc);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -66588,7 +66773,11 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
iRead = iFrame;
}
if( (nCollide--)==0 ){
- return SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match page(%u) to map into WAL", pgno);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, pgno, CORRUPT_TYPE_FRAME_WAL,
+ -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
iKey = walNextHash(iKey);
}
@@ -67258,7 +67447,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
assert( pWal->ckptLock==0 );
assert( pWal->writeLock==0 );
-
+ ResetLockStatus();
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
@@ -67280,6 +67469,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
** it will not be invoked in this case.
*/
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+ MARK_LAST_BUSY_LINE(rc);
testcase( rc==SQLITE_BUSY );
testcase( rc!=SQLITE_OK && xBusy2!=0 );
if( rc==SQLITE_OK ){
@@ -67296,6 +67486,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
*/
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
+ MARK_LAST_BUSY_LINE(rc);
if( rc==SQLITE_OK ){
pWal->writeLock = 1;
}else if( rc==SQLITE_BUSY ){
@@ -67321,7 +67512,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
if( rc==SQLITE_OK ){
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
- rc = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%d",
+ walPagesize(pWal),nBuf,pWal->hdr.mxFrame);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL,
+ -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT(&context);
}else{
rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
}
@@ -68768,7 +68964,7 @@ static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){
** with the page number and filename associated with the (MemPage*).
*/
#ifdef SQLITE_DEBUG
-int corruptPageError(int lineno, MemPage *p){
+int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){
char *zMsg;
sqlite3BeginBenignMalloc();
zMsg = sqlite3_mprintf("database corruption page %d of %s",
@@ -68779,11 +68975,11 @@ int corruptPageError(int lineno, MemPage *p){
sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
}
sqlite3_free(zMsg);
- return SQLITE_CORRUPT_BKPT;
+ return SQLITE_CORRUPT_REPORT(context);
}
-# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
+# define SQLITE_CORRUPT_PAGE(context,pMemPage) corruptPageError(__LINE__, (pMemPage),(context))
#else
-# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
+# define SQLITE_CORRUPT_PAGE(context,pMemPage) SQLITE_CORRUPT_PGNO((pMemPage)->pgno,(context))
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -69461,7 +69657,12 @@ static int btreeMoveto(
if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT;
sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey);
if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){
- rc = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected fields in total:%u, should not be 0 or greatter than %u",
+ pIdxKey->nField,pKeyInfo->nAllField);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, 0, CORRUPT_TYPE_PAGE_BTREE_LEAF,
+ -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT(&context);
}else{
rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes);
}
@@ -69642,7 +69843,10 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
assert( pBt->autoVacuum );
if( key==0 ){
- *pRC = SQLITE_CORRUPT_BKPT;
+ const char *zMsg = "ptrmap entry record pgno from 3, unexpected pgno";
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, 0, CORRUPT_TYPE_PAGE_PTR_MAP,
+ -1, 0, zMsg, NULL);
+ *pRC = SQLITE_CORRUPT_REPORT(&context);
return;
}
iPtrmap = PTRMAP_PAGENO(pBt, key);
@@ -69655,12 +69859,22 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
/* The first byte of the extra data is the MemPage.isInit byte.
** If that byte is set, it means this page is also being used
** as a btree page. */
- *pRC = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode((unsigned char *)sqlite3PagerGetExtra(pDbPage), 8, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) been initialized before as a btree page, base16:%s", iPtrmap, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP,
+ -1, 0, zMsg, NULL);
+ *pRC = SQLITE_CORRUPT_REPORT(&context);
goto ptrmap_exit;
}
offset = PTRMAP_PTROFFSET(iPtrmap, key);
if( offset<0 ){
- *pRC = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%u), target:%u, page usableSize=%u", iPtrmap, key, pBt->usableSize);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP,
+ -1, 0, zMsg, NULL);
+ *pRC = SQLITE_CORRUPT_REPORT(&context);
goto ptrmap_exit;
}
assert( offset <= (int)pBt->usableSize-5 );
@@ -69705,7 +69919,11 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
offset = PTRMAP_PTROFFSET(iPtrmap, key);
if( offset<0 ){
sqlite3PagerUnref(pDbPage);
- return SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%u), target:%u, page usableSize=%u", iPtrmap, key, pBt->usableSize);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP,
+ -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
assert( offset <= (int)pBt->usableSize-5 );
assert( pEType!=0 );
@@ -69713,7 +69931,15 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
sqlite3PagerUnref(pDbPage);
- if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap);
+ if( *pEType<1 || *pEType>5 ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // 5 bytes for each entry on ptrmap page
+ (void)sqlite3base16Encode(pPtrmap, 5, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect entry type:%d, correct in [1, 5], base16:%s", *pEType, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP,
+ offset, 5, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT_PGNO(&context);
+ }
return SQLITE_OK;
}
@@ -70105,7 +70331,14 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
Pgno ovfl;
if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
testcase( pSrc!=pPage );
- *pRC = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(pCell, info.nSize - info.nLocal - 4, xBuffer, sizeof(xBuffer)); // Output cell header as much as possible, 4 bytes for overflow pgno
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell overflow, offset=%d, rest=%d, length=%u, base16:%s",
+ pCell - pPage->aData, pSrc->aDataEnd - pCell, info.nSize, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF,
+ pCell - pPage->aData, info.nSize, zMsg, NULL);
+ *pRC = SQLITE_CORRUPT_REPORT(&context);
return;
}
ovfl = get4byte(&pCell[info.nSize-4]);
@@ -70163,10 +70396,24 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
** reconstruct the entire page. */
if( (int)data[hdr+7]<=nMaxFrag ){
int iFree = get2byte(&data[hdr+1]);
- if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iFree>usableSize-4 ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Output first 8 bytes as it's page header
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset=%d overflow, usableSize=%d, base16:%s", iFree, usableSize, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
if( iFree ){
int iFree2 = get2byte(&data[iFree]);
- if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iFree2>usableSize-4 ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data, 4, xBuffer, sizeof(xBuffer)); // Output first freeblock's header 4 bytes
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "first freeblock's next pointer overflow, indicate:%d, usableSize=%d, base16:%s", iFree2, usableSize, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iFree, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
u8 *pEnd = &data[cellOffset + nCell*2];
u8 *pAddr;
@@ -70174,16 +70421,40 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
int sz = get2byte(&data[iFree+2]);
int top = get2byte(&data[hdr+5]);
if( top>=iFree ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "first freeblock's offset:%d should greater than the cell content area's offset:%d, base16:%s", iFree, top, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iFree, 8, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
if( iFree2 ){
- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iFree+sz>iFree2 ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the first 2 freeblocks is out of order, 1st block offset:%d, size:%d, 2nd block offset:%d, base16:%s", iFree, sz, iFree2, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iFree, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
sz2 = get2byte(&data[iFree2+2]);
- if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iFree2+sz2 > usableSize ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data + iFree2, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 2nd block
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the 2nd freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", iFree2, sz2, usableSize, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iFree2, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
sz += sz2;
}else if( iFree+sz>usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data + iFree, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 1st block
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the 1st freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", iFree, sz, usableSize, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iFree, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
cbrk = top+sz;
@@ -70216,13 +70487,21 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
** if PRAGMA cell_size_check=ON.
*/
if( pciCellLast ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data + cellOffset + i*2, 2, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 1st block
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the %d-th cell pointer:%d out of range[%d, %d], base16:%s", i, pc, iCellStart, iCellLast, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, cellOffset + i*2, 2, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
assert( pc>=iCellStart && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrkusableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "move the %d-th cell from %d using unexpected size:%d", i, pc, size);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
assert( cbrk+size<=usableSize && cbrk>=iCellStart );
testcase( cbrk+size==usableSize );
@@ -70236,7 +70515,11 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
defragment_out:
assert( pPage->nFree>=0 );
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "after defragment, free bytes should not change, fragment bytes:%d, free space:%d, total:%d",
+ (int)data[hdr+7], cbrk-iCellFirst, pPage->nFree);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
assert( cbrk>=iCellFirst );
put2byte(&data[hdr+5], cbrk);
@@ -70261,7 +70544,7 @@ defragment_out:
** will be ignored if adding the extra space to the fragmentation count
** causes the fragmentation count to exceed 60.
*/
-static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
+static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree page
const int hdr = pPg->hdrOffset; /* Offset to page header */
u8 * const aData = pPg->aData; /* Page data */
int iAddr = hdr + 1; /* Address of ptr to pc */
@@ -70293,7 +70576,13 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
return &aData[pc];
}else if( x+pc > maxPC ){
/* This slot extends off the end of the usable part of the page */
- *pRc = SQLITE_CORRUPT_PAGE(pPg);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(aData + pc, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock rest bytes:%d begin at %d which cost %d, still exceed usableSize:%d, base16:%s",
+ x, pc, nByte, pPg->pBt->usableSize, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, pc, 4, zMsg, NULL);
+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg);
return 0;
}else{
/* The slot remains on the free-list. Reduce its size to account
@@ -70308,14 +70597,22 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
if( pc<=iAddr ){
if( pc ){
/* The next slot in the chain comes before the current slot */
- *pRc = SQLITE_CORRUPT_PAGE(pPg);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(pTmp, 2, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the next slot:%d in the chain comes before the current slot:%d, base16:%s", pc, iAddr, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iAddr, 2, zMsg, NULL);
+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg);
}
return 0;
}
}
if( pc>maxPC+nByte-4 ){
/* The free slot chain extends off the end of the page */
- *pRc = SQLITE_CORRUPT_PAGE(pPg);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the free slot:%d chain extends off the end of the page:%d", pc, maxPC+nByte-4);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg);
}
return 0;
}
@@ -70364,7 +70661,12 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print 8 bytes belong to page header
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cell content area offset:%d, base16:%s", top, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
}
@@ -70382,7 +70684,10 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
assert( pSpace+nByte<=data+pPage->pBt->usableSize );
*pIdx = g2 = (int)(pSpace-data);
if( g2<=gap ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cellpointers array(right boundary:%d) overlap with freeblock(offset:%d) found", gap, g2);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}else{
return SQLITE_OK;
}
@@ -70461,12 +70766,20 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
while( (iFreeBlk = get2byte(&data[iPtr]))pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
iPtr = iFreeBlk;
}
if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data + iPtr, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overflow, base16:%s", iFreeBlk, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB );
@@ -70478,10 +70791,20 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
*/
if( iFreeBlk && iEnd+3>=iFreeBlk ){
nFrag = iFreeBlk - iEnd;
- if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iEnd>iFreeBlk ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overlaps with pre block's end:%d", iFreeBlk, iEnd);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
if( iEnd > pPage->pBt->usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(data + iFreeBlk, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d, end:%d overflow, usableSize:%d, base16:%s", iFreeBlk, iEnd, pPage->pBt->usableSize, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iFreeBlk, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]);
@@ -70494,13 +70817,23 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
if( iPtr>hdr+1 ){
int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
if( iPtrEnd+3>=iStart ){
- if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( iPtrEnd>iStart ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "check pre freeblock end:%d overlaps with the pending free block:%d", iPtrEnd, iStart);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, iPtrEnd - iPtr, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
nFrag += iStart - iPtrEnd;
iSize = iEnd - iPtr;
iStart = iPtr;
}
}
- if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
+ if( nFrag>data[hdr+7] ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "fragment free bytes:%d increase unexpectly, should be %d", nFrag, (int)data[hdr+7]);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
data[hdr+7] -= nFrag;
}
pTmp = &data[hdr+5];
@@ -70509,8 +70842,18 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
** freelist entry */
- if( iStartpBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
+ if( iPtr!=hdr+1 ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the first freeblock's pos incorrect, hdr:%d, iPtr:%d", hdr, iPtr);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
+ }
put2byte(&data[hdr+1], iFreeBlk);
put2byte(&data[hdr+5], iEnd);
}else{
@@ -70606,7 +70949,12 @@ static int decodeFlags(MemPage *pPage, int flagByte){
pPage->maxLocal,
g_lastCkptTime);
#endif
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
pPage->max1bytePayload = pBt->max1bytePayload;
return SQLITE_OK;
@@ -70657,12 +71005,18 @@ static int btreeComputeFreeSpace(MemPage *pPage){
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
** always be at least one cell before the first freeblock.
*/
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the 1st freeblock:%d before all cells:%d", pc, top);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
while( 1 ){
if( pc>iCellLast ){
/* Freeblock off the end of the page */
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock end:%d out of page range:%d", pc, iCellLast);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
next = get2byte(&data[pc]);
size = get2byte(&data[pc+2]);
@@ -70672,11 +71026,17 @@ static int btreeComputeFreeSpace(MemPage *pPage){
}
if( next>0 ){
/* Freeblock not in ascending order */
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "all freeblocks should in ascending order, pre:%d, cur:%d", pc, next);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
if( pc+size>(unsigned int)usableSize ){
/* Last freeblock extends past page end */
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "last freeblock overflow, offset:%d, size:%d", pc, size);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
}
@@ -70688,7 +71048,11 @@ static int btreeComputeFreeSpace(MemPage *pPage){
** area, according to the page header, lies within the page.
*/
if( nFree>usableSize || nFreepBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
pPage->nFree = (u16)(nFree - iCellFirst);
return SQLITE_OK;
@@ -70719,12 +71083,18 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){
testcase( pc==iCellFirst );
testcase( pc==iCellLast );
if( pciCellLast ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell pointer:%d indicate out of range:[%d, %d]", pc, iCellFirst, iCellLast);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
sz = pPage->xCellSize(pPage, &data[pc]);
testcase( pc+sz==usableSize );
if( pc+sz>usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cell size:%d,offset:%d, out of range:%d", sz, pc, usableSize);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
}
return SQLITE_OK;
@@ -70756,7 +71126,7 @@ static int btreeInitPage(MemPage *pPage){
/* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
** the b-tree page type. */
if( decodeFlags(pPage, data[0]) ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ return SQLITE_CORRUPT_PAGE(NULL, pPage);
}
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
@@ -70770,7 +71140,10 @@ static int btreeInitPage(MemPage *pPage){
pPage->nCell = get2byte(&data[3]);
if( pPage->nCell>MX_CELL(pBt) ){
/* To many cells for a single page. The page must be corrupt */
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "too many cells(%d) for the page:%d, offset:%d, out of range:%d", pPage->nCell, pPage->pgno, pPage->hdrOffset + 3, MX_CELL(pBt));
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
testcase( pPage->nCell==MX_CELL(pBt) );
/* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
@@ -70925,7 +71298,10 @@ static int getAndInitPage(
assert( pCur==0 || pCur->iPage>0 );
if( pgno>btreePagecount(pBt) ){
- rc = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page number(%d) greater than database file size(%d)", pgno, btreePagecount(pBt));
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT(&context);
goto getAndInitPage_error1;
}
rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
@@ -70946,7 +71322,11 @@ static int getAndInitPage(
/* If obtaining a child page for a cursor, we must verify that the page is
** compatible with the root page. */
if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_PGNO(pgno);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "check btree page, nCell:%u, intKey:%u, cursor->curIntKey:%u",
+ (*ppPage)->nCell, (*ppPage)->intKey, pCur->curIntKey);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context);
goto getAndInitPage_error2;
}
return SQLITE_OK;
@@ -71049,7 +71429,7 @@ static void pageReinit(DbPage *pData){
}
}
-static void printLockInfoUsingPager(Pager *pPager);
+static void DumpLocksByPager(Pager *pPager);
/*
** Invoke the busy handler for a btree.
*/
@@ -71059,8 +71439,8 @@ static int btreeInvokeBusyHandler(void *pArg){
assert( sqlite3_mutex_held(pBt->db->mutex) );
int rc = sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
#if SQLITE_OS_UNIX
- if( rc==0 ){
- printLockInfoUsingPager( pBt->pPager );
+ if (rc == 0) {
+ DumpLocksByPager(pBt->pPager);
}
#endif /* SQLITE_OS_UNIX */
return rc;
@@ -72151,7 +72531,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
sqlite3BtreeEnter(p);
btreeIntegrity(p);
-
+ ResetLockStatus();
/* If the btree is already in a write-transaction, or it
** is already in a read-transaction and a read-transaction
** is requested, this is a no-op.
@@ -72375,7 +72755,10 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
if( eType==PTRMAP_OVERFLOW2 ){
/* The pointer is always the first 4 bytes of the page in this case. */
if( get4byte(pPage->aData)!=iFrom ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the first 4 bytes of overflow page(%d) point to the next(%d), should be %d", pPage->pgno, get4byte(pPage->aData), iFrom);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, 0, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
put4byte(pPage->aData, iTo);
}else{
@@ -72394,7 +72777,10 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
pPage->xParseCell(pPage, pCell, &info);
if( info.nLocal pPage->aData+pPage->pBt->usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell size overflow, out of page range, offset:%d, size:%d, usableSize:%d", pCell - pPage->aData, info.nSize, pPage->pBt->usableSize);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, info.nSize, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
if( iFrom==get4byte(pCell+info.nSize-4) ){
put4byte(pCell+info.nSize-4, iTo);
@@ -72403,7 +72789,10 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
}
}else{
if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell size overflow, out of page range, offset:%d, size:4, usableSize:%d", pCell - pPage->aData, pPage->pBt->usableSize);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
if( get4byte(pCell)==iFrom ){
put4byte(pCell, iTo);
@@ -72415,7 +72804,10 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
if( i==nCell ){
if( eType!=PTRMAP_BTREE ||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "missing pointer point to overflow page on btree page(%d)", pPage->pgno);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
}
@@ -72548,7 +72940,10 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
return rc;
}
if( eType==PTRMAP_ROOTPAGE ){
- return SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "try vacuum root page(%d), should not happened", nFin);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, PTRMAP_PAGENO(pBt, iLastPg), CORRUPT_TYPE_PAGE_PTR_MAP, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
if( eType==PTRMAP_FREEPAGE ){
@@ -73617,7 +74012,11 @@ static int accessPayload(
assert( eOp==0 || eOp==1 );
assert( pCur->eState==CURSOR_VALID );
if( pCur->ix>=pPage->nCell ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell index:%d exceed limit:%d on the page:%u",
+ pCur->ix, pPage->nCell, pPage->pgno);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
assert( cursorHoldsMutex(pCur) );
@@ -73632,7 +74031,11 @@ static int accessPayload(
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
** but is recast into its current form to avoid integer overflow problems
*/
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "base on payload size:%d, the max offset(%d) should greater than %d",
+ pCur->info.nLocal, aPayload - pPage->aData, pBt->usableSize - pCur->info.nLocal);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
/* Check if data must be read/written to/from the btree page itself. */
@@ -73694,7 +74097,14 @@ static int accessPayload(
assert( rc==SQLITE_OK && amt>0 );
while( nextPage ){
/* If required, populate the overflow page-list cache. */
- if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT;
+ if( nextPage > pBt->nPage ){
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(aPayload + pCur->info.nLocal, 4, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page number:%d should not exceed the size of database file, base16:%s", nextPage, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, aPayload - pPage->aData + pCur->info.nLocal, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
+ }
assert( pCur->aOverflow[iIdx]==0
|| pCur->aOverflow[iIdx]==nextPage
|| CORRUPT_DB );
@@ -73779,7 +74189,10 @@ static int accessPayload(
if( rc==SQLITE_OK && amt>0 ){
/* Overflow chain ends prematurely */
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow chain ends prematurely, rest:%d", amt);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
return rc;
}
@@ -74055,7 +74468,11 @@ static int moveToRoot(BtCursor *pCur){
** (or the freelist). */
assert( pRoot->intKey==1 || pRoot->intKey==0 );
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
- return SQLITE_CORRUPT_PAGE(pCur->pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "isInit:%u, pKeyInfo%s0, intKey:%u",
+ pRoot->isInit, ((pCur->pKeyInfo==0)?"==":"!="), pRoot->intKey);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, pRoot->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pCur->pPage);
}
skip_init:
@@ -74309,7 +74726,10 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto(
if( pPage->intKeyLeaf ){
while( 0x80 <= *(pCell++) ){
if( pCell>=pPage->aDataEnd ){
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell idx(%d) point to a cell should not out of page", idx);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
}
}
@@ -74592,7 +75012,10 @@ bypass_moveto_root:
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
testcase( nCell==2 ); /* Minimum legal index key size */
if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
- rc = SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "nCell:%d illegal, usableSize:%u, nPage:%d", nCell, pCur->pBt->usableSize, pCur->pBt->nPage);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_PAGE(&context, pPage);
goto moveto_index_finish;
}
pCellKey = sqlite3Malloc( nCell+nOverrun );
@@ -74920,7 +75343,12 @@ static int allocateBtreePage(
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
- return SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE*3] = {0};
+ (void)sqlite3base16Encode(pPage1->aData, 100, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "total number of pages(%u) in freelist should not over total size of db file(%u), base16:%s", n, mxPage, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 1, CORRUPT_TYPE_FILE_HEADER, 36, 4, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
if( n>0 ){
/* There are pages on the freelist. Reuse one of those pages. */
@@ -74976,7 +75404,10 @@ static int allocateBtreePage(
}
testcase( iTrunk==mxPage );
if( iTrunk>mxPage || nSearch++ > n ){
- rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freelist trunk page(%u) should not greater than the size of db(%u)", iTrunk, mxPage);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, (pPrevTrunk ? pPrevTrunk->pgno : 1), CORRUPT_TYPE_PAGE_FREE_LIST, -1, 0, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context);
}else{
rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0);
}
@@ -75005,7 +75436,12 @@ static int allocateBtreePage(
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
- rc = SQLITE_CORRUPT_PGNO(iTrunk);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(pTrunk->aData, 8, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "total leaf pages(%u) on trunk page over limit(%d), base16:%s", k, (u32)(pBt->usableSize/4 - 2), xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 0, 8, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context);
goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList
@@ -75039,7 +75475,12 @@ static int allocateBtreePage(
MemPage *pNewTrunk;
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
if( iNewTrunk>mxPage ){
- rc = SQLITE_CORRUPT_PGNO(iTrunk);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(pTrunk->aData, 12, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "leaf page's page number(%u) on trunk page exceed db file size(%d), base16:%s", iNewTrunk, mxPage, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 8, 4, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context);
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
@@ -75104,7 +75545,12 @@ static int allocateBtreePage(
iPage = get4byte(&aData[8+closest*4]);
testcase( iPage==mxPage );
if( iPage>mxPage || iPage<2 ){
- rc = SQLITE_CORRUPT_PGNO(iTrunk);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(aData+8+closest*4, 4, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "leaf page's page number(%u) out of range:[3, %d], base16:%s", iPage, mxPage, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 8+closest*4, 4, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context);
goto end_allocate_page;
}
testcase( iPage==mxPage );
@@ -75289,7 +75735,12 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
nLeaf = get4byte(&pTrunk->aData[4]);
assert( pBt->usableSize>32 );
if( nLeaf > (u32)pBt->usableSize/4 - 2 ){
- rc = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(pTrunk->aData, 4, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the number of leaf page(%u) on trunk page(%d) exceed limit, base16:%s", nLeaf, iTrunk, xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 0, 4, zMsg, NULL);
+ rc = SQLITE_CORRUPT_REPORT(&context);
goto freepage_out;
}
if( nLeaf < (u32)pBt->usableSize/4 - 8 ){
@@ -75378,7 +75829,11 @@ static SQLITE_NOINLINE int clearCellOverflow(
testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd );
if( pCell + pInfo->nSize > pPage->aDataEnd ){
/* Cell extends past end of page */
- return SQLITE_CORRUPT_PAGE(pPage);
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow end of page, pgno:%u, offset:%u, size:%u, usableSize:%u",
+ pPage->pgno, (pCell - pPage->aData), pInfo->nSize, pPage->pBt->usableSize);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pPage->pBt), pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_PAGE(&context, pPage);
}
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
pBt = pPage->pBt;
@@ -75395,7 +75850,12 @@ static SQLITE_NOINLINE int clearCellOverflow(
/* 0 is not a legal page number and page 1 cannot be an
** overflow page. Therefore if ovflPgno<2 or past the end of the
** file the database must be corrupt. */
- return SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0};
+ (void)sqlite3base16Encode(pCell + pInfo->nSize - 4, 4, xBuffer, sizeof(xBuffer));
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page's page number(%u) illegal, out of range:[2, %d], base16:%s", ovflPgno, btreePagecount(pBt), xBuffer);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pBt), pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
if( nOvfl ){
rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext);
@@ -75668,7 +76128,10 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
testcase( pc==(u32)get2byte(&data[hdr+5]) );
testcase( pc+sz==pPage->pBt->usableSize );
if( pc+sz > pPage->pBt->usableSize ){
- *pRC = SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell offset:%u size:%d, idx:%d overflow, usableSize:%u", pc, sz, idx, pPage->pBt->usableSize);
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ *pRC = SQLITE_CORRUPT_REPORT(&context);
return;
}
rc = freeSpace(pPage, pc, sz);
@@ -77578,7 +78041,11 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
|| pCur->info.pPayload < pPage->aData + pPage->cellOffset
){
- return SQLITE_CORRUPT_BKPT;
+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0};
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the cell payload cursor point to(%u), size:%u overlaps with non-cell content area:[%d, %d]",
+ (pCur->info.pPayload - pPage->aData), pCur->info.nLocal, pPage->cellOffset, (pPage->aDataEnd - pPage->aData));
+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL);
+ return SQLITE_CORRUPT_REPORT(&context);
}
/* Overwrite the local portion first */
rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
@@ -79521,6 +79988,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *
sqlite3BtreeEnter(p);
if( pBt->inTransaction!=TRANS_NONE ){
rc = SQLITE_LOCKED;
+ MARK_LAST_BUSY_LINE(rc);
}else{
rc = sqlite3PagerCheckpoint(pBt->pPager, p->db, eMode, pnLog, pnCkpt);
}
@@ -82760,7 +83228,7 @@ static int growOpArray(Vdbe *v, int nOp){
**
** Other useful labels for breakpoints include:
** test_trace_breakpoint(pc,pOp)
-** sqlite3CorruptError(lineno)
+** sqlite3CorruptError(lineno,context)
** sqlite3MisuseError(lineno)
** sqlite3CantopenError(lineno)
*/
@@ -85367,6 +85835,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
nTrans++;
}
rc = sqlite3PagerExclusiveLock(pPager);
+ MARK_LAST_BUSY_LINE(rc);
sqlite3BtreeLeave(pBt);
}
}
@@ -90417,7 +90886,7 @@ SQLITE_API int sqlite3_found_count = 0;
**
** Other useful labels for breakpoints include:
** test_addop_breakpoint(pc,pOp)
-** sqlite3CorruptError(lineno)
+** sqlite3CorruptError(lineno,context)
** sqlite3MisuseError(lineno)
** sqlite3CantopenError(lineno)
*/
@@ -174150,6 +174619,12 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
#endif /* SQLITE_OMIT_DESERIALIZE */
+ case SQLITE_CONFIG_CORRUPTION: {
+ typedef void(*CORRUPTION_FUNC_t)(void*, const void*);
+ sqlite3GlobalConfig.xCorruption = va_arg(ap, CORRUPTION_FUNC_t);
+ sqlite3GlobalConfig.pCorruptionArg = va_arg(ap, void*);
+ break;
+ }
default: {
rc = SQLITE_ERROR;
@@ -177220,9 +177695,21 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){
zType, lineno, 20+sqlite3_sourceid());
return iErr;
}
-SQLITE_PRIVATE int sqlite3CorruptError(int lineno){
+SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context){
testcase( sqlite3GlobalConfig.xLog!=0 );
- return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption");
+ if (context!=NULL && sqlite3GlobalConfig.xCorruption != 0) {
+ char zMsg[SQLITE_PRINT_BUF_SIZE] = {0}; /* Complete corruption log message */
+ sqlite3_snprintf(sizeof(zMsg), zMsg, "pgno:%u,type:%d,range:{%d,%d},line:%d",
+ context->pgno, (int)context->type, (int)context->zoneRange.offset, (int)context->zoneRange.size, lineno);
+ sqlite3GlobalConfig.xCorruption(sqlite3GlobalConfig.pCorruptionArg, zMsg);
+ }
+ char zCorruptMsg[SQLITE_PRINT_BUF_SIZE * 10] = {0};
+ if (context!=NULL && context->zMsg != NULL){
+ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption, %s", context->zMsg);
+ } else {
+ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption");
+ }
+ return sqlite3ReportError(SQLITE_CORRUPT, lineno, zCorruptMsg);
}
SQLITE_PRIVATE int sqlite3MisuseError(int lineno){
testcase( sqlite3GlobalConfig.xLog!=0 );
@@ -246249,106 +246736,236 @@ export_finish:
}
/************** End file hw_codec.c *****************************************/
#endif
-
#if SQLITE_OS_UNIX
-#define DB_LOCK_NUM 3
-#define DB_SHARED_LOCK_OFFSET 2
-#define WAL_LOCK_NUM 8
-#define WAL_READ_LOCK_POS 3
-#define LOCK_NUM (DB_LOCK_NUM+WAL_LOCK_NUM)
-static void printLockInfo(unixFile *dbFile, int walStat)
+#if defined(__linux__) && !defined(gettid)
+#include
+#define gettid() syscall(__NR_gettid)
+#endif
+static void ResetLockStatus(void)
{
- const char *lockType[DB_LOCK_NUM] = {"F_RDLCK", "F_WRLCK", "F_UNLCK"};
+ (void)memset(&g_lockStatus, 0, sizeof(g_lockStatus));
+}
+/*
+** Record lock info, correspond wal aLock buf, 1 aLock: 1
+*/
+static void TryRecordTid(int *tidBuf, int ofs, int lockLen)
+{
+ int lockOfs = ofs + lockLen;
+ for (int i = ofs; i < lockOfs; i++) {
+ if (tidBuf[i] == 0) {
+ tidBuf[i] = gettid();
+ }
+ }
+}
+/*
+** Clear locks info.
+*/
+static void TryClearTid(int *tidBuf, int ofs, int lockLen)
+{
+ int lockOfs = ofs + lockLen;
+ for (int i = ofs; i < lockOfs; i++) {
+ if (tidBuf[i] == gettid()) {
+ tidBuf[i] = 0;
+ }
+ }
+}
- sqlite3_log(SQLITE_WARNING, "*** SQLITE_LOG DB Lock ***");
- if( dbFile==NULL ){
- sqlite3_log(SQLITE_WARNING, "NO DB FILE !");
+static void MarkLockBusy(u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess)
+{
+ g_lockStatus.busyLockIdx = lockIdx;
+ g_lockStatus.busyLockType = lockType;
+ g_lockStatus.lockByProcess = lockByProcess;
+ g_lockStatus.lockLen = lockLen;
+}
+
+static void MarkLockStatus(u32 lockIdx, u32 lockLen, u8 lockType)
+{
+ if ((lockIdx + lockLen) > MAX_LOCK_NUM || lockLen == 0) {
+ sqlite3_log(SQLITE_ERROR, "Unexpect lock index %u lockLen %d!", lockIdx, lockLen);
return;
}
- unixInodeInfo *inode = dbFile->pInode;
- if( inode==NULL ){
- sqlite3_log(SQLITE_ERROR, "Inode is NULL !");
+ if (lockIdx == g_lockStatus.busyLockIdx) {
+ g_lockStatus.busyLockIdx = 0;
+ g_lockStatus.lockLen = 0;
+ }
+ if (lockLen == 1) {
+ g_lockStatus.lockStatus[lockIdx] = lockType;
+ } else {
+ size_t len = sizeof(u8) * lockLen;
+ (void)memset(&g_lockStatus.lockStatus[lockIdx], lockType, len);
+ }
+}
+
+static void MarkLockStatusByRc(int rc, u32 lockIdx, u32 lockLen, u8 lockType, u8 lockByProcess)
+{
+ if (rc == SQLITE_BUSY) {
+ MarkLockBusy(lockIdx, lockLen, lockType, lockByProcess);
return;
}
- sqlite3_log(SQLITE_WARNING, "fileLock %d inodeRef %d inodeLockCnt %d inodeFileLock %d inodeProcessLock %d",
- dbFile->eFileLock, inode->nRef, inode->nLock, inode->eFileLock, inode->bProcessLock);
-
- /* Set param list */
- int fdDb = dbFile->h;
- const char *lockNameList[LOCK_NUM] = {"pending lock ",
- "reserved lock",
- "shared lock ",
- "wal_write lock ",
- "wal_ckpt lock ",
- "wal_recover lock"};
- for(int i=DB_LOCK_NUM+WAL_READ_LOCK_POS; ipInode->pShmNode;
- int hasShm = (dbFile->pShm==NULL || pShmNode==NULL) ? 0 : 1;
- off_t startPos = PENDING_BYTE;
- for(int i=0; ihShm;
- }
- off_t lockLen = i==DB_SHARED_LOCK_OFFSET ? SHARED_SIZE : 1;
- struct flock flDb = { .l_type=F_WRLCK, .l_start=startPos, .l_len=lockLen, .l_whence=SEEK_SET };
- int ret = osFcntl(fdDb, F_GETLK, &flDb);
- if( ret!=SQLITE_OK ){
- sqlite3_log(SQLITE_ERROR, "Get File Lock Info Fail! errno: %d", ret);
- return;
- }
- if( flDb.l_type!=F_UNLCK ){
- sqlite3_log(SQLITE_WARNING, "lock name: %s, pos: 0x%x, len: 0x%x, lock type: %s, owner pId: %d",
- lockNameList[i], startPos, lockLen, lockType[flDb.l_type], flDb.l_pid);
+ if (rc == SQLITE_OK) {
+ MarkLockStatus(lockIdx, lockLen, lockType);
+ }
+ // only busy error code need record
+ if (lockIdx == g_lockStatus.busyLockIdx && g_lockStatus.lockLen != 0) {
+ g_lockStatus.busyLockIdx = 0;
+ g_lockStatus.busyLockType = NO_LOCK;
+ g_lockStatus.lockLen = 0;
+ }
+}
+
+static inline const char *LockStateName(int eLock)
+{
+ return eLock == NO_LOCK ? "NO_LOCK" :
+ eLock == RESERVED_LOCK ? "RESERVED" :
+ eLock == EXCLUSIVE_LOCK ? "EXCLUSIVE" :
+ eLock == SHARED_LOCK ? "SHARED" :
+ eLock == UNKNOWN_LOCK ? "UNKNOWN" : "?error?";
+}
+
+static inline const char *IdxToLockName(u32 idx)
+{
+ const char *lockName[MAX_LOCK_NUM] = {"write", "ckpt", "recover", "read0",
+ "read1", "read2", "read3", "read4", "wal_dms", "trxLock"};
+ return (idx < MAX_LOCK_NUM) ? lockName[idx] : "errLock";
+}
+
+static void DumpHandleLock(char *dumpBuf, int dumpBufLen)
+{
+ char *tmp = dumpBuf;
+ u8 *lockStatus = g_lockStatus.lockStatus;
+ int availLen = dumpBufLen - 1;
+ dumpBuf[availLen] = '\0';
+ for (int i = 0; i < MAX_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) {
+ if (lockStatus[i] != NO_LOCK) {
+ tmp[0] = '\0';
+ sqlite3_snprintf(availLen, tmp, "<%s, %s>", IdxToLockName((u32)i), LockStateName(lockStatus[i]));
+ int len = strlen(tmp);
+ tmp += len;
+ availLen -= len;
}
- startPos++;
}
-
- /* thread WAL Lock Info */
- for(int i=0; ipShm->pShmNode->aLock[i] ){
- sqlite3_log(SQLITE_WARNING, "Local WAL Lock[%d] for DB file: %d", i, dbFile->pShm->pShmNode->aLock[i]);
+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]BusyLine:%d, idx:%d, type:%d, fileLock:%d, len:%d, handleLocks:%s",
+ g_lockStatus.busyLine, g_lockStatus.busyLockIdx, g_lockStatus.busyLockType, g_lockStatus.lockByProcess,
+ g_lockStatus.lockLen, tmp != dumpBuf ? dumpBuf : "none");
+}
+
+static const char *FlockToName(int l_type)
+{
+ return l_type == F_RDLCK ? "F_RDLCK" :
+ l_type == F_WRLCK ? "F_WRLCK" :
+ l_type == F_UNLCK ? "F_UNLCK" : "F_UNKNOWN";
+}
+
+static int DumpProcessLocks(int fd, struct flock *lock, const char *lockName, char *dumpBuf, int bufLen)
+{
+ dumpBuf[0] = '\0';
+ if (osFcntl(fd, F_GETLK, lock) != SQLITE_OK) {
+ sqlite3_log(SQLITE_ERROR, "[SQLite]Get wal file lock ofs %u failed, errno: %d", lock->l_start, errno);
+ return 0;
+ }
+ if (lock->l_type != F_UNLCK) {
+ sqlite3_snprintf(bufLen, dumpBuf, "<%s, pid:%u, %s>", lockName, lock->l_pid, FlockToName(lock->l_type));
+ return strlen(dumpBuf);
+ }
+ return 0;
+}
+
+static void DumpTrxProcessLocks(unixFile *file, char *dumpBuf, int dumpBufLen)
+{
+ unixInodeInfo *inode = file->pInode;
+ if (inode == NULL) {
+ sqlite3_log(SQLITE_ERROR, "[SQLite]Inode is null!");
+ return;
+ }
+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]acqFlock:%s, dbRef:%d, lockCnt:%d, curFlock:%s, processLock:%d",
+ FlockToName(file->eFileLock), inode->nRef, inode->nLock, FlockToName(inode->eFileLock), inode->bProcessLock);
+ const char *lockName[DB_LOCK_NUM] = {"pending", "reserved", "shared"};
+ char *tmp = dumpBuf;
+ int availLen = dumpBufLen - 1;
+ dumpBuf[availLen] = '\0';
+ for (int i = 0; i < DB_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) {
+ off_t ofs = i + PENDING_BYTE;
+ off_t lockLen = (ofs == SHARED_FIRST) ? SHARED_SIZE : 1;
+ struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = lockLen, .l_whence = SEEK_SET};
+ int lockBufLen = DumpProcessLocks(file->h, &lock, lockName[i], tmp, availLen);
+ tmp += lockBufLen;
+ availLen -= lockBufLen;
+ }
+ if (tmp != dumpBuf) {
+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Trx locks: %s", dumpBuf);
+ }
+}
+
+static void DumpWalLocks(unixFile *file, u8 walEnabled, char *dumpBuf, int dumpBufLen)
+{
+ if (!walEnabled || file->pShm == NULL || file->pShm->pShmNode == NULL) {
+ sqlite3_log(SQLITE_ERROR, "[SQLite]Wal mode disabled!");
+ return;
+ }
+ unixShmNode *pShmNode = file->pShm->pShmNode;
+ char *tmp = dumpBuf;
+ int availLen = dumpBufLen - 1;
+ dumpBuf[availLen] = '\0';
+ for (int i = 0; i < WAL_LOCK_NUM && availLen > DUMP_MAX_STR_LEN; i++) {
+ if (pShmNode->aLock[i] && i < SQLITE_SHM_NLOCK) {
+ tmp[0] = '\0';
+ sqlite3_snprintf(availLen, tmp, "<%s, %d, tid:%d>", IdxToLockName((u32)i), pShmNode->aLock[i],
+ pShmNode->aLockTid[i]);
+ int strLen = strlen(tmp);
+ tmp += strLen;
+ availLen -= strLen;
}
+ off_t ofs = i + WALINDEX_LOCK_OFFSET;
+ struct flock lock = {.l_type = F_WRLCK, .l_start = ofs, .l_len = 1, .l_whence = SEEK_SET};
+ int bufLen = DumpProcessLocks(pShmNode->hShm, &lock, IdxToLockName((u32)i), tmp, availLen);
+ tmp += bufLen;
+ availLen -= bufLen;
+ }
+ if (tmp != dumpBuf) {
+ sqlite3_log(SQLITE_WARNING_DUMP, "[SQLite]Wal locks: %s", dumpBuf);
+ }
+}
+
+static void DumpLocksInfo(unixFile *file, int walEnabled)
+{
+ char *dumpBuf = sqlite3Malloc(DUMP_BUF_MAX_LEN);
+ if (dumpBuf == NULL) {
+ sqlite3_log(SQLITE_ERROR, "[SQLite]Can't alloc bufferSz %d for dump!", DUMP_BUF_MAX_LEN);
+ return;
}
+ DumpHandleLock(dumpBuf, DUMP_BUF_MAX_LEN);
+ DumpTrxProcessLocks(file, dumpBuf, DUMP_BUF_MAX_LEN);
+ DumpWalLocks(file, walEnabled, dumpBuf, DUMP_BUF_MAX_LEN);
+ sqlite3_free(dumpBuf);
}
#ifndef SQLITE_OMIT_WAL
-static void printLockInfoUsingWal(Wal *pWal)
+static void DumpLocksByWal(Wal *pWal)
{
- if( pWal==NULL ){
+ if (pWal == NULL) {
sqlite3_log(SQLITE_ERROR, "Wal ptr is NULL!");
return;
}
- if( pWal->pVfs==NULL || sqlite3_stricmp(pWal->pVfs->zName, "unix")!=0 ){
+ if (pWal->pVfs == NULL || sqlite3_stricmp(pWal->pVfs->zName, "unix") != 0) {
return;
}
- printLockInfo((unixFile *)(pWal->pDbFd), 1);
+ DumpLocksInfo((unixFile *)(pWal->pDbFd), 1);
}
#endif /* #ifndef SQLITE_OMIT_WAL */
-static void printLockInfoUsingPager(Pager *pPager)
+static void DumpLocksByPager(Pager *pPager)
{
- if( pPager==NULL ){
+ if (pPager == NULL) {
sqlite3_log(SQLITE_ERROR, "Pager ptr is NULL!");
return;
}
- if( pPager->pVfs==NULL || sqlite3_stricmp(pPager->pVfs->zName, "unix")!=0 ){
+ if (pPager->pVfs == NULL || sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0) {
return;
}
#ifndef SQLITE_OMIT_WAL
- printLockInfo((unixFile *)(pPager->fd), pPager->pWal!=NULL);
+ DumpLocksInfo((unixFile *)(pPager->fd), pPager->pWal != NULL);
#else /* #ifndef SQLITE_OMIT_WAL */
- printLockInfo((unixFile *)(pPager->fd), 0);
+ DumpLocksInfo((unixFile *)(pPager->fd), 0);
#endif /* #ifndef SQLITE_OMIT_WAL */
}
#endif /* SQLITE_OS_UNIX */