/ Check-in [209f672e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Split part of "PRAGMA ota_mode" off into "PRAGMA pager_ota_mode". This allows some specialized custom VFS implementations to intercept and implement the expected pager-related effects of this pragma.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: 209f672e588b54dfbfb83c7859cacdc4497f0f2b
User & Date: dan 2014-09-03 19:30:32
Context
2014-09-04
11:03
Avoid calling sqlite3OsFetch() on a file-handle for which the xFetch method is NULL. check-in: 071f7f2d user: dan tags: ota-update
2014-09-03
19:30
Split part of "PRAGMA ota_mode" off into "PRAGMA pager_ota_mode". This allows some specialized custom VFS implementations to intercept and implement the expected pager-related effects of this pragma. check-in: 209f672e user: dan tags: ota-update
08:25
Add a command line program that uses the extension. This serves as example code and is also useful for performance testing. check-in: ffa1524e user: dan tags: ota-update
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/ota/ota2.test.

    10     10   #***********************************************************************
    11     11   #
    12     12   
    13     13   set testdir [file join [file dirname $argv0] .. .. test]
    14     14   source $testdir/tester.tcl
    15     15   set ::testprefix ota2
    16     16   
           17  +forcedelete test.db-oal 
    17     18   
    18     19   do_execsql_test 1.0 {
    19         -  PRAGMA ota_mode = 1;
    20         -  PRAGMA journal_mode = wal;
    21     20     CREATE TABLE t1(a, b);
    22         -  BEGIN;
    23         -    INSERT INTO t1 VALUES(1, 2);
    24         -} {wal}
           21  +  INSERT INTO t1 VALUES(1, 2);
           22  +} {}
           23  +do_test 1.1 { glob test.db* } {test.db}
    25     24   
    26         -do_test 1.1 {
    27         -  set state [sqlite3_transaction_save db]
    28         -  db close
    29         -  file exists test.db-wal
    30         -} {1}
           25  +do_execsql_test 1.2 {
           26  +  PRAGMA pager_ota_mode = 1;
           27  +  INSERT INTO t1 VALUES(3, 4);
           28  +  INSERT INTO t1 VALUES(5, 6);
           29  +  SELECT * FROM t1;
           30  +} {1 2 3 4 5 6}
    31     31   
    32         -do_test 1.2 {
    33         -  sqlite3 db test.db
    34         -  db eval {SELECT * FROM t1}
    35         -} {}
    36         -
    37         -do_test 1.3 {
    38         -  execsql {BEGIN IMMEDIATE}
    39         -  sqlite3_transaction_restore db $::state
    40         -  db eval {SELECT * FROM t1}
    41         -} {1 2}
           32  +do_test 1.3 { glob test.db* } {test.db test.db-oal}
    42     33   
    43     34   do_test 1.4 {
    44         -  execsql {
    45         -    INSERT INTO t1 VALUES(3, 4);
    46         -    COMMIT;
    47         -    SELECT * FROM t1;
    48         -  }
    49         -} {1 2 3 4}
           35  +  sqlite3 db2 test.db
           36  +  db2 eval { SELECT * FROM t1 }
           37  +} {1 2}
    50     38   
    51     39   do_test 1.5 {
    52         -  db close
    53         -  file exists test.db-wal
    54         -} {0}
           40  +  catchsql { INSERT INTO t1 VALUES(7, 8) } db2
           41  +} {1 {database is locked}}
           42  +
           43  +db2 close
           44  +db close
           45  +
           46  +sqlite3 db test.db
           47  +do_execsql_test 1.6 {
           48  +  PRAGMA pager_ota_mode = 1;
           49  +  SELECT * FROM t1;
           50  +} {1 2 3 4 5 6}
           51  +
           52  +do_execsql_test 1.7 {
           53  +  INSERT INTO t1 VALUES(7,8);
           54  +  SELECT * FROM t1;
           55  +} {1 2 3 4 5 6 7 8}
           56  +
           57  +db close
           58  +sqlite3 db2 test.db
    55     59   
    56         -do_test 1.5 {
    57         -  sqlite3 db test.db
    58         -  db eval {SELECT * FROM t1}
    59         -} {1 2 3 4}
           60  +do_test 1.8 {
           61  +  execsql { BEGIN; SELECT * FROM t1 } db2
           62  +} {1 2}
           63  +do_test 1.9 {
           64  +  file rename test.db-oal test.db-wal
           65  +  execsql { SELECT * FROM t1 } db2
           66  +} {1 2}
           67  +do_test 1.10 {
           68  +  execsql { COMMIT; SELECT * FROM t1 } db2
           69  +} {1 2 3 4 5 6 7 8}
           70  +
    60     71   
    61     72   finish_test
    62     73   

Changes to ext/ota/sqlite3ota.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   */
    13     13   
    14     14   #include <assert.h>
    15     15   #include <string.h>
           16  +#include <stdio.h>
           17  +#include <unistd.h>
    16     18   
    17     19   #include "sqlite3.h"
    18     20   #include "sqlite3ota.h"
    19     21   
    20     22   
    21     23   /*
    22     24   ** The ota_state table is used to save the state of a partially applied
    23     25   ** update so that it can be resumed later. The table contains at most a
    24     26   ** single row:
    25     27   **
    26         -**   "wal_state" -> Blob to use with sqlite3_transaction_restore().
    27         -**
    28     28   **   "tbl"       -> Table currently being written (target database names).
    29     29   **
    30     30   **   "idx"       -> Index currently being written (target database names).
    31     31   **                  Or, if the main table is being written, a NULL value.
    32     32   **
    33     33   **   "row"       -> Last rowid processed from ota database table (i.e. data_%).
    34     34   **
    35     35   **   "progress"  -> total number of key/value b-tree operations performed
    36     36   **                  so far as part of this ota update.
    37     37   */
    38     38   #define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota_state"        \
    39         -                             "(wal_state, tbl, idx, row, progress)"
           39  +                             "(tbl, idx, row, progress)"
    40     40   
    41     41   typedef struct OtaTblIter OtaTblIter;
    42     42   typedef struct OtaIdxIter OtaIdxIter;
           43  +typedef struct OtaState OtaState;
    43     44   
    44     45   /*
    45     46   ** Iterator used to iterate through all data tables in the OTA. As follows:
    46     47   **
    47     48   **   OtaTblIter iter;
    48     49   **   for(rc=tblIterFirst(db, &iter); 
    49     50   **       rc==SQLITE_OK && iter.zTarget; 
................................................................................
    83     84   
    84     85     int nCol;                       /* Number of columns in index */
    85     86     int *aiCol;                     /* Array of column indexes */
    86     87     sqlite3_stmt *pWriter;          /* Index writer */
    87     88     sqlite3_stmt *pSelect;          /* Select to read values in index order */
    88     89   };
    89     90   
           91  +struct OtaState {
           92  +  char *zTbl;
           93  +  char *zIdx;
           94  +  sqlite3_int64 iRow;
           95  +};
           96  +
    90     97   
    91     98   struct sqlite3ota {
    92     99     sqlite3 *dbDest;                /* Target db */
    93    100     sqlite3 *dbOta;                 /* Ota db */
          101  +  char *zTarget;                  /* Path to target db */
    94    102   
    95    103     int rc;                         /* Value returned by last ota_step() call */
    96    104     char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */
    97    105   
    98    106     OtaTblIter tbliter;             /* Used to iterate through tables */
    99    107     OtaIdxIter idxiter;             /* Used to iterate through indexes */
   100    108   };
................................................................................
   502    510         const char *zErr = sqlite3_errmsg(*pDb);
   503    511         p->zErrmsg = sqlite3_mprintf("sqlite3_open(): %s", zErr);
   504    512       }
   505    513     }
   506    514   }
   507    515   
   508    516   static void otaSaveTransactionState(sqlite3ota *p){
   509         -  sqlite3_stmt *pStmt = 0;
   510         -  void *pWalState = 0;
   511         -  int nWalState = 0;
   512         -  int rc;
   513         -
   514         -  const char *zInsert = 
   515         -    "INSERT INTO ota_state(wal_state, tbl, idx, row, progress)"
   516         -    "VALUES(:wal_state, :tbl, :idx, :row, :progress)";
   517         -
   518         -  rc = sqlite3_transaction_save(p->dbDest, &pWalState, &nWalState);
   519         -  if( rc==SQLITE_OK ){
   520         -    rc = sqlite3_exec(p->dbOta, "DELETE FROM ota_state", 0, 0, 0);
   521         -  }
   522         -  if( rc==SQLITE_OK ){
   523         -    rc = prepareAndCollectError(p->dbOta, zInsert, &pStmt, &p->zErrmsg);
   524         -  }
   525         -  if( rc==SQLITE_OK ){
   526         -    sqlite3_stmt *pSelect;
   527         -    pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);
   528         -    sqlite3_bind_blob(pStmt, 1, pWalState, nWalState, SQLITE_STATIC);
   529         -    sqlite3_bind_text(pStmt, 2, p->tbliter.zTarget, -1, SQLITE_STATIC);
   530         -    if( p->idxiter.zIndex ){
   531         -      sqlite3_bind_text(pStmt, 3, p->idxiter.zIndex, -1, SQLITE_STATIC);
   532         -    }
   533         -    sqlite3_bind_int64(pStmt, 4, sqlite3_column_int64(pSelect, 0));
   534         -    sqlite3_step(pStmt);
   535         -    rc = sqlite3_finalize(pStmt);
   536         -    if( rc==SQLITE_OK ){
   537         -      rc = sqlite3_exec(p->dbOta, "COMMIT", 0, 0, 0);
   538         -    }
   539         -    if( rc!=SQLITE_OK ){
   540         -      p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->dbOta));
          517  +  sqlite3_stmt *pSelect;
          518  +  char *zInsert;
          519  +
          520  +  pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);
          521  +  zInsert = sqlite3_mprintf(
          522  +    "INSERT OR REPLACE INTO ota_state(rowid, tbl, idx, row, progress)"
          523  +    "VALUES(1, %Q, %Q, %lld, NULL)",
          524  +    p->tbliter.zTarget, p->idxiter.zIndex, sqlite3_column_int64(pSelect, 0)
          525  +  );
          526  +  if( zInsert==0 ){
          527  +    p->rc = SQLITE_NOMEM;
          528  +  }else{
          529  +    p->rc = sqlite3_exec(p->dbOta, zInsert, 0, 0, &p->zErrmsg);
          530  +    if( p->rc==SQLITE_OK ){
          531  +      p->rc = sqlite3_exec(p->dbOta, "COMMIT", 0, 0, &p->zErrmsg);
   541    532       }
   542    533     }
   543         -  sqlite3_free(pWalState);
   544         -  assert( p->rc==SQLITE_OK );
   545         -  p->rc = rc;
          534  +
          535  +  sqlite3_free(zInsert);
   546    536   }
   547    537   
   548         -static void otaLoadTransactionState(sqlite3ota *p){
   549         -  sqlite3_stmt *pStmt = 0;
          538  +/*
          539  +** Allocate an OtaState object and load the contents of the ota_state 
          540  +** table into it. Return a pointer to the new object. It is the 
          541  +** responsibility of the caller to eventually free the object using
          542  +** sqlite3_free().
          543  +**
          544  +** If an error occurs, leave an error code and message in the ota handle
          545  +** and return NULL.
          546  +*/
          547  +static OtaState *otaLoadState(sqlite3ota *p){
          548  +  const char *zSelect = "SELECT tbl, idx, row, progress FROM ota_state";
          549  +  OtaState *pRet = 0;
          550  +  sqlite3_stmt *pStmt;
   550    551     int rc;
   551    552   
   552         -  const char *zSelect = 
   553         -    "SELECT wal_state, tbl, idx, row, progress FROM ota_state";
   554         -
          553  +  assert( p->rc==SQLITE_OK );
   555    554     rc = prepareAndCollectError(p->dbOta, zSelect, &pStmt, &p->zErrmsg);
   556    555     if( rc==SQLITE_OK ){
   557         -    if( SQLITE_ROW==sqlite3_step(pStmt) ){
   558         -      const void *pWalState = 0;
   559         -      int nWalState = 0;
   560         -      const char *zTbl;
   561         -      const char *zIdx;
   562         -      sqlite3_int64 iRowid;
   563         -
   564         -      pWalState = sqlite3_column_blob(pStmt, 0);
   565         -      nWalState = sqlite3_column_bytes(pStmt, 0);
   566         -      zTbl = (const char*)sqlite3_column_text(pStmt, 1);
   567         -      zIdx = (const char*)sqlite3_column_text(pStmt, 2);
   568         -      iRowid = sqlite3_column_int64(pStmt, 3);
   569         -      rc = sqlite3_transaction_restore(p->dbDest, pWalState, nWalState);
   570         -
          556  +    if( sqlite3_step(pStmt)==SQLITE_ROW ){
          557  +      const char *zIdx = (const char*)sqlite3_column_text(pStmt, 1);
          558  +      const char *zTbl = (const char*)sqlite3_column_text(pStmt, 0);
          559  +      int nIdx = zIdx ? (strlen(zIdx) + 1) : 0;
          560  +      int nTbl = strlen(zTbl) + 1;
          561  +      int nByte = sizeof(OtaState) + nTbl + nIdx;
          562  +
          563  +      pRet = (OtaState*)sqlite3_malloc(nByte);
          564  +      if( pRet ){
          565  +        pRet->zTbl = (char*)&pRet[1];
          566  +        memcpy(pRet->zTbl, sqlite3_column_text(pStmt, 0), nTbl);
          567  +        if( zIdx ){
          568  +          pRet->zIdx = &pRet->zTbl[nTbl];
          569  +          memcpy(pRet->zIdx, zIdx, nIdx);
          570  +        }else{
          571  +          pRet->zIdx = 0;
          572  +        }
          573  +        pRet->iRow = sqlite3_column_int64(pStmt, 2);
          574  +      }
          575  +    }else{
          576  +      pRet = (OtaState*)sqlite3_malloc(sizeof(OtaState));
          577  +      if( pRet ){
          578  +        memset(pRet, 0, sizeof(*pRet));
          579  +      }
          580  +    }
          581  +    rc = sqlite3_finalize(pStmt);
          582  +    if( rc==SQLITE_OK && pRet==0 ) rc = SQLITE_NOMEM;
          583  +    if( rc!=SQLITE_OK ){
          584  +      sqlite3_free(pRet);
          585  +      pRet = 0;
          586  +    }
          587  +  }
          588  +
          589  +  p->rc = rc;
          590  +  return pRet;
          591  +}
          592  +
          593  +static void otaLoadTransactionState(sqlite3ota *p, OtaState *pState){
          594  +  assert( p->rc==SQLITE_OK );
          595  +  if( pState->zTbl ){
          596  +    int rc;
          597  +    while( rc==SQLITE_OK 
          598  +        && p->tbliter.zTarget 
          599  +        && sqlite3_stricmp(p->tbliter.zTarget, pState->zTbl) 
          600  +        ){
          601  +      rc = tblIterNext(&p->tbliter);
          602  +    }
          603  +    if( rc==SQLITE_OK && !p->tbliter.zTarget ){
          604  +      rc = SQLITE_ERROR;
          605  +      p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
          606  +    }
          607  +
          608  +    if( rc==SQLITE_OK && pState->zIdx ){
          609  +      rc = idxIterFirst(p->dbDest, p->tbliter.zTarget, &p->idxiter);
   571    610         while( rc==SQLITE_OK 
   572         -          && p->tbliter.zTarget 
   573         -          && sqlite3_stricmp(p->tbliter.zTarget, zTbl) 
   574         -      ){
   575         -        rc = tblIterNext(&p->tbliter);
          611  +          && p->idxiter.zIndex 
          612  +          && sqlite3_stricmp(p->idxiter.zIndex, pState->zIdx) 
          613  +          ){
          614  +        rc = idxIterNext(&p->idxiter);
          615  +      }
          616  +      if( rc==SQLITE_OK && !p->idxiter.zIndex ){
          617  +        rc = SQLITE_ERROR;
          618  +        p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
          619  +      }
          620  +    }
          621  +
          622  +    if( rc==SQLITE_OK ){
          623  +      rc = otaPrepareAll(p);
          624  +    }
          625  +
          626  +    if( rc==SQLITE_OK ){
          627  +      sqlite3_stmt *pSelect;
          628  +      pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);
          629  +      while( sqlite3_column_int64(pSelect, 0)!=pState->iRow ){
          630  +        rc = sqlite3_step(pSelect);
          631  +        if( rc!=SQLITE_ROW ) break;
   576    632         }
   577         -      if( rc==SQLITE_OK && !p->tbliter.zTarget ){
          633  +      if( rc==SQLITE_ROW ){
          634  +        rc = SQLITE_OK;
          635  +      }else{
   578    636           rc = SQLITE_ERROR;
   579    637           p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
   580    638         }
   581         -
   582         -      if( rc==SQLITE_OK && zIdx ){
   583         -        rc = idxIterFirst(p->dbDest, p->tbliter.zTarget, &p->idxiter);
   584         -        while( rc==SQLITE_OK 
   585         -            && p->idxiter.zIndex 
   586         -            && sqlite3_stricmp(p->idxiter.zIndex, zIdx) 
   587         -        ){
   588         -          rc = idxIterNext(&p->idxiter);
   589         -        }
   590         -        if( rc==SQLITE_OK && !p->idxiter.zIndex ){
   591         -          rc = SQLITE_ERROR;
   592         -          p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
   593         -        }
   594         -      }
   595         -
   596         -      if( rc==SQLITE_OK ){
   597         -        rc = otaPrepareAll(p);
   598         -      }
   599         -
   600         -      if( rc==SQLITE_OK ){
   601         -        sqlite3_stmt *pSelect;
   602         -        pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);
   603         -        while( sqlite3_column_int64(pSelect, 0)!=iRowid ){
   604         -          rc = sqlite3_step(pSelect);
   605         -          if( rc!=SQLITE_ROW ) break;
   606         -        }
   607         -        if( rc==SQLITE_ROW ){
   608         -          rc = SQLITE_OK;
   609         -        }else{
   610         -          rc = SQLITE_ERROR;
   611         -          p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
   612         -        }
   613         -      }
   614    639       }
   615         -    if( rc==SQLITE_OK ){
   616         -      rc = sqlite3_finalize(pStmt);
   617         -    }else{
   618         -      sqlite3_finalize(pStmt);
   619         -    }
          640  +    p->rc = rc;
          641  +  }
          642  +}
          643  +
          644  +/*
          645  +** Move the "*-oal" file corresponding to the target database to the
          646  +** "*-wal" location. If an error occurs, leave an error code and error 
          647  +** message in the ota handle.
          648  +*/
          649  +static void otaMoveOalFile(sqlite3ota *p){
          650  +  char *zWal = sqlite3_mprintf("%s-wal", p->zTarget);
          651  +  char *zOal = sqlite3_mprintf("%s-oal", p->zTarget);
          652  +
          653  +  assert( p->rc==SQLITE_DONE && p->zErrmsg==0 );
          654  +  if( zWal==0 || zOal==0 ){
          655  +    p->rc = SQLITE_NOMEM;
          656  +  }else{
          657  +    rename(zOal, zWal);
   620    658     }
   621         -  p->rc = rc;
          659  +
          660  +  sqlite3_free(zWal);
          661  +  sqlite3_free(zOal);
   622    662   }
   623    663   
          664  +/*
          665  +** If there is a "*-oal" file in the file-system corresponding to the
          666  +** target database in the file-system, delete it. If an error occurs,
          667  +** leave an error code and error message in the ota handle.
          668  +*/
          669  +static void otaDeleteOalFile(sqlite3ota *p){
          670  +  char *zOal = sqlite3_mprintf("%s-oal", p->zTarget);
          671  +  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
          672  +  unlink(zOal);
          673  +  sqlite3_free(zOal);
          674  +}
   624    675   
   625    676   /*
   626    677   ** Open and return a new OTA handle. 
   627    678   */
   628    679   sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
   629    680     sqlite3ota *p;
          681  +  int nTarget = strlen(zTarget);
   630    682   
   631         -  p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota));
          683  +  p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)+nTarget+1);
   632    684     if( p ){
          685  +    OtaState *pState = 0;
   633    686   
   634    687       /* Open the target database */
   635    688       memset(p, 0, sizeof(sqlite3ota));
          689  +    p->zTarget = (char*)&p[1];
          690  +    memcpy(p->zTarget, zTarget, nTarget+1);
   636    691       otaOpenDatabase(p, &p->dbDest, zTarget);
   637    692       otaOpenDatabase(p, &p->dbOta, zOta);
   638    693   
   639    694       /* If it has not already been created, create the ota_state table */
   640    695       if( p->rc==SQLITE_OK ){
   641    696         p->rc = sqlite3_exec(p->dbOta, OTA_CREATE_STATE, 0, 0, &p->zErrmsg);
   642    697       }
   643    698   
   644    699       if( p->rc==SQLITE_OK ){
   645         -      const char *zScript = 
          700  +      pState = otaLoadState(p);
          701  +      if( pState && pState->zTbl==0 ){
          702  +        otaDeleteOalFile(p);
          703  +      }
          704  +    }
          705  +
          706  +
          707  +    if( p->rc==SQLITE_OK ){
          708  +      const char *zScript =
          709  +        "PRAGMA journal_mode=off;"
          710  +        "PRAGMA pager_ota_mode=1;"
   646    711           "PRAGMA ota_mode=1;"
   647         -        "PRAGMA journal_mode=wal;"
   648    712           "BEGIN IMMEDIATE;"
   649    713         ;
   650    714         p->rc = sqlite3_exec(p->dbDest, zScript, 0, 0, &p->zErrmsg);
   651    715       }
   652    716   
   653    717       if( p->rc==SQLITE_OK ){
   654    718         const char *zScript = "BEGIN IMMEDIATE";
................................................................................
   657    721   
   658    722       /* Point the table iterator at the first table */
   659    723       if( p->rc==SQLITE_OK ){
   660    724         p->rc = tblIterFirst(p->dbOta, &p->tbliter);
   661    725       }
   662    726   
   663    727       if( p->rc==SQLITE_OK ){
   664         -      otaLoadTransactionState(p);
          728  +      otaLoadTransactionState(p, pState);
   665    729       }
          730  +
          731  +    sqlite3_free(pState);
   666    732     }
   667    733   
   668    734     return p;
   669    735   }
   670    736   
   671    737   static void otaCloseHandle(sqlite3 *db){
   672    738     int rc = sqlite3_close(db);
................................................................................
   686    752         otaSaveTransactionState(p);
   687    753       }
   688    754   
   689    755       /* Close all open statement handles. */
   690    756       tblIterFinalize(&p->tbliter);
   691    757       idxIterFinalize(&p->idxiter);
   692    758   
   693         -    /* If the ota update has been fully applied, commit the transaction
   694         -    ** on the target database. */
   695         -    if( p->rc==SQLITE_DONE ){
          759  +    /* Commit the transaction to the *-oal file. */
          760  +    if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
   696    761         rc = sqlite3_exec(p->dbDest, "COMMIT", 0, 0, &p->zErrmsg);
   697    762         if( rc!=SQLITE_OK ) p->rc = rc;
          763  +    }
          764  +    otaCloseHandle(p->dbDest);
          765  +    otaCloseHandle(p->dbOta);
          766  +
          767  +    if( p->rc==SQLITE_DONE ){
          768  +      otaMoveOalFile(p);
   698    769       }
   699    770   
   700    771       rc = p->rc;
   701    772       *pzErrmsg = p->zErrmsg;
   702         -    otaCloseHandle(p->dbDest);
   703         -    otaCloseHandle(p->dbOta);
   704    773       sqlite3_free(p);
   705    774     }else{
   706    775       rc = SQLITE_NOMEM;
   707    776       *pzErrmsg = 0;
   708    777     }
   709    778     return rc;
   710    779   }

Changes to src/btree.c.

  2042   2042     }
  2043   2043   #endif
  2044   2044     *ppBtree = p;
  2045   2045   
  2046   2046   btree_open_out:
  2047   2047     if( rc!=SQLITE_OK ){
  2048   2048       if( pBt && pBt->pPager ){
  2049         -      sqlite3PagerClose(pBt->pPager, 0);
         2049  +      sqlite3PagerClose(pBt->pPager);
  2050   2050       }
  2051   2051       sqlite3_free(pBt);
  2052   2052       sqlite3_free(p);
  2053   2053       *ppBtree = 0;
  2054   2054     }else{
  2055   2055       /* If the B-Tree was successfully opened, set the pager-cache size to the
  2056   2056       ** default value. Except, when opening on an existing shared pager-cache,
................................................................................
  2171   2171     if( !p->sharable || removeFromSharingList(pBt) ){
  2172   2172       /* The pBt is no longer on the sharing list, so we can access
  2173   2173       ** it without having to hold the mutex.
  2174   2174       **
  2175   2175       ** Clean out and delete the BtShared object.
  2176   2176       */
  2177   2177       assert( !pBt->pCursor );
  2178         -    sqlite3PagerClose(pBt->pPager, (p->db->flags & SQLITE_OtaMode)!=0);
         2178  +    sqlite3PagerClose(pBt->pPager);
  2179   2179       if( pBt->xFreeSchema && pBt->pSchema ){
  2180   2180         pBt->xFreeSchema(pBt->pSchema);
  2181   2181       }
  2182   2182       sqlite3DbFree(0, pBt->pSchema);
  2183   2183       freeTempSpace(pBt);
  2184   2184       sqlite3_free(pBt);
  2185   2185     }

Changes to src/pager.c.

   626    626     u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */
   627    627     u8 walSyncFlags;            /* SYNC_NORMAL or SYNC_FULL for wal writes */
   628    628     u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */
   629    629     u8 tempFile;                /* zFilename is a temporary or immutable file */
   630    630     u8 noLock;                  /* Do not lock (except in WAL mode) */
   631    631     u8 readOnly;                /* True for a read-only database */
   632    632     u8 memDb;                   /* True to inhibit all file I/O */
          633  +  u8 otaMode;                 /* True if in ota_mode */
   633    634   
   634    635     /**************************************************************************
   635    636     ** The following block contains those class members that change during
   636    637     ** routine opertion.  Class members not in this block are either fixed
   637    638     ** when the pager is first created or else only change when there is a
   638    639     ** significant mode change (such as changing the page_size, locking_mode,
   639    640     ** or the journal_mode).  From another view, these class members describe
................................................................................
   819    820   #else
   820    821   # define pagerUseWal(x) 0
   821    822   # define pagerRollbackWal(x) 0
   822    823   # define pagerWalFrames(v,w,x,y) 0
   823    824   # define pagerOpenWalIfPresent(z) SQLITE_OK
   824    825   # define pagerBeginReadTransaction(z) SQLITE_OK
   825    826   #endif
          827  +
          828  +static int pagerOpenWalInternal(Pager*, int*);
   826    829   
   827    830   #ifndef NDEBUG 
   828    831   /*
   829    832   ** Usage:
   830    833   **
   831    834   **   assert( assert_pager_state(pPager) );
   832    835   **
................................................................................
  2002   2005     }
  2003   2006   
  2004   2007     if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
  2005   2008       rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
  2006   2009       if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
  2007   2010     }
  2008   2011   
  2009         -  if( !pPager->exclusiveMode 
         2012  +  if( !pPager->exclusiveMode && !pPager->otaMode
  2010   2013      && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
  2011   2014     ){
  2012   2015       rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
  2013   2016       pPager->changeCountDone = 0;
  2014   2017     }
  2015   2018     pPager->eState = PAGER_READER;
  2016   2019     pPager->setMaster = 0;
................................................................................
  3943   3946   ** result in a coredump.
  3944   3947   **
  3945   3948   ** This function always succeeds. If a transaction is active an attempt
  3946   3949   ** is made to roll it back. If an error occurs during the rollback 
  3947   3950   ** a hot journal may be left in the filesystem but no error is returned
  3948   3951   ** to the caller.
  3949   3952   */
  3950         -int sqlite3PagerClose(Pager *pPager, int bOtaMode){
         3953  +int sqlite3PagerClose(Pager *pPager){
  3951   3954     u8 *pTmp = (u8 *)pPager->pTmpSpace;
  3952   3955   
  3953   3956     assert( assert_pager_state(pPager) );
  3954   3957     disable_simulated_io_errors();
  3955   3958     sqlite3BeginBenignMalloc();
  3956   3959     pagerFreeMapHdrs(pPager);
  3957   3960     /* pPager->errCode = 0; */
  3958   3961     pPager->exclusiveMode = 0;
  3959   3962   #ifndef SQLITE_OMIT_WAL
  3960         -  sqlite3WalClose(
  3961         -      pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, (bOtaMode?0:pTmp)
         3963  +  sqlite3WalClose(pPager->pWal, 
         3964  +      pPager->ckptSyncFlags, pPager->pageSize, (pPager->otaMode?0:pTmp)
  3962   3965     );
  3963   3966     pPager->pWal = 0;
  3964   3967   #endif
  3965   3968     pager_reset(pPager);
  3966   3969     if( MEMDB ){
  3967   3970       pager_unlock(pPager);
  3968   3971     }else{
................................................................................
  5160   5163         }
  5161   5164       }
  5162   5165   
  5163   5166       /* If there is a WAL file in the file-system, open this database in WAL
  5164   5167       ** mode. Otherwise, the following function call is a no-op.
  5165   5168       */
  5166   5169       rc = pagerOpenWalIfPresent(pPager);
         5170  +    if( rc==SQLITE_OK && pPager->otaMode ){
         5171  +      int nWal = sqlite3Strlen30(pPager->zWal);
         5172  +      pPager->zWal[nWal-3] = 'o';
         5173  +      rc = pagerOpenWalInternal(pPager, 0);
         5174  +    }
         5175  +
  5167   5176   #ifndef SQLITE_OMIT_WAL
  5168   5177       assert( pPager->pWal==0 || rc==SQLITE_OK );
  5169   5178   #endif
  5170   5179     }
  5171   5180   
  5172   5181     if( pagerUseWal(pPager) ){
  5173   5182       assert( rc==SQLITE_OK );
................................................................................
  7114   7123     }
  7115   7124   
  7116   7125     /* Open the connection to the log file. If this operation fails, 
  7117   7126     ** (e.g. due to malloc() failure), return an error code.
  7118   7127     */
  7119   7128     if( rc==SQLITE_OK ){
  7120   7129       rc = sqlite3WalOpen(pPager->pVfs,
  7121         -        pPager->fd, pPager->zWal, pPager->exclusiveMode,
         7130  +        pPager->fd, pPager->zWal, pPager->exclusiveMode || pPager->otaMode,
  7122   7131           pPager->journalSizeLimit, &pPager->pWal
  7123   7132       );
  7124   7133     }
  7125   7134     pagerFixMaplimit(pPager);
  7126   7135   
  7127   7136     return rc;
  7128   7137   }
  7129   7138   
  7130         -
  7131         -/*
  7132         -** The caller must be holding a SHARED lock on the database file to call
  7133         -** this function.
  7134         -**
  7135         -** If the pager passed as the first argument is open on a real database
  7136         -** file (not a temp file or an in-memory database), and the WAL file
  7137         -** is not already open, make an attempt to open it now. If successful,
  7138         -** return SQLITE_OK. If an error occurs or the VFS used by the pager does 
  7139         -** not support the xShmXXX() methods, return an error code. *pbOpen is
  7140         -** not modified in either case.
  7141         -**
  7142         -** If the pager is open on a temp-file (or in-memory database), or if
  7143         -** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK
  7144         -** without doing anything.
  7145         -*/
  7146         -int sqlite3PagerOpenWal(
         7139  +static int pagerOpenWalInternal(
  7147   7140     Pager *pPager,                  /* Pager object */
  7148   7141     int *pbOpen                     /* OUT: Set to true if call is a no-op */
  7149   7142   ){
  7150   7143     int rc = SQLITE_OK;             /* Return code */
  7151   7144   
  7152   7145     assert( assert_pager_state(pPager) );
  7153   7146     assert( pPager->eState==PAGER_OPEN   || pbOpen );
................................................................................
  7168   7161       }
  7169   7162     }else{
  7170   7163       *pbOpen = 1;
  7171   7164     }
  7172   7165   
  7173   7166     return rc;
  7174   7167   }
         7168  +
         7169  +/*
         7170  +** The caller must be holding a SHARED lock on the database file to call
         7171  +** this function.
         7172  +**
         7173  +** If the pager passed as the first argument is open on a real database
         7174  +** file (not a temp file or an in-memory database), and the WAL file
         7175  +** is not already open, make an attempt to open it now. If successful,
         7176  +** return SQLITE_OK. If an error occurs or the VFS used by the pager does 
         7177  +** not support the xShmXXX() methods, return an error code. *pbOpen is
         7178  +** not modified in either case.
         7179  +**
         7180  +** If the pager is open on a temp-file (or in-memory database), or if
         7181  +** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK
         7182  +** without doing anything.
         7183  +*/
         7184  +int sqlite3PagerOpenWal(
         7185  +  Pager *pPager,                  /* Pager object */
         7186  +  int *pbOpen                     /* OUT: Set to true if call is a no-op */
         7187  +){
         7188  +  if( pPager->otaMode ) return SQLITE_CANTOPEN;
         7189  +  return pagerOpenWalInternal(pPager, pbOpen);
         7190  +}
  7175   7191   
  7176   7192   /*
  7177   7193   ** This function is called to close the connection to the log file prior
  7178   7194   ** to switching from WAL to rollback mode.
  7179   7195   **
  7180   7196   ** Before closing the log file, this function attempts to take an 
  7181   7197   ** EXCLUSIVE lock on the database file. If this cannot be obtained, an
................................................................................
  7265   7281   ** is empty, return 0.
  7266   7282   */
  7267   7283   int sqlite3PagerWalFramesize(Pager *pPager){
  7268   7284     assert( pPager->eState==PAGER_READER );
  7269   7285     return sqlite3WalFramesize(pPager->pWal);
  7270   7286   }
  7271   7287   #endif
         7288  +
         7289  +/*
         7290  +** Set or clear the "OTA mode" flag.
         7291  +*/
         7292  +int sqlite3PagerSetOtaMode(Pager *pPager, int bOta){
         7293  +  if( pPager->pWal || pPager->eState!=PAGER_OPEN ){
         7294  +    return SQLITE_ERROR;
         7295  +  }
         7296  +  pPager->otaMode = (u8)bOta;
         7297  +  return SQLITE_OK;
         7298  +}
  7272   7299   
  7273   7300   #endif /* SQLITE_OMIT_DISKIO */

Changes to src/pager.h.

   108    108     Pager **ppPager,
   109    109     const char*,
   110    110     int,
   111    111     int,
   112    112     int,
   113    113     void(*)(DbPage*)
   114    114   );
   115         -int sqlite3PagerClose(Pager *pPager, int);
          115  +int sqlite3PagerClose(Pager *pPager);
   116    116   int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
   117    117   
   118    118   /* Functions used to configure a Pager object. */
   119    119   void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
   120    120   int sqlite3PagerSetPagesize(Pager*, u32*, int);
   121    121   int sqlite3PagerMaxPageCount(Pager*, int);
   122    122   void sqlite3PagerSetCachesize(Pager*, int);
................................................................................
   205    205   #else
   206    206   # define disable_simulated_io_errors()
   207    207   # define enable_simulated_io_errors()
   208    208   #endif
   209    209   
   210    210   int sqlite3PagerSaveState(Pager *pPager, void **ppState, int *pnState);
   211    211   int sqlite3PagerRestoreState(Pager *pPager, const void *pState, int nState);
          212  +
          213  +int sqlite3PagerSetOtaMode(Pager *pPager, int bOta);
   212    214   
   213    215   #endif /* _PAGER_H_ */

Changes to src/pragma.c.

    49     49   #define PragTyp_JOURNAL_MODE                  18
    50     50   #define PragTyp_JOURNAL_SIZE_LIMIT            19
    51     51   #define PragTyp_LOCK_PROXY_FILE               20
    52     52   #define PragTyp_LOCKING_MODE                  21
    53     53   #define PragTyp_PAGE_COUNT                    22
    54     54   #define PragTyp_MMAP_SIZE                     23
    55     55   #define PragTyp_PAGE_SIZE                     24
    56         -#define PragTyp_SECURE_DELETE                 25
    57         -#define PragTyp_SHRINK_MEMORY                 26
    58         -#define PragTyp_SOFT_HEAP_LIMIT               27
    59         -#define PragTyp_STATS                         28
    60         -#define PragTyp_SYNCHRONOUS                   29
    61         -#define PragTyp_TABLE_INFO                    30
    62         -#define PragTyp_TEMP_STORE                    31
    63         -#define PragTyp_TEMP_STORE_DIRECTORY          32
    64         -#define PragTyp_THREADS                       33
    65         -#define PragTyp_WAL_AUTOCHECKPOINT            34
    66         -#define PragTyp_WAL_CHECKPOINT                35
    67         -#define PragTyp_ACTIVATE_EXTENSIONS           36
    68         -#define PragTyp_HEXKEY                        37
    69         -#define PragTyp_KEY                           38
    70         -#define PragTyp_REKEY                         39
    71         -#define PragTyp_LOCK_STATUS                   40
    72         -#define PragTyp_PARSER_TRACE                  41
           56  +#define PragTyp_PAGER_OTA_MODE                25
           57  +#define PragTyp_SECURE_DELETE                 26
           58  +#define PragTyp_SHRINK_MEMORY                 27
           59  +#define PragTyp_SOFT_HEAP_LIMIT               28
           60  +#define PragTyp_STATS                         29
           61  +#define PragTyp_SYNCHRONOUS                   30
           62  +#define PragTyp_TABLE_INFO                    31
           63  +#define PragTyp_TEMP_STORE                    32
           64  +#define PragTyp_TEMP_STORE_DIRECTORY          33
           65  +#define PragTyp_THREADS                       34
           66  +#define PragTyp_WAL_AUTOCHECKPOINT            35
           67  +#define PragTyp_WAL_CHECKPOINT                36
           68  +#define PragTyp_ACTIVATE_EXTENSIONS           37
           69  +#define PragTyp_HEXKEY                        38
           70  +#define PragTyp_KEY                           39
           71  +#define PragTyp_REKEY                         40
           72  +#define PragTyp_LOCK_STATUS                   41
           73  +#define PragTyp_PARSER_TRACE                  42
    73     74   #define PragFlag_NeedSchema           0x01
    74     75   static const struct sPragmaNames {
    75     76     const char *const zName;  /* Name of pragma */
    76     77     u8 ePragTyp;              /* PragTyp_XXX value */
    77     78     u8 mPragFlag;             /* Zero or more PragFlag_XXX values */
    78     79     u32 iArg;                 /* Extra argument */
    79     80   } aPragmaNames[] = {
................................................................................
   319    320       /* ePragFlag: */ PragFlag_NeedSchema,
   320    321       /* iArg:      */ 0 },
   321    322     { /* zName:     */ "page_size",
   322    323       /* ePragTyp:  */ PragTyp_PAGE_SIZE,
   323    324       /* ePragFlag: */ 0,
   324    325       /* iArg:      */ 0 },
   325    326   #endif
          327  +  { /* zName:     */ "pager_ota_mode",
          328  +    /* ePragTyp:  */ PragTyp_PAGER_OTA_MODE,
          329  +    /* ePragFlag: */ 0,
          330  +    /* iArg:      */ 0 },
   326    331   #if defined(SQLITE_DEBUG)
   327    332     { /* zName:     */ "parser_trace",
   328    333       /* ePragTyp:  */ PragTyp_PARSER_TRACE,
   329    334       /* ePragFlag: */ 0,
   330    335       /* iArg:      */ 0 },
   331    336   #endif
   332    337   #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
................................................................................
   472    477   #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
   473    478     { /* zName:     */ "writable_schema",
   474    479       /* ePragTyp:  */ PragTyp_FLAG,
   475    480       /* ePragFlag: */ 0,
   476    481       /* iArg:      */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
   477    482   #endif
   478    483   };
   479         -/* Number of pragmas: 57 on by default, 70 total. */
          484  +/* Number of pragmas: 59 on by default, 72 total. */
          485  +/* Number of pragmas: 58 on by default, 71 total. */
   480    486   /* End of the automatically generated pragma table.
   481    487   ***************************************************************************/
   482    488   
   483    489   /*
   484    490   ** Interpret the given string as a safety level.  Return 0 for OFF,
   485    491   ** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
   486    492   ** unrecognized string argument.  The FULL option is disallowed
................................................................................
   865    871         assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
   866    872         pDb->pSchema->cache_size = size;
   867    873         sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
   868    874       }
   869    875       break;
   870    876     }
   871    877   #endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */
          878  +
          879  +  /*
          880  +  **  PRAGMA [database.]pager_ota_mode=[01]
          881  +  */
          882  +  case PragTyp_PAGER_OTA_MODE: {
          883  +    Btree *pBt = pDb->pBt;
          884  +    assert( pBt!=0 );
          885  +    if( zRight ){
          886  +      int iArg = !!sqlite3Atoi(zRight);
          887  +      rc = sqlite3PagerSetOtaMode(sqlite3BtreePager(pBt), iArg);
          888  +    }
          889  +    break;
          890  +  }
   872    891   
   873    892   #if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
   874    893     /*
   875    894     **  PRAGMA [database.]page_size
   876    895     **  PRAGMA [database.]page_size=N
   877    896     **
   878    897     ** The first form reports the current setting for the

Changes to src/test2.c.

    85     85     int rc;
    86     86     if( argc!=2 ){
    87     87       Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    88     88          " ID\"", 0);
    89     89       return TCL_ERROR;
    90     90     }
    91     91     pPager = sqlite3TestTextToPtr(argv[1]);
    92         -  rc = sqlite3PagerClose(pPager, 0);
           92  +  rc = sqlite3PagerClose(pPager);
    93     93     if( rc!=SQLITE_OK ){
    94     94       Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
    95     95       return TCL_ERROR;
    96     96     }
    97     97     return TCL_OK;
    98     98   }
    99     99   

Changes to tool/mkpragmatab.tcl.

   292    292   
   293    293     NAME: activate_extensions
   294    294     IF:   defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
   295    295   
   296    296     NAME: soft_heap_limit
   297    297   
   298    298     NAME: threads
          299  +
          300  +  NAME: pager_ota_mode
          301  +
          302  +  NAME: ota_mode
          303  +  TYPE: FLAG
          304  +  ARG:  SQLITE_OtaMode
   299    305   }
   300    306   fconfigure stdout -translation lf
   301    307   set name {}
   302    308   set type {}
   303    309   set if {}
   304    310   set flags {}
   305    311   set arg 0