// Copyright (c) 2012 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 "sql/meta_table.h"

#include <stdint.h>

#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "sql/connection.h"
#include "sql/statement.h"
#include "sql/transaction.h"

namespace {

// Keys understood directly by sql:MetaTable.
const char kVersionKey[] = "version";
const char kCompatibleVersionKey[] = "last_compatible_version";
const char kMmapStatusKey[] = "mmap_status";

// Used to track success/failure of deprecation checks.
enum DeprecationEventType {
  // Database has info, but no meta table.  This is probably bad.
  DEPRECATION_DATABASE_NOT_EMPTY = 0,

  // No meta, unable to query sqlite_master.  This is probably bad.
  DEPRECATION_DATABASE_UNKNOWN,

  // Failure querying meta table, corruption or similar problem likely.
  DEPRECATION_FAILED_VERSION,

  // Version key not found in meta table.  Some sort of update error likely.
  DEPRECATION_NO_VERSION,

  // Version was out-dated, database successfully razed.  Should only
  // happen once per long-idle user, low volume expected.
  DEPRECATION_RAZED,

  // Version was out-dated, database raze failed.  This user's
  // database will be stuck.
  DEPRECATION_RAZE_FAILED,

  // Always keep this at the end.
  DEPRECATION_EVENT_MAX,
};

void RecordDeprecationEvent(DeprecationEventType deprecation_event) {
  UMA_HISTOGRAM_ENUMERATION("Sqlite.DeprecationVersionResult",
                            deprecation_event, DEPRECATION_EVENT_MAX);
}

}  // namespace

namespace sql {

MetaTable::MetaTable() : db_(NULL) {
}

MetaTable::~MetaTable() {
}

// static
constexpr int64_t MetaTable::kMmapFailure;
constexpr int64_t MetaTable::kMmapSuccess;

// static
bool MetaTable::DoesTableExist(sql::Connection* db) {
  DCHECK(db);
  return db->DoesTableExist("meta");
}

// static
bool MetaTable::GetMmapStatus(Connection* db, int64_t* status) {
  const char* kMmapStatusSql = "SELECT value FROM meta WHERE key = ?";
  Statement s(db->GetUniqueStatement(kMmapStatusSql));
  if (!s.is_valid())
    return false;

  // It is fine for the status to be missing entirely, but any error prevents
  // memory-mapping.
  s.BindString(0, kMmapStatusKey);
  *status = s.Step() ? s.ColumnInt64(0) : 0;
  return s.Succeeded();
}

// static
bool MetaTable::SetMmapStatus(Connection* db, int64_t status) {
  DCHECK(status == kMmapFailure || status == kMmapSuccess || status >= 0);

  const char* kMmapUpdateStatusSql = "REPLACE INTO meta VALUES (?, ?)";
  Statement s(db->GetUniqueStatement(kMmapUpdateStatusSql));
  s.BindString(0, kMmapStatusKey);
  s.BindInt64(1, status);
  return s.Run();
}

// static
void MetaTable::RazeIfDeprecated(Connection* db, int deprecated_version) {
  DCHECK_GT(deprecated_version, 0);
  DCHECK_EQ(0, db->transaction_nesting());

  if (!DoesTableExist(db)) {
    sql::Statement s(db->GetUniqueStatement(
        "SELECT COUNT(*) FROM sqlite_master"));
    if (s.Step()) {
      if (s.ColumnInt(0) != 0) {
        RecordDeprecationEvent(DEPRECATION_DATABASE_NOT_EMPTY);
      }
      // NOTE(shess): Empty database at first run is expected, so
      // don't histogram that case.
    } else {
      RecordDeprecationEvent(DEPRECATION_DATABASE_UNKNOWN);
    }
    return;
  }

  // TODO(shess): Share sql with PrepareGetStatement().
  sql::Statement s(db->GetUniqueStatement(
                       "SELECT value FROM meta WHERE key=?"));
  s.BindCString(0, kVersionKey);
  if (!s.Step()) {
    if (!s.Succeeded()) {
      RecordDeprecationEvent(DEPRECATION_FAILED_VERSION);
    } else {
      RecordDeprecationEvent(DEPRECATION_NO_VERSION);
    }
    return;
  }

  int version = s.ColumnInt(0);
  s.Clear();  // Clear potential automatic transaction for Raze().
  if (version <= deprecated_version) {
    if (db->Raze()) {
      RecordDeprecationEvent(DEPRECATION_RAZED);
    } else {
      RecordDeprecationEvent(DEPRECATION_RAZE_FAILED);
    }
    return;
  }

  // NOTE(shess): Successfully getting a version which is not
  // deprecated is expected, so don't histogram that case.
}

bool MetaTable::Init(Connection* db, int version, int compatible_version) {
  DCHECK(!db_ && db);
  db_ = db;

  // If values stored are null or missing entirely, 0 will be reported.
  // Require new clients to start with a greater initial version.
  DCHECK_GT(version, 0);
  DCHECK_GT(compatible_version, 0);

  // Make sure the table is created an populated atomically.
  sql::Transaction transaction(db_);
  if (!transaction.Begin())
    return false;

  if (!DoesTableExist(db)) {
    if (!db_->Execute("CREATE TABLE meta"
        "(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR)"))
      return false;

    // Newly-created databases start out with mmap'ed I/O, but have no place to
    // store the setting.  Set here so that later opens don't need to validate.
    SetMmapStatus(db_, kMmapSuccess);

    // Note: there is no index over the meta table. We currently only have a
    // couple of keys, so it doesn't matter. If we start storing more stuff in
    // there, we should create an index.
    SetVersionNumber(version);
    SetCompatibleVersionNumber(compatible_version);
  } else {
    db_->AddTaggedHistogram("Sqlite.Version", GetVersionNumber());
  }
  return transaction.Commit();
}

void MetaTable::Reset() {
  db_ = NULL;
}

void MetaTable::SetVersionNumber(int version) {
  DCHECK_GT(version, 0);
  SetValue(kVersionKey, version);
}

int MetaTable::GetVersionNumber() {
  int version = 0;
  return GetValue(kVersionKey, &version) ? version : 0;
}

void MetaTable::SetCompatibleVersionNumber(int version) {
  DCHECK_GT(version, 0);
  SetValue(kCompatibleVersionKey, version);
}

int MetaTable::GetCompatibleVersionNumber() {
  int version = 0;
  return GetValue(kCompatibleVersionKey, &version) ? version : 0;
}

bool MetaTable::SetValue(const char* key, const std::string& value) {
  Statement s;
  PrepareSetStatement(&s, key);
  s.BindString(1, value);
  return s.Run();
}

bool MetaTable::SetValue(const char* key, int value) {
  Statement s;
  PrepareSetStatement(&s, key);
  s.BindInt(1, value);
  return s.Run();
}

bool MetaTable::SetValue(const char* key, int64_t value) {
  Statement s;
  PrepareSetStatement(&s, key);
  s.BindInt64(1, value);
  return s.Run();
}

bool MetaTable::GetValue(const char* key, std::string* value) {
  Statement s;
  if (!PrepareGetStatement(&s, key))
    return false;

  *value = s.ColumnString(0);
  return true;
}

bool MetaTable::GetValue(const char* key, int* value) {
  Statement s;
  if (!PrepareGetStatement(&s, key))
    return false;

  *value = s.ColumnInt(0);
  return true;
}

bool MetaTable::GetValue(const char* key, int64_t* value) {
  Statement s;
  if (!PrepareGetStatement(&s, key))
    return false;

  *value = s.ColumnInt64(0);
  return true;
}

bool MetaTable::DeleteKey(const char* key) {
  DCHECK(db_);
  Statement s(db_->GetUniqueStatement("DELETE FROM meta WHERE key=?"));
  s.BindCString(0, key);
  return s.Run();
}

void MetaTable::PrepareSetStatement(Statement* statement, const char* key) {
  DCHECK(db_ && statement);
  statement->Assign(db_->GetCachedStatement(SQL_FROM_HERE,
      "INSERT OR REPLACE INTO meta (key,value) VALUES (?,?)"));
  statement->BindCString(0, key);
}

bool MetaTable::PrepareGetStatement(Statement* statement, const char* key) {
  DCHECK(db_ && statement);
  statement->Assign(db_->GetCachedStatement(SQL_FROM_HERE,
      "SELECT value FROM meta WHERE key=?"));
  statement->BindCString(0, key);
  return statement->Step();
}

}  // namespace sql
