12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2012 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)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/directory_backing_store.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/connection.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/statement.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/transaction.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/base/node_ordinal.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/bookmark_specifics.pb.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/sync.pb.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable-inl.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/syncable_columns.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sync/syncable/syncable_util.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/util/time.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncable {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This just has to be big enough to hold an UPDATE or INSERT statement that
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modifies all the columns in the entry table.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const string::size_type kUpdateStatementBufferSize = 2048;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Increment this version whenever updating DB tables.
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int32 kCurrentDBVersion = 86;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Iterate over the fields of |entry| and bind each to |statement| for
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// updating.  Returns the number of args bound.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BindFields(const EntryKernel& entry,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                sql::Statement* statement) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = 0;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i = 0;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->BindInt64(index++, entry.ref(static_cast<Int64Field>(i)));
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < TIME_FIELDS_END; ++i) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->BindInt64(index++,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         TimeToProtoTime(
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             entry.ref(static_cast<TimeField>(i))));
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < ID_FIELDS_END; ++i) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->BindString(index++, entry.ref(static_cast<IdField>(i)).s_);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < BIT_FIELDS_END; ++i) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->BindInt(index++, entry.ref(static_cast<BitField>(i)));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < STRING_FIELDS_END; ++i) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->BindString(index++, entry.ref(static_cast<StringField>(i)));
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < PROTO_FIELDS_END; ++i) {
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string temp;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    entry.ref(static_cast<ProtoField>(i)).SerializeToString(&temp);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->BindBlob(index++, temp.data(), temp.length());
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for ( ; i < UNIQUE_POSITION_FIELDS_END; ++i) {
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string temp;
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    entry.ref(static_cast<UniquePositionField>(i)).SerializeToString(&temp);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->BindBlob(index++, temp.data(), temp.length());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The caller owns the returned EntryKernel*.  Assumes the statement currently
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// points to a valid row in the metas table. Returns NULL to indicate that
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// it detected a corruption in the data on unpacking.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<EntryKernel> UnpackEntry(sql::Statement* statement) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<EntryKernel> kernel(new EntryKernel());
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(statement->ColumnCount(), static_cast<int>(FIELD_COUNT));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i = 0;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (i = BEGIN_FIELDS; i < INT64_FIELDS_END; ++i) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel->put(static_cast<Int64Field>(i), statement->ColumnInt64(i));
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < TIME_FIELDS_END; ++i) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel->put(static_cast<TimeField>(i),
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                ProtoTimeToTime(statement->ColumnInt64(i)));
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < ID_FIELDS_END; ++i) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel->mutable_ref(static_cast<IdField>(i)).s_ =
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        statement->ColumnString(i);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < BIT_FIELDS_END; ++i) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel->put(static_cast<BitField>(i), (0 != statement->ColumnInt(i)));
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < STRING_FIELDS_END; ++i) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel->put(static_cast<StringField>(i),
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                statement->ColumnString(i));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for ( ; i < PROTO_FIELDS_END; ++i) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kernel->mutable_ref(static_cast<ProtoField>(i)).ParseFromArray(
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        statement->ColumnBlob(i), statement->ColumnByteLength(i));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for ( ; i < UNIQUE_POSITION_FIELDS_END; ++i) {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string temp;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement->ColumnBlobAsString(i, &temp);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sync_pb::UniquePosition proto;
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!proto.ParseFromString(temp)) {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      DVLOG(1) << "Unpacked invalid position.  Assuming the DB is corrupt";
1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return scoped_ptr<EntryKernel>();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    kernel->mutable_ref(static_cast<UniquePositionField>(i)) =
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        UniquePosition::FromProto(proto);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kernel.Pass();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string ComposeCreateTableColumnSpecs() {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ColumnSpec* begin = g_metas_columns;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const ColumnSpec* end = g_metas_columns + arraysize(g_metas_columns);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string query;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.reserve(kUpdateStatementBufferSize);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char separator = '(';
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (const ColumnSpec* column = begin; column != end; ++column) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    query.push_back(separator);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    separator = ',';
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    query.append(column->name);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    query.push_back(' ');
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    query.append(column->spec);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.push_back(')');
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return query;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AppendColumnList(std::string* output) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* joiner = " ";
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Be explicit in SELECT order to match up with UnpackEntry.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = BEGIN_FIELDS; i < FIELD_COUNT; ++i) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output->append(joiner);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    output->append(ColumnName(i));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    joiner = ", ";
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DirectoryBackingStore implementation.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryBackingStore::DirectoryBackingStore(const string& dir_name)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : db_(new sql::Connection()),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dir_name_(dir_name),
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    needs_column_refresh_(false) {
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  db_->set_histogram_tag("SyncDirectory");
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryBackingStore::DirectoryBackingStore(const string& dir_name,
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             sql::Connection* db)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : db_(db),
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dir_name_(dir_name),
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    needs_column_refresh_(false) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DirectoryBackingStore::~DirectoryBackingStore() {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DirectoryBackingStore::DeleteEntries(EntryTable from,
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const MetahandleSet& handles) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handles.empty())
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement statement;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Call GetCachedStatement() separately to get different statements for
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // different tables.
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (from) {
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case METAS_TABLE:
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      statement.Assign(db_->GetCachedStatement(
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SQL_FROM_HERE, "DELETE FROM metas WHERE metahandle = ?"));
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case DELETE_JOURNAL_TABLE:
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      statement.Assign(db_->GetCachedStatement(
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          SQL_FROM_HERE, "DELETE FROM deleted_metas WHERE metahandle = ?"));
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (MetahandleSet::const_iterator i = handles.begin(); i != handles.end();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++i) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.BindInt64(0, *i);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!statement.Run())
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    statement.Reset(true);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::SaveChanges(
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Directory::SaveChangesSnapshot& snapshot) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(db_->is_open());
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Back out early if there is nothing to write.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool save_info =
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status);
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (snapshot.dirty_metas.empty() && snapshot.metahandles_to_purge.empty() &&
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      snapshot.delete_journals.empty() &&
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      snapshot.delete_journals_to_purge.empty() && !save_info) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Transaction transaction(db_.get());
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!transaction.Begin())
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrepareSaveEntryStatement(METAS_TABLE, &save_meta_statment_);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (EntryKernelSet::const_iterator i = snapshot.dirty_metas.begin();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       i != snapshot.dirty_metas.end(); ++i) {
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK((*i)->is_dirty());
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!SaveEntryToDB(&save_meta_statment_, **i))
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!DeleteEntries(METAS_TABLE, snapshot.metahandles_to_purge))
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PrepareSaveEntryStatement(DELETE_JOURNAL_TABLE,
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            &save_delete_journal_statment_);
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (EntryKernelSet::const_iterator i = snapshot.delete_journals.begin();
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       i != snapshot.delete_journals.end(); ++i) {
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!SaveEntryToDB(&save_delete_journal_statment_, **i))
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!DeleteEntries(DELETE_JOURNAL_TABLE, snapshot.delete_journals_to_purge))
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (save_info) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const Directory::PersistedKernelInfo& info = snapshot.kernel_info;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s1(db_->GetCachedStatement(
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SQL_FROM_HERE,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "UPDATE share_info "
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "SET store_birthday = ?, "
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "next_id = ?, "
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "bag_of_chips = ?"));
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s1.BindString(0, info.store_birthday);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s1.BindInt64(1, info.next_id);
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    s1.BindBlob(2, info.bag_of_chips.data(), info.bag_of_chips.size());
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!s1.Run())
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(db_->GetLastChangeCount(), 1);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s2(db_->GetCachedStatement(
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            SQL_FROM_HERE,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "INSERT OR REPLACE "
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "INTO models (model_id, progress_marker, transaction_version) "
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "VALUES (?, ?, ?)"));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ModelTypeSet protocol_types = ProtocolTypes();
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         iter.Inc()) {
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ModelType type = iter.Get();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We persist not ModelType but rather a protobuf-derived ID.
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      string model_id = ModelTypeEnumToModelId(type);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string progress_marker;
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      info.download_progress[type].SerializeToString(&progress_marker);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s2.BindBlob(0, model_id.data(), model_id.length());
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s2.BindBlob(1, progress_marker.data(), progress_marker.length());
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      s2.BindInt64(2, info.transaction_version[type]);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!s2.Run())
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(db_->GetLastChangeCount(), 1);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s2.Reset(true);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return transaction.Commit();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::InitializeTables() {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Transaction transaction(db_.get());
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!transaction.Begin())
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int version_on_disk = GetVersion();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Upgrade from version 67. Version 67 was widely distributed as the original
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bookmark Sync release. Version 68 removed unique naming.
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 67) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion67To68())
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 68;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 69 introduced additional datatypes.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 68) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion68To69())
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 69;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 69) {
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion69To70())
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 70;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 71 changed the sync progress information to be per-datatype.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 70) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion70To71())
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 71;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 72 removed extended attributes, a legacy way to do extensible
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // key/value information, stored in their own table.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 71) {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion71To72())
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 72;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 73 added a field for notification state.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 72) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion72To73())
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 73;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 74 added state for the autofill migration.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 73) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion73To74())
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 74;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 75 migrated from int64-based timestamps to per-datatype tokens.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 74) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion74To75())
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 75;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 76 removed all (5) autofill migration related columns.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 75) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion75To76())
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 76;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 77 standardized all time fields to ms since the Unix
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // epoch.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 76) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion76To77())
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 77;
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 78 added the column base_server_specifics to the metas table.
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 77) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion77To78())
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 78;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 79 migration is a one-time fix for some users in a bad state.
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 78) {
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion78To79())
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 79;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 80 migration is adding the bag_of_chips column.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 79) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion79To80())
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 80;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 81 replaces the int64 server_position_in_parent_field
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with a blob server_ordinal_in_parent field.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 80) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion80To81())
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 81;
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 82 migration added transaction_version column per data type.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 81) {
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion81To82())
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 82;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 83 migration added transaction_version column per sync entry.
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == 82) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (MigrateVersion82To83())
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 83;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Version 84 migration added deleted_metas table.
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (version_on_disk == 83) {
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (MigrateVersion83To84())
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      version_on_disk = 84;
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Version 85 migration removes the initial_sync_ended bits.
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (version_on_disk == 84) {
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (MigrateVersion84To85())
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      version_on_disk = 85;
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Version 86 migration converts bookmarks to the unique positioning system.
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // It also introduces a new field to store a unique ID for each bookmark.
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (version_on_disk == 85) {
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (MigrateVersion85To86())
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      version_on_disk = 86;
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If one of the migrations requested it, drop columns that aren't current.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It's only safe to do this after migrating all the way to the current
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // version.
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!RefreshColumns())
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      version_on_disk = 0;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A final, alternative catch-all migration to simply re-sync everything.
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (version_on_disk != kCurrentDBVersion) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (version_on_disk > kCurrentDBVersion)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Fallback (re-sync everything) migration path.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Old/null sync database, version " << version_on_disk;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delete the existing database (if any), and create a fresh one.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DropAllTables();
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!CreateTables())
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(db_->GetUniqueStatement(
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "SELECT db_create_version, db_create_time FROM share_info"));
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!s.Step())
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string db_create_version = s.ColumnString(0);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int db_create_time = s.ColumnInt(1);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "DB created at " << db_create_time << " by version " <<
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      db_create_version;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return transaction.Commit();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function drops unused columns by creating a new table that contains only
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the currently used columns then copying all rows from the old tables into
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this new one.  The tables are then rearranged so the new replaces the old.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::RefreshColumns() {
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(needs_column_refresh_);
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a new table named temp_metas.
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("temp_metas");
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateMetasTable(true))
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Populate temp_metas from metas.
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // At this point, the metas table may contain columns belonging to obsolete
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // schema versions.  This statement explicitly lists only the columns that
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // belong to the current schema version, so the obsolete columns will be
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // effectively dropped once we rename temp_metas over top of metas.
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string query = "INSERT INTO temp_metas (";
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppendColumnList(&query);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(") SELECT ");
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AppendColumnList(&query);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(" FROM metas");
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(query.c_str()))
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop metas.
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("metas");
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rename temp_metas -> metas.
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute("ALTER TABLE temp_metas RENAME TO metas"))
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Repeat the process for share_info.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("temp_share_info");
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateShareInfoTable(true))
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(rlarocque, 124140): Remove notification_state.
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INSERT INTO temp_share_info (id, name, store_birthday, "
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "db_create_version, db_create_time, next_id, cache_guid,"
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "notification_state, bag_of_chips) "
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "SELECT id, name, store_birthday, db_create_version, "
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "db_create_time, next_id, cache_guid, notification_state, "
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "bag_of_chips "
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "FROM share_info"))
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("share_info");
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute("ALTER TABLE temp_share_info RENAME TO share_info"))
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  needs_column_refresh_ = false;
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
496868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool DirectoryBackingStore::LoadEntries(
497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    Directory::MetahandlesMap* handles_map) {
498868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  string select;
499868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  select.reserve(kUpdateStatementBufferSize);
500868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  select.append("SELECT ");
501868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  AppendColumnList(&select);
502868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  select.append(" FROM metas");
503868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
504868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  sql::Statement s(db_->GetUniqueStatement(select.c_str()));
505868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
506868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (s.Step()) {
507868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<EntryKernel> kernel = UnpackEntry(&s);
508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // A null kernel is evidence of external data corruption.
509868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!kernel)
510868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return false;
511868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
512868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int64 handle = kernel->ref(META_HANDLE);
513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (*handles_map)[handle] = kernel.release();
514868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
515868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return s.Succeeded();
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DirectoryBackingStore::LoadDeleteJournals(
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    JournalIndex* delete_journals) {
520868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  string select;
521868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  select.reserve(kUpdateStatementBufferSize);
522868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  select.append("SELECT ");
523868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  AppendColumnList(&select);
524868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  select.append(" FROM deleted_metas");
525868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
526868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  sql::Statement s(db_->GetUniqueStatement(select.c_str()));
527868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
528868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  while (s.Step()) {
529868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    scoped_ptr<EntryKernel> kernel = UnpackEntry(&s);
530868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // A null kernel is evidence of external data corruption.
531868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!kernel)
532868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return false;
533868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    delete_journals->insert(kernel.release());
534868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
535868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return s.Succeeded();
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetUniqueStatement(
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "SELECT store_birthday, next_id, cache_guid, bag_of_chips "
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "FROM share_info"));
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!s.Step())
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info->kernel_info.store_birthday = s.ColumnString(0);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info->kernel_info.next_id = s.ColumnInt64(1);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info->cache_guid = s.ColumnString(2);
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    s.ColumnBlobAsString(3, &(info->kernel_info.bag_of_chips));
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify there was only one row returned.
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!s.Step());
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(s.Succeeded());
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetUniqueStatement(
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "SELECT model_id, progress_marker, "
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "transaction_version FROM models"));
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (s.Step()) {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ModelType type = ModelIdToModelTypeEnum(s.ColumnBlob(0),
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              s.ColumnByteLength(0));
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (type != UNSPECIFIED && type != TOP_LEVEL_FOLDER) {
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        info->kernel_info.download_progress[type].ParseFromArray(
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            s.ColumnBlob(1), s.ColumnByteLength(1));
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        info->kernel_info.transaction_version[type] = s.ColumnInt64(2);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!s.Succeeded())
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        db_->GetUniqueStatement(
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "SELECT MAX(metahandle) FROM metas"));
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!s.Step())
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    info->max_metahandle = s.ColumnInt64(0);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify only one row was returned.
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!s.Step());
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(s.Succeeded());
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/* static */
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DirectoryBackingStore::SaveEntryToDB(sql::Statement* save_statement,
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const EntryKernel& entry) {
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  save_statement->Reset(true);
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BindFields(entry, save_statement);
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return save_statement->Run();
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::DropDeletedEntries() {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute("DELETE FROM metas "
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "WHERE is_del > 0 "
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "AND is_unsynced < 1 "
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "AND is_unapplied_update < 1")) {
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute("DELETE FROM metas "
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "WHERE is_del > 0 "
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    "AND id LIKE 'c%'")) {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::SafeDropTable(const char* table_name) {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string query = "DROP TABLE IF EXISTS ";
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(table_name);
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->Execute(query.c_str());
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DirectoryBackingStore::DropAllTables() {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("metas");
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("temp_metas");
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("share_info");
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("temp_share_info");
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("share_version");
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("extended_attributes");
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("models");
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("temp_models");
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  needs_column_refresh_ = false;
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ModelType DirectoryBackingStore::ModelIdToModelTypeEnum(
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const void* data, int size) {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_pb::EntitySpecifics specifics;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!specifics.ParseFromArray(data, size))
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return UNSPECIFIED;
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetModelTypeFromSpecifics(specifics);
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)string DirectoryBackingStore::ModelTypeEnumToModelId(ModelType model_type) {
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_pb::EntitySpecifics specifics;
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddDefaultFieldValue(model_type, &specifics);
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return specifics.SerializeAsString();
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DirectoryBackingStore::GenerateCacheGUID() {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Generate a GUID with 128 bits of randomness.
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kGuidBytes = 128 / 8;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string guid;
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Base64Encode(base::RandBytesAsString(kGuidBytes), &guid);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return guid;
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateToSpecifics(
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* old_columns,
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* specifics_column,
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void (*handler_function)(sql::Statement* old_value_query,
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int old_value_column,
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             sync_pb::EntitySpecifics* mutable_new_value)) {
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string query_sql = base::StringPrintf(
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT metahandle, %s, %s FROM metas", specifics_column, old_columns);
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string update_sql = base::StringPrintf(
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE metas SET %s = ? WHERE metahandle = ?", specifics_column);
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement query(db_->GetUniqueStatement(query_sql.c_str()));
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement update(db_->GetUniqueStatement(update_sql.c_str()));
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (query.Step()) {
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 metahandle = query.ColumnInt64(0);
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string new_value_bytes;
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    query.ColumnBlobAsString(1, &new_value_bytes);
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_pb::EntitySpecifics new_value;
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_value.ParseFromString(new_value_bytes);
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handler_function(&query, 2, &new_value);
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_value.SerializeToString(&new_value_bytes);
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update.BindBlob(0, new_value_bytes.data(), new_value_bytes.length());
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update.BindInt64(1, metahandle);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!update.Run())
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update.Reset(true);
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return query.Succeeded();
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::SetVersion(int version) {
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement s(db_->GetCachedStatement(
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          SQL_FROM_HERE, "UPDATE share_version SET data = ?"));
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  s.BindInt(0, version);
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return s.Run();
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int DirectoryBackingStore::GetVersion() {
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->DoesTableExist("share_version"))
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(db_->GetUniqueStatement(
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "SELECT data FROM share_version"));
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (statement.Step()) {
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return statement.ColumnInt(0);
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion67To68() {
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This change simply removed three columns:
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   string NAME
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   string UNSANITIZED_NAME
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   string SERVER_NAME
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No data migration is necessary, but we should do a column refresh.
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(68);
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  needs_column_refresh_ = true;
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion69To70() {
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Added "unique_client_tag", renamed "singleton_tag" to unique_server_tag
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(70);
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE metas ADD COLUMN unique_server_tag varchar"))
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE metas ADD COLUMN unique_client_tag varchar"))
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  needs_column_refresh_ = true;
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "UPDATE metas SET unique_server_tag = singleton_tag"))
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback passed to MigrateToSpecifics for the v68->v69 migration.  See
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MigrateVersion68To69().
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void EncodeBookmarkURLAndFavicon(sql::Statement* old_value_query,
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int old_value_column,
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 sync_pb::EntitySpecifics* mutable_new_value) {
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Extract data from the column trio we expect.
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool old_is_bookmark_object = old_value_query->ColumnBool(old_value_column);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string old_url = old_value_query->ColumnString(old_value_column + 1);
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string old_favicon;
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  old_value_query->ColumnBlobAsString(old_value_column + 2, &old_favicon);
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool old_is_dir = old_value_query->ColumnBool(old_value_column + 3);
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (old_is_bookmark_object) {
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_pb::BookmarkSpecifics* bookmark_data =
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mutable_new_value->mutable_bookmark();
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!old_is_dir) {
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_data->set_url(old_url);
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_data->set_favicon(old_favicon);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion68To69() {
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In Version 68, there were columns on table 'metas':
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   string BOOKMARK_URL
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   string SERVER_BOOKMARK_URL
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   blob BOOKMARK_FAVICON
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   blob SERVER_BOOKMARK_FAVICON
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In version 69, these columns went away in favor of storing
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a serialized EntrySpecifics protobuf in the columns:
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   protobuf blob SPECIFICS
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   protobuf blob SERVER_SPECIFICS
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For bookmarks, EntrySpecifics is extended as per
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bookmark_specifics.proto. This migration converts bookmarks from the
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // former scheme to the latter scheme.
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, add the two new columns to the schema.
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE metas ADD COLUMN specifics blob"))
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE metas ADD COLUMN server_specifics blob"))
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Next, fold data from the old columns into the new protobuf columns.
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MigrateToSpecifics(("is_bookmark_object, bookmark_url, "
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "bookmark_favicon, is_dir"),
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "specifics",
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &EncodeBookmarkURLAndFavicon)) {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MigrateToSpecifics(("server_is_bookmark_object, "
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "server_bookmark_url, "
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "server_bookmark_favicon, "
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "server_is_dir"),
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          "server_specifics",
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &EncodeBookmarkURLAndFavicon)) {
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Lastly, fix up the "Google Chrome" folder, which is of the TOP_LEVEL_FOLDER
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ModelType: it shouldn't have BookmarkSpecifics.
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "UPDATE metas SET specifics = NULL, server_specifics = NULL WHERE "
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "singleton_tag IN ('google_chrome')"))
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(69);
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  needs_column_refresh_ = true;  // Trigger deletion of old columns.
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Version 71, the columns 'initial_sync_ended' and 'last_sync_timestamp'
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// were removed from the share_info table.  They were replaced by
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the 'models' table, which has these values on a per-datatype basis.
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion70To71() {
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateV71ModelsTable())
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move data from the old share_info columns to the new models table.
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement fetch(db_->GetUniqueStatement(
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "SELECT last_sync_timestamp, initial_sync_ended FROM share_info"));
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!fetch.Step())
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 last_sync_timestamp = fetch.ColumnInt64(0);
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool initial_sync_ended = fetch.ColumnBool(1);
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify there were no additional rows returned.
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!fetch.Step());
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(fetch.Succeeded());
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement update(db_->GetUniqueStatement(
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "INSERT INTO models (model_id, "
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "last_download_timestamp, initial_sync_ended) VALUES (?, ?, ?)"));
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string bookmark_model_id = ModelTypeEnumToModelId(BOOKMARKS);
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update.BindBlob(0, bookmark_model_id.data(), bookmark_model_id.size());
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update.BindInt64(1, last_sync_timestamp);
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    update.BindBool(2, initial_sync_ended);
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!update.Run())
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop the columns from the old share_info table via a temp table.
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool kCreateAsTempShareInfo = true;
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateShareInfoTableVersion71(kCreateAsTempShareInfo))
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INSERT INTO temp_share_info (id, name, store_birthday, "
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "db_create_version, db_create_time, next_id, cache_guid) "
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "SELECT id, name, store_birthday, db_create_version, "
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "db_create_time, next_id, cache_guid FROM share_info"))
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("share_info");
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE temp_share_info RENAME TO share_info"))
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(71);
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion71To72() {
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 72 removed a table 'extended_attributes', whose
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // contents didn't matter.
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("extended_attributes");
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(72);
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion72To73() {
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 73 added one column to the table 'share_info': notification_state
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE share_info ADD COLUMN notification_state BLOB"))
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(73);
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion73To74() {
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 74 added the following columns to the table 'share_info':
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_migration_state
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   bookmarks_added_during_autofill_migration
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_migration_time
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_entries_added_during_migration
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_profiles_added_during_migration
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE share_info ADD COLUMN "
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "autofill_migration_state INT default 0"))
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE share_info ADD COLUMN "
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "bookmarks_added_during_autofill_migration "
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INT default 0"))
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE share_info ADD COLUMN autofill_migration_time "
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INT default 0"))
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE share_info ADD COLUMN "
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "autofill_entries_added_during_migration "
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INT default 0"))
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE share_info ADD COLUMN "
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "autofill_profiles_added_during_migration "
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INT default 0"))
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(74);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion74To75() {
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In version 74, there was a table 'models':
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     blob model_id (entity specifics, primary key)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     int last_download_timestamp
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     boolean initial_sync_ended
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In version 75, we deprecated the integer-valued last_download_timestamp,
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // using insted a protobuf-valued progress_marker field:
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     blob progress_marker
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The progress_marker values are initialized from the value of
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // last_download_timestamp, thereby preserving the download state.
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Move aside the old table and create a new empty one at the current schema.
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute("ALTER TABLE models RENAME TO temp_models"))
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CreateV75ModelsTable())
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement query(db_->GetUniqueStatement(
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "SELECT model_id, last_download_timestamp, initial_sync_ended "
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "FROM temp_models"));
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement update(db_->GetUniqueStatement(
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "INSERT INTO models (model_id, "
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "progress_marker, initial_sync_ended) VALUES (?, ?, ?)"));
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (query.Step()) {
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType type = ModelIdToModelTypeEnum(query.ColumnBlob(0),
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            query.ColumnByteLength(0));
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (type != UNSPECIFIED) {
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the |timestamp_token_for_migration| on a new
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // DataTypeProgressMarker, using the old value of last_download_timestamp.
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The server will turn this into a real token on our behalf the next
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // time we check for updates.
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_pb::DataTypeProgressMarker progress_marker;
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      progress_marker.set_data_type_id(
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetSpecificsFieldNumberFromModelType(type));
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      progress_marker.set_timestamp_token_for_migration(query.ColumnInt64(1));
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string progress_blob;
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      progress_marker.SerializeToString(&progress_blob);
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      update.BindBlob(0, query.ColumnBlob(0), query.ColumnByteLength(0));
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      update.BindBlob(1, progress_blob.data(), progress_blob.length());
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      update.BindBool(2, query.ColumnBool(2));
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!update.Run())
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      update.Reset(true);
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!query.Succeeded())
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop the old table.
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SafeDropTable("temp_models");
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(75);
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion75To76() {
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This change removed five columns:
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_migration_state
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   bookmarks_added_during_autofill_migration
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_migration_time
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_entries_added_during_migration
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   autofill_profiles_added_during_migration
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No data migration is necessary, but we should do a column refresh.
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(76);
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  needs_column_refresh_ = true;
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion76To77() {
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This change changes the format of stored timestamps to ms since
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the Unix epoch.
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On Windows, we used to store timestamps in FILETIME format (100s of
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ns since Jan 1, 1601).  Magic numbers taken from
1001c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// http://stackoverflow.com/questions/5398557/
1002c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//     java-library-for-dealing-with-win32-filetime
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// .
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TO_UNIX_TIME_MS(x) #x " = " #x " / 10000 - 11644473600000"
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On other platforms, we used to store timestamps in time_t format (s
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// since the Unix epoch).
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TO_UNIX_TIME_MS(x) #x " = " #x " * 1000"
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement update_timestamps(db_->GetUniqueStatement(
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "UPDATE metas SET "
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TO_UNIX_TIME_MS(mtime) ", "
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TO_UNIX_TIME_MS(server_mtime) ", "
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TO_UNIX_TIME_MS(ctime) ", "
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TO_UNIX_TIME_MS(server_ctime)));
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef TO_UNIX_TIME_MS
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update_timestamps.Run())
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(77);
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion77To78() {
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 78 added one column to table 'metas': base_server_specifics.
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE metas ADD COLUMN base_server_specifics BLOB")) {
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(78);
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion78To79() {
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some users are stuck with a DB that causes them to reuse existing IDs.  We
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // perform this one-time fixup on all users to help the few that are stuck.
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See crbug.com/142987 for details.
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "UPDATE share_info SET next_id = next_id - 65536")) {
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(79);
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion79To80() {
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "ALTER TABLE share_info ADD COLUMN bag_of_chips BLOB"))
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement update(db_->GetUniqueStatement(
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "UPDATE share_info SET bag_of_chips = ?"));
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // An empty message is serialized to an empty string.
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update.BindBlob(0, NULL, 0);
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update.Run())
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(80);
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion80To81() {
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if(!db_->Execute(
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         "ALTER TABLE metas ADD COLUMN server_ordinal_in_parent BLOB"))
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement get_positions(db_->GetUniqueStatement(
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "SELECT metahandle, server_position_in_parent FROM metas"));
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement put_ordinals(db_->GetUniqueStatement(
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE metas SET server_ordinal_in_parent = ?"
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "WHERE metahandle = ?"));
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while(get_positions.Step()) {
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 metahandle = get_positions.ColumnInt64(0);
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 position = get_positions.ColumnInt64(1);
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& ordinal = Int64ToNodeOrdinal(position).ToInternalValue();
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    put_ordinals.BindBlob(0, ordinal.data(), ordinal.length());
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    put_ordinals.BindInt64(1, metahandle);
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if(!put_ordinals.Run())
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    put_ordinals.Reset(true);
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(81);
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  needs_column_refresh_ = true;
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion81To82() {
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ALTER TABLE models ADD COLUMN transaction_version BIGINT default 0"))
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement update(db_->GetUniqueStatement(
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE models SET transaction_version = 0"));
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update.Run())
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(82);
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::MigrateVersion82To83() {
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version 83 added transaction_version on sync node.
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "ALTER TABLE metas ADD COLUMN transaction_version BIGINT default 0"))
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement update(db_->GetUniqueStatement(
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "UPDATE metas SET transaction_version = 0"));
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!update.Run())
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetVersion(83);
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DirectoryBackingStore::MigrateVersion83To84() {
11152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Version 84 added deleted_metas table to store deleted metas until we know
11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // for sure that the deletions are persisted in native models.
11172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  string query = "CREATE TABLE deleted_metas ";
11182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  query.append(ComposeCreateTableColumnSpecs());
11192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_->Execute(query.c_str()))
11202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
11212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetVersion(84);
11222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
11232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DirectoryBackingStore::MigrateVersion84To85() {
1126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Version 85 removes the initial_sync_ended flag.
11272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_->Execute("ALTER TABLE models RENAME TO temp_models"))
11282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
11292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CreateModelsTable())
11302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
11312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_->Execute("INSERT INTO models SELECT "
11322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    "model_id, progress_marker, transaction_version "
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    "FROM temp_models")) {
11342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
11352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
11362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeDropTable("temp_models");
11372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetVersion(85);
11392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
11402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
11412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DirectoryBackingStore::MigrateVersion85To86() {
1143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Version 86 removes both server ordinals and local NEXT_ID, PREV_ID and
1144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // SERVER_{POSITION,ORDINAL}_IN_PARENT and replaces them with UNIQUE_POSITION
1145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // and SERVER_UNIQUE_POSITION.
1146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!db_->Execute("ALTER TABLE metas ADD COLUMN "
1147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    "server_unique_position BLOB")) {
1148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!db_->Execute("ALTER TABLE metas ADD COLUMN "
1151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    "unique_position BLOB")) {
1152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!db_->Execute("ALTER TABLE metas ADD COLUMN "
1155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    "unique_bookmark_tag VARCHAR")) {
1156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Fetch the cache_guid from the DB, because we don't otherwise have access to
1160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // it from here.
1161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sql::Statement get_cache_guid(db_->GetUniqueStatement(
1162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "SELECT cache_guid FROM share_info"));
1163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!get_cache_guid.Step()) {
1164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
1165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string cache_guid = get_cache_guid.ColumnString(0);
1167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!get_cache_guid.Step());
1168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(get_cache_guid.Succeeded());
1169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sql::Statement get(db_->GetUniqueStatement(
1171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "SELECT "
1172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  metahandle, "
1173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  id, "
1174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  specifics, "
1175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  is_dir, "
1176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  unique_server_tag, "
1177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  server_ordinal_in_parent "
1178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "FROM metas"));
1179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note that we set both the local and server position based on the server
1181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // position.  We wll lose any unsynced local position changes.  Unfortunately,
1182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // there's nothing we can do to avoid that.  The NEXT_ID / PREV_ID values
1183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // can't be translated into a UNIQUE_POSTION in a reliable way.
1184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sql::Statement put(db_->GetCachedStatement(
1185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      SQL_FROM_HERE,
1186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "UPDATE metas SET"
1187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  server_unique_position = ?,"
1188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  unique_position = ?,"
1189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "  unique_bookmark_tag = ?"
1190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "WHERE metahandle = ?"));
1191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (get.Step()) {
1193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int64 metahandle = get.ColumnInt64(0);
1194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string id_string;
1196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    get.ColumnBlobAsString(1, &id_string);
1197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sync_pb::EntitySpecifics specifics;
1199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    specifics.ParseFromArray(
1200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        get.ColumnBlob(2), get.ColumnByteLength(2));
1201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool is_dir = get.ColumnBool(3);
1203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string server_unique_tag = get.ColumnString(4);
1205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string ordinal_string;
1207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    get.ColumnBlobAsString(5, &ordinal_string);
1208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NodeOrdinal ordinal(ordinal_string);
1209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string unique_bookmark_tag;
1212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We only maintain positions for bookmarks that are not server-defined
1214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // top-level folders.
1215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UniquePosition position;
1216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (GetModelTypeFromSpecifics(specifics) == BOOKMARKS
1217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        && !(is_dir && !server_unique_tag.empty())) {
1218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (id_string.at(0) == 'c') {
1219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // We found an uncommitted item.  This is rare, but fortunate.  This
1220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // means we can set the bookmark tag according to the originator client
1221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // item ID and originator cache guid, because (unlike the other case) we
1222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // know that this client is the originator.
1223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        unique_bookmark_tag = syncable::GenerateSyncableBookmarkHash(
1224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            cache_guid,
1225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            id_string.substr(1));
1226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      } else {
1227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // If we've already committed the item, then we don't know who the
1228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // originator was.  We do not have access to the originator client item
1229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // ID and originator cache guid at this point.
1230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        //
1231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // We will base our hash entirely on the server ID instead.  This is
1232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // incorrect, but at least all clients that undergo this migration step
1233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // will be incorrect in the same way.
1234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        //
1235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // To get everyone back into a synced state, we will update the bookmark
1236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // tag according to the originator_cache_guid and originator_item_id
1237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // when we see updates for this item.  That should ensure that commonly
1238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // modified items will end up with the proper tag values eventually.
1239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        unique_bookmark_tag = syncable::GenerateSyncableBookmarkHash(
1240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            std::string(), // cache_guid left intentionally blank.
1241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            id_string.substr(1));
1242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      int64 int_position = NodeOrdinalToInt64(ordinal);
1245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      position = UniquePosition::FromInt64(int_position, unique_bookmark_tag);
1246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
1247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Leave bookmark_tag and position at their default (invalid) values.
1248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string position_blob;
1251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    position.SerializeToString(&position_blob);
1252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    put.BindBlob(0, position_blob.data(), position_blob.length());
1253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    put.BindBlob(1, position_blob.data(), position_blob.length());
1254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    put.BindBlob(2, unique_bookmark_tag.data(), unique_bookmark_tag.length());
1255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    put.BindInt64(3, metahandle);
1256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!put.Run())
1258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
1259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    put.Reset(true);
1260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetVersion(86);
1263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  needs_column_refresh_ = true;
1264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return true;
1265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::CreateTables() {
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "First run, creating tables";
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create two little tables share_version and share_info
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!db_->Execute(
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "CREATE TABLE share_version ("
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "id VARCHAR(128) primary key, data INT)")) {
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db_->GetUniqueStatement(
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "INSERT INTO share_version VALUES(?, ?)"));
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindString(0, dir_name_);
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindInt(1, kCurrentDBVersion);
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!s.Run())
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool kCreateAsTempShareInfo = false;
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateShareInfoTable(kCreateAsTempShareInfo)) {
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db_->GetUniqueStatement(
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "INSERT INTO share_info VALUES"
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "(?, "  // id
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "?, "   // name
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "?, "   // store_birthday
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "?, "   // db_create_version
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "?, "   // db_create_time
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "-2, "  // next_id
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "?, "   // cache_guid
13012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // TODO(rlarocque, 124140): Remove notification_state field.
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "?, "   // notification_state
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "?);"));  // bag_of_chips
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindString(0, dir_name_);                   // id
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindString(1, dir_name_);                   // name
1306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    s.BindString(2, std::string());               // store_birthday
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(akalin): Remove this unused db_create_version field. (Or
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // actually use it for something.) http://crbug.com/118356
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindString(3, "Unknown");                   // db_create_version
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindInt(4, static_cast<int32>(time(0)));    // db_create_time
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindString(5, GenerateCacheGUID());         // cache_guid
13122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(rlarocque, 124140): Remove this unused notification-state field.
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindBlob(6, NULL, 0);                       // notification_state
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindBlob(7, NULL, 0);                       // bag_of_chips
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!s.Run())
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateModelsTable())
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the big metas table.
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateMetasTable(false))
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Insert the entry for the root into the metas table.
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const int64 now = TimeToProtoTime(base::Time::Now());
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sql::Statement s(db_->GetUniqueStatement(
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "INSERT INTO metas "
1331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            "( id, metahandle, is_dir, ctime, mtime ) "
1332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            "VALUES ( \"r\", 1, 1, ?, ? )"));
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindInt64(0, now);
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s.BindInt64(1, now);
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!s.Run())
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::CreateMetasTable(bool is_temporary) {
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string query = "CREATE TABLE ";
13452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  query.append(is_temporary ? "temp_metas" : "metas");
13462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  query.append(ComposeCreateTableColumnSpecs());
13472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!db_->Execute(query.c_str()))
13482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
13492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create a deleted_metas table to save copies of deleted metas until the
13512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // deletions are persisted. For simplicity, don't try to migrate existing
13522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // data because it's rarely used.
13532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeDropTable("deleted_metas");
13542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  query = "CREATE TABLE deleted_metas ";
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(ComposeCreateTableColumnSpecs());
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->Execute(query.c_str());
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::CreateV71ModelsTable() {
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is an old schema for the Models table, used from versions 71 to 74.
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->Execute(
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CREATE TABLE models ("
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "model_id BLOB primary key, "
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "last_download_timestamp INT, "
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Gets set if the syncer ever gets updates from the
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // server and the server returns 0.  Lets us detect the
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // end of the initial sync.
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "initial_sync_ended BOOLEAN default 0)");
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DirectoryBackingStore::CreateV75ModelsTable() {
13722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This is an old schema for the Models table, used from versions 75 to 80.
13732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return db_->Execute(
13742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "CREATE TABLE models ("
13752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "model_id BLOB primary key, "
13762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "progress_marker BLOB, "
13772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Gets set if the syncer ever gets updates from the
13782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // server and the server returns 0.  Lets us detect the
13792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // end of the initial sync.
13802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "initial_sync_ended BOOLEAN default 0)");
13812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
13822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::CreateModelsTable() {
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the current schema for the Models table, from version 81
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // onward.  If you change the schema, you'll probably want to double-check
13862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the use of this function in the v84-v85 migration.
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->Execute(
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CREATE TABLE models ("
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "model_id BLOB primary key, "
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "progress_marker BLOB, "
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Gets set if the syncer ever gets updates from the
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // server and the server returns 0.  Lets us detect the
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // end of the initial sync.
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "transaction_version BIGINT default 0)");
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::CreateShareInfoTable(bool is_temporary) {
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* name = is_temporary ? "temp_share_info" : "share_info";
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string query = "CREATE TABLE ";
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(name);
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the current schema for the ShareInfo table, from version 76
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // onward.
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(" ("
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "id TEXT primary key, "
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "name TEXT, "
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "store_birthday TEXT, "
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "db_create_version TEXT, "
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "db_create_time INT, "
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "next_id INT default -2, "
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "cache_guid TEXT, "
14112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(rlarocque, 124140): Remove notification_state field.
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "notification_state BLOB, "
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "bag_of_chips BLOB"
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ")");
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->Execute(query.c_str());
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::CreateShareInfoTableVersion71(
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_temporary) {
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* name = is_temporary ? "temp_share_info" : "share_info";
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string query = "CREATE TABLE ";
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(name);
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the schema for the ShareInfo table used from versions 71 to 72.
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  query.append(" ("
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "id TEXT primary key, "
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "name TEXT, "
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "store_birthday TEXT, "
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "db_create_version TEXT, "
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "db_create_time INT, "
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "next_id INT default -2, "
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "cache_guid TEXT )");
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return db_->Execute(query.c_str());
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function checks to see if the given list of Metahandles has any nodes
1436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// whose PARENT_ID values refer to ID values that do not actually exist.
1437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Returns true on success.
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryBackingStore::VerifyReferenceIntegrity(
1439868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const Directory::MetahandlesMap* handles_map) {
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("sync", "SyncDatabaseIntegrityCheck");
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  using namespace syncable;
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef base::hash_set<std::string> IdsSet;
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdsSet ids_set;
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_ok = true;
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1447868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (Directory::MetahandlesMap::const_iterator it = handles_map->begin();
1448868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != handles_map->end(); ++it) {
1449868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = it->second;
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_duplicate_id = !(ids_set.insert(entry->ref(ID).value()).second);
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_ok = is_ok && !is_duplicate_id;
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IdsSet::iterator end = ids_set.end();
1455868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (Directory::MetahandlesMap::const_iterator it = handles_map->begin();
1456868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != handles_map->end(); ++it) {
1457868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EntryKernel* entry = it->second;
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool parent_exists = (ids_set.find(entry->ref(PARENT_ID).value()) != end);
1459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!parent_exists) {
1460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
1461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_ok;
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DirectoryBackingStore::PrepareSaveEntryStatement(
14672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EntryTable table, sql::Statement* save_statement) {
14682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (save_statement->is_valid())
14692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
14702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  string query;
14722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  query.reserve(kUpdateStatementBufferSize);
14732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (table) {
14742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case METAS_TABLE:
14752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      query.append("INSERT OR REPLACE INTO metas ");
14762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
14772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case DELETE_JOURNAL_TABLE:
14782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      query.append("INSERT OR REPLACE INTO deleted_metas ");
14792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
14802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  string values;
14832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  values.reserve(kUpdateStatementBufferSize);
14842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  values.append(" VALUES ");
14852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const char* separator = "( ";
14862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int i = 0;
14872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (i = BEGIN_FIELDS; i < FIELD_COUNT; ++i) {
14882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    query.append(separator);
14892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    values.append(separator);
14902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    separator = ", ";
14912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    query.append(ColumnName(i));
14922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    values.append("?");
14932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
14942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  query.append(" ) ");
14952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  values.append(" )");
14962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  query.append(values);
14972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  save_statement->Assign(db_->GetUniqueStatement(
14982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::StringPrintf(query.c_str(), "metas").c_str()));
14992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
15002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncable
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncer
1503