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