296 lines
8.3 KiB
C++
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;
|
|
}
|
|
|
|
}
|
|
}
|