a8/a8/mysql.cc
aozhiwei e591648ac9 1
2022-12-16 17:04:15 +08:00

296 lines
8.3 KiB
C++

#include <assert.h>
#include <a8/a8.h>
#include <a8/mysql.h>
#include <mysql.h>
namespace a8
{
namespace mysql
{
struct ConnectionImpl
{
MYSQL* conn = nullptr;
std::string host;
int port = 0;
std::string username;
std::string passwd;
std::string database;
bool connected = false;
};
struct QueryImpl
{
a8::mysql::ConnectionImpl* conn_impl = nullptr;
MYSQL_RES* mysqlres = nullptr;
MYSQL_ROW row = nullptr;
MYSQL_FIELD* fileds = nullptr;
unsigned long* fieldslen = nullptr;
void FreeLastDataSet()
{
if(mysqlres){
mysql_free_result(mysqlres);
}
mysqlres = NULL;
row = NULL;
}
MYSQL* Conn()
{
return conn_impl->conn;
}
};
Connection::Connection()
{
impl_ = new ConnectionImpl;
impl_->conn = mysql_init(NULL);
assert(impl_->conn);
}
Connection::~Connection()
{
if(impl_->conn){
mysql_close(impl_->conn);
}
delete impl_;
impl_ = nullptr;
}
bool Connection::Connected()
{
return impl_->connected;
}
bool Connection::Connect(const std::string& host,
int port,
const std::string& username,
const std::string& pwd,
const std::string& dataBase)
{
impl_->host = host;
impl_->port = port;
impl_->username = username;
impl_->passwd = pwd;
impl_->database = dataBase;
return mysql_real_connect(impl_->conn,
impl_->host.c_str(),
impl_->username.c_str(),
impl_->passwd.c_str(),
impl_->database.c_str(),
impl_->port,
nullptr,
0);
}
void Connection::Close()
{
if(impl_->conn){
mysql_close(impl_->conn);
}
}
std::string Connection::GetError()
{
std::string strError = mysql_error(impl_->conn);
return strError;
}
a8::mysql::Query* Connection::CreateQuery()
{
return new Query(impl_);
}
std::string Connection::GetHost()
{
return impl_->host;
}
int Connection::GetPort()
{
return impl_->port;
}
std::string Connection::GetUser()
{
return impl_->username;
}
std::string Connection::GetPasswd()
{
return impl_->passwd;
}
std::string Connection::GetDataBase()
{
return impl_->database;
}
Query::Query(a8::mysql::ConnectionImpl* conn_impl)
{
impl_ = new QueryImpl();
impl_->conn_impl = conn_impl;
}
Query::~Query()
{
impl_->FreeLastDataSet();
delete impl_;
impl_ = nullptr;
}
int Query::ExecQuery(const char* querystr, std::vector<a8::XValue> args)
{
impl_->FreeLastDataSet();
std::string real_sql = FormatSql(querystr, args).c_str();
int err = mysql_query(impl_->Conn(), real_sql.c_str());
if(err == 0){
impl_->mysqlres = mysql_store_result(impl_->Conn());
if(RowsNum() > 0){
Next();
}
return RowsNum();
}
return -1;
}
bool Query::ExecScript(const char* scriptstr, std::vector<a8::XValue> args)
{
impl_->FreeLastDataSet();
std::string real_sql = FormatSql(scriptstr , args).c_str();
return mysql_query(impl_->Conn(), real_sql.c_str()) == 0;
}
std::string Query::FormatSqlEx(const char* fmt, std::vector<a8::XValue> args)
{
return FormatSql(fmt, args);
}
std::string Query::FormatSql(const char* fmt, std::vector<a8::XValue>& args)
{
std::string result;
result.reserve(1024);
auto itr = args.begin();
const char *p = fmt;
while(*p){
if(*p == '%' && *(p+1)){
p++;
switch(*p){
case 'd':
assert(itr != args.end());
result.append(itr->GetString().c_str());
itr++;
break;
case 'f':
assert(itr != args.end());
result.append(itr->GetString().c_str());
itr++;
break;
case 's':
{
assert(itr != args.end());
std::string str = itr->GetString();
char* p = new char[str.size() * 2 + 1];
p[0] = '\0';
mysql_real_escape_string(impl_->Conn(), p, str.data(), str.size());
result.append(p);
delete [] p;
itr++;
break;
}
default:
{
result.push_back('%');
result.push_back(*p);
}
}
}else{
result.push_back(*p);
}
p++;
}
return result;
}
int Query::RowsNum()
{
assert(impl_->mysqlres);
return impl_->mysqlres ? mysql_num_rows(impl_->mysqlres) : 0;
}
int Query::FieldsNum()
{
assert(impl_->mysqlres);
return impl_->mysqlres ? mysql_num_fields(impl_->mysqlres) : 0;
}
bool Query::Eof()
{
assert(impl_->mysqlres);
return impl_->row == NULL;
}
void Query::First()
{
assert(impl_->mysqlres);
if(impl_->mysqlres && RowsNum() > 0){
mysql_data_seek(impl_->mysqlres, 0);
impl_->row = mysql_fetch_row(impl_->mysqlres);
impl_->fieldslen = mysql_fetch_lengths(impl_->mysqlres);
}
}
void Query::Prev()
{
assert(impl_->mysqlres);
if(impl_->mysqlres){
mysql_row_seek(impl_->mysqlres, mysql_row_tell(impl_->mysqlres) - 1);
impl_->row = mysql_fetch_row(impl_->mysqlres);
impl_->fieldslen = mysql_fetch_lengths(impl_->mysqlres);
}
}
void Query::Next()
{
assert(impl_->mysqlres);
if(impl_->mysqlres){
impl_->row = mysql_fetch_row(impl_->mysqlres);
impl_->fieldslen = mysql_fetch_lengths(impl_->mysqlres);
}
}
void Query::Last()
{
assert(impl_->mysqlres);
if(impl_->mysqlres && RowsNum() > 0){
mysql_data_seek(impl_->mysqlres, RowsNum() - 1);
impl_->row = mysql_fetch_row(impl_->mysqlres);
impl_->fieldslen = mysql_fetch_lengths(impl_->mysqlres);
}
}
a8::XValue Query::GetValue(short idx)
{
a8::XValue xv;
if(impl_->row && impl_->row[idx]){
if(impl_->fieldslen[idx] > 0){
xv.SetDynData((const char*)impl_->row[idx], impl_->fieldslen[idx]);
}else{
xv.Set((const char*)impl_->row[idx]);
}
}
return xv;
}
std::string Query::GetError()
{
std::string strError = mysql_error(impl_->conn_impl->conn);
return strError;
}
}
}