Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | 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) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
614cbbafa180469744421f8fbe56cb39 |
User & Date: | drh 2003-12-07 00:24:35.000 |
Context
2003-12-10
| ||
01:31 | Fix the code generator to a void a VDBE stack overflow on 3-way joins. Ticket #519. (CVS 1129) (check-in: 230a4ff2c8 user: drh tags: trunk) | |
2003-12-07
| ||
00:24 | 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) (check-in: 614cbbafa1 user: drh tags: trunk) | |
2003-12-06
| ||
22:22 | Fail an ATTACH if the auxiliary database is locked. Ticket #514. (CVS 1127) (check-in: ac428c8d4a user: drh tags: trunk) | |
Changes
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.204 2003/12/07 00:24:35 drh Exp $ */ #include "config.h" #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" |
︙ | ︙ | |||
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 | void sqliteExprIfFalse(Parse*, Expr*, int, int); Table *sqliteFindTable(sqlite*,const char*, const char*); Table *sqliteLocateTable(Parse*,const char*, const char*); Index *sqliteFindIndex(sqlite*,const char*, const char*); void sqliteUnlinkAndDeleteIndex(sqlite*,Index*); void sqliteCopy(Parse*, SrcList*, Token*, Token*, int); void sqliteVacuum(Parse*, Token*); int sqliteGlobCompare(const unsigned char*,const unsigned char*); int sqliteLikeCompare(const unsigned char*,const unsigned char*); char *sqliteTableNameFromToken(Token*); int sqliteExprCheck(Parse*, Expr*, int, int*); int sqliteExprType(Expr*); int sqliteExprCompare(Expr*, Expr*); int sqliteFuncId(Token*); | > | 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 | void sqliteExprIfFalse(Parse*, Expr*, int, int); Table *sqliteFindTable(sqlite*,const char*, const char*); Table *sqliteLocateTable(Parse*,const char*, const char*); 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*); int sqliteExprCheck(Parse*, Expr*, int, int*); int sqliteExprType(Expr*); int sqliteExprCompare(Expr*, Expr*); int sqliteFuncId(Token*); |
︙ | ︙ |
Changes to src/vacuum.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains code used to implement the VACUUM command. ** ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains code used to implement the VACUUM command. ** ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. ** ** $Id: vacuum.c,v 1.9 2003/12/07 00:24:35 drh Exp $ */ #include "sqliteInt.h" #include "os.h" /* ** A structure for holding a dynamic string - a string that can grow ** without bound. |
︙ | ︙ | |||
33 34 35 36 37 38 39 | /* ** A structure that holds the vacuum context */ typedef struct vacuumStruct vacuumStruct; struct vacuumStruct { sqlite *dbOld; /* Original database */ sqlite *dbNew; /* New database */ | > | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /* ** A structure that holds the vacuum context */ typedef struct vacuumStruct vacuumStruct; struct vacuumStruct { sqlite *dbOld; /* Original database */ sqlite *dbNew; /* New database */ 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 */ }; #if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM /* |
︙ | ︙ | |||
81 82 83 84 85 86 87 | appendText(p, &zText[j], i-j); } appendText(p, "'", 1); } /* ** Execute statements of SQL. If an error occurs, write the error | | | < > | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | appendText(p, &zText[j], i-j); } appendText(p, "'", 1); } /* ** Execute statements of SQL. If an error occurs, write the error ** message into *pzErrMsg and return non-zero. */ 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( zErrMsg ){ sqliteSetString(pzErrMsg, zErrMsg, (char*)0); sqlite_freemem(zErrMsg); } return rc; } /* ** This is the second stage callback. Each invocation contains all the |
︙ | ︙ | |||
122 123 124 125 126 127 128 | if( argv[i]==0 ){ appendText(&p->s2, "NULL", 4); }else{ appendQuoted(&p->s2, argv[i]); } } appendText(&p->s2,")", 1); | | | | > | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | if( argv[i]==0 ){ appendText(&p->s2, "NULL", 4); }else{ appendQuoted(&p->s2, argv[i]); } } appendText(&p->s2,")", 1); rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z); return rc; } /* ** This is the first stage callback. Each invocation contains three ** arguments where are taken from the SQLITE_MASTER table of the original ** database: (1) the entry type, (2) the entry name, and (3) the SQL for ** the entry. In all cases, execute the SQL of the third argument. ** For tables, run a query to select all entries in that table and ** transfer them to the second-stage callback. */ static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){ vacuumStruct *p = (vacuumStruct*)pArg; int rc = 0; assert( argc==3 ); if( argv==0 ) return 0; assert( argv[0]!=0 ); assert( argv[1]!=0 ); assert( argv[2]!=0 ); rc = execsql(p->pzErrMsg, p->dbNew, argv[2]); if( rc==SQLITE_OK && strcmp(argv[0],"table")==0 ){ char *zErrMsg = 0; p->s1.nUsed = 0; appendText(&p->s1, "SELECT * FROM ", -1); appendQuoted(&p->s1, argv[1]); p->zTable = argv[1]; rc = sqlite_exec(p->dbOld, p->s1.z, vacuumCallback2, p, &zErrMsg); if( zErrMsg ){ sqliteSetString(p->pzErrMsg, zErrMsg, (char*)0); sqlite_freemem(zErrMsg); } } return rc; } /* ** This callback is used to transfer PRAGMA settings from one database ** to the other. The value in argv[0] should be passed to a pragma ** identified by ((vacuumStruct*)pArg)->zPragma. */ static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){ vacuumStruct *p = (vacuumStruct*)pArg; int rc = 0; char zBuf[200]; assert( argc==1 ); if( argv==0 ) return 0; assert( argv[0]!=0 ); assert( strlen(p->zPragma)<100 ); assert( strlen(argv[0])<30 ); sprintf(zBuf,"PRAGMA %s=%s;", p->zPragma, argv[0]); rc = execsql(p->pzErrMsg, p->dbNew, zBuf); return rc; } /* ** Generate a random name of 20 character in length. */ static void randomName(char *zBuf){ |
︙ | ︙ | |||
202 203 204 205 206 207 208 209 210 211 212 213 | ** ** In version 1.0.x of SQLite, the VACUUM command would call ** gdbm_reorganize() on all the database tables. But beginning ** with 2.0.0, SQLite no longer uses GDBM so this command has ** become a no-op. */ void sqliteVacuum(Parse *pParse, Token *pTableName){ #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 */ | > > > > > > > > > < | < < < < < < < | > | | | | | | | < < < < < | | > | | > | > > > > | | < | | > < < | < < > | | 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 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | ** ** In version 1.0.x of SQLite, the VACUUM command would call ** gdbm_reorganize() on all the database tables. But beginning ** with 2.0.0, SQLite no longer uses GDBM so this command has ** 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 */ int rc = SQLITE_OK; /* Return code from service routines */ int i; /* Loop counter */ char *zErrMsg; /* Error message */ vacuumStruct sVac; /* Information passed to callbacks */ /* These are all of the pragmas that need to be transferred over ** to the new database */ static const char *zPragma[] = { "default_synchronous", "default_cache_size", /* "default_temp_store", */ }; if( db->flags & SQLITE_InTrans ){ sqliteSetString(pzErrMsg, "cannot VACUUM from within a transaction", (char*)0); return SQLITE_ERROR; } memset(&sVac, 0, sizeof(sVac)); /* Get the full pathname of the database file and create two ** temporary filenames in the same directory as the original file. */ zFilename = sqliteBtreeGetFilename(db->aDb[0].pBt); if( zFilename==0 ){ /* This only happens with the in-memory database. VACUUM is a no-op ** there, so just return */ return SQLITE_OK; } nFilename = strlen(zFilename); zTemp = sqliteMalloc( nFilename+100 ); if( zTemp==0 ) return SQLITE_NOMEM; strcpy(zTemp, zFilename); for(i=0; i<10; i++){ zTemp[nFilename] = '-'; randomName(&zTemp[nFilename+1]); if( !sqliteOsFileExists(zTemp) ) break; } if( i>=10 ){ 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 ){ sqliteSetString(pzErrMsg, "unable to open a temporary database at ", zTemp, " - ", zErrMsg, (char*)0); goto end_of_vacuum; } 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.pzErrMsg = pzErrMsg; for(i=0; rc==SQLITE_OK && i<sizeof(zPragma)/sizeof(zPragma[0]); i++){ char zBuf[200]; assert( strlen(zPragma[i])<100 ); sprintf(zBuf, "PRAGMA %s;", zPragma[i]); sVac.zPragma = zPragma[i]; rc = sqlite_exec(db, zBuf, vacuumCallback3, &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==SQLITE_OK ){ rc = sqliteBtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt); sqlite_exec(db, "COMMIT", 0, 0, 0); sqliteResetInternalSchema(db, 0); } end_of_vacuum: 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); if( rc==SQLITE_ABORT ) rc = SQLITE_ERROR; return rc; #endif } |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** 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.244 2003/12/07 00:24:35 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 | } tos = ++p->tos; zStack[tos] = sqliteHashKey(pSet->prev); aStack[tos].n = sqliteHashKeysize(pSet->prev); aStack[tos].flags = STK_Str | STK_Ephem; break; } /* An other opcode is illegal... */ default: { sprintf(zBuf,"%d",pOp->opcode); sqliteSetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0); rc = SQLITE_INTERNAL; | > > > > > > > > > > > > > | 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 | } tos = ++p->tos; zStack[tos] = sqliteHashKey(pSet->prev); aStack[tos].n = sqliteHashKeysize(pSet->prev); aStack[tos].flags = STK_Str | STK_Ephem; 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: { sprintf(zBuf,"%d",pOp->opcode); sqliteSetString(&p->zErrMsg, "unknown opcode ", zBuf, (char*)0); rc = SQLITE_INTERNAL; |
︙ | ︙ |
Changes to test/auth.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # 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. # | | | 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: auth.test,v 1.12 2003/12/07 00:24:35 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # disable this test if the SQLITE_OMIT_AUTHORIZATION macro is # defined during compilation. |
︙ | ︙ | |||
1767 1768 1769 1770 1771 1772 1773 | if {$code=="SQLITE_SELECT"} { return bogus } return SQLITE_OK } 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}} | | | | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 | if {$code=="SQLITE_SELECT"} { return bogus } return SQLITE_OK } 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.1 { proc auth {code arg1 arg2 arg3 arg4} { if {$code=="SQLITE_READ" && $arg2=="a"} { return SQLITE_IGNORE } return SQLITE_OK } catchsql {SELECT * FROM t2, t3} } {0 {{} 2 33 44 55 66 {} 8 9 44 55 66}} do_test auth-2.11.2 { proc auth {code arg1 arg2 arg3 arg4} { if {$code=="SQLITE_READ" && $arg2=="x"} { return SQLITE_IGNORE } return SQLITE_OK } catchsql {SELECT * FROM t2, t3} |
︙ | ︙ |
Changes to test/vacuum.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # | | < | 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 | # 2001 September 15 # # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # # $Id: vacuum.test,v 1.14 2003/12/07 00:24:35 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl 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 } set cksum [string length $txt]-[md5 $txt] # puts $cksum-[file size test.db] return $cksum } do_test vacuum-1.1 { execsql { BEGIN; CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO t1 VALUES(NULL,randstr(10,100),randstr(5,50)); INSERT INTO t1 VALUES(123456,randstr(10,100),randstr(5,50)); INSERT INTO t1 SELECT NULL, b||'-'||rowid, c||'-'||rowid FROM t1; |
︙ | ︙ | |||
132 133 134 135 136 137 138 | PRAGMA empty_result_callbacks=on; VACUUM; } } {} # Ticket #464. Make sure VACUUM works with the sqlite_compile() API. # | < | > > | > | > > > > > > > > > > > > > > > > > > > > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | PRAGMA empty_result_callbacks=on; VACUUM; } } {} # Ticket #464. Make sure VACUUM works with the sqlite_compile() API. # do_test vacuum-4.1 { db close set DB [sqlite db test.db] set VM [sqlite_compile $DB {VACUUM} TAIL] sqlite_step $VM N VALUES COLNAMES } {SQLITE_DONE} do_test vacuum-4.2 { sqlite_finalize $VM } {} # 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 |