<commit_before>/**
 * This file is part of the CernVM file system.
 */

#include <fcntl.h>
#include <cerrno>
#include <cassert>

#include "platform.h"
#include "logging.h"

namespace sqlite {


template <class DerivedT>
Database<DerivedT>::Database(const std::string  &filename,
                             const OpenMode      open_mode) :
  sqlite_db_(NULL),
  filename_(filename),
  read_write_(kOpenReadWrite == open_mode),
  schema_version_(0.0f),
  schema_revision_(0) {}


template <class DerivedT>
DerivedT* Database<DerivedT>::Create(const std::string &filename) {
  // TODO: SharedPointer to avoid 'delete' in error conditions
  DerivedT *database = new DerivedT(filename, kOpenReadWrite);
  database->set_schema_version(DerivedT::kLatestSchema);
  database->set_schema_revision(DerivedT::kLatestSchemaRevision);

  if (! database) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database object");
    return NULL;
  }

  const int open_flags = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE |
                         SQLITE_OPEN_CREATE;
  if (! database->OpenDatabase(open_flags)) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database file");
    delete database;
    return NULL;
  }

  if (! database->CreatePropertiesTable()) {
    database->PrintSqlError("Failed to create common properties table");
    delete database;
    return NULL;
  }

  if (! database->CreateEmptyDatabase()) {
    database->PrintSqlError("Failed to create empty database");
    delete database;
    return NULL;
  }

  if (! database->PrepareCommonQueries()) {
    database->PrintSqlError("Failed to initialize properties queries");
    delete database;
    return NULL;
  }

  if (! database->StoreSchemaRevision()) {
    database->PrintSqlError("Failed to store initial schema revision");
    delete database;
    return NULL;
  }

  return database;
}


template <class DerivedT>
DerivedT* Database<DerivedT>::Open(const std::string  &filename,
                                   const OpenMode      open_mode) {
  DerivedT* database = new DerivedT(filename, open_mode);
  if (! database->Initialize()) {
    delete database;
    database = NULL;
  }

  return database;
}


template <class DerivedT>
bool Database<DerivedT>::Initialize() {
  const int flags = (read_write_) ? SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE
                                  : SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY;

  const bool successful = OpenDatabase(flags)        &&
                          FileReadAhead()            &&
                          PrepareCommonQueries();
  if (! successful) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open database file '%s'",
                                 filename_.c_str());
    return false;
  }

  ReadSchemaRevision();
  LogCvmfs(kLogSql, kLogDebug, "opened database with schema version %f "
                               "and revision %u",
                               schema_version_, schema_revision_);

  if (! static_cast<DerivedT*>(this)->CheckSchemaCompatibility()) {
    LogCvmfs(kLogSql, kLogDebug, "schema version %f not supported (%s)",
             schema_version_, filename_.c_str());
    return false;
  }

  if (read_write_ &&
      ! static_cast<DerivedT*>(this)->LiveSchemaUpgradeIfNecessary()) {
    LogCvmfs(kLogSql, kLogDebug, "failed tp upgrade schema revision");
    return false;
  }

  return true;
}


template <class DerivedT>
bool Database<DerivedT>::OpenDatabase(const int flags) {
  // Open database file (depending on the flags read-only or read-write)
  LogCvmfs(kLogSql, kLogDebug, "opening database file %s",
           filename_.c_str());
  if (SQLITE_OK != sqlite3_open_v2(filename_.c_str(), &sqlite_db_, flags, NULL))
  {
    LogCvmfs(kLogSql, kLogDebug, "cannot open database file %s",
             filename_.c_str());
    return false;
  }

  const int retval = sqlite3_extended_result_codes(sqlite_db_, 1);
  assert (SQLITE_OK == retval);

  return true;
}


template <class DerivedT>
Database<DerivedT>::~Database() {
  if (NULL != sqlite_db_) {
    sqlite3_close(sqlite_db_);
    sqlite_db_ = NULL;
  }
}


template <class DerivedT>
bool Database<DerivedT>::FileReadAhead() {
  // Read-ahead into file system buffers
  // TODO: mmap, re-readahead
  int fd_readahead = open(filename_.c_str(), O_RDONLY);
  if (fd_readahead < 0) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open %s for read-ahead (%d)",
             filename_.c_str(), errno);
    return false;
  }

  const int retval = platform_readahead(fd_readahead);
  close(fd_readahead);
  if (retval != 0) {
    LogCvmfs(kLogSql, kLogDebug | kLogSyslogWarn,
             "failed to read-ahead %s (%d)", filename_.c_str(), errno);
    return false;
  }

  return true;
}


template <class DerivedT>
bool Database<DerivedT>::PrepareCommonQueries() {
  sqlite3 *db = sqlite_db_;
  begin_transaction_  = new Sql(db, "BEGIN;");
  commit_transaction_ = new Sql(db, "COMMIT;");
  has_property_       = new Sql(db, "SELECT count(*) FROM properties "
                                    "WHERE key = :key;");
  get_property_       = new Sql(db, "SELECT value FROM properties "
                                    "WHERE key = :key;");
  set_property_       = new Sql(db, "INSERT OR REPLACE INTO properties "
                                    "(key, value) VALUES (:key, :value);");
  return (begin_transaction_ && commit_transaction_ &&
          has_property_ && get_property_ && set_property_);
}


template <class DerivedT>
void Database<DerivedT>::ReadSchemaRevision() {
  schema_version_  = (this->HasProperty(kSchemaVersionKey))
                        ? this->GetProperty<double>(kSchemaVersionKey)
                        : 1.0;
  schema_revision_ = (this->HasProperty(kSchemaRevisionKey))
                        ? this->GetProperty<int>(kSchemaRevisionKey)
                        : 0;
}


template <class DerivedT>
bool Database<DerivedT>::StoreSchemaRevision() {
  return this->SetProperty(kSchemaVersionKey,  schema_version_)   &&
         this->SetProperty(kSchemaRevisionKey, schema_revision_);
}


template <class DerivedT>
bool Database<DerivedT>::BeginTransaction() const {
  return begin_transaction_->Execute() &&
         begin_transaction_->Reset();
}


template <class DerivedT>
bool Database<DerivedT>::CommitTransaction() const {
  return commit_transaction_->Execute() &&
         commit_transaction_->Reset();
}


template <class DerivedT>
bool Database<DerivedT>::CreatePropertiesTable() {
  return Sql(sqlite_db_,
    "CREATE TABLE properties (key TEXT, value TEXT, "
    "CONSTRAINT pk_properties PRIMARY KEY (key));").Execute();
}


template <class DerivedT>
bool Database<DerivedT>::HasProperty(const std::string &key) const {
  assert (has_property_);
  const bool retval = has_property_->BindText(1, key) &&
                      has_property_->FetchRow();
  assert (retval);
  const bool result = has_property_->RetrieveInt64(0) > 0;
  has_property_->Reset();
  return result;
}

template <class DerivedT>
template <typename T>
T Database<DerivedT>::GetProperty(const std::string &key) const {
  assert (get_property_);
  const bool retval = get_property_->BindText(1, key);
                      get_property_->FetchRow();
  assert (retval);
  const T result = get_property_->Retrieve<T>(0);
  get_property_->Reset();
  return result;
}

template <class DerivedT>
template <typename T>
bool Database<DerivedT>::SetProperty(const std::string &key,
                                     const T            value) {
  assert (set_property_);<commit_msg>FIX: Coverity 59452 and 59453<commit_after>/**
 * This file is part of the CernVM file system.
 */

#include <fcntl.h>
#include <cerrno>
#include <cassert>

#include "platform.h"
#include "logging.h"

namespace sqlite {


template <class DerivedT>
Database<DerivedT>::Database(const std::string  &filename,
                             const OpenMode      open_mode) :
  sqlite_db_(NULL),
  filename_(filename),
  read_write_(kOpenReadWrite == open_mode),
  schema_version_(0.0f),
  schema_revision_(0) {}


template <class DerivedT>
DerivedT* Database<DerivedT>::Create(const std::string &filename) {
  // TODO: SharedPointer to avoid 'delete' in error conditions
  DerivedT *database = new DerivedT(filename, kOpenReadWrite);
  database->set_schema_version(DerivedT::kLatestSchema);
  database->set_schema_revision(DerivedT::kLatestSchemaRevision);

  if (! database) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database object");
    return NULL;
  }

  const int open_flags = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE |
                         SQLITE_OPEN_CREATE;
  if (! database->OpenDatabase(open_flags)) {
    LogCvmfs(kLogSql, kLogDebug, "Failed to create new database file");
    delete database;
    return NULL;
  }

  if (! database->CreatePropertiesTable()) {
    database->PrintSqlError("Failed to create common properties table");
    delete database;
    return NULL;
  }

  if (! database->CreateEmptyDatabase()) {
    database->PrintSqlError("Failed to create empty database");
    delete database;
    return NULL;
  }

  if (! database->PrepareCommonQueries()) {
    database->PrintSqlError("Failed to initialize properties queries");
    delete database;
    return NULL;
  }

  if (! database->StoreSchemaRevision()) {
    database->PrintSqlError("Failed to store initial schema revision");
    delete database;
    return NULL;
  }

  return database;
}


template <class DerivedT>
DerivedT* Database<DerivedT>::Open(const std::string  &filename,
                                   const OpenMode      open_mode) {
  DerivedT* database = new DerivedT(filename, open_mode);
  if (! database->Initialize()) {
    delete database;
    database = NULL;
  }

  return database;
}


template <class DerivedT>
bool Database<DerivedT>::Initialize() {
  const int flags = (read_write_) ? SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE
                                  : SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY;

  const bool successful = OpenDatabase(flags)        &&
                          FileReadAhead()            &&
                          PrepareCommonQueries();
  if (! successful) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open database file '%s'",
                                 filename_.c_str());
    return false;
  }

  ReadSchemaRevision();
  LogCvmfs(kLogSql, kLogDebug, "opened database with schema version %f "
                               "and revision %u",
                               schema_version_, schema_revision_);

  if (! static_cast<DerivedT*>(this)->CheckSchemaCompatibility()) {
    LogCvmfs(kLogSql, kLogDebug, "schema version %f not supported (%s)",
             schema_version_, filename_.c_str());
    return false;
  }

  if (read_write_ &&
      ! static_cast<DerivedT*>(this)->LiveSchemaUpgradeIfNecessary()) {
    LogCvmfs(kLogSql, kLogDebug, "failed tp upgrade schema revision");
    return false;
  }

  return true;
}


template <class DerivedT>
bool Database<DerivedT>::OpenDatabase(const int flags) {
  // Open database file (depending on the flags read-only or read-write)
  LogCvmfs(kLogSql, kLogDebug, "opening database file %s",
           filename_.c_str());
  if (SQLITE_OK != sqlite3_open_v2(filename_.c_str(), &sqlite_db_, flags, NULL))
  {
    LogCvmfs(kLogSql, kLogDebug, "cannot open database file %s",
             filename_.c_str());
    return false;
  }

  const int retval = sqlite3_extended_result_codes(sqlite_db_, 1);
  assert (SQLITE_OK == retval);

  return true;
}


template <class DerivedT>
Database<DerivedT>::~Database() {
  if (NULL != sqlite_db_) {
    sqlite3_close(sqlite_db_);
    sqlite_db_ = NULL;
  }
}


template <class DerivedT>
bool Database<DerivedT>::FileReadAhead() {
  // Read-ahead into file system buffers
  // TODO: mmap, re-readahead
  int fd_readahead = open(filename_.c_str(), O_RDONLY);
  if (fd_readahead < 0) {
    LogCvmfs(kLogSql, kLogDebug, "failed to open %s for read-ahead (%d)",
             filename_.c_str(), errno);
    return false;
  }

  const int retval = platform_readahead(fd_readahead);
  close(fd_readahead);
  if (retval != 0) {
    LogCvmfs(kLogSql, kLogDebug | kLogSyslogWarn,
             "failed to read-ahead %s (%d)", filename_.c_str(), errno);
    return false;
  }

  return true;
}


template <class DerivedT>
bool Database<DerivedT>::PrepareCommonQueries() {
  sqlite3 *db = sqlite_db_;
  begin_transaction_  = new Sql(db, "BEGIN;");
  commit_transaction_ = new Sql(db, "COMMIT;");
  has_property_       = new Sql(db, "SELECT count(*) FROM properties "
                                    "WHERE key = :key;");
  get_property_       = new Sql(db, "SELECT value FROM properties "
                                    "WHERE key = :key;");
  set_property_       = new Sql(db, "INSERT OR REPLACE INTO properties "
                                    "(key, value) VALUES (:key, :value);");
  return (begin_transaction_ && commit_transaction_ &&
          has_property_ && get_property_ && set_property_);
}


template <class DerivedT>
void Database<DerivedT>::ReadSchemaRevision() {
  schema_version_  = (this->HasProperty(kSchemaVersionKey))
                        ? this->GetProperty<double>(kSchemaVersionKey)
                        : 1.0;
  schema_revision_ = (this->HasProperty(kSchemaRevisionKey))
                        ? this->GetProperty<int>(kSchemaRevisionKey)
                        : 0;
}


template <class DerivedT>
bool Database<DerivedT>::StoreSchemaRevision() {
  return this->SetProperty(kSchemaVersionKey,  schema_version_)   &&
         this->SetProperty(kSchemaRevisionKey, schema_revision_);
}


template <class DerivedT>
bool Database<DerivedT>::BeginTransaction() const {
  return begin_transaction_->Execute() &&
         begin_transaction_->Reset();
}


template <class DerivedT>
bool Database<DerivedT>::CommitTransaction() const {
  return commit_transaction_->Execute() &&
         commit_transaction_->Reset();
}


template <class DerivedT>
bool Database<DerivedT>::CreatePropertiesTable() {
  return Sql(sqlite_db_,
    "CREATE TABLE properties (key TEXT, value TEXT, "
    "CONSTRAINT pk_properties PRIMARY KEY (key));").Execute();
}


template <class DerivedT>
bool Database<DerivedT>::HasProperty(const std::string &key) const {
  assert (has_property_);
  const bool retval = has_property_->BindText(1, key) &&
                      has_property_->FetchRow();
  assert (retval);
  const bool result = has_property_->RetrieveInt64(0) > 0;
  has_property_->Reset();
  return result;
}

template <class DerivedT>
template <typename T>
T Database<DerivedT>::GetProperty(const std::string &key) const {
  assert (get_property_);
  const bool retval = get_property_->BindText(1, key) &&
                      get_property_->FetchRow();
  assert (retval);
  const T result = get_property_->Retrieve<T>(0);
  get_property_->Reset();
  return result;
}

template <class DerivedT>
template <typename T>
bool Database<DerivedT>::SetProperty(const std::string &key,
                                     const T            value) {
  assert (set_property_);
{'fraction_non_alphanumeric': 0.11500198965380024, 'fraction_numerical': 0.0034487332537471815, 'mean_word_length': 3.1448598130841123, 'pattern_counts': {'":': 0, '<': 89, '<?xml version=': 0, '>': 153, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5475516', 'n_tokens_mistral': 4642, 'n_tokens_neox': 4429, 'n_words': 1075}