// 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
int64_t MetaTable::kMmapFailure = -2;
int64_t MetaTable::kMmapSuccess = -1;

// 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
