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 - sqlite/libsqlite/src - vacuum.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 134
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: vacuum.c 195361 2005-09-07 15:11:33Z iliaa $
      18                 : */
      19                 : #include "sqliteInt.h"
      20                 : #include "os.h"
      21                 : 
      22                 : /*
      23                 : ** A structure for holding a dynamic string - a string that can grow
      24                 : ** without bound. 
      25                 : */
      26                 : typedef struct dynStr dynStr;
      27                 : struct dynStr {
      28                 :   char *z;        /* Text of the string in space obtained from sqliteMalloc() */
      29                 :   int nAlloc;     /* Amount of space allocated to z[] */
      30                 :   int nUsed;      /* Next unused slot in z[] */
      31                 : };
      32                 : 
      33                 : /*
      34                 : ** A structure that holds the vacuum context
      35                 : */
      36                 : typedef struct vacuumStruct vacuumStruct;
      37                 : struct vacuumStruct {
      38                 :   sqlite *dbOld;       /* Original database */
      39                 :   sqlite *dbNew;       /* New database */
      40                 :   char **pzErrMsg;     /* Write errors here */
      41                 :   int rc;              /* Set to non-zero on an error */
      42                 :   const char *zTable;  /* Name of a table being copied */
      43                 :   const char *zPragma; /* Pragma to execute with results */
      44                 :   dynStr s1, s2;       /* Two dynamic strings */
      45                 : };
      46                 : 
      47                 : #if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
      48                 : /*
      49                 : ** Append text to a dynamic string
      50                 : */
      51               0 : static void appendText(dynStr *p, const char *zText, int nText){
      52               0 :   if( nText<0 ) nText = strlen(zText);
      53               0 :   if( p->z==0 || p->nUsed + nText + 1 >= p->nAlloc ){
      54                 :     char *zNew;
      55               0 :     p->nAlloc = p->nUsed + nText + 1000;
      56               0 :     zNew = sqliteRealloc(p->z, p->nAlloc);
      57               0 :     if( zNew==0 ){
      58               0 :       sqliteFree(p->z);
      59               0 :       memset(p, 0, sizeof(*p));
      60               0 :       return;
      61                 :     }
      62               0 :     p->z = zNew;
      63                 :   }
      64               0 :   memcpy(&p->z[p->nUsed], zText, nText+1);
      65               0 :   p->nUsed += nText;
      66                 : }
      67                 : 
      68                 : /*
      69                 : ** Append text to a dynamic string, having first put the text in quotes.
      70                 : */
      71               0 : static void appendQuoted(dynStr *p, const char *zText){
      72                 :   int i, j;
      73               0 :   appendText(p, "'", 1);
      74               0 :   for(i=j=0; zText[i]; i++){
      75               0 :     if( zText[i]=='\'' ){
      76               0 :       appendText(p, &zText[j], i-j+1);
      77               0 :       j = i + 1;
      78               0 :       appendText(p, "'", 1);
      79                 :     }
      80                 :   }
      81               0 :   if( j<i ){
      82               0 :     appendText(p, &zText[j], i-j);
      83                 :   }
      84               0 :   appendText(p, "'", 1);
      85               0 : }
      86                 : 
      87                 : /*
      88                 : ** Execute statements of SQL.  If an error occurs, write the error
      89                 : ** message into *pzErrMsg and return non-zero.
      90                 : */
      91               0 : static int execsql(char **pzErrMsg, sqlite *db, const char *zSql){ 
      92               0 :   char *zErrMsg = 0;
      93                 :   int rc;
      94                 : 
      95                 :   /* printf("***** executing *****\n%s\n", zSql); */
      96               0 :   rc = sqlite_exec(db, zSql, 0, 0, &zErrMsg);
      97               0 :   if( zErrMsg ){
      98               0 :     sqliteSetString(pzErrMsg, zErrMsg, (char*)0);
      99               0 :     sqlite_freemem(zErrMsg);
     100                 :   }
     101               0 :   return rc;
     102                 : }
     103                 : 
     104                 : /*
     105                 : ** This is the second stage callback.  Each invocation contains all the
     106                 : ** data for a single row of a single table in the original database.  This
     107                 : ** routine must write that information into the new database.
     108                 : */
     109               0 : static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){
     110               0 :   vacuumStruct *p = (vacuumStruct*)pArg;
     111               0 :   const char *zSep = "(";
     112                 :   int i;
     113                 : 
     114               0 :   if( argv==0 ) return 0;
     115               0 :   p->s2.nUsed = 0;
     116               0 :   appendText(&p->s2, "INSERT INTO ", -1);
     117               0 :   appendQuoted(&p->s2, p->zTable);
     118               0 :   appendText(&p->s2, " VALUES", -1);
     119               0 :   for(i=0; i<argc; i++){
     120               0 :     appendText(&p->s2, zSep, 1);
     121               0 :     zSep = ",";
     122               0 :     if( argv[i]==0 ){
     123               0 :       appendText(&p->s2, "NULL", 4);
     124                 :     }else{
     125               0 :       appendQuoted(&p->s2, argv[i]);
     126                 :     }
     127                 :   }
     128               0 :   appendText(&p->s2,")", 1);
     129               0 :   p->rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
     130               0 :   return p->rc;
     131                 : }
     132                 : 
     133                 : /*
     134                 : ** This is the first stage callback.  Each invocation contains three
     135                 : ** arguments where are taken from the SQLITE_MASTER table of the original
     136                 : ** database:  (1) the entry type, (2) the entry name, and (3) the SQL for
     137                 : ** the entry.  In all cases, execute the SQL of the third argument.
     138                 : ** For tables, run a query to select all entries in that table and 
     139                 : ** transfer them to the second-stage callback.
     140                 : */
     141               0 : static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){
     142               0 :   vacuumStruct *p = (vacuumStruct*)pArg;
     143               0 :   int rc = 0;
     144                 :   assert( argc==3 );
     145               0 :   if( argv==0 ) return 0;
     146                 :   assert( argv[0]!=0 );
     147                 :   assert( argv[1]!=0 );
     148                 :   assert( argv[2]!=0 );
     149               0 :   rc = execsql(p->pzErrMsg, p->dbNew, argv[2]);
     150               0 :   if( rc==SQLITE_OK && strcmp(argv[0],"table")==0 ){
     151               0 :     char *zErrMsg = 0;
     152               0 :     p->s1.nUsed = 0;
     153               0 :     appendText(&p->s1, "SELECT * FROM ", -1);
     154               0 :     appendQuoted(&p->s1, argv[1]);
     155               0 :     p->zTable = argv[1];
     156               0 :     rc = sqlite_exec(p->dbOld, p->s1.z, vacuumCallback2, p, &zErrMsg);
     157               0 :     if( zErrMsg ){
     158               0 :       sqliteSetString(p->pzErrMsg, zErrMsg, (char*)0);
     159               0 :       sqlite_freemem(zErrMsg);
     160                 :     }
     161                 :   }
     162               0 :   if( rc!=SQLITE_ABORT ) p->rc = rc;
     163               0 :   return rc;
     164                 : }
     165                 : 
     166                 : /*
     167                 : ** Generate a random name of 20 character in length.
     168                 : */
     169               0 : static void randomName(unsigned char *zBuf){
     170                 :   static const unsigned char zChars[] =
     171                 :     "abcdefghijklmnopqrstuvwxyz"
     172                 :     "0123456789";
     173                 :   int i;
     174               0 :   sqliteRandomness(20, zBuf);
     175               0 :   for(i=0; i<20; i++){
     176               0 :     zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
     177                 :   }
     178               0 : }
     179                 : #endif
     180                 : 
     181                 : /*
     182                 : ** The non-standard VACUUM command is used to clean up the database,
     183                 : ** collapse free space, etc.  It is modelled after the VACUUM command
     184                 : ** in PostgreSQL.
     185                 : **
     186                 : ** In version 1.0.x of SQLite, the VACUUM command would call
     187                 : ** gdbm_reorganize() on all the database tables.  But beginning
     188                 : ** with 2.0.0, SQLite no longer uses GDBM so this command has
     189                 : ** become a no-op.
     190                 : */
     191               0 : void sqliteVacuum(Parse *pParse, Token *pTableName){
     192               0 :   Vdbe *v = sqliteGetVdbe(pParse);
     193               0 :   sqliteVdbeAddOp(v, OP_Vacuum, 0, 0);
     194                 :   return;
     195                 : }
     196                 : 
     197                 : /*
     198                 : ** This routine implements the OP_Vacuum opcode of the VDBE.
     199                 : */
     200               0 : int sqliteRunVacuum(char **pzErrMsg, sqlite *db){
     201                 : #if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
     202                 :   const char *zFilename;  /* full pathname of the database file */
     203                 :   int nFilename;          /* number of characters  in zFilename[] */
     204               0 :   char *zTemp = 0;        /* a temporary file in same directory as zFilename */
     205               0 :   sqlite *dbNew = 0;      /* The new vacuumed database */
     206               0 :   int rc = SQLITE_OK;     /* Return code from service routines */
     207                 :   int i;                  /* Loop counter */
     208                 :   char *zErrMsg;          /* Error message */
     209                 :   vacuumStruct sVac;      /* Information passed to callbacks */
     210                 : 
     211               0 :   if( db->flags & SQLITE_InTrans ){
     212               0 :     sqliteSetString(pzErrMsg, "cannot VACUUM from within a transaction", 
     213                 :        (char*)0);
     214               0 :     return SQLITE_ERROR;
     215                 :   }
     216               0 :   if( db->flags & SQLITE_Interrupt ){
     217               0 :     return SQLITE_INTERRUPT;
     218                 :   }
     219               0 :   memset(&sVac, 0, sizeof(sVac));
     220                 : 
     221                 :   /* Get the full pathname of the database file and create two
     222                 :   ** temporary filenames in the same directory as the original file.
     223                 :   */
     224               0 :   zFilename = sqliteBtreeGetFilename(db->aDb[0].pBt);
     225               0 :   if( zFilename==0 ){
     226                 :     /* This only happens with the in-memory database.  VACUUM is a no-op
     227                 :     ** there, so just return */
     228               0 :     return SQLITE_OK;
     229                 :   }
     230               0 :   nFilename = strlen(zFilename);
     231               0 :   zTemp = sqliteMalloc( nFilename+100 );
     232               0 :   if( zTemp==0 ) return SQLITE_NOMEM;
     233               0 :   strcpy(zTemp, zFilename);
     234               0 :   for(i=0; i<10; i++){
     235               0 :     zTemp[nFilename] = '-';
     236               0 :     randomName((unsigned char*)&zTemp[nFilename+1]);
     237               0 :     if( !sqliteOsFileExists(zTemp) ) break;
     238                 :   }
     239               0 :   if( i>=10 ){
     240               0 :     sqliteSetString(pzErrMsg, "unable to create a temporary database file "
     241                 :        "in the same directory as the original database", (char*)0);
     242               0 :     goto end_of_vacuum;
     243                 :   }
     244                 : 
     245                 :   
     246               0 :   dbNew = sqlite_open(zTemp, 0, &zErrMsg);
     247               0 :   if( dbNew==0 ){
     248               0 :     sqliteSetString(pzErrMsg, "unable to open a temporary database at ",
     249                 :        zTemp, " - ", zErrMsg, (char*)0);
     250               0 :     goto end_of_vacuum;
     251                 :   }
     252               0 :   if( (rc = execsql(pzErrMsg, db, "BEGIN"))!=0 ) goto end_of_vacuum;
     253               0 :   if( (rc = execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN"))!=0 ){
     254               0 :     goto end_of_vacuum;
     255                 :   }
     256                 :   
     257               0 :   sVac.dbOld = db;
     258               0 :   sVac.dbNew = dbNew;
     259               0 :   sVac.pzErrMsg = pzErrMsg;
     260               0 :   if( rc==SQLITE_OK ){
     261               0 :     rc = sqlite_exec(db, 
     262                 :       "SELECT type, name, sql FROM sqlite_master "
     263                 :       "WHERE sql NOT NULL AND type!='view' "
     264                 :       "UNION ALL "
     265                 :       "SELECT type, name, sql FROM sqlite_master "
     266                 :       "WHERE sql NOT NULL AND type=='view'",
     267                 :       vacuumCallback1, &sVac, &zErrMsg);
     268                 :   }
     269               0 :   if( rc==SQLITE_OK ){
     270                 :     int meta1[SQLITE_N_BTREE_META];
     271                 :     int meta2[SQLITE_N_BTREE_META];
     272               0 :     sqliteBtreeGetMeta(db->aDb[0].pBt, meta1);
     273               0 :     sqliteBtreeGetMeta(dbNew->aDb[0].pBt, meta2);
     274               0 :     meta2[1] = meta1[1]+1;
     275               0 :     meta2[3] = meta1[3];
     276               0 :     meta2[4] = meta1[4];
     277               0 :     meta2[6] = meta1[6];
     278               0 :     rc = sqliteBtreeUpdateMeta(dbNew->aDb[0].pBt, meta2);
     279                 :   }
     280               0 :   if( rc==SQLITE_OK ){
     281               0 :     rc = sqliteBtreeCopyFile(db->aDb[0].pBt, dbNew->aDb[0].pBt);
     282               0 :     sqlite_exec(db, "COMMIT", 0, 0, 0);
     283               0 :     sqliteResetInternalSchema(db, 0);
     284                 :   }
     285                 : 
     286               0 : end_of_vacuum:
     287               0 :   if( rc && zErrMsg!=0 ){
     288               0 :     sqliteSetString(pzErrMsg, "unable to vacuum database - ", 
     289                 :        zErrMsg, (char*)0);
     290                 :   }
     291               0 :   sqlite_exec(db, "ROLLBACK", 0, 0, 0);
     292               0 :   if( (dbNew && (dbNew->flags & SQLITE_Interrupt)) 
     293                 :          || (db->flags & SQLITE_Interrupt) ){
     294               0 :     rc = SQLITE_INTERRUPT;
     295                 :   }
     296               0 :   if( dbNew ) sqlite_close(dbNew);
     297               0 :   sqliteOsDelete(zTemp);
     298               0 :   sqliteFree(zTemp);
     299               0 :   sqliteFree(sVac.s1.z);
     300               0 :   sqliteFree(sVac.s2.z);
     301               0 :   if( zErrMsg ) sqlite_freemem(zErrMsg);
     302               0 :   if( rc==SQLITE_ABORT && sVac.rc!=SQLITE_INTERRUPT ) sVac.rc = SQLITE_ERROR;
     303               0 :   return sVac.rc;
     304                 : #endif
     305                 : }

Generated by: LTP GCOV extension version 1.5

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

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