-C Explicit\scasts\sto\ssquelch\sbogus\swarnings\sfor\svc++.\s\sTicket\s#194.\s(CVS\s932)
-D 2003-04-25T03:13:25
+C Make\sVACUUM\swork\seven\sif\smultiple\sprocesses\shave\sthe\sdatabase\sopen\sat\sonce.\s(CVS\s933)
+D 2003-04-25T13:22:52
F Makefile.in 004acec253ecdde985c8ecd5b7c9accdb210378f
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
F src/attach.c 7ebc7487de43e357a64226f8abef81f2669f2183
F src/auth.c a4afd27964fb9f661147115790c8ae2ee230ebcc
-F src/btree.c 3de765f186a5d07d8764f970ecd07d83ccfdc51d
-F src/btree.h dc899dd3a10ec9a0c9b51308610d2f53e36b4820
-F src/btree_rb.c b427e6f2df7807cd338636259efadb4e43dba669
+F src/btree.c a9e8aa96c2af6a81e442719d0cbc1a71bb9b3e08
+F src/btree.h 6488448db856bb92729b1325b932864c9aa163f5
+F src/btree_rb.c 8e00e40be264716e1929987878672e55d9e0e76d
F src/build.c d5a26baeffa5bc49b4b7009a7723c6ab7e1b02d9
F src/copy.c 44b13fd4d2444fb53bff8a5ecee1c5f6f86a8263
F src/delete.c 23d33fd8967c6cc492943bbecea93be6491edc6a
F src/insert.c 19882be1edc4b1629b8f3097e2615164f2c9cecb
F src/main.c 5e4d4d081d82840a743c57269ca3c32640cefc06
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
-F src/os.c 7274951ed6894f383cb889342267ded07caf339b
+F src/os.c e56853eaea5dab258ab1ccb77b4743b453516e3a
F src/os.h 9e5bbddff123187295e3d00d49af06192cd1cd49
-F src/pager.c df4c81350cbd80c1ab48341ae0768ba78d99ad49
-F src/pager.h e3702f7d384921f6cd5ce0b3ed589185433e9f6c
+F src/pager.c 18066f5057500dccc2948c258ea5ffd4139bbf7d
+F src/pager.h 5da62c83443f26b1792cfd72c96c422f91aadd31
F src/parse.y 15ae47e7dd84304c1c6ae9205558405127977541
F src/pragma.c 118fe400d71b7fdcc03580d5eab6bb5aa00772a5
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
F src/trigger.c e763f4015c96e06b694184ead5754985c1dfdae0
F src/update.c b7fa7c427b74aee6db56ecfa09e5e151e6f9fa6a
F src/util.c 87635cfdfffa056a8d3147719357aa442374f78c
-F src/vacuum.c 67199f3d626aed21940b3b428c25979a98fda03d
+F src/vacuum.c 44420de0f02cc66a673469fee1f33b6d08bb717e
F src/vdbe.c f0868ac926d98395d28c2a29119364ff11b77852
F src/vdbe.h 985c24f312d10f9ef8f9a8b8ea62fcdf68e82f21
F src/where.c f632cd30f013163484a4d60c249d36fe31f5be12
F test/trigger4.test 9a5c1406344d743020c2753ae8d6dfe6eb75f818
F test/unique.test 22a46df72a3e0a3fd1a2d39e96fb59f18448dd5f
F test/update.test 198360dfa14e65354dbcc66d5b98d8070780e42b
-F test/vacuum.test baf8e0c44587322da5669996ffc55daf8cc60266
+F test/vacuum.test 9262504c37e9d796e3d8d6c1730e878c8fa8787a
F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246
F test/view.test d356f445d481c04ffa6036a4c61cb8ba70289f69
F test/where.test d719129a052280fe245a2ddcbd09bcc0b8c17ce4
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 5afb88008fed253e6d1fc0ed5172370b61d3727b
-R f2421cf3a297d027e70ffbccdb3ba489
+P cb808c14bc14e7bd1cfff134ae5206ace451f2df
+R 304a2370652d1a06037c5b9e50c2e06c
U drh
-Z 38db8e55b84708279a57f38314d421c3
+Z a3c697bfebd34cfeb9979168f63ba185
-cb808c14bc14e7bd1cfff134ae5206ace451f2df
\ No newline at end of file
+caa960289f3d1f5e8f35a94e9e4321996c211ed2
\ No newline at end of file
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.90 2003/04/25 03:13:25 drh Exp $
+** $Id: btree.c,v 1.91 2003/04/25 13:22:52 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
}
/*
-** Change the name of the underlying database file.
+** Copy the complete content of pBtFrom into pBtTo. A transaction
+** must be active for both files.
+**
+** The size of file pBtFrom may be reduced by this operation.
+** If anything goes wrong, the transaction on pBtFrom is rolled back.
*/
-static int fileBtreeChangeFilename(Btree *pBt, const char *zNew){
- return sqlitepager_rename(pBt->pPager, zNew);
+static int fileBtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
+ int rc = SQLITE_OK;
+ Pgno i, nPage;
+
+ if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR;
+ if( pBtTo->needSwab!=pBtFrom->needSwab ) return SQLITE_ERROR;
+ if( pBtTo->pCursor ) return SQLITE_BUSY;
+ memcpy(pBtTo->page1, pBtFrom->page1, SQLITE_PAGE_SIZE);
+ sqlitepager_overwrite(pBtTo->pPager, 1, pBtFrom->page1);
+ nPage = sqlitepager_pagecount(pBtFrom->pPager);
+ for(i=2; i<=nPage; i++){
+ void *pPage;
+ rc = sqlitepager_get(pBtFrom->pPager, i, &pPage);
+ if( rc ) break;
+ sqlitepager_overwrite(pBtTo->pPager, i, pPage);
+ sqlitepager_unref(pPage);
+ }
+ if( !rc ) rc = sqlitepager_truncate(pBtTo->pPager, nPage);
+ if( rc ){
+ fileBtreeRollback(pBtTo);
+ }
+ return rc;
}
/*
fileBtreeUpdateMeta,
fileBtreeIntegrityCheck,
fileBtreeGetFilename,
- fileBtreeChangeFilename,
+ fileBtreeCopyFile,
#ifdef SQLITE_TEST
fileBtreePageDump,
fileBtreePager
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
-** @(#) $Id: btree.h,v 1.32 2003/04/25 02:43:08 drh Exp $
+** @(#) $Id: btree.h,v 1.33 2003/04/25 13:22:53 drh Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
int (*UpdateMeta)(Btree*, int*);
char *(*IntegrityCheck)(Btree*, int*, int);
const char *(*GetFilename)(Btree*);
- int (*ChangeFilename)(Btree*, const char *zNew);
+ int (*CopyFile)(Btree*,Btree*);
#ifdef SQLITE_TEST
int (*PageDump)(Btree*, int, int);
struct Pager *(*Pager)(Btree*);
#define sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot)\
(btOps(pBt)->IntegrityCheck(pBt, aRoot, nRoot))
#define sqliteBtreeGetFilename(pBt) (btOps(pBt)->GetFilename(pBt))
-#define sqliteBtreeChangeFilename(pBt, zNew)\
- (btOps(pBt)->ChangeFilename(pBt, zNew))
+#define sqliteBtreeCopyFile(pBt1, pBt2) (btOps(pBt1)->CopyFile(pBt1, pBt2))
#ifdef SQLITE_TEST
#define sqliteBtreePageDump(pBt, pgno, recursive)\
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree_rb.c,v 1.8 2003/04/25 02:43:08 drh Exp $
+** $Id: btree_rb.c,v 1.9 2003/04/25 13:22:53 drh Exp $
**
** This file implements an in-core database using Red-Black balanced
** binary trees.
}
/*
-** Change the name of the underlying database file.
+** The copy file function is not implemented for the in-memory database
*/
-static int memBtreeChangeFilename(Btree *pBt, const char *zNew){
- return SQLITE_OK;
+static int memBtreeCopyFile(Btree *pBt, Btree *pBt2){
+ return SQLITE_INTERNAL; /* Not implemented */
}
static BtOps sqliteBtreeOps = {
memBtreeUpdateMeta,
memBtreeIntegrityCheck,
memBtreeGetFilename,
- memBtreeChangeFilename,
+ memBtreeCopyFile,
#ifdef SQLITE_TEST
memBtreePageDump,
}
+#if 0 /* NOT USED */
/*
** Change the name of an existing file.
*/
return SQLITE_ERROR;
#endif
}
-
+#endif /* NOT USED */
/*
** Attempt to open a file for both reading and writing. If that
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.81 2003/04/06 20:52:32 drh Exp $
+** @(#) $Id: pager.c,v 1.82 2003/04/25 13:22:53 drh Exp $
*/
#include "os.h" /* Must be first to enable large file support */
#include "sqliteInt.h"
return n;
}
+/*
+** Forward declaration
+*/
+static int syncAllPages(Pager*);
+
+/*
+** Truncate the file to the number of pages specified.
+*/
+int sqlitepager_truncate(Pager *pPager, Pgno nPage){
+ int rc;
+ if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager);
+ if( nPage>=pPager->dbSize ){
+ return SQLITE_OK;
+ }
+ syncAllPages(pPager);
+ rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)nPage);
+ if( rc==SQLITE_OK ){
+ pPager->dbSize = nPage;
+ }
+ return rc;
+}
+
/*
** Shutdown the page cache. Free all memory and close all files.
**
return pPager->zFilename;
}
-/*
-** Rename the database file
-*/
-int sqlitepager_rename(Pager *pPager, const char *zNewName){
- char *zNew;
- char *zJournal;
- int nName;
- int rc;
-
- nName = strlen(zNewName);
- zNew = sqliteMalloc( nName*2 + 30 );
- if( zNew==0 ){
- return SQLITE_NOMEM;
- }
- memcpy(zNew, zNewName, nName+1);
- zJournal = &zNew[nName+1];
- memcpy(zJournal, zNew, nName);
- strcpy(&zJournal[nName], "-journal");
- if( pPager->journalOpen ){
- rc = sqliteOsFileRename(pPager->zJournal, zJournal);
- if( rc ){
- sqliteFree(zNew);
- return rc;
- }
- }
- rc = sqliteOsFileRename(pPager->zFilename, zNew);
- if( rc ){
- sqliteFree(zNew);
- return rc;
- }
- if( pPager->zFilename!=(char*)&pPager[1] ){
- sqliteFree(pPager->zFilename);
- }
- pPager->zFilename = zNew;
- return SQLITE_OK;
-}
-
#ifdef SQLITE_TEST
/*
** Print a listing of all referenced pages and their ref count.
** subsystem. The page cache subsystem reads and writes a file a page
** at a time and provides a journal for rollback.
**
-** @(#) $Id: pager.h,v 1.22 2003/04/06 20:44:45 drh Exp $
+** @(#) $Id: pager.h,v 1.23 2003/04/25 13:22:53 drh Exp $
*/
/*
int sqlitepager_iswriteable(void*);
int sqlitepager_overwrite(Pager *pPager, Pgno pgno, void*);
int sqlitepager_pagecount(Pager*);
+int sqlitepager_truncate(Pager*,Pgno);
int sqlitepager_begin(void*);
int sqlitepager_commit(Pager*);
int sqlitepager_rollback(Pager*);
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
-** $Id: vacuum.c,v 1.4 2003/04/25 02:43:08 drh Exp $
+** $Id: vacuum.c,v 1.5 2003/04/25 13:22:53 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
const char *zFilename; /* full pathname of the database file */
int nFilename; /* number of characters in zFilename[] */
char *zTemp = 0; /* a temporary file in same directory as zFilename */
- char *zTemp2; /* Another temp file in the same directory */
sqlite *dbNew = 0; /* The new vacuumed database */
sqlite *db; /* The original database */
- int rc, i;
- char *zErrMsg = 0;
- char *zSql = 0;
- int safety = 0;
- vacuumStruct sVac;
+ int rc = SQLITE_OK; /* Return code from service routines */
+ int i; /* Loop counter */
+ char *zErrMsg = 0; /* Error messages stored here */
+ int safety = 0; /* TRUE if safety is off */
+ vacuumStruct sVac; /* Information passed to callbacks */
/* These are all of the pragmas that need to be transferred over
** to the new database */
return;
}
nFilename = strlen(zFilename);
- zTemp = sqliteMalloc( 2*(nFilename+40) );
+ zTemp = sqliteMalloc( nFilename+100 );
if( zTemp==0 ) return;
- zTemp2 = &zTemp[nFilename+40];
strcpy(zTemp, zFilename);
- strcpy(zTemp2, zFilename);
for(i=0; i<10; i++){
zTemp[nFilename] = '-';
randomName(&zTemp[nFilename+1]);
- zTemp2[nFilename] = '-';
- randomName(&zTemp2[nFilename+1]);
- if( !sqliteOsFileExists(zTemp) && !sqliteOsFileExists(zTemp2) ) break;
+ if( !sqliteOsFileExists(zTemp) ) break;
}
if( i>=10 ){
- sqliteErrorMsg(pParse, "unable to create a temporary database files "
+ sqliteErrorMsg(pParse, "unable to create a temporary database file "
"in the same directory as the original database");
goto end_of_vacuum;
}
}
safety = 1;
if( execsql(pParse, db, "BEGIN") ) goto end_of_vacuum;
- if( execsql(pParse, dbNew, "BEGIN") ) goto end_of_vacuum;
+ if( execsql(pParse, dbNew, "PRAGMA synchronous=off; BEGIN") ){
+ goto end_of_vacuum;
+ }
sVac.dbOld = db;
sVac.dbNew = dbNew;
sVac.pParse = pParse;
rc = sqlite_exec(db, zBuf, vacuumCallback3, &sVac, &zErrMsg);
if( rc ) goto vacuum_error;
}
- rc = sqlite_exec(db, "SELECT type, name, sql FROM sqlite_master "
- "WHERE sql NOT NULL", vacuumCallback1, &sVac, &zErrMsg);
- if( rc ) goto vacuum_error;
-
- if( sqliteOsFileRename(zFilename, zTemp2) ){
- sqliteErrorMsg(pParse, "unable to rename database file");
- goto end_of_vacuum;
- }
- if( sqliteOsFileRename(zTemp, zFilename) ){
- sqliteOsFileRename(zTemp2, zFilename);
- sqliteErrorMsg(pParse, "unable to rename database file");
- goto end_of_vacuum;
+ if( rc==SQLITE_OK ){
+ rc = sqlite_exec(db, "SELECT type, name, sql FROM sqlite_master "
+ "WHERE sql NOT NULL", vacuumCallback1, &sVac, &zErrMsg);
}
- if( execsql(pParse, dbNew, "COMMIT;") ){
- sqliteOsDelete(zFilename);
- sqliteOsFileRename(zTemp2, zFilename);
+ if( rc ){
+ if( pParse->zErrMsg==0 ){
+ sqliteErrorMsg(pParse, "unable to vacuum database - %s", zErrMsg);
+ }
goto end_of_vacuum;
}
- execsql(pParse, db, "COMMIT;"); /* Nothing was written so its gotta work */
- sqlite_close(dbNew);
- dbNew = 0;
- if( sqliteOsDelete(zTemp2) ){
- sqliteErrorMsg(pParse, "unable to delete old database: %s", zTemp2);
- }
- sqliteBtreeClose(db->aDb[0].pBt);
- zTemp2[nFilename] = 0;
- if( sqliteBtreeOpen(zTemp2, 0, MAX_PAGES, &db->aDb[0].pBt) ){
- sqliteErrorMsg(pParse, "unable to reopen database after vacuuming");
- }
+ rc = sqliteBtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt);
+ sqlite_exec(db, "COMMIT", 0, 0, 0);
sqliteResetInternalSchema(db, 0);
end_of_vacuum:
sqlite_exec(db, "COMMIT", 0, 0, 0);
- if( safety) {
+ if( safety ) {
sqliteSafetyOn(db);
}
if( dbNew ) sqlite_close(dbNew);
sqliteOsDelete(zTemp);
sqliteFree(zTemp);
- sqliteFree(zSql);
sqliteFree(sVac.s1.z);
sqliteFree(sVac.s2.z);
if( zErrMsg ) sqlite_freemem(zErrMsg);
return;
vacuum_error:
- if( pParse->zErrMsg==0 ){
- sqliteErrorMsg(pParse, "unable to vacuum database - %s", zErrMsg);
- }
- goto end_of_vacuum;
#endif
}
# This file implements regression tests for SQLite library. The
# focus of this file is testing the VACUUM statement.
#
-# $Id: vacuum.test,v 1.8 2003/04/25 02:43:08 drh Exp $
+# $Id: vacuum.test,v 1.9 2003/04/25 13:22:53 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
-proc cksum {filename} {
- set txt [db eval {SELECT name, type, sql FROM sqlite_master}]\n
- foreach tbl [db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
- append txt [db eval "SELECT * FROM $tbl"]\n
+proc cksum {{db db}} {
+ set txt [$db eval {SELECT name, type, sql FROM sqlite_master}]\n
+ foreach tbl [$db eval {SELECT name FROM sqlite_master WHERE type='table'}] {
+ append txt [$db eval "SELECT * FROM $tbl"]\n
}
foreach prag {default_synchronous default_cache_size} {
- append txt $prag-[db eval "PRAGMA $prag"]\n
+ append txt $prag-[$db eval "PRAGMA $prag"]\n
}
- # set fd [open $filename w]
- # puts $fd $txt
- # close $fd
- return [string length $txt]-[md5 $txt]
+ set cksum [string length $txt]-[md5 $txt]
+ puts $cksum-[file size test.db]
+ return $cksum
}
do_test vacuum-1.1 {
DROP TABLE t2;
}
set ::size1 [file size test.db]
- set ::cksum [cksum vacuum1.txt]
+ set ::cksum [cksum]
expr {$::cksum!=""}
} {1}
do_test vacuum-1.2 {
execsql {
VACUUM;
}
- cksum vacuum2.txt
+ cksum
} $cksum
do_test vacuum-1.3 {
expr {[file size test.db]<$::size1}
DROP TABLE t2;
}
set ::size1 [file size test.db]
- set ::cksum [cksum vacuum3.txt]
+ set ::cksum [cksum]
expr {$::cksum!=""}
} {1}
do_test vacuum-1.5 {
execsql {
VACUUM;
}
- cksum vacuum4.txt
+ cksum
} $cksum
do_test vacuum-1.6 {
expr {[file size test.db]<$::size1}
COMMIT;
}
} {1 {cannot VACUUM from within a transaction}}
-execsql COMMIT
+catch {db eval COMMIT}
+do_test vacuum-2.2 {
+ sqlite db2 test.db
+ execsql {
+ BEGIN;
+ CREATE TABLE t4 AS SELECT * FROM t1;
+ CREATE TABLE t5 AS SELECT * FROM t1;
+ COMMIT;
+ DROP TABLE t4;
+ DROP TABLE t5;
+ } db2
+ set ::cksum [cksum db2]
+ catchsql {
+ VACUUM
+ }
+} {1 {database schema has changed}}
+do_test vacuum-2.3 {
+ execsql {
+ VACUUM;
+ }
+ cksum
+} $cksum
+do_test vacuum-2.4 {
+ catch {db2 eval {SELECT count(*) FROM sqlite_master}}
+ cksum db2
+} $cksum
+
+
+catch {db2 close}
# finish_test