#include "stdafx.h" #include "mysql/mysql.h" #include "mysqlwrapper.h" using namespace sqlwrapper; const char *CellWrapper::c_str() const { return data; } string CellWrapper::get_string() const { if (data != nullptr) return data; return ""; } CellWrapper::operator string() const { if (data != nullptr) return data; return ""; } CellWrapper::operator int() const { if (data != nullptr) return atoi(data); return 0; } CellWrapper::operator unsigned int() const { char *out; if (data != nullptr) return strtoul(data, &out, 10); return 0; } CellWrapper::operator bool() const { return int(*this) != 0; } int64_t CellWrapper::longlong() const { char *out; if (data != nullptr) return strtoll(data, &out, 10); return 0; } uint64_t CellWrapper::ulonglong() const { char* out; if (data != nullptr) return strtoull(data, &out, 10); return 0; } void CellWrapper::storeBlob(std::vector& d) const { if (data != nullptr) { d.resize(length); memcpy(d.data(), data, length); } } bool CellWrapper::is_null() const { return data == nullptr; } CellWrapper RowWrapper::at(int col) const { if (res && row) { auto lengths = mysql_fetch_lengths(res->result); return CellWrapper(row[col], lengths[col]); } throw Exception("Invalid offset"); } CellWrapper RowWrapper::operator[](const char *name) const { if (res) { int col = res->field_num(name); return at(col); } throw Exception("Invalid offset"); } CellWrapper RowWrapper::operator[](int ix) const { if (res) { return at(ix); } throw Exception("Invalid offset"); } RowWrapper::RowWrapper(ResultBase *res, MYSQL_ROW row) : res(res), row(row) { } int RowWrapper::size() const { if (res && res->result) return mysql_num_fields(res->result); return 0; } RowWrapper::operator bool() const { return row != nullptr; } const char *RowWrapper::raw_string(int ix) const { if (row) return row[ix]; return nullptr; } ResultBase::ResultBase(ConnectionWrapper *con, MYSQL_RES * res) : con(con), result(res) { } ResultBase::ResultBase(ResultBase &&r) : con(r.con) { result = r.result; r.result = nullptr; } const ResultBase &ResultBase::operator=(ResultBase &&r) { con = r.con; if (result) mysql_free_result(result); name2Col.clear(); result = r.result; r.result = nullptr; return *this; } ResultBase:: ~ResultBase() { if (result) { mysql_free_result(result); result = nullptr; } } int ResultBase::field_num(const string &fieldName) { if (name2Col.empty()) { //if (mysql_result_metadata() unsigned int num_fields; unsigned int i; MYSQL_FIELD *fields; num_fields = mysql_num_fields(result); fields = mysql_fetch_fields(result); for (i = 0; i < num_fields; i++) name2Col[fields[i].name] = i; } auto res = name2Col.find(fieldName); if (res == name2Col.end()) throw BadFieldName(fieldName); return res->second; } ResultWrapper::ResultWrapper(ConnectionWrapper &con, MYSQL_RES * res) : ResultBase(&con, res) { } int ResultWrapper::num_rows() const { if (result) return (int)mysql_num_rows(result); return 0; } RowWrapper ResultWrapper::at(int row) { if (result && row>=0 && row < num_rows()) { mysql_data_seek(result, row); auto rd = mysql_fetch_row(result); if (rd) { return RowWrapper(this, rd); } } throw Exception("Invalid offset"); } ResultWrapper::operator bool() const { return result != nullptr; } bool ResultWrapper::empty() const { return num_rows() == 0; } ResUseWrapper::ResUseWrapper(ConnectionWrapper &con, MYSQL_RES *res) : ResultBase(&con, res) { } ResUseWrapper::operator bool() const { return result != nullptr; } RowWrapper ResUseWrapper::fetch_row() { if (!result) throw Exception("Invalid result"); auto row = mysql_fetch_row(result); if (row) return RowWrapper(this, row); else throw EndOfResults(); } ResNSel::operator bool() const{ return rows>=0; }; Exception::Exception(const char *w) : w(w) {} const char *Exception::what() const { return w.c_str(); } QueryWrapper::QueryWrapper(ConnectionWrapper &con) : con(con) { sql.reserve(1024*4); } QueryWrapper::~QueryWrapper() { } ResultWrapper QueryWrapper::store(const string &q) { exec(q); auto result = mysql_store_result(con.get()); con.unusedResult = false; if (result || mysql_field_count(con.get()) == 0) { return ResultWrapper(con, result); } throw Exception(mysql_error(con.get())); } ResultWrapper QueryWrapper::store() { return store(sql); } ResUseWrapper QueryWrapper::use(const string &q) { exec(q); auto result = mysql_use_result(con.get()); con.unusedResult = false; if (result || mysql_field_count(con.get()) == 0) { return ResUseWrapper(con, result); } throw Exception(mysql_error(con.get())); } void QueryWrapper::reset() { sql.clear(); } ResNSel QueryWrapper::execute() { exec(sql); int id = (int) mysql_insert_id(con.get()); int r = (int) mysql_affected_rows(con.get()); return ResNSel(id, r); } ResNSel QueryWrapper::execute(const string &q) { exec(q); int id = (int)mysql_insert_id(con.get()); int r = (int)mysql_affected_rows(con.get()); return ResNSel(id, r); } void QueryWrapper::exec(const string &q) { auto c = con.get(); if (con.unusedResult) { auto res = mysql_store_result(c); if (res) mysql_free_result(res); } if (mysql_real_query(c, q.c_str(), q.length()) != 0) throw Exception(mysql_error(c)); con.unusedResult = true; } const string &QueryWrapper::str() const { return sql; } QueryWrapper & QueryWrapper::operator<<(const string &arg) { if (qnext) { int len = arg.size(); int pt = sql.size(); sql.resize(pt + len * 2); int realsize = mysql_real_escape_string(con.get(), &sql[pt], arg.c_str(), len); sql.resize(pt + realsize); sql += "'"; qnext = false; } else { sql += arg; } return *this; } QueryWrapper & QueryWrapper::operator<<(const char *arg) { if (qnext) { int len = strlen(arg); int pt = sql.size(); sql.resize(pt + len*2); int realsize = mysql_real_escape_string(con.get(), &sql[pt], arg, len); sql.resize(pt + realsize); sql += "'"; qnext = false; } else { sql += arg; } return *this; } QueryWrapper & QueryWrapper::operator<<(int arg) { sql += to_string(arg); if (qnext) { sql += "'"; qnext = false; } return *this; } QueryWrapper & QueryWrapper::operator<<(uint32_t arg) { sql += to_string(arg); if (qnext) { sql += "'"; qnext = false; } return *this; } QueryWrapper & QueryWrapper::operator<<(int64_t arg) { sql += to_string(arg); if (qnext) { sql += "'"; qnext = false; } return *this; } QueryWrapper & QueryWrapper::operator<<(QT arg) { sql += "'"; qnext = true; return *this; } ConnectionWrapper::ConnectionWrapper() { } ConnectionWrapper::~ConnectionWrapper() { close(); } void ConnectionWrapper::close() { if (mysql != nullptr) { mysql_close(mysql); mysql = nullptr; } } bool ConnectionWrapper::select_db(const string &db) { if (mysql_select_db(get(), db.c_str()) != 0) throw Exception(mysql_error(mysql)); return true; } void ConnectionWrapper::create_db(const string &db) { string sql = "CREATE DATABASE " + db + ""; if (mysql_query(get(), sql.c_str()) != 0) throw Exception(mysql_error(mysql)); } void ConnectionWrapper::drop_db(const string &db) { string sql = "DROP DATABASE " + db + ""; if (mysql_query(get(), sql.c_str()) != 0) throw Exception(mysql_error(mysql)); } MYSQL *ConnectionWrapper::get() const { if (!mysql) throw Exception("Not connected"); return mysql; } string ConnectionWrapper::server_info() const { const char *ptr = mysql_get_server_info(get()); if (ptr) return ptr; return ""; } bool ConnectionWrapper::connected() const { return mysql != nullptr; } void ConnectionWrapper::connect(const string &unused, const string &server, const string &user, const string &pwd, int port) { close(); mysql = mysql_init(nullptr); if (!mysql_real_connect(mysql, server.c_str(), user.c_str(), pwd.c_str(), nullptr, port, nullptr, 0)) { string err = mysql_error(mysql); mysql_close(mysql); mysql = nullptr; throw Exception(err.c_str()); } bool t = true; mysql_options(mysql, MYSQL_OPT_RECONNECT, &t); } QueryWrapper ConnectionWrapper::query() { return QueryWrapper(*this); }