普通文本  |  201行  |  6.16 KB

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/history/download_database.h"

#include <limits>
#include <vector>

#include "app/sql/statement.h"
#include "base/file_path.h"
#include "base/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/download/download_item.h"
#include "chrome/browser/history/download_create_info.h"

// Download schema:
//
//   id             SQLite-generated primary key.
//   full_path      Location of the download on disk.
//   url            URL of the downloaded file.
//   start_time     When the download was started.
//   received_bytes Total size downloaded.
//   total_bytes    Total size of the download.
//   state          Identifies if this download is completed or not. Not used
//                  directly by the history system. See DownloadItem's
//                  DownloadState for where this is used.

namespace history {

namespace {

#if defined(OS_POSIX)

// Binds/reads the given file path to the given column of the given statement.
void BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
  statement.BindString(col, path.value());
}
FilePath ColumnFilePath(sql::Statement& statement, int col) {
  return FilePath(statement.ColumnString(col));
}

#else

// See above.
void BindFilePath(sql::Statement& statement, const FilePath& path, int col) {
  statement.BindString(col, UTF16ToUTF8(path.value()));
}
FilePath ColumnFilePath(sql::Statement& statement, int col) {
  return FilePath(UTF8ToUTF16(statement.ColumnString(col)));
}

#endif

}  // namespace

DownloadDatabase::DownloadDatabase() {
}

DownloadDatabase::~DownloadDatabase() {
}

bool DownloadDatabase::InitDownloadTable() {
  if (!GetDB().DoesTableExist("downloads")) {
    if (!GetDB().Execute(
        "CREATE TABLE downloads ("
        "id INTEGER PRIMARY KEY,"
        "full_path LONGVARCHAR NOT NULL,"
        "url LONGVARCHAR NOT NULL,"
        "start_time INTEGER NOT NULL,"
        "received_bytes INTEGER NOT NULL,"
        "total_bytes INTEGER NOT NULL,"
        "state INTEGER NOT NULL)"))
      return false;
  }
  return true;
}

bool DownloadDatabase::DropDownloadTable() {
  return GetDB().Execute("DROP TABLE downloads");
}

void DownloadDatabase::QueryDownloads(
    std::vector<DownloadCreateInfo>* results) {
  results->clear();

  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "SELECT id, full_path, url, start_time, received_bytes, "
        "total_bytes, state "
      "FROM downloads "
      "ORDER BY start_time"));
  if (!statement)
    return;

  while (statement.Step()) {
    DownloadCreateInfo info;
    info.db_handle = statement.ColumnInt64(0);

    info.path = ColumnFilePath(statement, 1);
    info.url_chain.push_back(GURL(statement.ColumnString(2)));
    info.start_time = base::Time::FromTimeT(statement.ColumnInt64(3));
    info.received_bytes = statement.ColumnInt64(4);
    info.total_bytes = statement.ColumnInt64(5);
    info.state = statement.ColumnInt(6);
    results->push_back(info);
  }
}

bool DownloadDatabase::UpdateDownload(int64 received_bytes,
                                      int32 state,
                                      DownloadID db_handle) {
  DCHECK(db_handle > 0);
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "UPDATE downloads "
      "SET received_bytes=?, state=? WHERE id=?"));
  if (!statement)
    return false;

  statement.BindInt64(0, received_bytes);
  statement.BindInt(1, state);
  statement.BindInt64(2, db_handle);
  return statement.Run();
}

bool DownloadDatabase::UpdateDownloadPath(const FilePath& path,
                                          DownloadID db_handle) {
  DCHECK(db_handle > 0);
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "UPDATE downloads SET full_path=? WHERE id=?"));
  if (!statement)
    return false;

  BindFilePath(statement, path, 0);
  statement.BindInt64(1, db_handle);
  return statement.Run();
}

bool DownloadDatabase::CleanUpInProgressEntries() {
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "UPDATE downloads SET state=? WHERE state=?"));
  if (!statement)
    return false;
  statement.BindInt(0, DownloadItem::CANCELLED);
  statement.BindInt(1, DownloadItem::IN_PROGRESS);
  return statement.Run();
}

int64 DownloadDatabase::CreateDownload(const DownloadCreateInfo& info) {
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "INSERT INTO downloads "
      "(full_path, url, start_time, received_bytes, total_bytes, state) "
      "VALUES (?, ?, ?, ?, ?, ?)"));
  if (!statement)
    return 0;

  BindFilePath(statement, info.path, 0);
  statement.BindString(1, info.url().spec());
  statement.BindInt64(2, info.start_time.ToTimeT());
  statement.BindInt64(3, info.received_bytes);
  statement.BindInt64(4, info.total_bytes);
  statement.BindInt(5, info.state);

  if (statement.Run())
    return GetDB().GetLastInsertRowId();
  return 0;
}

void DownloadDatabase::RemoveDownload(DownloadID db_handle) {
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "DELETE FROM downloads WHERE id=?"));
  if (!statement)
    return;

  statement.BindInt64(0, db_handle);
  statement.Run();
}

void DownloadDatabase::RemoveDownloadsBetween(base::Time delete_begin,
                                              base::Time delete_end) {
  // This does not use an index. We currently aren't likely to have enough
  // downloads where an index by time will give us a lot of benefit.
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "DELETE FROM downloads WHERE start_time >= ? AND start_time < ? "
      "AND (State = ? OR State = ? OR State = ?)"));
  if (!statement)
    return;

  time_t start_time = delete_begin.ToTimeT();
  time_t end_time = delete_end.ToTimeT();
  statement.BindInt64(0, start_time);
  statement.BindInt64(
      1,
      end_time ? end_time : std::numeric_limits<int64>::max());
  statement.BindInt(2, DownloadItem::COMPLETE);
  statement.BindInt(3, DownloadItem::CANCELLED);
  statement.BindInt(4, DownloadItem::INTERRUPTED);
  statement.Run();
}

}  // namespace history