PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - pdo_sqlite/sqlite/src - vacuum.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 78
Code covered: 0.0 % Executed lines: 0
Legend: not executed executed

       1                 : /*
       2                 : ** 2003 April 6
       3                 : **
       4                 : ** The author disclaims copyright to this source code.  In place of
       5                 : ** a legal notice, here is a blessing:
       6                 : **
       7                 : **    May you do good and not evil.
       8                 : **    May you find forgiveness for yourself and forgive others.
       9                 : **    May you share freely, never taking more than you give.
      10                 : **
      11                 : *************************************************************************
      12                 : ** This file contains code used to implement the VACUUM command.
      13                 : **
      14                 : ** Most of the code in this file may be omitted by defining the
      15                 : ** SQLITE_OMIT_VACUUM macro.
      16                 : **
      17                 : ** $Id$
      18                 : */
      19                 : #include "sqliteInt.h"
      20                 : #include "vdbeInt.h"
      21                 : #include "os.h"
      22                 : 
      23                 : #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
      24                 : /*
      25                 : ** Execute zSql on database db. Return an error code.
      26                 : */
      27               0 : static int execSql(sqlite3 *db, const char *zSql){
      28                 :   sqlite3_stmt *pStmt;
      29               0 :   if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
      30               0 :     return sqlite3_errcode(db);
      31                 :   }
      32               0 :   while( SQLITE_ROW==sqlite3_step(pStmt) ){}
      33               0 :   return sqlite3_finalize(pStmt);
      34                 : }
      35                 : 
      36                 : /*
      37                 : ** Execute zSql on database db. The statement returns exactly
      38                 : ** one column. Execute this as SQL on the same database.
      39                 : */
      40               0 : static int execExecSql(sqlite3 *db, const char *zSql){
      41                 :   sqlite3_stmt *pStmt;
      42                 :   int rc;
      43                 : 
      44               0 :   rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
      45               0 :   if( rc!=SQLITE_OK ) return rc;
      46                 : 
      47               0 :   while( SQLITE_ROW==sqlite3_step(pStmt) ){
      48               0 :     rc = execSql(db, (char*)sqlite3_column_text(pStmt, 0));
      49               0 :     if( rc!=SQLITE_OK ){
      50               0 :       sqlite3_finalize(pStmt);
      51               0 :       return rc;
      52                 :     }
      53                 :   }
      54                 : 
      55               0 :   return sqlite3_finalize(pStmt);
      56                 : }
      57                 : 
      58                 : /*
      59                 : ** The non-standard VACUUM command is used to clean up the database,
      60                 : ** collapse free space, etc.  It is modelled after the VACUUM command
      61                 : ** in PostgreSQL.
      62                 : **
      63                 : ** In version 1.0.x of SQLite, the VACUUM command would call
      64                 : ** gdbm_reorganize() on all the database tables.  But beginning
      65                 : ** with 2.0.0, SQLite no longer uses GDBM so this command has
      66                 : ** become a no-op.
      67                 : */
      68               0 : void sqlite3Vacuum(Parse *pParse){
      69               0 :   Vdbe *v = sqlite3GetVdbe(pParse);
      70               0 :   if( v ){
      71               0 :     sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
      72                 :   }
      73                 :   return;
      74                 : }
      75                 : 
      76                 : /*
      77                 : ** This routine implements the OP_Vacuum opcode of the VDBE.
      78                 : */
      79               0 : int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
      80               0 :   int rc = SQLITE_OK;     /* Return code from service routines */
      81                 :   Btree *pMain;           /* The database being vacuumed */
      82                 :   Btree *pTemp;           /* The temporary database we vacuum into */
      83               0 :   char *zSql = 0;         /* SQL statements */
      84                 :   int saved_flags;        /* Saved value of the db->flags */
      85               0 :   Db *pDb = 0;            /* Database to detach at end of vacuum */
      86                 : 
      87                 :   /* Save the current value of the write-schema flag before setting it. */
      88               0 :   saved_flags = db->flags;
      89               0 :   db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
      90                 : 
      91               0 :   if( !db->autoCommit ){
      92               0 :     sqlite3SetString(pzErrMsg, "cannot VACUUM from within a transaction", 
      93                 :        (char*)0);
      94               0 :     rc = SQLITE_ERROR;
      95               0 :     goto end_of_vacuum;
      96                 :   }
      97               0 :   pMain = db->aDb[0].pBt;
      98                 : 
      99                 :   /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
     100                 :   ** can be set to 'off' for this file, as it is not recovered if a crash
     101                 :   ** occurs anyway. The integrity of the database is maintained by a
     102                 :   ** (possibly synchronous) transaction opened on the main database before
     103                 :   ** sqlite3BtreeCopyFile() is called.
     104                 :   **
     105                 :   ** An optimisation would be to use a non-journaled pager.
     106                 :   */
     107               0 :   zSql = "ATTACH '' AS vacuum_db;";
     108               0 :   rc = execSql(db, zSql);
     109               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     110               0 :   pDb = &db->aDb[db->nDb-1];
     111                 :   assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
     112               0 :   pTemp = db->aDb[db->nDb-1].pBt;
     113               0 :   sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
     114                 :      sqlite3BtreeGetReserve(pMain));
     115               0 :   if( sqlite3MallocFailed() ){
     116               0 :     rc = SQLITE_NOMEM;
     117               0 :     goto end_of_vacuum;
     118                 :   }
     119                 :   assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
     120               0 :   rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
     121               0 :   if( rc!=SQLITE_OK ){
     122               0 :     goto end_of_vacuum;
     123                 :   }
     124                 : 
     125                 : #ifndef SQLITE_OMIT_AUTOVACUUM
     126               0 :   sqlite3BtreeSetAutoVacuum(pTemp, sqlite3BtreeGetAutoVacuum(pMain));
     127                 : #endif
     128                 : 
     129                 :   /* Begin a transaction */
     130               0 :   rc = execSql(db, "BEGIN EXCLUSIVE;");
     131               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     132                 : 
     133                 :   /* Query the schema of the main database. Create a mirror schema
     134                 :   ** in the temporary database.
     135                 :   */
     136               0 :   rc = execExecSql(db, 
     137                 :       "SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
     138                 :       "  FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
     139                 :       "   AND rootpage>0"
     140                 :   );
     141               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     142               0 :   rc = execExecSql(db, 
     143                 :       "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
     144                 :       "  FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
     145               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     146               0 :   rc = execExecSql(db, 
     147                 :       "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
     148                 :       "  FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
     149               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     150                 : 
     151                 :   /* Loop through the tables in the main database. For each, do
     152                 :   ** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
     153                 :   ** the contents to the temporary database.
     154                 :   */
     155               0 :   rc = execExecSql(db, 
     156                 :       "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
     157                 :       "|| ' SELECT * FROM ' || quote(name) || ';'"
     158                 :       "FROM sqlite_master "
     159                 :       "WHERE type = 'table' AND name!='sqlite_sequence' "
     160                 :       "  AND rootpage>0"
     161                 : 
     162                 :   );
     163               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     164                 : 
     165                 :   /* Copy over the sequence table
     166                 :   */
     167               0 :   rc = execExecSql(db, 
     168                 :       "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
     169                 :       "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
     170                 :   );
     171               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     172               0 :   rc = execExecSql(db, 
     173                 :       "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
     174                 :       "|| ' SELECT * FROM ' || quote(name) || ';' "
     175                 :       "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
     176                 :   );
     177               0 :   if( rc!=SQLITE_OK ) goto end_of_vacuum;
     178                 : 
     179                 : 
     180                 :   /* Copy the triggers, views, and virtual tables from the main database
     181                 :   ** over to the temporary database.  None of these objects has any
     182                 :   ** associated storage, so all we have to do is copy their entries
     183                 :   ** from the SQLITE_MASTER table.
     184                 :   */
     185               0 :   rc = execSql(db,
     186                 :       "INSERT INTO vacuum_db.sqlite_master "
     187                 :       "  SELECT type, name, tbl_name, rootpage, sql"
     188                 :       "    FROM sqlite_master"
     189                 :       "   WHERE type='view' OR type='trigger'"
     190                 :       "      OR (type='table' AND rootpage=0)"
     191                 :   );
     192               0 :   if( rc ) goto end_of_vacuum;
     193                 : 
     194                 :   /* At this point, unless the main db was completely empty, there is now a
     195                 :   ** transaction open on the vacuum database, but not on the main database.
     196                 :   ** Open a btree level transaction on the main database. This allows a
     197                 :   ** call to sqlite3BtreeCopyFile(). The main database btree level
     198                 :   ** transaction is then committed, so the SQL level never knows it was
     199                 :   ** opened for writing. This way, the SQL transaction used to create the
     200                 :   ** temporary database never needs to be committed.
     201                 :   */
     202               0 :   if( rc==SQLITE_OK ){
     203                 :     u32 meta;
     204                 :     int i;
     205                 : 
     206                 :     /* This array determines which meta meta values are preserved in the
     207                 :     ** vacuum.  Even entries are the meta value number and odd entries
     208                 :     ** are an increment to apply to the meta value after the vacuum.
     209                 :     ** The increment is used to increase the schema cookie so that other
     210                 :     ** connections to the same database will know to reread the schema.
     211                 :     */
     212                 :     static const unsigned char aCopy[] = {
     213                 :        1, 1,    /* Add one to the old schema cookie */
     214                 :        3, 0,    /* Preserve the default page cache size */
     215                 :        5, 0,    /* Preserve the default text encoding */
     216                 :        6, 0,    /* Preserve the user version */
     217                 :     };
     218                 : 
     219                 :     assert( 1==sqlite3BtreeIsInTrans(pTemp) );
     220                 :     assert( 1==sqlite3BtreeIsInTrans(pMain) );
     221                 : 
     222                 :     /* Copy Btree meta values */
     223               0 :     for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){
     224               0 :       rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
     225               0 :       if( rc!=SQLITE_OK ) goto end_of_vacuum;
     226               0 :       rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);
     227               0 :       if( rc!=SQLITE_OK ) goto end_of_vacuum;
     228                 :     }
     229                 : 
     230               0 :     rc = sqlite3BtreeCopyFile(pMain, pTemp);
     231               0 :     if( rc!=SQLITE_OK ) goto end_of_vacuum;
     232               0 :     rc = sqlite3BtreeCommit(pTemp);
     233               0 :     if( rc!=SQLITE_OK ) goto end_of_vacuum;
     234               0 :     rc = sqlite3BtreeCommit(pMain);
     235                 :   }
     236                 : 
     237               0 : end_of_vacuum:
     238                 :   /* Restore the original value of db->flags */
     239               0 :   db->flags = saved_flags;
     240                 : 
     241                 :   /* Currently there is an SQL level transaction open on the vacuum
     242                 :   ** database. No locks are held on any other files (since the main file
     243                 :   ** was committed at the btree level). So it safe to end the transaction
     244                 :   ** by manually setting the autoCommit flag to true and detaching the
     245                 :   ** vacuum database. The vacuum_db journal file is deleted when the pager
     246                 :   ** is closed by the DETACH.
     247                 :   */
     248               0 :   db->autoCommit = 1;
     249                 : 
     250               0 :   if( pDb ){
     251                 :     sqlite3MallocDisallow();
     252               0 :     sqlite3BtreeClose(pDb->pBt);
     253                 :     sqlite3MallocAllow();
     254               0 :     pDb->pBt = 0;
     255               0 :     pDb->pSchema = 0;
     256                 :   }
     257                 : 
     258               0 :   sqlite3ResetInternalSchema(db, 0);
     259                 : 
     260               0 :   return rc;
     261                 : }
     262                 : #endif  /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:16 +0000 (5 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.