xref: /sqlite-3.40.0/src/vacuum.c (revision 80b30f99)
1c11d4f93Sdrh /*
2c11d4f93Sdrh ** 2003 April 6
3c11d4f93Sdrh **
4c11d4f93Sdrh ** The author disclaims copyright to this source code.  In place of
5c11d4f93Sdrh ** a legal notice, here is a blessing:
6c11d4f93Sdrh **
7c11d4f93Sdrh **    May you do good and not evil.
8c11d4f93Sdrh **    May you find forgiveness for yourself and forgive others.
9c11d4f93Sdrh **    May you share freely, never taking more than you give.
10c11d4f93Sdrh **
11c11d4f93Sdrh *************************************************************************
12c11d4f93Sdrh ** This file contains code used to implement the VACUUM command.
13c11d4f93Sdrh **
14c11d4f93Sdrh ** Most of the code in this file may be omitted by defining the
15c11d4f93Sdrh ** SQLITE_OMIT_VACUUM macro.
16c11d4f93Sdrh */
17c11d4f93Sdrh #include "sqliteInt.h"
18f4208043Sdanielk1977 #include "vdbeInt.h"
19c11d4f93Sdrh 
20fdbcdee5Sdrh #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
21cda455b7Sdrh 
22cda455b7Sdrh /*
239ef5e770Sdrh ** Execute zSql on database db.
249ef5e770Sdrh **
256a754dc7Sdrh ** If zSql returns rows, then each row will have exactly one
266a754dc7Sdrh ** column.  (This will only happen if zSql begins with "SELECT".)
276a754dc7Sdrh ** Take each row of result and call execSql() again recursively.
289ef5e770Sdrh **
299ef5e770Sdrh ** The execSqlF() routine does the same thing, except it accepts
309ef5e770Sdrh ** a format string as its third argument
313df6b257Sdanielk1977 */
execSql(sqlite3 * db,char ** pzErrMsg,const char * zSql)32cda455b7Sdrh static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
333df6b257Sdanielk1977   sqlite3_stmt *pStmt;
343df6b257Sdanielk1977   int rc;
353df6b257Sdanielk1977 
369ef5e770Sdrh   /* printf("SQL: [%s]\n", zSql); fflush(stdout); */
379ef5e770Sdrh   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
383df6b257Sdanielk1977   if( rc!=SQLITE_OK ) return rc;
396a754dc7Sdrh   while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
409ef5e770Sdrh     const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
416a754dc7Sdrh     assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
4234b27edcSdrh     /* The secondary SQL must be one of CREATE TABLE, CREATE INDEX,
4334b27edcSdrh     ** or INSERT.  Historically there have been attacks that first
441e32bed3Sdrh     ** corrupt the sqlite_schema.sql field with other kinds of statements
4534b27edcSdrh     ** then run VACUUM to get those statements to execute at inappropriate
4634b27edcSdrh     ** times. */
4734b27edcSdrh     if( zSubSql
4834b27edcSdrh      && (strncmp(zSubSql,"CRE",3)==0 || strncmp(zSubSql,"INS",3)==0)
4934b27edcSdrh     ){
509ef5e770Sdrh       rc = execSql(db, pzErrMsg, zSubSql);
519ef5e770Sdrh       if( rc!=SQLITE_OK ) break;
529ef5e770Sdrh     }
539ef5e770Sdrh   }
546a754dc7Sdrh   assert( rc!=SQLITE_ROW );
556a754dc7Sdrh   if( rc==SQLITE_DONE ) rc = SQLITE_OK;
569ef5e770Sdrh   if( rc ){
579ef5e770Sdrh     sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
589ef5e770Sdrh   }
599ef5e770Sdrh   (void)sqlite3_finalize(pStmt);
603df6b257Sdanielk1977   return rc;
613df6b257Sdanielk1977 }
execSqlF(sqlite3 * db,char ** pzErrMsg,const char * zSql,...)629ef5e770Sdrh static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
639ef5e770Sdrh   char *z;
649ef5e770Sdrh   va_list ap;
659ef5e770Sdrh   int rc;
669ef5e770Sdrh   va_start(ap, zSql);
679ef5e770Sdrh   z = sqlite3VMPrintf(db, zSql, ap);
689ef5e770Sdrh   va_end(ap);
699ef5e770Sdrh   if( z==0 ) return SQLITE_NOMEM;
709ef5e770Sdrh   rc = execSql(db, pzErrMsg, z);
719ef5e770Sdrh   sqlite3DbFree(db, z);
729ef5e770Sdrh   return rc;
733df6b257Sdanielk1977 }
743df6b257Sdanielk1977 
75c11d4f93Sdrh /*
768b8d28ddSdrh ** The VACUUM command is used to clean up the database,
77c11d4f93Sdrh ** collapse free space, etc.  It is modelled after the VACUUM command
788b8d28ddSdrh ** in PostgreSQL.  The VACUUM command works as follows:
79c11d4f93Sdrh **
808b8d28ddSdrh **   (1)  Create a new transient database file
818b8d28ddSdrh **   (2)  Copy all content from the database being vacuumed into
828b8d28ddSdrh **        the new transient database file
838b8d28ddSdrh **   (3)  Copy content from the transient database back into the
848b8d28ddSdrh **        original database.
858b8d28ddSdrh **
868b8d28ddSdrh ** The transient database requires temporary disk space approximately
878b8d28ddSdrh ** equal to the size of the original database.  The copy operation of
888b8d28ddSdrh ** step (3) requires additional temporary disk space approximately equal
898b8d28ddSdrh ** to the size of the original database for the rollback journal.
908b8d28ddSdrh ** Hence, temporary disk space that is approximately 2x the size of the
9160ec914cSpeter.d.reid ** original database is required.  Every page of the database is written
928b8d28ddSdrh ** approximately 3 times:  Once for step (2) and twice for step (3).
938b8d28ddSdrh ** Two writes per page are required in step (3) because the original
948b8d28ddSdrh ** database content must be written into the rollback journal prior to
958b8d28ddSdrh ** overwriting the database with the vacuumed content.
968b8d28ddSdrh **
978b8d28ddSdrh ** Only 1x temporary space and only 1x writes would be required if
9886a11b8aSdrh ** the copy of step (3) were replaced by deleting the original database
998b8d28ddSdrh ** and renaming the transient database as the original.  But that will
1008b8d28ddSdrh ** not work if other processes are attached to the original database.
1018b8d28ddSdrh ** And a power loss in between deleting the original and renaming the
1028b8d28ddSdrh ** transient would cause the database file to appear to be deleted
1038b8d28ddSdrh ** following reboot.
104c11d4f93Sdrh */
sqlite3Vacuum(Parse * pParse,Token * pNm,Expr * pInto)1052f6239edSdrh void sqlite3Vacuum(Parse *pParse, Token *pNm, Expr *pInto){
1064adee20fSdanielk1977   Vdbe *v = sqlite3GetVdbe(pParse);
107eeea412aSdrh   int iDb = 0;
1082f6239edSdrh   if( v==0 ) goto build_vacuum_end;
10929e78006Sdrh   if( pParse->nErr ) goto build_vacuum_end;
110eeea412aSdrh   if( pNm ){
111eeea412aSdrh #ifndef SQLITE_BUG_COMPATIBLE_20160819
112eeea412aSdrh     /* Default behavior:  Report an error if the argument to VACUUM is
113eeea412aSdrh     ** not recognized */
114eeea412aSdrh     iDb = sqlite3TwoPartName(pParse, pNm, pNm, &pNm);
1152f6239edSdrh     if( iDb<0 ) goto build_vacuum_end;
116eeea412aSdrh #else
117eeea412aSdrh     /* When SQLITE_BUG_COMPATIBLE_20160819 is defined, unrecognized arguments
118eeea412aSdrh     ** to VACUUM are silently ignored.  This is a back-out of a bug fix that
119eeea412aSdrh     ** occurred on 2016-08-19 (https://www.sqlite.org/src/info/083f9e6270).
120eeea412aSdrh     ** The buggy behavior is required for binary compatibility with some
121eeea412aSdrh     ** legacy applications. */
122eeea412aSdrh     iDb = sqlite3FindDb(pParse->db, pNm);
123eeea412aSdrh     if( iDb<0 ) iDb = 0;
124eeea412aSdrh #endif
125eeea412aSdrh   }
126eeea412aSdrh   if( iDb!=1 ){
1272f6239edSdrh     int iIntoReg = 0;
128ee751fabSdrh     if( pInto && sqlite3ResolveSelfReference(pParse,0,0,pInto,0)==0 ){
1292f6239edSdrh       iIntoReg = ++pParse->nMem;
1302f6239edSdrh       sqlite3ExprCode(pParse, pInto, iIntoReg);
1312f6239edSdrh     }
1322f6239edSdrh     sqlite3VdbeAddOp2(v, OP_Vacuum, iDb, iIntoReg);
1339ef5e770Sdrh     sqlite3VdbeUsesBtree(v, iDb);
134b0b7db91Sdrh   }
1352f6239edSdrh build_vacuum_end:
1362f6239edSdrh   sqlite3ExprDelete(pParse->db, pInto);
1376f8c91caSdrh   return;
1386f8c91caSdrh }
1396f8c91caSdrh 
1406f8c91caSdrh /*
1416f8c91caSdrh ** This routine implements the OP_Vacuum opcode of the VDBE.
1426f8c91caSdrh */
sqlite3RunVacuum(char ** pzErrMsg,sqlite3 * db,int iDb,sqlite3_value * pOut)14367752575Sdrh SQLITE_NOINLINE int sqlite3RunVacuum(
1442f6239edSdrh   char **pzErrMsg,        /* Write error message here */
1452f6239edSdrh   sqlite3 *db,            /* Database connection */
1462f6239edSdrh   int iDb,                /* Which attached DB to vacuum */
147d0f820a7Sdrh   sqlite3_value *pOut     /* Write results here, if not NULL. VACUUM INTO */
1482f6239edSdrh ){
1493df6b257Sdanielk1977   int rc = SQLITE_OK;     /* Return code from service routines */
150f2a611c9Sdrh   Btree *pMain;           /* The database being vacuumed */
1510058d844Sdrh   Btree *pTemp;           /* The temporary database we vacuum into */
15270d5dfbaSdrh   u32 saved_mDbFlags;     /* Saved value of db->mDbFlags */
15370d5dfbaSdrh   u64 saved_flags;        /* Saved value of db->flags */
1542c718873Sdan   i64 saved_nChange;      /* Saved value of db->nChange */
1552c718873Sdan   i64 saved_nTotalChange; /* Saved value of db->nTotalChange */
156d0f820a7Sdrh   u32 saved_openFlags;    /* Saved value of db->openFlags */
1573d2a529dSdrh   u8 saved_mTrace;        /* Saved trace settings */
1580203bde9Sdanielk1977   Db *pDb = 0;            /* Database to detach at end of vacuum */
15943996e85Sdanielk1977   int isMemDb;            /* True if vacuuming a :memory: database */
160acd07818Sdrh   int nRes;               /* Bytes of reserved space at the end of each page */
161acd07818Sdrh   int nDb;                /* Number of attached databases */
1629ef5e770Sdrh   const char *zDbMain;    /* Schema name of database to vacuum */
1632f6239edSdrh   const char *zOut;       /* Name of output file */
164*80b30f99Sdan   u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
1653a3f38e0Sdanielk1977 
166663d56d4Sdrh   if( !db->autoCommit ){
167663d56d4Sdrh     sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
168eacc8816Sdrh     return SQLITE_ERROR; /* IMP: R-12218-18073 */
169663d56d4Sdrh   }
1704f7d3a5fSdrh   if( db->nVdbeActive>1 ){
171099d1470Sdan     sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
172eacc8816Sdrh     return SQLITE_ERROR; /* IMP: R-15610-35227 */
173099d1470Sdan   }
174d0f820a7Sdrh   saved_openFlags = db->openFlags;
1752f6239edSdrh   if( pOut ){
1762f6239edSdrh     if( sqlite3_value_type(pOut)!=SQLITE_TEXT ){
1772f6239edSdrh       sqlite3SetString(pzErrMsg, db, "non-text filename");
1782f6239edSdrh       return SQLITE_ERROR;
1792f6239edSdrh     }
1802f6239edSdrh     zOut = (const char*)sqlite3_value_text(pOut);
181d0f820a7Sdrh     db->openFlags &= ~SQLITE_OPEN_READONLY;
182d0f820a7Sdrh     db->openFlags |= SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE;
1832f6239edSdrh   }else{
1842f6239edSdrh     zOut = "";
1852f6239edSdrh   }
186663d56d4Sdrh 
18775cbd984Sdan   /* Save the current value of the database flags so that it can be
18875cbd984Sdan   ** restored before returning. Then set the writable-schema flag, and
18975cbd984Sdan   ** disable CHECK and foreign key constraints.  */
1900cd2d4c9Sdrh   saved_flags = db->flags;
19167752575Sdrh   saved_mDbFlags = db->mDbFlags;
192e63b2c21Sdrh   saved_nChange = db->nChange;
193e63b2c21Sdrh   saved_nTotalChange = db->nTotalChange;
1943d2a529dSdrh   saved_mTrace = db->mTrace;
1958257aa8dSdrh   db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
19667752575Sdrh   db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
197d5b44d60Sdrh   db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
1980f0d3ddfSdrh                    | SQLITE_Defensive | SQLITE_CountRows);
1991637a517Sdrh   db->mTrace = 0;
20045a304eeSdrh 
2019ef5e770Sdrh   zDbMain = db->aDb[iDb].zDbSName;
2029ef5e770Sdrh   pMain = db->aDb[iDb].pBt;
20343996e85Sdanielk1977   isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
2043df6b257Sdanielk1977 
20546c43eddSdanielk1977   /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
20646c43eddSdanielk1977   ** can be set to 'off' for this file, as it is not recovered if a crash
20746c43eddSdanielk1977   ** occurs anyway. The integrity of the database is maintained by a
20846c43eddSdanielk1977   ** (possibly synchronous) transaction opened on the main database before
20946c43eddSdanielk1977   ** sqlite3BtreeCopyFile() is called.
21046c43eddSdanielk1977   **
21146c43eddSdanielk1977   ** An optimisation would be to use a non-journaled pager.
21246979886Sdrh   ** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
21346979886Sdrh   ** that actually made the VACUUM run slower.  Very little journalling
21446979886Sdrh   ** actually occurs when doing a vacuum since the vacuum_db is initially
21546979886Sdrh   ** empty.  Only the journal header is written.  Apparently it takes more
21646979886Sdrh   ** time to parse and run the PRAGMA to turn journalling off than it does
21746979886Sdrh   ** to write the journal header file.
21846c43eddSdanielk1977   */
219acd07818Sdrh   nDb = db->nDb;
2202f6239edSdrh   rc = execSqlF(db, pzErrMsg, "ATTACH %Q AS vacuum_db", zOut);
221d0f820a7Sdrh   db->openFlags = saved_openFlags;
222acd07818Sdrh   if( rc!=SQLITE_OK ) goto end_of_vacuum;
2239ef5e770Sdrh   assert( (db->nDb-1)==nDb );
2249ef5e770Sdrh   pDb = &db->aDb[nDb];
2259ef5e770Sdrh   assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
2269ef5e770Sdrh   pTemp = pDb->pBt;
2272f6239edSdrh   if( pOut ){
2287464f578Sdrh     sqlite3_file *id = sqlite3PagerFile(sqlite3BtreePager(pTemp));
2297464f578Sdrh     i64 sz = 0;
2307464f578Sdrh     if( id->pMethods!=0 && (sqlite3OsFileSize(id, &sz)!=SQLITE_OK || sz>0) ){
2317464f578Sdrh       rc = SQLITE_ERROR;
2327464f578Sdrh       sqlite3SetString(pzErrMsg, db, "output file already exists");
2337464f578Sdrh       goto end_of_vacuum;
2347464f578Sdrh     }
23567752575Sdrh     db->mDbFlags |= DBFLAG_VacuumInto;
236*80b30f99Sdan 
237*80b30f99Sdan     /* For a VACUUM INTO, the pager-flags are set to the same values as
238*80b30f99Sdan     ** they are for the database being vacuumed, except that PAGER_CACHESPILL
239*80b30f99Sdan     ** is always set. */
240*80b30f99Sdan     pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK);
2417464f578Sdrh   }
24245248de3Sdrh   nRes = sqlite3BtreeGetRequestedReserve(pMain);
243cdb7a0feSdrh 
2449ef5e770Sdrh   sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
2459d608759Sdrh   sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
246*80b30f99Sdan   sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
247f602963dSdan 
248f602963dSdan   /* Begin a transaction and take an exclusive lock on the main database
249f602963dSdan   ** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
250f602963dSdan   ** to ensure that we do not try to change the page-size on a WAL database.
251f602963dSdan   */
2529ef5e770Sdrh   rc = execSql(db, pzErrMsg, "BEGIN");
253f602963dSdan   if( rc!=SQLITE_OK ) goto end_of_vacuum;
2542f6239edSdrh   rc = sqlite3BtreeBeginTrans(pMain, pOut==0 ? 2 : 0, 0);
255f602963dSdan   if( rc!=SQLITE_OK ) goto end_of_vacuum;
256f602963dSdan 
257811bdbd2Sdrh   /* Do not attempt to change the page size for a WAL database */
2580b9b4301Sdrh   if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
259cfb52496Sdrh                                                ==PAGER_JOURNALMODE_WAL
260cfb52496Sdrh    && pOut==0
261cfb52496Sdrh   ){
262811bdbd2Sdrh     db->nextPagesize = 0;
263811bdbd2Sdrh   }
264811bdbd2Sdrh 
265ce4869f8Sdrh   if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
266ce4869f8Sdrh    || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
2675dc348a2Sdrh    || NEVER(db->mallocFailed)
268f653d782Sdanielk1977   ){
269fad3039cSmistachkin     rc = SQLITE_NOMEM_BKPT;
270884c5b32Sdanielk1977     goto end_of_vacuum;
271884c5b32Sdanielk1977   }
2723df6b257Sdanielk1977 
27342741be9Sdanielk1977 #ifndef SQLITE_OMIT_AUTOVACUUM
274ddac25c7Sdrh   sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
275ddac25c7Sdrh                                            sqlite3BtreeGetAutoVacuum(pMain));
27642741be9Sdanielk1977 #endif
27742741be9Sdanielk1977 
2783df6b257Sdanielk1977   /* Query the schema of the main database. Create a mirror schema
2793df6b257Sdanielk1977   ** in the temporary database.
2803df6b257Sdanielk1977   */
2819ef5e770Sdrh   db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
2829ef5e770Sdrh   rc = execSqlF(db, pzErrMsg,
2831e32bed3Sdrh       "SELECT sql FROM \"%w\".sqlite_schema"
2849ef5e770Sdrh       " WHERE type='table'AND name<>'sqlite_sequence'"
28534b27edcSdrh       " AND coalesce(rootpage,1)>0",
2869ef5e770Sdrh       zDbMain
28766b224cbSdrh   );
28827c77438Sdanielk1977   if( rc!=SQLITE_OK ) goto end_of_vacuum;
2899ef5e770Sdrh   rc = execSqlF(db, pzErrMsg,
2901e32bed3Sdrh       "SELECT sql FROM \"%w\".sqlite_schema"
29134b27edcSdrh       " WHERE type='index'",
2929ef5e770Sdrh       zDbMain
2939ef5e770Sdrh   );
29427c77438Sdanielk1977   if( rc!=SQLITE_OK ) goto end_of_vacuum;
2959ef5e770Sdrh   db->init.iDb = 0;
2963df6b257Sdanielk1977 
2973df6b257Sdanielk1977   /* Loop through the tables in the main database. For each, do
298397308dfSdrh   ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
2993df6b257Sdanielk1977   ** the contents to the temporary database.
3003df6b257Sdanielk1977   */
3019ef5e770Sdrh   rc = execSqlF(db, pzErrMsg,
302bd26f925Sdanielk1977       "SELECT'INSERT INTO vacuum_db.'||quote(name)"
3039ef5e770Sdrh       "||' SELECT*FROM\"%w\".'||quote(name)"
3041e32bed3Sdrh       "FROM vacuum_db.sqlite_schema "
3059ef5e770Sdrh       "WHERE type='table'AND coalesce(rootpage,1)>0",
3069ef5e770Sdrh       zDbMain
3073df6b257Sdanielk1977   );
3088257aa8dSdrh   assert( (db->mDbFlags & DBFLAG_Vacuum)!=0 );
30967752575Sdrh   db->mDbFlags &= ~DBFLAG_Vacuum;
3103df6b257Sdanielk1977   if( rc!=SQLITE_OK ) goto end_of_vacuum;
3113df6b257Sdanielk1977 
312fdd48a76Sdrh   /* Copy the triggers, views, and virtual tables from the main database
313fdd48a76Sdrh   ** over to the temporary database.  None of these objects has any
314fdd48a76Sdrh   ** associated storage, so all we have to do is copy their entries
315346a70caSdrh   ** from the schema table.
3163df6b257Sdanielk1977   */
3179ef5e770Sdrh   rc = execSqlF(db, pzErrMsg,
3181e32bed3Sdrh       "INSERT INTO vacuum_db.sqlite_schema"
3191e32bed3Sdrh       " SELECT*FROM \"%w\".sqlite_schema"
3209ef5e770Sdrh       " WHERE type IN('view','trigger')"
3219ef5e770Sdrh       " OR(type='table'AND rootpage=0)",
3229ef5e770Sdrh       zDbMain
3233df6b257Sdanielk1977   );
324fdd48a76Sdrh   if( rc ) goto end_of_vacuum;
32513bff815Sdrh 
326c5f20a00Sdan   /* At this point, there is a write transaction open on both the
327c5f20a00Sdan   ** vacuum database and the main database. Assuming no error occurs,
328c5f20a00Sdan   ** both transactions are closed by this block - the main database
329c5f20a00Sdan   ** transaction by sqlite3BtreeCopyFile() and the other by an explicit
330c5f20a00Sdan   ** call to sqlite3BtreeCommit().
3313df6b257Sdanielk1977   */
3325dc348a2Sdrh   {
3333df6b257Sdanielk1977     u32 meta;
3348cbd373cSdrh     int i;
3358cbd373cSdrh 
3368cbd373cSdrh     /* This array determines which meta meta values are preserved in the
3378cbd373cSdrh     ** vacuum.  Even entries are the meta value number and odd entries
3388cbd373cSdrh     ** are an increment to apply to the meta value after the vacuum.
3398cbd373cSdrh     ** The increment is used to increase the schema cookie so that other
3408cbd373cSdrh     ** connections to the same database will know to reread the schema.
3418cbd373cSdrh     */
3428cbd373cSdrh     static const unsigned char aCopy[] = {
3430d19f7acSdanielk1977        BTREE_SCHEMA_VERSION,     1,  /* Add one to the old schema cookie */
3440d19f7acSdanielk1977        BTREE_DEFAULT_CACHE_SIZE, 0,  /* Preserve the default page cache size */
3450d19f7acSdanielk1977        BTREE_TEXT_ENCODING,      0,  /* Preserve the text encoding */
3460d19f7acSdanielk1977        BTREE_USER_VERSION,       0,  /* Preserve the user version */
347b8a67ec8Sdrh        BTREE_APPLICATION_ID,     0,  /* Preserve the application id */
3488cbd373cSdrh     };
3493df6b257Sdanielk1977 
35099744fa4Sdrh     assert( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) );
35199744fa4Sdrh     assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) );
3521d850a72Sdanielk1977 
3538cbd373cSdrh     /* Copy Btree meta values */
35400e13613Sdanielk1977     for(i=0; i<ArraySize(aCopy); i+=2){
3555dc348a2Sdrh       /* GetMeta() and UpdateMeta() cannot fail in this context because
3565dc348a2Sdrh       ** we already have page 1 loaded into cache and marked dirty. */
357602b466eSdanielk1977       sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
3588cbd373cSdrh       rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
3595dc348a2Sdrh       if( NEVER(rc!=SQLITE_OK) ) goto end_of_vacuum;
3608cbd373cSdrh     }
3613df6b257Sdanielk1977 
3622f6239edSdrh     if( pOut==0 ){
3633df6b257Sdanielk1977       rc = sqlite3BtreeCopyFile(pMain, pTemp);
364b0b7db91Sdrh     }
365369f27ebSdanielk1977     if( rc!=SQLITE_OK ) goto end_of_vacuum;
366c9ac5caaSdrh     rc = sqlite3BtreeCommit(pTemp);
367c9ac5caaSdrh     if( rc!=SQLITE_OK ) goto end_of_vacuum;
36806249db1Sdanielk1977 #ifndef SQLITE_OMIT_AUTOVACUUM
3692f6239edSdrh     if( pOut==0 ){
37006249db1Sdanielk1977       sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp));
371b0b7db91Sdrh     }
37206249db1Sdanielk1977 #endif
3732e6d11bcSdrh   }
37413bff815Sdrh 
3755dc348a2Sdrh   assert( rc==SQLITE_OK );
3762f6239edSdrh   if( pOut==0 ){
37741724ebcSdrh     nRes = sqlite3BtreeGetRequestedReserve(pTemp);
378ce4869f8Sdrh     rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
379b0b7db91Sdrh   }
380f653d782Sdanielk1977 
38113bff815Sdrh end_of_vacuum:
3820cd2d4c9Sdrh   /* Restore the original value of db->flags */
3839ef5e770Sdrh   db->init.iDb = 0;
3848257aa8dSdrh   db->mDbFlags = saved_mDbFlags;
3850cd2d4c9Sdrh   db->flags = saved_flags;
386e63b2c21Sdrh   db->nChange = saved_nChange;
387e63b2c21Sdrh   db->nTotalChange = saved_nTotalChange;
3883d2a529dSdrh   db->mTrace = saved_mTrace;
389e937df81Sdrh   sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
3903a3f38e0Sdanielk1977 
39146c43eddSdanielk1977   /* Currently there is an SQL level transaction open on the vacuum
39246c43eddSdanielk1977   ** database. No locks are held on any other files (since the main file
39346c43eddSdanielk1977   ** was committed at the btree level). So it safe to end the transaction
39446c43eddSdanielk1977   ** by manually setting the autoCommit flag to true and detaching the
39546c43eddSdanielk1977   ** vacuum database. The vacuum_db journal file is deleted when the pager
39646c43eddSdanielk1977   ** is closed by the DETACH.
39746c43eddSdanielk1977   */
39846c43eddSdanielk1977   db->autoCommit = 1;
399261919ccSdanielk1977 
4000203bde9Sdanielk1977   if( pDb ){
4010203bde9Sdanielk1977     sqlite3BtreeClose(pDb->pBt);
4020203bde9Sdanielk1977     pDb->pBt = 0;
4030203bde9Sdanielk1977     pDb->pSchema = 0;
404261919ccSdanielk1977   }
405f4208043Sdanielk1977 
40603faf63bSdrh   /* This both clears the schemas and reduces the size of the db->aDb[]
40703faf63bSdrh   ** array. */
40881028a45Sdrh   sqlite3ResetAllSchemasOfConnection(db);
40989dec819Sdrh 
4103df6b257Sdanielk1977   return rc;
4113df6b257Sdanielk1977 }
412c7792fa0Sdrh 
413fdbcdee5Sdrh #endif  /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */
414