#include #include #include #include #include #include #include "mysqlwrap.h" CMySqlDB::CMySqlDB(void) : m_fIsInit(false) { memset(&m_mySql, 0, sizeof(m_mySql)); Init(); } CMySqlDB::~CMySqlDB(void) { Close(); } bool CMySqlDB::Init(void) throw() { if(!m_fIsInit) m_fIsInit = !!mysql_init(&m_mySql); return m_fIsInit; } void CMySqlDB::Close(void) throw() { if(m_fIsInit) { mysql_close(&m_mySql); m_fIsInit = false; memset(&m_mySql, 0, sizeof(m_mySql)); } } bool CMySqlDB::Connect( const char *host, const char *user, const char *pass, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) { if(!Init()) return false; return !!mysql_real_connect(&m_mySql, host, user, pass, db, port, unix_socket, client_flag); } int CMySqlDB::SetCharSet(const char *pszCharset) { return !mysql_set_character_set(&m_mySql, pszCharset); } int CMySqlDB::Options(enum mysql_option option, const void *arg) { return !mysql_options(&m_mySql, option, arg); } CMySqlResult CMySqlDB::Query(const char *sql) { bool bErr = true; MYSQL_RES *pRes = NULL; if(m_fIsInit) { if(!(bErr = !!mysql_query(&m_mySql, sql))) pRes = mysql_store_result(&m_mySql); } return CMySqlResult(pRes, bErr); } int CMySqlDB::SelectDB(const char *db) { return mysql_select_db(&m_mySql, db); } std::string CMySqlDB::EscapeStringQuote(const char *from, char quote) { if( m_fIsInit && from && *from) { size_t len = strlen(from); size_t lenBuf = len * 2 + 1; char *buf = (char*)alloca(lenBuf); #if MYSQL_VERSION_ID >= 50706 if(mysql_real_escape_string_quote(&m_mySql, buf, from, (unsigned long)len, quote)) #else // MYSQL_VERSION_ID (void)quote; if(mysql_real_escape_string(&m_mySql, buf, from, (unsigned long)len)) #endif // MYSQL_VERSION_ID return buf; } return ""; } std::string CMySqlDB::EscapeString(const char *from) { if( m_fIsInit && from && *from) { size_t len = strlen(from); size_t lenBuf = len * 2 + 1; char *buf = (char*)alloca(lenBuf); if(mysql_real_escape_string(&m_mySql, buf, from, (unsigned long)len)) return buf; } return ""; } std::string CMySqlDB::LastError(void) { if(m_fIsInit) return mysql_error(&m_mySql); else return "MySQL not initialized!"; } unsigned int CMySqlDB::LastErrno(void) { if(m_fIsInit) return mysql_errno(&m_mySql); else return -1; } ///////////////////////////////////////////////////////////////////////////// CMySqlResult::CMySqlResult(MYSQL_RES *pRes, bool err) : m_pRes(pRes), m_bError(err) { } CMySqlResult::~CMySqlResult(void) { Free(); } void CMySqlResult::Free(void) { if(m_pRes) { mysql_free_result(m_pRes); m_pRes = NULL; } } my_ulonglong CMySqlResult::RowCount(void) const { if(m_pRes) return mysql_num_rows(m_pRes); return 0; } unsigned int CMySqlResult::FieldCount(void) const { if(m_pRes) return mysql_num_fields(m_pRes); return 0; } MYSQL_ROW CMySqlResult::FetchRow(void) { if(m_pRes) return mysql_fetch_row(m_pRes); return NULL; } bool CMySqlResult::FetchRow(CMySqlRow &row) const { if(m_pRes) { MYSQL_ROW pRow = mysql_fetch_row(m_pRes); if(pRow) return row.Create(FieldCount(), FetchFields(), pRow); } return false; } const MYSQL_FIELD * CMySqlResult::FetchFields(void) const { if(m_pRes) return mysql_fetch_fields(m_pRes); return NULL; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// const CMySqlVar CMySqlRow::m_vNul; CMySqlRow::CMySqlRow(void) : m_bValid(false), m_nFieldCount(0) { } CMySqlRow::~CMySqlRow(void) { } void CMySqlRow::Clear(void) { m_bValid = false; m_nFieldCount = 0; m_fields.clear(); } bool CMySqlRow::Create(unsigned int nFieldCount, const MYSQL_FIELD *pFields, MYSQL_ROW pRow) { Clear(); if((nFieldCount > 0) && pFields && pRow) { for(m_nFieldCount = 0; m_nFieldCount < nFieldCount; ++m_nFieldCount) { std::string s(pFields[m_nFieldCount].name); if(!m_fields.emplace(s, std::move(CMySqlVar(pFields[m_nFieldCount], pRow[m_nFieldCount]))).second) { Clear(); return false; } } m_bValid = true; } return m_bValid; } const CMySqlVar& CMySqlRow::Value(const char *pszFieldname) const { if(m_bValid) { CMySqlFieldMap::const_iterator it; if(FindField(pszFieldname, it)) return it->second; } return m_vNul; } CMySqlRow::CMySqlFieldMap::const_iterator CMySqlRow::begin(void) { return m_fields.begin(); } CMySqlRow::CMySqlFieldMap::const_iterator CMySqlRow::end(void) { return m_fields.end(); } bool CMySqlRow::FindField(const char *pszFieldname, CMySqlFieldMap::const_iterator &it) const { if(m_bValid) { it = m_fields.find(pszFieldname); return (it != m_fields.end()); } return false; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// CMySqlVar::CMySqlVar(void) { Clear(); } CMySqlVar::CMySqlVar(const MYSQL_FIELD &rField, const char *pszVal) { FromField(rField, pszVal); } CMySqlVar::CMySqlVar(CMySqlVar &&o) : m_bValid(std::move(o.m_bValid)), m_bInteger(std::move(o.m_bInteger)), m_bReal(std::move(o.m_bReal)), m_bUnsigned(std::move(o.m_bUnsigned)), m_bString(std::move(o.m_bString)), m_strVal(std::move(o.m_strVal)), m_strFieldname(std::move(o.m_strFieldname)), m_sqlFt(std::move(o.m_sqlFt)), m_numVal(std::move(o.m_numVal)) { if(this != &o) o.Clear(); } CMySqlVar::~CMySqlVar(void) { } void CMySqlVar::Clear(void) { m_bValid = false; m_bUnsigned = false; m_bInteger = false; m_bReal = false; m_bString = false; m_strFieldname.clear(); m_strVal.clear(); m_sqlFt = MYSQL_TYPE_NULL; m_numVal.uVal = 0; } bool CMySqlVar::FromField(const MYSQL_FIELD &rField, const char *pszVal) { Clear(); if(pszVal) { char *pszEndPtr; bool bUnsigned = !!(rField.flags & UNSIGNED_FLAG); m_strFieldname = rField.name; switch(rField.type) { case MYSQL_TYPE_BIT: case MYSQL_TYPE_TINY: // 8 Bit => 8 Bit case MYSQL_TYPE_SHORT: // 16 Bit => 16 Bit case MYSQL_TYPE_INT24: // 24 Bit => 32 Bit case MYSQL_TYPE_LONG: // 32 Bit => 32 Bit case MYSQL_TYPE_LONGLONG: // 64 Bit => 64 Bit if(bUnsigned) { int64_t val = strtoll(pszVal, &pszEndPtr, 10); if(!*pszVal || ((val == LLONG_MIN || val == LLONG_MAX) && errno == ERANGE) || *pszEndPtr) m_bValid = false; else { m_sqlFt = rField.type; m_strVal = pszVal; m_numVal.iVal = val; m_bUnsigned = true; m_bInteger = true; m_bValid = true; } } else { uint64_t val = strtoull(pszVal, &pszEndPtr, 10); if(!*pszVal || (val == ULLONG_MAX && errno == ERANGE) || *pszEndPtr) m_bValid = false; else { m_sqlFt = rField.type; m_strVal = pszVal; m_numVal.uVal = val; m_bInteger = true; m_bValid = true; } } break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: { double val = strtod(pszVal, &pszEndPtr); if(!*pszVal || ((val == HUGE_VAL || val == -HUGE_VAL) && errno == ERANGE) || *pszEndPtr) m_bValid = false; else { m_sqlFt = rField.type; m_strVal = pszVal; m_numVal.fVal = val; m_bReal = true; m_bValid = true; } } break; case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: m_sqlFt = rField.type; m_strVal = pszVal; m_bString = true; m_bValid = true; break; case MYSQL_TYPE_DATE: case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIMESTAMP: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_YEAR: case MYSQL_TYPE_NEWDATE: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_GEOMETRY: break; case MYSQL_TYPE_NULL: m_sqlFt = rField.type; m_strVal = ""; m_bValid = true; break; default: break; } } return m_bValid; }