1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/browser/dom_storage/dom_storage_database.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/bind.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/statement.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/transaction.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/sqlite/sqlite3.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const base::FilePath::CharType kJournal[] = FILE_PATH_LITERAL("-journal");
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anon namespace
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace content {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
23bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbase::FilePath DOMStorageDatabase::GetJournalFilePath(
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& database_path) {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType journal_file_name =
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      database_path.BaseName().value() + kJournal;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return database_path.DirName().Append(journal_file_name);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
30bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageDatabase::DOMStorageDatabase(const base::FilePath& file_path)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : file_path_(file_path) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: in normal use we should never get an empty backing path here.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // However, the unit test for this class can contruct an instance
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with an empty path.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Init();
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageDatabase::DOMStorageDatabase() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Init();
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageDatabase::Init() {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  failed_to_open_ = false;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tried_to_recreate_ = false;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  known_to_be_empty_ = false;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageDatabase::~DOMStorageDatabase() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (known_to_be_empty_ && !file_path_.empty()) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delete the db and any lingering journal file from disk.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Close();
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    sql::Connection::Delete(file_path_);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageDatabase::ReadAllValues(DOMStorageValuesMap* result) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!LazyOpen(false))
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   "SELECT * from ItemTable"));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(statement.is_valid());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (statement.Step()) {
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::string16 key = statement.ColumnString16(0);
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::string16 value;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.ColumnBlobAsString16(1, &value);
687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    (*result)[key] = base::NullableString16(value, false);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  known_to_be_empty_ = result->empty();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageDatabase::CommitChanges(bool clear_all_first,
74bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                       const DOMStorageValuesMap& changes) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!LazyOpen(!changes.empty())) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we're being asked to commit changes that will result in an
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // empty database, we return true if the database file doesn't exist.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return clear_all_first && changes.empty() &&
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch           !base::PathExists(file_path_);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool old_known_to_be_empty = known_to_be_empty_;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Transaction transaction(db_.get());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!transaction.Begin())
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (clear_all_first) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->Execute("DELETE FROM ItemTable"))
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    known_to_be_empty_ = true;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool did_delete = false;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool did_insert = false;
95bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  DOMStorageValuesMap::const_iterator it = changes.begin();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(; it != changes.end(); ++it) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement statement;
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::string16 key = it->first;
997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::NullableString16 value = it->second;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (value.is_null()) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         "DELETE FROM ItemTable WHERE key=?"));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      statement.BindString16(0, key);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      did_delete = true;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      statement.Assign(db_->GetCachedStatement(SQL_FROM_HERE,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INSERT INTO ItemTable VALUES (?,?)"));
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      statement.BindString16(0, key);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      statement.BindBlob(1, value.string().data(),
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         value.string().length() * sizeof(base::char16));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      known_to_be_empty_ = false;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      did_insert = true;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(statement.is_valid());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.Run();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!known_to_be_empty_ && did_delete && !did_insert) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "SELECT count(key) from ItemTable"));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (statement.Step())
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      known_to_be_empty_ = statement.ColumnInt(0) == 0;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = transaction.Commit();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!success)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    known_to_be_empty_ = old_known_to_be_empty;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
131bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageDatabase::LazyOpen(bool create_if_needed) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (failed_to_open_) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Don't try to open a database that we know has failed
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // already.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsOpen())
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool database_exists = base::PathExists(file_path_);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!database_exists && !create_if_needed) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the file doesn't exist already and we haven't been asked to create
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a file on disk, then we don't bother opening the database. This means
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we wait until we absolutely need to put something onto disk before we
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // do so.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(new sql::Connection());
152bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  db_->set_histogram_tag("DOMStorageDatabase");
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_path_.empty()) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This code path should only be triggered by unit tests.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->OpenInMemory()) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Unable to open DOM storage database in memory.";
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      failed_to_open_ = true;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!db_->Open(file_path_)) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Unable to open DOM storage database at "
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << file_path_.value()
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << " error: " << db_->GetErrorMessage();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (database_exists && !tried_to_recreate_)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return DeleteFileAndRecreate();
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      failed_to_open_ = true;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sql::Connection uses UTF-8 encoding, but WebCore style databases use
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UTF-16, so ensure we match.
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignore_result(db_->Execute("PRAGMA encoding=\"UTF-16\""));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!database_exists) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is a new database, create the table and we're done!
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CreateTableV2())
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The database exists already - check if we need to upgrade
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and whether it's usable (i.e. not corrupted).
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SchemaVersion current_version = DetectSchemaVersion();
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_version == V2) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (current_version == V1) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (UpgradeVersion1To2())
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the exceptional case - to try and recover we'll attempt
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to delete the file and start again.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Close();
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DeleteFileAndRecreate();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
200bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochDOMStorageDatabase::SchemaVersion DOMStorageDatabase::DetectSchemaVersion() {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsOpen());
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Connection::Open() may succeed even if the file we try and open is not a
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // database, however in the case that the database is corrupted to the point
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that SQLite doesn't actually think it's a database,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sql::Connection::GetCachedStatement will DCHECK when we later try and
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // run statements. So we run a query here that will not DCHECK but fail
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on an invalid database to verify that what we've opened is usable.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (db_->ExecuteAndReturnErrorCode("PRAGMA auto_vacuum") != SQLITE_OK)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return INVALID;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look at the current schema - if it doesn't look right, assume corrupt.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->DoesTableExist("ItemTable") ||
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !db_->DoesColumnExist("ItemTable", "key") ||
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !db_->DoesColumnExist("ItemTable", "value"))
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return INVALID;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We must use a unique statement here as we aren't going to step it.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->GetUniqueStatement("SELECT key,value from ItemTable LIMIT 1"));
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (statement.DeclaredColumnType(0) != sql::COLUMN_TYPE_TEXT)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return INVALID;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (statement.DeclaredColumnType(1)) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::COLUMN_TYPE_BLOB:
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return V2;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case sql::COLUMN_TYPE_TEXT:
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return V1;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return INVALID;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
234bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageDatabase::CreateTableV2() {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsOpen());
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->Execute(
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CREATE TABLE ItemTable ("
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "key TEXT UNIQUE ON CONFLICT REPLACE, "
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "value BLOB NOT NULL ON CONFLICT FAIL)");
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageDatabase::DeleteFileAndRecreate() {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!IsOpen());
2457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(base::PathExists(file_path_));
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should only try and do this once.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tried_to_recreate_)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tried_to_recreate_ = true;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If it's not a directory and we can delete the file, try and open it again.
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::DirectoryExists(file_path_) &&
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      sql::Connection::Delete(file_path_)) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LazyOpen(true);
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  failed_to_open_ = true;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
263bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool DOMStorageDatabase::UpgradeVersion1To2() {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsOpen());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(DetectSchemaVersion() == V1);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_->GetCachedStatement(SQL_FROM_HERE,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT * FROM ItemTable"));
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(statement.is_valid());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need to migrate from TEXT value column to BLOB.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Store the current database content so we can re-insert
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the data into the new V2 table.
274bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  DOMStorageValuesMap values;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (statement.Step()) {
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::string16 key = statement.ColumnString16(0);
2777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::NullableString16 value(statement.ColumnString16(1), false);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    values[key] = value;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Transaction migration(db_.get());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return migration.Begin() &&
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_->Execute("DROP TABLE ItemTable") &&
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateTableV2() &&
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CommitChanges(false, values) &&
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      migration.Commit();
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
289bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid DOMStorageDatabase::Close() {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  db_.reset(NULL);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
293bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace content
294