/ Check-in [2c145ee6]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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 Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

2254
2255
2256
2257
2258
2259
2260

2261
2262
2263
2264
2265
2266
2267
....
2377
2378
2379
2380
2381
2382
2383








2384


2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
....
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
....
4449
4450
4451
4452
4453
4454
4455



4456

4457
4458
4459
4460
4461
4462
4463
  int rc;
  PgHdr *pPg;                   /* An existing page in the cache */
  Pgno pgno;                    /* The page number of a page in journal */
  u32 cksum;                    /* Checksum used for sanity checking */
  char *aData;                  /* Temporary storage for the page */
  sqlite3_file *jfd;            /* The file descriptor for the journal file */
  int isSynced;                 /* True if journal page is synced */


  assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
  assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
  assert( isMainJrnl || pDone );     /* pDone always used on sub-journals */
  assert( isSavepnt || pDone==0 );   /* pDone never used on non-savepoint */

  aData = pPager->pTmpSpace;
................................................................................
  if( isOpen(pPager->fd)
   && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
   && isSynced
  ){
    i64 ofst = (pgno-1)*(i64)pPager->pageSize;
    testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
    assert( !pagerUseWal(pPager) );








    rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);


    if( pgno>pPager->dbFileSize ){
      pPager->dbFileSize = pgno;
    }
    if( pPager->pBackup ){
      CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
      sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
      CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
    }
  }else if( !isMainJrnl && pPg==0 ){
    /* If this is a rollback of a savepoint and data was not written to
    ** the database and the page is not in-memory, there is a potential
    ** problem. When the page is next fetched by the b-tree layer, it 
    ** will be read from the database file, which may or may not be 
    ** current. 
................................................................................
    /* If this was page 1, then restore the value of Pager.dbFileVers.
    ** Do this before any decoding. */
    if( pgno==1 ){
      memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
    }

    /* Decode the page just read from disk */
    CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
    sqlite3PcacheRelease(pPg);
  }
  return rc;
}

/*
** Parameter zMaster is the name of a master journal file. A single journal
................................................................................
    /* If the sub-journal was opened successfully (or was already open),
    ** write the journal record into the file.  */
    if( rc==SQLITE_OK ){
      void *pData = pPg->pData;
      i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
      char *pData2;
  



      CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);

      PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
      rc = write32bits(pPager->sjfd, offset, pPg->pgno);
      if( rc==SQLITE_OK ){
        rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
      }
    }
  }







>







 







>
>
>
>
>
>
>
>

>
>




|

|







 







|







 







>
>
>
|
>







2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
....
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
....
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
....
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
  int rc;
  PgHdr *pPg;                   /* An existing page in the cache */
  Pgno pgno;                    /* The page number of a page in journal */
  u32 cksum;                    /* Checksum used for sanity checking */
  char *aData;                  /* Temporary storage for the page */
  sqlite3_file *jfd;            /* The file descriptor for the journal file */
  int isSynced;                 /* True if journal page is synced */
  const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);

  assert( (isMainJrnl&~1)==0 );      /* isMainJrnl is 0 or 1 */
  assert( (isSavepnt&~1)==0 );       /* isSavepnt is 0 or 1 */
  assert( isMainJrnl || pDone );     /* pDone always used on sub-journals */
  assert( isSavepnt || pDone==0 );   /* pDone never used on non-savepoint */

  aData = pPager->pTmpSpace;
................................................................................
  if( isOpen(pPager->fd)
   && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
   && isSynced
  ){
    i64 ofst = (pgno-1)*(i64)pPager->pageSize;
    testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
    assert( !pagerUseWal(pPager) );

    /* Write the data read from the journal back into the database file.
    ** This is usually safe even for an encrypted database - as the data
    ** was encrypted before it was written to the journal file. The exception
    ** is if the data was just read from an in-memory sub-journal. In that
    ** case it must be encrypted here before it is copied into the database
    ** file.  */
    if( !jrnlEnc ){CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);}
    rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
    if( !jrnlEnc ){CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);}

    if( pgno>pPager->dbFileSize ){
      pPager->dbFileSize = pgno;
    }
    if( pPager->pBackup ){
      if( jrnlEnc ){CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);}
      sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
      if( jrnlEnc ){CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);}
    }
  }else if( !isMainJrnl && pPg==0 ){
    /* If this is a rollback of a savepoint and data was not written to
    ** the database and the page is not in-memory, there is a potential
    ** problem. When the page is next fetched by the b-tree layer, it 
    ** will be read from the database file, which may or may not be 
    ** current. 
................................................................................
    /* If this was page 1, then restore the value of Pager.dbFileVers.
    ** Do this before any decoding. */
    if( pgno==1 ){
      memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
    }

    /* Decode the page just read from disk */
    if( jrnlEnc ) CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT);
    sqlite3PcacheRelease(pPg);
  }
  return rc;
}

/*
** Parameter zMaster is the name of a master journal file. A single journal
................................................................................
    /* If the sub-journal was opened successfully (or was already open),
    ** write the journal record into the file.  */
    if( rc==SQLITE_OK ){
      void *pData = pPg->pData;
      i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
      char *pData2;
  
      if( pPager->subjInMemory ){
        pData2 = pData;
      }else{
        CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
      }
      PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
      rc = write32bits(pPager->sjfd, offset, pPg->pgno);
      if( rc==SQLITE_OK ){
        rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
      }
    }
  }

Added test/subjournal.test.













































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 2017 May 9
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix subjournal

do_execsql_test 1.0 {
  PRAGMA temp_store = memory;
  CREATE TABLE t1(a,b,c);
  INSERT INTO t1 VALUES(1, 2, 3);
} {}
do_execsql_test 1.1 {
  BEGIN;
    INSERT INTO t1 VALUES(4, 5, 6);
    SAVEPOINT one;
      INSERT INTO t1 VALUES(7, 8, 9);
    ROLLBACK TO one;
    SELECT * FROM t1;
} {1 2 3 4 5 6}
do_execsql_test 1.2 {
  COMMIT;
}

do_execsql_test 2.0 {
  PRAGMA cache_size = 5;
  CREATE TABLE t2(a BLOB);
  CREATE INDEX i2 ON t2(a);
  WITH s(i) AS (
    SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
  ) INSERT INTO t2 SELECT randomblob(500) FROM s;
}

do_test 2.1 {
  forcedelete test.db2
  sqlite3 db2 test2.db
  sqlite3_backup B db2 main db main
  set nPage [db one {PRAGMA page_count}]
  B step [expr $nPage-10]
} {SQLITE_OK}

do_execsql_test 2.2 {
  BEGIN;
    UPDATE t2 SET a=randomblob(499);
    SAVEPOINT two;
      UPDATE t2 SET a=randomblob(498);
    ROLLBACK TO two;
  COMMIT;
  PRAGMA integrity_check;
} {ok}

do_test 2.3 {
  B step 1000
} {SQLITE_DONE}
do_test 2.4 {
  B finish
  execsql { PRAGMA integrity_check } db2
} {ok}

finish_test