Merge the VACUUM attached database enhancement from trunk.
FossilOrigin-Name: 12d5e38d269ede27cd38a031a395915301fffe56
This commit is contained in:
commit
05a41ee9ec
30
manifest
30
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\sSQLITE_DBCONFIG_MAINDBNAME\sinterface.
|
||||
D 2016-08-18T22:44:22.865
|
||||
C Merge\sthe\sVACUUM\sattached\sdatabase\senhancement\sfrom\strunk.
|
||||
D 2016-08-19T15:17:51.033
|
||||
F Makefile.in cfd8fb987cd7a6af046daa87daa146d5aad0e088
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
|
||||
@ -331,7 +331,7 @@ F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 2551bd3ecb8b8988fb8b23aabadfb214dbc38e46
|
||||
F src/btree.h 075c45707c0f8f8af118f739f36df8098a08b7da
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c c38fd92a8d886a5b9397267bf63b76ebad05c4d5
|
||||
F src/build.c d32cacbb59a403b68e1c2ec962ca31b6f3aad4fc
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c e77f3dc297b4b65c96da78b4ae4272fdfae863d7
|
||||
@ -346,7 +346,7 @@ F src/global.c c45ea22aff29334f6a9ec549235ac3357c970015
|
||||
F src/hash.c 55b5fb474100cee0b901edaf203e26c970940f36
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/insert.c d5cd8315c0577e86e17dda9239b45cffa81022c0
|
||||
F src/insert.c a255eb795cf475e7a0659297144fc80f70eb4e30
|
||||
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
|
||||
F src/loadext.c dd7a2b77902cc66c22555aef02e1a682554b7aec
|
||||
F src/main.c 4dba24a78c9797c4005521107905f42217668b86
|
||||
@ -373,13 +373,13 @@ F src/os_win.c 520f23475f1de530c435d30b67b7b15fe90874b0
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 40928c450320da78bb4bd3ae82818f4239e19b7e
|
||||
F src/pager.h 966d2769e76ae347c8a32c4165faf6e6cb64546d
|
||||
F src/parse.y 99b676e6fc2f4e331ab93e76b3987cffdbd28efa
|
||||
F src/parse.y ed6990c2d41eb0302eda90d5009c51fec792c850
|
||||
F src/pcache.c 5583c8ade4b05075a60ba953ef471d1c1a9c05df
|
||||
F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
|
||||
F src/pcache1.c 4bb7a6a5300c67d0b033d25adb509c120c03e812
|
||||
F src/pragma.c d932ba278654617cdd281f88a790a3185fca7c44
|
||||
F src/pragma.h 64c78a648751b9f4f297276c4eb7507b14b4628c
|
||||
F src/prepare.c a668988f324961397305b8352cf6bd87776fb347
|
||||
F src/prepare.c 0fcf16eaacc90c1059055519a76b75b516a59a88
|
||||
F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c d67b9a5cc33339256e2088c5a722745fc2ff5219
|
||||
@ -389,7 +389,7 @@ F src/shell.c 79dda477be6c96eba6e952a934957ad36f87acc7
|
||||
F src/sqlite.h.in 4a030e254e204570444b34bf7d40fb4a5416089e
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
|
||||
F src/sqliteInt.h f81e279da1bae217d9afcc60d5580a0d4615727e
|
||||
F src/sqliteInt.h 153099746007418dfa03a99c8355c8d47b0a1cc9
|
||||
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
|
||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||
@ -449,8 +449,8 @@ F src/trigger.c 11e20b3b12c847b3b9055594c0f1631266bb53fc
|
||||
F src/update.c 8179e699dbd45b92934fd02d3d8e3732e8da8802
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d
|
||||
F src/vacuum.c f6f10c88f8af5feb6b3632e5e4133e4482819c4f
|
||||
F src/vdbe.c 6242a21f22a68899db5e758c69a32cad163585e2
|
||||
F src/vacuum.c 913970b9d86dd6c2b8063ef1af421880f1464ec3
|
||||
F src/vdbe.c 15376952b0c5dc0afbac6cd8791579dd19ff0a01
|
||||
F src/vdbe.h 67bc551f7faf04c33493892e4b378aada823ed10
|
||||
F src/vdbeInt.h c59381049af5c7751a83456c39b80d1a6fde1f9d
|
||||
F src/vdbeapi.c a32d61b7dd05e6890d8fd44d2805f55e2f5ba9f3
|
||||
@ -655,7 +655,7 @@ F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
|
||||
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
||||
F test/e_uri.test 25385396082b67fd02ae0038b95a3b3575fe0519
|
||||
F test/e_vacuum.test 120f29ea56bdce4d43279527ece894ab5d1729d3
|
||||
F test/e_vacuum.test 9e5e47e4059a779c777f47e0f560fc82c99336df
|
||||
F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625
|
||||
F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8
|
||||
F test/e_walckpt.test 28c371a6bb5e5fe7f31679c1df1763a19d19e8a0
|
||||
@ -1327,6 +1327,7 @@ F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b
|
||||
F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
||||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/vacuum5.test 99d4a0629252f9ef2fc642caefe92436a744db3a
|
||||
F test/vacuummem.test e53a3fdca4612a99c515e1afe7934728a2383764
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
@ -1510,10 +1511,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P cb9865e14db1c0076618f13400151112f84960cb
|
||||
R 2f06ec82e9a3f57e0b8d261a230c1531
|
||||
T *branch * dbconfig_maindbname
|
||||
T *sym-dbconfig_maindbname *
|
||||
T -sym-trunk *
|
||||
P d6e3d5796c9991ca0af45ed92ce36f55efc02348 083f9e6270fa4faa402b91231271da4f3915c79f
|
||||
R a6e4b4d3ce0ef3f2cf848bb14d9b8323
|
||||
U drh
|
||||
Z 8066580a45fc98ac9d9fef6e64c8a3cf
|
||||
Z 52253f5e7188c5e562d511d2d515cb7a
|
||||
|
@ -1 +1 @@
|
||||
d6e3d5796c9991ca0af45ed92ce36f55efc02348
|
||||
12d5e38d269ede27cd38a031a395915301fffe56
|
@ -773,7 +773,7 @@ int sqlite3TwoPartName(
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
assert( db->init.iDb==0 || db->init.busy );
|
||||
assert( db->init.iDb==0 || db->init.busy || (db->flags & SQLITE_Vacuum)!=0);
|
||||
iDb = db->init.iDb;
|
||||
*pUnqual = pName1;
|
||||
}
|
||||
@ -2011,7 +2011,7 @@ void sqlite3EndTable(
|
||||
/* Check to see if we need to create an sqlite_sequence table for
|
||||
** keeping track of autoincrement keys.
|
||||
*/
|
||||
if( p->tabFlags & TF_Autoincrement ){
|
||||
if( (p->tabFlags & TF_Autoincrement)!=0 ){
|
||||
Db *pDb = &db->aDb[iDb];
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
if( pDb->pSchema->pSeqTab==0 ){
|
||||
|
@ -200,7 +200,9 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
|
||||
/*
|
||||
** Locate or create an AutoincInfo structure associated with table pTab
|
||||
** which is in database iDb. Return the register number for the register
|
||||
** that holds the maximum rowid.
|
||||
** that holds the maximum rowid. Return zero if pTab is not an AUTOINCREMENT
|
||||
** table. (Also return zero when doing a VACUUM since we do not want to
|
||||
** update the AUTOINCREMENT counters during a VACUUM.)
|
||||
**
|
||||
** There is at most one AutoincInfo structure per table even if the
|
||||
** same table is autoincremented multiple times due to inserts within
|
||||
@ -223,7 +225,9 @@ static int autoIncBegin(
|
||||
Table *pTab /* The table we are writing to */
|
||||
){
|
||||
int memId = 0; /* Register holding maximum rowid */
|
||||
if( pTab->tabFlags & TF_Autoincrement ){
|
||||
if( (pTab->tabFlags & TF_Autoincrement)!=0
|
||||
&& (pParse->db->flags & SQLITE_Vacuum)==0
|
||||
){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
AutoincInfo *pInfo;
|
||||
|
||||
|
@ -1285,8 +1285,8 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
|
||||
//
|
||||
%ifndef SQLITE_OMIT_VACUUM
|
||||
%ifndef SQLITE_OMIT_ATTACH
|
||||
cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
|
||||
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
|
||||
cmd ::= VACUUM. {sqlite3Vacuum(pParse,0);}
|
||||
cmd ::= VACUUM nm(X). {sqlite3Vacuum(pParse,&X);}
|
||||
%endif SQLITE_OMIT_ATTACH
|
||||
%endif SQLITE_OMIT_VACUUM
|
||||
|
||||
|
@ -73,6 +73,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
** structures that describe the table, index, or view.
|
||||
*/
|
||||
int rc;
|
||||
u8 saved_iDb = db->init.iDb;
|
||||
sqlite3_stmt *pStmt;
|
||||
TESTONLY(int rcp); /* Return code from sqlite3_prepare() */
|
||||
|
||||
@ -83,7 +84,8 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
|
||||
TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
|
||||
rc = db->errCode;
|
||||
assert( (rc&0xFF)==(rcp&0xFF) );
|
||||
db->init.iDb = 0;
|
||||
db->init.iDb = saved_iDb;
|
||||
assert( saved_iDb==0 || (db->flags & SQLITE_Vacuum)!=0 );
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( db->init.orphanTrigger ){
|
||||
assert( iDb==1 );
|
||||
|
@ -3701,8 +3701,8 @@ Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
|
||||
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
||||
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
void sqlite3Vacuum(Parse*);
|
||||
int sqlite3RunVacuum(char**, sqlite3*);
|
||||
void sqlite3Vacuum(Parse*,Token*);
|
||||
int sqlite3RunVacuum(char**, sqlite3*, int);
|
||||
char *sqlite3NameFromToken(sqlite3*, Token*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*, int);
|
||||
int sqlite3ExprListCompare(ExprList*, ExprList*, int);
|
||||
|
186
src/vacuum.c
186
src/vacuum.c
@ -18,57 +18,52 @@
|
||||
#include "vdbeInt.h"
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/*
|
||||
** Finalize a prepared statement. If there was an error, store the
|
||||
** text of the error message in *pzErrMsg. Return the result code.
|
||||
*/
|
||||
static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
|
||||
int rc;
|
||||
rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
|
||||
if( rc ){
|
||||
sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. Return an error code.
|
||||
** Execute zSql on database db.
|
||||
**
|
||||
** If zSql returns rows, then each row will have exactly one
|
||||
** column. (This will only happen if zSql begins with "SELECT".)
|
||||
** Take each row of result and call execSql() again recursively.
|
||||
**
|
||||
** The execSqlF() routine does the same thing, except it accepts
|
||||
** a format string as its third argument
|
||||
*/
|
||||
static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
VVA_ONLY( int rc; )
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
|
||||
sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
|
||||
return sqlite3_errcode(db);
|
||||
}
|
||||
VVA_ONLY( rc = ) sqlite3_step(pStmt);
|
||||
assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) );
|
||||
return vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Execute zSql on database db. The statement returns exactly
|
||||
** one column. Execute this as SQL on the same database.
|
||||
*/
|
||||
static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
||||
sqlite3_stmt *pStmt;
|
||||
int rc;
|
||||
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
|
||||
/* printf("SQL: [%s]\n", zSql); fflush(stdout); */
|
||||
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
||||
rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
|
||||
if( rc!=SQLITE_OK ){
|
||||
vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
return rc;
|
||||
while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
|
||||
const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
|
||||
assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
|
||||
if( zSubSql ){
|
||||
assert( zSubSql[0]!='S' );
|
||||
rc = execSql(db, pzErrMsg, zSubSql);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
}
|
||||
}
|
||||
|
||||
return vacuumFinalize(db, pStmt, pzErrMsg);
|
||||
assert( rc!=SQLITE_ROW );
|
||||
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
||||
if( rc ){
|
||||
sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
|
||||
}
|
||||
(void)sqlite3_finalize(pStmt);
|
||||
return rc;
|
||||
}
|
||||
static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
|
||||
char *z;
|
||||
va_list ap;
|
||||
int rc;
|
||||
va_start(ap, zSql);
|
||||
z = sqlite3VMPrintf(db, zSql, ap);
|
||||
va_end(ap);
|
||||
if( z==0 ) return SQLITE_NOMEM;
|
||||
rc = execSql(db, pzErrMsg, z);
|
||||
sqlite3DbFree(db, z);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -101,11 +96,12 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
||||
** transient would cause the database file to appear to be deleted
|
||||
** following reboot.
|
||||
*/
|
||||
void sqlite3Vacuum(Parse *pParse){
|
||||
void sqlite3Vacuum(Parse *pParse, Token *pNm){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
|
||||
sqlite3VdbeUsesBtree(v, 0);
|
||||
int iDb = pNm ? sqlite3TwoPartName(pParse, pNm, pNm, &pNm) : 0;
|
||||
if( v && (iDb>=2 || iDb==0) ){
|
||||
sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -113,11 +109,10 @@ void sqlite3Vacuum(Parse *pParse){
|
||||
/*
|
||||
** This routine implements the OP_Vacuum opcode of the VDBE.
|
||||
*/
|
||||
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
|
||||
int rc = SQLITE_OK; /* Return code from service routines */
|
||||
Btree *pMain; /* The database being vacuumed */
|
||||
Btree *pTemp; /* The temporary database we vacuum into */
|
||||
char *zSql = 0; /* SQL statements */
|
||||
int saved_flags; /* Saved value of the db->flags */
|
||||
int saved_nChange; /* Saved value of db->nChange */
|
||||
int saved_nTotalChange; /* Saved value of db->nTotalChange */
|
||||
@ -126,6 +121,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
int isMemDb; /* True if vacuuming a :memory: database */
|
||||
int nRes; /* Bytes of reserved space at the end of each page */
|
||||
int nDb; /* Number of attached databases */
|
||||
const char *zDbMain; /* Schema name of database to vacuum */
|
||||
|
||||
if( !db->autoCommit ){
|
||||
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
|
||||
@ -143,11 +139,13 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
saved_nChange = db->nChange;
|
||||
saved_nTotalChange = db->nTotalChange;
|
||||
saved_mTrace = db->mTrace;
|
||||
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
|
||||
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
|
||||
db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
|
||||
| SQLITE_PreferBuiltin | SQLITE_Vacuum);
|
||||
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
|
||||
db->mTrace = 0;
|
||||
|
||||
pMain = db->aDb[0].pBt;
|
||||
zDbMain = db->aDb[iDb].zDbSName;
|
||||
pMain = db->aDb[iDb].pBt;
|
||||
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
|
||||
|
||||
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
|
||||
@ -165,18 +163,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
** to write the journal header file.
|
||||
*/
|
||||
nDb = db->nDb;
|
||||
if( sqlite3TempInMemory(db) ){
|
||||
zSql = "ATTACH ':memory:' AS vacuum_db;";
|
||||
}else{
|
||||
zSql = "ATTACH '' AS vacuum_db;";
|
||||
}
|
||||
rc = execSql(db, pzErrMsg, zSql);
|
||||
if( db->nDb>nDb ){
|
||||
pDb = &db->aDb[db->nDb-1];
|
||||
assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
|
||||
}
|
||||
rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
pTemp = db->aDb[db->nDb-1].pBt;
|
||||
assert( (db->nDb-1)==nDb );
|
||||
pDb = &db->aDb[nDb];
|
||||
assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
|
||||
pTemp = pDb->pBt;
|
||||
|
||||
/* The call to execSql() to attach the temp database has left the file
|
||||
** locked (as there was more than one active statement when the transaction
|
||||
@ -197,16 +189,15 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3BtreeSetCacheSize(pTemp, db->aDb[0].pSchema->cache_size);
|
||||
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
|
||||
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
|
||||
rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF);
|
||||
|
||||
/* Begin a transaction and take an exclusive lock on the main database
|
||||
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
|
||||
** to ensure that we do not try to change the page-size on a WAL database.
|
||||
*/
|
||||
rc = execSql(db, pzErrMsg, "BEGIN;");
|
||||
rc = execSql(db, pzErrMsg, "BEGIN");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = sqlite3BtreeBeginTrans(pMain, 2);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
@ -233,64 +224,48 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
/* Query the schema of the main database. Create a mirror schema
|
||||
** in the temporary database.
|
||||
*/
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14) "
|
||||
" FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
|
||||
" AND coalesce(rootpage,1)>0"
|
||||
db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"SELECT sql FROM \"%w\".sqlite_master"
|
||||
" WHERE type='table'AND name<>'sqlite_sequence'"
|
||||
" AND coalesce(rootpage,1)>0",
|
||||
zDbMain
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
|
||||
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"SELECT sql FROM \"%w\".sqlite_master"
|
||||
" WHERE type='index' AND length(sql)>10",
|
||||
zDbMain
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
db->init.iDb = 0;
|
||||
|
||||
/* Loop through the tables in the main database. For each, do
|
||||
** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
|
||||
** the contents to the temporary database.
|
||||
*/
|
||||
assert( (db->flags & SQLITE_Vacuum)==0 );
|
||||
db->flags |= SQLITE_Vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';'"
|
||||
"FROM main.sqlite_master "
|
||||
"WHERE type = 'table' AND name!='sqlite_sequence' "
|
||||
" AND coalesce(rootpage,1)>0"
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
|
||||
"||' SELECT*FROM\"%w\".'||quote(name)"
|
||||
"FROM vacuum_db.sqlite_master "
|
||||
"WHERE type='table'AND coalesce(rootpage,1)>0",
|
||||
zDbMain
|
||||
);
|
||||
assert( (db->flags & SQLITE_Vacuum)!=0 );
|
||||
db->flags &= ~SQLITE_Vacuum;
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
/* Copy over the sequence table
|
||||
*/
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
|
||||
"FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
rc = execExecSql(db, pzErrMsg,
|
||||
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
|
||||
"|| ' SELECT * FROM main.' || quote(name) || ';' "
|
||||
"FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
|
||||
);
|
||||
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
||||
|
||||
|
||||
/* Copy the triggers, views, and virtual tables from the main database
|
||||
** over to the temporary database. None of these objects has any
|
||||
** associated storage, so all we have to do is copy their entries
|
||||
** from the SQLITE_MASTER table.
|
||||
*/
|
||||
rc = execSql(db, pzErrMsg,
|
||||
"INSERT INTO vacuum_db.sqlite_master "
|
||||
" SELECT type, name, tbl_name, rootpage, sql"
|
||||
" FROM main.sqlite_master"
|
||||
" WHERE type='view' OR type='trigger'"
|
||||
" OR (type='table' AND rootpage=0)"
|
||||
rc = execSqlF(db, pzErrMsg,
|
||||
"INSERT INTO vacuum_db.sqlite_master"
|
||||
" SELECT*FROM \"%w\".sqlite_master"
|
||||
" WHERE type IN('view','trigger')"
|
||||
" OR(type='table'AND rootpage=0)",
|
||||
zDbMain
|
||||
);
|
||||
if( rc ) goto end_of_vacuum;
|
||||
|
||||
@ -344,6 +319,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
||||
|
||||
end_of_vacuum:
|
||||
/* Restore the original value of db->flags */
|
||||
db->init.iDb = 0;
|
||||
db->flags = saved_flags;
|
||||
db->nChange = saved_nChange;
|
||||
db->nTotalChange = saved_nTotalChange;
|
||||
|
@ -6262,15 +6262,14 @@ case OP_JournalMode: { /* out2 */
|
||||
#endif /* SQLITE_OMIT_PRAGMA */
|
||||
|
||||
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
|
||||
/* Opcode: Vacuum * * * * *
|
||||
/* Opcode: Vacuum P1 * * * *
|
||||
**
|
||||
** 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.
|
||||
** Vacuum the entire database P1. P1 is 0 for "main", and 2 or more
|
||||
** for an attached database. The "temp" database may not be vacuumed.
|
||||
*/
|
||||
case OP_Vacuum: {
|
||||
assert( p->readOnly==0 );
|
||||
rc = sqlite3RunVacuum(&p->zErrMsg, db);
|
||||
rc = sqlite3RunVacuum(&p->zErrMsg, db, pOp->p1);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
break;
|
||||
}
|
||||
|
@ -202,12 +202,8 @@ do_execsql_test e_vacuum-2.1.1 {
|
||||
} {}
|
||||
set original_size [file size test.db2]
|
||||
|
||||
# Try everything we can think of to get the aux database vacuumed:
|
||||
# Vacuuming the main database does not affect aux
|
||||
do_execsql_test e_vacuum-2.1.3 { VACUUM } {}
|
||||
do_execsql_test e_vacuum-2.1.4 { VACUUM aux } {}
|
||||
do_execsql_test e_vacuum-2.1.5 { VACUUM 'test.db2' } {}
|
||||
|
||||
# Despite our efforts, space in the aux database has not been reclaimed:
|
||||
do_test e_vacuum-2.1.6 { expr {[file size test.db2]==$::original_size} } 1
|
||||
|
||||
# EVIDENCE-OF: R-17495-17419 The VACUUM command may change the ROWIDs of
|
||||
|
111
test/vacuum5.test
Normal file
111
test/vacuum5.test
Normal file
@ -0,0 +1,111 @@
|
||||
# 2016-08-19
|
||||
#
|
||||
# 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 a test for VACUUM on attached databases.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# If the VACUUM statement is disabled in the current build, skip all
|
||||
# the tests in this file.
|
||||
#
|
||||
ifcapable !vacuum {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
forcedelete test2.db test3.db
|
||||
do_execsql_test vacuum5-1.1 {
|
||||
CREATE TABLE main.t1(a,b);
|
||||
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000)
|
||||
INSERT INTO t1(a,b) SELECT x, randomblob(1000) FROM c;
|
||||
CREATE TEMP TABLE ttemp(x,y);
|
||||
INSERT INTO ttemp SELECT * FROM t1;
|
||||
ATTACH 'test2.db' AS x2;
|
||||
ATTACH 'test3.db' AS x3;
|
||||
CREATE TABLE x2.t2(c,d);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
CREATE TABLE x3.t3(e,f);
|
||||
INSERT INTO t3 SELECT * FROM t1;
|
||||
DELETE FROM t1 WHERE (rowid%3)!=0;
|
||||
DELETE FROM t2 WHERE (rowid%4)!=0;
|
||||
DELETE FROM t3 WHERE (rowid%5)!=0;
|
||||
PRAGMA main.integrity_check;
|
||||
PRAGMA x2.integrity_check;
|
||||
PRAGMA x3.integrity_check;
|
||||
} {ok ok ok}
|
||||
set size1 [file size test.db]
|
||||
set size2 [file size test2.db]
|
||||
set size3 [file size test3.db]
|
||||
|
||||
do_execsql_test vacuum5-1.2.1 {
|
||||
VACUUM main;
|
||||
} {}
|
||||
do_test vacuum5-1.2.2 {
|
||||
expr {[file size test.db]<$size1}
|
||||
} {1}
|
||||
do_test vacuum5-1.2.3 {
|
||||
file size test2.db
|
||||
} $size2
|
||||
do_test vacuum5-1.2.4 {
|
||||
file size test3.db
|
||||
} $size3
|
||||
set size1 [file size test.db]
|
||||
do_execsql_test vacuum-1.2.5 {
|
||||
DELETE FROM t1;
|
||||
PRAGMA main.integrity_check;
|
||||
} {ok}
|
||||
|
||||
do_execsql_test vacuum5-1.3.1 {
|
||||
VACUUM x2;
|
||||
} {}
|
||||
do_test vacuum5-1.3.2 {
|
||||
file size test.db
|
||||
} $size1
|
||||
do_test vacuum5-1.3.3 {
|
||||
expr {[file size test2.db]<$size2}
|
||||
} 1
|
||||
do_test vacuum5-1.3.4 {
|
||||
file size test3.db
|
||||
} $size3
|
||||
set size2 [file size test2.db]
|
||||
do_execsql_test vacuum-1.3.5 {
|
||||
DELETE FROM t2;
|
||||
PRAGMA x2.integrity_check;
|
||||
} {ok}
|
||||
|
||||
do_execsql_test vacuum5-1.4.1 {
|
||||
VACUUM x3;
|
||||
} {}
|
||||
do_test vacuum5-1.3.2 {
|
||||
file size test.db
|
||||
} $size1
|
||||
do_test vacuum5-1.3.3 {
|
||||
file size test2.db
|
||||
} $size2
|
||||
do_test vacuum5-1.3.4 {
|
||||
expr {[file size test3.db]<$size3}
|
||||
} 1
|
||||
|
||||
# VACUUM is a no-op on the TEMP table
|
||||
#
|
||||
set sizeTemp [db one {PRAGMA temp.page_count}]
|
||||
do_execsql_test vacuum5-1.4.1 {
|
||||
VACUUM temp;
|
||||
} {}
|
||||
do_execsql_test vacuum5-1.4.2 {
|
||||
PRAGMA temp.page_count;
|
||||
} $sizeTemp
|
||||
|
||||
do_catchsql_test vacuum5-2.0 {
|
||||
VACUUM olaf;
|
||||
} {1 {unknown database olaf}}
|
Loading…
x
Reference in New Issue
Block a user