| Index: third_party/sqlite/src/src/vacuum.c
|
| diff --git a/third_party/sqlite/src/src/vacuum.c b/third_party/sqlite/src/src/vacuum.c
|
| index 5a4ed32052c52ce6b0a24f70926440e77637c4b1..4d0c0976a182a01a0195b047dc5289bca1095cb4 100644
|
| --- a/third_party/sqlite/src/src/vacuum.c
|
| +++ b/third_party/sqlite/src/src/vacuum.c
|
| @@ -45,7 +45,7 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
| return sqlite3_errcode(db);
|
| }
|
| VVA_ONLY( rc = ) sqlite3_step(pStmt);
|
| - assert( rc!=SQLITE_ROW );
|
| + assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) );
|
| return vacuumFinalize(db, pStmt, pzErrMsg);
|
| }
|
|
|
| @@ -72,19 +72,40 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
| }
|
|
|
| /*
|
| -** The non-standard VACUUM command is used to clean up the database,
|
| +** The VACUUM command is used to clean up the database,
|
| ** collapse free space, etc. It is modelled after the VACUUM command
|
| -** in PostgreSQL.
|
| +** in PostgreSQL. The VACUUM command works as follows:
|
| **
|
| -** 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.
|
| +** (1) Create a new transient database file
|
| +** (2) Copy all content from the database being vacuumed into
|
| +** the new transient database file
|
| +** (3) Copy content from the transient database back into the
|
| +** original database.
|
| +**
|
| +** The transient database requires temporary disk space approximately
|
| +** equal to the size of the original database. The copy operation of
|
| +** step (3) requires additional temporary disk space approximately equal
|
| +** to the size of the original database for the rollback journal.
|
| +** Hence, temporary disk space that is approximately 2x the size of the
|
| +** original database is required. Every page of the database is written
|
| +** approximately 3 times: Once for step (2) and twice for step (3).
|
| +** Two writes per page are required in step (3) because the original
|
| +** database content must be written into the rollback journal prior to
|
| +** overwriting the database with the vacuumed content.
|
| +**
|
| +** Only 1x temporary space and only 1x writes would be required if
|
| +** the copy of step (3) were replace by deleting the original database
|
| +** and renaming the transient database as the original. But that will
|
| +** not work if other processes are attached to the original database.
|
| +** And a power loss in between deleting the original and renaming the
|
| +** transient would cause the database file to appear to be deleted
|
| +** following reboot.
|
| */
|
| void sqlite3Vacuum(Parse *pParse){
|
| Vdbe *v = sqlite3GetVdbe(pParse);
|
| if( v ){
|
| sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
|
| + sqlite3VdbeUsesBtree(v, 0);
|
| }
|
| return;
|
| }
|
| @@ -110,7 +131,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
| sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
|
| return SQLITE_ERROR;
|
| }
|
| - if( db->activeVdbeCnt>1 ){
|
| + if( db->nVdbeActive>1 ){
|
| sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
|
| return SQLITE_ERROR;
|
| }
|
| @@ -176,6 +197,18 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
| }
|
| #endif
|
|
|
| + rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
|
| + if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
| +
|
| + /* 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;");
|
| + if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
| + rc = sqlite3BtreeBeginTrans(pMain, 2);
|
| + if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
| +
|
| /* Do not attempt to change the page size for a WAL database */
|
| if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
|
| ==PAGER_JOURNALMODE_WAL ){
|
| @@ -189,27 +222,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
| rc = SQLITE_NOMEM;
|
| goto end_of_vacuum;
|
| }
|
| - rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
|
| - if( rc!=SQLITE_OK ){
|
| - goto end_of_vacuum;
|
| - }
|
|
|
| #ifndef SQLITE_OMIT_AUTOVACUUM
|
| sqlite3BtreeSetAutoVacuum(pTemp, db->nextAutovac>=0 ? db->nextAutovac :
|
| sqlite3BtreeGetAutoVacuum(pMain));
|
| #endif
|
|
|
| - /* Begin a transaction */
|
| - rc = execSql(db, pzErrMsg, "BEGIN EXCLUSIVE;");
|
| - if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
| -
|
| /* 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 rootpage>0"
|
| + " AND coalesce(rootpage,1)>0"
|
| );
|
| if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
| rc = execExecSql(db, pzErrMsg,
|
| @@ -230,7 +255,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
| "|| ' SELECT * FROM main.' || quote(name) || ';'"
|
| "FROM main.sqlite_master "
|
| "WHERE type = 'table' AND name!='sqlite_sequence' "
|
| - " AND rootpage>0"
|
| + " AND coalesce(rootpage,1)>0"
|
| );
|
| if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
|
|
| @@ -263,13 +288,11 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
| );
|
| if( rc ) goto end_of_vacuum;
|
|
|
| - /* At this point, unless the main db was completely empty, there is now a
|
| - ** transaction open on the vacuum database, but not on the main database.
|
| - ** Open a btree level transaction on the main database. This allows a
|
| - ** call to sqlite3BtreeCopyFile(). The main database btree level
|
| - ** transaction is then committed, so the SQL level never knows it was
|
| - ** opened for writing. This way, the SQL transaction used to create the
|
| - ** temporary database never needs to be committed.
|
| + /* At this point, there is a write transaction open on both the
|
| + ** vacuum database and the main database. Assuming no error occurs,
|
| + ** both transactions are closed by this block - the main database
|
| + ** transaction by sqlite3BtreeCopyFile() and the other by an explicit
|
| + ** call to sqlite3BtreeCommit().
|
| */
|
| {
|
| u32 meta;
|
| @@ -286,6 +309,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
|
| BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */
|
| BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */
|
| BTREE_USER_VERSION, 0, /* Preserve the user version */
|
| + BTREE_APPLICATION_ID, 0, /* Preserve the application id */
|
| };
|
|
|
| assert( 1==sqlite3BtreeIsInTrans(pTemp) );
|
| @@ -337,7 +361,7 @@ end_of_vacuum:
|
|
|
| /* This both clears the schemas and reduces the size of the db->aDb[]
|
| ** array. */
|
| - sqlite3ResetInternalSchema(db, -1);
|
| + sqlite3ResetAllSchemasOfConnection(db);
|
|
|
| return rc;
|
| }
|
|
|