Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -857,11 +857,11 @@ ** to the cell content. ** ** This routine works only for pages that do not contain overflow cells. */ #define findCell(P,I) \ - ((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)]))) + ((P)->aData + ((P)->maskPage & get2byte(&(P)->aCellIdx[2*(I)]))) #define findCellv2(D,M,O,I) (D+(M&get2byte(D+(O+2*(I))))) /* ** This a more complex version of findCell() that works for @@ -1407,10 +1407,12 @@ assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nOverflow = 0; usableSize = pBt->usableSize; pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf; + pPage->aDataEnd = &data[usableSize]; + pPage->aCellIdx = &data[cellOffset]; top = get2byteNotZero(&data[hdr+5]); pPage->nCell = get2byte(&data[hdr+3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_BKPT; @@ -1510,10 +1512,12 @@ put2byte(&data[hdr+5], pBt->usableSize); pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); pPage->hdrOffset = hdr; pPage->cellOffset = first; + pPage->aDataEnd = &data[pBt->usableSize]; + pPage->aCellIdx = &data[first]; pPage->nOverflow = 0; assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nCell = 0; pPage->isInit = 1; @@ -4548,20 +4552,26 @@ ** the entire cell by checking for the cases where the record is ** stored entirely within the b-tree page by inspecting the first ** 2 bytes of the cell. */ int nCell = pCell[0]; - if( !(nCell & 0x80) && nCell<=pPage->maxLocal ){ + if( !(nCell & 0x80) + && nCell<=pPage->maxLocal + && (pCell+nCell+1)<=pPage->aDataEnd + ){ /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ + testcase( pCell+nCell+1==pPage->aDataEnd ); c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + && (pCell+nCell+2)<=pPage->aDataEnd ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ + testcase( pCell+nCell+2==pPage->aDataEnd ); c = sqlite3VdbeRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In ** this case the whole cell needs to be parsed, a buffer allocated ** and accessPayload() used to retrieve the record into the @@ -5452,11 +5462,11 @@ assert( idx>=0 && idxnCell ); assert( sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); data = pPage->aData; - ptr = &data[pPage->cellOffset + 2*idx]; + ptr = &pPage->aCellIdx[2*idx]; pc = get2byte(ptr); hdr = pPage->hdrOffset; testcase( pc==get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc < (u32)get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){ @@ -5466,11 +5476,11 @@ rc = freeSpace(pPage, pc, sz); if( rc ){ *pRC = rc; return; } - endPtr = &data[pPage->cellOffset + 2*pPage->nCell - 2]; + endPtr = &pPage->aCellIdx[2*pPage->nCell - 2]; assert( (SQLITE_PTR_TO_INT(ptr)&1)==0 ); /* ptr is always 2-byte aligned */ while( ptrnCell==0 ); assert( get2byteNotZero(&data[hdr+5])==nUsable ); - pCellptr = &data[pPage->cellOffset + nCell*2]; + pCellptr = &pPage->aCellIdx[nCell*2]; cellbody = nUsable; for(i=nCell-1; i>=0; i--){ u16 sz = aSize[i]; pCellptr -= 2; cellbody -= sz; Index: src/btreeInt.h ================================================================== --- src/btreeInt.h +++ src/btreeInt.h @@ -287,10 +287,12 @@ u8 *pCell; /* Pointers to the body of the overflow cell */ u16 idx; /* Insert this cell before idx-th non-overflow cell */ } aOvfl[5]; BtShared *pBt; /* Pointer to BtShared that this page is part of */ u8 *aData; /* Pointer to disk image of the page data */ + u8 *aDataEnd; /* One byte past the end of usable data */ + u8 *aCellIdx; /* The cell index area */ DbPage *pDbPage; /* Pager page handle */ Pgno pgno; /* Page number for this page */ }; /* Index: src/os_win.c ================================================================== --- src/os_win.c +++ src/os_win.c @@ -46,17 +46,10 @@ #ifdef __CYGWIN__ # include #endif -/* -** Macros used to determine whether or not to use threads. -*/ -#if defined(THREADSAFE) && THREADSAFE -# define SQLITE_W32_THREADS 1 -#endif - /* ** Include code that is common to all os_*.c files */ #include "os_common.h" @@ -556,24 +549,25 @@ /* ** The return value of getLastErrorMsg ** is zero if the error message fits in the buffer, or non-zero ** otherwise (if the message was truncated). */ -static int getLastErrorMsg(int nBuf, char *zBuf){ +static int getLastErrorMsg(DWORD lastErrno, int nBuf, char *zBuf){ /* FormatMessage returns 0 on failure. Otherwise it ** returns the number of TCHARs written to the output ** buffer, excluding the terminating null char. */ - DWORD error = GetLastError(); DWORD dwLen = 0; char *zOut = 0; if( isNT() ){ WCHAR *zTempWide = NULL; - dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, - error, + lastErrno, 0, (LPWSTR) &zTempWide, 0, 0); if( dwLen > 0 ){ @@ -587,13 +581,15 @@ ** it's important to not reference them for WINCE builds. */ #if SQLITE_OS_WINCE==0 }else{ char *zTemp = NULL; - dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, - error, + lastErrno, 0, (LPSTR) &zTemp, 0, 0); if( dwLen > 0 ){ @@ -603,11 +599,11 @@ LocalFree(zTemp); } #endif } if( 0 == dwLen ){ - sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error); + sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", lastErrno, lastErrno); }else{ /* copy a maximum of nBuf chars to output buffer */ sqlite3_snprintf(nBuf, zBuf, "%s", zOut); /* free the UTF8 buffer */ free(zOut); @@ -628,30 +624,30 @@ ** The first argument passed to the macro should be the error code that ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). ** The two subsequent arguments should be the name of the OS function that ** failed and the the associated file-system path, if any. */ -#define winLogError(a,b,c) winLogErrorAtLine(a,b,c,__LINE__) +#define winLogError(a,b,c,d) winLogErrorAtLine(a,b,c,d,__LINE__) static int winLogErrorAtLine( int errcode, /* SQLite error code */ + DWORD lastErrno, /* Win32 last error */ const char *zFunc, /* Name of OS function that failed */ const char *zPath, /* File path associated with error */ int iLine /* Source line number where error occurred */ ){ char zMsg[500]; /* Human readable error text */ int i; /* Loop counter */ - DWORD iErrno = GetLastError(); /* Error code */ zMsg[0] = 0; - getLastErrorMsg(sizeof(zMsg), zMsg); + getLastErrorMsg(lastErrno, sizeof(zMsg), zMsg); assert( errcode!=SQLITE_OK ); if( zPath==0 ) zPath = ""; for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} zMsg[i] = 0; sqlite3_log(errcode, "os_win.c:%d: (%d) %s(%s) - %s", - iLine, iErrno, zFunc, zPath, zMsg + iLine, lastErrno, zFunc, zPath, zMsg ); return errcode; } @@ -778,11 +774,11 @@ /* Create/open the named mutex */ pFile->hMutex = CreateMutexW(NULL, FALSE, zName); if (!pFile->hMutex){ pFile->lastErrno = GetLastError(); - winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename); + winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename); free(zName); return FALSE; } /* Acquire the mutex before continuing */ @@ -810,11 +806,12 @@ pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); /* If mapping failed, close the shared memory handle and erase it */ if (!pFile->shared){ pFile->lastErrno = GetLastError(); - winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename); + winLogError(SQLITE_ERROR, pFile->lastErrno, + "winceCreateLock2", zFilename); CloseHandle(pFile->hShared); pFile->hShared = NULL; } } @@ -1056,11 +1053,12 @@ ** GetLastError(). */ dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){ pFile->lastErrno = GetLastError(); - winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath); + winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno, + "seekWinFile", pFile->zPath); return 1; } return 0; } @@ -1103,11 +1101,12 @@ } #endif OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed")); OpenCounter(-1); return rc ? SQLITE_OK - : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath); + : winLogError(SQLITE_IOERR_CLOSE, GetLastError(), + "winClose", pFile->zPath); } /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes @@ -1131,11 +1130,12 @@ return SQLITE_FULL; } while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ if( retryIoerr(&nRetry) ) continue; pFile->lastErrno = GetLastError(); - return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath); + return winLogError(SQLITE_IOERR_READ, pFile->lastErrno, + "winRead", pFile->zPath); } logIoerr(nRetry); if( nRead<(DWORD)amt ){ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[nRead], 0, amt-nRead); @@ -1190,11 +1190,12 @@ if( rc ){ if( ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ) || ( pFile->lastErrno==ERROR_DISK_FULL )){ return SQLITE_FULL; } - return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath); + return winLogError(SQLITE_IOERR_WRITE, pFile->lastErrno, + "winWrite", pFile->zPath); }else{ logIoerr(nRetry); } return SQLITE_OK; } @@ -1220,14 +1221,16 @@ nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; } /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ if( seekWinFile(pFile, nByte) ){ - rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath); + rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, + "winTruncate1", pFile->zPath); }else if( 0==SetEndOfFile(pFile->h) ){ pFile->lastErrno = GetLastError(); - rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath); + rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, + "winTruncate2", pFile->zPath); } OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok")); return rc; } @@ -1294,11 +1297,12 @@ SimulateIOError( rc=FALSE ); if( rc ){ return SQLITE_OK; }else{ pFile->lastErrno = GetLastError(); - return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath); + return winLogError(SQLITE_IOERR_FSYNC, pFile->lastErrno, + "winSync", pFile->zPath); } #endif } /* @@ -1315,11 +1319,12 @@ lowerBits = GetFileSize(pFile->h, &upperBits); if( (lowerBits == INVALID_FILE_SIZE) && ((error = GetLastError()) != NO_ERROR) ) { pFile->lastErrno = error; - return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath); + return winLogError(SQLITE_IOERR_FSTAT, pFile->lastErrno, + "winFileSize", pFile->zPath); } *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; return SQLITE_OK; } @@ -1375,11 +1380,12 @@ res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); #endif } if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){ pFile->lastErrno = GetLastError(); - winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath); + winLogError(SQLITE_IOERR_UNLOCK, pFile->lastErrno, + "unlockReadLock", pFile->zPath); } return res; } /* @@ -1443,15 +1449,17 @@ || ( (locktype==EXCLUSIVE_LOCK) && (pFile->locktype==RESERVED_LOCK)) ){ int cnt = 3; while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ - /* Try 3 times to get the pending lock. The pending lock might be - ** held by another reader process who will release it momentarily. + /* Try 3 times to get the pending lock. This is needed to work + ** around problems caused by anti-virus software on windows system. + ** If you are using this code as a model for alternative VFSes, do not + ** copy this retry logic. It is a hack intended for windows only. */ OSTRACE(("could not get a PENDING lock. cnt=%d\n", cnt)); - Sleep(1); + if( cnt ) Sleep(1); } gotPendingLock = res; if( !res ){ error = GetLastError(); } @@ -1576,11 +1584,12 @@ if( type>=EXCLUSIVE_LOCK ){ UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ - rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath); + rc = winLogError(SQLITE_IOERR_UNLOCK, GetLastError(), + "winUnlock", pFile->zPath); } } if( type>=RESERVED_LOCK ){ UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); } @@ -1967,11 +1976,12 @@ ** If not, truncate the file to zero length. */ if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath); + rc = winLogError(SQLITE_IOERR_SHMOPEN, GetLastError(), + "winOpenShm", pDbFd->zPath); } } if( rc==SQLITE_OK ){ winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1); @@ -2226,11 +2236,12 @@ ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath); + rc = winLogError(SQLITE_IOERR_SHMSIZE, GetLastError(), + "winShmMap1", pDbFd->zPath); goto shmpage_out; } if( szhFile, nByte); if( rc!=SQLITE_OK ){ - rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap2", pDbFd->zPath); + rc = winLogError(SQLITE_IOERR_SHMSIZE, GetLastError(), + "winShmMap2", pDbFd->zPath); goto shmpage_out; } } /* Map the requested memory region into this processes address space. */ @@ -2277,11 +2289,12 @@ (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, pMap ? "ok" : "failed")); } if( !pMap ){ pShmNode->lastErrno = GetLastError(); - rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath); + rc = winLogError(SQLITE_IOERR_SHMMAP, pShmNode->lastErrno, + "winShmMap3", pDbFd->zPath); if( hMap ) CloseHandle(hMap); goto shmpage_out; } pShmNode->aRegion[pShmNode->nRegion].pMap = pMap; @@ -2611,11 +2624,11 @@ h, zName, dwDesiredAccess, h==INVALID_HANDLE_VALUE ? "failed" : "ok")); if( h==INVALID_HANDLE_VALUE ){ pFile->lastErrno = GetLastError(); - winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name); + winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); free(zConverted); if( isReadWrite && !isExclusive ){ return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); }else{ @@ -2704,11 +2717,12 @@ (rc = DeleteFileA(zConverted))==0 && retryIoerr(&cnt) ){} rc = rc ? SQLITE_OK : SQLITE_ERROR; #endif } if( rc ){ - rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename); + rc = winLogError(SQLITE_IOERR_DELETE, GetLastError(), + "winDelete", zFilename); }else{ logIoerr(cnt); } free(zConverted); OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" ))); @@ -2751,13 +2765,14 @@ attr = INVALID_FILE_ATTRIBUTES; }else{ attr = sAttrData.dwFileAttributes; } }else{ + DWORD lastErrno = GetLastError(); logIoerr(cnt); - if( GetLastError()!=ERROR_FILE_NOT_FOUND ){ - winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename); + if( lastErrno!=ERROR_FILE_NOT_FOUND ){ + winLogError(SQLITE_IOERR_ACCESS, lastErrno, "winAccess", zFilename); free(zConverted); return SQLITE_IOERR_ACCESS; }else{ attr = INVALID_FILE_ATTRIBUTES; } @@ -2977,11 +2992,11 @@ free(zConverted); return (void*)h; } static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ UNUSED_PARAMETER(pVfs); - getLastErrorMsg(nBuf, zBufOut); + getLastErrorMsg(GetLastError(), nBuf, zBufOut); } static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ UNUSED_PARAMETER(pVfs); #if SQLITE_OS_WINCE /* The GetProcAddressA() routine is only available on wince. */ @@ -3151,11 +3166,11 @@ ** by sqlite into the error message available to the user using ** sqlite3_errmsg(), possibly making IO errors easier to debug. */ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ UNUSED_PARAMETER(pVfs); - return getLastErrorMsg(nBuf, zBuf); + return getLastErrorMsg(GetLastError(), nBuf, zBuf); } /*