/ Check-in [2c145ee6]
Login

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

Overview
Comment:Do not invoke codec macros when reading or writing an in-memory sub-journal.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | codecless-inmemory-subjournal
Files: files | file ages | folders
SHA3-256:2c145ee6c9e7916f022331453384cbe61ee3654c08a1b88467f85235b5bc18c4
User & Date: dan 2017-05-08 18:29:36
Context
2017-05-10
12:49
Do not invoke codec macros for in-memory subjournals. Closed-Leaf check-in: d2bb0066 user: drh tags: codecless-inmemory-subjournal
2017-05-08
18:29
Do not invoke codec macros when reading or writing an in-memory sub-journal. check-in: 2c145ee6 user: dan tags: codecless-inmemory-subjournal
2017-05-06
18:09
Fix an obscure assertion fault that can follow an OOM. The problem was introduced by check-in [a1cf44763277b6c7]. check-in: 04e7e565 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  2254   2254     int rc;
  2255   2255     PgHdr *pPg;                   /* An existing page in the cache */
  2256   2256     Pgno pgno;                    /* The page number of a page in journal */
  2257   2257     u32 cksum;                    /* Checksum used for sanity checking */
  2258   2258     char *aData;                  /* Temporary storage for the page */
  2259   2259     sqlite3_file *jfd;            /* The file descriptor for the journal file */
  2260   2260     int isSynced;                 /* True if journal page is synced */
         2261  +  const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
  2261   2262   
  2262   2263     assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
  2263   2264     assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
  2264   2265     assert( isMainJrnl || pDone );     /* pDone always used on sub-journals */
  2265   2266     assert( isSavepnt || pDone==0 );   /* pDone never used on non-savepoint */
  2266   2267   
  2267   2268     aData = pPager->pTmpSpace;
................................................................................
  2377   2378     if( isOpen(pPager->fd)
  2378   2379      && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
  2379   2380      && isSynced
  2380   2381     ){
  2381   2382       i64 ofst = (pgno-1)*(i64)pPager->pageSize;
  2382   2383       testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
  2383   2384       assert( !pagerUseWal(pPager) );
         2385  +
         2386  +    /* Write the data read from the journal back into the database file.
         2387  +    ** This is usually safe even for an encrypted database - as the data
         2388  +    ** was encrypted before it was written to the journal file. The exception
         2389  +    ** is if the data was just read from an in-memory sub-journal. In that
         2390  +    ** case it must be encrypted here before it is copied into the database
         2391  +    ** file.  */
         2392  +    if( !jrnlEnc ){CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);}
  2384   2393       rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
         2394  +    if( !jrnlEnc ){CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);}
         2395  +
  2385   2396       if( pgno>pPager->dbFileSize ){
  2386   2397         pPager->dbFileSize = pgno;
  2387   2398       }
  2388   2399       if( pPager->pBackup ){
  2389         -      CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
         2400  +      if( jrnlEnc ){CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);}
  2390   2401         sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
  2391         -      CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
         2402  +      if( jrnlEnc ){CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);}
  2392   2403       }
  2393   2404     }else if( !isMainJrnl && pPg==0 ){
  2394   2405       /* If this is a rollback of a savepoint and data was not written to
  2395   2406       ** the database and the page is not in-memory, there is a potential
  2396   2407       ** problem. When the page is next fetched by the b-tree layer, it 
  2397   2408       ** will be read from the database file, which may or may not be 
  2398   2409       ** current. 
................................................................................
  2436   2447       /* If this was page 1, then restore the value of Pager.dbFileVers.
  2437   2448       ** Do this before any decoding. */
  2438   2449       if( pgno==1 ){
  2439   2450         memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
  2440   2451       }
  2441   2452   
  2442   2453       /* Decode the page just read from disk */
  2443         -    CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
         2454  +    if( jrnlEnc ) CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
  2444   2455       sqlite3PcacheRelease(pPg);
  2445   2456     }
  2446   2457     return rc;
  2447   2458   }
  2448   2459   
  2449   2460   /*
  2450   2461   ** Parameter zMaster is the name of a master journal file. A single journal
................................................................................
  4449   4460       /* If the sub-journal was opened successfully (or was already open),
  4450   4461       ** write the journal record into the file.  */
  4451   4462       if( rc==SQLITE_OK ){
  4452   4463         void *pData = pPg->pData;
  4453   4464         i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
  4454   4465         char *pData2;
  4455   4466     
  4456         -      CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
         4467  +      if( pPager->subjInMemory ){
         4468  +        pData2 = pData;
         4469  +      }else{
         4470  +        CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
         4471  +      }
  4457   4472         PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
  4458   4473         rc = write32bits(pPager->sjfd, offset, pPg->pgno);
  4459   4474         if( rc==SQLITE_OK ){
  4460   4475           rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
  4461   4476         }
  4462   4477       }
  4463   4478     }

Added test/subjournal.test.

            1  +# 2017 May 9
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +
           13  +set testdir [file dirname $argv0]
           14  +source $testdir/tester.tcl
           15  +set testprefix subjournal
           16  +
           17  +do_execsql_test 1.0 {
           18  +  PRAGMA temp_store = memory;
           19  +  CREATE TABLE t1(a,b,c);
           20  +  INSERT INTO t1 VALUES(1, 2, 3);
           21  +} {}
           22  +do_execsql_test 1.1 {
           23  +  BEGIN;
           24  +    INSERT INTO t1 VALUES(4, 5, 6);
           25  +    SAVEPOINT one;
           26  +      INSERT INTO t1 VALUES(7, 8, 9);
           27  +    ROLLBACK TO one;
           28  +    SELECT * FROM t1;
           29  +} {1 2 3 4 5 6}
           30  +do_execsql_test 1.2 {
           31  +  COMMIT;
           32  +}
           33  +
           34  +do_execsql_test 2.0 {
           35  +  PRAGMA cache_size = 5;
           36  +  CREATE TABLE t2(a BLOB);
           37  +  CREATE INDEX i2 ON t2(a);
           38  +  WITH s(i) AS (
           39  +    SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
           40  +  ) INSERT INTO t2 SELECT randomblob(500) FROM s;
           41  +}
           42  +
           43  +do_test 2.1 {
           44  +  forcedelete test.db2
           45  +  sqlite3 db2 test2.db
           46  +  sqlite3_backup B db2 main db main
           47  +  set nPage [db one {PRAGMA page_count}]
           48  +  B step [expr $nPage-10]
           49  +} {SQLITE_OK}
           50  +
           51  +do_execsql_test 2.2 {
           52  +  BEGIN;
           53  +    UPDATE t2 SET a=randomblob(499);
           54  +    SAVEPOINT two;
           55  +      UPDATE t2 SET a=randomblob(498);
           56  +    ROLLBACK TO two;
           57  +  COMMIT;
           58  +  PRAGMA integrity_check;
           59  +} {ok}
           60  +
           61  +do_test 2.3 {
           62  +  B step 1000
           63  +} {SQLITE_DONE}
           64  +do_test 2.4 {
           65  +  B finish
           66  +  execsql { PRAGMA integrity_check } db2
           67  +} {ok}
           68  +
           69  +finish_test
           70  +