/ Check-in [209f672e]
Login

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

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

Changes to ext/ota/ota2.test.

10
11
12
13
14
15
16

17
18
19
20
21
22
23
24

25
26

27
28
29
30
31


32
33
34
35
36
37
38
39









40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

55
56
57




58
59




60
61
62
#***********************************************************************
#

set testdir [file join [file dirname $argv0] .. .. test]
source $testdir/tester.tcl
set ::testprefix ota2



do_execsql_test 1.0 {
  PRAGMA ota_mode = 1;
  PRAGMA journal_mode = wal;
  CREATE TABLE t1(a, b);
  BEGIN;
    INSERT INTO t1 VALUES(1, 2);
} {wal}


do_test 1.1 {

  set state [sqlite3_transaction_save db]
  db close
  file exists test.db-wal
} {1}



do_test 1.2 {
  sqlite3 db test.db
  db eval {SELECT * FROM t1}
} {}

do_test 1.3 {
  execsql {BEGIN IMMEDIATE}
  sqlite3_transaction_restore db $::state









  db eval {SELECT * FROM t1}
} {1 2}

do_test 1.4 {
  execsql {
    INSERT INTO t1 VALUES(3, 4);
    COMMIT;
    SELECT * FROM t1;
  }
} {1 2 3 4}

do_test 1.5 {
  db close
  file exists test.db-wal
} {0}


do_test 1.5 {
  sqlite3 db test.db




  db eval {SELECT * FROM t1}
} {1 2 3 4}





finish_test








>


<
<

<
|
|
>

|
>
|
|
|
|

>
>
|
|
|
|

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

<
|
|
<
|
<
|

<
|
<
<
>

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



10
11
12
13
14
15
16
17
18
19


20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51

52
53

54

55
56

57


58
59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
#***********************************************************************
#

set testdir [file join [file dirname $argv0] .. .. test]
source $testdir/tester.tcl
set ::testprefix ota2

forcedelete test.db-oal 

do_execsql_test 1.0 {


  CREATE TABLE t1(a, b);

  INSERT INTO t1 VALUES(1, 2);
} {}
do_test 1.1 { glob test.db* } {test.db}

do_execsql_test 1.2 {
  PRAGMA pager_ota_mode = 1;
  INSERT INTO t1 VALUES(3, 4);
  INSERT INTO t1 VALUES(5, 6);
  SELECT * FROM t1;
} {1 2 3 4 5 6}

do_test 1.3 { glob test.db* } {test.db test.db-oal}

do_test 1.4 {
  sqlite3 db2 test.db
  db2 eval { SELECT * FROM t1 }
} {1 2}

do_test 1.5 {


  catchsql { INSERT INTO t1 VALUES(7, 8) } db2
} {1 {database is locked}}

db2 close
db close

sqlite3 db test.db
do_execsql_test 1.6 {
  PRAGMA pager_ota_mode = 1;
  SELECT * FROM t1;
} {1 2 3 4 5 6}


do_execsql_test 1.7 {
  INSERT INTO t1 VALUES(7,8);

  SELECT * FROM t1;

} {1 2 3 4 5 6 7 8}


db close


sqlite3 db2 test.db

do_test 1.8 {

  execsql { BEGIN; SELECT * FROM t1 } db2
} {1 2}
do_test 1.9 {
  file rename test.db-oal test.db-wal
  execsql { SELECT * FROM t1 } db2
} {1 2}
do_test 1.10 {
  execsql { COMMIT; SELECT * FROM t1 } db2
} {1 2 3 4 5 6 7 8}


finish_test

Changes to ext/ota/sqlite3ota.c.

9
10
11
12
13
14
15


16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
..
83
84
85
86
87
88
89






90
91
92
93

94
95
96
97
98
99
100
...
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532



533
534
535





536
537
538
539
540
541
542
543
544
545
546
547
548












549
550
551
552
553
554

555
556
557
558
559
560
561
562




563
564
565



566
567






568



569

570

















571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613

614
615
616














617
618

619
620
621


622
623











624
625
626
627
628
629

630
631
632

633
634
635


636
637
638
639
640
641
642
643
644








645


646
647
648
649
650
651
652
653
654
...
657
658
659
660
661
662
663
664
665


666
667
668
669
670
671
672
...
686
687
688
689
690
691
692
693
694
695
696
697






698
699
700
701
702
703
704
705
706
707
708
709
710
**    May you share freely, never taking more than you give.
**
*************************************************************************
*/

#include <assert.h>
#include <string.h>



#include "sqlite3.h"
#include "sqlite3ota.h"


/*
** The ota_state table is used to save the state of a partially applied
** update so that it can be resumed later. The table contains at most a
** single row:
**
**   "wal_state" -> Blob to use with sqlite3_transaction_restore().
**
**   "tbl"       -> Table currently being written (target database names).
**
**   "idx"       -> Index currently being written (target database names).
**                  Or, if the main table is being written, a NULL value.
**
**   "row"       -> Last rowid processed from ota database table (i.e. data_%).
**
**   "progress"  -> total number of key/value b-tree operations performed
**                  so far as part of this ota update.
*/
#define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota_state"        \
                             "(wal_state, tbl, idx, row, progress)"

typedef struct OtaTblIter OtaTblIter;
typedef struct OtaIdxIter OtaIdxIter;


/*
** Iterator used to iterate through all data tables in the OTA. As follows:
**
**   OtaTblIter iter;
**   for(rc=tblIterFirst(db, &iter); 
**       rc==SQLITE_OK && iter.zTarget; 
................................................................................

  int nCol;                       /* Number of columns in index */
  int *aiCol;                     /* Array of column indexes */
  sqlite3_stmt *pWriter;          /* Index writer */
  sqlite3_stmt *pSelect;          /* Select to read values in index order */
};








struct sqlite3ota {
  sqlite3 *dbDest;                /* Target db */
  sqlite3 *dbOta;                 /* Ota db */


  int rc;                         /* Value returned by last ota_step() call */
  char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */

  OtaTblIter tbliter;             /* Used to iterate through tables */
  OtaIdxIter idxiter;             /* Used to iterate through indexes */
};
................................................................................
      const char *zErr = sqlite3_errmsg(*pDb);
      p->zErrmsg = sqlite3_mprintf("sqlite3_open(): %s", zErr);
    }
  }
}

static void otaSaveTransactionState(sqlite3ota *p){
  sqlite3_stmt *pStmt = 0;
  void *pWalState = 0;
  int nWalState = 0;
  int rc;

  const char *zInsert = 
    "INSERT INTO ota_state(wal_state, tbl, idx, row, progress)"
    "VALUES(:wal_state, :tbl, :idx, :row, :progress)";

  rc = sqlite3_transaction_save(p->dbDest, &pWalState, &nWalState);
  if( rc==SQLITE_OK ){
    rc = sqlite3_exec(p->dbOta, "DELETE FROM ota_state", 0, 0, 0);
  }
  if( rc==SQLITE_OK ){
    rc = prepareAndCollectError(p->dbOta, zInsert, &pStmt, &p->zErrmsg);
  }
  if( rc==SQLITE_OK ){
    sqlite3_stmt *pSelect;
    pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);
    sqlite3_bind_blob(pStmt, 1, pWalState, nWalState, SQLITE_STATIC);
    sqlite3_bind_text(pStmt, 2, p->tbliter.zTarget, -1, SQLITE_STATIC);
    if( p->idxiter.zIndex ){
      sqlite3_bind_text(pStmt, 3, p->idxiter.zIndex, -1, SQLITE_STATIC);
    }



    sqlite3_bind_int64(pStmt, 4, sqlite3_column_int64(pSelect, 0));
    sqlite3_step(pStmt);
    rc = sqlite3_finalize(pStmt);





    if( rc==SQLITE_OK ){
      rc = sqlite3_exec(p->dbOta, "COMMIT", 0, 0, 0);
    }
    if( rc!=SQLITE_OK ){
      p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->dbOta));
    }
  }
  sqlite3_free(pWalState);
  assert( p->rc==SQLITE_OK );
  p->rc = rc;
}

static void otaLoadTransactionState(sqlite3ota *p){












  sqlite3_stmt *pStmt = 0;
  int rc;

  const char *zSelect = 
    "SELECT wal_state, tbl, idx, row, progress FROM ota_state";


  rc = prepareAndCollectError(p->dbOta, zSelect, &pStmt, &p->zErrmsg);
  if( rc==SQLITE_OK ){
    if( SQLITE_ROW==sqlite3_step(pStmt) ){
      const void *pWalState = 0;
      int nWalState = 0;
      const char *zTbl;
      const char *zIdx;
      sqlite3_int64 iRowid;





      pWalState = sqlite3_column_blob(pStmt, 0);
      nWalState = sqlite3_column_bytes(pStmt, 0);



      zTbl = (const char*)sqlite3_column_text(pStmt, 1);
      zIdx = (const char*)sqlite3_column_text(pStmt, 2);






      iRowid = sqlite3_column_int64(pStmt, 3);



      rc = sqlite3_transaction_restore(p->dbDest, pWalState, nWalState);



















      while( rc==SQLITE_OK 
          && p->tbliter.zTarget 
          && sqlite3_stricmp(p->tbliter.zTarget, zTbl) 
      ){
        rc = tblIterNext(&p->tbliter);
      }
      if( rc==SQLITE_OK && !p->tbliter.zTarget ){
        rc = SQLITE_ERROR;
        p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
      }

      if( rc==SQLITE_OK && zIdx ){
        rc = idxIterFirst(p->dbDest, p->tbliter.zTarget, &p->idxiter);
        while( rc==SQLITE_OK 
            && p->idxiter.zIndex 
            && sqlite3_stricmp(p->idxiter.zIndex, zIdx) 
        ){
          rc = idxIterNext(&p->idxiter);
        }
        if( rc==SQLITE_OK && !p->idxiter.zIndex ){
          rc = SQLITE_ERROR;
          p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
        }
      }

      if( rc==SQLITE_OK ){
        rc = otaPrepareAll(p);
      }

      if( rc==SQLITE_OK ){
        sqlite3_stmt *pSelect;
        pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);
        while( sqlite3_column_int64(pSelect, 0)!=iRowid ){
          rc = sqlite3_step(pSelect);
          if( rc!=SQLITE_ROW ) break;
        }
        if( rc==SQLITE_ROW ){
          rc = SQLITE_OK;
        }else{
          rc = SQLITE_ERROR;
          p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
        }
      }

    }
    if( rc==SQLITE_OK ){
      rc = sqlite3_finalize(pStmt);














    }else{
      sqlite3_finalize(pStmt);

    }
  }
  p->rc = rc;


}













/*
** Open and return a new OTA handle. 
*/
sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
  sqlite3ota *p;


  p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota));
  if( p ){


    /* Open the target database */
    memset(p, 0, sizeof(sqlite3ota));


    otaOpenDatabase(p, &p->dbDest, zTarget);
    otaOpenDatabase(p, &p->dbOta, zOta);

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

    if( p->rc==SQLITE_OK ){








      const char *zScript = 


        "PRAGMA ota_mode=1;"
        "PRAGMA journal_mode=wal;"
        "BEGIN IMMEDIATE;"
      ;
      p->rc = sqlite3_exec(p->dbDest, zScript, 0, 0, &p->zErrmsg);
    }

    if( p->rc==SQLITE_OK ){
      const char *zScript = "BEGIN IMMEDIATE";
................................................................................

    /* Point the table iterator at the first table */
    if( p->rc==SQLITE_OK ){
      p->rc = tblIterFirst(p->dbOta, &p->tbliter);
    }

    if( p->rc==SQLITE_OK ){
      otaLoadTransactionState(p);
    }


  }

  return p;
}

static void otaCloseHandle(sqlite3 *db){
  int rc = sqlite3_close(db);
................................................................................
      otaSaveTransactionState(p);
    }

    /* Close all open statement handles. */
    tblIterFinalize(&p->tbliter);
    idxIterFinalize(&p->idxiter);

    /* If the ota update has been fully applied, commit the transaction
    ** on the target database. */
    if( p->rc==SQLITE_DONE ){
      rc = sqlite3_exec(p->dbDest, "COMMIT", 0, 0, &p->zErrmsg);
      if( rc!=SQLITE_OK ) p->rc = rc;






    }

    rc = p->rc;
    *pzErrmsg = p->zErrmsg;
    otaCloseHandle(p->dbDest);
    otaCloseHandle(p->dbOta);
    sqlite3_free(p);
  }else{
    rc = SQLITE_NOMEM;
    *pzErrmsg = 0;
  }
  return rc;
}







>
>










<
<











|



>







 







>
>
>
>
>
>




>







 







|
<
<
<
<
|
<
<

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

<
<
|
|
|
<
<


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


<
<
<
>


|
<
<
<
|
<
>
>
>
>

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

|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|

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


>
>
>
>
>
>
>
>
>
>
>






>

|

>



>
>









>
>
>
>
>
>
>
>
|
>
>

<







 







|

>
>







 







|
<
|


>
>
>
>
>
>




<
<







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
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
...
510
511
512
513
514
515
516
517




518


519









520





521
522
523
524


525
526
527
528
529
530
531
532


533
534
535


536
537

538
539
540
541
542
543
544
545
546
547
548
549
550
551
552



553
554
555
556



557

558
559
560
561
562


563
564
565
566

567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641


642
643
644
645
646
647
648
649
650
651
652
653
654
655
656

657
658
659

660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711

712
713
714
715
716
717
718
...
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
...
752
753
754
755
756
757
758
759

760
761
762
763
764
765
766
767
768
769
770
771
772


773
774
775
776
777
778
779
**    May you share freely, never taking more than you give.
**
*************************************************************************
*/

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

#include "sqlite3.h"
#include "sqlite3ota.h"


/*
** The ota_state table is used to save the state of a partially applied
** update so that it can be resumed later. The table contains at most a
** single row:
**


**   "tbl"       -> Table currently being written (target database names).
**
**   "idx"       -> Index currently being written (target database names).
**                  Or, if the main table is being written, a NULL value.
**
**   "row"       -> Last rowid processed from ota database table (i.e. data_%).
**
**   "progress"  -> total number of key/value b-tree operations performed
**                  so far as part of this ota update.
*/
#define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota_state"        \
                             "(tbl, idx, row, progress)"

typedef struct OtaTblIter OtaTblIter;
typedef struct OtaIdxIter OtaIdxIter;
typedef struct OtaState OtaState;

/*
** Iterator used to iterate through all data tables in the OTA. As follows:
**
**   OtaTblIter iter;
**   for(rc=tblIterFirst(db, &iter); 
**       rc==SQLITE_OK && iter.zTarget; 
................................................................................

  int nCol;                       /* Number of columns in index */
  int *aiCol;                     /* Array of column indexes */
  sqlite3_stmt *pWriter;          /* Index writer */
  sqlite3_stmt *pSelect;          /* Select to read values in index order */
};

struct OtaState {
  char *zTbl;
  char *zIdx;
  sqlite3_int64 iRow;
};


struct sqlite3ota {
  sqlite3 *dbDest;                /* Target db */
  sqlite3 *dbOta;                 /* Ota db */
  char *zTarget;                  /* Path to target db */

  int rc;                         /* Value returned by last ota_step() call */
  char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */

  OtaTblIter tbliter;             /* Used to iterate through tables */
  OtaIdxIter idxiter;             /* Used to iterate through indexes */
};
................................................................................
      const char *zErr = sqlite3_errmsg(*pDb);
      p->zErrmsg = sqlite3_mprintf("sqlite3_open(): %s", zErr);
    }
  }
}

static void otaSaveTransactionState(sqlite3ota *p){
  sqlite3_stmt *pSelect;




  char *zInsert;












  pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);





  zInsert = sqlite3_mprintf(
    "INSERT OR REPLACE INTO ota_state(rowid, tbl, idx, row, progress)"
    "VALUES(1, %Q, %Q, %lld, NULL)",
    p->tbliter.zTarget, p->idxiter.zIndex, sqlite3_column_int64(pSelect, 0)


  );
  if( zInsert==0 ){
    p->rc = SQLITE_NOMEM;
  }else{
    p->rc = sqlite3_exec(p->dbOta, zInsert, 0, 0, &p->zErrmsg);
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_exec(p->dbOta, "COMMIT", 0, 0, &p->zErrmsg);
    }


  }

  sqlite3_free(zInsert);


}


/*
** 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 
** responsibility of the caller to eventually free the object using
** sqlite3_free().
**
** If an error occurs, leave an error code and message in the ota handle
** and return NULL.
*/
static OtaState *otaLoadState(sqlite3ota *p){
  const char *zSelect = "SELECT tbl, idx, row, progress FROM ota_state";
  OtaState *pRet = 0;
  sqlite3_stmt *pStmt;
  int rc;




  assert( p->rc==SQLITE_OK );
  rc = prepareAndCollectError(p->dbOta, zSelect, &pStmt, &p->zErrmsg);
  if( rc==SQLITE_OK ){
    if( sqlite3_step(pStmt)==SQLITE_ROW ){



      const char *zIdx = (const char*)sqlite3_column_text(pStmt, 1);

      const char *zTbl = (const char*)sqlite3_column_text(pStmt, 0);
      int nIdx = zIdx ? (strlen(zIdx) + 1) : 0;
      int nTbl = strlen(zTbl) + 1;
      int nByte = sizeof(OtaState) + nTbl + nIdx;



      pRet = (OtaState*)sqlite3_malloc(nByte);
      if( pRet ){
        pRet->zTbl = (char*)&pRet[1];
        memcpy(pRet->zTbl, sqlite3_column_text(pStmt, 0), nTbl);

        if( zIdx ){
          pRet->zIdx = &pRet->zTbl[nTbl];
          memcpy(pRet->zIdx, zIdx, nIdx);
        }else{
          pRet->zIdx = 0;
        }
        pRet->iRow = sqlite3_column_int64(pStmt, 2);
      }
    }else{
      pRet = (OtaState*)sqlite3_malloc(sizeof(OtaState));
      if( pRet ){
        memset(pRet, 0, sizeof(*pRet));
      }
    }
    rc = sqlite3_finalize(pStmt);
    if( rc==SQLITE_OK && pRet==0 ) rc = SQLITE_NOMEM;
    if( rc!=SQLITE_OK ){
      sqlite3_free(pRet);
      pRet = 0;
    }
  }

  p->rc = rc;
  return pRet;
}

static void otaLoadTransactionState(sqlite3ota *p, OtaState *pState){
  assert( p->rc==SQLITE_OK );
  if( pState->zTbl ){
    int rc;
    while( rc==SQLITE_OK 
        && p->tbliter.zTarget 
        && sqlite3_stricmp(p->tbliter.zTarget, pState->zTbl) 
        ){
      rc = tblIterNext(&p->tbliter);
    }
    if( rc==SQLITE_OK && !p->tbliter.zTarget ){
      rc = SQLITE_ERROR;
      p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
    }

    if( rc==SQLITE_OK && pState->zIdx ){
      rc = idxIterFirst(p->dbDest, p->tbliter.zTarget, &p->idxiter);
      while( rc==SQLITE_OK 
          && p->idxiter.zIndex 
          && sqlite3_stricmp(p->idxiter.zIndex, pState->zIdx) 
          ){
        rc = idxIterNext(&p->idxiter);
      }
      if( rc==SQLITE_OK && !p->idxiter.zIndex ){
        rc = SQLITE_ERROR;
        p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
      }
    }

    if( rc==SQLITE_OK ){
      rc = otaPrepareAll(p);
    }

    if( rc==SQLITE_OK ){
      sqlite3_stmt *pSelect;
      pSelect = (p->idxiter.zIndex ? p->idxiter.pSelect : p->tbliter.pSelect);
      while( sqlite3_column_int64(pSelect, 0)!=pState->iRow ){
        rc = sqlite3_step(pSelect);
        if( rc!=SQLITE_ROW ) break;
      }
      if( rc==SQLITE_ROW ){
        rc = SQLITE_OK;
      }else{
        rc = SQLITE_ERROR;
        p->zErrmsg = sqlite3_mprintf("ota_state mismatch error");
      }
    }
    p->rc = rc;
  }


}

/*
** Move the "*-oal" file corresponding to the target database to the
** "*-wal" location. If an error occurs, leave an error code and error 
** message in the ota handle.
*/
static void otaMoveOalFile(sqlite3ota *p){
  char *zWal = sqlite3_mprintf("%s-wal", p->zTarget);
  char *zOal = sqlite3_mprintf("%s-oal", p->zTarget);

  assert( p->rc==SQLITE_DONE && p->zErrmsg==0 );
  if( zWal==0 || zOal==0 ){
    p->rc = SQLITE_NOMEM;
  }else{

    rename(zOal, zWal);
  }


  sqlite3_free(zWal);
  sqlite3_free(zOal);
}

/*
** If there is a "*-oal" file in the file-system corresponding to the
** target database in the file-system, delete it. If an error occurs,
** leave an error code and error message in the ota handle.
*/
static void otaDeleteOalFile(sqlite3ota *p){
  char *zOal = sqlite3_mprintf("%s-oal", p->zTarget);
  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
  unlink(zOal);
  sqlite3_free(zOal);
}

/*
** Open and return a new OTA handle. 
*/
sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
  sqlite3ota *p;
  int nTarget = strlen(zTarget);

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

    /* Open the target database */
    memset(p, 0, sizeof(sqlite3ota));
    p->zTarget = (char*)&p[1];
    memcpy(p->zTarget, zTarget, nTarget+1);
    otaOpenDatabase(p, &p->dbDest, zTarget);
    otaOpenDatabase(p, &p->dbOta, zOta);

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

    if( p->rc==SQLITE_OK ){
      pState = otaLoadState(p);
      if( pState && pState->zTbl==0 ){
        otaDeleteOalFile(p);
      }
    }


    if( p->rc==SQLITE_OK ){
      const char *zScript =
        "PRAGMA journal_mode=off;"
        "PRAGMA pager_ota_mode=1;"
        "PRAGMA ota_mode=1;"

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

    if( p->rc==SQLITE_OK ){
      const char *zScript = "BEGIN IMMEDIATE";
................................................................................

    /* Point the table iterator at the first table */
    if( p->rc==SQLITE_OK ){
      p->rc = tblIterFirst(p->dbOta, &p->tbliter);
    }

    if( p->rc==SQLITE_OK ){
      otaLoadTransactionState(p, pState);
    }

    sqlite3_free(pState);
  }

  return p;
}

static void otaCloseHandle(sqlite3 *db){
  int rc = sqlite3_close(db);
................................................................................
      otaSaveTransactionState(p);
    }

    /* Close all open statement handles. */
    tblIterFinalize(&p->tbliter);
    idxIterFinalize(&p->idxiter);

    /* Commit the transaction to the *-oal file. */

    if( p->rc==SQLITE_OK || p->rc==SQLITE_DONE ){
      rc = sqlite3_exec(p->dbDest, "COMMIT", 0, 0, &p->zErrmsg);
      if( rc!=SQLITE_OK ) p->rc = rc;
    }
    otaCloseHandle(p->dbDest);
    otaCloseHandle(p->dbOta);

    if( p->rc==SQLITE_DONE ){
      otaMoveOalFile(p);
    }

    rc = p->rc;
    *pzErrmsg = p->zErrmsg;


    sqlite3_free(p);
  }else{
    rc = SQLITE_NOMEM;
    *pzErrmsg = 0;
  }
  return rc;
}

Changes to src/btree.c.

2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
....
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
  }
#endif
  *ppBtree = p;

btree_open_out:
  if( rc!=SQLITE_OK ){
    if( pBt && pBt->pPager ){
      sqlite3PagerClose(pBt->pPager, 0);
    }
    sqlite3_free(pBt);
    sqlite3_free(p);
    *ppBtree = 0;
  }else{
    /* If the B-Tree was successfully opened, set the pager-cache size to the
    ** default value. Except, when opening on an existing shared pager-cache,
................................................................................
  if( !p->sharable || removeFromSharingList(pBt) ){
    /* The pBt is no longer on the sharing list, so we can access
    ** it without having to hold the mutex.
    **
    ** Clean out and delete the BtShared object.
    */
    assert( !pBt->pCursor );
    sqlite3PagerClose(pBt->pPager, (p->db->flags & SQLITE_OtaMode)!=0);
    if( pBt->xFreeSchema && pBt->pSchema ){
      pBt->xFreeSchema(pBt->pSchema);
    }
    sqlite3DbFree(0, pBt->pSchema);
    freeTempSpace(pBt);
    sqlite3_free(pBt);
  }







|







 







|







2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
....
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
  }
#endif
  *ppBtree = p;

btree_open_out:
  if( rc!=SQLITE_OK ){
    if( pBt && pBt->pPager ){
      sqlite3PagerClose(pBt->pPager);
    }
    sqlite3_free(pBt);
    sqlite3_free(p);
    *ppBtree = 0;
  }else{
    /* If the B-Tree was successfully opened, set the pager-cache size to the
    ** default value. Except, when opening on an existing shared pager-cache,
................................................................................
  if( !p->sharable || removeFromSharingList(pBt) ){
    /* The pBt is no longer on the sharing list, so we can access
    ** it without having to hold the mutex.
    **
    ** Clean out and delete the BtShared object.
    */
    assert( !pBt->pCursor );
    sqlite3PagerClose(pBt->pPager);
    if( pBt->xFreeSchema && pBt->pSchema ){
      pBt->xFreeSchema(pBt->pSchema);
    }
    sqlite3DbFree(0, pBt->pSchema);
    freeTempSpace(pBt);
    sqlite3_free(pBt);
  }

Changes to src/pager.c.

626
627
628
629
630
631
632

633
634
635
636
637
638
639
...
819
820
821
822
823
824
825


826
827
828
829
830
831
832
....
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
....
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
....
5160
5161
5162
5163
5164
5165
5166






5167
5168
5169
5170
5171
5172
5173
....
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140
7141
7142
7143
7144
7145
7146

7147
7148
7149
7150
7151
7152
7153
....
7168
7169
7170
7171
7172
7173
7174























7175
7176
7177
7178
7179
7180
7181
....
7265
7266
7267
7268
7269
7270
7271
7272











7273
  u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */
  u8 walSyncFlags;            /* SYNC_NORMAL or SYNC_FULL for wal writes */
  u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */
  u8 tempFile;                /* zFilename is a temporary or immutable file */
  u8 noLock;                  /* Do not lock (except in WAL mode) */
  u8 readOnly;                /* True for a read-only database */
  u8 memDb;                   /* True to inhibit all file I/O */


  /**************************************************************************
  ** The following block contains those class members that change during
  ** routine opertion.  Class members not in this block are either fixed
  ** when the pager is first created or else only change when there is a
  ** significant mode change (such as changing the page_size, locking_mode,
  ** or the journal_mode).  From another view, these class members describe
................................................................................
#else
# define pagerUseWal(x) 0
# define pagerRollbackWal(x) 0
# define pagerWalFrames(v,w,x,y) 0
# define pagerOpenWalIfPresent(z) SQLITE_OK
# define pagerBeginReadTransaction(z) SQLITE_OK
#endif



#ifndef NDEBUG 
/*
** Usage:
**
**   assert( assert_pager_state(pPager) );
**
................................................................................
  }

  if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
    rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
    if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
  }

  if( !pPager->exclusiveMode 
   && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
  ){
    rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
    pPager->changeCountDone = 0;
  }
  pPager->eState = PAGER_READER;
  pPager->setMaster = 0;
................................................................................
** result in a coredump.
**
** This function always succeeds. If a transaction is active an attempt
** is made to roll it back. If an error occurs during the rollback 
** a hot journal may be left in the filesystem but no error is returned
** to the caller.
*/
int sqlite3PagerClose(Pager *pPager, int bOtaMode){
  u8 *pTmp = (u8 *)pPager->pTmpSpace;

  assert( assert_pager_state(pPager) );
  disable_simulated_io_errors();
  sqlite3BeginBenignMalloc();
  pagerFreeMapHdrs(pPager);
  /* pPager->errCode = 0; */
  pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
  sqlite3WalClose(
      pPager->pWal, pPager->ckptSyncFlags, pPager->pageSize, (bOtaMode?0:pTmp)
  );
  pPager->pWal = 0;
#endif
  pager_reset(pPager);
  if( MEMDB ){
    pager_unlock(pPager);
  }else{
................................................................................
      }
    }

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

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  if( rc==SQLITE_OK ){
    rc = sqlite3WalOpen(pPager->pVfs,
        pPager->fd, pPager->zWal, pPager->exclusiveMode,
        pPager->journalSizeLimit, &pPager->pWal
    );
  }
  pagerFixMaplimit(pPager);

  return rc;
}


/*
** The caller must be holding a SHARED lock on the database file to call
** this function.
**
** If the pager passed as the first argument is open on a real database
** file (not a temp file or an in-memory database), and the WAL file
** is not already open, make an attempt to open it now. If successful,
** return SQLITE_OK. If an error occurs or the VFS used by the pager does 
** not support the xShmXXX() methods, return an error code. *pbOpen is
** not modified in either case.
**
** If the pager is open on a temp-file (or in-memory database), or if
** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK
** without doing anything.
*/
int sqlite3PagerOpenWal(

  Pager *pPager,                  /* Pager object */
  int *pbOpen                     /* OUT: Set to true if call is a no-op */
){
  int rc = SQLITE_OK;             /* Return code */

  assert( assert_pager_state(pPager) );
  assert( pPager->eState==PAGER_OPEN   || pbOpen );
................................................................................
    }
  }else{
    *pbOpen = 1;
  }

  return rc;
}
























/*
** This function is called to close the connection to the log file prior
** to switching from WAL to rollback mode.
**
** Before closing the log file, this function attempts to take an 
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
................................................................................
** is empty, return 0.
*/
int sqlite3PagerWalFramesize(Pager *pPager){
  assert( pPager->eState==PAGER_READER );
  return sqlite3WalFramesize(pPager->pWal);
}
#endif












#endif /* SQLITE_OMIT_DISKIO */







>







 







>
>







 







|







 







|









|
|







 







>
>
>
>
>
>







 







|








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







 







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







 








>
>
>
>
>
>
>
>
>
>
>

626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
...
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
....
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
....
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
....
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
....
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138

















7139
7140
7141
7142
7143
7144
7145
7146
....
7161
7162
7163
7164
7165
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
....
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
  u8 ckptSyncFlags;           /* SYNC_NORMAL or SYNC_FULL for checkpoint */
  u8 walSyncFlags;            /* SYNC_NORMAL or SYNC_FULL for wal writes */
  u8 syncFlags;               /* SYNC_NORMAL or SYNC_FULL otherwise */
  u8 tempFile;                /* zFilename is a temporary or immutable file */
  u8 noLock;                  /* Do not lock (except in WAL mode) */
  u8 readOnly;                /* True for a read-only database */
  u8 memDb;                   /* True to inhibit all file I/O */
  u8 otaMode;                 /* True if in ota_mode */

  /**************************************************************************
  ** The following block contains those class members that change during
  ** routine opertion.  Class members not in this block are either fixed
  ** when the pager is first created or else only change when there is a
  ** significant mode change (such as changing the page_size, locking_mode,
  ** or the journal_mode).  From another view, these class members describe
................................................................................
#else
# define pagerUseWal(x) 0
# define pagerRollbackWal(x) 0
# define pagerWalFrames(v,w,x,y) 0
# define pagerOpenWalIfPresent(z) SQLITE_OK
# define pagerBeginReadTransaction(z) SQLITE_OK
#endif

static int pagerOpenWalInternal(Pager*, int*);

#ifndef NDEBUG 
/*
** Usage:
**
**   assert( assert_pager_state(pPager) );
**
................................................................................
  }

  if( rc==SQLITE_OK && bCommit && isOpen(pPager->fd) ){
    rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_COMMIT_PHASETWO, 0);
    if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
  }

  if( !pPager->exclusiveMode && !pPager->otaMode
   && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
  ){
    rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
    pPager->changeCountDone = 0;
  }
  pPager->eState = PAGER_READER;
  pPager->setMaster = 0;
................................................................................
** result in a coredump.
**
** This function always succeeds. If a transaction is active an attempt
** is made to roll it back. If an error occurs during the rollback 
** a hot journal may be left in the filesystem but no error is returned
** to the caller.
*/
int sqlite3PagerClose(Pager *pPager){
  u8 *pTmp = (u8 *)pPager->pTmpSpace;

  assert( assert_pager_state(pPager) );
  disable_simulated_io_errors();
  sqlite3BeginBenignMalloc();
  pagerFreeMapHdrs(pPager);
  /* pPager->errCode = 0; */
  pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL
  sqlite3WalClose(pPager->pWal, 
      pPager->ckptSyncFlags, pPager->pageSize, (pPager->otaMode?0:pTmp)
  );
  pPager->pWal = 0;
#endif
  pager_reset(pPager);
  if( MEMDB ){
    pager_unlock(pPager);
  }else{
................................................................................
      }
    }

    /* 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);
    if( rc==SQLITE_OK && pPager->otaMode ){
      int nWal = sqlite3Strlen30(pPager->zWal);
      pPager->zWal[nWal-3] = 'o';
      rc = pagerOpenWalInternal(pPager, 0);
    }

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

  if( pagerUseWal(pPager) ){
    assert( rc==SQLITE_OK );
................................................................................
  }

  /* Open the connection to the log file. If this operation fails, 
  ** (e.g. due to malloc() failure), return an error code.
  */
  if( rc==SQLITE_OK ){
    rc = sqlite3WalOpen(pPager->pVfs,
        pPager->fd, pPager->zWal, pPager->exclusiveMode || pPager->otaMode,
        pPager->journalSizeLimit, &pPager->pWal
    );
  }
  pagerFixMaplimit(pPager);

  return rc;
}


















static int pagerOpenWalInternal(
  Pager *pPager,                  /* Pager object */
  int *pbOpen                     /* OUT: Set to true if call is a no-op */
){
  int rc = SQLITE_OK;             /* Return code */

  assert( assert_pager_state(pPager) );
  assert( pPager->eState==PAGER_OPEN   || pbOpen );
................................................................................
    }
  }else{
    *pbOpen = 1;
  }

  return rc;
}

/*
** The caller must be holding a SHARED lock on the database file to call
** this function.
**
** If the pager passed as the first argument is open on a real database
** file (not a temp file or an in-memory database), and the WAL file
** is not already open, make an attempt to open it now. If successful,
** return SQLITE_OK. If an error occurs or the VFS used by the pager does 
** not support the xShmXXX() methods, return an error code. *pbOpen is
** not modified in either case.
**
** If the pager is open on a temp-file (or in-memory database), or if
** the WAL file is already open, set *pbOpen to 1 and return SQLITE_OK
** without doing anything.
*/
int sqlite3PagerOpenWal(
  Pager *pPager,                  /* Pager object */
  int *pbOpen                     /* OUT: Set to true if call is a no-op */
){
  if( pPager->otaMode ) return SQLITE_CANTOPEN;
  return pagerOpenWalInternal(pPager, pbOpen);
}

/*
** This function is called to close the connection to the log file prior
** to switching from WAL to rollback mode.
**
** Before closing the log file, this function attempts to take an 
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
................................................................................
** is empty, return 0.
*/
int sqlite3PagerWalFramesize(Pager *pPager){
  assert( pPager->eState==PAGER_READER );
  return sqlite3WalFramesize(pPager->pWal);
}
#endif

/*
** Set or clear the "OTA mode" flag.
*/
int sqlite3PagerSetOtaMode(Pager *pPager, int bOta){
  if( pPager->pWal || pPager->eState!=PAGER_OPEN ){
    return SQLITE_ERROR;
  }
  pPager->otaMode = (u8)bOta;
  return SQLITE_OK;
}

#endif /* SQLITE_OMIT_DISKIO */

Changes to src/pager.h.

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
205
206
207
208
209
210
211
212


213
  Pager **ppPager,
  const char*,
  int,
  int,
  int,
  void(*)(DbPage*)
);
int sqlite3PagerClose(Pager *pPager, int);
int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);

/* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u32*, int);
int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int);
................................................................................
#else
# define disable_simulated_io_errors()
# define enable_simulated_io_errors()
#endif

int sqlite3PagerSaveState(Pager *pPager, void **ppState, int *pnState);
int sqlite3PagerRestoreState(Pager *pPager, const void *pState, int nState);



#endif /* _PAGER_H_ */







|







 








>
>

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
205
206
207
208
209
210
211
212
213
214
215
  Pager **ppPager,
  const char*,
  int,
  int,
  int,
  void(*)(DbPage*)
);
int sqlite3PagerClose(Pager *pPager);
int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);

/* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u32*, int);
int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int);
................................................................................
#else
# define disable_simulated_io_errors()
# define enable_simulated_io_errors()
#endif

int sqlite3PagerSaveState(Pager *pPager, void **ppState, int *pnState);
int sqlite3PagerRestoreState(Pager *pPager, const void *pState, int nState);

int sqlite3PagerSetOtaMode(Pager *pPager, int bOta);

#endif /* _PAGER_H_ */

Changes to src/pragma.c.

49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
...
319
320
321
322
323
324
325




326
327
328
329
330
331
332
...
472
473
474
475
476
477
478
479

480
481
482
483
484
485
486
...
865
866
867
868
869
870
871













872
873
874
875
876
877
878
#define PragTyp_JOURNAL_MODE                  18
#define PragTyp_JOURNAL_SIZE_LIMIT            19
#define PragTyp_LOCK_PROXY_FILE               20
#define PragTyp_LOCKING_MODE                  21
#define PragTyp_PAGE_COUNT                    22
#define PragTyp_MMAP_SIZE                     23
#define PragTyp_PAGE_SIZE                     24

#define PragTyp_SECURE_DELETE                 25
#define PragTyp_SHRINK_MEMORY                 26
#define PragTyp_SOFT_HEAP_LIMIT               27
#define PragTyp_STATS                         28
#define PragTyp_SYNCHRONOUS                   29
#define PragTyp_TABLE_INFO                    30
#define PragTyp_TEMP_STORE                    31
#define PragTyp_TEMP_STORE_DIRECTORY          32
#define PragTyp_THREADS                       33
#define PragTyp_WAL_AUTOCHECKPOINT            34
#define PragTyp_WAL_CHECKPOINT                35
#define PragTyp_ACTIVATE_EXTENSIONS           36
#define PragTyp_HEXKEY                        37
#define PragTyp_KEY                           38
#define PragTyp_REKEY                         39
#define PragTyp_LOCK_STATUS                   40
#define PragTyp_PARSER_TRACE                  41
#define PragFlag_NeedSchema           0x01
static const struct sPragmaNames {
  const char *const zName;  /* Name of pragma */
  u8 ePragTyp;              /* PragTyp_XXX value */
  u8 mPragFlag;             /* Zero or more PragFlag_XXX values */
  u32 iArg;                 /* Extra argument */
} aPragmaNames[] = {
................................................................................
    /* ePragFlag: */ PragFlag_NeedSchema,
    /* iArg:      */ 0 },
  { /* zName:     */ "page_size",
    /* ePragTyp:  */ PragTyp_PAGE_SIZE,
    /* ePragFlag: */ 0,
    /* iArg:      */ 0 },
#endif




#if defined(SQLITE_DEBUG)
  { /* zName:     */ "parser_trace",
    /* ePragTyp:  */ PragTyp_PARSER_TRACE,
    /* ePragFlag: */ 0,
    /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
................................................................................
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
  { /* zName:     */ "writable_schema",
    /* ePragTyp:  */ PragTyp_FLAG,
    /* ePragFlag: */ 0,
    /* iArg:      */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif
};
/* Number of pragmas: 57 on by default, 70 total. */

/* End of the automatically generated pragma table.
***************************************************************************/

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
** unrecognized string argument.  The FULL option is disallowed
................................................................................
      assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
      pDb->pSchema->cache_size = size;
      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    }
    break;
  }
#endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */














#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
  /*
  **  PRAGMA [database.]page_size
  **  PRAGMA [database.]page_size=N
  **
  ** The first form reports the current setting for the







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







 







>
>
>
>







 







|
>







 







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







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
#define PragTyp_JOURNAL_MODE                  18
#define PragTyp_JOURNAL_SIZE_LIMIT            19
#define PragTyp_LOCK_PROXY_FILE               20
#define PragTyp_LOCKING_MODE                  21
#define PragTyp_PAGE_COUNT                    22
#define PragTyp_MMAP_SIZE                     23
#define PragTyp_PAGE_SIZE                     24
#define PragTyp_PAGER_OTA_MODE                25
#define PragTyp_SECURE_DELETE                 26
#define PragTyp_SHRINK_MEMORY                 27
#define PragTyp_SOFT_HEAP_LIMIT               28
#define PragTyp_STATS                         29
#define PragTyp_SYNCHRONOUS                   30
#define PragTyp_TABLE_INFO                    31
#define PragTyp_TEMP_STORE                    32
#define PragTyp_TEMP_STORE_DIRECTORY          33
#define PragTyp_THREADS                       34
#define PragTyp_WAL_AUTOCHECKPOINT            35
#define PragTyp_WAL_CHECKPOINT                36
#define PragTyp_ACTIVATE_EXTENSIONS           37
#define PragTyp_HEXKEY                        38
#define PragTyp_KEY                           39
#define PragTyp_REKEY                         40
#define PragTyp_LOCK_STATUS                   41
#define PragTyp_PARSER_TRACE                  42
#define PragFlag_NeedSchema           0x01
static const struct sPragmaNames {
  const char *const zName;  /* Name of pragma */
  u8 ePragTyp;              /* PragTyp_XXX value */
  u8 mPragFlag;             /* Zero or more PragFlag_XXX values */
  u32 iArg;                 /* Extra argument */
} aPragmaNames[] = {
................................................................................
    /* ePragFlag: */ PragFlag_NeedSchema,
    /* iArg:      */ 0 },
  { /* zName:     */ "page_size",
    /* ePragTyp:  */ PragTyp_PAGE_SIZE,
    /* ePragFlag: */ 0,
    /* iArg:      */ 0 },
#endif
  { /* zName:     */ "pager_ota_mode",
    /* ePragTyp:  */ PragTyp_PAGER_OTA_MODE,
    /* ePragFlag: */ 0,
    /* iArg:      */ 0 },
#if defined(SQLITE_DEBUG)
  { /* zName:     */ "parser_trace",
    /* ePragTyp:  */ PragTyp_PARSER_TRACE,
    /* ePragFlag: */ 0,
    /* iArg:      */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
................................................................................
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
  { /* zName:     */ "writable_schema",
    /* ePragTyp:  */ PragTyp_FLAG,
    /* ePragFlag: */ 0,
    /* iArg:      */ SQLITE_WriteSchema|SQLITE_RecoveryMode },
#endif
};
/* Number of pragmas: 59 on by default, 72 total. */
/* Number of pragmas: 58 on by default, 71 total. */
/* End of the automatically generated pragma table.
***************************************************************************/

/*
** Interpret the given string as a safety level.  Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL.  Return 1 for an empty or 
** unrecognized string argument.  The FULL option is disallowed
................................................................................
      assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
      pDb->pSchema->cache_size = size;
      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    }
    break;
  }
#endif /* !SQLITE_OMIT_PAGER_PRAGMAS && !SQLITE_OMIT_DEPRECATED */

  /*
  **  PRAGMA [database.]pager_ota_mode=[01]
  */
  case PragTyp_PAGER_OTA_MODE: {
    Btree *pBt = pDb->pBt;
    assert( pBt!=0 );
    if( zRight ){
      int iArg = !!sqlite3Atoi(zRight);
      rc = sqlite3PagerSetOtaMode(sqlite3BtreePager(pBt), iArg);
    }
    break;
  }

#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
  /*
  **  PRAGMA [database.]page_size
  **  PRAGMA [database.]page_size=N
  **
  ** The first form reports the current setting for the

Changes to src/test2.c.

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








|







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

Changes to tool/mkpragmatab.tcl.

292
293
294
295
296
297
298






299
300
301
302
303
304
305

  NAME: activate_extensions
  IF:   defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)

  NAME: soft_heap_limit

  NAME: threads






}
fconfigure stdout -translation lf
set name {}
set type {}
set if {}
set flags {}
set arg 0







>
>
>
>
>
>







292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311

  NAME: activate_extensions
  IF:   defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)

  NAME: soft_heap_limit

  NAME: threads

  NAME: pager_ota_mode

  NAME: ota_mode
  TYPE: FLAG
  ARG:  SQLITE_OtaMode
}
fconfigure stdout -translation lf
set name {}
set type {}
set if {}
set flags {}
set arg 0