// 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 <cstdint>
#include <string>

#include "base/check_op.h"
#include "base/strings/string_piece.h"
#include "sql/database.h"
#include "sql/statement.h"
#include "sql/statement_id.h"
#include "sql/transaction.h"

namespace sql {

namespace {

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

void PrepareSetStatement(base::StringPiece key,
                         Database& db,
                         Statement& insert_statement) {
  insert_statement.Assign(db.GetCachedStatement(
      SQL_FROM_HERE, "INSERT OR REPLACE INTO meta(key,value) VALUES(?,?)"));
  insert_statement.BindString(0, key);
}

bool PrepareGetStatement(base::StringPiece key,
                         Database& db,
                         Statement& select_statement) {
  select_statement.Assign(db.GetCachedStatement(
      SQL_FROM_HERE, "SELECT value FROM meta WHERE key=?"));
  if (!select_statement.is_valid())
    return false;

  select_statement.BindString(0, key);
  return select_statement.Step();
}

}  // namespace

MetaTable::MetaTable() = default;

MetaTable::~MetaTable() = default;

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

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

// static
bool MetaTable::DeleteTableForTesting(sql::Database* db) {
  DCHECK(db);
  return db->Execute("DROP TABLE IF EXISTS meta");
}

// static
bool MetaTable::GetMmapStatus(Database* db, int64_t* status) {
  DCHECK(db);
  DCHECK(status);

  // It is fine for the status to be missing entirely, but any error prevents
  // memory-mapping.
  Statement select;
  if (!PrepareGetStatement(kMmapStatusKey, *db, select)) {
    *status = 0;
    return true;
  }

  *status = select.ColumnInt64(0);
  return select.Succeeded();
}

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

  Statement insert;
  PrepareSetStatement(kMmapStatusKey, *db, insert);
  insert.BindInt64(1, status);
  return insert.Run();
}

// static
void MetaTable::RazeIfIncompatible(Database* db,
                                   int lowest_supported_version,
                                   int current_version) {
  DCHECK(db);

  if (!DoesTableExist(db))
    return;

  sql::Statement select;
  if (!PrepareGetStatement(kVersionKey, *db, select))
    return;
  int64_t on_disk_schema_version = select.ColumnInt64(0);

  if (!PrepareGetStatement(kCompatibleVersionKey, *db, select))
    return;
  int64_t on_disk_compatible_version = select.ColumnInt(0);

  select.Clear();  // Clear potential automatic transaction for Raze().

  if ((lowest_supported_version != kNoLowestSupportedVersion &&
       lowest_supported_version > on_disk_schema_version) ||
      (current_version < on_disk_compatible_version)) {
    db->Raze();
    return;
  }
}

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

  // If values stored are nullptr 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);
  }
  return transaction.Commit();
}

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

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

int MetaTable::GetVersionNumber() {
  int64_t 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(base::StringPiece key, const std::string& value) {
  DCHECK(db_);

  Statement insert;
  PrepareSetStatement(key, *db_, insert);
  insert.BindString(1, value);
  return insert.Run();
}

bool MetaTable::SetValue(base::StringPiece key, int64_t value) {
  DCHECK(db_);

  Statement insert;
  PrepareSetStatement(key, *db_, insert);
  insert.BindInt64(1, value);
  return insert.Run();
}

bool MetaTable::GetValue(base::StringPiece key, std::string* value) {
  DCHECK(value);
  DCHECK(db_);

  Statement select;
  if (!PrepareGetStatement(key, *db_, select))
    return false;

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

bool MetaTable::GetValue(base::StringPiece key, int* value) {
  DCHECK(value);
  DCHECK(db_);

  Statement select;
  if (!PrepareGetStatement(key, *db_, select))
    return false;

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

bool MetaTable::GetValue(base::StringPiece key, int64_t* value) {
  DCHECK(value);
  DCHECK(db_);

  Statement select;
  if (!PrepareGetStatement(key, *db_, select))
    return false;

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

bool MetaTable::DeleteKey(base::StringPiece key) {
  DCHECK(db_);

  Statement delete_statement(
      db_->GetUniqueStatement("DELETE FROM meta WHERE key=?"));
  delete_statement.BindString(0, key);
  return delete_statement.Run();
}

}  // namespace sql
