<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 <NAME>, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord/logging.h>
#include <fnord/net/mysql/MySQLConnection.h>

namespace fnord {
namespace mysql {

std::unique_ptr<MySQLConnection> MySQLConnection::openConnection(
    const fnord::URI& uri) {
  std::unique_ptr<MySQLConnection> conn(new MySQLConnection());
  conn->connect(uri);
  return conn;
}

std::unique_ptr<MySQLConnection> MySQLConnection::openConnection(
    const std::string& host,
    unsigned int port,
    const std::string& database,
    const std::string& username,
    const std::string& password) {
  std::unique_ptr<MySQLConnection> conn(new MySQLConnection());
  conn->connect(host, port, database, username, password);
  return conn;
}

MySQLConnection::MySQLConnection() : mysql_(nullptr) {
#ifdef FNORD_ENABLE_MYSQL
  mysql_ = mysql_init(NULL);

  if (mysql_ == nullptr) {
    RAISE(kRuntimeError, "mysql_init() failed\n");
  }

  mysql_options(mysql_, MYSQL_SET_CHARSET_NAME, "utf8");
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
}

MySQLConnection::~MySQLConnection() {
#ifdef FNORD_ENABLE_MYSQL
  mysql_close(mysql_);
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
}

void MySQLConnection::connect(const fnord::URI& uri) {
  unsigned int port = 3306;
  std::string host = uri.host();
  std::string username;
  std::string password;
  std::string database;

  if (host.size() == 0) {
    RAISE(
        kRuntimeError,
        "invalid mysql:// URI: has no hostname (URI: '%s')",
        uri.toString().c_str());
  }

  if (uri.port() > 0) {
    port = uri.port();
  }

  if (uri.path().size() < 2 || uri.path()[0] != '/') {
    RAISE(
        kRuntimeError,
        "invalid mysql:// URI: missing database, format is: mysql://host/db "
        " (URI: %s)",
        uri.toString().c_str());
  }

  database = uri.path().substr(1);

  for (const auto& param : uri.queryParams()) {
    if (param.first == "username" || param.first == "user") {
      username = param.second;
      continue;
    }

    if (param.first == "password" || param.first == "<PASSWORD>") {
      password = param.second;
      continue;
    }

    RAISE(
        kRuntimeError,
        "invalid parameter for mysql:// URI: '%s=%s'",
        param.first.c_str(),
        param.second.c_str());
  }

  connect(host, port, database, username, password);
}

void MySQLConnection::connect(
    const std::string& host,
    unsigned int port,
    const std::string& database,
    const std::string& username,
    const std::string& password) {
#ifdef FNORD_ENABLE_MYSQL
  auto ret = mysql_real_connect(
      mysql_,
      host.c_str(),
      username.size() > 0 ? username.c_str() : NULL,
      password.size() > 0 ? password.c_str() : NULL,
      database.size() > 0 ? database.c_str() : NULL,
      port,
      NULL,
      CLIENT_COMPRESS);

  if (ret != mysql_) {
    RAISE(
      kRuntimeError,
      "mysql_real_connect() failed: %s\n",
      mysql_error(mysql_));
  }
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
}

std::vector<std::string> MySQLConnection::describeTable(
    const std::string& table_name) {
  std::vector<std::string> columns;

#ifdef FNORD_ENABLE_MYSQL
  MYSQL_RES* res = mysql_list_fields(mysql_, table_name.c_str(), NULL);
  if (res == nullptr) {
    RAISE(
      kRuntimeError,
      "mysql_list_fields() failed: %s\n",
      mysql_error(mysql_));
  }

  auto num_cols = mysql_num_fields(res);
  for (int i = 0; i < num_cols; ++i) {
    MYSQL_FIELD* col = mysql_fetch_field_direct(res, i);
    columns.emplace_back(col->name);
  }

  mysql_free_result(res);
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
  return columns;
}

RefPtr<msg::MessageSchema> MySQLConnection::getTableSchema(
    const std::string& table_name) {
  std::vector<std::string> columns;
#ifdef FNORD_ENABLE_MYSQL
  MYSQL_RES* res = mysql_list_fields(mysql_, table_name.c_str(), NULL);
  if (res == nullptr) {
    RAISE(
      kRuntimeError,
      "mysql_list_fields() failed: %s\n",
      mysql_error(mysql_));
  }

  Vector<msg::MessageSchemaField> schema_fields;
  auto num_cols = mysql_num_fields(res);
  for (int i = 0; i < num_cols; ++i) {
    MYSQL_FIELD* col = mysql_fetch_field_direct(res, i);

    bool optional = (col->flags & NOT_NULL_FLAG) > 0;
    bool is_unsigned = (col->flags & UNSIGNED_FLAG) > 0;
    msg::FieldType type;

    switch (col->type) {
      case MYSQL_TYPE_TINY:<commit_msg>mysql cols always optional<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 <NAME>, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnord/logging.h>
#include <fnord/net/mysql/MySQLConnection.h>

namespace fnord {
namespace mysql {

std::unique_ptr<MySQLConnection> MySQLConnection::openConnection(
    const fnord::URI& uri) {
  std::unique_ptr<MySQLConnection> conn(new MySQLConnection());
  conn->connect(uri);
  return conn;
}

std::unique_ptr<MySQLConnection> MySQLConnection::openConnection(
    const std::string& host,
    unsigned int port,
    const std::string& database,
    const std::string& username,
    const std::string& password) {
  std::unique_ptr<MySQLConnection> conn(new MySQLConnection());
  conn->connect(host, port, database, username, password);
  return conn;
}

MySQLConnection::MySQLConnection() : mysql_(nullptr) {
#ifdef FNORD_ENABLE_MYSQL
  mysql_ = mysql_init(NULL);

  if (mysql_ == nullptr) {
    RAISE(kRuntimeError, "mysql_init() failed\n");
  }

  mysql_options(mysql_, MYSQL_SET_CHARSET_NAME, "utf8");
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
}

MySQLConnection::~MySQLConnection() {
#ifdef FNORD_ENABLE_MYSQL
  mysql_close(mysql_);
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
}

void MySQLConnection::connect(const fnord::URI& uri) {
  unsigned int port = 3306;
  std::string host = uri.host();
  std::string username;
  std::string password;
  std::string database;

  if (host.size() == 0) {
    RAISE(
        kRuntimeError,
        "invalid mysql:// URI: has no hostname (URI: '%s')",
        uri.toString().c_str());
  }

  if (uri.port() > 0) {
    port = uri.port();
  }

  if (uri.path().size() < 2 || uri.path()[0] != '/') {
    RAISE(
        kRuntimeError,
        "invalid mysql:// URI: missing database, format is: mysql://host/db "
        " (URI: %s)",
        uri.toString().c_str());
  }

  database = uri.path().substr(1);

  for (const auto& param : uri.queryParams()) {
    if (param.first == "username" || param.first == "user") {
      username = param.second;
      continue;
    }

    if (param.first == "password" || param.first == "pass") {
      password = param.second;
      continue;
    }

    RAISE(
        kRuntimeError,
        "invalid parameter for mysql:// URI: '%s=%s'",
        param.first.c_str(),
        param.second.c_str());
  }

  connect(host, port, database, username, password);
}

void MySQLConnection::connect(
    const std::string& host,
    unsigned int port,
    const std::string& database,
    const std::string& username,
    const std::string& password) {
#ifdef FNORD_ENABLE_MYSQL
  auto ret = mysql_real_connect(
      mysql_,
      host.c_str(),
      username.size() > 0 ? username.c_str() : NULL,
      password.size() > 0 ? password.c_str() : NULL,
      database.size() > 0 ? database.c_str() : NULL,
      port,
      NULL,
      CLIENT_COMPRESS);

  if (ret != mysql_) {
    RAISE(
      kRuntimeError,
      "mysql_real_connect() failed: %s\n",
      mysql_error(mysql_));
  }
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
}

std::vector<std::string> MySQLConnection::describeTable(
    const std::string& table_name) {
  std::vector<std::string> columns;

#ifdef FNORD_ENABLE_MYSQL
  MYSQL_RES* res = mysql_list_fields(mysql_, table_name.c_str(), NULL);
  if (res == nullptr) {
    RAISE(
      kRuntimeError,
      "mysql_list_fields() failed: %s\n",
      mysql_error(mysql_));
  }

  auto num_cols = mysql_num_fields(res);
  for (int i = 0; i < num_cols; ++i) {
    MYSQL_FIELD* col = mysql_fetch_field_direct(res, i);
    columns.emplace_back(col->name);
  }

  mysql_free_result(res);
#else
  RAISE(kRuntimeError, "libfnord was compiled without libmysqlclient");
#endif
  return columns;
}

RefPtr<msg::MessageSchema> MySQLConnection::getTableSchema(
    const std::string& table_name) {
  std::vector<std::string> columns;
#ifdef FNORD_ENABLE_MYSQL
  MYSQL_RES* res = mysql_list_fields(mysql_, table_name.c_str(), NULL);
  if (res == nullptr) {
    RAISE(
      kRuntimeError,
      "mysql_list_fields() failed: %s\n",
      mysql_error(mysql_));
  }

  Vector<msg::MessageSchemaField> schema_fields;
  auto num_cols = mysql_num_fields(res);
  for (int i = 0; i < num_cols; ++i) {
    MYSQL_FIELD* col = mysql_fetch_field_direct(res, i);

    bool optional = true; // (col->flags & NOT_NULL_FLAG) > 0;
    bool is_unsigned = (col->flags & UNSIGNED_FLAG) > 0;
    msg::FieldType type;

    switch (col->type) {
      case MYSQL_TYPE_TINY:
{'fraction_non_alphanumeric': 0.14102300739523418, 'fraction_numerical': 0.004724732949876746, 'mean_word_length': 3.641086749285033, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 54, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '396507', 'n_tokens_mistral': 3325, 'n_tokens_neox': 3231, 'n_words': 779}