** Valid if STAGE==3. The blob to pass to sqlite3ckpt_start() to resume
** the incremental checkpoint.
**
+** OTA_STATE_COOKIE:
+** Valid if STAGE==1. The current change-counter cookie value in the
+** target db file.
*/
#define OTA_STATE_STAGE 1
#define OTA_STATE_TBL 2
#define OTA_STATE_ROW 4
#define OTA_STATE_PROGRESS 5
#define OTA_STATE_CKPT 6
+#define OTA_STATE_COOKIE 7
#define OTA_STAGE_OAL 1
#define OTA_STAGE_COPY 2
int nProgress; /* Rows processed for all objects */
OtaObjIter objiter; /* Iterator for skipping through tbl/idx */
sqlite3_ckpt *pCkpt; /* Incr-checkpoint handle */
+ sqlite3_vfs *pVfs; /* Special ota VFS object */
+ unsigned int iCookie;
};
+static void otaCreateVfs(sqlite3ota*, const char*);
+static void otaDeleteVfs(sqlite3ota*);
+
/*
** Prepare the SQL statement in buffer zSql against database handle db.
** If successful, set *ppStmt to point to the new statement and return
return zSql;
}
+static void *otaMalloc(sqlite3ota *p, int nByte){
+ void *pRet = 0;
+ if( p->rc==SQLITE_OK ){
+ pRet = sqlite3_malloc(nByte);
+ if( pRet==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ memset(pRet, 0, nByte);
+ }
+ }
+ return pRet;
+}
+
/*
** This function constructs and returns a pointer to a nul-terminated
** string containing some SQL clause or list based on one or more of the
** error occurs, leave an error code and message in the OTA handle.
*/
static void otaOpenDatabase(sqlite3ota *p){
+ int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
assert( p->rc==SQLITE_OK );
- sqlite3_close(p->db);
- p->db = 0;
+ assert( p->db==0 );
- p->rc = sqlite3_open(p->zTarget, &p->db);
+ p->rc = sqlite3_open_v2(p->zTarget, &p->db, flags, p->pVfs->zName);
if( p->rc ){
p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
}
/* Re-open the databases. */
otaObjIterFinalize(&p->objiter);
- otaOpenDatabase(p);
+ sqlite3_close(p->db);
+ p->db = 0;
p->eStage = OTA_STAGE_CKPT;
+ otaOpenDatabase(p);
}
sqlite3_free(zWal);
"(%d, %Q), "
"(%d, %d), "
"(%d, %lld), "
- "(%d, ?) ",
+ "(%d, ?), "
+ "(%d, %lld) ",
OTA_STATE_STAGE, p->eStage,
OTA_STATE_TBL, p->objiter.zTbl,
OTA_STATE_IDX, p->objiter.zIdx,
OTA_STATE_ROW, p->nStep,
OTA_STATE_PROGRESS, p->nProgress,
- OTA_STATE_CKPT
+ OTA_STATE_CKPT,
+ OTA_STATE_COOKIE, (sqlite3_int64)p->iCookie
)
);
assert( pInsert==0 || rc==SQLITE_OK );
);
break;
+ case OTA_STATE_COOKIE:
+ /* At this point (p->iCookie) contains the value of the change-counter
+ ** cookie (the thing that gets incremented when a transaction is
+ ** committed in rollback mode) currently stored on page 1 of the
+ ** database file. */
+ if( pRet->eStage==OTA_STAGE_OAL
+ && p->iCookie!=(unsigned int)sqlite3_column_int64(pStmt, 1)
+ ){
+ rc = SQLITE_BUSY;
+ p->zErrmsg = sqlite3_mprintf("database modified during ota update");
+ }
+ break;
+
default:
rc = SQLITE_CORRUPT;
break;
if( p ){
OtaState *pState = 0;
- /* Open the target database */
+ /* Create the custom VFS */
memset(p, 0, sizeof(sqlite3ota));
- p->zTarget = (char*)&p[1];
- memcpy(p->zTarget, zTarget, nTarget+1);
- p->zOta = &p->zTarget[nTarget+1];
- memcpy(p->zOta, zOta, nOta+1);
- otaOpenDatabase(p);
+ otaCreateVfs(p, 0);
+
+ /* Open the target database */
+ if( p->rc==SQLITE_OK ){
+ p->zTarget = (char*)&p[1];
+ memcpy(p->zTarget, zTarget, nTarget+1);
+ p->zOta = &p->zTarget[nTarget+1];
+ memcpy(p->zOta, zOta, nOta+1);
+ otaOpenDatabase(p);
+ }
/* If it has not already been created, create the ota_state table */
if( p->rc==SQLITE_OK ){
if( p->eStage==OTA_STAGE_OAL ){
const char *zScript =
"PRAGMA journal_mode=off;"
- "PRAGMA pager_ota_mode=1;"
"BEGIN IMMEDIATE;"
;
p->rc = sqlite3_exec(p->db, zScript, 0, 0, &p->zErrmsg);
p->rc = sqlite3_exec(p->db, "COMMIT", 0, 0, &p->zErrmsg);
}
- if( p->rc==SQLITE_OK && p->eStage==OTA_STAGE_CKPT ){
- p->rc = sqlite3_exec(p->db, "PRAGMA pager_ota_mode=2", 0, 0, &p->zErrmsg);
- }
-
- /* Close the open database handle */
+ /* Close the open database handle and VFS object. */
if( p->pCkpt ) sqlite3_ckpt_close(p->pCkpt, 0, 0);
sqlite3_close(p->db);
+ otaDeleteVfs(p);
otaEditErrmsg(p);
rc = p->rc;
return pOta->nProgress;
}
+/**************************************************************************
+** Beginning of OTA VFS shim methods. The VFS shim modifies the behaviour
+** of a standard VFS in the following ways:
+**
+** TODO
+*/
+
+#if 0
+#define OTA_FILE_VANILLA 0
+#define OTA_FILE_TARGET_DB 1
+#define OTA_FILE_TARGET_WAL 2
+#endif
+
+typedef struct ota_file ota_file;
+typedef struct ota_vfs ota_vfs;
+
+struct ota_file {
+ sqlite3_file base; /* sqlite3_file methods */
+ sqlite3_file *pReal; /* Underlying file handle */
+ ota_vfs *pOtaVfs; /* Pointer to the ota_vfs object */
+
+ int nShm; /* Number of entries in apShm[] array */
+ char **apShm; /* Array of mmap'd *-shm regions */
+ char *zFilename; /* Filename for *-oal file only */
+};
+
+struct ota_vfs {
+ sqlite3_vfs base; /* ota VFS shim methods */
+ sqlite3_vfs *pRealVfs; /* Underlying VFS */
+ sqlite3ota *pOta;
+ ota_file *pTargetDb; /* Target database file descriptor */
+ const char *zTargetDb; /* Path that pTargetDb was opened with */
+};
+
+/*
+** Close an ota file.
+*/
+static int otaVfsClose(sqlite3_file *pFile){
+ ota_file *p = (ota_file*)pFile;
+ ota_vfs *pOtaVfs = p->pOtaVfs;
+ int rc;
+ int i;
+
+ /* Free the contents of the apShm[] array. And the array itself. */
+ for(i=0; i<p->nShm; i++){
+ sqlite3_free(p->apShm[i]);
+ }
+ sqlite3_free(p->apShm);
+ p->apShm = 0;
+ sqlite3_free(p->zFilename);
+
+ if( p==pOtaVfs->pTargetDb ){
+ pOtaVfs->pTargetDb = 0;
+ pOtaVfs->zTargetDb = 0;
+ }
+
+ rc = p->pReal->pMethods->xClose(p->pReal);
+ return rc;
+}
+
+
+/*
+** Read and return an unsigned 32-bit big-endian integer from the buffer
+** passed as the only argument.
+*/
+static unsigned int otaGetU32(unsigned char *aBuf){
+ return ((unsigned int)aBuf[0] << 24)
+ + ((unsigned int)aBuf[1] << 16)
+ + ((unsigned int)aBuf[2] << 8)
+ + ((unsigned int)aBuf[3]);
+}
+
+/*
+** Read data from an otaVfs-file.
+*/
+static int otaVfsRead(
+ sqlite3_file *pFile,
+ void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ ota_file *p = (ota_file*)pFile;
+ ota_vfs *pOtaVfs = p->pOtaVfs;
+ int rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
+ if( rc==SQLITE_OK && p==pOtaVfs->pTargetDb && iOfst==0 ){
+ unsigned char *pBuf = (unsigned char*)zBuf;
+ assert( iAmt>=100 );
+ pOtaVfs->pOta->iCookie = otaGetU32(&pBuf[24]);
+ }
+ return rc;
+}
+
+/*
+** Write data to an otaVfs-file.
+*/
+static int otaVfsWrite(
+ sqlite3_file *pFile,
+ const void *zBuf,
+ int iAmt,
+ sqlite_int64 iOfst
+){
+ ota_file *p = (ota_file*)pFile;
+ ota_vfs *pOtaVfs = p->pOtaVfs;
+ int rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
+ if( rc==SQLITE_OK && p==pOtaVfs->pTargetDb && iOfst==0 ){
+ unsigned char *pBuf = (unsigned char*)zBuf;
+ assert( iAmt>=100 );
+ pOtaVfs->pOta->iCookie = otaGetU32(&pBuf[24]);
+ }
+ return rc;
+}
+
+/*
+** Truncate an otaVfs-file.
+*/
+static int otaVfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
+ ota_file *p = (ota_file*)pFile;
+ return p->pReal->pMethods->xTruncate(p->pReal, size);
+}
+
+/*
+** Sync an otaVfs-file.
+*/
+static int otaVfsSync(sqlite3_file *pFile, int flags){
+ ota_file *p = (ota_file *)pFile;
+ return p->pReal->pMethods->xSync(p->pReal, flags);
+}
+
+/*
+** Return the current file-size of an otaVfs-file.
+*/
+static int otaVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
+ ota_file *p = (ota_file *)pFile;
+ return p->pReal->pMethods->xFileSize(p->pReal, pSize);
+}
+
+/*
+** Lock an otaVfs-file.
+*/
+static int otaVfsLock(sqlite3_file *pFile, int eLock){
+ ota_file *p = (ota_file*)pFile;
+ ota_vfs *pOtaVfs = p->pOtaVfs;
+ int rc = SQLITE_OK;
+ int eStage = pOtaVfs->pOta->eStage;
+
+ if( pOtaVfs->pTargetDb==p
+ && (eStage==OTA_STAGE_OAL || eStage==OTA_STAGE_CKPT)
+ && eLock==SQLITE_LOCK_EXCLUSIVE
+ ){
+ /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
+ ** prevents it from checkpointing the database from sqlite3_close(). */
+ rc = SQLITE_BUSY;
+ }else{
+ rc = p->pReal->pMethods->xLock(p->pReal, eLock);
+ }
+
+ return rc;
+}
+
+/*
+** Unlock an otaVfs-file.
+*/
+static int otaVfsUnlock(sqlite3_file *pFile, int eLock){
+ ota_file *p = (ota_file *)pFile;
+ return p->pReal->pMethods->xUnlock(p->pReal, eLock);
+}
+
+/*
+** Check if another file-handle holds a RESERVED lock on an otaVfs-file.
+*/
+static int otaVfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
+ ota_file *p = (ota_file *)pFile;
+ return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
+}
+
+/*
+** File control method. For custom operations on an otaVfs-file.
+*/
+static int otaVfsFileControl(sqlite3_file *pFile, int op, void *pArg){
+ ota_file *p = (ota_file *)pFile;
+ return p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
+}
+
+/*
+** Return the sector-size in bytes for an otaVfs-file.
+*/
+static int otaVfsSectorSize(sqlite3_file *pFile){
+ ota_file *p = (ota_file *)pFile;
+ return p->pReal->pMethods->xSectorSize(p->pReal);
+}
+
+/*
+** Return the device characteristic flags supported by an otaVfs-file.
+*/
+static int otaVfsDeviceCharacteristics(sqlite3_file *pFile){
+ ota_file *p = (ota_file *)pFile;
+ return p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
+}
+
+/*
+** Shared-memory methods are all pass-thrus.
+*/
+static int otaVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
+ ota_file *p = (ota_file*)pFile;
+ ota_vfs *pOtaVfs = p->pOtaVfs;
+ int rc = SQLITE_OK;
+
+#ifdef SQLITE_AMALGAMATION
+ assert( WAL_WRITE_CKPT==1 );
+#endif
+
+ if( pOtaVfs->pTargetDb==p && pOtaVfs->pOta->eStage==OTA_STAGE_OAL ){
+ /* Magic number 1 is the WAL_WRITE_CKPT lock. Preventing SQLite from
+ ** taking this lock also prevents any checkpoints from occurring.
+ ** todo: really, it's not clear why this might occur, as
+ ** wal_autocheckpoint ought to be turned off. */
+ if( ofst==1 && n==1 ) rc = SQLITE_BUSY;
+ }else{
+ assert( p->nShm==0 );
+ return p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
+ }
+
+ return rc;
+}
+
+static int otaVfsShmMap(
+ sqlite3_file *pFile,
+ int iRegion,
+ int szRegion,
+ int isWrite,
+ void volatile **pp
+){
+ ota_file *p = (ota_file*)pFile;
+ ota_vfs *pOtaVfs = p->pOtaVfs;
+ int rc = SQLITE_OK;
+
+ /* If not in OTA_STAGE_OAL, allow this call to pass through. Or, if this
+ ** ota is in the OTA_STAGE_OAL state, use heap memory for *-shm space
+ ** instead of a file on disk. */
+ if( pOtaVfs->pTargetDb==p && pOtaVfs->pOta->eStage==OTA_STAGE_OAL ){
+ if( iRegion<=p->nShm ){
+ int nByte = (iRegion+1) * sizeof(char*);
+ char **apNew = (char**)sqlite3_realloc(p->apShm, nByte);
+ if( apNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(&apNew[p->nShm], 0, sizeof(char*) * (1 + iRegion - p->nShm));
+ p->apShm = apNew;
+ p->nShm = iRegion+1;
+ }
+ }
+
+ if( rc==SQLITE_OK && p->apShm[iRegion]==0 ){
+ char *pNew = (char*)sqlite3_malloc(szRegion);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ p->apShm[iRegion] = pNew;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ *pp = p->apShm[iRegion];
+ }else{
+ *pp = 0;
+ }
+ }else{
+ assert( p->apShm==0 );
+ rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
+ }
+
+ return rc;
+}
+
+/*
+** Memory barrier.
+*/
+static void otaVfsShmBarrier(sqlite3_file *pFile){
+ ota_file *p = (ota_file *)pFile;
+ p->pReal->pMethods->xShmBarrier(p->pReal);
+}
+
+static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
+ ota_file *p = (ota_file*)pFile;
+ ota_vfs *pOtaVfs = p->pOtaVfs;
+ int rc = SQLITE_OK;
+
+ if( pOtaVfs->pTargetDb==p && pOtaVfs->pOta->eStage==OTA_STAGE_OAL ){
+ /* no-op */
+ }else{
+ rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
+ }
+ return rc;
+}
+
+
+static int otaVfsIswal(ota_vfs *pOtaVfs, const char *zPath){
+ int nPath = strlen(zPath);
+ int nTargetDb = strlen(pOtaVfs->zTargetDb);
+ return ( nPath==(nTargetDb+4)
+ && 0==memcmp(zPath, pOtaVfs->zTargetDb, nTargetDb)
+ && 0==memcmp(&zPath[nTargetDb], "-wal", 4)
+ );
+}
+
+
+/*
+** Open an ota file handle.
+*/
+static int otaVfsOpen(
+ sqlite3_vfs *pVfs,
+ const char *zName,
+ sqlite3_file *pFile,
+ int flags,
+ int *pOutFlags
+){
+ static sqlite3_io_methods otavfs_io_methods = {
+ 2, /* iVersion */
+ otaVfsClose, /* xClose */
+ otaVfsRead, /* xRead */
+ otaVfsWrite, /* xWrite */
+ otaVfsTruncate, /* xTruncate */
+ otaVfsSync, /* xSync */
+ otaVfsFileSize, /* xFileSize */
+ otaVfsLock, /* xLock */
+ otaVfsUnlock, /* xUnlock */
+ otaVfsCheckReservedLock, /* xCheckReservedLock */
+ otaVfsFileControl, /* xFileControl */
+ otaVfsSectorSize, /* xSectorSize */
+ otaVfsDeviceCharacteristics, /* xDeviceCharacteristics */
+ otaVfsShmMap, /* xShmMap */
+ otaVfsShmLock, /* xShmLock */
+ otaVfsShmBarrier, /* xShmBarrier */
+ otaVfsShmUnmap /* xShmUnmap */
+ };
+ ota_vfs *pOtaVfs = (ota_vfs*)pVfs;
+ sqlite3_vfs *pRealVfs = pOtaVfs->pRealVfs;
+ sqlite3ota *p = pOtaVfs->pOta;
+ ota_file *pFd = (ota_file *)pFile;
+ int rc = SQLITE_OK;
+ const char *zOpen = zName;
+
+ memset(pFd, 0, sizeof(ota_file));
+ pFd->pReal = (sqlite3_file*)&pFd[1];
+ pFd->pOtaVfs = pOtaVfs;
+
+ if( zName && p->eStage==OTA_STAGE_OAL && otaVfsIswal(pOtaVfs, zName) ){
+ char *zCopy = otaStrndup(zName, -1, &rc);
+ if( zCopy ){
+ int nCopy = strlen(zCopy);
+ zCopy[nCopy-3] = 'o';
+ zOpen = (const char*)(pFd->zFilename = zCopy);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags);
+ }
+ if( pFd->pReal->pMethods ){
+ pFile->pMethods = &otavfs_io_methods;
+ if( pOtaVfs->pTargetDb==0 ){
+ /* This is the target db file. */
+ assert( (flags & SQLITE_OPEN_MAIN_DB) );
+ assert( zOpen==zName );
+ pOtaVfs->pTargetDb = pFd;
+ pOtaVfs->zTargetDb = zName;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Delete the file located at zPath.
+*/
+static int otaVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xDelete(pRealVfs, zPath, dirSync);
+}
+
+/*
+** Test for access permissions. Return true if the requested permission
+** is available, or false otherwise.
+*/
+static int otaVfsAccess(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int flags,
+ int *pResOut
+){
+ ota_vfs *pOtaVfs = (ota_vfs*)pVfs;
+ sqlite3_vfs *pRealVfs = pOtaVfs->pRealVfs;
+ int rc;
+
+ rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);
+
+ if( rc==SQLITE_OK
+ && flags==SQLITE_ACCESS_EXISTS
+ && pOtaVfs->pOta->eStage==OTA_STAGE_OAL
+ && otaVfsIswal(pOtaVfs, zPath)
+ ){
+ if( *pResOut ){
+ rc = SQLITE_CANTOPEN;
+ }else{
+ *pResOut = 1;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Populate buffer zOut with the full canonical pathname corresponding
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
+** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
+*/
+static int otaVfsFullPathname(
+ sqlite3_vfs *pVfs,
+ const char *zPath,
+ int nOut,
+ char *zOut
+){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xFullPathname(pRealVfs, zPath, nOut, zOut);
+}
+
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+/*
+** Open the dynamic library located at zPath and return a handle.
+*/
+static void *otaVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xDlOpen(pRealVfs, zPath);
+}
+
+/*
+** Populate the buffer zErrMsg (size nByte bytes) with a human readable
+** utf-8 string describing the most recent error encountered associated
+** with dynamic libraries.
+*/
+static void otaVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ pRealVfs->xDlError(pRealVfs, nByte, zErrMsg);
+}
+
+/*
+** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
+*/
+static void (*otaVfsDlSym(
+ sqlite3_vfs *pVfs,
+ void *pArg,
+ const char *zSym
+))(void){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xDlSym(pRealVfs, pArg, zSym);
+}
+
+/*
+** Close the dynamic library handle pHandle.
+*/
+static void otaVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xDlClose(pRealVfs, pHandle);
+}
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+
+/*
+** Populate the buffer pointed to by zBufOut with nByte bytes of
+** random data.
+*/
+static int otaVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xRandomness(pRealVfs, nByte, zBufOut);
+}
+
+/*
+** Sleep for nMicro microseconds. Return the number of microseconds
+** actually slept.
+*/
+static int otaVfsSleep(sqlite3_vfs *pVfs, int nMicro){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xSleep(pRealVfs, nMicro);
+}
+
+/*
+** Return the current time as a Julian Day number in *pTimeOut.
+*/
+static int otaVfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
+ sqlite3_vfs *pRealVfs = ((ota_vfs*)pVfs)->pRealVfs;
+ return pRealVfs->xCurrentTime(pRealVfs, pTimeOut);
+}
+
+static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
+ return 0;
+}
+
+static void otaCreateVfs(sqlite3ota *p, const char *zParent){
+
+ /* Template for VFS */
+ static sqlite3_vfs vfs_template = {
+ 1, /* iVersion */
+ 0, /* szOsFile */
+ 0, /* mxPathname */
+ 0, /* pNext */
+ 0, /* zName */
+ 0, /* pAppData */
+ otaVfsOpen, /* xOpen */
+ otaVfsDelete, /* xDelete */
+ otaVfsAccess, /* xAccess */
+ otaVfsFullPathname, /* xFullPathname */
+
+ otaVfsDlOpen, /* xDlOpen */
+ otaVfsDlError, /* xDlError */
+ otaVfsDlSym, /* xDlSym */
+ otaVfsDlClose, /* xDlClose */
+
+ otaVfsRandomness, /* xRandomness */
+ otaVfsSleep, /* xSleep */
+ otaVfsCurrentTime, /* xCurrentTime */
+ otaVfsGetLastError, /* xGetLastError */
+ 0, /* xCurrentTimeInt64 (version 2) */
+ 0, 0, 0 /* Unimplemented version 3 methods */
+ };
+
+ sqlite3_vfs *pParent; /* Parent VFS */
+ ota_vfs *pNew = 0; /* Newly allocated VFS */
+
+ assert( p->rc==SQLITE_OK );
+ pParent = sqlite3_vfs_find(zParent);
+ if( pParent==0 ){
+ p->rc = SQLITE_ERROR;
+ p->zErrmsg = sqlite3_mprintf("no such vfs: %s", zParent);
+ }else{
+ int nByte = sizeof(ota_vfs) + 64;
+ pNew = (ota_vfs*)otaMalloc(p, nByte);
+ }
+
+ if( pNew ){
+ int rnd;
+ char *zName;
+ memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
+ pNew->base.mxPathname = pParent->mxPathname;
+ pNew->base.szOsFile = sizeof(ota_file) + pParent->szOsFile;
+ pNew->pOta = p;
+ pNew->pRealVfs = pParent;
+
+ /* Give the new VFS a unique name */
+ sqlite3_randomness(sizeof(int), (void*)&rnd);
+ pNew->base.zName = (const char*)(zName = (char*)&pNew[1]);
+ sprintf(zName, "ota_vfs_%d", rnd);
+
+ /* Register the new VFS (not as the default) */
+ assert( p->rc==SQLITE_OK );
+ p->rc = sqlite3_vfs_register(&pNew->base, 0);
+ if( p->rc ){
+ p->zErrmsg = sqlite3_mprintf("error in sqlite3_vfs_register()");
+ sqlite3_free(pNew);
+ }else{
+ p->pVfs = &pNew->base;
+ }
+ }
+}
+
+static void otaDeleteVfs(sqlite3ota *p){
+ if( p->pVfs ){
+ sqlite3_vfs_unregister(p->pVfs);
+ sqlite3_free(p->pVfs);
+ p->pVfs = 0;
+ }
+}
+
/**************************************************************************/
-C Merge\sthe\scommand-line\sshell\senhancements\sfrom\strunk.
-D 2015-02-06T15:03:45.342
+C Remove\s"PRAGMA\spager_ota_mode".
+D 2015-02-07T19:17:36.157
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 6b9e7677829aa94b9f30949656e27312aefb9a46
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
-F ext/ota/README.txt 78d4a9f78f567d4bf826cf0f02df6254902562ca
+F ext/ota/README.txt 2ce4ffbb0aaa6731b041c27a7359f9a5f1c69152
F ext/ota/ota.c c11a85af71dccc45976622fe7a51169a481caa91
-F ext/ota/ota1.test 719854e444dff2ead58ff6b62d8315954bd7762a
+F ext/ota/ota1.test e6b64d6ffb23dcae72386da153626b40566a69e9
F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
-F ext/ota/ota2.test 2829bc08ffbb71b605392a68fedfd554763356a7
F ext/ota/ota3.test a77efbce7723332eb688d2b28bf18204fc9614d7
-F ext/ota/ota4.test 82434aa39c9acca6cd6317f6b0ab07b0ec6c2e7d
F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
-F ext/ota/ota6.test 82f1f757ec9b2ad07d6de4060b8e3ba8e44dfdd3
+F ext/ota/ota6.test 1fbba5fd46e3e0bfa5ae1d0caf9da27d15cb7cdf
F ext/ota/ota7.test 1fe2c5761705374530e29f70c39693076028221a
F ext/ota/ota8.test cd70e63a0c29c45c0906692827deafa34638feda
F ext/ota/ota9.test d3eee95dd836824d07a22e5efcdb7bf6e869358b
F ext/ota/otafault.test 508ba87c83d632670ac0f94371a465d4bb4d49dd
-F ext/ota/sqlite3ota.c bf417242a191617841cc1ab0815071b49444c9c8
+F ext/ota/sqlite3ota.c 7015400382d1d6655626046f2c1763634dd8a168
F ext/ota/sqlite3ota.h b4c54c7df5d223f2ee40efa5ba363188daa3ad37
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 14e6239434d4e3f65d3e90320713f26aa24e167f
F src/os_unix.c aefeaf915aaef9f81aa2645e0d5d06fa1bd83beb
F src/os_win.c 8223e7db5b7c4a81d8b161098ac3959400434cdb
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
-F src/pager.c 90b164ac8fefed940cd50fad6938cd18b55af8f3
-F src/pager.h 19d83e2782fe978976cb1acf474d09d9a6124ac3
+F src/pager.c 46bc7849b02c51e13f0165fa6d6faa452e91a957
+F src/pager.h 20954a3fa1bbf05d39063d94e789ad9efd15e5d1
F src/parse.y c5d0d964f9ac023e8154cad512e54b0b6058e086
F src/pcache.c d210cf90d04365a74f85d21374dded65af67b0cb
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
F src/pcache1.c 1e77432b40b7d3288327d9cdf399dcdfd2b6d3bf
-F src/pragma.c 8042d2b202140c49ffccb267aaa2012b50e337e4
-F src/pragma.h d2f776d719d156544638fe3f87f9627d8e16222f
+F src/pragma.c ea0be138a99784b14e87bd4522fea40e7b979e9c
+F src/pragma.h 09c89bca58e9a44de2116cc8272b8d454657129f
F src/prepare.c 173a5a499138451b2561614ecb87d78f9f4644b9
F src/printf.c 05edc41450d0eb2c05ef7db113bf32742ae65325
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/vdbesort.c 6d64c5448b64851b99931ede980addc3af70d5e2
F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9
-F src/wal.c 735d081f736fd7fecbf8f2aa213484e641ba35ff
+F src/wal.c 7a8a4e7a40d693d44dbfc4d1f2bcb7e2b620f530
F src/wal.h 0d3ba0c3f1b4c25796cb213568a84b9f9063f465
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
F src/where.c d46de821bc604a4fd36fa3928c086950e91aafb1
F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f
F tool/mkkeywordhash.c dfff09dbbfaf950e89af294f48f902181b144670
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
-F tool/mkpragmatab.tcl a5cb9b20ad7abb2ffd519c85f1f8f99bcbfa6823
+F tool/mkpragmatab.tcl 94f196c9961e0ca3513e29f57125a3197808be2d
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 9ef48e1748dce7b844f67e2450ff9dfeb0fb4ab5
F tool/mksqlite3c.tcl 6b8e572a90eb4e0086e3ba90d88b76c085919863
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 7f10a0eaf1fedfa020cbd7019ec9342ffdc3b9b0 0f65a7e2e09f801b66897479d501607caeae4abf
-R 1ef390b8e8775fda79ba88277a4a2044
-U drh
-Z f716caa3559c7f56ae8a7035846f96fb
+P c3931db560ab4a2601c7f7318fb02c8d5e6862b1
+R 8cb076bc2c2cc0b3b28786011832c69d
+T *branch * ota-update-no-pager_ota_mode
+T *sym-ota-update-no-pager_ota_mode *
+T -sym-ota-update *
+U dan
+Z b552e61eecb5b9b2a0bf7b3905abae17
u8 noLock; /* Do not lock (except in WAL mode) */
u8 readOnly; /* True for a read-only database */
u8 memDb; /* True to inhibit all file I/O */
-#ifdef SQLITE_ENABLE_OTA
- u8 otaMode; /* Non-zero if in ota_mode */
-#endif
/**************************************************************************
** The following block contains those class members that change during
#endif
};
-/*
-** Return the value of the pager otaMode flag (0, 1 or 2). Or, if
-** SQLITE_ENABLE_OTA is not defined, return constant value 0.
-*/
-#ifdef SQLITE_ENABLE_OTA
-# define PagerOtaMode(pPager) ((pPager)->otaMode)
-#else
-# define PagerOtaMode(pPager) 0
-#endif
-
/*
** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains
** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
}
- if( !pPager->exclusiveMode && !PagerOtaMode(pPager)
+ if( !pPager->exclusiveMode
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
){
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
/* pPager->errCode = 0; */
pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
- sqlite3WalClose(pPager->pWal,
- pPager->ckptSyncFlags, pPager->pageSize, (PagerOtaMode(pPager)?0:pTmp)
- );
+ sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, pTmp);
pPager->pWal = 0;
#endif
pager_reset(pPager);
** mode. Otherwise, the following function call is a no-op.
*/
rc = pagerOpenWalIfPresent(pPager);
- if( rc==SQLITE_OK && PagerOtaMode(pPager) ){
- int nWal = sqlite3Strlen30(pPager->zWal);
- pPager->zWal[nWal-3] = 'o';
- rc = pagerOpenWalInternal(pPager, 0);
- }
#ifndef SQLITE_OMIT_WAL
assert( pPager->pWal==0 || rc==SQLITE_OK );
if( pagerUseWal(pPager) ){
assert( rc==SQLITE_OK );
rc = pagerBeginReadTransaction(pPager);
- if( rc==SQLITE_OK && PagerOtaMode(pPager)==1 ){
- rc = sqlite3WalCheckSalt(pPager->pWal, pPager->fd);
- if( rc!=SQLITE_OK ){
- sqlite3WalClose(pPager->pWal, 0, 0, 0);
- pPager->pWal = 0;
- }else{
-#ifdef SQLITE_ENABLE_OTA
- pPager->otaMode = 2;
-#endif
- }
- }
}
if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
*/
int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
int rc = SQLITE_OK;
- if( pPager->pWal && PagerOtaMode(pPager)==0 ){
+ if( pPager->pWal ){
rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
pPager->pBusyHandlerArg,
*/
if( rc==SQLITE_OK ){
rc = sqlite3WalOpen(pPager->pVfs,
- pPager->fd, pPager->zWal, pPager->exclusiveMode || PagerOtaMode(pPager),
+ pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, &pPager->pWal
);
}
Pager *pPager, /* Pager object */
int *pbOpen /* OUT: Set to true if call is a no-op */
){
- if( PagerOtaMode(pPager) ) return SQLITE_CANTOPEN_BKPT;
return pagerOpenWalInternal(pPager, pbOpen);
}
return rc;
}
-/*
-** This function is called by the wal.c module to obtain the 8 bytes of
-** "salt" written into the wal file header. In OTA mode, this is a copy
-** of bytes 24-31 of the database file. In non-OTA mode, it is 8 bytes
-** of pseudo-random data.
-*/
-void sqlite3PagerWalSalt(Pager *pPager, u32 *aSalt){
- if( PagerOtaMode(pPager) ){
- memcpy(aSalt, pPager->dbFileVers, 8);
- }else{
- sqlite3_randomness(8, aSalt);
- }
-}
-
#endif /* !SQLITE_OMIT_WAL */
#ifdef SQLITE_ENABLE_ZIPVFS
#endif
#ifdef SQLITE_ENABLE_OTA
-/*
-** Set or clear the "OTA mode" flag.
-*/
-int sqlite3PagerSetOtaMode(Pager *pPager, int iOta){
- assert( iOta==1 || iOta==2 );
- if( iOta==1 && (pPager->pWal || pPager->eState!=PAGER_OPEN) ){
- return SQLITE_ERROR;
- }
- pPager->otaMode = iOta;
- return SQLITE_OK;
-}
/*
** Open an incremental checkpoint handle.