meos-2024/code/mysqlwrapper.cpp
2023-02-09 08:15:40 +01:00

414 lines
8.9 KiB
C++

#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<uint8_t>& 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);
}