| 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 adc802e60b4330608c511829857dd14c74c597ce..25b1258510fc5435e172047d60b225043da826c1 100644
 | 
| --- a/third_party/sqlite/src/src/vacuum.c
 | 
| +++ b/third_party/sqlite/src/src/vacuum.c
 | 
| @@ -18,57 +18,52 @@
 | 
|  #include "vdbeInt.h"
 | 
|  
 | 
|  #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
 | 
| -/*
 | 
| -** Finalize a prepared statement.  If there was an error, store the
 | 
| -** text of the error message in *pzErrMsg.  Return the result code.
 | 
| -*/
 | 
| -static int vacuumFinalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
 | 
| -  int rc;
 | 
| -  rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
 | 
| -  if( rc ){
 | 
| -    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
 | 
| -  }
 | 
| -  return rc;
 | 
| -}
 | 
|  
 | 
|  /*
 | 
| -** Execute zSql on database db. Return an error code.
 | 
| +** Execute zSql on database db.
 | 
| +**
 | 
| +** If zSql returns rows, then each row will have exactly one
 | 
| +** column.  (This will only happen if zSql begins with "SELECT".)
 | 
| +** Take each row of result and call execSql() again recursively.
 | 
| +**
 | 
| +** The execSqlF() routine does the same thing, except it accepts
 | 
| +** a format string as its third argument
 | 
|  */
 | 
|  static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
 | 
|    sqlite3_stmt *pStmt;
 | 
| -  VVA_ONLY( int rc; )
 | 
| -  if( !zSql ){
 | 
| -    return SQLITE_NOMEM;
 | 
| -  }
 | 
| -  if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
 | 
| -    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
 | 
| -    return sqlite3_errcode(db);
 | 
| -  }
 | 
| -  VVA_ONLY( rc = ) sqlite3_step(pStmt);
 | 
| -  assert( rc!=SQLITE_ROW || (db->flags&SQLITE_CountRows) );
 | 
| -  return vacuumFinalize(db, pStmt, pzErrMsg);
 | 
| -}
 | 
| -
 | 
| -/*
 | 
| -** Execute zSql on database db. The statement returns exactly
 | 
| -** one column. Execute this as SQL on the same database.
 | 
| -*/
 | 
| -static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
 | 
| -  sqlite3_stmt *pStmt;
 | 
|    int rc;
 | 
|  
 | 
| -  rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
 | 
| +  /* printf("SQL: [%s]\n", zSql); fflush(stdout); */
 | 
| +  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
 | 
|    if( rc!=SQLITE_OK ) return rc;
 | 
| -
 | 
| -  while( SQLITE_ROW==sqlite3_step(pStmt) ){
 | 
| -    rc = execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
 | 
| -    if( rc!=SQLITE_OK ){
 | 
| -      vacuumFinalize(db, pStmt, pzErrMsg);
 | 
| -      return rc;
 | 
| +  while( SQLITE_ROW==(rc = sqlite3_step(pStmt)) ){
 | 
| +    const char *zSubSql = (const char*)sqlite3_column_text(pStmt,0);
 | 
| +    assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
 | 
| +    if( zSubSql ){
 | 
| +      assert( zSubSql[0]!='S' );
 | 
| +      rc = execSql(db, pzErrMsg, zSubSql);
 | 
| +      if( rc!=SQLITE_OK ) break;
 | 
|      }
 | 
|    }
 | 
| -
 | 
| -  return vacuumFinalize(db, pStmt, pzErrMsg);
 | 
| +  assert( rc!=SQLITE_ROW );
 | 
| +  if( rc==SQLITE_DONE ) rc = SQLITE_OK;
 | 
| +  if( rc ){
 | 
| +    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
 | 
| +  }
 | 
| +  (void)sqlite3_finalize(pStmt);
 | 
| +  return rc;
 | 
| +}
 | 
| +static int execSqlF(sqlite3 *db, char **pzErrMsg, const char *zSql, ...){
 | 
| +  char *z;
 | 
| +  va_list ap;
 | 
| +  int rc;
 | 
| +  va_start(ap, zSql);
 | 
| +  z = sqlite3VMPrintf(db, zSql, ap);
 | 
| +  va_end(ap);
 | 
| +  if( z==0 ) return SQLITE_NOMEM;
 | 
| +  rc = execSql(db, pzErrMsg, z);
 | 
| +  sqlite3DbFree(db, z);
 | 
| +  return rc;
 | 
|  }
 | 
|  
 | 
|  /*
 | 
| @@ -101,11 +96,12 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
 | 
|  ** transient would cause the database file to appear to be deleted
 | 
|  ** following reboot.
 | 
|  */
 | 
| -void sqlite3Vacuum(Parse *pParse){
 | 
| +void sqlite3Vacuum(Parse *pParse, Token *pNm){
 | 
|    Vdbe *v = sqlite3GetVdbe(pParse);
 | 
| -  if( v ){
 | 
| -    sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
 | 
| -    sqlite3VdbeUsesBtree(v, 0);
 | 
| +  int iDb = pNm ? sqlite3TwoPartName(pParse, pNm, pNm, &pNm) : 0;
 | 
| +  if( v && (iDb>=2 || iDb==0) ){
 | 
| +    sqlite3VdbeAddOp1(v, OP_Vacuum, iDb);
 | 
| +    sqlite3VdbeUsesBtree(v, iDb);
 | 
|    }
 | 
|    return;
 | 
|  }
 | 
| @@ -113,19 +109,19 @@ void sqlite3Vacuum(Parse *pParse){
 | 
|  /*
 | 
|  ** This routine implements the OP_Vacuum opcode of the VDBE.
 | 
|  */
 | 
| -int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
 | 
| +int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db, int iDb){
 | 
|    int rc = SQLITE_OK;     /* Return code from service routines */
 | 
|    Btree *pMain;           /* The database being vacuumed */
 | 
|    Btree *pTemp;           /* The temporary database we vacuum into */
 | 
| -  char *zSql = 0;         /* SQL statements */
 | 
|    int saved_flags;        /* Saved value of the db->flags */
 | 
|    int saved_nChange;      /* Saved value of db->nChange */
 | 
|    int saved_nTotalChange; /* Saved value of db->nTotalChange */
 | 
| -  void (*saved_xTrace)(void*,const char*);  /* Saved db->xTrace */
 | 
| +  u8 saved_mTrace;        /* Saved trace settings */
 | 
|    Db *pDb = 0;            /* Database to detach at end of vacuum */
 | 
|    int isMemDb;            /* True if vacuuming a :memory: database */
 | 
|    int nRes;               /* Bytes of reserved space at the end of each page */
 | 
|    int nDb;                /* Number of attached databases */
 | 
| +  const char *zDbMain;    /* Schema name of database to vacuum */
 | 
|  
 | 
|    if( !db->autoCommit ){
 | 
|      sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
 | 
| @@ -142,12 +138,14 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
 | 
|    saved_flags = db->flags;
 | 
|    saved_nChange = db->nChange;
 | 
|    saved_nTotalChange = db->nTotalChange;
 | 
| -  saved_xTrace = db->xTrace;
 | 
| -  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
 | 
| -  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
 | 
| -  db->xTrace = 0;
 | 
| -
 | 
| -  pMain = db->aDb[0].pBt;
 | 
| +  saved_mTrace = db->mTrace;
 | 
| +  db->flags |= (SQLITE_WriteSchema | SQLITE_IgnoreChecks
 | 
| +                 | SQLITE_PreferBuiltin | SQLITE_Vacuum);
 | 
| +  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder | SQLITE_CountRows);
 | 
| +  db->mTrace = 0;
 | 
| +
 | 
| +  zDbMain = db->aDb[iDb].zDbSName;
 | 
| +  pMain = db->aDb[iDb].pBt;
 | 
|    isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
 | 
|  
 | 
|    /* Attach the temporary database as 'vacuum_db'. The synchronous pragma
 | 
| @@ -165,18 +163,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
 | 
|    ** to write the journal header file.
 | 
|    */
 | 
|    nDb = db->nDb;
 | 
| -  if( sqlite3TempInMemory(db) ){
 | 
| -    zSql = "ATTACH ':memory:' AS vacuum_db;";
 | 
| -  }else{
 | 
| -    zSql = "ATTACH '' AS vacuum_db;";
 | 
| -  }
 | 
| -  rc = execSql(db, pzErrMsg, zSql);
 | 
| -  if( db->nDb>nDb ){
 | 
| -    pDb = &db->aDb[db->nDb-1];
 | 
| -    assert( strcmp(pDb->zName,"vacuum_db")==0 );
 | 
| -  }
 | 
| +  rc = execSql(db, pzErrMsg, "ATTACH''AS vacuum_db");
 | 
|    if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
| -  pTemp = db->aDb[db->nDb-1].pBt;
 | 
| +  assert( (db->nDb-1)==nDb );
 | 
| +  pDb = &db->aDb[nDb];
 | 
| +  assert( strcmp(pDb->zDbSName,"vacuum_db")==0 );
 | 
| +  pTemp = pDb->pBt;
 | 
|  
 | 
|    /* The call to execSql() to attach the temp database has left the file
 | 
|    ** locked (as there was more than one active statement when the transaction
 | 
| @@ -197,14 +189,15 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
 | 
|    }
 | 
|  #endif
 | 
|  
 | 
| -  rc = execSql(db, pzErrMsg, "PRAGMA vacuum_db.synchronous=OFF");
 | 
| -  if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
| +  sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
 | 
| +  sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
 | 
| +  sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
 | 
|  
 | 
|    /* 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;");
 | 
| +  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;
 | 
| @@ -219,7 +212,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
 | 
|     || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
 | 
|     || NEVER(db->mallocFailed)
 | 
|    ){
 | 
| -    rc = SQLITE_NOMEM;
 | 
| +    rc = SQLITE_NOMEM_BKPT;
 | 
|      goto end_of_vacuum;
 | 
|    }
 | 
|  
 | 
| @@ -231,64 +224,48 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
 | 
|    /* 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 coalesce(rootpage,1)>0"
 | 
| +  db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
 | 
| +  rc = execSqlF(db, pzErrMsg,
 | 
| +      "SELECT sql FROM \"%w\".sqlite_master"
 | 
| +      " WHERE type='table'AND name<>'sqlite_sequence'"
 | 
| +      " AND coalesce(rootpage,1)>0",
 | 
| +      zDbMain
 | 
|    );
 | 
|    if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
| -  rc = execExecSql(db, pzErrMsg,
 | 
| -      "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)"
 | 
| -      "  FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %' ");
 | 
| -  if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
| -  rc = execExecSql(db, pzErrMsg,
 | 
| -      "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) "
 | 
| -      "  FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
 | 
| +  rc = execSqlF(db, pzErrMsg,
 | 
| +      "SELECT sql FROM \"%w\".sqlite_master"
 | 
| +      " WHERE type='index' AND length(sql)>10",
 | 
| +      zDbMain
 | 
| +  );
 | 
|    if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
| +  db->init.iDb = 0;
 | 
|  
 | 
|    /* Loop through the tables in the main database. For each, do
 | 
|    ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy
 | 
|    ** the contents to the temporary database.
 | 
|    */
 | 
| -  assert( (db->flags & SQLITE_Vacuum)==0 );
 | 
| -  db->flags |= SQLITE_Vacuum;
 | 
| -  rc = execExecSql(db, pzErrMsg,
 | 
| -      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
 | 
| -      "|| ' SELECT * FROM main.' || quote(name) || ';'"
 | 
| -      "FROM main.sqlite_master "
 | 
| -      "WHERE type = 'table' AND name!='sqlite_sequence' "
 | 
| -      "  AND coalesce(rootpage,1)>0"
 | 
| +  rc = execSqlF(db, pzErrMsg,
 | 
| +      "SELECT'INSERT INTO vacuum_db.'||quote(name)"
 | 
| +      "||' SELECT*FROM\"%w\".'||quote(name)"
 | 
| +      "FROM vacuum_db.sqlite_master "
 | 
| +      "WHERE type='table'AND coalesce(rootpage,1)>0",
 | 
| +      zDbMain
 | 
|    );
 | 
|    assert( (db->flags & SQLITE_Vacuum)!=0 );
 | 
|    db->flags &= ~SQLITE_Vacuum;
 | 
|    if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
|  
 | 
| -  /* Copy over the sequence table
 | 
| -  */
 | 
| -  rc = execExecSql(db, pzErrMsg,
 | 
| -      "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' "
 | 
| -      "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' "
 | 
| -  );
 | 
| -  if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
| -  rc = execExecSql(db, pzErrMsg,
 | 
| -      "SELECT 'INSERT INTO vacuum_db.' || quote(name) "
 | 
| -      "|| ' SELECT * FROM main.' || quote(name) || ';' "
 | 
| -      "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';"
 | 
| -  );
 | 
| -  if( rc!=SQLITE_OK ) goto end_of_vacuum;
 | 
| -
 | 
| -
 | 
|    /* Copy the triggers, views, and virtual tables from the main database
 | 
|    ** over to the temporary database.  None of these objects has any
 | 
|    ** associated storage, so all we have to do is copy their entries
 | 
|    ** from the SQLITE_MASTER table.
 | 
|    */
 | 
| -  rc = execSql(db, pzErrMsg,
 | 
| -      "INSERT INTO vacuum_db.sqlite_master "
 | 
| -      "  SELECT type, name, tbl_name, rootpage, sql"
 | 
| -      "    FROM main.sqlite_master"
 | 
| -      "   WHERE type='view' OR type='trigger'"
 | 
| -      "      OR (type='table' AND rootpage=0)"
 | 
| +  rc = execSqlF(db, pzErrMsg,
 | 
| +      "INSERT INTO vacuum_db.sqlite_master"
 | 
| +      " SELECT*FROM \"%w\".sqlite_master"
 | 
| +      " WHERE type IN('view','trigger')"
 | 
| +      " OR(type='table'AND rootpage=0)",
 | 
| +      zDbMain
 | 
|    );
 | 
|    if( rc ) goto end_of_vacuum;
 | 
|  
 | 
| @@ -342,10 +319,11 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
 | 
|  
 | 
|  end_of_vacuum:
 | 
|    /* Restore the original value of db->flags */
 | 
| +  db->init.iDb = 0;
 | 
|    db->flags = saved_flags;
 | 
|    db->nChange = saved_nChange;
 | 
|    db->nTotalChange = saved_nTotalChange;
 | 
| -  db->xTrace = saved_xTrace;
 | 
| +  db->mTrace = saved_mTrace;
 | 
|    sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
 | 
|  
 | 
|    /* Currently there is an SQL level transaction open on the vacuum
 | 
| 
 |