]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Make the VACUUM command run out of the VDBE like all other commands.
authordrh <drh@noemail.net>
Sun, 7 Dec 2003 00:24:35 +0000 (00:24 +0000)
committerdrh <drh@noemail.net>
Sun, 7 Dec 2003 00:24:35 +0000 (00:24 +0000)
(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

manifest
manifest.uuid
src/sqliteInt.h
src/vacuum.c
src/vdbe.c
test/auth.test
test/vacuum.test

index 31d68e18ef9ed94e736a166b7eccc273addcdefb..313778f18aa36e0a19048ebf31f2a300c51a6f66 100644 (file)
--- 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
index 57e7efcead34b88caf3fc07d3717031c16af1af8..8c3a32eadd22524f9fd7a35ea9085ca64e18b73d 100644 (file)
@@ -1 +1 @@
-ac428c8d4a731678cc26cf198689814a8a56d141
\ No newline at end of file
+614cbbafa180469744421f8fbe56cb392f48d05f
\ No newline at end of file
index 9712d3718861959d6657fc54bd408bbd91899bfc..f30ab18666882accd84d508e06305cca6c1d2401 100644 (file)
@@ -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*);
index 76863b5f4918e5fe8a40508c4276e834d19f1d3b..95e7add47dce0efbbb5f53e77cee57e318fe89b8 100644 (file)
@@ -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 && i<sizeof(zPragma)/sizeof(zPragma[0]); i++){
     char zBuf[200];
     assert( strlen(zPragma[i])<100 );
@@ -288,32 +288,34 @@ void sqliteVacuum(Parse *pParse, Token *pTableName){
     sVac.zPragma = zPragma[i];
     rc = sqlite_exec(db, zBuf, vacuumCallback3, &sVac, &zErrMsg);
   }
-  if( !rc ){
-    rc = sqlite_exec(db, "SELECT type, name, sql FROM sqlite_master "
-             "WHERE sql NOT NULL", vacuumCallback1, &sVac, &zErrMsg);
+  if( rc==SQLITE_OK ){
+    rc = sqlite_exec(db, 
+      "SELECT type, name, sql FROM sqlite_master "
+      "WHERE sql NOT NULL AND type!='view' "
+      "UNION ALL "
+      "SELECT type, name, sql FROM sqlite_master "
+      "WHERE sql NOT NULL AND type=='view'",
+      vacuumCallback1, &sVac, &zErrMsg);
   }
-  if( !rc ){
+  if( rc==SQLITE_OK ){
     rc = sqliteBtreeCopyFile(db->aDb[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
 }
index 22519e398029f0f71dea5ebe96db7308a9b484ff..898017d5398c3b4b2853f61a1c07d6bcffe14215 100644 (file)
@@ -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: {
index 249f294c3bdeb9a32aac5095d3307ad9abff52db..c88415792e735621674c4d7c234a9027b9ce9ef6 100644 (file)
@@ -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
index 5222fb6f0fc2f68a3cfbbfb928f761d4d4c90c09..7ed20510175762cd00d788272dc7995092c3704e 100644 (file)
@@ -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