1// Copyright (c) 2012 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/history/android/android_urls_database.h"
6
7#include "base/logging.h"
8
9namespace history {
10
11AndroidURLsDatabase::AndroidURLsDatabase() {
12}
13
14AndroidURLsDatabase::~AndroidURLsDatabase() {
15}
16
17bool AndroidURLsDatabase::CreateAndroidURLsTable() {
18  const char* name = "android_urls";
19  if (!GetDB().DoesTableExist(name)) {
20    std::string sql;
21    sql.append("CREATE TABLE ");
22    sql.append(name);
23    sql.append("("
24               "id INTEGER PRIMARY KEY,"
25               "raw_url LONGVARCHAR,"              // Passed in raw url.
26               "url_id INTEGER NOT NULL"           // url id in urls table.
27               ")");
28    if (!GetDB().Execute(sql.c_str())) {
29      LOG(ERROR) << GetDB().GetErrorMessage();
30      return false;
31    }
32
33    if (!GetDB().Execute("CREATE INDEX android_urls_raw_url_idx"
34                         " ON android_urls(raw_url)")) {
35      LOG(ERROR) << GetDB().GetErrorMessage();
36      return false;
37    }
38
39    if (!GetDB().Execute("CREATE INDEX android_urls_url_id_idx"
40                         " ON android_urls(url_id)")) {
41      LOG(ERROR) << GetDB().GetErrorMessage();
42      return false;
43    }
44  }
45  return true;
46}
47
48AndroidURLID AndroidURLsDatabase::AddAndroidURLRow(const std::string& raw_url,
49                                                   URLID url_id) {
50  if (GetAndroidURLRow(url_id, NULL)) {
51    LOG(ERROR) << "url_id already exist";
52    return 0;
53  }
54
55  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
56      "INSERT INTO android_urls (raw_url, url_id) VALUES (?, ?)"));
57
58  statement.BindString(0, raw_url);
59  statement.BindInt64(1, static_cast<int64>(url_id));
60
61  if (!statement.Run()) {
62    LOG(ERROR) << GetDB().GetErrorMessage();
63    return 0;
64  }
65  return GetDB().GetLastInsertRowId();
66}
67
68bool AndroidURLsDatabase::GetAndroidURLRow(URLID url_id, AndroidURLRow* row) {
69  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
70      "SELECT id, raw_url, url_id FROM android_urls WHERE url_id = ?"));
71
72  statement.BindInt64(0, url_id);
73
74  if (!statement.Step())
75    return false;
76  if (row) {
77    row->id = statement.ColumnInt64(0);
78    row->raw_url = statement.ColumnString(1);
79    row->url_id = statement.ColumnInt64(2);
80  }
81  return true;
82}
83
84bool AndroidURLsDatabase::DeleteAndroidURLRows(
85    const std::vector<URLID>& url_ids) {
86  if (url_ids.empty())
87    return true;
88
89  std::string sql;
90  sql.append("DELETE FROM android_urls ");
91  std::ostringstream oss;
92  bool has_id = false;
93  for (std::vector<URLID>::const_iterator i = url_ids.begin();
94       i != url_ids.end(); ++i) {
95    if (has_id)
96      oss << ", ";
97    else
98      has_id = true;
99    oss << *i;
100  }
101
102  if (has_id) {
103    sql.append(" WHERE url_id in ( ");
104    sql.append(oss.str());
105    sql.append(" )");
106  }
107
108  if (!GetDB().Execute(sql.c_str())) {
109    LOG(ERROR) << GetDB().GetErrorMessage();
110    return false;
111  }
112  return true;
113}
114
115bool AndroidURLsDatabase::DeleteUnusedAndroidURLs() {
116  return GetDB().Execute("DELETE FROM android_urls WHERE url_id NOT IN ("
117                         "SELECT id FROM urls)");
118}
119
120bool AndroidURLsDatabase::UpdateAndroidURLRow(AndroidURLID id,
121                                              const std::string& raw_url,
122                                              URLID url_id) {
123  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
124      "UPDATE android_urls SET raw_url = ?, url_id = ? WHERE id = ?"));
125
126  statement.BindString(0, raw_url);
127  statement.BindInt64(1, url_id);
128  statement.BindInt64(2, id);
129
130  if (!statement.is_valid()) {
131    LOG(ERROR) << GetDB().GetErrorMessage();
132    return false;
133  }
134
135  if (!statement.Run()) {
136    LOG(ERROR) << GetDB().GetErrorMessage();
137    return false;
138  }
139
140  return true;
141}
142
143bool AndroidURLsDatabase::ClearAndroidURLRows() {
144  // The android_urls table might not exist if the Android content provider is
145  // never used, especially in the unit tests. See http://b/6385692.
146  if (GetDB().DoesTableExist("android_urls"))
147    return GetDB().Execute("DELETE FROM android_urls");
148
149  return true;
150}
151
152bool AndroidURLsDatabase::MigrateToVersion22() {
153  if (!GetDB().DoesTableExist("android_urls"))
154    return true;
155
156  if (!GetDB().Execute("ALTER TABLE android_urls RENAME TO android_urls_tmp"))
157    return false;
158
159  if (!GetDB().Execute("DROP INDEX android_urls_raw_url_idx"))
160    return false;
161
162  if (!GetDB().Execute("DROP INDEX android_urls_url_id_idx"))
163    return false;
164
165  if (!CreateAndroidURLsTable())
166    return false;
167
168  if (!GetDB().Execute(
169      "INSERT INTO android_urls (id, raw_url, url_id) "
170      "SELECT id, raw_url, url_id FROM android_urls_tmp"))
171    return false;
172
173  if (!GetDB().Execute("DROP TABLE android_urls_tmp"))
174    return false;
175
176  return true;
177}
178
179}  // namespace history
180