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