1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/activity_log/database_string_table.h"
6
7#include "base/strings/stringprintf.h"
8#include "sql/connection.h"
9#include "sql/statement.h"
10
11using base::StringPrintf;
12
13namespace extensions {
14
15DatabaseStringTable::DatabaseStringTable(const std::string& table)
16    : table_(table) {}
17
18DatabaseStringTable::~DatabaseStringTable() {}
19
20bool DatabaseStringTable::Initialize(sql::Connection* connection) {
21  if (!connection->DoesTableExist(table_.c_str())) {
22    return connection->Execute(StringPrintf(
23        "CREATE TABLE %s (id INTEGER PRIMARY KEY, value TEXT NOT NULL); "
24        "CREATE UNIQUE INDEX %s_index ON %s(value)",
25        table_.c_str(),
26        table_.c_str(),
27        table_.c_str()).c_str());
28  } else {
29    return true;
30  }
31}
32
33bool DatabaseStringTable::StringToInt(sql::Connection* connection,
34                                      const std::string& value,
35                                      int64* id) {
36  std::map<std::string, int64>::const_iterator lookup =
37      value_to_id_.find(value);
38  if (lookup != value_to_id_.end()) {
39    *id = lookup->second;
40    return true;
41  }
42
43  // Operate on the assumption that the cache does a good job on
44  // frequently-used strings--if there is a cache miss, first act on the
45  // assumption that the string is not in the database either.
46  sql::Statement update(connection->GetUniqueStatement(
47      StringPrintf("INSERT OR IGNORE INTO %s(value) VALUES (?)", table_.c_str())
48          .c_str()));
49  update.BindString(0, value);
50  if (!update.Run())
51    return false;
52
53  if (connection->GetLastChangeCount() == 1) {
54    *id = connection->GetLastInsertRowId();
55    id_to_value_[*id] = value;
56    value_to_id_[value] = *id;
57    return true;
58  }
59
60  // The specified string may have already existed in the database, in which
61  // case the insert above will have been ignored.  If this happens, do a
62  // lookup to find the old value.
63  sql::Statement query(connection->GetUniqueStatement(
64      StringPrintf("SELECT id FROM %s WHERE value = ?", table_.c_str())
65          .c_str()));
66  query.BindString(0, value);
67  if (!query.Step())
68    return false;
69  *id = query.ColumnInt64(0);
70  id_to_value_[*id] = value;
71  value_to_id_[value] = *id;
72  return true;
73}
74
75bool DatabaseStringTable::IntToString(sql::Connection* connection,
76                                      int64 id,
77                                      std::string* value) {
78  std::map<int64, std::string>::const_iterator lookup =
79      id_to_value_.find(id);
80  if (lookup != id_to_value_.end()) {
81    *value = lookup->second;
82    return true;
83  }
84
85  sql::Statement query(connection->GetUniqueStatement(
86      StringPrintf("SELECT value FROM %s WHERE id = ?", table_.c_str())
87          .c_str()));
88  query.BindInt64(0, id);
89  if (!query.Step())
90    return false;
91
92  *value = query.ColumnString(0);
93  id_to_value_[id] = *value;
94  value_to_id_[*value] = id;
95  return true;
96}
97
98void DatabaseStringTable::ClearCache() {
99  id_to_value_.clear();
100  value_to_id_.clear();
101}
102
103}  // namespace extensions
104