15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 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 "chrome/browser/history/download_database.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/alias.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/download_row.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/history/history_types.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/download_interrupt_reasons.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_item.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sql/statement.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::DownloadItem;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace history {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Reason for dropping a particular record.
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)enum DroppedReason {
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DROPPED_REASON_BAD_STATE = 0,
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DROPPED_REASON_BAD_DANGER_TYPE = 1,
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DROPPED_REASON_BAD_ID = 2,
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DROPPED_REASON_DUPLICATE_ID = 3,
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DROPPED_REASON_MAX
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if defined(OS_POSIX)
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Binds/reads the given file path to the given column of the given statement.
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BindFilePath(sql::Statement& statement, const base::FilePath& path,
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  int col) {
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  statement.BindString(col, path.value());
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::FilePath ColumnFilePath(sql::Statement& statement, int col) {
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::FilePath(statement.ColumnString(col));
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#else
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// See above.
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BindFilePath(sql::Statement& statement, const base::FilePath& path,
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  int col) {
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  statement.BindString16(col, path.value());
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::FilePath ColumnFilePath(sql::Statement& statement, int col) {
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::FilePath(statement.ColumnString16(col));
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// These constants and the transformation functions below are used to allow
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DownloadItem::DownloadState and DownloadDangerType to change without
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// breaking the database schema.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// They guarantee that the values of the |state| field in the database are one
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the values returned by StateToInt, and that the values of the |state|
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// field of the DownloadRows returned by QueryDownloads() are one of the values
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// returned by IntToState().
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kStateInvalid = -1;
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kStateInProgress = 0;
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kStateComplete = 1;
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kStateCancelled = 2;
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kStateBug140687 = 3;
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kStateInterrupted = 4;
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeInvalid = -1;
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeNotDangerous = 0;
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeDangerousFile = 1;
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeDangerousUrl = 2;
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeDangerousContent = 3;
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeMaybeDangerousContent = 4;
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeUncommonContent = 5;
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeUserValidated = 6;
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int DownloadDatabase::kDangerTypeDangerousHost = 7;
90a3f7b4e666c476898878fa745f637129375cd889Ben Murdochconst int DownloadDatabase::kDangerTypePotentiallyUnwanted = 8;
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int DownloadDatabase::StateToInt(DownloadItem::DownloadState state) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state) {
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadItem::IN_PROGRESS: return DownloadDatabase::kStateInProgress;
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadItem::COMPLETE: return DownloadDatabase::kStateComplete;
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadItem::CANCELLED: return DownloadDatabase::kStateCancelled;
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadItem::INTERRUPTED: return DownloadDatabase::kStateInterrupted;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case DownloadItem::MAX_DOWNLOAD_STATE:
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kStateInvalid;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DownloadDatabase::kStateInvalid;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)DownloadItem::DownloadState DownloadDatabase::IntToState(int state) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state) {
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kStateInProgress: return DownloadItem::IN_PROGRESS;
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kStateComplete: return DownloadItem::COMPLETE;
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kStateCancelled: return DownloadItem::CANCELLED;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We should not need kStateBug140687 here because MigrateDownloadsState()
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // is called in HistoryDatabase::Init().
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kStateInterrupted: return DownloadItem::INTERRUPTED;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default: return DownloadItem::MAX_DOWNLOAD_STATE;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)int DownloadDatabase::DangerTypeToInt(content::DownloadDangerType danger_type) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (danger_type) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeNotDangerous;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE:
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeDangerousFile;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeDangerousUrl;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeDangerousContent;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeMaybeDangerousContent;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT:
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeUncommonContent;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeUserValidated;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeDangerousHost;
136a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
137a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      return DownloadDatabase::kDangerTypePotentiallyUnwanted;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case content::DOWNLOAD_DANGER_TYPE_MAX:
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return DownloadDatabase::kDangerTypeInvalid;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED();
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return DownloadDatabase::kDangerTypeInvalid;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)content::DownloadDangerType DownloadDatabase::IntToDangerType(int danger_type) {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (danger_type) {
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeNotDangerous:
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeDangerousFile:
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE;
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeDangerousUrl:
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL;
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeDangerousContent:
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT;
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeMaybeDangerousContent:
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT;
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeUncommonContent:
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT;
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeUserValidated:
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED;
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case DownloadDatabase::kDangerTypeDangerousHost:
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST;
164a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    case DownloadDatabase::kDangerTypePotentiallyUnwanted:
165a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      return content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED;
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return content::DOWNLOAD_DANGER_TYPE_MAX;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadDatabase::DownloadDatabase()
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : owning_thread_set_(false),
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      owning_thread_(0),
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      in_progress_entry_cleanup_completed_(false) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadDatabase::~DownloadDatabase() {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadDatabase::EnsureColumnExists(
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name, const std::string& type) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string add_col = "ALTER TABLE downloads ADD COLUMN " + name + " " + type;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetDB().DoesColumnExist("downloads", name.c_str()) ||
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         GetDB().Execute(add_col.c_str());
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool DownloadDatabase::MigrateMimeType() {
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return EnsureColumnExists("mime_type", "VARCHAR(255) NOT NULL"
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            " DEFAULT \"\"") &&
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)         EnsureColumnExists("original_mime_type", "VARCHAR(255) NOT NULL"
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            " DEFAULT \"\"");
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadDatabase::MigrateDownloadsState() {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetUniqueStatement(
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      "UPDATE downloads SET state=? WHERE state=?"));
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(0, kStateInterrupted);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statement.BindInt(1, kStateBug140687);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DownloadDatabase::MigrateDownloadsReasonPathsAndDangerType() {
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We need to rename the table and copy back from it because SQLite
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // provides no way to rename or delete a column.
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetDB().Execute("ALTER TABLE downloads RENAME TO downloads_tmp"))
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char kReasonPathDangerSchema[] =
209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "CREATE TABLE downloads ("
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "id INTEGER PRIMARY KEY,"
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "current_path LONGVARCHAR NOT NULL,"
212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "target_path LONGVARCHAR NOT NULL,"
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "start_time INTEGER NOT NULL,"
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "received_bytes INTEGER NOT NULL,"
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "total_bytes INTEGER NOT NULL,"
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "state INTEGER NOT NULL,"
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "danger_type INTEGER NOT NULL,"
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "interrupt_reason INTEGER NOT NULL,"
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "end_time INTEGER NOT NULL,"
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "opened INTEGER NOT NULL)";
221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  static const char kReasonPathDangerUrlChainSchema[] =
223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "CREATE TABLE downloads_url_chains ("
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "id INTEGER NOT NULL,"                // downloads.id.
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "chain_index INTEGER NOT NULL,"       // Index of url in chain
226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            // 0 is initial target,
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            // MAX is target after redirects.
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "url LONGVARCHAR NOT NULL, "          // URL.
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "PRIMARY KEY (id, chain_index) )";
230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Recreate main table.
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!GetDB().Execute(kReasonPathDangerSchema))
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Populate it.  As we do so, we transform the time values from time_t
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (seconds since 1/1/1970 UTC), to our internal measure (microseconds
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // since the Windows Epoch).  Note that this is dependent on the
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // internal representation of base::Time and needs to change if that changes.
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement statement_populate(GetDB().GetUniqueStatement(
241ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "INSERT INTO downloads "
242ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "( id, current_path, target_path, start_time, received_bytes, "
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "  total_bytes, state, danger_type, interrupt_reason, end_time, opened ) "
244ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "SELECT id, full_path, full_path, "
245ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "       CASE start_time WHEN 0 THEN 0 ELSE "
246ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "            (start_time + 11644473600) * 1000000 END, "
247ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "       received_bytes, total_bytes, "
248ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "       state, ?, ?, "
249ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "       CASE end_time WHEN 0 THEN 0 ELSE "
250ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "            (end_time + 11644473600) * 1000000 END, "
251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "       opened "
252ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "FROM downloads_tmp"));
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement_populate.BindInt(0, content::DOWNLOAD_INTERRUPT_REASON_NONE);
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement_populate.BindInt(1, kDangerTypeNotDangerous);
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!statement_populate.Run())
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create new chain table and populate it.
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!GetDB().Execute(kReasonPathDangerUrlChainSchema))
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetDB().Execute("INSERT INTO downloads_url_chains "
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       "  ( id, chain_index, url) "
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                       "  SELECT id, 0, url from downloads_tmp"))
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get rid of temporary table.
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetDB().Execute("DROP TABLE downloads_tmp"))
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool DownloadDatabase::MigrateReferrer() {
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return EnsureColumnExists("referrer", "VARCHAR NOT NULL DEFAULT \"\"");
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
278a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool DownloadDatabase::MigrateDownloadedByExtension() {
279a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return EnsureColumnExists("by_ext_id", "VARCHAR NOT NULL DEFAULT \"\"") &&
280a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)         EnsureColumnExists("by_ext_name", "VARCHAR NOT NULL DEFAULT \"\"");
281a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
282a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
283ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool DownloadDatabase::MigrateDownloadValidators() {
284ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return EnsureColumnExists("etag", "VARCHAR NOT NULL DEFAULT \"\"") &&
285ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch         EnsureColumnExists("last_modified", "VARCHAR NOT NULL DEFAULT \"\"");
286ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch}
287ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadDatabase::InitDownloadTable() {
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char kSchema[] =
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "CREATE TABLE downloads ("
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "id INTEGER PRIMARY KEY,"             // Primary key.
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "current_path LONGVARCHAR NOT NULL,"  // Current disk location
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "target_path LONGVARCHAR NOT NULL,"   // Final disk location
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "start_time INTEGER NOT NULL,"        // When the download was started.
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "received_bytes INTEGER NOT NULL,"    // Total size downloaded.
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "total_bytes INTEGER NOT NULL,"       // Total size of the download.
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "state INTEGER NOT NULL,"             // 1=complete, 4=interrupted
298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "danger_type INTEGER NOT NULL,"       // Danger type, validated.
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "interrupt_reason INTEGER NOT NULL,"  // content::DownloadInterruptReason
300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "end_time INTEGER NOT NULL,"          // When the download completed.
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "opened INTEGER NOT NULL,"            // 1 if it has ever been opened
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            // else 0
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "referrer VARCHAR NOT NULL,"          // HTTP Referrer
304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "by_ext_id VARCHAR NOT NULL,"         // ID of extension that started the
305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            // download
306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "by_ext_name VARCHAR NOT NULL,"       // name of extension
307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "etag VARCHAR NOT NULL,"              // ETag
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "last_modified VARCHAR NOT NULL,"     // Last-Modified header
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "mime_type VARCHAR(255) NOT NULL,"    // MIME type.
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "original_mime_type VARCHAR(255) NOT NULL)";  // Original MIME type.
311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const char kUrlChainSchema[] =
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "CREATE TABLE downloads_url_chains ("
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "id INTEGER NOT NULL,"                // downloads.id.
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "chain_index INTEGER NOT NULL,"       // Index of url in chain
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            // 0 is initial target,
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                            // MAX is target after redirects.
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "url LONGVARCHAR NOT NULL, "          // URL.
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "PRIMARY KEY (id, chain_index) )";
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetDB().DoesTableExist("downloads")) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return EnsureColumnExists("end_time", "INTEGER NOT NULL DEFAULT 0") &&
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           EnsureColumnExists("opened", "INTEGER NOT NULL DEFAULT 0");
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If the "downloads" table doesn't exist, the downloads_url_chain
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // table better not.
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (!GetDB().DoesTableExist("downloads_url_chain") &&
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            GetDB().Execute(kSchema) && GetDB().Execute(kUrlChainSchema));
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)uint32 DownloadDatabase::GetNextDownloadId() {
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  sql::Statement select_max_id(GetDB().GetUniqueStatement(
3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      "SELECT max(id) FROM downloads"));
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool result = select_max_id.Step();
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(result);
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If there are zero records in the downloads table, then max(id) will return
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // 0 = kInvalidId, so GetNextDownloadId() will set *id = kInvalidId + 1.
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If there is at least one record but all of the |id|s are <= kInvalidId,
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // then max(id) will return <= kInvalidId, so GetNextDownloadId should return
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // kInvalidId + 1. Note that any records with |id <= kInvalidId| will be
3427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // dropped in QueryDownloads()
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // SQLITE doesn't have unsigned integers.
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return 1 + static_cast<uint32>(std::max(
3457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      static_cast<int64>(content::DownloadItem::kInvalidId),
3467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      select_max_id.ColumnInt64(0)));
3477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadDatabase::DropDownloadTable() {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetDB().Execute("DROP TABLE downloads");
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadDatabase::QueryDownloads(
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::vector<DownloadRow>* results) {
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnsureInProgressEntriesCleanedUp();
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results->clear();
3587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::set<uint32> ids;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  std::map<uint32, DownloadRow*> info_map;
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement statement_main(GetDB().GetCachedStatement(SQL_FROM_HERE,
363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "SELECT id, current_path, target_path, "
364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "mime_type, original_mime_type, "
365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "start_time, received_bytes, "
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "total_bytes, state, danger_type, interrupt_reason, end_time, opened, "
367ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "referrer, by_ext_id, by_ext_name, etag, last_modified "
368eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "FROM downloads ORDER BY start_time"));
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (statement_main.Step()) {
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<DownloadRow> info(new DownloadRow());
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int column = 0;
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // SQLITE does not have unsigned integers, so explicitly handle negative
3757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // |id|s instead of casting them to very large uint32s, which would break
3767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // the max(id) logic in GetNextDownloadId().
3777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 signed_id = statement_main.ColumnInt64(column++);
3787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    info->id = static_cast<uint32>(signed_id);
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->current_path = ColumnFilePath(statement_main, column++);
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->target_path = ColumnFilePath(statement_main, column++);
381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    info->mime_type = statement_main.ColumnString(column++);
382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    info->original_mime_type = statement_main.ColumnString(column++);
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->start_time = base::Time::FromInternalValue(
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        statement_main.ColumnInt64(column++));
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->received_bytes = statement_main.ColumnInt64(column++);
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->total_bytes = statement_main.ColumnInt64(column++);
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int state = statement_main.ColumnInt(column++);
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->state = IntToState(state);
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (info->state == DownloadItem::MAX_DOWNLOAD_STATE)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      UMA_HISTOGRAM_COUNTS("Download.DatabaseInvalidState", state);
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->danger_type = IntToDangerType(statement_main.ColumnInt(column++));
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->interrupt_reason = static_cast<content::DownloadInterruptReason>(
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        statement_main.ColumnInt(column++));
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->end_time = base::Time::FromInternalValue(
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        statement_main.ColumnInt64(column++));
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->opened = statement_main.ColumnInt(column++) != 0;
397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    info->referrer_url = GURL(statement_main.ColumnString(column++));
398a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    info->by_ext_id = statement_main.ColumnString(column++);
399a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    info->by_ext_name = statement_main.ColumnString(column++);
400ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    info->etag = statement_main.ColumnString(column++);
401ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    info->last_modified = statement_main.ColumnString(column++);
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If the record is corrupted, note that and drop it.
4047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // http://crbug.com/251269
4057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DroppedReason dropped_reason = DROPPED_REASON_MAX;
4067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (signed_id <= static_cast<int64>(content::DownloadItem::kInvalidId)) {
4077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      // SQLITE doesn't have unsigned integers.
4087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dropped_reason = DROPPED_REASON_BAD_ID;
4097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else if (!ids.insert(info->id).second) {
4107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dropped_reason = DROPPED_REASON_DUPLICATE_ID;
4117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      NOTREACHED() << info->id;
4127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else if (info->state == DownloadItem::MAX_DOWNLOAD_STATE) {
4137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dropped_reason = DROPPED_REASON_BAD_STATE;
4147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else if (info->danger_type == content::DOWNLOAD_DANGER_TYPE_MAX) {
4157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dropped_reason = DROPPED_REASON_BAD_DANGER_TYPE;
4167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
4177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (dropped_reason != DROPPED_REASON_MAX) {
4187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      UMA_HISTOGRAM_ENUMERATION("Download.DatabaseRecordDropped",
4197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                dropped_reason,
4207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                DROPPED_REASON_MAX + 1);
4217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    } else {
4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      DCHECK(!ContainsKey(info_map, info->id));
4237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      uint32 id = info->id;
4247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      info_map[id] = info.release();
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement statement_chain(GetDB().GetCachedStatement(
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SQL_FROM_HERE,
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "SELECT id, chain_index, url FROM downloads_url_chains "
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "ORDER BY id, chain_index"));
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (statement_chain.Step()) {
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int column = 0;
4357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // See the comment above about SQLITE lacking unsigned integers.
4367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int64 signed_id = statement_chain.ColumnInt64(column++);
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int chain_index = statement_chain.ColumnInt(column++);
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (signed_id <= static_cast<int64>(content::DownloadItem::kInvalidId))
4407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      continue;
4417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    uint32 id = static_cast<uint32>(signed_id);
4427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Note that these DCHECKs may trip as a result of corrupted databases.
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We have them because in debug builds the chances are higher there's
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // an actual bug than that the database is corrupt, but we handle the
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // DB corruption case in production code.
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Confirm the id has already been seen--if it hasn't, discard the
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // record.
4507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    DCHECK(ContainsKey(info_map, id));
4517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (!ContainsKey(info_map, id))
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Confirm all previous URLs in the chain have already been seen;
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // if not, fill in with null or discard record.
4567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    int current_chain_size = info_map[id]->url_chain.size();
4577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    std::vector<GURL>* url_chain(&info_map[id]->url_chain);
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK_EQ(chain_index, current_chain_size);
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while (current_chain_size < chain_index) {
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url_chain->push_back(GURL());
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      current_chain_size++;
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (current_chain_size > chain_index)
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Save the record.
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    url_chain->push_back(GURL(statement_chain.ColumnString(2)));
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (std::map<uint32, DownloadRow*>::iterator
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           it = info_map.begin(); it != info_map.end(); ++it) {
472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    DownloadRow* row = it->second;
473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool empty_url_chain = row->url_chain.empty();
474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("Download.DatabaseEmptyUrlChain", empty_url_chain);
475c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (empty_url_chain) {
4767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      RemoveDownload(row->id);
477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Copy the contents of the stored info.
479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      results->push_back(*row);
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delete row;
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    it->second = NULL;
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DownloadDatabase::UpdateDownload(const DownloadRow& data) {
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnsureInProgressEntriesCleanedUp();
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_NE(content::DownloadItem::kInvalidId, data.id);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int state = StateToInt(data.state);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == kStateInvalid) {
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int danger_type = DangerTypeToInt(data.danger_type);
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (danger_type == kDangerTypeInvalid) {
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "UPDATE downloads "
503f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "SET current_path=?, target_path=?, "
504f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "mime_type=?, original_mime_type=?, "
505f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      "received_bytes=?, state=?, "
506ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "danger_type=?, interrupt_reason=?, end_time=?, total_bytes=?, "
507ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "opened=?, by_ext_id=?, by_ext_name=?, etag=?, last_modified=? "
508ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      "WHERE id=?"));
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int column = 0;
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BindFilePath(statement, data.current_path, column++);
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BindFilePath(statement, data.target_path, column++);
512f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  statement.BindString(column++, data.mime_type);
513f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  statement.BindString(column++, data.original_mime_type);
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt64(column++, data.received_bytes);
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt(column++, state);
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt(column++, danger_type);
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt(column++, static_cast<int>(data.interrupt_reason));
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt64(column++, data.end_time.ToInternalValue());
519868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  statement.BindInt64(column++, data.total_bytes);
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.BindInt(column++, (data.opened ? 1 : 0));
521a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  statement.BindString(column++, data.by_ext_id);
522a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  statement.BindString(column++, data.by_ext_name);
523ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  statement.BindString(column++, data.etag);
524ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  statement.BindString(column++, data.last_modified);
5257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  statement.BindInt(column++, data.id);
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return statement.Run();
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
530c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DownloadDatabase::EnsureInProgressEntriesCleanedUp() {
531c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (in_progress_entry_cleanup_completed_)
532c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
533c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      "UPDATE downloads SET state=?, interrupt_reason=? WHERE state=?"));
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  statement.BindInt(0, kStateInterrupted);
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  statement.BindInt(1, content::DOWNLOAD_INTERRUPT_REASON_CRASH);
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  statement.BindInt(2, kStateInProgress);
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
540c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  statement.Run();
541c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  in_progress_entry_cleanup_completed_ = true;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool DownloadDatabase::CreateDownload(const DownloadRow& info) {
5457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_NE(content::DownloadItem::kInvalidId, info.id);
546c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnsureInProgressEntriesCleanedUp();
547c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
548c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (info.url_chain.empty())
5497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
550c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int state = StateToInt(info.state);
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == kStateInvalid)
5537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int danger_type = DangerTypeToInt(info.danger_type);
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (danger_type == kDangerTypeInvalid)
5577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sql::Statement statement_insert(GetDB().GetCachedStatement(
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        SQL_FROM_HERE,
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        "INSERT INTO downloads "
563f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        "(id, current_path, target_path, "
564f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        " mime_type, original_mime_type, "
565f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        " start_time, "
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        " received_bytes, total_bytes, state, danger_type, interrupt_reason, "
567ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        " end_time, opened, referrer, by_ext_id, by_ext_name, etag, "
568ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        " last_modified) "
569f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"));
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int column = 0;
5727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    statement_insert.BindInt(column++, info.id);
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BindFilePath(statement_insert, info.current_path, column++);
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BindFilePath(statement_insert, info.target_path, column++);
575f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    statement_insert.BindString(column++, info.mime_type);
576f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    statement_insert.BindString(column++, info.original_mime_type);
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt64(column++, info.start_time.ToInternalValue());
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt64(column++, info.received_bytes);
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt64(column++, info.total_bytes);
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt(column++, state);
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt(column++, danger_type);
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt(column++, info.interrupt_reason);
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt64(column++, info.end_time.ToInternalValue());
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert.BindInt(column++, info.opened ? 1 : 0);
585eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    statement_insert.BindString(column++, info.referrer_url.spec());
586a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    statement_insert.BindString(column++, info.by_ext_id);
587a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    statement_insert.BindString(column++, info.by_ext_name);
588ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    statement_insert.BindString(column++, info.etag);
589ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    statement_insert.BindString(column++, info.last_modified);
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!statement_insert.Run()) {
591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // GetErrorCode() returns a bitmask where the lower byte is a more general
592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // code and the upper byte is a more specific code. In order to save
593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // memory, take the general code, of which there are fewer than 50. See
594c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // also sql/connection.cc
595c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // http://www.sqlite.org/c3ref/c_abort_rollback.html
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainInsertError",
597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                GetDB().GetErrorCode() & 0xff, 50);
5987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return false;
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
603c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    sql::Statement count_urls(GetDB().GetCachedStatement(SQL_FROM_HERE,
604c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        "SELECT count(*) FROM downloads_url_chains WHERE id=?"));
6057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    count_urls.BindInt(0, info.id);
606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (count_urls.Step()) {
607c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool corrupt_urls = count_urls.ColumnInt(0) > 0;
608c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      UMA_HISTOGRAM_BOOLEAN("Download.DatabaseCorruptUrls", corrupt_urls);
609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (corrupt_urls) {
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // There should not be any URLs in downloads_url_chains for this
6117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        // info.id.  If there are, we don't want them to interfere with
612c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // inserting the correct URLs, so just remove them.
6137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        RemoveDownloadURLs(info.id);
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement statement_insert_chain(
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetDB().GetCachedStatement(SQL_FROM_HERE,
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 "INSERT INTO downloads_url_chains "
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 "(id, chain_index, url) "
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 "VALUES (?, ?, ?)"));
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < info.url_chain.size(); ++i) {
6247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    statement_insert_chain.BindInt(0, info.id);
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert_chain.BindInt(1, i);
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert_chain.BindString(2, info.url_chain[i].spec());
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!statement_insert_chain.Run()) {
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainInsertError",
629c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                GetDB().GetErrorCode() & 0xff, 50);
6307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      RemoveDownload(info.id);
6317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return false;
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    statement_insert_chain.Reset(true);
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DownloadDatabase::RemoveDownload(uint32 id) {
639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnsureInProgressEntriesCleanedUp();
640c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement downloads_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "DELETE FROM downloads WHERE id=?"));
6437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  downloads_statement.BindInt(0, id);
644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!downloads_statement.Run()) {
645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Download.DatabaseMainDeleteError",
646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              GetDB().GetErrorCode() & 0xff, 50);
647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
6497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  RemoveDownloadURLs(id);
650c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid DownloadDatabase::RemoveDownloadURLs(uint32 id) {
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement urlchain_statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "DELETE FROM downloads_url_chains WHERE id=?"));
6557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  urlchain_statement.BindInt(0, id);
656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!urlchain_statement.Run()) {
657c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("Download.DatabaseURLChainDeleteError",
658c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                              GetDB().GetErrorCode() & 0xff, 50);
659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochsize_t DownloadDatabase::CountDownloads() {
663c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EnsureInProgressEntriesCleanedUp();
664c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "SELECT count(*) from downloads"));
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  statement.Step();
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return statement.ColumnInt(0);
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace history
672