OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/history/download_database.h" | 5 #include "chrome/browser/history/download_database.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "app/sql/statement.h" | 10 #include "app/sql/statement.h" |
11 #include "base/file_path.h" | 11 #include "base/file_path.h" |
12 #include "base/utf_string_conversions.h" | 12 #include "base/utf_string_conversions.h" |
13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
14 #include "chrome/browser/download/download_item.h" | 14 #include "chrome/browser/download/download_item.h" |
15 #include "chrome/browser/history/download_history_info.h" | 15 #include "chrome/browser/history/download_history_info.h" |
16 | 16 |
17 // Download schema: | 17 // Download schema: |
18 // | 18 // |
19 // id SQLite-generated primary key. | 19 // pid DownloadPrefs-generated unique persistent identifier. |
20 // full_path Location of the download on disk. | 20 // full_path Location of the download on disk. |
21 // url URL of the downloaded file. | 21 // url URL of the downloaded file. |
22 // start_time When the download was started. | 22 // start_time When the download was started. |
23 // received_bytes Total size downloaded. | 23 // received_bytes Total size downloaded. |
24 // total_bytes Total size of the download. | 24 // total_bytes Total size of the download. |
25 // state Identifies if this download is completed or not. Not used | 25 // state Identifies if this download is completed or not. Not used |
26 // directly by the history system. See DownloadItem's | 26 // directly by the history system. See DownloadItem's |
27 // DownloadState for where this is used. | 27 // DownloadState for where this is used. |
28 | 28 |
29 namespace history { | 29 namespace history { |
(...skipping 24 matching lines...) Expand all Loading... |
54 | 54 |
55 } // namespace | 55 } // namespace |
56 | 56 |
57 DownloadDatabase::DownloadDatabase() { | 57 DownloadDatabase::DownloadDatabase() { |
58 } | 58 } |
59 | 59 |
60 DownloadDatabase::~DownloadDatabase() { | 60 DownloadDatabase::~DownloadDatabase() { |
61 } | 61 } |
62 | 62 |
63 bool DownloadDatabase::InitDownloadTable() { | 63 bool DownloadDatabase::InitDownloadTable() { |
64 if (!GetDB().DoesTableExist("downloads")) { | 64 return GetDB().DoesTableExist("downloads") || |
65 if (!GetDB().Execute( | 65 GetDB().Execute( |
66 "CREATE TABLE downloads (" | 66 "CREATE TABLE downloads (" |
67 "id INTEGER PRIMARY KEY," | 67 "pid INTEGER PRIMARY KEY," |
68 "full_path LONGVARCHAR NOT NULL," | 68 "full_path LONGVARCHAR NOT NULL," |
69 "url LONGVARCHAR NOT NULL," | 69 "url LONGVARCHAR NOT NULL," |
70 "start_time INTEGER NOT NULL," | 70 "start_time INTEGER NOT NULL," |
71 "received_bytes INTEGER NOT NULL," | 71 "received_bytes INTEGER NOT NULL," |
72 "total_bytes INTEGER NOT NULL," | 72 "total_bytes INTEGER NOT NULL," |
73 "state INTEGER NOT NULL)")) | 73 "state INTEGER NOT NULL)"); |
74 return false; | |
75 } | |
76 return true; | |
77 } | 74 } |
78 | 75 |
79 bool DownloadDatabase::DropDownloadTable() { | 76 bool DownloadDatabase::DropDownloadTable() { |
80 return GetDB().Execute("DROP TABLE downloads"); | 77 return GetDB().Execute("DROP TABLE downloads"); |
81 } | 78 } |
82 | 79 |
83 void DownloadDatabase::QueryDownloads( | 80 bool DownloadDatabase::MaybeUpgradeTable( |
84 std::vector<DownloadHistoryInfo>* results) { | 81 DownloadQueryParameters::GetNextIdThunk get_next_id) { |
85 results->clear(); | 82 static const char kNoPidColumnError[] = "no such column: pid"; |
| 83 sql::Statement have_pid(GetDB().GetUniqueStatement( |
| 84 "SELECT pid FROM downloads")); |
| 85 if (!have_pid && |
| 86 (std::string(GetDB().GetErrorMessage()) == std::string(kNoPidColumnError))
) { |
| 87 CHECK(!get_next_id.is_null()); |
| 88 std::vector<DownloadHistoryInfo> infos; |
| 89 sql::Statement get_infos(GetDB().GetUniqueStatement( |
| 90 "SELECT full_path, url, start_time, received_bytes, " |
| 91 "total_bytes, state FROM downloads")); |
| 92 if (!get_infos) { |
| 93 return false; |
| 94 } |
| 95 while (get_infos.Step()) { |
| 96 infos.push_back(DownloadHistoryInfo( |
| 97 ColumnFilePath(get_infos, 1)/*path*/, |
| 98 GURL(get_infos.ColumnString(2))/*url*/, |
| 99 GURL("")/*referrer*/, |
| 100 base::Time::FromTimeT(get_infos.ColumnInt64(3))/*start*/, |
| 101 get_infos.ColumnInt64(4)/*received*/, |
| 102 get_infos.ColumnInt64(5)/*total*/, |
| 103 get_infos.ColumnInt(6)/*state*/, |
| 104 get_next_id.Run()/*id*/)); |
| 105 } |
| 106 if (!DropDownloadTable()) { |
| 107 return false; |
| 108 } |
| 109 if (!InitDownloadTable()) { |
| 110 return false; |
| 111 } |
| 112 for (std::vector<DownloadHistoryInfo>::const_iterator iter = infos.begin(); |
| 113 iter != infos.end(); ++iter) { |
| 114 sql::Statement reinsert(GetDB().GetCachedStatement(SQL_FROM_HERE, |
| 115 "INSERT INTO downloads (pid, full_path, url, start_time, " |
| 116 "received_bytes, total_bytes, state) VALUES (?, ?, ?, ?, ?, ?, ?)")); |
| 117 if (!reinsert) { |
| 118 return false; |
| 119 } |
| 120 reinsert.BindInt(0, iter->id); |
| 121 BindFilePath(reinsert, iter->path, 1); |
| 122 reinsert.BindString(2, iter->url.spec()); |
| 123 reinsert.BindInt64(3, iter->start_time.ToTimeT()); |
| 124 reinsert.BindInt64(4, iter->received_bytes); |
| 125 reinsert.BindInt64(5, iter->total_bytes); |
| 126 reinsert.BindInt(6, iter->state); |
| 127 if (!reinsert.Run()) { |
| 128 return false; |
| 129 } |
| 130 } |
| 131 sql::Statement have_pid2(GetDB().GetUniqueStatement( |
| 132 "SELECT pid FROM downloads")); |
| 133 if (!have_pid2) { |
| 134 return false; |
| 135 } |
| 136 } |
| 137 return true; |
| 138 } |
| 139 |
| 140 void DownloadDatabase::QueryDownloads(DownloadQueryParameters* params) { |
| 141 params->results.clear(); |
| 142 if (!MaybeUpgradeTable(params->get_next_id)) { |
| 143 return; |
| 144 } |
86 | 145 |
87 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 146 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
88 "SELECT id, full_path, url, start_time, received_bytes, " | 147 "SELECT pid, full_path, url, start_time, received_bytes, " |
89 "total_bytes, state " | 148 "total_bytes, state " |
90 "FROM downloads " | 149 "FROM downloads " |
91 "ORDER BY start_time")); | 150 "ORDER BY start_time")); |
92 if (!statement) | 151 if (!statement) { |
93 return; | 152 return; |
| 153 } |
94 | 154 |
95 while (statement.Step()) { | 155 while (statement.Step()) { |
96 DownloadHistoryInfo info; | 156 params->results.push_back(DownloadHistoryInfo( |
97 info.db_handle = statement.ColumnInt64(0); | 157 ColumnFilePath(statement, 1)/*path*/, |
98 | 158 GURL(statement.ColumnString(2))/*url*/, |
99 info.path = ColumnFilePath(statement, 1); | 159 GURL("")/*referrer*/, |
100 info.url = GURL(statement.ColumnString(2)); | 160 base::Time::FromTimeT(statement.ColumnInt64(3))/*start*/, |
101 info.start_time = base::Time::FromTimeT(statement.ColumnInt64(3)); | 161 statement.ColumnInt64(4)/*received*/, |
102 info.received_bytes = statement.ColumnInt64(4); | 162 statement.ColumnInt64(5)/*total*/, |
103 info.total_bytes = statement.ColumnInt64(5); | 163 statement.ColumnInt(6)/*state*/, |
104 info.state = statement.ColumnInt(6); | 164 statement.ColumnInt64(0)/*id*/)); |
105 results->push_back(info); | |
106 } | 165 } |
107 } | 166 } |
108 | 167 |
109 bool DownloadDatabase::UpdateDownload(int64 received_bytes, | 168 bool DownloadDatabase::UpdateDownload(int64 received_bytes, |
110 int32 state, | 169 int32 state, |
111 DownloadID db_handle) { | 170 DownloadID id) { |
112 DCHECK(db_handle > 0); | 171 DCHECK(id >= 0) << id; |
113 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 172 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
114 "UPDATE downloads " | 173 "UPDATE downloads " |
115 "SET received_bytes=?, state=? WHERE id=?")); | 174 "SET received_bytes=?, state=? WHERE pid=?")); |
116 if (!statement) | 175 if (!statement) |
117 return false; | 176 return false; |
118 | 177 |
119 statement.BindInt64(0, received_bytes); | 178 statement.BindInt64(0, received_bytes); |
120 statement.BindInt(1, state); | 179 statement.BindInt(1, state); |
121 statement.BindInt64(2, db_handle); | 180 statement.BindInt64(2, id); |
122 return statement.Run(); | 181 return statement.Run(); |
123 } | 182 } |
124 | 183 |
125 bool DownloadDatabase::UpdateDownloadPath(const FilePath& path, | 184 bool DownloadDatabase::UpdateDownloadPath(const FilePath& path, |
126 DownloadID db_handle) { | 185 DownloadID id) { |
127 DCHECK(db_handle > 0); | 186 DCHECK(id >= 0); |
128 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 187 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
129 "UPDATE downloads SET full_path=? WHERE id=?")); | 188 "UPDATE downloads SET full_path=? WHERE pid=?")); |
130 if (!statement) | 189 if (!statement) |
131 return false; | 190 return false; |
132 | 191 |
133 BindFilePath(statement, path, 0); | 192 BindFilePath(statement, path, 0); |
134 statement.BindInt64(1, db_handle); | 193 statement.BindInt64(1, id); |
135 return statement.Run(); | 194 return statement.Run(); |
136 } | 195 } |
137 | 196 |
138 bool DownloadDatabase::CleanUpInProgressEntries() { | 197 bool DownloadDatabase::CleanUpInProgressEntries() { |
139 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 198 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
140 "UPDATE downloads SET state=? WHERE state=?")); | 199 "UPDATE downloads SET state=? WHERE state=?")); |
141 if (!statement) | 200 if (!statement) |
142 return false; | 201 return false; |
143 statement.BindInt(0, DownloadItem::CANCELLED); | 202 statement.BindInt(0, DownloadItem::CANCELLED); |
144 statement.BindInt(1, DownloadItem::IN_PROGRESS); | 203 statement.BindInt(1, DownloadItem::IN_PROGRESS); |
145 return statement.Run(); | 204 return statement.Run(); |
146 } | 205 } |
147 | 206 |
148 int64 DownloadDatabase::CreateDownload(const DownloadHistoryInfo& info) { | 207 bool DownloadDatabase::CreateDownload(const DownloadHistoryInfo& info) { |
149 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 208 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
150 "INSERT INTO downloads " | 209 "INSERT INTO downloads " |
151 "(full_path, url, start_time, received_bytes, total_bytes, state) " | 210 "(pid, full_path, url, start_time, received_bytes, total_bytes, state) " |
152 "VALUES (?, ?, ?, ?, ?, ?)")); | 211 "VALUES (?, ?, ?, ?, ?, ?, ?)")); |
153 if (!statement) | 212 if (!statement) |
154 return 0; | 213 return false; |
155 | 214 |
156 BindFilePath(statement, info.path, 0); | 215 statement.BindInt(0, info.id); |
157 statement.BindString(1, info.url.spec()); | 216 BindFilePath(statement, info.path, 1); |
158 statement.BindInt64(2, info.start_time.ToTimeT()); | 217 statement.BindString(2, info.url.spec()); |
159 statement.BindInt64(3, info.received_bytes); | 218 statement.BindInt64(3, info.start_time.ToTimeT()); |
160 statement.BindInt64(4, info.total_bytes); | 219 statement.BindInt64(4, info.received_bytes); |
161 statement.BindInt(5, info.state); | 220 statement.BindInt64(5, info.total_bytes); |
| 221 statement.BindInt(6, info.state); |
162 | 222 |
163 if (statement.Run()) | 223 return statement.Run(); |
164 return GetDB().GetLastInsertRowId(); | |
165 return 0; | |
166 } | 224 } |
167 | 225 |
168 void DownloadDatabase::RemoveDownload(DownloadID db_handle) { | 226 void DownloadDatabase::RemoveDownload(DownloadID id) { |
169 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 227 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
170 "DELETE FROM downloads WHERE id=?")); | 228 "DELETE FROM downloads WHERE pid=?")); |
171 if (!statement) | 229 if (!statement) |
172 return; | 230 return; |
173 | 231 |
174 statement.BindInt64(0, db_handle); | 232 statement.BindInt64(0, id); |
175 statement.Run(); | 233 statement.Run(); |
176 } | 234 } |
177 | 235 |
178 void DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin, | 236 void DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin, |
179 base::Time delete_end) { | 237 base::Time delete_end) { |
180 // This does not use an index. We currently aren't likely to have enough | 238 // This does not use an index. We currently aren't likely to have enough |
181 // downloads where an index by time will give us a lot of benefit. | 239 // downloads where an index by time will give us a lot of benefit. |
182 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, | 240 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, |
183 "DELETE FROM downloads WHERE start_time >= ? AND start_time < ? " | 241 "DELETE FROM downloads WHERE start_time >= ? AND start_time < ? " |
184 "AND (State = ? OR State = ? OR State = ?)")); | 242 "AND (State = ? OR State = ? OR State = ?)")); |
185 if (!statement) | 243 if (!statement) |
186 return; | 244 return; |
187 | 245 |
188 time_t start_time = delete_begin.ToTimeT(); | 246 time_t start_time = delete_begin.ToTimeT(); |
189 time_t end_time = delete_end.ToTimeT(); | 247 time_t end_time = delete_end.ToTimeT(); |
190 statement.BindInt64(0, start_time); | 248 statement.BindInt64(0, start_time); |
191 statement.BindInt64( | 249 statement.BindInt64( |
192 1, | 250 1, |
193 end_time ? end_time : std::numeric_limits<int64>::max()); | 251 end_time ? end_time : std::numeric_limits<int64>::max()); |
194 statement.BindInt(2, DownloadItem::COMPLETE); | 252 statement.BindInt(2, DownloadItem::COMPLETE); |
195 statement.BindInt(3, DownloadItem::CANCELLED); | 253 statement.BindInt(3, DownloadItem::CANCELLED); |
196 statement.BindInt(4, DownloadItem::INTERRUPTED); | 254 statement.BindInt(4, DownloadItem::INTERRUPTED); |
197 statement.Run(); | 255 statement.Run(); |
198 } | 256 } |
199 | 257 |
200 } // namespace history | 258 } // namespace history |
OLD | NEW |