mysqlwrap.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <limits.h>
  5. #include <utility>
  6. #include <math.h>
  7. #include "mysqlwrap.h"
  8. CMySqlDB::CMySqlDB(void) : m_fIsInit(false)
  9. {
  10. memset(&m_mySql, 0, sizeof(m_mySql));
  11. Init();
  12. }
  13. CMySqlDB::~CMySqlDB(void)
  14. {
  15. Close();
  16. }
  17. bool CMySqlDB::Init(void) throw()
  18. {
  19. if(!m_fIsInit)
  20. m_fIsInit = !!mysql_init(&m_mySql);
  21. return m_fIsInit;
  22. }
  23. void CMySqlDB::Close(void) throw()
  24. {
  25. if(m_fIsInit)
  26. {
  27. mysql_close(&m_mySql);
  28. m_fIsInit = false;
  29. memset(&m_mySql, 0, sizeof(m_mySql));
  30. }
  31. }
  32. bool CMySqlDB::Connect( const char *host,
  33. const char *user,
  34. const char *pass,
  35. const char *db,
  36. unsigned int port,
  37. const char *unix_socket,
  38. unsigned long client_flag)
  39. {
  40. if(!Init())
  41. return false;
  42. return !!mysql_real_connect(&m_mySql, host, user, pass, db, port, unix_socket, client_flag);
  43. }
  44. int CMySqlDB::SetCharSet(const char *pszCharset)
  45. {
  46. return !mysql_set_character_set(&m_mySql, pszCharset);
  47. }
  48. int CMySqlDB::Options(enum mysql_option option, const void *arg)
  49. {
  50. return !mysql_options(&m_mySql, option, arg);
  51. }
  52. CMySqlResult CMySqlDB::Query(const char *sql)
  53. {
  54. bool bErr = true;
  55. MYSQL_RES *pRes = NULL;
  56. if(m_fIsInit)
  57. {
  58. if(!(bErr = !!mysql_query(&m_mySql, sql)))
  59. pRes = mysql_store_result(&m_mySql);
  60. }
  61. return CMySqlResult(pRes, bErr);
  62. }
  63. int CMySqlDB::SelectDB(const char *db)
  64. {
  65. return mysql_select_db(&m_mySql, db);
  66. }
  67. std::string CMySqlDB::EscapeStringQuote(const char *from, char quote)
  68. {
  69. if( m_fIsInit &&
  70. from && *from)
  71. {
  72. size_t len = strlen(from);
  73. size_t lenBuf = len * 2 + 1;
  74. char *buf = (char*)alloca(lenBuf);
  75. #if MYSQL_VERSION_ID >= 50706
  76. if(mysql_real_escape_string_quote(&m_mySql, buf, from, (unsigned long)len, quote))
  77. #else // MYSQL_VERSION_ID
  78. (void)quote;
  79. if(mysql_real_escape_string(&m_mySql, buf, from, (unsigned long)len))
  80. #endif // MYSQL_VERSION_ID
  81. return buf;
  82. }
  83. return "";
  84. }
  85. std::string CMySqlDB::EscapeString(const char *from)
  86. {
  87. if( m_fIsInit &&
  88. from && *from)
  89. {
  90. size_t len = strlen(from);
  91. size_t lenBuf = len * 2 + 1;
  92. char *buf = (char*)alloca(lenBuf);
  93. if(mysql_real_escape_string(&m_mySql, buf, from, (unsigned long)len))
  94. return buf;
  95. }
  96. return "";
  97. }
  98. std::string CMySqlDB::LastError(void)
  99. {
  100. if(m_fIsInit)
  101. return mysql_error(&m_mySql);
  102. else
  103. return "MySQL not initialized!";
  104. }
  105. unsigned int CMySqlDB::LastErrno(void)
  106. {
  107. if(m_fIsInit)
  108. return mysql_errno(&m_mySql);
  109. else
  110. return -1;
  111. }
  112. /////////////////////////////////////////////////////////////////////////////
  113. CMySqlResult::CMySqlResult(MYSQL_RES *pRes, bool err) : m_pRes(pRes),
  114. m_bError(err)
  115. {
  116. }
  117. CMySqlResult::~CMySqlResult(void)
  118. {
  119. Free();
  120. }
  121. void CMySqlResult::Free(void)
  122. {
  123. if(m_pRes)
  124. {
  125. mysql_free_result(m_pRes);
  126. m_pRes = NULL;
  127. }
  128. }
  129. my_ulonglong CMySqlResult::RowCount(void) const
  130. {
  131. if(m_pRes)
  132. return mysql_num_rows(m_pRes);
  133. return 0;
  134. }
  135. unsigned int CMySqlResult::FieldCount(void) const
  136. {
  137. if(m_pRes)
  138. return mysql_num_fields(m_pRes);
  139. return 0;
  140. }
  141. MYSQL_ROW CMySqlResult::FetchRow(void)
  142. {
  143. if(m_pRes)
  144. return mysql_fetch_row(m_pRes);
  145. return NULL;
  146. }
  147. bool CMySqlResult::FetchRow(CMySqlRow &row) const
  148. {
  149. if(m_pRes)
  150. {
  151. MYSQL_ROW pRow = mysql_fetch_row(m_pRes);
  152. if(pRow)
  153. return row.Create(FieldCount(), FetchFields(), pRow);
  154. }
  155. return false;
  156. }
  157. const MYSQL_FIELD * CMySqlResult::FetchFields(void) const
  158. {
  159. if(m_pRes)
  160. return mysql_fetch_fields(m_pRes);
  161. return NULL;
  162. }
  163. /////////////////////////////////////////////////////////////////////////////
  164. /////////////////////////////////////////////////////////////////////////////
  165. /////////////////////////////////////////////////////////////////////////////
  166. const CMySqlVar CMySqlRow::m_vNul;
  167. CMySqlRow::CMySqlRow(void) : m_bValid(false), m_nFieldCount(0)
  168. {
  169. }
  170. CMySqlRow::~CMySqlRow(void)
  171. {
  172. }
  173. void CMySqlRow::Clear(void)
  174. {
  175. m_bValid = false;
  176. m_nFieldCount = 0;
  177. m_fields.clear();
  178. }
  179. bool CMySqlRow::Create(unsigned int nFieldCount, const MYSQL_FIELD *pFields, MYSQL_ROW pRow)
  180. {
  181. Clear();
  182. if((nFieldCount > 0) && pFields && pRow)
  183. {
  184. for(m_nFieldCount = 0; m_nFieldCount < nFieldCount; ++m_nFieldCount)
  185. {
  186. std::string s(pFields[m_nFieldCount].name);
  187. if(!m_fields.emplace(s, std::move(CMySqlVar(pFields[m_nFieldCount], pRow[m_nFieldCount]))).second)
  188. {
  189. Clear();
  190. return false;
  191. }
  192. }
  193. m_bValid = true;
  194. }
  195. return m_bValid;
  196. }
  197. const CMySqlVar& CMySqlRow::Value(const char *pszFieldname) const
  198. {
  199. if(m_bValid)
  200. {
  201. CMySqlFieldMap::const_iterator it;
  202. if(FindField(pszFieldname, it))
  203. return it->second;
  204. }
  205. return m_vNul;
  206. }
  207. CMySqlRow::CMySqlFieldMap::const_iterator CMySqlRow::begin(void)
  208. {
  209. return m_fields.begin();
  210. }
  211. CMySqlRow::CMySqlFieldMap::const_iterator CMySqlRow::end(void)
  212. {
  213. return m_fields.end();
  214. }
  215. bool CMySqlRow::FindField(const char *pszFieldname, CMySqlFieldMap::const_iterator &it) const
  216. {
  217. if(m_bValid)
  218. {
  219. it = m_fields.find(pszFieldname);
  220. return (it != m_fields.end());
  221. }
  222. return false;
  223. }
  224. /////////////////////////////////////////////////////////////////////////////
  225. /////////////////////////////////////////////////////////////////////////////
  226. /////////////////////////////////////////////////////////////////////////////
  227. CMySqlVar::CMySqlVar(void)
  228. {
  229. Clear();
  230. }
  231. CMySqlVar::CMySqlVar(const MYSQL_FIELD &rField, const char *pszVal)
  232. {
  233. FromField(rField, pszVal);
  234. }
  235. 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)),
  236. 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))
  237. {
  238. if(this != &o)
  239. o.Clear();
  240. }
  241. CMySqlVar::CMySqlVar(const CMySqlVar &o) : m_bValid(o.m_bValid), m_bInteger(o.m_bInteger), m_bReal(o.m_bReal), m_bUnsigned(o.m_bUnsigned), m_bString(o.m_bString),
  242. m_strVal(o.m_strVal), m_strFieldname(o.m_strFieldname), m_sqlFt(o.m_sqlFt), m_numVal(o.m_numVal)
  243. {
  244. }
  245. CMySqlVar::~CMySqlVar(void)
  246. {
  247. }
  248. void CMySqlVar::Clear(void)
  249. {
  250. m_bValid = false;
  251. m_bUnsigned = false;
  252. m_bInteger = false;
  253. m_bReal = false;
  254. m_bString = false;
  255. m_strFieldname.clear();
  256. m_strVal.clear();
  257. m_sqlFt = MYSQL_TYPE_NULL;
  258. m_numVal.uVal = 0;
  259. }
  260. bool CMySqlVar::FromField(const MYSQL_FIELD &rField, const char *pszVal)
  261. {
  262. Clear();
  263. if(pszVal)
  264. {
  265. char *pszEndPtr;
  266. bool bUnsigned = !!(rField.flags & UNSIGNED_FLAG);
  267. m_strFieldname = rField.name;
  268. switch(rField.type)
  269. {
  270. case MYSQL_TYPE_BIT:
  271. case MYSQL_TYPE_TINY: // 8 Bit => 8 Bit
  272. case MYSQL_TYPE_SHORT: // 16 Bit => 16 Bit
  273. case MYSQL_TYPE_INT24: // 24 Bit => 32 Bit
  274. case MYSQL_TYPE_LONG: // 32 Bit => 32 Bit
  275. case MYSQL_TYPE_LONGLONG: // 64 Bit => 64 Bit
  276. if(bUnsigned)
  277. {
  278. int64_t val = strtoll(pszVal, &pszEndPtr, 10);
  279. if(!*pszVal || ((val == LLONG_MIN || val == LLONG_MAX) && errno == ERANGE) || *pszEndPtr)
  280. m_bValid = false;
  281. else
  282. {
  283. m_sqlFt = rField.type;
  284. m_strVal = pszVal;
  285. m_numVal.iVal = val;
  286. m_bUnsigned = true;
  287. m_bInteger = true;
  288. m_bValid = true;
  289. }
  290. }
  291. else
  292. {
  293. uint64_t val = strtoull(pszVal, &pszEndPtr, 10);
  294. if(!*pszVal || (val == ULLONG_MAX && errno == ERANGE) || *pszEndPtr)
  295. m_bValid = false;
  296. else
  297. {
  298. m_sqlFt = rField.type;
  299. m_strVal = pszVal;
  300. m_numVal.uVal = val;
  301. m_bInteger = true;
  302. m_bValid = true;
  303. }
  304. }
  305. break;
  306. case MYSQL_TYPE_FLOAT:
  307. case MYSQL_TYPE_DOUBLE:
  308. case MYSQL_TYPE_DECIMAL:
  309. case MYSQL_TYPE_NEWDECIMAL:
  310. {
  311. double val = strtod(pszVal, &pszEndPtr);
  312. if(!*pszVal || ((val == HUGE_VAL || val == -HUGE_VAL) && errno == ERANGE) || *pszEndPtr)
  313. m_bValid = false;
  314. else
  315. {
  316. m_sqlFt = rField.type;
  317. m_strVal = pszVal;
  318. m_numVal.fVal = val;
  319. m_bReal = true;
  320. m_bValid = true;
  321. }
  322. }
  323. break;
  324. case MYSQL_TYPE_VARCHAR:
  325. case MYSQL_TYPE_VAR_STRING:
  326. case MYSQL_TYPE_STRING:
  327. m_sqlFt = rField.type;
  328. m_strVal = pszVal;
  329. m_bString = true;
  330. m_bValid = true;
  331. break;
  332. case MYSQL_TYPE_DATE:
  333. case MYSQL_TYPE_TIME:
  334. case MYSQL_TYPE_DATETIME:
  335. m_sqlFt = rField.type;
  336. m_strVal = pszVal;
  337. m_bValid = true;
  338. break;
  339. case MYSQL_TYPE_TIMESTAMP:
  340. case MYSQL_TYPE_YEAR:
  341. case MYSQL_TYPE_NEWDATE:
  342. case MYSQL_TYPE_ENUM:
  343. case MYSQL_TYPE_SET:
  344. case MYSQL_TYPE_TINY_BLOB:
  345. case MYSQL_TYPE_MEDIUM_BLOB:
  346. case MYSQL_TYPE_LONG_BLOB:
  347. case MYSQL_TYPE_BLOB:
  348. case MYSQL_TYPE_GEOMETRY:
  349. break;
  350. case MYSQL_TYPE_NULL:
  351. m_sqlFt = rField.type;
  352. m_strVal = "";
  353. m_bValid = true;
  354. break;
  355. default:
  356. break;
  357. }
  358. }
  359. return m_bValid;
  360. }