/ Check-in [b64a11a7]
Login

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

Overview
Comment:Change the way the "incremental checkpoint" function of OTA works in order to reduce the effect on the SQLite core code.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: b64a11a754dc56f3406d3b703531ebe9e4af4908
User & Date: dan 2015-02-14 18:58:22
Context
2015-02-16
06:27
Move tcl test code from sqlite3ota.c to new file ext/ota/test_ota.c. check-in: f20779a6 user: dan tags: ota-update
2015-02-14
18:58
Change the way the "incremental checkpoint" function of OTA works in order to reduce the effect on the SQLite core code. check-in: b64a11a7 user: dan tags: ota-update
2015-02-11
17:05
Merge the ota-update-no-pager_ota_mode branch into this one. check-in: 71887cd9 user: dan tags: ota-update
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/ota/ota1.test.

194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
...
471
472
473
474
475
476
477

478
479
480
481
482
483
      }
    } {
      reset_db
      execsql $schema

      do_test $tn3.1.$tn2.$tn.1 {
        create_ota1 ota.db
        breakpoint
        $cmd test.db ota.db
      } {SQLITE_DONE}

      do_execsql_test $tn3.1.$tn2.$tn.2 { SELECT * FROM t1 ORDER BY a ASC } {
        1 2 3 
        2 two three 
        3 {} 8.2
................................................................................

      do_test $tn3.6.$tn {
        list [catch { run_ota test.db ota.db } msg] $msg
      } [list 1 $error]
    }
  }


  eval $destroy_vfs
}


finish_test








<







 







>






194
195
196
197
198
199
200

201
202
203
204
205
206
207
...
470
471
472
473
474
475
476
477
478
479
480
481
482
483
      }
    } {
      reset_db
      execsql $schema

      do_test $tn3.1.$tn2.$tn.1 {
        create_ota1 ota.db

        $cmd test.db ota.db
      } {SQLITE_DONE}

      do_execsql_test $tn3.1.$tn2.$tn.2 { SELECT * FROM t1 ORDER BY a ASC } {
        1 2 3 
        2 two three 
        3 {} 8.2
................................................................................

      do_test $tn3.6.$tn {
        list [catch { run_ota test.db ota.db } msg] $msg
      } [list 1 $error]
    }
  }

  catch { db close }
  eval $destroy_vfs
}


finish_test

Changes to ext/ota/ota6.test.

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    list [file exists test.db-oal] [file exists test.db-wal]
  } {1 0}
  do_test 1.$nStep.4 {
    list [catch { ota close } msg] $msg
  } {1 {SQLITE_BUSY - database modified during ota update}}
}

for {set nStep 7} {$nStep < 8} {incr nStep} {
  do_test 1.$nStep.1 {
    setup_test
    sqlite3ota ota test.db ota.db
    for {set i 0} {$i<$nStep} {incr i} {ota step}
    ota close
    sqlite3 db test.db
    execsql { INSERT INTO t1 VALUES(5, 'hello') }
    sqlite3ota ota test.db ota.db
    ota step
  } {SQLITE_OK}
  do_test 1.$nStep.2 {
    ota step
  } {SQLITE_OK}
  do_test 1.$nStep.3 {
    list [file exists test.db-oal] [file exists test.db-wal]
  } {0 1}
  do_test 1.$nStep.4 {
    list [catch { ota close } msg] $msg
  } {0 SQLITE_OK}
}


# Test the outcome of some other client writing the db after the *-oal
# file has been copied to the *-wal path. Once this has happened, any
# other client writing to the db causes OTA to consider its job finished.
#
for {set nStep 8} {$nStep < 20} {incr nStep} {
  do_test 1.$nStep.1 {
    setup_test
    sqlite3ota ota test.db ota.db
    for {set i 0} {$i<$nStep} {incr i} {ota step}
    ota close
    sqlite3 db test.db
    execsql { INSERT INTO t1 VALUES(5, 'hello') }







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<





|







64
65
66
67
68
69
70






















71
72
73
74
75
76
77
78
79
80
81
82
83
    list [file exists test.db-oal] [file exists test.db-wal]
  } {1 0}
  do_test 1.$nStep.4 {
    list [catch { ota close } msg] $msg
  } {1 {SQLITE_BUSY - database modified during ota update}}
}
























# Test the outcome of some other client writing the db after the *-oal
# file has been copied to the *-wal path. Once this has happened, any
# other client writing to the db causes OTA to consider its job finished.
#
for {set nStep 7} {$nStep < 20} {incr nStep} {
  do_test 1.$nStep.1 {
    setup_test
    sqlite3ota ota test.db ota.db
    for {set i 0} {$i<$nStep} {incr i} {ota step}
    ota close
    sqlite3 db test.db
    execsql { INSERT INTO t1 VALUES(5, 'hello') }

Changes to ext/ota/sqlite3ota.c.

71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89















90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
...
154
155
156
157
158
159
160






161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176












177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199




200
201
202
203
204
205
206
...
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
...
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
....
1476
1477
1478
1479
1480
1481
1482

1483
1484
1485
1486


1487

1488
1489
1490
1491
1492
1493


1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
....
1528
1529
1530
1531
1532
1533
1534































































































1535
1536
1537
1538
1539
1540
1541
....
1558
1559
1560
1561
1562
1563
1564
1565
1566

1567
1568
1569
1570
1571
1572
1573
....
1803
1804
1805
1806
1807
1808
1809


1810
1811
1812


1813

1814
1815
1816
1817
1818
1819
1820




1821
1822
1823
1824




1825
1826
1827
1828

1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
....
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
....
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
....
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
....
2049
2050
2051
2052
2053
2054
2055





2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079

2080
2081
2082
2083
2084
2085

2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
....
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169


2170
2171
2172
2173
2174
2175
2176
....
2233
2234
2235
2236
2237
2238
2239








2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267








2268
2269
2270
2271
2272

2273
2274

2275
2276
2277
2278
2279
2280
2281
....
2282
2283
2284
2285
2286
2287
2288







2289
2290
2291
2292
2293

2294
2295

2296
2297
2298
2299
2300
2301
2302
....
2306
2307
2308
2309
2310
2311
2312






2313
2314
2315
2316
2317
2318
2319
....
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
....
2361
2362
2363
2364
2365
2366
2367

2368
2369
2370
2371
2372
2373
2374
....
2381
2382
2383
2384
2385
2386
2387

2388
2389
2390
2391
2392
2393
2394
....
2410
2411
2412
2413
2414
2415
2416

2417
2418
2419
2420
2421
2422

2423
2424
2425
2426
2427
2428
2429
2430








2431




2432
2433
2434
2435
2436
2437
2438
....
2443
2444
2445
2446
2447
2448
2449

2450
2451
2452
2453
2454
2455
2456
....
2491
2492
2493
2494
2495
2496
2497

2498
2499
2500
2501
2502
2503
2504








2505
2506
2507
2508
2509
2510
2511
....
2563
2564
2565
2566
2567
2568
2569
2570



2571
2572
2573
2574
2575




2576
2577
2578
2579
2580
2581
2582
2583



2584






2585
2586
2587
2588
2589
2590
2591
....
2607
2608
2609
2610
2611
2612
2613














2614


2615
2616
2617
2618

2619
2620
2621
2622
2623
2624
2625
#define OTA_STATE_IDX         3
#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_CKPT        3
#define OTA_STAGE_DONE        4


#define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota.ota_state"        \
                             "(k INTEGER PRIMARY KEY, v)"

typedef struct OtaState OtaState;
typedef struct OtaObjIter OtaObjIter;
typedef struct ota_vfs ota_vfs;
typedef struct ota_file ota_file;
















/*
** A structure to store values read from the ota_state table in memory.
*/
struct OtaState {
  int eStage;
  char *zTbl;
  char *zIdx;
  unsigned char *pCkptState;
  int nCkptState;
  int nRow;
  sqlite3_int64 nProgress;
};

/*
** An iterator of this type is used to iterate through all objects in
** the target database that require updating. For each such table, the
** iterator visits, in order:
**
................................................................................
struct OtaObjIter {
  sqlite3_stmt *pTblIter;         /* Iterate through tables */
  sqlite3_stmt *pIdxIter;         /* Index iterator */
  int nTblCol;                    /* Size of azTblCol[] array */
  char **azTblCol;                /* Array of unquoted target column names */
  char **azTblType;               /* Array of target column types */
  int *aiSrcOrder;                /* src table col -> target table col */
  unsigned char *abTblPk;         /* Array of flags, set on target PK columns */
  unsigned char *abNotNull;       /* Array of flags, set on NOT NULL columns */
  int eType;                      /* Table type - an OTA_PK_XXX value */

  /* Output variables. zTbl==0 implies EOF. */
  int bCleanup;                   /* True in "cleanup" state */
  const char *zTbl;               /* Name of target db table */
  const char *zIdx;               /* Name of target db index (or null) */
  int iTnum;                      /* Root page of current object */
................................................................................
#define OTA_PK_NONE           1
#define OTA_PK_IPK            2
#define OTA_PK_EXTERNAL       3
#define OTA_PK_WITHOUT_ROWID  4
#define OTA_PK_VTAB           5








/*
** OTA handle.
*/
struct sqlite3ota {
  int eStage;                     /* Value of OTA_STATE_STAGE field */
  sqlite3 *db;                    /* "main" -> target db, "ota" -> ota db */
  char *zTarget;                  /* Path to target db */
  char *zOta;                     /* Path to ota db */
  int rc;                         /* Value returned by last ota_step() call */
  char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */
  int nStep;                      /* Rows processed for current object */
  int nProgress;                  /* Rows processed for all objects */
  OtaObjIter objiter;             /* Iterator for skipping through tbl/idx */
  sqlite3_ckpt *pCkpt;            /* Incr-checkpoint handle */
  ota_file *pTargetFd;            /* File handle open on target db */
  const char *zVfsName;           /* Name of automatically created ota vfs */












};

struct ota_vfs {
  sqlite3_vfs base;             /* ota VFS shim methods */
  sqlite3_vfs *pRealVfs;        /* Underlying VFS */
  sqlite3_mutex *mutex;
  const char *zOtaWal;
};

struct ota_file {
  sqlite3_file base;              /* sqlite3_file methods */
  sqlite3_file *pReal;            /* Underlying file handle */
  ota_vfs *pOtaVfs;               /* Pointer to the ota_vfs object */
  sqlite3ota *pOta;               /* Pointer to ota object (ota target only) */

  int openFlags;                  /* Flags this file was opened with */
  unsigned int iCookie;           /* Cookie value for main db files */
  unsigned char iWriteVer;        /* "write-version" value for main db files */

  int nShm;                       /* Number of entries in apShm[] array */
  char **apShm;                   /* Array of mmap'd *-shm regions */
  const char *zWal;               /* Wal filename for this db file */
  char *zDel;                     /* Delete this when closing file */




};


static void otaCreateVfs(sqlite3ota*, const char*);
static void otaDeleteVfs(sqlite3ota*);

/*
................................................................................

/*
** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that
** there is room for at least nCol elements. If an OOM occurs, store an
** error code in the OTA handle passed as the first argument.
*/
static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
  int nByte = (2*sizeof(char*) + sizeof(int) + 2*sizeof(unsigned char)) * nCol;
  char **azNew;

  azNew = (char**)otaMalloc(p, nByte);
  if( azNew ){
    pIter->azTblCol = azNew;
    pIter->azTblType = &azNew[nCol];
    pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol];
    pIter->abTblPk = (unsigned char*)&pIter->aiSrcOrder[nCol];
    pIter->abNotNull = (unsigned char*)&pIter->abTblPk[nCol];
  }
}

static char *otaStrndup(const char *zStr, int nStr, int *pRc){
  char *zRet = 0;
  assert( *pRc==SQLITE_OK );

................................................................................
  zSql = sqlite3_mprintf("PRAGMA index_list=%Q",zTab);
  if( zSql==0 ) return SQLITE_NOMEM;
  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
  sqlite3_free(zSql);
  zSql = 0;
  if( pStmt==0 ) goto otaTableType_end;
  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    const unsigned char *zOrig = sqlite3_column_text(pStmt,3);
    if( zOrig && zOrig[0]=='p' ){
      zSql = sqlite3_mprintf("SELECT rootpage FROM main.sqlite_master"
                             " WHERE name=%Q", sqlite3_column_text(pStmt,1));
      if( zSql==0 ){ rc = SQLITE_NOMEM; goto otaTableType_end; }
      break;
    }
  }
................................................................................
        if( i!=iOrder ){
          SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]);
          SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]);
        }

        pIter->azTblType[iOrder] = otaStrndup(zType, -1, &p->rc);
        pIter->abTblPk[iOrder] = (iPk!=0);
        pIter->abNotNull[iOrder] = (unsigned char)bNotNull || (iPk!=0);
        iOrder++;
      }
    }

    rc2 = sqlite3_finalize(pStmt);
    if( p->rc==SQLITE_OK ) p->rc = rc2;
  }
................................................................................
** 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 );
  assert( p->db==0 );


  p->rc = sqlite3_open_v2(p->zTarget, &p->db, flags, p->zVfsName);
  if( p->rc ){
    p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
  }else{


    otaMPrintfExec(p, "ATTACH %Q AS ota", p->zOta);


    /* Mark the database file just opened as an OTA target database. If 
    ** this call returns SQLITE_NOTFOUND, then the OTA vfs is not in use.
    ** This is an error.  */
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_OTA, (void*)p);


      if( p->rc==SQLITE_NOTFOUND ){
        p->rc = SQLITE_ERROR;
        p->zErrmsg = sqlite3_mprintf("ota vfs not found");
      }
    }
  }
}

/*
** This routine is a copy of the sqlite3FileSuffix3() routine from the core.
** It is a no-op unless SQLITE_ENABLE_8_3_NAMES is defined.
................................................................................
    int i, sz;
    sz = sqlite3Strlen30(z);
    for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
    if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
  }
#endif
}
































































































/*
** The OTA handle is currently in OTA_STAGE_OAL state, with a SHARED lock
** on the database file. This proc moves the *-oal file to the *-wal path,
** then reopens the database file (this time in vanilla, non-oal, WAL mode).
** If an error occurs, leave an error code and error message in the ota 
** handle.
................................................................................
    otaFileSuffix3(zBase, zOal);
    rename(zOal, zWal);

    /* Re-open the databases. */
    otaObjIterFinalize(&p->objiter);
    sqlite3_close(p->db);
    p->db = 0;
    p->eStage = OTA_STAGE_CKPT;
    otaOpenDatabase(p);

  }

  sqlite3_free(zWal);
  sqlite3_free(zOal);
}

/*
................................................................................
            otaMoveOalFile(p);
          }
        }
        break;
      }

      case OTA_STAGE_CKPT: {



        if( p->rc==SQLITE_OK && p->pCkpt==0 ){
          p->rc = sqlite3_ckpt_open(p->db, 0, 0, &p->pCkpt);


        }

        if( p->rc==SQLITE_OK ){
          if( p->pCkpt==0 ){
            p->eStage = OTA_STAGE_DONE;
            p->rc = SQLITE_DONE;
          }else if( SQLITE_OK!=sqlite3_ckpt_step(p->pCkpt) ){
            p->rc = sqlite3_ckpt_close(p->pCkpt, 0, 0);
            p->pCkpt = 0;




            if( p->rc==SQLITE_OK ){
              p->eStage = OTA_STAGE_DONE;
              p->rc = SQLITE_DONE;
            }




          }
          p->nProgress++;
        }


        break;
      }

      default:
        break;
    }
    return p->rc;
  }else{
    return SQLITE_NOMEM;
  }
}

static void otaSaveTransactionState(sqlite3ota *p){
  sqlite3_stmt *pInsert;
  int rc;

  assert( (p->rc==SQLITE_OK || p->rc==SQLITE_DONE) && p->zErrmsg==0 );
  rc = prepareFreeAndCollectError(p->db, &pInsert, &p->zErrmsg, 
      sqlite3_mprintf(
        "INSERT OR REPLACE INTO ota.ota_state(k, v) VALUES "
        "(%d, %d), "
        "(%d, %Q), "
        "(%d, %Q), "
        "(%d, %d), "
        "(%d, %lld), "
        "(%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_COOKIE, (sqlite3_int64)p->pTargetFd->iCookie
      )
  );
  assert( pInsert==0 || rc==SQLITE_OK );
  if( rc==SQLITE_OK ){
    if( p->pCkpt ){
      unsigned char *pCkptState = 0;
      int nCkptState = 0;
      rc = sqlite3_ckpt_close(p->pCkpt, &pCkptState, &nCkptState);
      p->pCkpt = 0;
      sqlite3_bind_blob(pInsert, 1, pCkptState, nCkptState, SQLITE_TRANSIENT);
      sqlite3_free(pCkptState);
    }
  }
  if( rc==SQLITE_OK ){
    sqlite3_step(pInsert);
    rc = sqlite3_finalize(pInsert);
  }else{
    sqlite3_finalize(pInsert);
  }

................................................................................
  }
}

static void otaFreeState(OtaState *p){
  if( p ){
    sqlite3_free(p->zTbl);
    sqlite3_free(p->zIdx);
    sqlite3_free(p->pCkptState);
    sqlite3_free(p);
  }
}

/*
** Allocate an OtaState object and load the contents of the ota_state 
** table into it. Return a pointer to the new object. It is the 
................................................................................
        break;

      case OTA_STATE_PROGRESS:
        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
        break;

      case OTA_STATE_CKPT:
        pRet->nCkptState = sqlite3_column_bytes(pStmt, 1);
        pRet->pCkptState = (unsigned char*)otaStrndup(
            (char*)sqlite3_column_blob(pStmt, 1), pRet->nCkptState, &rc
        );
        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->pTargetFd->iCookie!=(unsigned int)sqlite3_column_int64(pStmt, 1) 
        ){
          rc = SQLITE_BUSY;
          p->zErrmsg = sqlite3_mprintf("database modified during ota update");
        }
        break;

      default:
................................................................................
  int nTarget = strlen(zTarget);
  int nOta = strlen(zOta);

  p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)+nTarget+1+nOta+1);
  if( p ){
    OtaState *pState = 0;

    /* Create the custom VFS */
    memset(p, 0, sizeof(sqlite3ota));
    otaCreateVfs(p, 0);

    /* Open the target database */
    if( p->rc==SQLITE_OK ){
      p->zTarget = (char*)&p[1];
      memcpy(p->zTarget, zTarget, nTarget+1);
................................................................................
    }

    /* If it has not already been created, create the ota_state table */
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_exec(p->db, OTA_CREATE_STATE, 0, 0, &p->zErrmsg);
    }






    if( p->rc==SQLITE_OK && p->pTargetFd->iWriteVer>1 ){
      p->rc = SQLITE_ERROR;
      p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
    }

    if( p->rc==SQLITE_OK ){
      pState = otaLoadState(p);
      assert( pState || p->rc!=SQLITE_OK );
      if( p->rc==SQLITE_OK ){
        if( pState->eStage==0 ){ 
          otaDeleteOalFile(p);
          p->eStage = 1;
        }else{
          p->eStage = pState->eStage;
        }
        p->nProgress = pState->nProgress;
      }
    }
    assert( p->rc!=SQLITE_OK || p->eStage!=0 );

    if( p->rc==SQLITE_OK ){
      if( p->eStage==OTA_STAGE_OAL ){
        ota_vfs *pOtaVfs = p->pTargetFd->pOtaVfs;


        sqlite3_mutex_enter(pOtaVfs->mutex);
        assert( pOtaVfs->zOtaWal==0 );
        pOtaVfs->zOtaWal = p->pTargetFd->zWal;
        p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
        pOtaVfs->zOtaWal = 0;
        sqlite3_mutex_leave(pOtaVfs->mutex);

  
        /* Point the object iterator at the first object */
        if( p->rc==SQLITE_OK ){
          p->rc = otaObjIterFirst(p, &p->objiter);
        }
  
        if( p->rc==SQLITE_OK ){
          otaLoadTransactionState(p, pState);
        }
      }else if( p->eStage==OTA_STAGE_CKPT ){
        p->rc = sqlite3_ckpt_open(
            p->db, pState->pCkptState, pState->nCkptState, &p->pCkpt
        );
        if( p->rc==SQLITE_MISMATCH || (p->rc==SQLITE_OK && p->pCkpt==0) ){
          p->eStage = OTA_STAGE_DONE;
          p->rc = SQLITE_DONE;
        }
      }else if( p->eStage==OTA_STAGE_DONE ){
        p->rc = SQLITE_DONE;
      }
    }

    otaFreeState(pState);
  }
................................................................................

    /* If the update has not been fully applied, save the state in 
    ** the ota db. If successful, this call also commits the open 
    ** transaction on the ota db. */
    assert( p->rc!=SQLITE_ROW );
    if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
      assert( p->zErrmsg==0 );
      otaSaveTransactionState(p);
    }

    /* Close any open statement handles. */
    otaObjIterFinalize(&p->objiter);

    /* Commit the transaction to the *-oal file. */
    if( p->rc==SQLITE_OK && p->eStage==OTA_STAGE_OAL ){
      p->rc = sqlite3_exec(p->db, "COMMIT", 0, 0, &p->zErrmsg);
    }

    /* 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;
    *pzErrmsg = p->zErrmsg;
    sqlite3_free(p);
  }else{
    rc = SQLITE_NOMEM;
................................................................................
  /* 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->zDel);









  /* Close the underlying file handle */
  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;








  int rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
  if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
    /* These look like magic numbers. But they are stable, as they are part
    ** of the definition of the SQLite file format, which may not change. */
    unsigned char *pBuf = (unsigned char*)zBuf;

    p->iCookie = otaGetU32(&pBuf[24]);
    p->iWriteVer = pBuf[19];

  }
  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;







  int rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
  if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
    /* These look like magic numbers. But they are stable, as they are part
    ** of the definition of the SQLite file format, which may not change. */
    unsigned char *pBuf = (unsigned char*)zBuf;

    p->iCookie = otaGetU32(&pBuf[24]);
    p->iWriteVer = pBuf[19];

  }
  return rc;
}

/*
** Truncate an otaVfs-file.
*/
................................................................................
}

/*
** 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){
................................................................................
** Lock an otaVfs-file.
*/
static int otaVfsLock(sqlite3_file *pFile, int eLock){
  ota_file *p = (ota_file*)pFile;
  sqlite3ota *pOta = p->pOta;
  int rc = SQLITE_OK;

  if( pOta && eLock==SQLITE_LOCK_EXCLUSIVE
   && (pOta->eStage==OTA_STAGE_OAL || pOta->eStage==OTA_STAGE_CKPT) 
  ){
    /* 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);
  }

................................................................................
/*
** 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;
  int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;


  if( op==SQLITE_FCNTL_OTA ){
    int rc;
    sqlite3ota *pOta = (sqlite3ota*)pArg;

    /* First try to find another OTA vfs lower down in the vfs stack. If
    ** one is found, this vfs will operate in pass-through mode. The lower
    ** level vfs will do the special OTA handling.  */
................................................................................
      rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS_PAGER, &dummy);
      if( rc==SQLITE_OK ){
        rc = SQLITE_ERROR;
        pOta->zErrmsg = sqlite3_mprintf("ota/zipvfs setup error");
      }else if( rc==SQLITE_NOTFOUND ){
        pOta->pTargetFd = p;
        p->pOta = pOta;

        rc = SQLITE_OK;
      }
    }
    return rc;
  }
  return xControl(p->pReal, op, pArg);
}
................................................................................
}

/*
** 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;

  int rc = SQLITE_OK;

#ifdef SQLITE_AMALGAMATION
    assert( WAL_CKPT_LOCK==1 );
#endif


  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
    /* Magic number 1 is the WAL_CKPT_LOCK 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 );








    rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);




  }

  return rc;
}

static int otaVfsShmMap(
  sqlite3_file *pFile, 
................................................................................
){
  ota_file *p = (ota_file*)pFile;
  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( p->pOta && p->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{
................................................................................
  p->pReal->pMethods->xShmBarrier(p->pReal);
}

static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
  ota_file *p = (ota_file*)pFile;
  int rc = SQLITE_OK;


  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
    /* no-op */
  }else{
    rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
  }
  return rc;
}









/*
** Open an ota file handle.
*/
static int otaVfsOpen(
  sqlite3_vfs *pVfs,
  const char *zName,
................................................................................
        z += 2;
      }else{
        while( *z==0 ) z++;
      }
      z += (n + 8 + 1);
      pFd->zWal = z;
    }
    else if( (flags & SQLITE_OPEN_WAL) && zName==pOtaVfs->zOtaWal ){



      char *zCopy = otaStrndup(zName, -1, &rc);
      if( zCopy ){
        int nCopy = strlen(zCopy);
        zCopy[nCopy-3] = 'o';
        zOpen = (const char*)(pFd->zDel = zCopy);




      }
    }
  }

  if( rc==SQLITE_OK ){
    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags);
  }
  if( pFd->pReal->pMethods ){



    pFile->pMethods = &otavfs_io_methods;






  }

  return rc;
}

/*
** Delete the file located at zPath.
................................................................................
){
  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->zOtaWal==zPath ){


    if( *pResOut ){
      rc = SQLITE_CANTOPEN;
    }else{
      *pResOut = 1;

    }
  }

  return rc;
}

/*







>












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







|
<

|







 







|
|







 







>
>
>
>
>
>













|

<
>
>
>
>
>
>
>
>
>
>
>
>



|
|
|
|









|
|



<

>
>
>
>







 







|







|
|







 







|







 







|







 







>




>
>
|
>






>
>
|
|
|
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<

>







 







>
>

<
<
>
>
|
>
|
<
<
<
|
|
|
>
>
>
>
|
|
|
|
>
>
>
>
|
<
|
<
>












|












|






|
|



<
<
<
<
<
<
<
<
|
<







 







<







 







|
<
<
<








|







 







|







 







>
>
>
>
>











|










<

>
|
<
<
|
<
<
>










|
|
<
<
<
<
<







 







|











<


>
>







 







>
>
>
>
>
>
>
>











|
|
|
|
|












>
>
>
>
>
>
>
>
|
|
|
|
<
>
|
|
>







 







>
>
>
>
>
>
>
|
|
|
|
<
>
|
|
>







 







>
>
>
>
>
>







 







|
|
<







 







>







 







>







 







>






>
|




|

|
>
>
>
>
>
>
>
>
|
>
>
>
>







 







>







 







>







>
>
>
>
>
>
>
>







 







|
>
>
>
|
|
|
|
|
>
>
>
>








>
>
>

>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
|
|
|
>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

114
115
116
117
118
119
120
121
122
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

230
231
232
233
234
235
236
237
238
239
240
241
...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
....
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537

1538
1539
1540
1541
1542
1543
1544
....
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
....
1693
1694
1695
1696
1697
1698
1699

1700
1701
1702
1703
1704
1705
1706
1707
1708
....
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947


1948
1949
1950
1951
1952



1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968

1969

1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007








2008

2009
2010
2011
2012
2013
2014
2015
....
2018
2019
2020
2021
2022
2023
2024

2025
2026
2027
2028
2029
2030
2031
....
2075
2076
2077
2078
2079
2080
2081
2082



2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
....
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
....
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211

2212
2213
2214


2215


2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228





2229
2230
2231
2232
2233
2234
2235
....
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292

2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
....
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414

2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
....
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443

2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
....
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
....
2483
2484
2485
2486
2487
2488
2489
2490
2491

2492
2493
2494
2495
2496
2497
2498
....
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
....
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
....
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
....
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
....
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
....
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
....
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
#define OTA_STATE_IDX         3
#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_CAPTURE     2
#define OTA_STAGE_CKPT        3
#define OTA_STAGE_DONE        4


#define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota.ota_state"        \
                             "(k INTEGER PRIMARY KEY, v)"

typedef struct OtaState OtaState;
typedef struct OtaObjIter OtaObjIter;
typedef struct ota_vfs ota_vfs;
typedef struct ota_file ota_file;

#if !defined(SQLITE_AMALGAMATION)
typedef unsigned int u32;
typedef unsigned char u8;
typedef sqlite3_int64 i64;
#endif

/*
** These values must match the values defined in wal.c for the equivalent
** locks. These are not magic numbers as they are part of the SQLite file
** format.
*/
#define WAL_LOCK_WRITE  0
#define WAL_LOCK_CKPT   1
#define WAL_LOCK_READ0  3

/*
** A structure to store values read from the ota_state table in memory.
*/
struct OtaState {
  int eStage;
  char *zTbl;
  char *zIdx;
  i64 iWalCksum;

  int nRow;
  i64 nProgress;
};

/*
** An iterator of this type is used to iterate through all objects in
** the target database that require updating. For each such table, the
** iterator visits, in order:
**
................................................................................
struct OtaObjIter {
  sqlite3_stmt *pTblIter;         /* Iterate through tables */
  sqlite3_stmt *pIdxIter;         /* Index iterator */
  int nTblCol;                    /* Size of azTblCol[] array */
  char **azTblCol;                /* Array of unquoted target column names */
  char **azTblType;               /* Array of target column types */
  int *aiSrcOrder;                /* src table col -> target table col */
  u8 *abTblPk;                    /* Array of flags, set on target PK columns */
  u8 *abNotNull;                  /* Array of flags, set on NOT NULL columns */
  int eType;                      /* Table type - an OTA_PK_XXX value */

  /* Output variables. zTbl==0 implies EOF. */
  int bCleanup;                   /* True in "cleanup" state */
  const char *zTbl;               /* Name of target db table */
  const char *zIdx;               /* Name of target db index (or null) */
  int iTnum;                      /* Root page of current object */
................................................................................
#define OTA_PK_NONE           1
#define OTA_PK_IPK            2
#define OTA_PK_EXTERNAL       3
#define OTA_PK_WITHOUT_ROWID  4
#define OTA_PK_VTAB           5


typedef struct OtaFrame OtaFrame;
struct OtaFrame {
  u32 iDbPage;
  u32 iWalFrame;
};

/*
** OTA handle.
*/
struct sqlite3ota {
  int eStage;                     /* Value of OTA_STATE_STAGE field */
  sqlite3 *db;                    /* "main" -> target db, "ota" -> ota db */
  char *zTarget;                  /* Path to target db */
  char *zOta;                     /* Path to ota db */
  int rc;                         /* Value returned by last ota_step() call */
  char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */
  int nStep;                      /* Rows processed for current object */
  int nProgress;                  /* Rows processed for all objects */
  OtaObjIter objiter;             /* Iterator for skipping through tbl/idx */
  const char *zVfsName;           /* Name of automatically created ota vfs */
  ota_file *pTargetFd;            /* File handle open on target db */


  /* The following state variables are used as part of the incremental
  ** checkpoint stage (eStage==OTA_STAGE_CKPT). See function otaSetupCkpt()
  ** for details.  */
  u32 iMaxFrame;                  /* Largest iWalFrame value in aFrame[] */
  u32 mLock;
  int nFrame;                     /* Entries in aFrame[] array */
  int nFrameAlloc;                /* Allocated size of aFrame[] array */
  OtaFrame *aFrame;
  int pgsz;
  u8 *aBuf;
  i64 iWalCksum;
};

struct ota_vfs {
  sqlite3_vfs base;               /* ota VFS shim methods */
  sqlite3_vfs *pRealVfs;          /* Underlying VFS */
  sqlite3_mutex *mutex;           /* Mutex to protect pMain */
  ota_file *pMain;                /* Linked list of main db files */
};

struct ota_file {
  sqlite3_file base;              /* sqlite3_file methods */
  sqlite3_file *pReal;            /* Underlying file handle */
  ota_vfs *pOtaVfs;               /* Pointer to the ota_vfs object */
  sqlite3ota *pOta;               /* Pointer to ota object (ota target only) */

  int openFlags;                  /* Flags this file was opened with */
  u32 iCookie;                    /* Cookie value for main db files */
  u8 iWriteVer;                   /* "write-version" value for main db files */

  int nShm;                       /* Number of entries in apShm[] array */
  char **apShm;                   /* Array of mmap'd *-shm regions */

  char *zDel;                     /* Delete this when closing file */

  const char *zWal;               /* Wal filename for this main db file */
  ota_file *pWalFd;               /* Wal file descriptor for this main db */
  ota_file *pMainNext;            /* Next MAIN_DB file */
};


static void otaCreateVfs(sqlite3ota*, const char*);
static void otaDeleteVfs(sqlite3ota*);

/*
................................................................................

/*
** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that
** there is room for at least nCol elements. If an OOM occurs, store an
** error code in the OTA handle passed as the first argument.
*/
static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
  int nByte = (2*sizeof(char*) + sizeof(int) + 2*sizeof(u8)) * nCol;
  char **azNew;

  azNew = (char**)otaMalloc(p, nByte);
  if( azNew ){
    pIter->azTblCol = azNew;
    pIter->azTblType = &azNew[nCol];
    pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol];
    pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol];
    pIter->abNotNull = (u8*)&pIter->abTblPk[nCol];
  }
}

static char *otaStrndup(const char *zStr, int nStr, int *pRc){
  char *zRet = 0;
  assert( *pRc==SQLITE_OK );

................................................................................
  zSql = sqlite3_mprintf("PRAGMA index_list=%Q",zTab);
  if( zSql==0 ) return SQLITE_NOMEM;
  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
  sqlite3_free(zSql);
  zSql = 0;
  if( pStmt==0 ) goto otaTableType_end;
  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    const u8 *zOrig = sqlite3_column_text(pStmt,3);
    if( zOrig && zOrig[0]=='p' ){
      zSql = sqlite3_mprintf("SELECT rootpage FROM main.sqlite_master"
                             " WHERE name=%Q", sqlite3_column_text(pStmt,1));
      if( zSql==0 ){ rc = SQLITE_NOMEM; goto otaTableType_end; }
      break;
    }
  }
................................................................................
        if( i!=iOrder ){
          SWAP(int, pIter->aiSrcOrder[i], pIter->aiSrcOrder[iOrder]);
          SWAP(char*, pIter->azTblCol[i], pIter->azTblCol[iOrder]);
        }

        pIter->azTblType[iOrder] = otaStrndup(zType, -1, &p->rc);
        pIter->abTblPk[iOrder] = (iPk!=0);
        pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0);
        iOrder++;
      }
    }

    rc2 = sqlite3_finalize(pStmt);
    if( p->rc==SQLITE_OK ) p->rc = rc2;
  }
................................................................................
** 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 );
  assert( p->db==0 );

  p->eStage = 0;
  p->rc = sqlite3_open_v2(p->zTarget, &p->db, flags, p->zVfsName);
  if( p->rc ){
    p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
  }else{
    p->rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_OTA, (void*)p);
    if( p->rc==SQLITE_OK ){
      otaMPrintfExec(p, "ATTACH %Q AS ota", p->zOta);
    }

    /* Mark the database file just opened as an OTA target database. If 
    ** this call returns SQLITE_NOTFOUND, then the OTA vfs is not in use.
    ** This is an error.  */
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_file_control(p->db, "main", SQLITE_FCNTL_OTA, (void*)p);
    }

    if( p->rc==SQLITE_NOTFOUND ){
      p->rc = SQLITE_ERROR;
      p->zErrmsg = sqlite3_mprintf("ota vfs not found");

    }
  }
}

/*
** This routine is a copy of the sqlite3FileSuffix3() routine from the core.
** It is a no-op unless SQLITE_ENABLE_8_3_NAMES is defined.
................................................................................
    int i, sz;
    sz = sqlite3Strlen30(z);
    for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){}
    if( z[i]=='.' && ALWAYS(sz>i+4) ) memmove(&z[i+1], &z[sz-3], 4);
  }
#endif
}

/*
** Return the current wal-index header checksum for the target database 
** as a 64-bit integer.
**
** The checksum is store in the first page of xShmMap memory as an 8-byte 
** blob starting at byte offset 40.
*/
static i64 otaShmChecksum(sqlite3ota *p){
  i64 iRet;
  if( p->rc==SQLITE_OK ){
    sqlite3_file *pDb = p->pTargetFd->pReal;
    u32 volatile *ptr;
    p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, (void volatile**)&ptr);
    if( p->rc==SQLITE_OK ){
      iRet = ((i64)ptr[10] << 32) + ptr[11];
    }
  }
  return iRet;
}

static void otaSetupCheckpoint(sqlite3ota *p, OtaState *pState){

  if( pState==0 ){
    p->eStage = 0;
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_exec(p->db, "SELECT * FROM sqlite_master", 0, 0, 0);
    }
  }

  if( p->rc==SQLITE_OK ){
    int rc2;
    p->eStage = OTA_STAGE_CAPTURE;
    rc2 = sqlite3_exec(p->db, "PRAGMA main.wal_checkpoint=restart", 0, 0, 0);
    if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
  }

  if( p->rc==SQLITE_OK ){
    p->eStage = OTA_STAGE_CKPT;
    p->nStep = 0;
    p->aBuf = otaMalloc(p, p->pgsz);
    p->iWalCksum = otaShmChecksum(p);
  }

  if( p->rc==SQLITE_OK && pState && pState->iWalCksum!=p->iWalCksum ){
    p->rc = SQLITE_DONE;
    p->eStage = OTA_STAGE_DONE;
  }
}

static int otaCaptureWalRead(sqlite3ota *pOta, i64 iOff, int iAmt){
  const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0);
  u32 iFrame;

  if( pOta->mLock!=mReq ){
    return SQLITE_BUSY;
  }

  pOta->pgsz = iAmt;
  if( pOta->nFrame==pOta->nFrameAlloc ){
    int nNew = (pOta->nFrameAlloc ? pOta->nFrameAlloc : 64) * 2;
    OtaFrame *aNew;
    aNew = (OtaFrame*)sqlite3_realloc(pOta->aFrame, nNew * sizeof(OtaFrame));
    if( aNew==0 ) return SQLITE_NOMEM;
    pOta->aFrame = aNew;
    pOta->nFrameAlloc = nNew;
  }

  iFrame = (u32)((iOff-32) / (i64)(iAmt+24)) + 1;
  if( pOta->iMaxFrame<iFrame ) pOta->iMaxFrame = iFrame;
  pOta->aFrame[pOta->nFrame].iWalFrame = iFrame;
  pOta->aFrame[pOta->nFrame].iDbPage = 0;
  pOta->nFrame++;
  return SQLITE_OK;
}

static int otaCaptureDbWrite(sqlite3ota *pOta, i64 iOff){
  pOta->aFrame[pOta->nFrame-1].iDbPage = (u32)(iOff / pOta->pgsz) + 1;
  return SQLITE_OK;
}

static void otaCheckpointFrame(sqlite3ota *p, OtaFrame *pFrame){
  if( p->rc==SQLITE_OK ){
    sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
    sqlite3_file *pDb = p->pTargetFd->pReal;
    i64 iOff;

    iOff = (i64)(pFrame->iWalFrame-1) * (p->pgsz + 24) + 32 + 24;
    p->rc = pWal->pMethods->xRead(pWal, p->aBuf, p->pgsz, iOff);
    if( p->rc ) return;

    iOff = (i64)(pFrame->iDbPage-1) * p->pgsz;
    p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
  }
}

/*
** The OTA handle is currently in OTA_STAGE_OAL state, with a SHARED lock
** on the database file. This proc moves the *-oal file to the *-wal path,
** then reopens the database file (this time in vanilla, non-oal, WAL mode).
** If an error occurs, leave an error code and error message in the ota 
** handle.
................................................................................
    otaFileSuffix3(zBase, zOal);
    rename(zOal, zWal);

    /* Re-open the databases. */
    otaObjIterFinalize(&p->objiter);
    sqlite3_close(p->db);
    p->db = 0;

    otaOpenDatabase(p);
    otaSetupCheckpoint(p, 0);
  }

  sqlite3_free(zWal);
  sqlite3_free(zOal);
}

/*
................................................................................
            otaMoveOalFile(p);
          }
        }
        break;
      }

      case OTA_STAGE_CKPT: {
        if( p->nStep>=p->nFrame ){
          sqlite3_file *pDb = p->pTargetFd->pReal;



          /* Sync the db file */
          p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);

          /* Update nBackfill */
          if( p->rc==SQLITE_OK ){



            void volatile *ptr;
            p->rc = pDb->pMethods->xShmMap(pDb, 0, 32*1024, 0, &ptr);
            if( p->rc==SQLITE_OK ){
              ((u32*)ptr)[12] = p->iMaxFrame;
            }
          }

          if( p->rc==SQLITE_OK ){
            p->eStage = OTA_STAGE_DONE;
            p->rc = SQLITE_DONE;
          }
        }else{
          OtaFrame *pFrame = &p->aFrame[p->nStep];
          otaCheckpointFrame(p, pFrame);
          p->nStep++;
        }



        p->nProgress++;
        break;
      }

      default:
        break;
    }
    return p->rc;
  }else{
    return SQLITE_NOMEM;
  }
}

static void otaSaveState(sqlite3ota *p){
  sqlite3_stmt *pInsert;
  int rc;

  assert( (p->rc==SQLITE_OK || p->rc==SQLITE_DONE) && p->zErrmsg==0 );
  rc = prepareFreeAndCollectError(p->db, &pInsert, &p->zErrmsg, 
      sqlite3_mprintf(
        "INSERT OR REPLACE INTO ota.ota_state(k, v) VALUES "
        "(%d, %d), "
        "(%d, %Q), "
        "(%d, %Q), "
        "(%d, %d), "
        "(%d, %lld), "
        "(%d, %lld), "
        "(%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, p->iWalCksum,
        OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie
      )
  );
  assert( pInsert==0 || rc==SQLITE_OK );










  if( rc==SQLITE_OK ){
    sqlite3_step(pInsert);
    rc = sqlite3_finalize(pInsert);
  }else{
    sqlite3_finalize(pInsert);
  }

................................................................................
  }
}

static void otaFreeState(OtaState *p){
  if( p ){
    sqlite3_free(p->zTbl);
    sqlite3_free(p->zIdx);

    sqlite3_free(p);
  }
}

/*
** Allocate an OtaState object and load the contents of the ota_state 
** table into it. Return a pointer to the new object. It is the 
................................................................................
        break;

      case OTA_STATE_PROGRESS:
        pRet->nProgress = sqlite3_column_int64(pStmt, 1);
        break;

      case OTA_STATE_CKPT:
        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);



        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->pTargetFd->iCookie!=(u32)sqlite3_column_int64(pStmt, 1) 
        ){
          rc = SQLITE_BUSY;
          p->zErrmsg = sqlite3_mprintf("database modified during ota update");
        }
        break;

      default:
................................................................................
  int nTarget = strlen(zTarget);
  int nOta = strlen(zOta);

  p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)+nTarget+1+nOta+1);
  if( p ){
    OtaState *pState = 0;

    /* Create the custom VFS. */
    memset(p, 0, sizeof(sqlite3ota));
    otaCreateVfs(p, 0);

    /* Open the target database */
    if( p->rc==SQLITE_OK ){
      p->zTarget = (char*)&p[1];
      memcpy(p->zTarget, zTarget, nTarget+1);
................................................................................
    }

    /* If it has not already been created, create the ota_state table */
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_exec(p->db, OTA_CREATE_STATE, 0, 0, &p->zErrmsg);
    }

    /* Check that this is not a wal mode database. If it is, it cannot be
    ** updated. There is also a check for a live *-wal file in otaVfsAccess()
    ** function, on the off chance that the target is a wal database for
    ** which the first page of the db file has been overwritten by garbage
    ** during an earlier failed checkpoint.  */
    if( p->rc==SQLITE_OK && p->pTargetFd->iWriteVer>1 ){
      p->rc = SQLITE_ERROR;
      p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
    }

    if( p->rc==SQLITE_OK ){
      pState = otaLoadState(p);
      assert( pState || p->rc!=SQLITE_OK );
      if( p->rc==SQLITE_OK ){
        if( pState->eStage==0 ){ 
          otaDeleteOalFile(p);
          p->eStage = OTA_STAGE_OAL;
        }else{
          p->eStage = pState->eStage;
        }
        p->nProgress = pState->nProgress;
      }
    }
    assert( p->rc!=SQLITE_OK || p->eStage!=0 );

    if( p->rc==SQLITE_OK ){
      if( p->eStage==OTA_STAGE_OAL ){


        /* Open the transaction */
        if( p->rc==SQLITE_OK ){


          p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);


        }
  
        /* Point the object iterator at the first object */
        if( p->rc==SQLITE_OK ){
          p->rc = otaObjIterFirst(p, &p->objiter);
        }
  
        if( p->rc==SQLITE_OK ){
          otaLoadTransactionState(p, pState);
        }
      }else if( p->eStage==OTA_STAGE_CKPT ){
        otaSetupCheckpoint(p, pState);
        p->nStep = pState->nRow;





      }else if( p->eStage==OTA_STAGE_DONE ){
        p->rc = SQLITE_DONE;
      }
    }

    otaFreeState(pState);
  }
................................................................................

    /* If the update has not been fully applied, save the state in 
    ** the ota db. If successful, this call also commits the open 
    ** transaction on the ota db. */
    assert( p->rc!=SQLITE_ROW );
    if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
      assert( p->zErrmsg==0 );
      otaSaveState(p);
    }

    /* Close any open statement handles. */
    otaObjIterFinalize(&p->objiter);

    /* Commit the transaction to the *-oal file. */
    if( p->rc==SQLITE_OK && p->eStage==OTA_STAGE_OAL ){
      p->rc = sqlite3_exec(p->db, "COMMIT", 0, 0, &p->zErrmsg);
    }

    /* Close the open database handle and VFS object. */

    sqlite3_close(p->db);
    otaDeleteVfs(p);
    sqlite3_free(p->aBuf);
    sqlite3_free(p->aFrame);

    otaEditErrmsg(p);
    rc = p->rc;
    *pzErrmsg = p->zErrmsg;
    sqlite3_free(p);
  }else{
    rc = SQLITE_NOMEM;
................................................................................
  /* 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->zDel);

  if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
    ota_file **pp;
    sqlite3_mutex_enter(p->pOtaVfs->mutex);
    for(pp=&p->pOtaVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
    *pp = p->pMainNext;
    sqlite3_mutex_leave(p->pOtaVfs->mutex);
  }

  /* Close the underlying file handle */
  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 u32 otaGetU32(u8 *aBuf){
  return ((u32)aBuf[0] << 24)
       + ((u32)aBuf[1] << 16)
       + ((u32)aBuf[2] <<  8)
       + ((u32)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;
  int rc;

  if( p->pOta 
   && p->pOta->eStage==OTA_STAGE_CAPTURE
   && (p->openFlags & SQLITE_OPEN_WAL) 
  ){
    rc = otaCaptureWalRead(p->pOta, iOfst, iAmt);
  }else{
    rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
      /* These look like magic numbers. But they are stable, as they are part
       ** of the definition of the SQLite file format, which may not change. */

      u8 *pBuf = (u8*)zBuf;
      p->iCookie = otaGetU32(&pBuf[24]);
      p->iWriteVer = pBuf[19];
    }
  }
  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;
  int rc;
  if( p->pOta 
   && p->pOta->eStage==OTA_STAGE_CAPTURE
   && (p->openFlags & SQLITE_OPEN_MAIN_DB)
  ){
    rc = otaCaptureDbWrite(p->pOta, iOfst);
  }else{
    rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
    if( rc==SQLITE_OK && iOfst==0 && (p->openFlags & SQLITE_OPEN_MAIN_DB) ){
      /* These look like magic numbers. But they are stable, as they are part
      ** of the definition of the SQLite file format, which may not change. */

      u8 *pBuf = (u8*)zBuf;
      p->iCookie = otaGetU32(&pBuf[24]);
      p->iWriteVer = pBuf[19];
    }
  }
  return rc;
}

/*
** Truncate an otaVfs-file.
*/
................................................................................
}

/*
** Sync an otaVfs-file.
*/
static int otaVfsSync(sqlite3_file *pFile, int flags){
  ota_file *p = (ota_file *)pFile;
  if( p->pOta && p->pOta->eStage==OTA_STAGE_CAPTURE ){
    if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
      return SQLITE_INTERNAL;
    }
    return SQLITE_OK;
  }
  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){
................................................................................
** Lock an otaVfs-file.
*/
static int otaVfsLock(sqlite3_file *pFile, int eLock){
  ota_file *p = (ota_file*)pFile;
  sqlite3ota *pOta = p->pOta;
  int rc = SQLITE_OK;

  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
  if( pOta && eLock==SQLITE_LOCK_EXCLUSIVE && pOta->eStage!=OTA_STAGE_DONE ){

    /* 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);
  }

................................................................................
/*
** 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;
  int (*xControl)(sqlite3_file*,int,void*) = p->pReal->pMethods->xFileControl;

  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
  if( op==SQLITE_FCNTL_OTA ){
    int rc;
    sqlite3ota *pOta = (sqlite3ota*)pArg;

    /* First try to find another OTA vfs lower down in the vfs stack. If
    ** one is found, this vfs will operate in pass-through mode. The lower
    ** level vfs will do the special OTA handling.  */
................................................................................
      rc = xControl(p->pReal, SQLITE_FCNTL_ZIPVFS_PAGER, &dummy);
      if( rc==SQLITE_OK ){
        rc = SQLITE_ERROR;
        pOta->zErrmsg = sqlite3_mprintf("ota/zipvfs setup error");
      }else if( rc==SQLITE_NOTFOUND ){
        pOta->pTargetFd = p;
        p->pOta = pOta;
        if( p->pWalFd ) p->pWalFd->pOta = pOta;
        rc = SQLITE_OK;
      }
    }
    return rc;
  }
  return xControl(p->pReal, op, pArg);
}
................................................................................
}

/*
** 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;
  sqlite3ota *pOta = p->pOta;
  int rc = SQLITE_OK;

#ifdef SQLITE_AMALGAMATION
    assert( WAL_CKPT_LOCK==1 );
#endif

  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
  if( pOta && pOta->eStage==OTA_STAGE_OAL ){
    /* Magic number 1 is the WAL_CKPT_LOCK 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==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
  }else{
    int bCapture = 0;
    if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE)
     && p->pOta && p->pOta->eStage==OTA_STAGE_CAPTURE
     && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0)
    ){
      bCapture = 1;
    }

    if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
      rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
      if( bCapture && rc==SQLITE_OK ){
        p->pOta->mLock |= (1 << ofst);
      }
    }
  }

  return rc;
}

static int otaVfsShmMap(
  sqlite3_file *pFile, 
................................................................................
){
  ota_file *p = (ota_file*)pFile;
  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.  */
  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
  if( p->pOta && p->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{
................................................................................
  p->pReal->pMethods->xShmBarrier(p->pReal);
}

static int otaVfsShmUnmap(sqlite3_file *pFile, int delFlag){
  ota_file *p = (ota_file*)pFile;
  int rc = SQLITE_OK;

  assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
  if( p->pOta && p->pOta->eStage==OTA_STAGE_OAL ){
    /* no-op */
  }else{
    rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
  }
  return rc;
}

static ota_file *otaFindMaindb(ota_vfs *pOtaVfs, const char *zWal){
  ota_file *pDb;
  sqlite3_mutex_enter(pOtaVfs->mutex);
  for(pDb=pOtaVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext);
  sqlite3_mutex_leave(pOtaVfs->mutex);
  return pDb;
}

/*
** Open an ota file handle.
*/
static int otaVfsOpen(
  sqlite3_vfs *pVfs,
  const char *zName,
................................................................................
        z += 2;
      }else{
        while( *z==0 ) z++;
      }
      z += (n + 8 + 1);
      pFd->zWal = z;
    }
    else if( flags & SQLITE_OPEN_WAL ){
      ota_file *pDb = otaFindMaindb(pOtaVfs, zName);
      if( pDb ){
        if( pDb->pOta && pDb->pOta->eStage==OTA_STAGE_OAL ){
          char *zCopy = otaStrndup(zName, -1, &rc);
          if( zCopy ){
            int nCopy = strlen(zCopy);
            zCopy[nCopy-3] = 'o';
            zOpen = (const char*)(pFd->zDel = zCopy);
          }
          pFd->pOta = pDb->pOta;
        }
        pDb->pWalFd = pFd;
      }
    }
  }

  if( rc==SQLITE_OK ){
    rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, flags, pOutFlags);
  }
  if( pFd->pReal->pMethods ){
    /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
    ** pointer and, if the file is a main database file, link it into the
    ** mutex protected linked list of all such files.  */
    pFile->pMethods = &otavfs_io_methods;
    if( flags & SQLITE_OPEN_MAIN_DB ){
      sqlite3_mutex_enter(pOtaVfs->mutex);
      pFd->pMainNext = pOtaVfs->pMain;
      pOtaVfs->pMain = pFd;
      sqlite3_mutex_leave(pOtaVfs->mutex);
    }
  }

  return rc;
}

/*
** Delete the file located at zPath.
................................................................................
){
  ota_vfs *pOtaVfs = (ota_vfs*)pVfs;
  sqlite3_vfs *pRealVfs = pOtaVfs->pRealVfs;
  int rc;

  rc = pRealVfs->xAccess(pRealVfs, zPath, flags, pResOut);

  /* If this call is to check if a *-wal file associated with an OTA target
  ** database connection exists, and the OTA update is in OTA_STAGE_OAL,
  ** the following special handling is activated:
  **
  **   a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
  **      ensures that the OTA extension never tries to update a database
  **      in wal mode, even if the first page of the database file has
  **      been damaged. 
  **
  **   b) if the *-wal file does not exist, claim that it does anyway,
  **      causing SQLite to call xOpen() to open it. This call will also
  **      be intercepted (see the otaVfsOpen() function) and the *-oal
  **      file opened instead.
  */
  if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
    ota_file *pDb = otaFindMaindb(pOtaVfs, zPath);
    if( pDb && pDb->pOta && pDb->pOta->eStage==OTA_STAGE_OAL ){
      if( *pResOut ){
        rc = SQLITE_CANTOPEN;
      }else{
        *pResOut = 1;
      }
    }
  }

  return rc;
}

/*

Changes to src/main.c.

1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
  }
  rc = sqlite3ApiExit(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
#endif
}

#ifdef SQLITE_ENABLE_OTA
/*
** Open an incremental checkpoint handle.
*/
int sqlite3_ckpt_open(
  sqlite3 *db, 
  unsigned char *a, int n, 
  sqlite3_ckpt **ppCkpt
){
  Pager *pPager = 0;
  int rc;

  *ppCkpt = 0;
  sqlite3_mutex_enter(db->mutex);

  /* Find the Pager object. */
  rc = sqlite3_file_control(db,"main",SQLITE_FCNTL_ZIPVFS_PAGER,(void*)&pPager);
  if( rc!=SQLITE_OK ){
    pPager = sqlite3BtreePager(db->aDb[0].pBt);
  }

  rc = sqlite3PagerWalCheckpointStart(db, pPager, a, n, ppCkpt);
  sqlite3_mutex_leave(db->mutex);
  return rc;
}
#endif /* SQLITE_ENABLE_OTA */


/*
** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
** to contains a zero-length string, all attached databases are 
** checkpointed.
*/
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1972
1973
1974
1975
1976
1977
1978



























1979
1980
1981
1982
1983
1984
1985
  }
  rc = sqlite3ApiExit(db, rc);
  sqlite3_mutex_leave(db->mutex);
  return rc;
#endif
}





























/*
** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
** to contains a zero-length string, all attached databases are 
** checkpointed.
*/
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){

Changes to src/pager.c.

5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
....
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
      }
    }

    /* If there is a WAL file in the file-system, open this database in WAL
    ** mode. Otherwise, the following function call is a no-op.
    */
    rc = pagerOpenWalIfPresent(pPager);

#ifndef SQLITE_OMIT_WAL
    assert( pPager->pWal==0 || rc==SQLITE_OK );
#endif
  }

  if( pagerUseWal(pPager) ){
    assert( rc==SQLITE_OK );
................................................................................
*/
int sqlite3PagerWalFramesize(Pager *pPager){
  assert( pPager->eState>=PAGER_READER );
  return sqlite3WalFramesize(pPager->pWal);
}
#endif

#ifdef SQLITE_ENABLE_OTA

/*
** Open an incremental checkpoint handle.
*/
int sqlite3PagerWalCheckpointStart(
  sqlite3 *db, 
  Pager *pPager,
  u8 *a, int n, 
  sqlite3_ckpt **ppCkpt
){
  if( pPager->pWal==0 ){
    *ppCkpt = 0;
    return SQLITE_OK;
  }else{
    return sqlite3WalCheckpointStart(db, pPager->pWal, a, n,
        pPager->xBusyHandler, pPager->pBusyHandlerArg,
        pPager->ckptSyncFlags, ppCkpt
    );
  }
}
#endif /* !SQLITE_ENABLE_OTA */

#endif /* SQLITE_OMIT_DISKIO */







<







 







<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

5177
5178
5179
5180
5181
5182
5183

5184
5185
5186
5187
5188
5189
5190
....
7264
7265
7266
7267
7268
7269
7270

7271





















7272
      }
    }

    /* If there is a WAL file in the file-system, open this database in WAL
    ** mode. Otherwise, the following function call is a no-op.
    */
    rc = pagerOpenWalIfPresent(pPager);

#ifndef SQLITE_OMIT_WAL
    assert( pPager->pWal==0 || rc==SQLITE_OK );
#endif
  }

  if( pagerUseWal(pPager) ){
    assert( rc==SQLITE_OK );
................................................................................
*/
int sqlite3PagerWalFramesize(Pager *pPager){
  assert( pPager->eState>=PAGER_READER );
  return sqlite3WalFramesize(pPager->pWal);
}
#endif
























#endif /* SQLITE_OMIT_DISKIO */

Changes to src/pager.h.

206
207
208
209
210
211
212
213
214
215
  void disable_simulated_io_errors(void);
  void enable_simulated_io_errors(void);
#else
# define disable_simulated_io_errors()
# define enable_simulated_io_errors()
#endif

int sqlite3PagerWalCheckpointStart(sqlite3*, Pager*, u8*, int, sqlite3_ckpt**);

#endif /* _PAGER_H_ */







<
<

206
207
208
209
210
211
212


213
  void disable_simulated_io_errors(void);
  void enable_simulated_io_errors(void);
#else
# define disable_simulated_io_errors()
# define enable_simulated_io_errors()
#endif



#endif /* _PAGER_H_ */

Changes to src/sqlite.h.in.

7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
**
** This API is only available if the library is built with pre-processor
** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
*/
SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);

/*
** Incremental checkpoint API.
**
** An incremental checkpoint handle is opened using the sqlite3_ckpt_open()
** API. To begin a new checkpoint, the second and third arguments should both
** be passed zero. To resume an earlier checkpoint, the second and third
** arguments should specify a buffer returned by an earlier call to
** sqlite3_ckpt_close(). When resuming a checkpoint, if the database or WAL 
** file has been modified since the checkpoint was suspended, the 
** sqlite3_ckpt_open() call fails with SQLITE_MISMATCH.
**
** Each time sqlite3_ckpt_step() is called on an open checkpoint handle, a
** single page is copied from the WAL file to the database. If no error 
** occurs, but the checkpoint is not finished, SQLITE_OK is returned. If the
** checkpoint has been finished (and so sqlite3_ckpt_step() should not be
** called again), SQLITE_DONE is returned. Otherwise, if an error occurs,
** some other SQLite error code is returned.
**
** Calling sqlite3_ckpt_close() closes an open checkpoint handle. If the
** checkpoint has finished and no error has occurred, SQLITE_OK is returned
** and the two output parameters zeroed. Or, if an error has occurred, an
** error code is returned and the two output parameters are zeroed. Finally,
** if the checkpoint is not finished but no error has occurred, SQLITE_OK is
** returned and the first output variable set to point to a buffer allocated 
** using sqlite3_malloc() containing the serialized state of the checkpoint. 
** The contents of this buffer may be passed to a later call to
** sqlite3_ckpt_open() to restart the checkpoint. The second output variable 
** is set to the size of the buffer in bytes.
**
** These APIs are only available if SQLITE_ENABLE_OTA is defined at compile
** time. They are intended for use by the OTA extension only. As such, they 
** are subject to change or removal at any point.
*/
typedef struct sqlite3_ckpt sqlite3_ckpt;
int sqlite3_ckpt_open(sqlite3*, unsigned char*, int n, sqlite3_ckpt **ppCkpt);
int sqlite3_ckpt_step(sqlite3_ckpt*);
int sqlite3_ckpt_close(sqlite3_ckpt*, unsigned char **pa, int *pn);

/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* _SQLITE3_H_ */







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<













7582
7583
7584
7585
7586
7587
7588





































7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
** ^Zero all [sqlite3_stmt_scanstatus()] related event counters.
**
** This API is only available if the library is built with pre-processor
** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined.
*/
SQLITE_EXPERIMENTAL void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);







































/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# undef double
#endif

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif
#endif /* _SQLITE3_H_ */

Changes to src/wal.c.

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
....
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
....
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
....
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905







1906
1907

1908













1909
1910
1911
1912
1913



















1914
1915
1916

































































1917
1918
1919
1920


1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
....
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
....
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
....
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
....
3130
3131
3132
3133
3134
3135
3136



3137

3138
3139
3140
3141
3142
3143
3144
....
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
    ht_slot *aIndex;              /* i0, i1, i2... such that aPgno[iN] ascend */
    u32 *aPgno;                   /* Array of page numbers. */
    int nEntry;                   /* Nr. of entries in aPgno[] and aIndex[] */
    int iZero;                    /* Frame number associated with aPgno[0] */
  } aSegment[1];                  /* One for every 32KB page in the wal-index */
};

/*
** An object of the following type is used to store state information for
** an ongoing checkpoint operation. For normal checkpoints, the instance 
** is allocated on the stack by the walCheckpoint() function. For the special
** incremental checkpoints performed by OTA clients, it is allocated in
** heap memory by sqlite3WalCheckpointStart().
**
** See the implementations of walCheckpointStart(), walCheckpointStep() and 
** walCheckpointFinalize() for further details.
*/
typedef struct WalCkpt WalCkpt;
struct WalCkpt {
  sqlite3 *db;                    /* Database pointer (incremental only) */
  int szPage;                     /* Database page-size */
  int sync_flags;                 /* Flags for OsSync() (or 0) */
  u32 mxSafeFrame;                /* Max frame that can be backfilled */
  u32 mxPage;                     /* Max database page to write */
  volatile WalCkptInfo *pInfo;    /* The checkpoint status information */
  WalIterator *pIter;             /* Wal iterator context */
  Wal *pWal;                      /* Pointer to owner object */                 
  u8 *aBuf;                       /* Temporary page-sized buffer to use */
  int rc;                         /* Error code. SQLITE_DONE -> finished */
  int nStep;                      /* Number of times pIter has been stepped */
};

/*
** Define the parameters of the hash tables in the wal-index file. There
** is a hash-table following every HASHTABLE_NPAGE page numbers in the
** wal-index.
**
** Changing any of these constants will alter the wal-index format and
** create incompatibilities.
................................................................................
      p->aSegment[i].aPgno = (u32 *)aPgno;
    }
  }
  sqlite3_free(aTmp);

  if( rc!=SQLITE_OK ){
    walIteratorFree(p);
    p = 0;
  }
  *pp = p;
  return rc;
}

/*
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
................................................................................
** The cache of the wal-index header must be valid to call this function.
** Return the page-size in bytes used by the database.
*/
static int walPagesize(Wal *pWal){
  return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
}

/*
** Initialize the contents of the WalCkpt object indicated by the final
** argument and begin a checkpoint operation. The CKPT lock must already
** be held when this function is called.
**
** Return SQLITE_OK if successful or an error code otherwise.
*/
static int walCheckpointStart(
  Wal *pWal,                      /* Wal connection */
  u8 *aBuf,                       /* Page-sized temporary buffer */
  int nBuf,                       /* Size of aBuf[] in bytes */
  int (*xBusy)(void*),            /* Function to call when busy (or NULL) */
  void *pBusyArg,                 /* Context argument for xBusyHandler */
  int sync_flags,                 /* Flags for OsSync() (or 0) */
  WalCkpt *p                      /* Allocated object to populate */
){
  int rc;                         /* Return code */
  int i;                          /* Iterator variable */

  memset(p, 0, sizeof(WalCkpt));
  if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
    return SQLITE_CORRUPT_BKPT;
  }

  p->szPage = walPagesize(pWal);
  p->pWal = pWal;
  p->aBuf = aBuf;
  p->sync_flags = sync_flags;
  testcase( p->szPage<=32768 );
  testcase( p->szPage>=65536 );
  p->pInfo = walCkptInfo(pWal);
  if( p->pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;

  /* Allocate the iterator */
  rc = walIteratorInit(pWal, &p->pIter);
  if( rc!=SQLITE_OK ) return rc;
  assert( p->pIter );

  /* Compute in mxSafeFrame the index of the last frame of the WAL that is
  ** safe to write into the database.  Frames beyond mxSafeFrame might
  ** overwrite database pages that are in use by active readers and thus
  ** cannot be backfilled from the WAL.
  */
  p->mxSafeFrame = pWal->hdr.mxFrame;
  p->mxPage = pWal->hdr.nPage;
  for(i=1; i<WAL_NREADER; i++){
    u32 y = p->pInfo->aReadMark[i];
    if( p->mxSafeFrame>y ){
      assert( y<=pWal->hdr.mxFrame );
      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
      if( rc==SQLITE_OK ){
        p->pInfo->aReadMark[i] = (i==1 ? p->mxSafeFrame : READMARK_NOT_USED);
        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
      }else if( rc==SQLITE_BUSY ){
        p->mxSafeFrame = y;
        xBusy = 0;
      }else{
        walIteratorFree(p->pIter);
        p->pIter = 0;
        return rc;
      }
    }
  }

  if( p->pInfo->nBackfill>=p->mxSafeFrame
   || (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))!=SQLITE_OK
  ){
    walIteratorFree(p->pIter);
    p->pIter = 0;
  }
  if( rc==SQLITE_BUSY ) rc = SQLITE_OK;

  if( rc==SQLITE_OK && p->pIter ){
    /* Sync the WAL to disk */
    if( sync_flags ){
      rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
    }

    /* If the database may grow as a result of this checkpoint, hint
    ** about the eventual size of the db file to the VFS layer.  */
    if( rc==SQLITE_OK ){
      i64 nSize;                  /* Current size of database file */
      i64 nReq = ((i64)p->mxPage * p->szPage);
      rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
      if( rc==SQLITE_OK && nSize<nReq ){
        sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
      }
    }
  }

  return rc;
}

/*
** Attempt to copy the next frame from the wal file to the database file. If
** there are no more frames to copy to the database file return SQLITE_DONE.
** If the frame is successfully copied, return SQLITE_OK. Or, if an error
** occurs, return an SQLite error code.
*/
static int walCheckpointStep(WalCkpt *p){
  u32 iDbpage = 0;                /* Next database page to write */
  u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
  int rc = SQLITE_DONE;

  assert( p->rc==SQLITE_OK );
  while( p->pIter && 0==walIteratorNext(p->pIter, &iDbpage, &iFrame) ){
    i64 iOffset;
    assert( walFramePgno(p->pWal, iFrame)==iDbpage );
    p->nStep++;
    if( iFrame<=p->pInfo->nBackfill 
     || iFrame>p->mxSafeFrame 
     || iDbpage>p->mxPage 
    ){
      continue;
    }

    iOffset = walFrameOffset(iFrame, p->szPage) + WAL_FRAME_HDRSIZE;
    /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
    rc = sqlite3OsRead(p->pWal->pWalFd, p->aBuf, p->szPage, iOffset);
    if( rc!=SQLITE_OK ) break;
    iOffset = (iDbpage-1)*(i64)p->szPage;
    testcase( IS_BIG_INT(iOffset) );
    rc = sqlite3OsWrite(p->pWal->pDbFd, p->aBuf, p->szPage, iOffset);
    break;
  }

  p->rc = rc;
  return rc;
}

/*
** The current round of checkpointing work using the object indicated by
** the only argument is now finished. If no error occcurred, this function
** saves the results to shared memory (i.e. updates the WalCkptInfo.nBackfill
** variable), and truncates and syncs the database file as required.
**
** All dynamic resources currently held by the WalCkpt object are released. 
** It is the responsibility of the caller to delete the WalCkpt itself if
** required.
*/
static int walCheckpointFinalize(WalCkpt *p){
  if( p->pIter ){
    int rc = p->rc;
    Wal *pWal = p->pWal;

    if( rc==SQLITE_DONE ){
      /* If work was completed */
      rc = SQLITE_OK;
      if( p->mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
        i64 szDb = pWal->hdr.nPage*(i64)p->szPage;
        testcase( IS_BIG_INT(szDb) );
        rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
        if( rc==SQLITE_OK && p->sync_flags ){
          rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags);
        }
      }
      if( rc==SQLITE_OK ){
        p->pInfo->nBackfill = p->mxSafeFrame;
      }
      p->rc = rc;
    }else{
#ifdef SQLITE_ENABLE_OTA
      if( rc==SQLITE_OK && p->sync_flags ){
        /* If work was not completed, but no error has occured. */
        p->rc = sqlite3OsSync(pWal->pDbFd, p->sync_flags);
      }
#else
      assert( rc!=SQLITE_OK );
#endif
    }

    /* Release the reader lock held while backfilling */
    walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
    walIteratorFree(p->pIter);
    p->pIter = 0;
  }else if( p->rc==SQLITE_DONE ){
    p->rc = SQLITE_OK;
  }

  return p->rc;
}

/*
** The following is guaranteed when this function is called:
**
**   a) the WRITER lock is held,
**   b) the entire log file has been checkpointed, and
**   c) any existing readers are reading exclusively from the database
**      file - there are no readers that may attempt to read a frame from
................................................................................
*/
static int walCheckpoint(
  Wal *pWal,                      /* Wal connection */
  int eMode,                      /* One of PASSIVE, FULL or RESTART */
  int (*xBusy)(void*),            /* Function to call when busy */
  void *pBusyArg,                 /* Context argument for xBusyHandler */
  int sync_flags,                 /* Flags for OsSync() (or 0) */
  u8 *zBuf,                       /* Temporary buffer to use */
  int nBuf                        /* Size of zBuf in bytes */
){







  int rc;                         /* Return code */
  WalCkpt sC;















  /* 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 );

  rc = walCheckpointStart(pWal, zBuf, nBuf, xBusy, pBusyArg, sync_flags, &sC);



















  if( rc!=SQLITE_OK ) goto walcheckpoint_out;

  /* Step the checkpoint object until it reports something other than 

































































  ** SQLITE_OK.  */
  while( SQLITE_OK==(rc = walCheckpointStep(&sC)) );
  rc = walCheckpointFinalize(&sC);



  /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
  ** entire wal file has been copied into the database file, then block 
  ** until all readers have finished using the wal file. This ensures that 
  ** the next process to write to the database restarts the wal file.
  */
  if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
    assert( pWal->writeLock );
    if( sC.pInfo->nBackfill<pWal->hdr.mxFrame ){
      rc = SQLITE_BUSY;
    }else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
      u32 salt1;
      sqlite3_randomness(4, &salt1);
      assert( sC.pInfo->nBackfill==pWal->hdr.mxFrame );
      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
      if( rc==SQLITE_OK ){
        if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
          /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
          ** SQLITE_CHECKPOINT_RESTART with the addition that it also
          ** truncates the log file to zero bytes just prior to a
          ** successful return.
................................................................................
        }
        walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
      }
    }
  }

 walcheckpoint_out:
  walIteratorFree(sC.pIter);
  return rc;
}

/*
** If the WAL file is currently larger than nMax bytes in size, truncate
** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
*/
................................................................................
  if( rx ){
    sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
  }
}

/*
** Close a connection to a log file.
**
** If parameter zBuf is not NULL, also attempt to obtain an exclusive 
** lock and run a checkpoint.
*/
int sqlite3WalClose(
  Wal *pWal,                      /* Wal to close */
  int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
  int nBuf,
  u8 *zBuf                        /* Buffer of at least nBuf bytes */
){
................................................................................
    ** ordinary, rollback-mode locking methods, this guarantees that the
    ** connection associated with this log file is the only connection to
    ** the database. In this case checkpoint the database and unlink both
    ** the wal and wal-index files.
    **
    ** The EXCLUSIVE lock is not released before returning.
    */
#ifdef SQLITE_ENABLE_OTA
    if( zBuf )          /* In non-OTA builds, zBuf is always non-NULL */
#endif
    {
      rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
      if( rc==SQLITE_OK ){
        if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
          pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
        }
        rc = sqlite3WalCheckpoint(
            pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
        );
        if( rc==SQLITE_OK ){
          int bPersist = -1;
          sqlite3OsFileControlHint(
              pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
          );
          if( bPersist!=1 ){
            /* Try to delete the WAL file if the checkpoint completed and
            ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
            ** mode (!bPersist) */
            isDelete = 1;
          }else if( pWal->mxWalSize>=0 ){
            /* Try to truncate the WAL file to zero bytes if the checkpoint
            ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
            ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
            ** non-negative value (pWal->mxWalSize>=0).  Note that we truncate
            ** to zero bytes as truncating to the journal_size_limit might
            ** leave a corrupt WAL file on disk. */
            walLimitSize(pWal, 0);
          }
        }
      }
    }

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){
................................................................................
    if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
      sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
    }
  }

  /* Copy data from the log to the database file. */
  if( rc==SQLITE_OK ){



    rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf, nBuf);


    /* If no error occurred, set the output variables. */
    if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
      if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
      if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
    }
  }
................................................................................
  sqlite3WalEndWriteTransaction(pWal);
  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
  pWal->ckptLock = 0;
  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
  return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
}

#ifdef SQLITE_ENABLE_OTA

/*
** Step the checkpoint object passed as the first argument.
*/
int sqlite3_ckpt_step(sqlite3_ckpt *pCkpt){
  int rc;
  WalCkpt *p = (WalCkpt*)pCkpt;
  sqlite3_mutex_enter(p->db->mutex);
  rc = walCheckpointStep(p);
  sqlite3_mutex_leave(p->db->mutex);
  return rc;
}

/*
** Close the checkpoint object passed as the first argument. If the checkpoint
** was completed, zero the two output variables. Otherwise, set *paState to
** point to a buffer containing data that may be passed to a subsequent 
** call to ckpt_open() to resume the checkpoint. In this case *pnState is
** set to the size of the buffer in bytes. The buffer should be eventually
** freed by the caller using sqlite3_free().
*/
int sqlite3_ckpt_close(sqlite3_ckpt *pCkpt, u8 **paState, int *pnState){
  int rc;
  WalCkpt *p = (WalCkpt*)pCkpt;
  sqlite3 *db = p->db;
  Wal *pWal = p->pWal;
  sqlite3_mutex_enter(db->mutex);
  if( paState ){
    *paState = 0;
    *pnState = 0;
    if( p->rc==SQLITE_OK ){
      u8 *aState = sqlite3_malloc(sizeof(u32) * 3);
      if( aState==0 ){
        p->rc = SQLITE_NOMEM;
      }else{
        *pnState = sizeof(u32)*3;
        sqlite3Put4byte(&aState[0], p->nStep);
        sqlite3Put4byte(&aState[4], p->pWal->hdr.aCksum[0]);
        sqlite3Put4byte(&aState[8], p->pWal->hdr.aCksum[1]);
        *paState = aState;
      }
    }
  }
  rc = walCheckpointFinalize(p);
  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
  pWal->ckptLock = 0;
  sqlite3_free(p);
  memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

/*
** Open an incremental checkpoint handle.
*/
int sqlite3WalCheckpointStart(
  sqlite3 *db,                    /* Database connection */
  Wal *pWal,                      /* Wal connection */
  u8 *aState, int nState,         /* Checkpoint state to restore */
  int (*xBusy)(void*),            /* Function to call when busy */
  void *pBusyArg,                 /* Context argument for xBusyHandler */
  int sync_flags,                 /* Flags to sync db file with (or 0) */
  sqlite3_ckpt **ppCkpt           /* OUT: Incremental checkpoint object */
){
  WalCkpt *p = 0;
  int isChanged = 0;
  int rc;
  int pgsz;

  *ppCkpt = 0;
  if( pWal->readOnly ) return SQLITE_READONLY;
  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
  if( rc ){
    /* Usually this is SQLITE_BUSY meaning that another thread or process
    ** is already running a checkpoint, or maybe a recovery.  But it might
    ** also be SQLITE_IOERR. */
    return rc;
  }
  pWal->ckptLock = 1;

  /* Read the wal-index header. */
  rc = walIndexReadHdr(pWal, &isChanged);
  if( rc!=SQLITE_OK ) goto ckptstart_out;
  if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
    sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
  }

  pgsz = walPagesize(pWal);
  p = sqlite3_malloc(sizeof(WalCkpt) + pgsz);
  if( p==0 ){
    rc = SQLITE_NOMEM;
    goto ckptstart_out;
  }

  rc = walCheckpointStart(
      pWal, (u8*)&p[1], pgsz, xBusy, pBusyArg, sync_flags, p
  );
  p->db = db;

  if( rc==SQLITE_OK && aState ){
    if( nState!=sizeof(u32)*3 ){
      rc = SQLITE_CORRUPT_BKPT;
    }else{
      int i;
      if( pWal->hdr.aCksum[0]!=sqlite3Get4byte(&aState[4])
       || pWal->hdr.aCksum[1]!=sqlite3Get4byte(&aState[8])
      ){
        rc = SQLITE_MISMATCH;
      }else{
        p->nStep = (int)sqlite3Get4byte(aState);
        sqlite3Put4byte(&aState[4], pWal->hdr.aCksum[0]);
        sqlite3Put4byte(&aState[8], pWal->hdr.aCksum[1]);
        for(i=0; rc==SQLITE_OK && i<p->nStep; i++){
          u32 dummy1, dummy2; 
          rc = walIteratorNext(p->pIter, &dummy1, &dummy2);
        }
      }
    }
  }

 ckptstart_out:
  if( rc!=SQLITE_OK ){
    if( p ) walIteratorFree(p->pIter);
    walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
    pWal->ckptLock = 0;
    sqlite3_free(p);
    p = 0;
  }
  *ppCkpt = (sqlite3_ckpt*)p;
  return rc;
}
#endif /* SQLITE_ENABLE_OTA */

/*
** Unless the wal file is empty, check that the 8 bytes of salt stored in
** the wal header are identical to those in the buffer indicated by the
** second argument. If they are not, return SQLITE_BUSY_SNAPSHOT. Otherwise,
** if the buffers match or the WAL file is empty, return SQLITE_OK.
*/
int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file *pFd){
  int rc = SQLITE_OK;
  if( pWal->hdr.mxFrame>0 ){
    u8 aData[16];
    rc = sqlite3OsRead(pFd, aData, sizeof(aData), 24);
    if( rc==SQLITE_OK && memcmp(pWal->hdr.aSalt, aData, 8) ){
      rc = SQLITE_BUSY_SNAPSHOT;
    }
  }
  return rc;
}

/* Return the value to pass to a sqlite3_wal_hook callback, the
** number of frames in the WAL at the point of the last commit since
** sqlite3WalCallback() was called.  If no commits have occurred since
** the last call, then return 0.
*/
int sqlite3WalCallback(Wal *pWal){
  u32 ret = 0;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
|

>
>
>
>
>
>
>
|
<
>

>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|

<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
<
|
>
>







|




|







 







|







 







<
<
<







 







<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<







 







>
>
>
|
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







478
479
480
481
482
483
484

























485
486
487
488
489
490
491
....
1586
1587
1588
1589
1590
1591
1592

1593
1594
1595
1596
1597
1598
1599
....
1619
1620
1621
1622
1623
1624
1625






















































































































































































1626
1627
1628
1629
1630
1631
1632
....
1688
1689
1690
1691
1692
1693
1694

1695
1696
1697
1698
1699
1700
1701
1702
1703
1704

1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723

1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744

1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810


1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
....
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
....
1869
1870
1871
1872
1873
1874
1875



1876
1877
1878
1879
1880
1881
1882
....
1888
1889
1890
1891
1892
1893
1894




1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920

1921
1922
1923
1924
1925
1926
1927
....
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
....
3046
3047
3048
3049
3050
3051
3052

























































































































































3053
3054
3055
3056
3057
3058
3059
    ht_slot *aIndex;              /* i0, i1, i2... such that aPgno[iN] ascend */
    u32 *aPgno;                   /* Array of page numbers. */
    int nEntry;                   /* Nr. of entries in aPgno[] and aIndex[] */
    int iZero;                    /* Frame number associated with aPgno[0] */
  } aSegment[1];                  /* One for every 32KB page in the wal-index */
};


























/*
** Define the parameters of the hash tables in the wal-index file. There
** is a hash-table following every HASHTABLE_NPAGE page numbers in the
** wal-index.
**
** Changing any of these constants will alter the wal-index format and
** create incompatibilities.
................................................................................
      p->aSegment[i].aPgno = (u32 *)aPgno;
    }
  }
  sqlite3_free(aTmp);

  if( rc!=SQLITE_OK ){
    walIteratorFree(p);

  }
  *pp = p;
  return rc;
}

/*
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
................................................................................
** The cache of the wal-index header must be valid to call this function.
** Return the page-size in bytes used by the database.
*/
static int walPagesize(Wal *pWal){
  return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
}























































































































































































/*
** The following is guaranteed when this function is called:
**
**   a) the WRITER lock is held,
**   b) the entire log file has been checkpointed, and
**   c) any existing readers are reading exclusively from the database
**      file - there are no readers that may attempt to read a frame from
................................................................................
*/
static int walCheckpoint(
  Wal *pWal,                      /* Wal connection */
  int eMode,                      /* One of PASSIVE, FULL or RESTART */
  int (*xBusy)(void*),            /* Function to call when busy */
  void *pBusyArg,                 /* Context argument for xBusyHandler */
  int sync_flags,                 /* Flags for OsSync() (or 0) */

  u8 *zBuf                        /* Temporary buffer to use */
){
  int rc = SQLITE_OK;             /* Return code */
  int szPage;                     /* Database page-size */
  WalIterator *pIter = 0;         /* Wal iterator context */
  u32 iDbpage = 0;                /* Next database page to write */
  u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
  u32 mxSafeFrame;                /* Max frame that can be backfilled */
  u32 mxPage;                     /* Max database page to write */
  int i;                          /* Loop counter */

  volatile WalCkptInfo *pInfo;    /* The checkpoint status information */

  szPage = walPagesize(pWal);
  testcase( szPage<=32768 );
  testcase( szPage>=65536 );
  pInfo = walCkptInfo(pWal);
  if( pInfo->nBackfill<pWal->hdr.mxFrame ){

    /* Allocate the iterator */
    rc = walIteratorInit(pWal, &pIter);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    assert( pIter );

    /* 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 );


    /* Compute in mxSafeFrame the index of the last frame of the WAL that is
    ** safe to write into the database.  Frames beyond mxSafeFrame might
    ** overwrite database pages that are in use by active readers and thus
    ** cannot be backfilled from the WAL.
    */
    mxSafeFrame = pWal->hdr.mxFrame;
    mxPage = pWal->hdr.nPage;
    for(i=1; i<WAL_NREADER; i++){
      u32 y = pInfo->aReadMark[i];
      if( mxSafeFrame>y ){
        assert( y<=pWal->hdr.mxFrame );
        rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
        if( rc==SQLITE_OK ){
          pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
        }else if( rc==SQLITE_BUSY ){
          mxSafeFrame = y;
          xBusy = 0;
        }else{
          goto walcheckpoint_out;
        }

      }
    }

    if( pInfo->nBackfill<mxSafeFrame
     && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
    ){
      i64 nSize;                    /* Current size of database file */
      u32 nBackfill = pInfo->nBackfill;

      /* Sync the WAL to disk */
      if( sync_flags ){
        rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
      }

      /* If the database may grow as a result of this checkpoint, hint
      ** about the eventual size of the db file to the VFS layer.
      */
      if( rc==SQLITE_OK ){
        i64 nReq = ((i64)mxPage * szPage);
        rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
        if( rc==SQLITE_OK && nSize<nReq ){
          sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
        }
      }


      /* Iterate through the contents of the WAL, copying data to the db file */
      while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
        i64 iOffset;
        assert( walFramePgno(pWal, iFrame)==iDbpage );
        if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ){
          continue;
        }
        iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
        /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
        rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
        if( rc!=SQLITE_OK ) break;
        iOffset = (iDbpage-1)*(i64)szPage;
        testcase( IS_BIG_INT(iOffset) );
        rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
        if( rc!=SQLITE_OK ) break;
      }

      /* If work was actually accomplished... */
      if( rc==SQLITE_OK ){
        if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
          i64 szDb = pWal->hdr.nPage*(i64)szPage;
          testcase( IS_BIG_INT(szDb) );
          rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
          if( rc==SQLITE_OK && sync_flags ){
            rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
          }
        }
        if( rc==SQLITE_OK ){
          pInfo->nBackfill = mxSafeFrame;
        }
      }

      /* Release the reader lock held while backfilling */
      walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
    }

    if( rc==SQLITE_BUSY ){
      /* Reset the return code so as not to report a checkpoint failure
      ** just because there are active readers.  */
      rc = SQLITE_OK;


    }
  }

  /* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
  ** entire wal file has been copied into the database file, then block 
  ** until all readers have finished using the wal file. This ensures that 
  ** the next process to write to the database restarts the wal file.
  */
  if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
    assert( pWal->writeLock );
    if( pInfo->nBackfill<pWal->hdr.mxFrame ){
      rc = SQLITE_BUSY;
    }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);
      if( rc==SQLITE_OK ){
        if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
          /* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
          ** SQLITE_CHECKPOINT_RESTART with the addition that it also
          ** truncates the log file to zero bytes just prior to a
          ** successful return.
................................................................................
        }
        walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
      }
    }
  }

 walcheckpoint_out:
  walIteratorFree(pIter);
  return rc;
}

/*
** If the WAL file is currently larger than nMax bytes in size, truncate
** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
*/
................................................................................
  if( rx ){
    sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
  }
}

/*
** Close a connection to a log file.



*/
int sqlite3WalClose(
  Wal *pWal,                      /* Wal to close */
  int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
  int nBuf,
  u8 *zBuf                        /* Buffer of at least nBuf bytes */
){
................................................................................
    ** ordinary, rollback-mode locking methods, this guarantees that the
    ** connection associated with this log file is the only connection to
    ** the database. In this case checkpoint the database and unlink both
    ** the wal and wal-index files.
    **
    ** The EXCLUSIVE lock is not released before returning.
    */




    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){
      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
      }
      rc = sqlite3WalCheckpoint(
          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
      );
      if( rc==SQLITE_OK ){
        int bPersist = -1;
        sqlite3OsFileControlHint(
            pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
        );
        if( bPersist!=1 ){
          /* Try to delete the WAL file if the checkpoint completed and
          ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
          ** mode (!bPersist) */
          isDelete = 1;
        }else if( pWal->mxWalSize>=0 ){
          /* Try to truncate the WAL file to zero bytes if the checkpoint
          ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
          ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
          ** non-negative value (pWal->mxWalSize>=0).  Note that we truncate
          ** to zero bytes as truncating to the journal_size_limit might
          ** leave a corrupt WAL file on disk. */
          walLimitSize(pWal, 0);

        }
      }
    }

    walIndexClose(pWal, isDelete);
    sqlite3OsClose(pWal->pWalFd);
    if( isDelete ){
................................................................................
    if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
      sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
    }
  }

  /* Copy data from the log to the database file. */
  if( rc==SQLITE_OK ){
    if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
      rc = SQLITE_CORRUPT_BKPT;
    }else{
      rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
    }

    /* If no error occurred, set the output variables. */
    if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
      if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
      if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
    }
  }
................................................................................
  sqlite3WalEndWriteTransaction(pWal);
  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
  pWal->ckptLock = 0;
  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
  return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
}


























































































































































/* Return the value to pass to a sqlite3_wal_hook callback, the
** number of frames in the WAL at the point of the last commit since
** sqlite3WalCallback() was called.  If no commits have occurred since
** the last call, then return 0.
*/
int sqlite3WalCallback(Wal *pWal){
  u32 ret = 0;

Changes to src/wal.h.

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

/* Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
** WAL module is using shared-memory, return false. 
*/
int sqlite3WalHeapMemory(Wal *pWal);

int sqlite3WalCheckSalt(Wal *pWal, sqlite3_file*);

int sqlite3WalCheckpointStart(sqlite3 *,
  Wal *pWal,                      /* Wal connection */
  u8 *aState, int nState,         /* Checkpoint state to restore */
  int (*xBusy)(void*),            /* Function to call when busy */
  void *pBusyArg,                 /* Context argument for xBusyHandler */
  int sync_flags,                 /* Flags to sync db file with (or 0) */
  sqlite3_ckpt **ppCkpt           /* OUT: Incremental checkpoint object */
);

#ifdef SQLITE_ENABLE_ZIPVFS
/* If the WAL file is not empty, return the number of bytes of content
** stored in each frame (i.e. the db page-size when the WAL was created).
*/
int sqlite3WalFramesize(Wal *pWal);
#endif

#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* _WAL_H_ */







<
<
<
<
<
<
<
<
<
<
<









122
123
124
125
126
127
128











129
130
131
132
133
134
135
136
137

/* Return true if the argument is non-NULL and the WAL module is using
** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
** WAL module is using shared-memory, return false. 
*/
int sqlite3WalHeapMemory(Wal *pWal);












#ifdef SQLITE_ENABLE_ZIPVFS
/* If the WAL file is not empty, return the number of bytes of content
** stored in each frame (i.e. the db page-size when the WAL was created).
*/
int sqlite3WalFramesize(Wal *pWal);
#endif

#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* _WAL_H_ */