extensions/sqlite/sqlite-source/vacuum.c
changeset 1203 633c25ce6405
child 1645 27307df4d711
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/extensions/sqlite/sqlite-source/vacuum.c	Sun Jul 29 01:15:31 2007 +0000
     1.3 @@ -0,0 +1,262 @@
     1.4 +/*
     1.5 +** 2003 April 6
     1.6 +**
     1.7 +** The author disclaims copyright to this source code.  In place of
     1.8 +** a legal notice, here is a blessing:
     1.9 +**
    1.10 +**    May you do good and not evil.
    1.11 +**    May you find forgiveness for yourself and forgive others.
    1.12 +**    May you share freely, never taking more than you give.
    1.13 +**
    1.14 +*************************************************************************
    1.15 +** This file contains code used to implement the VACUUM command.
    1.16 +**
    1.17 +** Most of the code in this file may be omitted by defining the
    1.18 +** SQLITE_OMIT_VACUUM macro.
    1.19 +**
    1.20 +** $Id$
    1.21 +*/
    1.22 +#include "sqliteInt.h"
    1.23 +#include "vdbeInt.h"
    1.24 +#include "os.h"
    1.25 +
    1.26 +#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
    1.27 +/*
    1.28 +** Execute zSql on database db. Return an error code.
    1.29 +*/
    1.30 +static int execSql(sqlite3 *db, const char *zSql){
    1.31 +  sqlite3_stmt *pStmt;
    1.32 +  if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
    1.33 +    return sqlite3_errcode(db);
    1.34 +  }
    1.35 +  while( SQLITE_ROW==sqlite3_step(pStmt) ){}
    1.36 +  return sqlite3_finalize(pStmt);
    1.37 +}
    1.38 +
    1.39 +/*
    1.40 +** Execute zSql on database db. The statement returns exactly
    1.41 +** one column. Execute this as SQL on the same database.
    1.42 +*/
    1.43 +static int execExecSql(sqlite3 *db, const char *zSql){
    1.44 +  sqlite3_stmt *pStmt;
    1.45 +  int rc;
    1.46 +
    1.47 +  rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
    1.48 +  if( rc!=SQLITE_OK ) return rc;
    1.49 +
    1.50 +  while( SQLITE_ROW==sqlite3_step(pStmt) ){
    1.51 +    rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
    1.52 +    if( rc!=SQLITE_OK ){
    1.53 +      sqlite3_finalize(pStmt);
    1.54 +      return rc;
    1.55 +    }
    1.56 +  }
    1.57 +
    1.58 +  return sqlite3_finalize(pStmt);
    1.59 +}
    1.60 +
    1.61 +/*
    1.62 +** The non-standard VACUUM command is used to clean up the database,
    1.63 +** collapse free space, etc.  It is modelled after the VACUUM command
    1.64 +** in PostgreSQL.
    1.65 +**
    1.66 +** In version 1.0.x of SQLite, the VACUUM command would call
    1.67 +** gdbm_reorganize() on all the database tables.  But beginning
    1.68 +** with 2.0.0, SQLite no longer uses GDBM so this command has
    1.69 +** become a no-op.
    1.70 +*/
    1.71 +void sqlite3Vacuum(Parse *pParse){
    1.72 +  Vdbe *v = sqlite3GetVdbe(pParse);
    1.73 +  if( v ){
    1.74 +    sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
    1.75 +  }
    1.76 +  return;
    1.77 +}
    1.78 +
    1.79 +/*
    1.80 +** This routine implements the OP_Vacuum opcode of the VDBE.
    1.81 +*/
    1.82 +int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
    1.83 +  int rc = SQLITE_OK;     /* Return code from service routines */
    1.84 +  Btree *pMain;           /* The database being vacuumed */
    1.85 +  Btree *pTemp;           /* The temporary database we vacuum into */
    1.86 +  char *zSql = 0;         /* SQL statements */
    1.87 +  int saved_flags;        /* Saved value of the db->flags */
    1.88 +  Db *pDb = 0;            /* Database to detach at end of vacuum */
    1.89 +
    1.90 +  /* Save the current value of the write-schema flag before setting it. */
    1.91 +  saved_flags = db->flags;
    1.92 +  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
    1.93 +
    1.94 +  if( !db->autoCommit ){
    1.95 +    sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", 
    1.96 +       (char*)0);
    1.97 +    rc = SQLITE_ERROR;
    1.98 +    goto end_of_vacuum;
    1.99 +  }
   1.100 +  pMain = db->aDb[0].pBt;
   1.101 +
   1.102 +  /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
   1.103 +  ** can be set to 'off' for this file, as it is not recovered if a crash
   1.104 +  ** occurs anyway. The integrity of the database is maintained by a
   1.105 +  ** (possibly synchronous) transaction opened on the main database before
   1.106 +  ** sqlite3BtreeCopyFile() is called.
   1.107 +  **
   1.108 +  ** An optimisation would be to use a non-journaled pager.
   1.109 +  */
   1.110 +  zSql = "ATTACH '' AS vacuum_db;";
   1.111 +  rc = execSql(db, zSql);
   1.112 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.113 +  pDb = &db->aDb[db->nDb-1];
   1.114 +  assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
   1.115 +  pTemp = db->aDb[db->nDb-1].pBt;
   1.116 +  sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
   1.117 +     sqlite3BtreeGetReserve(pMain));
   1.118 +  if( sqlite3MallocFailed() ){
   1.119 +    rc = SQLITE_NOMEM;
   1.120 +    goto end_of_vacuum;
   1.121 +  }
   1.122 +  assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
   1.123 +  rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
   1.124 +  if( rc!=SQLITE_OK ){
   1.125 +    goto end_of_vacuum;
   1.126 +  }
   1.127 +
   1.128 +#ifndef SQLITE_OMIT_AUTOVACUUM
   1.129 +  sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
   1.130 +#endif
   1.131 +
   1.132 +  /* Begin a transaction */
   1.133 +  rc = execSql(db, "BEGIN EXCLUSIVE;");
   1.134 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.135 +
   1.136 +  /* Query the schema of the main database. Create a mirror schema
   1.137 +  ** in the temporary database.
   1.138 +  */
   1.139 +  rc = execExecSql(db, 
   1.140 +      "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
   1.141 +      "  FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
   1.142 +      "   AND rootpage>0"
   1.143 +  );
   1.144 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.145 +  rc = execExecSql(db, 
   1.146 +      "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
   1.147 +      "  FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
   1.148 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.149 +  rc = execExecSql(db, 
   1.150 +      "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
   1.151 +      "  FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
   1.152 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.153 +
   1.154 +  /* Loop through the tables in the main database. For each, do
   1.155 +  ** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
   1.156 +  ** the contents to the temporary database.
   1.157 +  */
   1.158 +  rc = execExecSql(db, 
   1.159 +      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
   1.160 +      "|| ' SELECT * FROM ' || quote(name) || ';'"
   1.161 +      "FROM sqlite_master "
   1.162 +      "WHERE type = 'table' AND name!='sqlite_sequence' "
   1.163 +      "  AND rootpage>0"
   1.164 +
   1.165 +  );
   1.166 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.167 +
   1.168 +  /* Copy over the sequence table
   1.169 +  */
   1.170 +  rc = execExecSql(db, 
   1.171 +      "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
   1.172 +      "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
   1.173 +  );
   1.174 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.175 +  rc = execExecSql(db, 
   1.176 +      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
   1.177 +      "|| ' SELECT * FROM ' || quote(name) || ';' "
   1.178 +      "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
   1.179 +  );
   1.180 +  if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.181 +
   1.182 +
   1.183 +  /* Copy the triggers, views, and virtual tables from the main database
   1.184 +  ** over to the temporary database.  None of these objects has any
   1.185 +  ** associated storage, so all we have to do is copy their entries
   1.186 +  ** from the SQLITE_MASTER table.
   1.187 +  */
   1.188 +  rc = execSql(db,
   1.189 +      "INSERT INTO vacuum_db.sqlite_master "
   1.190 +      "  SELECT type, name, tbl_name, rootpage, sql"
   1.191 +      "    FROM sqlite_master"
   1.192 +      "   WHERE type='view' OR type='trigger'"
   1.193 +      "      OR (type='table' AND rootpage=0)"
   1.194 +  );
   1.195 +  if( rc ) goto end_of_vacuum;
   1.196 +
   1.197 +  /* At this point, unless the main db was completely empty, there is now a
   1.198 +  ** transaction open on the vacuum database, but not on the main database.
   1.199 +  ** Open a btree level transaction on the main database. This allows a
   1.200 +  ** call to sqlite3BtreeCopyFile(). The main database btree level
   1.201 +  ** transaction is then committed, so the SQL level never knows it was
   1.202 +  ** opened for writing. This way, the SQL transaction used to create the
   1.203 +  ** temporary database never needs to be committed.
   1.204 +  */
   1.205 +  if( rc==SQLITE_OK ){
   1.206 +    u32 meta;
   1.207 +    int i;
   1.208 +
   1.209 +    /* This array determines which meta meta values are preserved in the
   1.210 +    ** vacuum.  Even entries are the meta value number and odd entries
   1.211 +    ** are an increment to apply to the meta value after the vacuum.
   1.212 +    ** The increment is used to increase the schema cookie so that other
   1.213 +    ** connections to the same database will know to reread the schema.
   1.214 +    */
   1.215 +    static const unsigned char aCopy[] = {
   1.216 +       1, 1,    /* Add one to the old schema cookie */
   1.217 +       3, 0,    /* Preserve the default page cache size */
   1.218 +       5, 0,    /* Preserve the default text encoding */
   1.219 +       6, 0,    /* Preserve the user version */
   1.220 +    };
   1.221 +
   1.222 +    assert( 1==sqlite3BtreeIsInTrans(pTemp) );
   1.223 +    assert( 1==sqlite3BtreeIsInTrans(pMain) );
   1.224 +
   1.225 +    /* Copy Btree meta values */
   1.226 +    for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
   1.227 +      rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
   1.228 +      if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.229 +      rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
   1.230 +      if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.231 +    }
   1.232 +
   1.233 +    rc = sqlite3BtreeCopyFile(pMain, pTemp);
   1.234 +    if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.235 +    rc = sqlite3BtreeCommit(pTemp);
   1.236 +    if( rc!=SQLITE_OK ) goto end_of_vacuum;
   1.237 +    rc = sqlite3BtreeCommit(pMain);
   1.238 +  }
   1.239 +
   1.240 +end_of_vacuum:
   1.241 +  /* Restore the original value of db->flags */
   1.242 +  db->flags = saved_flags;
   1.243 +
   1.244 +  /* Currently there is an SQL level transaction open on the vacuum
   1.245 +  ** database. No locks are held on any other files (since the main file
   1.246 +  ** was committed at the btree level). So it safe to end the transaction
   1.247 +  ** by manually setting the autoCommit flag to true and detaching the
   1.248 +  ** vacuum database. The vacuum_db journal file is deleted when the pager
   1.249 +  ** is closed by the DETACH.
   1.250 +  */
   1.251 +  db->autoCommit = 1;
   1.252 +
   1.253 +  if( pDb ){
   1.254 +    sqlite3MallocDisallow();
   1.255 +    sqlite3BtreeClose(pDb->pBt);
   1.256 +    sqlite3MallocAllow();
   1.257 +    pDb->pBt = 0;
   1.258 +    pDb->pSchema = 0;
   1.259 +  }
   1.260 +
   1.261 +  sqlite3ResetInternalSchema(db, 0);
   1.262 +
   1.263 +  return rc;
   1.264 +}
   1.265 +#endif  /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */