395 lines
8.4 KiB
C++
395 lines
8.4 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::ulonglong() const {
|
|
char *out;
|
|
if (data != nullptr)
|
|
return strtoll(data, &out, 10);
|
|
return 0;
|
|
}
|
|
|
|
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) {
|
|
throw Exception("Not implemented");
|
|
}
|
|
|
|
MYSQL *ConnectionWrapper::get() const {
|
|
if (!mysql)
|
|
throw Exception("Not connected");
|
|
return mysql;
|
|
}
|
|
|
|
string ConnectionWrapper::server_info() const {
|
|
return mysql_get_server_info(get());
|
|
}
|
|
|
|
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);
|
|
}
|