SQLite

Check-in [6b2b6b2dbd]
Login

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

Overview
Comment:Be more agressive about not creating or opening the TEMP database if there are no TEMP tables. (CVS 1891)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6b2b6b2dbd821070a2781685c4b63a50bc8f5cae
User & Date: drh 2004-08-18 15:58:23.000
Context
2004-08-18
16:05
Better debug logging of the pager. (CVS 1892) (check-in: 1cc0323f25 user: drh tags: trunk)
15:58
Be more agressive about not creating or opening the TEMP database if there are no TEMP tables. (CVS 1891) (check-in: 6b2b6b2dbd user: drh tags: trunk)
02:10
Avoid creating a TEMP database unless it is absolutely necessary. (CVS 1890) (check-in: 5914a11caa user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/build.c.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.247 2004/08/18 02:10:15 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**     PRAGMA
**
** $Id: build.c,v 1.248 2004/08/18 15:58:23 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Check to see if the schema for the database needs
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
  Vdbe *v = sqlite3GetVdbe(pParse);
  if( v==0 ) return;
  sqlite3CodeVerifySchema(pParse, iDb);
  pParse->writeMask |= 1<<iDb;
  if( setStatement ){
    sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
  }
  if( iDb!=1 ){
    sqlite3BeginWriteOperation(pParse, setStatement, 1);
  }
}

/*
** Generate code that concludes an operation that may have changed
** the database.  If a statement transaction was started, then emit







|







2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
  Vdbe *v = sqlite3GetVdbe(pParse);
  if( v==0 ) return;
  sqlite3CodeVerifySchema(pParse, iDb);
  pParse->writeMask |= 1<<iDb;
  if( setStatement ){
    sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
  }
  if( iDb!=1 && pParse->db->aDb[1].pBt!=0 ){
    sqlite3BeginWriteOperation(pParse, setStatement, 1);
  }
}

/*
** Generate code that concludes an operation that may have changed
** the database.  If a statement transaction was started, then emit
Changes to src/pager.c.
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
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.155 2004/08/18 02:10:15 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

/*
** Macros for troubleshooting.  Normally turned off
*/
#if 0
static Pager *mainPager = 0;
#define SET_PAGER(X)  if( mainPager==0 ) mainPager = (X)
#define CLR_PAGER(X)  if( mainPager==(X) ) mainPager = 0
#define TRACE1(X)     if( pPager==mainPager ) sqlite3DebugPrintf(X)
#define TRACE2(X,Y)   if( pPager==mainPager ) sqlite3DebugPrintf(X,Y)
#define TRACE3(X,Y,Z) if( pPager==mainPager ) sqlite3DebugPrintf(X,Y,Z)
#else
#define SET_PAGER(X)
#define CLR_PAGER(X)
#define TRACE1(X)
#define TRACE2(X,Y)
#define TRACE3(X,Y,Z)

#endif


/*
** The page cache as a whole is always in one of the following
** states:
**







|











<
|
<
|
|
|

<
<



>







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
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.156 2004/08/18 15:58:23 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

/*
** Macros for troubleshooting.  Normally turned off
*/
#if 0

#define TRACE1(X)       sqlite3DebugPrintf(X)

#define TRACE2(X,Y)     sqlite3DebugPrintf(X,Y)
#define TRACE3(X,Y,Z)   sqlite3DebugPrintf(X,Y,Z)
#define TRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
#else


#define TRACE1(X)
#define TRACE2(X,Y)
#define TRACE3(X,Y,Z)
#define TRACE4(X,Y,Z,W)
#endif


/*
** The page cache as a whole is always in one of the following
** states:
**
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
  ** not the database file. The page is left marked dirty in this case.
  **
  ** If in EXCLUSIVE state, then we update the pager cache if it exists
  ** and the main file. The page is then marked not dirty.
  */
  pPg = pager_lookup(pPager, pgno);
  assert( pPager->state>=PAGER_EXCLUSIVE || pPg );
  TRACE2("PLAYBACK page %d\n", pgno);
  if( pPager->state>=PAGER_EXCLUSIVE ){
    sqlite3OsSeek(&pPager->fd, (pgno-1)*(off_t)pPager->pageSize);
    rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
  }
  if( pPg ){
    /* No page should ever be rolled back that is in use, except for page
    ** 1 which is held in use in order to keep the lock on the database







|







864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
  ** not the database file. The page is left marked dirty in this case.
  **
  ** If in EXCLUSIVE state, then we update the pager cache if it exists
  ** and the main file. The page is then marked not dirty.
  */
  pPg = pager_lookup(pPager, pgno);
  assert( pPager->state>=PAGER_EXCLUSIVE || pPg );
  TRACE3("PLAYBACK %d page %d\n", pPager->fd.h, pgno);
  if( pPager->state>=PAGER_EXCLUSIVE ){
    sqlite3OsSeek(&pPager->fd, (pgno-1)*(off_t)pPager->pageSize);
    rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
  }
  if( pPg ){
    /* No page should ever be rolled back that is in use, except for page
    ** 1 which is held in use in order to keep the lock on the database
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  int rc = SQLITE_OK;
  for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
    char zBuf[SQLITE_MAX_PAGE_SIZE];
    if( !pPg->dirty ) continue;
    if( (int)pPg->pgno <= pPager->origDbSize ){
      sqlite3OsSeek(&pPager->fd, pPager->pageSize*(off_t)(pPg->pgno-1));
      rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
      TRACE2("REFETCH page %d\n", pPg->pgno);
      if( rc ) break;
      CODEC(pPager, zBuf, pPg->pgno, 2);
    }else{
      memset(zBuf, 0, pPager->pageSize);
    }
    if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), pPager->pageSize) ){
      memcpy(PGHDR_TO_DATA(pPg), zBuf, pPager->pageSize);







|







993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  int rc = SQLITE_OK;
  for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
    char zBuf[SQLITE_MAX_PAGE_SIZE];
    if( !pPg->dirty ) continue;
    if( (int)pPg->pgno <= pPager->origDbSize ){
      sqlite3OsSeek(&pPager->fd, pPager->pageSize*(off_t)(pPg->pgno-1));
      rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
      TRACE3("REFETCH %d page %d\n", pPager->fd.h, pPg->pgno);
      if( rc ) break;
      CODEC(pPager, zBuf, pPg->pgno, 2);
    }else{
      memset(zBuf, 0, pPager->pageSize);
    }
    if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), pPager->pageSize) ){
      memcpy(PGHDR_TO_DATA(pPg), zBuf, pPager->pageSize);
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
  nameLen = strlen(zFullPathname);
  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
  if( pPager==0 ){
    sqlite3OsClose(&fd);
    sqliteFree(zFullPathname);
    return SQLITE_NOMEM;
  }
  SET_PAGER(pPager);
  pPager->zFilename = (char*)&pPager[1];
  pPager->zDirectory = &pPager->zFilename[nameLen+1];
  pPager->zJournal = &pPager->zDirectory[nameLen+1];
  strcpy(pPager->zFilename, zFullPathname);
  strcpy(pPager->zDirectory, zFullPathname);
  for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
  if( i>0 ) pPager->zDirectory[i-1] = 0;







|







1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  nameLen = strlen(zFullPathname);
  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
  if( pPager==0 ){
    sqlite3OsClose(&fd);
    sqliteFree(zFullPathname);
    return SQLITE_NOMEM;
  }
  TRACE3("OPEN %d %s\n", fd.h, zFullPathname);
  pPager->zFilename = (char*)&pPager[1];
  pPager->zDirectory = &pPager->zFilename[nameLen+1];
  pPager->zJournal = &pPager->zDirectory[nameLen+1];
  strcpy(pPager->zFilename, zFullPathname);
  strcpy(pPager->zDirectory, zFullPathname);
  for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
  if( i>0 ) pPager->zDirectory[i-1] = 0;
1724
1725
1726
1727
1728
1729
1730

1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
      assert( !pHist->pOrig );
      assert( !pHist->pStmt );
    }
#endif
    pNext = pPg->pNextAll;
    sqliteFree(pPg);
  }

  sqlite3OsClose(&pPager->fd);
  assert( pPager->journalOpen==0 );
  /* Temp files are automatically deleted by the OS
  ** if( pPager->tempFile ){
  **   sqlite3OsDelete(pPager->zFilename);
  ** }
  */
  CLR_PAGER(pPager);
  if( pPager->zFilename!=(char*)&pPager[1] ){
    assert( 0 );  /* Cannot happen */
    sqliteFree(pPager->zFilename);
    sqliteFree(pPager->zJournal);
    sqliteFree(pPager->zDirectory);
  }
  sqliteFree(pPager);







>







<







1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735

1736
1737
1738
1739
1740
1741
1742
      assert( !pHist->pOrig );
      assert( !pHist->pStmt );
    }
#endif
    pNext = pPg->pNextAll;
    sqliteFree(pPg);
  }
  TRACE2("CLOSE %d\n", pPager->fd.h);
  sqlite3OsClose(&pPager->fd);
  assert( pPager->journalOpen==0 );
  /* Temp files are automatically deleted by the OS
  ** if( pPager->tempFile ){
  **   sqlite3OsDelete(pPager->zFilename);
  ** }
  */

  if( pPager->zFilename!=(char*)&pPager[1] ){
    assert( 0 );  /* Cannot happen */
    sqliteFree(pPager->zFilename);
    sqliteFree(pPager->zJournal);
    sqliteFree(pPager->zDirectory);
  }
  sqliteFree(pPager);
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
  }
  pPager->state = PAGER_EXCLUSIVE;

  while( pList ){
    assert( pList->dirty );
    sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(off_t)pPager->pageSize);
    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
    TRACE2("STORE page %d\n", pList->pgno);
    rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
    if( rc ) return rc;
    pList->dirty = 0;
    pList = pList->pDirty;
  }
  return SQLITE_OK;







|







1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
  }
  pPager->state = PAGER_EXCLUSIVE;

  while( pList ){
    assert( pList->dirty );
    sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(off_t)pPager->pageSize);
    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
    TRACE3("STORE %d page %d\n", pPager->fd.h, pList->pgno);
    rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize);
    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
    if( rc ) return rc;
    pList->dirty = 0;
    pList = pList->pDirty;
  }
  return SQLITE_OK;
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
    if( pPager->dbSize<(int)pgno ){
      memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
    }else{
      int rc;
      assert( pPager->memDb==0 );
      sqlite3OsSeek(&pPager->fd, (pgno-1)*(off_t)pPager->pageSize);
      rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
      TRACE2("FETCH page %d\n", pPg->pgno);
      CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
      if( rc!=SQLITE_OK ){
        off_t fileSize;
        if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
               || fileSize>=pgno*pPager->pageSize ){
          sqlite3pager_unref(PGHDR_TO_DATA(pPg));
          return rc;







|







2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
    if( pPager->dbSize<(int)pgno ){
      memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
    }else{
      int rc;
      assert( pPager->memDb==0 );
      sqlite3OsSeek(&pPager->fd, (pgno-1)*(off_t)pPager->pageSize);
      rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
      TRACE3("FETCH %d page %d\n", pPager->fd.h, pPg->pgno);
      CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
      if( rc!=SQLITE_OK ){
        off_t fileSize;
        if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
               || fileSize>=pgno*pPager->pageSize ){
          sqlite3pager_unref(PGHDR_TO_DATA(pPg));
          return rc;
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535

2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555

2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
  */
  if( !pPg->inJournal && (pPager->useJournal || pPager->memDb) ){
    if( (int)pPg->pgno <= pPager->origDbSize ){
      int szPg;
      u32 saved;
      if( pPager->memDb ){
        PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
        TRACE2("JOURNAL page %d\n", pPg->pgno);
        assert( pHist->pOrig==0 );
        pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
        if( pHist->pOrig ){
          memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
        }
        pPg->inJournal = 1;
      }else{
        u32 cksum;
        CODEC(pPager, pData, pPg->pgno, 7);
        cksum = pager_cksum(pPager, pPg->pgno, pData);
        saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
        store32bits(cksum, pPg, pPager->pageSize);
        szPg = pPager->pageSize+8;
        store32bits(pPg->pgno, pPg, -4);
        rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
        pPager->journalOff += szPg;

        TRACE3("JOURNAL page %d needSync=%d\n", pPg->pgno, pPg->needSync);
        CODEC(pPager, pData, pPg->pgno, 0);
        *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
        if( rc!=SQLITE_OK ){
          sqlite3pager_rollback(pPager);
          pPager->errMask |= PAGER_ERR_FULL;
          return rc;
        }
        pPager->nRec++;
        assert( pPager->aInJournal!=0 );
        pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
        pPg->needSync = !pPager->noSync;
        pPg->inJournal = 1;
        if( pPager->stmtInUse ){
          pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
          page_add_to_stmt_list(pPg);
        }
      }
    }else{
      pPg->needSync = !pPager->journalStarted && !pPager->noSync;

      TRACE3("APPEND page %d needSync=%d\n", pPg->pgno, pPg->needSync);
    }
    if( pPg->needSync ){
      pPager->needSync = 1;
    }
  }

  /* If the statement journal is open and the page is not in it,
  ** then write the current page to the statement journal.  Note that
  ** the statement journal format differs from the standard journal format
  ** in that it omits the checksums and the header.
  */
  if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
    if( pPager->memDb ){
      PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
      assert( pHist->pStmt==0 );
      pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
      if( pHist->pStmt ){
        memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
      }
      TRACE2("STMT-JOURNAL page %d\n", pPg->pgno);
    }else{
      store32bits(pPg->pgno, pPg, -4);
      CODEC(pPager, pData, pPg->pgno, 7);
      rc = sqlite3OsWrite(&pPager->stfd, ((char*)pData)-4, pPager->pageSize+4);
      TRACE2("STMT-JOURNAL page %d\n", pPg->pgno);
      CODEC(pPager, pData, pPg->pgno, 0);
      if( rc!=SQLITE_OK ){
        sqlite3pager_rollback(pPager);
        pPager->errMask |= PAGER_ERR_FULL;
        return rc;
      }
      pPager->stmtNRec++;







|
















>
|



















>
|




















|




|







2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
  */
  if( !pPg->inJournal && (pPager->useJournal || pPager->memDb) ){
    if( (int)pPg->pgno <= pPager->origDbSize ){
      int szPg;
      u32 saved;
      if( pPager->memDb ){
        PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
        TRACE3("JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
        assert( pHist->pOrig==0 );
        pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
        if( pHist->pOrig ){
          memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
        }
        pPg->inJournal = 1;
      }else{
        u32 cksum;
        CODEC(pPager, pData, pPg->pgno, 7);
        cksum = pager_cksum(pPager, pPg->pgno, pData);
        saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
        store32bits(cksum, pPg, pPager->pageSize);
        szPg = pPager->pageSize+8;
        store32bits(pPg->pgno, pPg, -4);
        rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
        pPager->journalOff += szPg;
        TRACE4("JOURNAL %d page %d needSync=%d\n",
                pPager->fd.h, pPg->pgno, pPg->needSync);
        CODEC(pPager, pData, pPg->pgno, 0);
        *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
        if( rc!=SQLITE_OK ){
          sqlite3pager_rollback(pPager);
          pPager->errMask |= PAGER_ERR_FULL;
          return rc;
        }
        pPager->nRec++;
        assert( pPager->aInJournal!=0 );
        pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
        pPg->needSync = !pPager->noSync;
        pPg->inJournal = 1;
        if( pPager->stmtInUse ){
          pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
          page_add_to_stmt_list(pPg);
        }
      }
    }else{
      pPg->needSync = !pPager->journalStarted && !pPager->noSync;
      TRACE4("APPEND %d page %d needSync=%d\n",
              pPager->fd.h, pPg->pgno, pPg->needSync);
    }
    if( pPg->needSync ){
      pPager->needSync = 1;
    }
  }

  /* If the statement journal is open and the page is not in it,
  ** then write the current page to the statement journal.  Note that
  ** the statement journal format differs from the standard journal format
  ** in that it omits the checksums and the header.
  */
  if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
    if( pPager->memDb ){
      PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
      assert( pHist->pStmt==0 );
      pHist->pStmt = sqliteMallocRaw( pPager->pageSize );
      if( pHist->pStmt ){
        memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
      }
      TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
    }else{
      store32bits(pPg->pgno, pPg, -4);
      CODEC(pPager, pData, pPg->pgno, 7);
      rc = sqlite3OsWrite(&pPager->stfd, ((char*)pData)-4, pPager->pageSize+4);
      TRACE3("STMT-JOURNAL %d page %d\n", pPager->fd.h, pPg->pgno);
      CODEC(pPager, pData, pPg->pgno, 0);
      if( rc!=SQLITE_OK ){
        sqlite3pager_rollback(pPager);
        pPager->errMask |= PAGER_ERR_FULL;
        return rc;
      }
      pPager->stmtNRec++;
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
        assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt );
        continue;
      }

      pHist = PGHDR_TO_HIST(p, pPager);
      if( pHist->pOrig ){
        memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize);
        TRACE2("ROLLBACK-PAGE %d\n", p->pgno);
      }else{
        TRACE2("PAGE %d is clean\n", p->pgno);
      }
      clearHistory(pHist);
      p->dirty = 0;
      p->inJournal = 0;
      p->inStmt = 0;
      p->pPrevStmt = p->pNextStmt = 0;








|

|







2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
        assert( !((PgHistory *)PGHDR_TO_HIST(p, pPager))->pStmt );
        continue;
      }

      pHist = PGHDR_TO_HIST(p, pPager);
      if( pHist->pOrig ){
        memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize);
        TRACE3("ROLLBACK-PAGE %d of %d\n", p->pgno, pPager->fd.h);
      }else{
        TRACE3("PAGE %d is clean on %d\n", p->pgno, pPager->fd.h);
      }
      clearHistory(pHist);
      p->dirty = 0;
      p->inJournal = 0;
      p->inStmt = 0;
      p->pPrevStmt = p->pNextStmt = 0;

Changes to test/attach.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach.test,v 1.25 2004/08/01 03:52:18 drh Exp $
#

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

for {set i 2} {$i<=15} {incr i} {
  file delete -force test$i.db







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach.test,v 1.26 2004/08/18 15:58:24 drh Exp $
#

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

for {set i 2} {$i<=15} {incr i} {
  file delete -force test$i.db
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  foreach {idx name file} [execsql {PRAGMA database_list} $db] {
    lappend list $idx $name
  }
  return $list
}
do_test attach-1.11b {
  db_list db
} {0 main 1 temp 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9}
do_test attach-1.12 {
  catchsql {
    ATTACH 'test.db' as db2;
  }
} {1 {database db2 is already in use}}
do_test attach-1.13 {
  catchsql {







|







100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  foreach {idx name file} [execsql {PRAGMA database_list} $db] {
    lappend list $idx $name
  }
  return $list
}
do_test attach-1.11b {
  db_list db
} {0 main 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9}
do_test attach-1.12 {
  catchsql {
    ATTACH 'test.db' as db2;
  }
} {1 {database db2 is already in use}}
do_test attach-1.13 {
  catchsql {
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  }
} {1 {too many attached databases - max 10}}
do_test attach-1.20.1 {
  execsql {
    DETACH db5;
  }
  db_list db
} {0 main 1 temp 2 db2 3 db3 4 db4 5 db6 6 db7 7 db8 8 db9 9 db10 10 db11}
integrity_check attach-1.20.2
do_test attach-1.21 {
  catchsql {
    ATTACH 'test.db' as db12;
  }
} {0 {}}
do_test attach-1.22 {







|







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  }
} {1 {too many attached databases - max 10}}
do_test attach-1.20.1 {
  execsql {
    DETACH db5;
  }
  db_list db
} {0 main 2 db2 3 db3 4 db4 5 db6 6 db7 7 db8 8 db9 9 db10 10 db11}
integrity_check attach-1.20.2
do_test attach-1.21 {
  catchsql {
    ATTACH 'test.db' as db12;
  }
} {0 {}}
do_test attach-1.22 {
Changes to test/attach2.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.23 2004/08/18 02:10:15 drh Exp $
#

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


# Ticket #354







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is testing the ATTACH and DETACH commands
# and related functionality.
#
# $Id: attach2.test,v 1.24 2004/08/18 15:58:24 drh Exp $
#

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


# Ticket #354
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  # to commit a write to test.db from db2
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  } db2 
} {1 {database is locked}}

lock_status 4.4.1 db {main shared temp closed file2 unlocked}
lock_status 4.4.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.5 {
  # Handle 'db2' reserves file2.
  execsql {BEGIN} db2
  execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
  # Lock status:
  #    db  - shared(main)
  #    db2 - reserved(file2)
} {}

lock_status 4.5.1 db {main shared temp closed file2 unlocked}
lock_status 4.5.2 db2 {main unlocked temp reserved file2 reserved}

do_test attach2-4.6.1 {
  # Reads are allowed against a reserved database.
  catchsql {
    SELECT * FROM file2.t1;
  }
  # Lock status:
  #    db  - shared(main), shared(file2)
  #    db2 - reserved(file2)
} {0 {}}

lock_status 4.6.1.1 db {main shared temp closed file2 shared}
lock_status 4.6.1.2 db2 {main unlocked temp reserved file2 reserved}

do_test attach2-4.6.2 {
  # Writes against a reserved database are not allowed.
  catchsql {
    UPDATE file2.t1 SET a=0;
  }
} {1 {database is locked}}

lock_status 4.6.2.1 db {main shared temp reserved file2 shared}
lock_status 4.6.2.2 db2 {main unlocked temp reserved file2 reserved}

do_test attach2-4.7 {
  # Ensure handle 'db' retains the lock on the main file after
  # failing to obtain a write-lock on file2.
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  } db2 
} {0 {}}

lock_status 4.7.1 db {main shared temp reserved file2 shared}
lock_status 4.7.2 db2 {main reserved temp reserved file2 reserved}

do_test attach2-4.8 {
  # We should still be able to read test.db from db2
  execsql {SELECT * FROM t1} db2
} {1 2}

lock_status 4.8.1 db {main shared temp reserved file2 shared}
lock_status 4.8.2 db2 {main reserved temp reserved file2 reserved}

do_test attach2-4.9 {
  # Try to upgrade the handle 'db' lock.
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  }
} {1 {database is locked}}

lock_status 4.9.1 db {main shared temp reserved file2 shared}
lock_status 4.9.2 db2 {main reserved temp reserved file2 reserved}

btree_breakpoint
do_test attach2-4.10 {
  # We cannot commit db2 while db is holding a read-lock
  catchsql {COMMIT} db2
} {1 {database is locked}}

lock_status 4.10.1 db {main shared temp reserved file2 shared}
lock_status 4.10.2 db2 {main pending temp reserved file2 reserved}

set sqlite_os_trace 0
btree_breakpoint
do_test attach2-4.11 {
  # db is able to commit.
  catchsql {COMMIT}
} {0 {}}

lock_status 4.11.1 db {main unlocked temp unlocked file2 unlocked}
lock_status 4.11.2 db2 {main pending temp reserved file2 reserved}

do_test attach2-4.12 {
  # Now we can commit db2
  catchsql {COMMIT} db2
} {0 {}}

lock_status 4.12.1 db {main unlocked temp unlocked file2 unlocked}
lock_status 4.12.2 db2 {main unlocked temp unlocked file2 unlocked}

do_test attach2-4.13 {
  execsql {SELECT * FROM file2.t1}
} {1 2}
do_test attach2-4.14 {
  execsql {INSERT INTO t1 VALUES(1, 2)}
} {}







|











|












|








|
|









|
|






|
|








|
|







|
|








|
|






|
|







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  # to commit a write to test.db from db2
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  } db2 
} {1 {database is locked}}

lock_status 4.4.1 db {main shared temp closed file2 unlocked}
lock_status 4.4.2 db2 {main unlocked temp closed file2 unlocked}

do_test attach2-4.5 {
  # Handle 'db2' reserves file2.
  execsql {BEGIN} db2
  execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2
  # Lock status:
  #    db  - shared(main)
  #    db2 - reserved(file2)
} {}

lock_status 4.5.1 db {main shared temp closed file2 unlocked}
lock_status 4.5.2 db2 {main unlocked temp closed file2 reserved}

do_test attach2-4.6.1 {
  # Reads are allowed against a reserved database.
  catchsql {
    SELECT * FROM file2.t1;
  }
  # Lock status:
  #    db  - shared(main), shared(file2)
  #    db2 - reserved(file2)
} {0 {}}

lock_status 4.6.1.1 db {main shared temp closed file2 shared}
lock_status 4.6.1.2 db2 {main unlocked temp closed file2 reserved}

do_test attach2-4.6.2 {
  # Writes against a reserved database are not allowed.
  catchsql {
    UPDATE file2.t1 SET a=0;
  }
} {1 {database is locked}}

lock_status 4.6.2.1 db {main shared temp closed file2 shared}
lock_status 4.6.2.2 db2 {main unlocked temp closed file2 reserved}

do_test attach2-4.7 {
  # Ensure handle 'db' retains the lock on the main file after
  # failing to obtain a write-lock on file2.
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  } db2 
} {0 {}}

lock_status 4.7.1 db {main shared temp closed file2 shared}
lock_status 4.7.2 db2 {main reserved temp closed file2 reserved}

do_test attach2-4.8 {
  # We should still be able to read test.db from db2
  execsql {SELECT * FROM t1} db2
} {1 2}

lock_status 4.8.1 db {main shared temp closed file2 shared}
lock_status 4.8.2 db2 {main reserved temp closed file2 reserved}

do_test attach2-4.9 {
  # Try to upgrade the handle 'db' lock.
  catchsql {
    INSERT INTO t1 VALUES(1, 2)
  }
} {1 {database is locked}}

lock_status 4.9.1 db {main shared temp closed file2 shared}
lock_status 4.9.2 db2 {main reserved temp closed file2 reserved}

btree_breakpoint
do_test attach2-4.10 {
  # We cannot commit db2 while db is holding a read-lock
  catchsql {COMMIT} db2
} {1 {database is locked}}

lock_status 4.10.1 db {main shared temp closed file2 shared}
lock_status 4.10.2 db2 {main pending temp closed file2 reserved}

set sqlite_os_trace 0
btree_breakpoint
do_test attach2-4.11 {
  # db is able to commit.
  catchsql {COMMIT}
} {0 {}}

lock_status 4.11.1 db {main unlocked temp closed file2 unlocked}
lock_status 4.11.2 db2 {main pending temp closed file2 reserved}

do_test attach2-4.12 {
  # Now we can commit db2
  catchsql {COMMIT} db2
} {0 {}}

lock_status 4.12.1 db {main unlocked temp closed file2 unlocked}
lock_status 4.12.2 db2 {main unlocked temp closed file2 unlocked}

do_test attach2-4.13 {
  execsql {SELECT * FROM file2.t1}
} {1 2}
do_test attach2-4.14 {
  execsql {INSERT INTO t1 VALUES(1, 2)}
} {}