Beispiel #1
0
/*
** Initialize all database files - the main database file, the file
** used to store temporary tables, and any additional database files
** created using ATTACH statements.  Return a success code.  If an
** error occurs, write an error message into *pzErrMsg.
**
** After the database is initialized, the SQLITE_Initialized
** bit is set in the flags field of the sqlite structure.  An
** attempt is made to initialize the database as soon as it
** is opened.  If that fails (perhaps because another process
** has the sqlite_master table locked) than another attempt
** is made the first time the database is accessed.
*/
int sqliteInit(sqlite *db, char **pzErrMsg){
  int i, rc;
  
  if( db->init.busy ) return SQLITE_OK;
  assert( (db->flags & SQLITE_Initialized)==0 );
  rc = SQLITE_OK;
  db->init.busy = 1;
  for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
    if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
    assert( i!=1 );  /* Should have been initialized together with 0 */
    rc = sqliteInitOne(db, i, pzErrMsg);
    if( rc ){
      sqliteResetInternalSchema(db, i);
    }
  }
  db->init.busy = 0;
  if( rc==SQLITE_OK ){
    db->flags |= SQLITE_Initialized;
    sqliteCommitInternalChanges(db);
  }

  /* If the database is in formats 1 or 2, then upgrade it to
  ** version 3.  This will reconstruct all indices.  If the
  ** upgrade fails for any reason (ex: out of disk space, database
  ** is read only, interrupt received, etc.) then fail the init.
  */
  if( rc==SQLITE_OK && db->file_format<3 ){
    char *zErr = 0;
    InitData initData;
    int meta[SQLITE_N_BTREE_META];

    db->magic = SQLITE_MAGIC_OPEN;
    initData.db = db;
    initData.pzErrMsg = &zErr;
    db->file_format = 3;
    rc = sqlite_exec(db,
      "BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
      upgrade_3_callback,
      &initData,
      &zErr);
    if( rc==SQLITE_OK ){
      sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
      meta[2] = 4;
      sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
      sqlite_exec(db, "COMMIT", 0, 0, 0);
    }
    if( rc!=SQLITE_OK ){
      sqliteSetString(pzErrMsg, 
        "unable to upgrade database to the version 2.6 format",
        zErr ? ": " : 0, zErr, (char*)0);
    }
    sqlite_freemem(zErr);
  }

  if( rc!=SQLITE_OK ){
    db->flags &= ~SQLITE_Initialized;
  }
  return rc;
}
Beispiel #2
0
/*
** Attempt to read the database schema and initialize internal
** data structures for a single database file.  The index of the
** database file is given by iDb.  iDb==0 is used for the main
** database.  iDb==1 should never be used.  iDb>=2 is used for
** auxiliary databases.  Return one of the SQLITE_ error codes to
** indicate success or failure.
*/
static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
  int rc;
  BtCursor *curMain;
  int size;
  Table *pTab;
  char const *azArg[6];
  char zDbNum[30];
  int meta[SQLITE_N_BTREE_META];
  InitData initData;
  char const *zMasterSchema;
  char const *zMasterName;
  char *zSql = 0;

  /*
  ** The master database table has a structure like this
  */
  static char master_schema[] = 
     "CREATE TABLE sqlite_master(\n"
     "  type text,\n"
     "  name text,\n"
     "  tbl_name text,\n"
     "  rootpage integer,\n"
     "  sql text\n"
     ")"
  ;
  static char temp_master_schema[] = 
     "CREATE TEMP TABLE sqlite_temp_master(\n"
     "  type text,\n"
     "  name text,\n"
     "  tbl_name text,\n"
     "  rootpage integer,\n"
     "  sql text\n"
     ")"
  ;

  assert( iDb>=0 && iDb<db->nDb );

  /* zMasterSchema and zInitScript are set to point at the master schema
  ** and initialisation script appropriate for the database being
  ** initialised. zMasterName is the name of the master table.
  */
  if( iDb==1 ){
    zMasterSchema = temp_master_schema;
    zMasterName = TEMP_MASTER_NAME;
  }else{
    zMasterSchema = master_schema;
    zMasterName = MASTER_NAME;
  }

  /* Construct the schema table.
  */
  sqliteSafetyOff(db);
  azArg[0] = "table";
  azArg[1] = zMasterName;
  azArg[2] = "2";
  azArg[3] = zMasterSchema;
  sprintf(zDbNum, "%d", iDb);
  azArg[4] = zDbNum;
  azArg[5] = 0;
  initData.db = db;
  initData.pzErrMsg = pzErrMsg;
  sqliteInitCallback(&initData, 5, (char **)azArg, 0);
  pTab = sqliteFindTable(db, zMasterName, db->aDb[iDb].zName);
  if( pTab ){
    pTab->readOnly = 1;
  }else{
    return SQLITE_NOMEM;
  }
  sqliteSafetyOn(db);

  /* Create a cursor to hold the database open
  */
  if( db->aDb[iDb].pBt==0 ) return SQLITE_OK;
  rc = sqliteBtreeCursor(db->aDb[iDb].pBt, 2, 0, &curMain);
  if( rc ){
    sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0);
    return rc;
  }

  /* Get the database meta information
  */
  rc = sqliteBtreeGetMeta(db->aDb[iDb].pBt, meta);
  if( rc ){
    sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0);
    sqliteBtreeCloseCursor(curMain);
    return rc;
  }
  db->aDb[iDb].schema_cookie = meta[1];
  if( iDb==0 ){
    db->next_cookie = meta[1];
    db->file_format = meta[2];
    size = meta[3];
    if( size==0 ){ size = MAX_PAGES; }
    db->cache_size = size;
    db->safety_level = meta[4];
    if( meta[6]>0 && meta[6]<=2 && db->temp_store==0 ){
      db->temp_store = meta[6];
    }
    if( db->safety_level==0 ) db->safety_level = 2;

    /*
    **  file_format==1    Version 2.1.0.
    **  file_format==2    Version 2.2.0. Add support for INTEGER PRIMARY KEY.
    **  file_format==3    Version 2.6.0. Fix empty-string index bug.
    **  file_format==4    Version 2.7.0. Add support for separate numeric and
    **                    text datatypes.
    */
    if( db->file_format==0 ){
      /* This happens if the database was initially empty */
      db->file_format = 4;
    }else if( db->file_format>4 ){
      sqliteBtreeCloseCursor(curMain);
      sqliteSetString(pzErrMsg, "unsupported file format", (char*)0);
      return SQLITE_ERROR;
    }
  }else if( iDb!=1 && (db->file_format!=meta[2] || db->file_format<4) ){
    assert( db->file_format>=4 );
    if( meta[2]==0 ){
      sqliteSetString(pzErrMsg, "cannot attach empty database: ",
         db->aDb[iDb].zName, (char*)0);
    }else{
      sqliteSetString(pzErrMsg, "incompatible file format in auxiliary "
         "database: ", db->aDb[iDb].zName, (char*)0);
    }
    sqliteBtreeClose(db->aDb[iDb].pBt);
    db->aDb[iDb].pBt = 0;
    return SQLITE_FORMAT;
  }
  sqliteBtreeSetCacheSize(db->aDb[iDb].pBt, db->cache_size);
  sqliteBtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[4]==0 ? 2 : meta[4]);

  /* Read the schema information out of the schema tables
  */
  assert( db->init.busy );
  sqliteSafetyOff(db);

  /* The following SQL will read the schema from the master tables.
  ** The first version works with SQLite file formats 2 or greater.
  ** The second version is for format 1 files.
  **
  ** Beginning with file format 2, the rowid for new table entries
  ** (including entries in sqlite_master) is an increasing integer.
  ** So for file format 2 and later, we can play back sqlite_master
  ** and all the CREATE statements will appear in the right order.
  ** But with file format 1, table entries were random and so we
  ** have to make sure the CREATE TABLEs occur before their corresponding
  ** CREATE INDEXs.  (We don't have to deal with CREATE VIEW or
  ** CREATE TRIGGER in file format 1 because those constructs did
  ** not exist then.) 
  */
  if( db->file_format>=2 ){
    sqliteSetString(&zSql, 
        "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
       db->aDb[iDb].zName, "\".", zMasterName, (char*)0);
  }else{
    sqliteSetString(&zSql, 
        "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
       db->aDb[iDb].zName, "\".", zMasterName, 
       " WHERE type IN ('table', 'index')"
       " ORDER BY CASE type WHEN 'table' THEN 0 ELSE 1 END", (char*)0);
  }
  rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0);

  sqliteFree(zSql);
  sqliteSafetyOn(db);
  sqliteBtreeCloseCursor(curMain);
  if( sqlite_malloc_failed ){
    sqliteSetString(pzErrMsg, "out of memory", (char*)0);
    rc = SQLITE_NOMEM;
    sqliteResetInternalSchema(db, 0);
  }
  if( rc==SQLITE_OK ){
    DbSetProperty(db, iDb, DB_SchemaLoaded);
  }else{
    sqliteResetInternalSchema(db, iDb);
  }
  return rc;
}