DBD-SQLite2
view release on metacpan or search on metacpan
** This callback is used to transfer PRAGMA settings from one database
** to the other. The value in argv[0] should be passed to a pragma
** identified by ((vacuumStruct*)pArg)->zPragma.
*/
static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){
vacuumStruct *p = (vacuumStruct*)pArg;
char zBuf[200];
assert( argc==1 );
if( argv==0 ) return 0;
assert( argv[0]!=0 );
assert( strlen(p->zPragma)<100 );
assert( strlen(argv[0])<30 );
sprintf(zBuf,"PRAGMA %s=%s;", p->zPragma, argv[0]);
p->rc = execsql(p->pzErrMsg, p->dbNew, zBuf);
return p->rc;
}
/*
** Generate a random name of 20 character in length.
*/
static void randomName(unsigned char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"0123456789";
int i;
sqliteRandomness(20, zBuf);
for(i=0; i<20; i++){
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
}
}
#endif
/*
** The non-standard VACUUM command is used to clean up the database,
** collapse free space, etc. It is modelled after the VACUUM command
** in PostgreSQL.
**
** 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.
*/
void sqliteVacuum(Parse *pParse, Token *pTableName){
Vdbe *v = sqliteGetVdbe(pParse);
sqliteVdbeAddOp(v, OP_Vacuum, 0, 0);
return;
}
/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/
int sqliteRunVacuum(char **pzErrMsg, sqlite *db){
#if !defined(SQLITE_OMIT_VACUUM) || SQLITE_OMIT_VACUUM
const char *zFilename; /* full pathname of the database file */
int nFilename; /* number of characters in zFilename[] */
char *zTemp = 0; /* a temporary file in same directory as zFilename */
sqlite *dbNew = 0; /* The new vacuumed database */
int rc = SQLITE_OK; /* Return code from service routines */
int i; /* Loop counter */
char *zErrMsg; /* Error message */
vacuumStruct sVac; /* Information passed to callbacks */
/* These are all of the pragmas that need to be transferred over
** to the new database */
static const char *zPragma[] = {
"default_synchronous",
"default_cache_size",
/* "default_temp_store", */
};
if( db->flags & SQLITE_InTrans ){
sqliteSetString(pzErrMsg, "cannot VACUUM from within a transaction",
(char*)0);
return SQLITE_ERROR;
}
if( db->flags & SQLITE_Interrupt ){
return SQLITE_INTERRUPT;
}
memset(&sVac, 0, sizeof(sVac));
/* Get the full pathname of the database file and create two
** temporary filenames in the same directory as the original file.
*/
zFilename = sqliteBtreeGetFilename(db->aDb[0].pBt);
if( zFilename==0 ){
/* This only happens with the in-memory database. VACUUM is a no-op
** there, so just return */
return SQLITE_OK;
}
nFilename = strlen(zFilename);
zTemp = sqliteMalloc( nFilename+100 );
if( zTemp==0 ) return SQLITE_NOMEM;
strcpy(zTemp, zFilename);
for(i=0; i<10; i++){
zTemp[nFilename] = '-';
randomName((unsigned char*)&zTemp[nFilename+1]);
if( !sqliteOsFileExists(zTemp) ) break;
}
if( i>=10 ){
sqliteSetString(pzErrMsg, "unable to create a temporary database file "
"in the same directory as the original database", (char*)0);
goto end_of_vacuum;
}
dbNew = sqlite_open(zTemp, 0, &zErrMsg);
if( dbNew==0 ){
sqliteSetString(pzErrMsg, "unable to open a temporary database at ",
zTemp, " - ", zErrMsg, (char*)0);
goto end_of_vacuum;
}
if( (rc = execsql(pzErrMsg, db, "BEGIN"))!=0 ) goto end_of_vacuum;
if( (rc = execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN"))!=0 ){
goto end_of_vacuum;
}
sVac.dbOld = db;
sVac.dbNew = dbNew;
sVac.pzErrMsg = pzErrMsg;
for(i=0; rc==SQLITE_OK && i<sizeof(zPragma)/sizeof(zPragma[0]); i++){
char zBuf[200];
( run in 3.765 seconds using v1.01-cache-2.11-cpan-140bd7fdf52 )