Home | History | Annotate | Download | only in history
      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.
     36 void BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
     37   statement.BindString(col, path.value());
     38 }
     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 
     57 DownloadDatabase::DownloadDatabase() {
     58 }
     59 
     60 DownloadDatabase::~DownloadDatabase() {
     61 }
     62 
     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 
     79 bool DownloadDatabase::DropDownloadTable() {
     80   return GetDB().Execute("DROP TABLE downloads");
     81 }
     82 
     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 
    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 
    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 
    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 
    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 
    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 
    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