/ Check-in [95cc3f6f]
Login

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

Overview
Comment:Refactor and simplify the logic used to change journalmode.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 95cc3f6fdec5494560c3cd4439d06870d1c62506
User & Date: drh 2010-06-11 17:01:25
Context
2010-06-14
17:09
Merge the experimental shared-memory mmap-by-chunk changes into the trunk. check-in: f295e7ed user: drh tags: trunk
2010-06-11
19:04
Experimental change to the xShmXXX parts of the VFS interface. check-in: ca68472d user: dan tags: experimental
17:01
Refactor and simplify the logic used to change journalmode. check-in: 95cc3f6f user: drh tags: trunk
2010-06-10
16:25
Adding original art for the new SQLite logo. check-in: af353bd8 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/backup.c.

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
      bCloseTrans = 1;
    }

    /* Do not allow backup if the destination database is in WAL mode
    ** and the page sizes are different between source and destination */
    pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
    pgszDest = sqlite3BtreeGetPageSize(p->pDest);
    destMode = sqlite3PagerJournalMode(sqlite3BtreePager(p->pDest),
                                         PAGER_JOURNALMODE_QUERY);
    if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
      rc = SQLITE_READONLY;
    }
  
    /* Now that there is a read-lock on the source database, query the
    ** source pager for the number of pages in the database.
    */







|
<







331
332
333
334
335
336
337
338

339
340
341
342
343
344
345
      bCloseTrans = 1;
    }

    /* Do not allow backup if the destination database is in WAL mode
    ** and the page sizes are different between source and destination */
    pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
    pgszDest = sqlite3BtreeGetPageSize(p->pDest);
    destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));

    if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
      rc = SQLITE_READONLY;
    }
  
    /* Now that there is a read-lock on the source database, query the
    ** source pager for the number of pages in the database.
    */

Changes to src/build.c.

3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
    }
    db->aDb[1].pBt = pBt;
    assert( db->aDb[1].pSchema );
    if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
      db->mallocFailed = 1;
      return 1;
    }
    sqlite3PagerJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode);
  }
  return 0;
}

/*
** Generate VDBE code that will verify the schema cookie and start
** a read-transaction for all named database files.







|







3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
    }
    db->aDb[1].pBt = pBt;
    assert( db->aDb[1].pSchema );
    if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
      db->mallocFailed = 1;
      return 1;
    }
    sqlite3PagerSetJournalMode(sqlite3BtreePager(pBt), db->dfltJournalMode);
  }
  return 0;
}

/*
** Generate VDBE code that will verify the schema cookie and start
** a read-transaction for all named database files.

Changes to src/pager.c.

5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840


5841
5842
5843
5844
5845
5846
5847
5848


5849
5850
5851
5852












5853
5854
5855
5856
5857
5858





5859
5860
5861








5862
5863
5864
5865
5866
5867

5868
5869
5870
5871


5872
5873





5874
5875











5876
5877
5878
5879
5880
5881
5882
  if( eMode>=0 && !pPager->tempFile ){
    pPager->exclusiveMode = (u8)eMode;
  }
  return (int)pPager->exclusiveMode;
}

/*
** Get/set the journal-mode for this pager. Parameter eMode must be one of:
**
**    PAGER_JOURNALMODE_QUERY
**    PAGER_JOURNALMODE_DELETE
**    PAGER_JOURNALMODE_TRUNCATE
**    PAGER_JOURNALMODE_PERSIST
**    PAGER_JOURNALMODE_OFF
**    PAGER_JOURNALMODE_MEMORY
**    PAGER_JOURNALMODE_WAL
**
** If the parameter is not _QUERY, then the journal_mode is set to the
** value specified if the change is allowed. The change may be disallowed
** for the following reasons:
**
**   *  An in-memory database can only have its journal_mode set to _OFF
**      or _MEMORY.
**
**   *  The journal mode may not be changed while a transaction is active.
**
** The returned indicate the current (possibly updated) journal-mode.
*/
int sqlite3PagerJournalMode(Pager *pPager, int eMode){
  assert( eMode==PAGER_JOURNALMODE_QUERY


            || eMode==PAGER_JOURNALMODE_DELETE
            || eMode==PAGER_JOURNALMODE_TRUNCATE
            || eMode==PAGER_JOURNALMODE_PERSIST
            || eMode==PAGER_JOURNALMODE_OFF 
            || eMode==PAGER_JOURNALMODE_WAL 
            || eMode==PAGER_JOURNALMODE_MEMORY );
  assert( PAGER_JOURNALMODE_QUERY<0 );



  if( eMode==PAGER_JOURNALMODE_WAL 
   && pPager->journalMode==PAGER_JOURNALMODE_DELETE
  ){
    pPager->journalMode = PAGER_JOURNALMODE_WAL;












  }else if( eMode>=0
   && (pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL)
   && (!MEMDB || eMode==PAGER_JOURNALMODE_MEMORY||eMode==PAGER_JOURNALMODE_OFF)
   && !pPager->dbModified
   && (!isOpen(pPager->jfd) || 0==pPager->journalOff)
  ){





    if( isOpen(pPager->jfd) ){
      sqlite3OsClose(pPager->jfd);
    }








    assert( (PAGER_JOURNALMODE_TRUNCATE & 1)==1 );
    assert( (PAGER_JOURNALMODE_PERSIST & 1)==1 );
    assert( (PAGER_JOURNALMODE_DELETE & 1)==0 );
    assert( (PAGER_JOURNALMODE_MEMORY & 1)==0 );
    assert( (PAGER_JOURNALMODE_OFF & 1)==0 );
    if( (pPager->journalMode & 1)==1 && (eMode & 1)==0

         && !pPager->exclusiveMode ){
      sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
    }



    pPager->journalMode = (u8)eMode;
  }





  return (int)pPager->journalMode;
}












/*
** Get/set the size-limit used for persistent journal files.
**
** Setting the size limit to -1 means no limit is enforced.
** An attempt to set a limit smaller than -1 is a no-op.
*/







|

<







<
|
|




|



|
|
>
>
|





<

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


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


|
>
>
|
|
>
>
>
>
>


>
>
>
>
>
>
>
>
>
>
>







5811
5812
5813
5814
5815
5816
5817
5818
5819

5820
5821
5822
5823
5824
5825
5826

5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846

5847
5848
5849
5850
5851

5852
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
5864
5865





5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886

5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
  if( eMode>=0 && !pPager->tempFile ){
    pPager->exclusiveMode = (u8)eMode;
  }
  return (int)pPager->exclusiveMode;
}

/*
** Set the journal-mode for this pager. Parameter eMode must be one of:
**

**    PAGER_JOURNALMODE_DELETE
**    PAGER_JOURNALMODE_TRUNCATE
**    PAGER_JOURNALMODE_PERSIST
**    PAGER_JOURNALMODE_OFF
**    PAGER_JOURNALMODE_MEMORY
**    PAGER_JOURNALMODE_WAL
**

** The journalmode is set to the value specified if the change is allowed.
** The change may be disallowed for the following reasons:
**
**   *  An in-memory database can only have its journal_mode set to _OFF
**      or _MEMORY.
**
**   *  Temporary databases cannot have _WAL journalmode.
**
** The returned indicate the current (possibly updated) journal-mode.
*/
int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
  u8 eOld = pPager->journalMode;    /* Prior journalmode */

  /* The eMode parameter is always valid */
  assert(      eMode==PAGER_JOURNALMODE_DELETE
            || eMode==PAGER_JOURNALMODE_TRUNCATE
            || eMode==PAGER_JOURNALMODE_PERSIST
            || eMode==PAGER_JOURNALMODE_OFF 
            || eMode==PAGER_JOURNALMODE_WAL 
            || eMode==PAGER_JOURNALMODE_MEMORY );


  /* Do not allow the journalmode of a TEMP database to be changed to WAL
  */
  if( pPager->tempFile && eMode==PAGER_JOURNALMODE_WAL ){
    assert( eOld!=PAGER_JOURNALMODE_WAL );

    eMode = eOld;
  }

  /* Do allow the journalmode of an in-memory database to be set to
  ** anything other than MEMORY or OFF
  */
  if( MEMDB ){
    assert( eOld==PAGER_JOURNALMODE_MEMORY || eOld==PAGER_JOURNALMODE_OFF );
    if( eMode!=PAGER_JOURNALMODE_MEMORY && eMode!=PAGER_JOURNALMODE_OFF ){
      eMode = eOld;
    }
  }

  if( eMode!=eOld ){





    /* When changing between rollback modes, close the journal file prior
    ** to the change.  But when changing from a rollback mode to WAL, keep
    ** the journal open since there is a rollback-style transaction in play
    ** used to convert the version numbers in the btree header.
    */
    if( isOpen(pPager->jfd) && eMode!=PAGER_JOURNALMODE_WAL ){
      sqlite3OsClose(pPager->jfd);
    }

    /* Change the journal mode. */
    pPager->journalMode = (u8)eMode;

    /* When transistioning from TRUNCATE or PERSIST to any other journal
    ** mode (and we are not in locking_mode=EXCLUSIVE) then delete the
    ** journal file.
    */
    assert( (PAGER_JOURNALMODE_TRUNCATE & 5)==1 );
    assert( (PAGER_JOURNALMODE_PERSIST & 5)==1 );
    assert( (PAGER_JOURNALMODE_DELETE & 5)!=1 );
    assert( (PAGER_JOURNALMODE_MEMORY & 5)!=1 );
    assert( (PAGER_JOURNALMODE_OFF & 5)!=1 );

    assert( (PAGER_JOURNALMODE_WAL & 5)!=1 );
    if( (eOld & 5)==1 && (eMode & 5)!=1 && !pPager->exclusiveMode ){
      sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
    }
  }

  /* Return the new journal mode */
  return (int)pPager->journalMode;
}

/*
** Return the current journal mode.
*/
int sqlite3PagerGetJournalMode(Pager *pPager){
  return (int)pPager->journalMode;
}

/*
** Return TRUE if the pager is in a state where it is OK to change the
** journalmode.  Journalmode changes can only happen when the database
** is unmodified.
*/
int sqlite3PagerOkToChangeJournalMode(Pager *pPager){
  if( pPager->dbModified ) return 0;
  if( isOpen(pPager->jfd) && pPager->journalOff>0 ) return 0;
  return 1;
}

/*
** Get/set the size-limit used for persistent journal files.
**
** Setting the size limit to -1 means no limit is enforced.
** An attempt to set a limit smaller than -1 is a no-op.
*/

Changes to src/pager.h.

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
...
100
101
102
103
104
105
106
107


108
109
110
111
112
113
114
** Valid values for the second argument to sqlite3PagerLockingMode().
*/
#define PAGER_LOCKINGMODE_QUERY      -1
#define PAGER_LOCKINGMODE_NORMAL      0
#define PAGER_LOCKINGMODE_EXCLUSIVE   1

/*
** Valid values for the second argument to sqlite3PagerJournalMode().
*/
#define PAGER_JOURNALMODE_QUERY      -1
#define PAGER_JOURNALMODE_DELETE      0   /* Commit by deleting journal file */
#define PAGER_JOURNALMODE_PERSIST     1   /* Commit by zeroing journal header */
#define PAGER_JOURNALMODE_OFF         2   /* Journal omitted.  */
#define PAGER_JOURNALMODE_TRUNCATE    3   /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY      4   /* In-memory journal file */
#define PAGER_JOURNALMODE_WAL         5   /* Use write-ahead logging */

................................................................................
/* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u16*, int);
int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int);
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
int sqlite3PagerLockingMode(Pager *, int);
int sqlite3PagerJournalMode(Pager *, int);


i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
sqlite3_backup **sqlite3PagerBackupPtr(Pager*);

/* Functions used to obtain and release page references. */ 
int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);







|

|







 







|
>
>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
** Valid values for the second argument to sqlite3PagerLockingMode().
*/
#define PAGER_LOCKINGMODE_QUERY      -1
#define PAGER_LOCKINGMODE_NORMAL      0
#define PAGER_LOCKINGMODE_EXCLUSIVE   1

/*
** Numeric constants that encode the journalmode.  
*/
#define PAGER_JOURNALMODE_QUERY     (-1)  /* Query the value of journalmode */
#define PAGER_JOURNALMODE_DELETE      0   /* Commit by deleting journal file */
#define PAGER_JOURNALMODE_PERSIST     1   /* Commit by zeroing journal header */
#define PAGER_JOURNALMODE_OFF         2   /* Journal omitted.  */
#define PAGER_JOURNALMODE_TRUNCATE    3   /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY      4   /* In-memory journal file */
#define PAGER_JOURNALMODE_WAL         5   /* Use write-ahead logging */

................................................................................
/* Functions used to configure a Pager object. */
void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u16*, int);
int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int);
void sqlite3PagerSetSafetyLevel(Pager*,int,int);
int sqlite3PagerLockingMode(Pager *, int);
int sqlite3PagerSetJournalMode(Pager *, int);
int sqlite3PagerGetJournalMode(Pager*);
int sqlite3PagerOkToChangeJournalMode(Pager*);
i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
sqlite3_backup **sqlite3PagerBackupPtr(Pager*);

/* Functions used to obtain and release page references. */ 
int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);

Changes to src/vacuum.c.

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    char *zKey;
    sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
    if( nKey ) db->nextPagesize = 0;
  }
#endif

  /* Do not attempt to change the page size for a WAL database */
  if( sqlite3PagerJournalMode(sqlite3BtreePager(pMain),
                              PAGER_JOURNALMODE_QUERY)==PAGER_JOURNALMODE_WAL ){
    db->nextPagesize = 0;
  }

  if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
   || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
   || NEVER(db->mallocFailed)
  ){







|
|







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    char *zKey;
    sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
    if( nKey ) db->nextPagesize = 0;
  }
#endif

  /* Do not attempt to change the page size for a WAL database */
  if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
                                               ==PAGER_JOURNALMODE_WAL ){
    db->nextPagesize = 0;
  }

  if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
   || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
   || NEVER(db->mallocFailed)
  ){

Changes to src/vdbe.c.

5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
....
5207
5208
5209
5210
5211
5212
5213



5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270

5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
** without signaling the error.
*/
case OP_JournalMode: {    /* out2-prerelease */
  Btree *pBt;                     /* Btree to change journal mode of */
  Pager *pPager;                  /* Pager associated with pBt */
  int eNew;                       /* New journal mode */
  int eOld;                       /* The old journal mode */
  const sqlite3_vfs *pVfs;        /* The VFS of pPager */
  const char *zFilename;          /* Name of database file for pPager */

  eNew = pOp->p3;
  assert( eNew==PAGER_JOURNALMODE_DELETE 
       || eNew==PAGER_JOURNALMODE_TRUNCATE 
       || eNew==PAGER_JOURNALMODE_PERSIST 
       || eNew==PAGER_JOURNALMODE_OFF
................................................................................
    ** database. */
    sqlite3VdbeUsesBtree(p, pOp->p1);
    sqlite3VdbeMutexArrayEnter(p);
  }

  pBt = db->aDb[pOp->p1].pBt;
  pPager = sqlite3BtreePager(pBt);




#ifndef SQLITE_OMIT_WAL
  zFilename = sqlite3PagerFilename(pPager);
  pVfs = sqlite3PagerVfs(pPager);

  /* Do not allow a transition to journal_mode=WAL for a database
  ** in temporary storage or if the VFS does not support xShmOpen.
  */
  if( eNew==PAGER_JOURNALMODE_WAL
   && (zFilename[0]==0                         /* Temp file */
       || !sqlite3PagerWalSupported(pPager))   /* No xShmOpen support */
  ){
    eNew = PAGER_JOURNALMODE_QUERY;
  }

  if( eNew!=PAGER_JOURNALMODE_QUERY ){
    eOld = sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_QUERY);
    if( (eNew!=eOld)
     && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL)
    ){
      if( !db->autoCommit || db->activeVdbeCnt>1 ){
        rc = SQLITE_ERROR;
        sqlite3SetString(&p->zErrMsg, db, 
            "cannot change %s wal mode from within a transaction",
            (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
        );
        break;
      }else{
  
        if( eOld==PAGER_JOURNALMODE_WAL ){
          /* If leaving WAL mode, close the log file. If successful, the call
          ** to PagerCloseWal() checkpoints and deletes the write-ahead-log 
          ** file. An EXCLUSIVE lock may still be held on the database file 
          ** after a successful return. 
          */
          rc = sqlite3PagerCloseWal(pPager);
          if( rc==SQLITE_OK ){
            sqlite3PagerJournalMode(pPager, eNew);
          }else if( rc==SQLITE_BUSY && pOp->p5==0 ){
            goto abort_due_to_error;
          }
        }else{
          sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
          rc = SQLITE_OK;
        }
  
        /* Open a transaction on the database file. Regardless of the journal
        ** mode, this transaction always uses a rollback journal.
        */
        assert( sqlite3BtreeIsInTrans(pBt)==0 );
        if( rc==SQLITE_OK ){
          rc = sqlite3BtreeSetVersion(pBt, 
                                      (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
          if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error;
        }
        if( rc==SQLITE_BUSY ){
          eNew = PAGER_JOURNALMODE_QUERY;

          rc = SQLITE_OK;
        }
      }
    }
  }
#endif /* ifndef SQLITE_OMIT_WAL */

  eNew = sqlite3PagerJournalMode(pPager, eNew);
  pOut = &aMem[pOp->p2];
  pOut->flags = MEM_Str|MEM_Static|MEM_Term;
  pOut->z = (char *)sqlite3JournalModename(eNew);
  pOut->n = sqlite3Strlen30(pOut->z);
  pOut->enc = SQLITE_UTF8;
  sqlite3VdbeChangeEncoding(pOut, encoding);
  break;







<







 







>
>
>



<








|


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

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





|







5172
5173
5174
5175
5176
5177
5178

5179
5180
5181
5182
5183
5184
5185
....
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218

5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229


5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268

5269
5270

5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
** without signaling the error.
*/
case OP_JournalMode: {    /* out2-prerelease */
  Btree *pBt;                     /* Btree to change journal mode of */
  Pager *pPager;                  /* Pager associated with pBt */
  int eNew;                       /* New journal mode */
  int eOld;                       /* The old journal mode */

  const char *zFilename;          /* Name of database file for pPager */

  eNew = pOp->p3;
  assert( eNew==PAGER_JOURNALMODE_DELETE 
       || eNew==PAGER_JOURNALMODE_TRUNCATE 
       || eNew==PAGER_JOURNALMODE_PERSIST 
       || eNew==PAGER_JOURNALMODE_OFF
................................................................................
    ** database. */
    sqlite3VdbeUsesBtree(p, pOp->p1);
    sqlite3VdbeMutexArrayEnter(p);
  }

  pBt = db->aDb[pOp->p1].pBt;
  pPager = sqlite3BtreePager(pBt);
  eOld = sqlite3PagerGetJournalMode(pPager);
  if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld;
  if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld;

#ifndef SQLITE_OMIT_WAL
  zFilename = sqlite3PagerFilename(pPager);


  /* Do not allow a transition to journal_mode=WAL for a database
  ** in temporary storage or if the VFS does not support xShmOpen.
  */
  if( eNew==PAGER_JOURNALMODE_WAL
   && (zFilename[0]==0                         /* Temp file */
       || !sqlite3PagerWalSupported(pPager))   /* No xShmOpen support */
  ){
    eNew = eOld;
  }



  if( (eNew!=eOld)
   && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL)
  ){
    if( !db->autoCommit || db->activeVdbeCnt>1 ){
      rc = SQLITE_ERROR;
      sqlite3SetString(&p->zErrMsg, db, 
          "cannot change %s wal mode from within a transaction",
          (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
      );
      break;
    }else{
 
      if( eOld==PAGER_JOURNALMODE_WAL ){
        /* If leaving WAL mode, close the log file. If successful, the call
        ** to PagerCloseWal() checkpoints and deletes the write-ahead-log 
        ** file. An EXCLUSIVE lock may still be held on the database file 
        ** after a successful return. 
        */
        rc = sqlite3PagerCloseWal(pPager);
        if( rc==SQLITE_OK ){
          sqlite3PagerSetJournalMode(pPager, eNew);
        }else if( rc==SQLITE_BUSY && pOp->p5==0 ){
          goto abort_due_to_error;
        }
      }else{
        sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
        rc = SQLITE_OK;
      }
  
      /* Open a transaction on the database file. Regardless of the journal
      ** mode, this transaction always uses a rollback journal.
      */
      assert( sqlite3BtreeIsInTrans(pBt)==0 );
      if( rc==SQLITE_OK ){
        rc = sqlite3BtreeSetVersion(pBt, 
                                    (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
        if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error;
      }
      if( rc==SQLITE_BUSY ){

        eNew = eOld;
        rc = SQLITE_OK;

      }
    }
  }
#endif /* ifndef SQLITE_OMIT_WAL */

  eNew = sqlite3PagerSetJournalMode(pPager, eNew);
  pOut = &aMem[pOp->p2];
  pOut->flags = MEM_Str|MEM_Static|MEM_Term;
  pOut->z = (char *)sqlite3JournalModename(eNew);
  pOut->n = sqlite3Strlen30(pOut->z);
  pOut->enc = SQLITE_UTF8;
  sqlite3VdbeChangeEncoding(pOut, encoding);
  break;