chromium/components/history/core/browser/android/android_urls_database.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/history/core/browser/android/android_urls_database.h"

#include <stdint.h>

#include "base/logging.h"
#include "sql/database.h"
#include "sql/statement.h"

namespace history {

AndroidURLsDatabase::AndroidURLsDatabase() {
}

AndroidURLsDatabase::~AndroidURLsDatabase() {
}

bool AndroidURLsDatabase::CreateAndroidURLsTable() {
  const char* name = "android_urls";
  if (!GetDB().DoesTableExist(name)) {
    std::string sql;
    sql.append("CREATE TABLE ");
    sql.append(name);
    sql.append("("
               "id INTEGER PRIMARY KEY,"
               "raw_url LONGVARCHAR,"              // Passed in raw url.
               "url_id INTEGER NOT NULL"           // url id in urls table.
               ")");
    if (!GetDB().Execute(sql)) {
      LOG(ERROR) << GetDB().GetErrorMessage();
      return false;
    }

    if (!GetDB().Execute("CREATE INDEX android_urls_raw_url_idx"
                         " ON android_urls(raw_url)")) {
      LOG(ERROR) << GetDB().GetErrorMessage();
      return false;
    }

    if (!GetDB().Execute("CREATE INDEX android_urls_url_id_idx"
                         " ON android_urls(url_id)")) {
      LOG(ERROR) << GetDB().GetErrorMessage();
      return false;
    }
  }
  return true;
}

AndroidURLID AndroidURLsDatabase::AddAndroidURLRow(const std::string& raw_url,
                                                   URLID url_id) {
  if (GetAndroidURLRow(url_id, NULL)) {
    LOG(ERROR) << "url_id already exist";
    return 0;
  }

  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "INSERT INTO android_urls (raw_url, url_id) VALUES (?, ?)"));

  statement.BindString(0, raw_url);
  statement.BindInt64(1, static_cast<int64_t>(url_id));

  if (!statement.Run()) {
    LOG(ERROR) << GetDB().GetErrorMessage();
    return 0;
  }
  return GetDB().GetLastInsertRowId();
}

bool AndroidURLsDatabase::GetAndroidURLRow(URLID url_id, AndroidURLRow* row) {
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "SELECT id, raw_url, url_id FROM android_urls WHERE url_id = ?"));

  statement.BindInt64(0, url_id);

  if (!statement.Step())
    return false;
  if (row) {
    row->id = statement.ColumnInt64(0);
    row->raw_url = statement.ColumnString(1);
    row->url_id = statement.ColumnInt64(2);
  }
  return true;
}

bool AndroidURLsDatabase::DeleteAndroidURLRows(
    const std::vector<URLID>& url_ids) {
  if (url_ids.empty())
    return true;

  std::string sql;
  sql.append("DELETE FROM android_urls ");
  std::ostringstream oss;
  bool has_id = false;
  for (std::vector<URLID>::const_iterator i = url_ids.begin();
       i != url_ids.end(); ++i) {
    if (has_id)
      oss << ", ";
    else
      has_id = true;
    oss << *i;
  }

  if (has_id) {
    sql.append(" WHERE url_id in ( ");
    sql.append(oss.str());
    sql.append(" )");
  }

  if (!GetDB().Execute(sql)) {
    LOG(ERROR) << GetDB().GetErrorMessage();
    return false;
  }
  return true;
}

bool AndroidURLsDatabase::DeleteUnusedAndroidURLs() {
  return GetDB().Execute("DELETE FROM android_urls WHERE url_id NOT IN ("
                         "SELECT id FROM urls)");
}

bool AndroidURLsDatabase::UpdateAndroidURLRow(AndroidURLID id,
                                              const std::string& raw_url,
                                              URLID url_id) {
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "UPDATE android_urls SET raw_url = ?, url_id = ? WHERE id = ?"));

  statement.BindString(0, raw_url);
  statement.BindInt64(1, url_id);
  statement.BindInt64(2, id);

  if (!statement.is_valid()) {
    LOG(ERROR) << GetDB().GetErrorMessage();
    return false;
  }

  if (!statement.Run()) {
    LOG(ERROR) << GetDB().GetErrorMessage();
    return false;
  }

  return true;
}

bool AndroidURLsDatabase::ClearAndroidURLRows() {
  // The android_urls table might not exist if the Android content provider is
  // never used, especially in the unit tests. See http://b/6385692.
  if (GetDB().DoesTableExist("android_urls"))
    return GetDB().Execute("DELETE FROM android_urls");

  return true;
}

bool AndroidURLsDatabase::MigrateToVersion22() {
  if (!GetDB().DoesTableExist("android_urls"))
    return true;

  if (!GetDB().Execute("ALTER TABLE android_urls RENAME TO android_urls_tmp"))
    return false;

  if (!GetDB().Execute("DROP INDEX android_urls_raw_url_idx"))
    return false;

  if (!GetDB().Execute("DROP INDEX android_urls_url_id_idx"))
    return false;

  if (!CreateAndroidURLsTable())
    return false;

  if (!GetDB().Execute(
      "INSERT INTO android_urls (id, raw_url, url_id) "
      "SELECT id, raw_url, url_id FROM android_urls_tmp"))
    return false;

  if (!GetDB().Execute("DROP TABLE android_urls_tmp"))
    return false;

  return true;
}

}  // namespace history