PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/src/libs/storage/db_mysql.c

http://bsp2.googlecode.com/
C | 461 lines | 326 code | 82 blank | 53 comment | 78 complexity | 89c1e5e6790bb141f396e343d4e3df80 MD5 | raw file
Possible License(s): GPL-3.0
  1. /*
  2. * db_mysql.c
  3. *
  4. * Copyright (C) 2011 - Dr.NP
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * @version db_mysql.c 1.0
  21. * @package storage
  22. * @author Dr.NP <np@bsgroup.org>
  23. * @update 08/17/2011
  24. */
  25. /**
  26. * MySQL database operator
  27. *
  28. * === CHANGELOG ===
  29. * [08/17/2011] - Creation
  30. */
  31. #include "bsp.h"
  32. #include "bsp_conf.h"
  33. #include "bsp_hash.h"
  34. #include "bsp_object.h"
  35. #include "bsp_utils.h"
  36. #include "bsp_db_mysql.h"
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <unistd.h>
  40. #include <string.h>
  41. #include <err.h>
  42. #include <sys/types.h>
  43. #include "mysql.h"
  44. #include "errmsg.h"
  45. struct mysql_conn *mysql_conn_list;
  46. size_t mysql_conn_list_size;
  47. int db_mysql_init()
  48. {
  49. mysql_conn_list = ensure_list_space(NULL, sizeof(struct mysql_conn), &mysql_conn_list_size, MYSQL_CONN_LIST_INITIAL);
  50. if (!mysql_conn_list)
  51. {
  52. err(RTN_ERROR_MEMORY_ALLOC, "MySQL connection list initial error!!!");
  53. }
  54. memset(mysql_conn_list, 0, sizeof(struct mysql_conn) * mysql_conn_list_size);
  55. debug_info("Storage :: MySQL initialized\n");
  56. return RTN_SUCCESS;
  57. }
  58. int db_mysql_connect(
  59. const char *host,
  60. const char *user,
  61. const char *pass,
  62. const char *db,
  63. int max_active_results
  64. )
  65. {
  66. // Caculate the hash value
  67. char srv_sig[4096];
  68. snprintf(srv_sig,
  69. 4095,
  70. "%s:%s@%s/%s#%d",
  71. user ? user : "",
  72. pass ? pass : "",
  73. host ? host : "",
  74. db ? db : "",
  75. max_active_results);
  76. u_int32_t srv_hash = hash(srv_sig, strlen(srv_sig));
  77. // Find available connection
  78. struct mysql_conn *curr = NULL;
  79. int i;
  80. for (i = 0; i < mysql_conn_list_size; i ++)
  81. {
  82. if ((!mysql_conn_list[i].mask & CONN_MASK_IN_USE) && mysql_conn_list[i].srv_hash == srv_hash)
  83. {
  84. // Available connection
  85. curr = &mysql_conn_list[i];
  86. curr->mask |= CONN_MASK_IN_USE;
  87. return curr->id;
  88. }
  89. }
  90. // Make a new one?
  91. for (i = 0; i < mysql_conn_list_size; i ++)
  92. {
  93. if (!mysql_conn_list[i].srv_hash && !mysql_conn_list[i].mask)
  94. {
  95. // An empty slot
  96. curr = &mysql_conn_list[i];
  97. curr->id = i;
  98. break;
  99. }
  100. }
  101. if (!curr)
  102. {
  103. // Enlarge conn list
  104. mysql_conn_list = ensure_list_space(mysql_conn_list, sizeof(struct mysql_conn), &mysql_conn_list_size, mysql_conn_list_size * 2);
  105. if (!mysql_conn_list)
  106. {
  107. err(RTN_ERROR_MEMORY_ALLOC, "MySQL connection list initial error!!!");
  108. }
  109. i = (mysql_conn_list_size / 2);
  110. memset(mysql_conn_list + i * sizeof(struct mysql_conn), 0, sizeof(struct mysql_conn));
  111. curr = &mysql_conn_list[i];
  112. curr->id = i;
  113. }
  114. const char *conn_host = (const char *) NULL;
  115. const char *conn_sock = (const char *) NULL;
  116. const char *conn_user = user ? user : "";
  117. // For the password, a value of the empty string in the mysql_real_connect()
  118. // call cannot be overridden in an option file, because the empty string indicates
  119. // explicitly that the MySQL account must have an empty password.
  120. const char *conn_pass = pass ? pass : (const char *) NULL;
  121. const char *conn_db = db ? db : (const char *) NULL;
  122. // If "host" is a local sock pipe?
  123. FILE *tfp = fopen(host, "r");
  124. if (tfp)
  125. {
  126. // Local sock file
  127. conn_sock = host;
  128. fclose(tfp);
  129. }
  130. else
  131. {
  132. conn_host = host;
  133. }
  134. curr->conn = mysql_init(NULL);
  135. if (!mysql_real_connect(curr->conn,
  136. conn_host,
  137. conn_user,
  138. conn_pass,
  139. conn_db,
  140. 0,
  141. conn_sock,
  142. 0))
  143. {
  144. return RTN_ERROR_DB_CONNECTION;
  145. }
  146. my_bool my_true = 0x1;
  147. mysql_options(curr->conn, MYSQL_OPT_RECONNECT, &my_true);
  148. // Set default charset
  149. mysql_query(curr->conn, "SET NAMES 'utf8'");
  150. // Set default database
  151. if (conn_db)
  152. {
  153. mysql_select_db(curr->conn, conn_db);
  154. }
  155. // Set hash
  156. curr->srv_hash = srv_hash;
  157. // Set mask
  158. curr->mask |= CONN_MASK_IN_USE;
  159. if (db && strlen(db))
  160. {
  161. curr->mask |= CONN_MASK_DB_SET;
  162. }
  163. curr->result_list_size = max_active_results;
  164. if (curr->result_list)
  165. {
  166. db_mysql_free_results(curr->id);
  167. free(curr->result_list);
  168. }
  169. curr->result_list = ensure_list_space(NULL, sizeof(MYSQL_RES *), NULL, max_active_results);
  170. memset(curr->result_list, 0, sizeof(MYSQL_RES *) * max_active_results);
  171. return curr->id;
  172. }
  173. int db_mysql_close(int conn_id)
  174. {
  175. struct mysql_conn *curr = NULL;
  176. if (conn_id >= 0 && conn_id < mysql_conn_list_size)
  177. {
  178. curr = &mysql_conn_list[conn_id];
  179. }
  180. if (curr && curr->conn)
  181. {
  182. db_mysql_free_results(curr->id);
  183. mysql_close(curr->conn);
  184. curr->mask &= ~CONN_MASK_IN_USE;
  185. }
  186. return RTN_SUCCESS;
  187. }
  188. int db_mysql_query(int conn_id, const char *query, size_t stmt_len)
  189. {
  190. struct mysql_conn *curr = NULL;
  191. int res, i;
  192. if (conn_id >= 0 && conn_id < mysql_conn_list_size)
  193. {
  194. curr = &mysql_conn_list[conn_id];
  195. }
  196. if (curr && curr->conn && curr->mask & CONN_MASK_IN_USE)
  197. {
  198. if ((signed) stmt_len < 0)
  199. {
  200. stmt_len = strlen(query);
  201. }
  202. res = mysql_real_query(curr->conn, query, stmt_len);
  203. if (0 == res)
  204. {
  205. // Query succssfully
  206. curr->queries ++;
  207. MYSQL_RES *qres = mysql_store_result(curr->conn);
  208. int res_id = -1;
  209. if (qres)
  210. {
  211. // SELECT / SHOW / DESCRIBE / EXPLAIN / CHECK TABLE ...
  212. // A result set returned, and stored into object
  213. // Find a empty result slot
  214. for (i = 0; i < curr->result_list_size; i ++)
  215. {
  216. if (!curr->result_list[i])
  217. {
  218. curr->result_list[i] = qres;
  219. res_id = i;
  220. return res_id;
  221. }
  222. }
  223. if (res_id < 0)
  224. {
  225. // Result list full, you have to free some used result first!!!
  226. return RTN_ERROR_DB_RESULT_FULL;
  227. }
  228. }
  229. else
  230. {
  231. // Statement didn't return a result set
  232. }
  233. return RTN_SUCCESS;
  234. }
  235. else if (CR_SERVER_GONE_ERROR == res || CR_SERVER_LOST == res)
  236. {
  237. // MySQL gone
  238. db_mysql_close(curr->id);
  239. return RTN_ERROR_DB_CONNECTION;
  240. }
  241. else
  242. {
  243. return RTN_ERROR_DB_UNKNOWN;
  244. }
  245. }
  246. else
  247. {
  248. res = RTN_ERROR_DB_UNAVAILABLE;
  249. }
  250. return res;
  251. }
  252. const char * db_mysql_error(int conn_id)
  253. {
  254. struct mysql_conn *curr = NULL;
  255. if (conn_id >= 0 && conn_id < mysql_conn_list_size)
  256. {
  257. curr = &mysql_conn_list[conn_id];
  258. }
  259. if (curr && curr->conn && curr->mask & CONN_MASK_IN_USE)
  260. {
  261. return mysql_error(curr->conn);
  262. }
  263. return "";
  264. }
  265. int db_mysql_free_result(int conn_id, int res_id)
  266. {
  267. struct mysql_conn *curr = NULL;
  268. if (conn_id >= 0 && conn_id < mysql_conn_list_size)
  269. {
  270. curr = &mysql_conn_list[conn_id];
  271. }
  272. else
  273. {
  274. return RTN_ERROR_DB_UNAVAILABLE;
  275. }
  276. if (curr && curr->conn && curr->result_list && res_id >= 0 && res_id < curr->result_list_size)
  277. {
  278. if (curr->result_list[res_id])
  279. {
  280. mysql_free_result(curr->result_list[res_id]);
  281. curr->result_list[res_id] = NULL;
  282. }
  283. }
  284. else
  285. {
  286. return RTN_ERROR_DB_INVALID_RESULT;
  287. }
  288. return RTN_SUCCESS;
  289. }
  290. int db_mysql_free_results(int conn_id)
  291. {
  292. struct mysql_conn *curr = NULL;
  293. if (conn_id >= 0 && conn_id < mysql_conn_list_size)
  294. {
  295. curr = &mysql_conn_list[conn_id];
  296. }
  297. else
  298. {
  299. return RTN_ERROR_DB_UNAVAILABLE;
  300. }
  301. if (curr && curr->conn && curr->result_list)
  302. {
  303. int i;
  304. for (i = 0; i < curr->result_list_size; i ++)
  305. {
  306. if (curr->result_list[i])
  307. {
  308. mysql_free_result(curr->result_list[i]);
  309. curr->result_list[i] = NULL;
  310. }
  311. }
  312. }
  313. return RTN_SUCCESS;
  314. }
  315. u_int64_t db_mysql_num_rows(int conn_id, int res_id)
  316. {
  317. struct mysql_conn *curr = NULL;
  318. u_int64_t rows = 0;
  319. if (conn_id >= 0 && conn_id < mysql_conn_list_size)
  320. {
  321. curr = &mysql_conn_list[conn_id];
  322. }
  323. else
  324. {
  325. return RTN_ERROR_DB_UNAVAILABLE;
  326. }
  327. if (curr && curr->conn && curr->result_list && res_id >= 0 && res_id < curr->result_list_size)
  328. {
  329. if (curr->result_list[res_id])
  330. {
  331. rows = mysql_num_rows(curr->result_list[res_id]);
  332. }
  333. }
  334. return rows;
  335. }
  336. int db_mysql_fetch_row(int conn_id, int res_id, struct object_t *obj)
  337. {
  338. struct mysql_conn *curr = NULL;
  339. struct kv_t *item;
  340. MYSQL_ROW row;
  341. MYSQL_FIELD *fields;
  342. unsigned long *lengths;
  343. u_int32_t num_fields;
  344. int i;
  345. if (!obj)
  346. {
  347. return RTN_ERROR_MEMORY_OBJECT;
  348. }
  349. if (conn_id >= 0 && conn_id < mysql_conn_list_size)
  350. {
  351. curr = &mysql_conn_list[conn_id];
  352. }
  353. else
  354. {
  355. return RTN_ERROR_DB_UNAVAILABLE;
  356. }
  357. if (curr && curr->conn && curr->result_list && res_id >= 0 && res_id < curr->result_list_size)
  358. {
  359. if (curr->result_list[res_id])
  360. {
  361. row = mysql_fetch_row(curr->result_list[res_id]);
  362. fields = mysql_fetch_fields(curr->result_list[res_id]);
  363. lengths = mysql_fetch_lengths(curr->result_list[res_id]);
  364. num_fields = mysql_num_fields(curr->result_list[res_id]);
  365. if (row && fields && lengths)
  366. {
  367. for (i = 0; i < num_fields; i ++)
  368. {
  369. // Store result
  370. item = alloc_item((const char *) fields[i].name, -1);
  371. set_string_item(item, (const char *) row[i], lengths[i]);
  372. insert_item(obj, item);
  373. }
  374. return num_fields;
  375. }
  376. }
  377. }
  378. return RTN_SUCCESS;
  379. }