1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/history/download_database.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <limits>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "app/sql/statement.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_path.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/download/download_item.h"
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/history/download_create_info.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Download schema:
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   id             SQLite-generated primary key.
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   full_path      Location of the download on disk.
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   url            URL of the downloaded file.
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   start_time     When the download was started.
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   received_bytes Total size downloaded.
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   total_bytes    Total size of the download.
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//   state          Identifies if this download is completed or not. Not used
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//                  directly by the history system. See DownloadItem's
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//                  DownloadState for where this is used.
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace history {
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_POSIX)
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Binds/reads the given file path to the given column of the given statement.
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString(col, path.value());
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath ColumnFilePath(sql::Statement& statement, int col) {
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FilePath(statement.ColumnString(col));
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// See above.
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindString(col, UTF16ToUTF8(path.value()));
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochFilePath ColumnFilePath(sql::Statement& statement, int col) {
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return FilePath(UTF8ToUTF16(statement.ColumnString(col)));
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadDatabase::DownloadDatabase() {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochDownloadDatabase::~DownloadDatabase() {
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DownloadDatabase::InitDownloadTable() {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!GetDB().DoesTableExist("downloads")) {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!GetDB().Execute(
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "CREATE TABLE downloads ("
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "id INTEGER PRIMARY KEY,"
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "full_path LONGVARCHAR NOT NULL,"
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "url LONGVARCHAR NOT NULL,"
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "start_time INTEGER NOT NULL,"
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "received_bytes INTEGER NOT NULL,"
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "total_bytes INTEGER NOT NULL,"
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "state INTEGER NOT NULL)"))
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DownloadDatabase::DropDownloadTable() {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return GetDB().Execute("DROP TABLE downloads");
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadDatabase::QueryDownloads(
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<DownloadCreateInfo>* results) {
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  results->clear();
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SELECT id, full_path, url, start_time, received_bytes, "
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "total_bytes, state "
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "FROM downloads "
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "ORDER BY start_time"));
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (statement.Step()) {
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DownloadCreateInfo info;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    info.db_handle = statement.ColumnInt64(0);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    info.path = ColumnFilePath(statement, 1);
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    info.url_chain.push_back(GURL(statement.ColumnString(2)));
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    info.start_time = base::Time::FromTimeT(statement.ColumnInt64(3));
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    info.received_bytes = statement.ColumnInt64(4);
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    info.total_bytes = statement.ColumnInt64(5);
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    info.state = statement.ColumnInt(6);
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    results->push_back(info);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DownloadDatabase::UpdateDownload(int64 received_bytes,
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      int32 state,
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      DownloadID db_handle) {
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(db_handle > 0);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "UPDATE downloads "
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "SET received_bytes=?, state=? WHERE id=?"));
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(0, received_bytes);
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt(1, state);
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(2, db_handle);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return statement.Run();
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DownloadDatabase::UpdateDownloadPath(const FilePath& path,
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                          DownloadID db_handle) {
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(db_handle > 0);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "UPDATE downloads SET full_path=? WHERE id=?"));
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BindFilePath(statement, path, 0);
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(1, db_handle);
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return statement.Run();
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool DownloadDatabase::CleanUpInProgressEntries() {
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "UPDATE downloads SET state=? WHERE state=?"));
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt(0, DownloadItem::CANCELLED);
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt(1, DownloadItem::IN_PROGRESS);
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return statement.Run();
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint64 DownloadDatabase::CreateDownload(const DownloadCreateInfo& info) {
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "INSERT INTO downloads "
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "(full_path, url, start_time, received_bytes, total_bytes, state) "
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "VALUES (?, ?, ?, ?, ?, ?)"));
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return 0;
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BindFilePath(statement, info.path, 0);
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  statement.BindString(1, info.url().spec());
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(2, info.start_time.ToTimeT());
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(3, info.received_bytes);
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(4, info.total_bytes);
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt(5, info.state);
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (statement.Run())
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return GetDB().GetLastInsertRowId();
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return 0;
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadDatabase::RemoveDownload(DownloadID db_handle) {
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "DELETE FROM downloads WHERE id=?"));
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(0, db_handle);
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.Run();
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin,
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              base::Time delete_end) {
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This does not use an index. We currently aren't likely to have enough
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // downloads where an index by time will give us a lot of benefit.
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "DELETE FROM downloads WHERE start_time >= ? AND start_time < ? "
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "AND (State = ? OR State = ? OR State = ?)"));
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!statement)
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  time_t start_time = delete_begin.ToTimeT();
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  time_t end_time = delete_end.ToTimeT();
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(0, start_time);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt64(
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      1,
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      end_time ? end_time : std::numeric_limits<int64>::max());
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt(2, DownloadItem::COMPLETE);
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.BindInt(3, DownloadItem::CANCELLED);
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  statement.BindInt(4, DownloadItem::INTERRUPTED);
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.Run();
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace history
201