From: drh Date: Sun, 7 Dec 2003 00:24:35 +0000 (+0000) Subject: Make the VACUUM command run out of the VDBE like all other commands. X-Git-Tag: version-3.6.10~4940 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6f8c91caa08ad25378bd8833b759893a49a0fe62;p=thirdparty%2Fsqlite.git Make the VACUUM command run out of the VDBE like all other commands. (Ticket #464). Make the VACUUM command work even if there are VIEWs in the SQLITE_MASTER table that come before tables they reference. (Ticket #515) (CVS 1128) FossilOrigin-Name: 614cbbafa180469744421f8fbe56cb392f48d05f --- diff --git a/manifest b/manifest index 31d68e18ef..313778f18a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fail\san\sATTACH\sif\sthe\sauxiliary\sdatabase\sis\slocked.\s\sTicket\s#514.\s(CVS\s1127) -D 2003-12-06T22:22:36 +C Make\sthe\sVACUUM\scommand\srun\sout\sof\sthe\sVDBE\slike\sall\sother\scommands.\n(Ticket\s#464).\s\sMake\sthe\sVACUUM\scommand\swork\seven\sif\sthere\sare\sVIEWs\nin\sthe\sSQLITE_MASTER\stable\sthat\scome\sbefore\stables\sthey\sreference.\n(Ticket\s#515)\s(CVS\s1128) +D 2003-12-07T00:24:35 F Makefile.in 5cb273b7d0e945d47ee8b9ad1c2a04ce79927d2d F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -50,7 +50,7 @@ F src/select.c d79ac60ba1595ff3c94b12892e87098329776482 F src/shell.c 3b067edc098c45caca164bcad1fa79192c3ec5ae F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in e6cfff01fafc8a82ce82cd8c932af421dc9adb54 -F src/sqliteInt.h 882aa33ee2aed7685449b899d917a316b9cc2c44 +F src/sqliteInt.h f8549cf426920e43efb105a08484768cdb73c808 F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895 F src/tclsqlite.c 3efac6b5861ac149c41251d4d4c420c94be5ba6a F src/test1.c f9d5816610f7ec4168ab7b098d5207a5708712b6 @@ -61,8 +61,8 @@ F src/tokenize.c d10e7f0b4d8634f6f37237b4e65314e3e5a3a34b F src/trigger.c ce83e017b407d046e909d05373d7f8ee70f9f7f9 F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397 F src/util.c cc95dd360fac09a059b2ab98e4c333d1a2308db5 -F src/vacuum.c e4724eade07e4cf8897060a8cf632dbd92408eeb -F src/vdbe.c d61f720a836a7c948356105b87b2512a9484cb3b +F src/vacuum.c 77485a64a6e4e358170f150fff681c1624a092b0 +F src/vdbe.c b40c2a7002c0c8e5a226666622f487e241dadf36 F src/vdbe.h 3957844e46fea71fd030e78f6a3bd2f7e320fb43 F src/vdbeInt.h 2824bf88895b901b3a8c9e44527c67530e1c0dcb F src/vdbeaux.c 877ae44ab42f43d38e8cd989087627508a4c98dd @@ -70,7 +70,7 @@ F src/where.c d01a3506f3c1e3a205028068c8a14d713872c633 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test c26848402e7ac829e043e1fa5e0eb87032e5d81d F test/attach2.test d0105f4e8b1debf0ac25ed7df986b5854620e172 -F test/auth.test b7d6bdeffa804b96b7bcac2712e5f71ce014a1b8 +F test/auth.test 5c4d95cdaf539c0c236e20ce1f71a93e7dde9185 F test/bigfile.test 1cd8256d4619c39bea48147d344f348823e78678 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/bind.test 56a57043b42c4664ca705f6050e56717a8a6699a @@ -135,7 +135,7 @@ F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8 F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b F test/update.test 2ef5a6655f2966f0aef733a9f4495b3fe8e16809 -F test/vacuum.test a58776ef529e9bc21980ac120d6859d4ee34b578 +F test/vacuum.test 9447f1d7633b083c9b97f807fa05f9b27ada7503 F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246 F test/view.test 1ee12c6f8f4791a2c0655120d5562a49400cfe53 F test/where.test cb3a2ed062ce4b5f08aff2d08027c6a46d68c47b @@ -176,7 +176,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P 656c90387a4a714b4f31040ece9b0e15e30934af -R 9ba0dba1a5b0b6a0c4f493ffeeb808ce +P ac428c8d4a731678cc26cf198689814a8a56d141 +R de0e25f496472fda102deb07f0a3f4c2 U drh -Z 4d2d90a1bb0f4a7af58cf43ec43a116f +Z da3da18ef1bdac6a224ddd572daad46d diff --git a/manifest.uuid b/manifest.uuid index 57e7efcead..8c3a32eadd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ac428c8d4a731678cc26cf198689814a8a56d141 \ No newline at end of file +614cbbafa180469744421f8fbe56cb392f48d05f \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 9712d37188..f30ab18666 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.203 2003/11/27 00:48:58 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.204 2003/12/07 00:24:35 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -1125,6 +1125,7 @@ Index *sqliteFindIndex(sqlite*,const char*, const char*); void sqliteUnlinkAndDeleteIndex(sqlite*,Index*); void sqliteCopy(Parse*, SrcList*, Token*, Token*, int); void sqliteVacuum(Parse*, Token*); +int sqliteRunVacuum(char**, sqlite*); int sqliteGlobCompare(const unsigned char*,const unsigned char*); int sqliteLikeCompare(const unsigned char*,const unsigned char*); char *sqliteTableNameFromToken(Token*); diff --git a/src/vacuum.c b/src/vacuum.c index 76863b5f49..95e7add47d 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -14,7 +14,7 @@ ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** -** $Id: vacuum.c,v 1.8 2003/08/15 13:24:52 drh Exp $ +** $Id: vacuum.c,v 1.9 2003/12/07 00:24:35 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -37,7 +37,8 @@ typedef struct vacuumStruct vacuumStruct; struct vacuumStruct { sqlite *dbOld; /* Original database */ sqlite *dbNew; /* New database */ - Parse *pParse; /* The parser context */ + char **pzErrMsg; /* Write errors here */ + int rc; /* Set to non-zero on an error */ const char *zTable; /* Name of a table being copied */ const char *zPragma; /* Pragma to execute with results */ dynStr s1, s2; /* Two dynamic strings */ @@ -85,16 +86,16 @@ static void appendQuoted(dynStr *p, const char *zText){ /* ** Execute statements of SQL. If an error occurs, write the error -** message into pParse->zErrMsg and return non-zero. +** message into *pzErrMsg and return non-zero. */ -static int execsql(Parse *pParse, sqlite *db, const char *zSql){ - int rc; +static int execsql(char **pzErrMsg, sqlite *db, const char *zSql){ char *zErrMsg = 0; + int rc; /* printf("***** executing *****\n%s\n", zSql); */ rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg); - if( rc ){ - sqliteErrorMsg(pParse, "%s", zErrMsg); + if( zErrMsg ){ + sqliteSetString(pzErrMsg, zErrMsg, (char*)0); sqlite_freemem(zErrMsg); } return rc; @@ -126,7 +127,7 @@ static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){ } } appendText(&p->s2,")", 1); - rc = execsql(p->pParse, p->dbNew, p->s2.z); + rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z); return rc; } @@ -146,7 +147,7 @@ static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){ assert( argv[0]!=0 ); assert( argv[1]!=0 ); assert( argv[2]!=0 ); - rc = execsql(p->pParse, p->dbNew, argv[2]); + rc = execsql(p->pzErrMsg, p->dbNew, argv[2]); if( rc==SQLITE_OK && strcmp(argv[0],"table")==0 ){ char *zErrMsg = 0; p->s1.nUsed = 0; @@ -154,8 +155,9 @@ static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){ appendQuoted(&p->s1, argv[1]); p->zTable = argv[1]; rc = sqlite_exec(p->dbOld, p->s1.z, vacuumCallback2, p, &zErrMsg); - if( rc && p->pParse->zErrMsg==0 ){ - sqliteErrorMsg(p->pParse, "%s", zErrMsg); + if( zErrMsg ){ + sqliteSetString(p->pzErrMsg, zErrMsg, (char*)0); + sqlite_freemem(zErrMsg); } } return rc; @@ -176,7 +178,7 @@ static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){ assert( strlen(p->zPragma)<100 ); assert( strlen(argv[0])<30 ); sprintf(zBuf,"PRAGMA %s=%s;", p->zPragma, argv[0]); - rc = execsql(p->pParse, p->dbNew, zBuf); + rc = execsql(p->pzErrMsg, p->dbNew, zBuf); return rc; } @@ -206,16 +208,23 @@ static void randomName(char *zBuf){ ** become a no-op. */ void sqliteVacuum(Parse *pParse, Token *pTableName){ + Vdbe *v = sqliteGetVdbe(pParse); + sqliteVdbeAddOp(v, OP_Vacuum, 0, 0); + return; +} + +/* +** This routine implements the OP_Vacuum opcode of the VDBE. +*/ +int sqliteRunVacuum(char **pzErrMsg, sqlite *db){ #if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM 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 */ sqlite *dbNew = 0; /* The new vacuumed database */ - sqlite *db; /* The original database */ 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 */ + char *zErrMsg; /* Error message */ vacuumStruct sVac; /* Information passed to callbacks */ /* These are all of the pragmas that need to be transferred over @@ -226,15 +235,10 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ /* "default_temp_store", */ }; - /* Initial error checks - */ - if( pParse->explain ){ - return; - } - db = pParse->db; if( db->flags & SQLITE_InTrans ){ - sqliteErrorMsg(pParse, "cannot VACUUM from within a transaction"); - return; + sqliteSetString(pzErrMsg, "cannot VACUUM from within a transaction", + (char*)0); + return SQLITE_ERROR; } memset(&sVac, 0, sizeof(sVac)); @@ -245,11 +249,11 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ if( zFilename==0 ){ /* This only happens with the in-memory database. VACUUM is a no-op ** there, so just return */ - return; + return SQLITE_OK; } nFilename = strlen(zFilename); zTemp = sqliteMalloc( nFilename+100 ); - if( zTemp==0 ) return; + if( zTemp==0 ) return SQLITE_NOMEM; strcpy(zTemp, zFilename); for(i=0; i<10; i++){ zTemp[nFilename] = '-'; @@ -257,30 +261,26 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){ if( !sqliteOsFileExists(zTemp) ) break; } if( i>=10 ){ - sqliteErrorMsg(pParse, "unable to create a temporary database file " - "in the same directory as the original database"); + sqliteSetString(pzErrMsg, "unable to create a temporary database file " + "in the same directory as the original database", (char*)0); goto end_of_vacuum; } dbNew = sqlite_open(zTemp, 0, &zErrMsg); if( dbNew==0 ){ - sqliteErrorMsg(pParse, "unable to open a temporary database at %s - %s", - zTemp, zErrMsg); - goto end_of_vacuum; - } - if( sqliteSafetyOff(db) ){ - sqliteErrorMsg(pParse, "library routines called out of sequence"); + sqliteSetString(pzErrMsg, "unable to open a temporary database at ", + zTemp, " - ", zErrMsg, (char*)0); goto end_of_vacuum; } - safety = 1; - if( execsql(pParse, db, "BEGIN") ) goto end_of_vacuum; - if( execsql(pParse, dbNew, "PRAGMA synchronous=off; BEGIN") ){ + if( execsql(pzErrMsg, db, "BEGIN") ) goto end_of_vacuum; + if( execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN") ){ goto end_of_vacuum; } + sVac.dbOld = db; sVac.dbNew = dbNew; - sVac.pParse = pParse; + sVac.pzErrMsg = pzErrMsg; for(i=0; rc==SQLITE_OK && iaDb[0].pBt, dbNew->aDb[0].pBt); sqlite_exec(db, "COMMIT", 0, 0, 0); - sqlite_exec(db, "ROLLBACK", 0, 0, 0); /* In case the COMMIT failed */ sqliteResetInternalSchema(db, 0); } end_of_vacuum: - if( rc && pParse->zErrMsg==0 && zErrMsg!=0 ){ - sqliteErrorMsg(pParse, "unable to vacuum database - %s", zErrMsg); - } - if( safety ) { - sqlite_exec(db, "COMMIT", 0, 0, 0); - sqlite_exec(db, "ROLLBACK", 0, 0, 0); /* In case the COMMIT failed */ - sqliteSafetyOn(db); + if( rc && zErrMsg!=0 ){ + sqliteSetString(pzErrMsg, "unable to vacuum database - ", + zErrMsg, (char*)0); } + sqlite_exec(db, "ROLLBACK", 0, 0, 0); if( dbNew ) sqlite_close(dbNew); sqliteOsDelete(zTemp); sqliteFree(zTemp); sqliteFree(sVac.s1.z); sqliteFree(sVac.s2.z); if( zErrMsg ) sqlite_freemem(zErrMsg); - return; + if( rc==SQLITE_ABORT ) rc = SQLITE_ERROR; + return rc; #endif } diff --git a/src/vdbe.c b/src/vdbe.c index 22519e3980..898017d539 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.243 2003/12/06 21:43:56 drh Exp $ +** $Id: vdbe.c,v 1.244 2003/12/07 00:24:35 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -4651,6 +4651,19 @@ case OP_SetNext: { break; } +/* Opcode: Vacuum * * * +** +** Vacuum the entire database. This opcode will cause other virtual +** machines to be created and run. It may not be called from within +** a transaction. +*/ +case OP_Vacuum: { + if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; + rc = sqliteRunVacuum(&p->zErrMsg, db); + if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; + break; +} + /* An other opcode is illegal... */ default: { diff --git a/test/auth.test b/test/auth.test index 249f294c3b..c88415792e 100644 --- a/test/auth.test +++ b/test/auth.test @@ -12,7 +12,7 @@ # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # -# $Id: auth.test,v 1.11 2003/11/27 00:49:23 drh Exp $ +# $Id: auth.test,v 1.12 2003/12/07 00:24:35 drh Exp $ # set testdir [file dirname $argv0] @@ -1771,7 +1771,7 @@ do_test auth-2.10 { } catchsql {SELECT ROWID,b,c FROM t2} } {1 {illegal return value (1) from the authorization function - should be SQLITE_OK, SQLITE_IGNORE, or SQLITE_DENY}} -do_test auth-2.11 { +do_test auth-2.11.1 { proc auth {code arg1 arg2 arg3 arg4} { if {$code=="SQLITE_READ" && $arg2=="a"} { return SQLITE_IGNORE @@ -1780,7 +1780,7 @@ do_test auth-2.11 { } catchsql {SELECT * FROM t2, t3} } {0 {{} 2 33 44 55 66 {} 8 9 44 55 66}} -do_test auth-2.11 { +do_test auth-2.11.2 { proc auth {code arg1 arg2 arg3 arg4} { if {$code=="SQLITE_READ" && $arg2=="x"} { return SQLITE_IGNORE diff --git a/test/vacuum.test b/test/vacuum.test index 5222fb6f0f..7ed2051017 100644 --- a/test/vacuum.test +++ b/test/vacuum.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # -# $Id: vacuum.test,v 1.13 2003/09/27 01:08:38 drh Exp $ +# $Id: vacuum.test,v 1.14 2003/12/07 00:24:35 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -28,7 +28,6 @@ proc cksum {{db db}} { # puts $cksum-[file size test.db] return $cksum } - do_test vacuum-1.1 { execsql { BEGIN; @@ -136,7 +135,6 @@ do_test vacuum-3.1 { # Ticket #464. Make sure VACUUM works with the sqlite_compile() API. # -if 0 { do_test vacuum-4.1 { db close set DB [sqlite db test.db] @@ -146,8 +144,33 @@ do_test vacuum-4.1 { do_test vacuum-4.2 { sqlite_finalize $VM } {} -} -catch {db2 close} +# Ticket #515. VACUUM after deleting and recreating the table that +# a view refers to. +# +do_test vacuum-5.1 { + db close + file delete -force test.db + sqlite db test.db + catchsql { + CREATE TABLE Test (TestID int primary key); + INSERT INTO Test VALUES (NULL); + CREATE VIEW viewTest AS SELECT * FROM Test; + + BEGIN; + CREATE TEMP TABLE tempTest (TestID int primary key, Test2 int NULL); + INSERT INTO tempTest SELECT TestID, 1 FROM Test; + DROP TABLE Test; + CREATE TABLE Test(TestID int primary key, Test2 int NULL); + INSERT INTO Test SELECT * FROM tempTest; + COMMIT; + VACUUM; + } +} {0 {}} +do_test vacuum-5.2 { + catchsql { + VACUUM; + } +} {0 {}} # finish_test