Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(362)

Side by Side Diff: chrome/browser/history/download_database.cc

Issue 11363222: Persist download interrupt reason, both target and current paths, and url_chain. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Changed ordering of target_path and current_path everywhere to match that of DownloadItemImpl. Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/debug/alias.h" 11 #include "base/debug/alias.h"
12 #include "base/file_path.h" 12 #include "base/file_path.h"
13 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
14 #include "base/stl_util.h"
15 #include "base/stringprintf.h"
14 #include "base/time.h" 16 #include "base/time.h"
15 #include "base/utf_string_conversions.h" 17 #include "base/utf_string_conversions.h"
16 #include "build/build_config.h" 18 #include "build/build_config.h"
17 #include "chrome/browser/history/download_row.h" 19 #include "chrome/browser/history/download_row.h"
20 #include "chrome/browser/history/history_types.h"
18 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/download_interrupt_reasons.h"
19 #include "content/public/browser/download_item.h" 23 #include "content/public/browser/download_item.h"
20 #include "sql/statement.h" 24 #include "sql/statement.h"
21 25
22 using content::DownloadItem; 26 using content::DownloadItem;
23 27
24 namespace history { 28 namespace history {
25 29
26 // static 30 // static
27 const int64 DownloadDatabase::kUninitializedHandle = -1; 31 const int64 DownloadDatabase::kUninitializedHandle = -1;
28 32
29 namespace { 33 namespace {
30 34
31 static const char kSchema[] = 35 static const char kSchema[] =
32 "CREATE TABLE downloads (" 36 "CREATE TABLE downloads ("
33 "id INTEGER PRIMARY KEY," // SQLite-generated primary key. 37 "id INTEGER PRIMARY KEY," // Primary key.
34 "full_path LONGVARCHAR NOT NULL," // Location of the download on disk. 38 "current_path LONGVARCHAR NOT NULL," // Current location of the download
35 "url LONGVARCHAR NOT NULL," // URL of the downloaded file. 39 // on disk.
40 "target_path LONGVARCHAR NOT NULL," // Final location of the download on disk.
36 "start_time INTEGER NOT NULL," // When the download was started. 41 "start_time INTEGER NOT NULL," // When the download was started.
37 "received_bytes INTEGER NOT NULL," // Total size downloaded. 42 "received_bytes INTEGER NOT NULL," // Total size downloaded.
38 "total_bytes INTEGER NOT NULL," // Total size of the download. 43 "total_bytes INTEGER NOT NULL," // Total size of the download.
39 "state INTEGER NOT NULL," // 1=complete, 2=cancelled, 4=interrupted 44 "state INTEGER NOT NULL," // 1=complete, 4=interrupted
45 "interrupt_reason INTEGER NOT NULL,"// Reason the download was interrupted.
40 "end_time INTEGER NOT NULL," // When the download completed. 46 "end_time INTEGER NOT NULL," // When the download completed.
41 "opened INTEGER NOT NULL)"; // 1 if it has ever been opened else 0 47 "opened INTEGER NOT NULL)"; // 1 if it has ever been opened else 0
42 48
49 static const char kUrlChainSchema[] =
50 "CREATE TABLE downloads_url_chains ("
51 "id INTEGER NOT NULL," // downloads.id.
52 "chain_index INTEGER NOT NULL," // Index of url in chain
53 // 0 is initial target,
54 // MAX is target after redirects.
55 "url LONGVARCHAR NOT NULL, " // URL.
56 "PRIMARY KEY (id, chain_index) )";
57
43 // These constants and next two functions are used to allow 58 // These constants and next two functions are used to allow
44 // DownloadItem::DownloadState to change without breaking the database schema. 59 // DownloadItem::DownloadState to change without breaking the database schema.
45 // They guarantee that the values of the |state| field in the database are one 60 // They guarantee that the values of the |state| field in the database are one
46 // of the values returned by StateToInt, and that the values of the |state| 61 // of the values returned by StateToInt, and that the values of the |state|
47 // field of the DownloadRows returned by QueryDownloads() are one of the values 62 // field of the DownloadRows returned by QueryDownloads() are one of the values
48 // returned by IntToState(). 63 // returned by IntToState().
49 static const int kStateInvalid = -1; 64 static const int kStateInvalid = -1;
50 static const int kStateInProgress = 0; 65 static const int kStateInProgress = 0;
51 static const int kStateComplete = 1; 66 static const int kStateComplete = 1;
52 static const int kStateCancelled = 2; 67 static const int kStateCancelled = 2;
53 static const int kStateBug140687 = 3; 68 static const int kStateBug140687 = 3;
54 static const int kStateInterrupted = 4; 69 static const int kStateInterrupted = 4;
55 70
56 int StateToInt(DownloadItem::DownloadState state) { 71 int StateToInt(DownloadItem::DownloadState state) {
57 switch (state) { 72 switch (state) {
58 case DownloadItem::IN_PROGRESS: return kStateInProgress; 73 case DownloadItem::IN_PROGRESS: return kStateInProgress;
59 case DownloadItem::COMPLETE: return kStateComplete; 74 case DownloadItem::COMPLETE: return kStateComplete;
60 case DownloadItem::CANCELLED: return kStateCancelled; 75 case DownloadItem::CANCELLED: return kStateCancelled;
61 case DownloadItem::INTERRUPTED: return kStateInterrupted; 76 case DownloadItem::INTERRUPTED: return kStateInterrupted;
62 case DownloadItem::MAX_DOWNLOAD_STATE: return kStateInvalid; 77 case DownloadItem::MAX_DOWNLOAD_STATE: return kStateInvalid;
63 default: return kStateInvalid; 78 default: return kStateInvalid;
64 } 79 }
65 } 80 }
66 81
67 DownloadItem::DownloadState IntToState(int state) { 82 DownloadItem::DownloadState IntToState(int state) {
68 switch (state) { 83 switch (state) {
69 case kStateInProgress: return DownloadItem::IN_PROGRESS; 84 case kStateInProgress: return DownloadItem::IN_PROGRESS;
70 case kStateComplete: return DownloadItem::COMPLETE; 85 case kStateComplete: return DownloadItem::COMPLETE;
71 case kStateCancelled: return DownloadItem::CANCELLED; 86 case kStateCancelled: return DownloadItem::CANCELLED;
72 // We should not need kStateBug140687 here because MigrateDownloadState() 87 // We should not need kStateBug140687 here because MigrateDownloadsState()
73 // is called in HistoryDatabase::Init(). 88 // is called in HistoryDatabase::Init().
74 case kStateInterrupted: return DownloadItem::INTERRUPTED; 89 case kStateInterrupted: return DownloadItem::INTERRUPTED;
75 default: return DownloadItem::MAX_DOWNLOAD_STATE; 90 default: return DownloadItem::MAX_DOWNLOAD_STATE;
76 } 91 }
77 } 92 }
78 93
79 #if defined(OS_POSIX) 94 #if defined(OS_POSIX)
80 95
81 // Binds/reads the given file path to the given column of the given statement. 96 // Binds/reads the given file path to the given column of the given statement.
82 void BindFilePath(sql::Statement& statement, const FilePath& path, int col) { 97 void BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 } 137 }
123 138
124 bool DownloadDatabase::MigrateDownloadsState() { 139 bool DownloadDatabase::MigrateDownloadsState() {
125 sql::Statement statement(GetDB().GetUniqueStatement( 140 sql::Statement statement(GetDB().GetUniqueStatement(
126 "UPDATE downloads SET state=? WHERE state=?")); 141 "UPDATE downloads SET state=? WHERE state=?"));
127 statement.BindInt(0, kStateInterrupted); 142 statement.BindInt(0, kStateInterrupted);
128 statement.BindInt(1, kStateBug140687); 143 statement.BindInt(1, kStateBug140687);
129 return statement.Run(); 144 return statement.Run();
130 } 145 }
131 146
147 bool DownloadDatabase::MigrateDownloadsReasonAndPaths() {
148 // We need to rename the table and copy back from it because SQLite
149 // provides no way to rename or delete a column.
150 if (!GetDB().Execute("ALTER TABLE downloads RENAME TO downloads_tmp"))
151 return false;
152
153 // Recreate main table.
154 if (!GetDB().Execute(kSchema))
155 return false;
156
157 // Populate it. As we do so, we transform the time values from time_t
158 // (seconds since 1/1/1970 UTC), to our internal measure (microseconds
159 // since the Windows Epoch). Note that this is dependent in the
benjhayden 2012/12/10 16:38:42 dependent on
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 Done.
160 // implementation of base::Time and needs to change if that changes.
benjhayden 2012/12/10 16:38:42 What parts of base::Time specifically?
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 Updated comment.
161 sql::Statement statement_populate(GetDB().GetUniqueStatement(
162 "INSERT INTO downloads "
163 "( id, current_path, target_path, start_time, received_bytes, total_bytes, "
164 " state, interrupt_reason, end_time, opened ) "
165 "SELECT id, full_path, full_path, "
166 " CASE start_time WHEN 0 THEN 0 ELSE "
167 " (start_time + 11644473600) * 1000000 END, "
168 " received_bytes, total_bytes, "
169 " state, ?, "
170 " CASE end_time WHEN 0 THEN 0 ELSE "
171 " (end_time + 11644473600) * 1000000 END, "
172 " opened "
173 "FROM downloads_tmp"));
174 statement_populate.BindInt(0, content::DOWNLOAD_INTERRUPT_REASON_NONE);
175 if (!statement_populate.Run())
176 return false;
177
178 // Create new chain table and populate it.
179 if (!GetDB().Execute(kUrlChainSchema))
180 return false;
181
182 if (!GetDB().Execute("INSERT INTO downloads_url_chains "
183 " ( id, chain_index, url) "
184 " SELECT id, 0, url from downloads_tmp"))
185 return false;
186
187 // Get rid of temporary table.
188 if (!GetDB().Execute("DROP TABLE downloads_tmp"))
189 return false;
190
191 return true;
192 }
193
132 bool DownloadDatabase::InitDownloadTable() { 194 bool DownloadDatabase::InitDownloadTable() {
133 GetMetaTable().GetValue(kNextDownloadId, &next_id_); 195 GetMetaTable().GetValue(kNextDownloadId, &next_id_);
134 if (GetDB().DoesTableExist("downloads")) { 196 if (GetDB().DoesTableExist("downloads")) {
135 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") && 197 return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
136 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0"); 198 EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
137 } else { 199 } else {
138 return GetDB().Execute(kSchema); 200 // If the "downloads" table doesn't exist, the downloads_url_chain
201 // table better not.
202 return (!GetDB().DoesTableExist("downloads_url_chain") &&
203 GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema));
139 } 204 }
140 } 205 }
141 206
142 bool DownloadDatabase::DropDownloadTable() { 207 bool DownloadDatabase::DropDownloadTable() {
143 return GetDB().Execute("DROP TABLE downloads"); 208 return GetDB().Execute("DROP TABLE downloads");
144 } 209 }
145 210
146 void DownloadDatabase::QueryDownloads( 211 void DownloadDatabase::QueryDownloads(
147 std::vector<DownloadRow>* results) { 212 std::vector<DownloadRow>* results) {
148 results->clear(); 213 results->clear();
149 if (next_db_handle_ < 1) 214 if (next_db_handle_ < 1)
150 next_db_handle_ = 1; 215 next_db_handle_ = 1;
151 std::set<int64> db_handles; 216 std::set<int64> db_handles;
152 217
153 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 218 std::map<DownloadID, DownloadRow*> info_map;
154 "SELECT id, full_path, url, start_time, received_bytes, " 219
155 "total_bytes, state, end_time, opened " 220 sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE,
221 "SELECT id, current_path, target_path, start_time, received_bytes, "
222 "total_bytes, state, interrupt_reason, end_time, opened "
156 "FROM downloads " 223 "FROM downloads "
157 "ORDER BY start_time")); 224 "ORDER BY start_time"));
158 225
159 while (statement.Step()) { 226 while (statement_main.Step()) {
160 DownloadRow info; 227 DownloadRow* info(new DownloadRow());
161 info.db_handle = statement.ColumnInt64(0); 228 int column = 0;
162 info.path = ColumnFilePath(statement, 1); 229
163 info.url = GURL(statement.ColumnString(2)); 230 info->db_handle = statement_main.ColumnInt64(column++);
164 info.start_time = base::Time::FromTimeT(statement.ColumnInt64(3)); 231 info->current_path = ColumnFilePath(statement_main, column++);
165 info.received_bytes = statement.ColumnInt64(4); 232 info->target_path = ColumnFilePath(statement_main, column++);
166 info.total_bytes = statement.ColumnInt64(5); 233 info->start_time = base::Time::FromInternalValue(
167 int state = statement.ColumnInt(6); 234 statement_main.ColumnInt64(column++));
168 info.state = IntToState(state); 235 info->received_bytes = statement_main.ColumnInt64(column++);
169 info.end_time = base::Time::FromTimeT(statement.ColumnInt64(7)); 236 info->total_bytes = statement_main.ColumnInt64(column++);
170 info.opened = statement.ColumnInt(8) != 0; 237 int state = statement_main.ColumnInt(column++);
171 if (info.db_handle >= next_db_handle_) 238 info->state = IntToState(state);
172 next_db_handle_ = info.db_handle + 1; 239 info->interrupt_reason = static_cast<content::DownloadInterruptReason>(
173 if (!db_handles.insert(info.db_handle).second) { 240 statement_main.ColumnInt(column++));
174 // info.db_handle was already in db_handles. The database is corrupt. 241 info->end_time = base::Time::FromInternalValue(
175 base::debug::Alias(&info.db_handle); 242 statement_main.ColumnInt64(column++));
243 info->opened = statement_main.ColumnInt(column++) != 0;
244 if (info->db_handle >= next_db_handle_)
245 next_db_handle_ = info->db_handle + 1;
246 if (!db_handles.insert(info->db_handle).second) {
247 // info->db_handle was already in db_handles. The database is corrupt.
248 base::debug::Alias(&info->db_handle);
176 DCHECK(false); 249 DCHECK(false);
177 } 250 }
178 if (info.state == DownloadItem::MAX_DOWNLOAD_STATE) { 251 if (info->state == DownloadItem::MAX_DOWNLOAD_STATE) {
179 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state); 252 UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state);
180 continue; 253 continue;
benjhayden 2012/12/10 16:38:42 Does this leak info?
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 D'oh! Thanks. Switched to scoped_ptr<>.
181 } 254 }
182 results->push_back(info); 255 DCHECK(!ContainsKey(info_map, info->db_handle));
256 info_map[info->db_handle] = info;
257 }
258
259 sql::Statement statement_chain(GetDB().GetCachedStatement(
260 SQL_FROM_HERE,
261 "SELECT id, chain_index, url FROM downloads_url_chains "
262 "ORDER BY id, chain_index"));
263
264 while (statement_chain.Step()) {
265 int64 db_handle = statement_chain.ColumnInt64(0);
benjhayden 2012/12/10 16:38:42 Why not use the column++ trick here?
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 Didn't seem as necessary as there were only two it
266 int chain_index = statement_chain.ColumnInt(1);
267
268 // Note that these DCHECKs may trip as a result of corrupted databases.
269 // We have them because in debug builds the chances are higher there's
270 // an actual bug than that the database is corrupt, but we handle the
271 // DB corruption case in production code.
272
273 // Confirm the handle has already been seen--if it hasn't, discard the
274 // record.
275 DCHECK(ContainsKey(info_map, db_handle));
276 if (!ContainsKey(info_map, db_handle))
277 continue;
278
279 // Confirm all previous URLs in the chain have already been seen;
280 // if not, fill in with null or discard record.
281 int current_chain_size = info_map[db_handle]->url_chain.size();
282 std::vector<GURL>* url_chain(&info_map[db_handle]->url_chain);
283 DCHECK_EQ(chain_index, current_chain_size);
284 while (current_chain_size < chain_index) {
285 url_chain->push_back(GURL());
286 current_chain_size++;
287 }
288 if (current_chain_size > chain_index)
289 continue;
290
291 // Save the record.
292 url_chain->push_back(GURL(statement_chain.ColumnString(2)));
293 }
294
295 for (std::map<DownloadID, DownloadRow*>::iterator
296 it = info_map.begin(); it != info_map.end(); ++it) {
297 results->push_back(*it->second);
benjhayden 2012/12/10 16:38:42 Took me a second to see that this copies the info.
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 Done.
298 delete it->second;
299 it->second = NULL;
183 } 300 }
184 } 301 }
185 302
186 bool DownloadDatabase::UpdateDownload(const DownloadRow& data) { 303 bool DownloadDatabase::UpdateDownload(const DownloadRow& data) {
187 DCHECK(data.db_handle > 0); 304 DCHECK(data.db_handle > 0);
188 int state = StateToInt(data.state); 305 int state = StateToInt(data.state);
189 if (state == kStateInvalid) { 306 if (state == kStateInvalid) {
190 // TODO(benjhayden) [D]CHECK instead. 307 // TODO(benjhayden) [D]CHECK instead.
191 return false; 308 return false;
192 } 309 }
193 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 310 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
194 "UPDATE downloads " 311 "UPDATE downloads "
195 "SET full_path=?, received_bytes=?, state=?, end_time=?, total_bytes=?, " 312 "SET current_path=?, target_path=?, received_bytes=?, state=?, "
196 "opened=? WHERE id=?")); 313 "interrupt_reason=?, end_time=?, total_bytes=?, opened=? WHERE id=?"));
197 BindFilePath(statement, data.path, 0); 314 int column = 0;
198 statement.BindInt64(1, data.received_bytes); 315 BindFilePath(statement, data.current_path, column++);
199 statement.BindInt(2, state); 316 BindFilePath(statement, data.target_path, column++);
200 statement.BindInt64(3, data.end_time.ToTimeT()); 317 statement.BindInt64(column++, data.received_bytes);
201 statement.BindInt(4, data.total_bytes); 318 statement.BindInt(column++, state);
202 statement.BindInt(5, (data.opened ? 1 : 0)); 319 statement.BindInt(column++, static_cast<int>(data.interrupt_reason));
203 statement.BindInt64(6, data.db_handle); 320 statement.BindInt64(column++, data.end_time.ToInternalValue());
321 statement.BindInt(column++, data.total_bytes);
322 statement.BindInt(column++, (data.opened ? 1 : 0));
323 statement.BindInt64(column++, data.db_handle);
204 324
205 return statement.Run(); 325 return statement.Run();
206 } 326 }
207 327
208 bool DownloadDatabase::CleanUpInProgressEntries() { 328 bool DownloadDatabase::CleanUpInProgressEntries() {
209 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 329 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
210 "UPDATE downloads SET state=? WHERE state=?")); 330 "UPDATE downloads SET state=? WHERE state=?"));
211 statement.BindInt(0, kStateCancelled); 331 statement.BindInt(0, kStateCancelled);
212 statement.BindInt(1, kStateInProgress); 332 statement.BindInt(1, kStateInProgress);
213 333
214 return statement.Run(); 334 return statement.Run();
215 } 335 }
216 336
217 int64 DownloadDatabase::CreateDownload( 337 int64 DownloadDatabase::CreateDownload(
218 const DownloadRow& info) { 338 const DownloadRow& info) {
219 if (next_db_handle_ == 0) { 339 if (next_db_handle_ == 0) {
220 // This is unlikely. All current known tests and users already call 340 // This is unlikely. All current known tests and users already call
221 // QueryDownloads() before CreateDownload(). 341 // QueryDownloads() before CreateDownload().
222 std::vector<DownloadRow> results; 342 std::vector<DownloadRow> results;
223 QueryDownloads(&results); 343 QueryDownloads(&results);
224 CHECK_NE(0, next_db_handle_); 344 CHECK_NE(0, next_db_handle_);
225 } 345 }
226 346
227 int state = StateToInt(info.state); 347 int state = StateToInt(info.state);
228 if (state == kStateInvalid) 348 if (state == kStateInvalid)
229 return kUninitializedHandle; 349 return kUninitializedHandle;
230 350
231 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
232 "INSERT INTO downloads "
233 "(id, full_path, url, start_time, received_bytes, total_bytes, state, "
234 "end_time, opened) "
235 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"));
236
237 int db_handle = next_db_handle_++; 351 int db_handle = next_db_handle_++;
238 352
239 statement.BindInt64(0, db_handle); 353 {
240 BindFilePath(statement, info.path, 1); 354 sql::Statement statement_insert(GetDB().GetCachedStatement(
241 statement.BindString(2, info.url.spec()); 355 SQL_FROM_HERE,
242 statement.BindInt64(3, info.start_time.ToTimeT()); 356 "INSERT INTO downloads "
243 statement.BindInt64(4, info.received_bytes); 357 "(id, current_path, target_path, start_time, "
244 statement.BindInt64(5, info.total_bytes); 358 " received_bytes, total_bytes, state, interrupt_reason, "
245 statement.BindInt(6, state); 359 " end_time, opened) "
246 statement.BindInt64(7, info.end_time.ToTimeT()); 360 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
247 statement.BindInt(8, info.opened ? 1 : 0);
248 361
249 if (statement.Run()) { 362 int column = 0;
250 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;} 363 statement_insert.BindInt64(column++, db_handle);
251 GetMetaTable().SetValue(kNextDownloadId, ++next_id_); 364 BindFilePath(statement_insert, info.current_path, column++);
365 BindFilePath(statement_insert, info.target_path, column++);
366 statement_insert.BindInt64(column++, info.start_time.ToInternalValue());
367 statement_insert.BindInt64(column++, info.received_bytes);
368 statement_insert.BindInt64(column++, info.total_bytes);
369 statement_insert.BindInt(column++, state);
370 statement_insert.BindInt(column++, content::DOWNLOAD_INTERRUPT_REASON_NONE);
371 statement_insert.BindInt64(column++, info.end_time.ToInternalValue());
benjhayden 2012/12/10 16:38:42 I'm going to trust that you've talked to the appro
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 It was Scott in c#2 and c#4 above, and I believe h
372 statement_insert.BindInt(column++, info.opened ? 1 : 0);
373 if (!statement_insert.Run()) {
374 LOG(WARNING) << "Main insertion for download create failed.";
375 return 0;
benjhayden 2012/12/10 16:38:42 return kUninitializedHandle;
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 Done.
376 }
377 }
252 378
253 return db_handle; 379 sql::Statement statement_insert_chain(
380 GetDB().GetCachedStatement(SQL_FROM_HERE,
381 "INSERT INTO downloads_url_chains "
382 "(id, chain_index, url) "
383 "VALUES (?, ?, ?)"));
384 for (size_t i = 0; i < info.url_chain.size(); ++i) {
385 statement_insert_chain.BindInt64(0, db_handle);
386 statement_insert_chain.BindInt(1, i);
387 statement_insert_chain.BindString(2, info.url_chain[i].spec());
388 if (!statement_insert_chain.Run()) {
389 LOG(WARNING) << "Url insertion for download create failed.";
390 return 0;
benjhayden 2012/12/10 16:38:42 return kUninitializedHandle;
Randy Smith (Not in Mondays) 2012/12/11 18:17:30 Done.
391 }
392 statement_insert_chain.Reset(true);
254 } 393 }
255 return kUninitializedHandle; 394
395 // TODO(benjhayden) if(info.id>next_id_){setvalue;next_id_=info.id;}
396 GetMetaTable().SetValue(kNextDownloadId, ++next_id_);
397
398 return db_handle;
256 } 399 }
257 400
258 void DownloadDatabase::RemoveDownload(int64 handle) { 401 void DownloadDatabase::RemoveDownload(int64 handle) {
259 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 402 sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
260 "DELETE FROM downloads WHERE id=?")); 403 "DELETE FROM downloads WHERE id=?"));
261 statement.BindInt64(0, handle); 404 downloads_statement.BindInt64(0, handle);
262 statement.Run(); 405 downloads_statement.Run();
406
407 sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
408 "DELETE FROM downloads_url_chains WHERE id=?"));
409 urlchain_statement.BindInt64(0, handle);
410 urlchain_statement.Run();
263 } 411 }
264 412
265 int DownloadDatabase::CountDownloads() { 413 int DownloadDatabase::CountDownloads() {
266 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE, 414 sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
267 "SELECT count(*) from downloads")); 415 "SELECT count(*) from downloads"));
268 statement.Step(); 416 statement.Step();
269 return statement.ColumnInt(0); 417 return statement.ColumnInt(0);
270 } 418 }
271 419
272 } // namespace history 420 } // namespace history
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698