PageRenderTime 26ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/boinc-6.12.38/db/db_base.cpp

https://github.com/matszpk/native-boinc-for-android
C++ | 500 lines | 367 code | 68 blank | 65 comment | 83 complexity | 3eda6a46102e4ceb5e3bc564bac2ab2e MD5 | raw file
  1. // This file is part of BOINC.
  2. // http://boinc.berkeley.edu
  3. // Copyright (C) 2008 University of California
  4. //
  5. // BOINC is free software; you can redistribute it and/or modify it
  6. // under the terms of the GNU Lesser General Public License
  7. // as published by the Free Software Foundation,
  8. // either version 3 of the License, or (at your option) any later version.
  9. //
  10. // BOINC is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. // See the GNU Lesser General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Lesser General Public License
  16. // along with BOINC. If not, see <http://www.gnu.org/licenses/>.
  17. #include "config.h"
  18. #include <cstdio>
  19. #include <cstring>
  20. #include <cstdlib>
  21. #include <mysql.h>
  22. #include "error_numbers.h"
  23. #include "str_util.h"
  24. #include "str_replace.h"
  25. #include "db_base.h"
  26. #ifdef _USING_FCGI_
  27. #include "fcgi_stdio.h"
  28. #include "sched_msgs.h"
  29. #endif
  30. bool g_print_queries = false;
  31. DB_CONN::DB_CONN() {
  32. mysql = 0;
  33. }
  34. int DB_CONN::open(char* db_name, char* db_host, char* db_user, char* dbpassword) {
  35. mysql = mysql_init(0);
  36. if (!mysql) return ERR_DB_CANT_INIT;
  37. // MySQL's support for the reconnect option has changed over time:
  38. // see http://dev.mysql.com/doc/refman/5.0/en/mysql-options.html
  39. // and http://dev.mysql.com/doc/refman/5.1/en/mysql-options.html
  40. //
  41. // v < 5.0.13: not supported
  42. // 5.0.13 <= v < 5.0.19: set option after real_connect()
  43. // 5.0.19 < v < 5.1: set option before real_connect();
  44. // 5.1.0 <= v < 5.1.6: set option after real_connect()
  45. // 5.1.6 <= v: set option before real_connect
  46. int v = MYSQL_VERSION_ID;
  47. bool set_opt_before = false, set_opt_after = false;
  48. if (v < 50013 ) {
  49. } else if (v < 50019) {
  50. set_opt_after = true;
  51. } else if (v < 50100) {
  52. set_opt_before = true;
  53. } else if (v < 50106) {
  54. set_opt_after = true;
  55. } else {
  56. set_opt_before = true;
  57. }
  58. if (set_opt_before) {
  59. my_bool mbReconnect = 1;
  60. mysql_options(mysql, MYSQL_OPT_RECONNECT, &mbReconnect);
  61. }
  62. // CLIENT_FOUND_ROWS means that the # of affected rows for an update
  63. // is the # matched by the where, rather than the # actually changed
  64. //
  65. mysql = mysql_real_connect(
  66. mysql, db_host, db_user, dbpassword, db_name, 0, 0, CLIENT_FOUND_ROWS
  67. );
  68. if (mysql == 0) return ERR_DB_CANT_CONNECT;
  69. if (set_opt_after) {
  70. my_bool mbReconnect = 1;
  71. mysql_options(mysql, MYSQL_OPT_RECONNECT, &mbReconnect);
  72. }
  73. return 0;
  74. }
  75. void DB_CONN::close() {
  76. if (mysql) mysql_close(mysql);
  77. }
  78. int DB_CONN::set_isolation_level(ISOLATION_LEVEL level) {
  79. const char* level_str;
  80. char query[256];
  81. switch(level) {
  82. case READ_UNCOMMITTED:
  83. level_str = "READ UNCOMMITTED";
  84. break;
  85. case READ_COMMITTED:
  86. level_str = "READ COMMITTED";
  87. break;
  88. case REPEATABLE_READ:
  89. level_str = "REPEATABLE READ";
  90. break;
  91. case SERIALIZABLE:
  92. level_str = "SERIALIZABLE";
  93. break;
  94. default:
  95. return -1;
  96. }
  97. sprintf(query, "SET SESSION TRANSACTION ISOLATION LEVEL %s", level_str);
  98. return do_query(query);
  99. }
  100. int DB_CONN::do_query(const char* p) {
  101. int retval;
  102. if (g_print_queries) {
  103. #ifdef _USING_FCGI_
  104. log_messages.printf(MSG_NORMAL, "query: %s\n", p);
  105. #else
  106. fprintf(stderr, "query: %s\n", p);
  107. #endif
  108. }
  109. retval = mysql_query(mysql, p);
  110. if (retval) {
  111. fprintf(stderr, "Database error: %s\nquery=%s\n", error_string(), p);
  112. }
  113. return retval;
  114. }
  115. // returns the number of rows matched by an update query
  116. //
  117. int DB_CONN::affected_rows() {
  118. unsigned long x = (unsigned long)mysql_affected_rows(mysql);
  119. //fprintf(stderr, "x: %lu i: %d\n", x, (int)x);
  120. return (int)x;
  121. }
  122. int DB_CONN::insert_id() {
  123. int retval;
  124. MYSQL_ROW row;
  125. MYSQL_RES* rp;
  126. retval = do_query("select LAST_INSERT_ID()");
  127. if (retval) return retval;
  128. rp = mysql_store_result(mysql);
  129. row = mysql_fetch_row(rp);
  130. int x = atoi(row[0]);
  131. mysql_free_result(rp);
  132. return x;
  133. }
  134. void DB_CONN::print_error(const char* p) {
  135. fprintf(stderr, "%s: Database error: %s\n", p, error_string());
  136. }
  137. const char* DB_CONN::error_string() {
  138. return mysql?mysql_error(mysql):"Not connected";
  139. }
  140. int DB_CONN::start_transaction() {
  141. return do_query("START TRANSACTION");
  142. }
  143. int DB_CONN::commit_transaction() {
  144. return do_query("COMMIT");
  145. }
  146. int DB_CONN::rollback_transaction() {
  147. return do_query("ROLLBACK");
  148. }
  149. int DB_CONN::ping() {
  150. int retval = mysql_ping(mysql);
  151. if (retval) return ERR_DB_CANT_CONNECT;
  152. return 0;
  153. }
  154. DB_BASE::DB_BASE(const char *tn, DB_CONN* p) : db(p), table_name(tn) {
  155. }
  156. int DB_BASE::get_id() { return 0;}
  157. void DB_BASE::db_print(char*) {}
  158. void DB_BASE::db_parse(MYSQL_ROW&) {}
  159. int DB_BASE::insert() {
  160. char vals[MAX_QUERY_LEN], query[MAX_QUERY_LEN];
  161. db_print(vals);
  162. sprintf(query, "insert into %s set %s", table_name, vals);
  163. return db->do_query(query);
  164. }
  165. int DB_BASE::insert_batch(std::string& values) {
  166. std::string query;
  167. query = "insert into " + std::string(table_name) + " values " + values;
  168. return db->do_query(query.c_str());
  169. }
  170. int DB_BASE::affected_rows() {
  171. return db->affected_rows();
  172. }
  173. //////////// FUNCTIONS FOR TABLES THAT HAVE AN ID FIELD ///////
  174. int DB_BASE::lookup_id(int id) {
  175. char query[MAX_QUERY_LEN];
  176. int retval;
  177. MYSQL_ROW row;
  178. MYSQL_RES* rp;
  179. sprintf(query, "select * from %s where id=%d", table_name, id);
  180. retval = db->do_query(query);
  181. if (retval) return retval;
  182. rp = mysql_store_result(db->mysql);
  183. if (!rp) return -1;
  184. row = mysql_fetch_row(rp);
  185. if (row) db_parse(row);
  186. mysql_free_result(rp);
  187. if (row == 0) return ERR_DB_NOT_FOUND;
  188. // don't bother checking for uniqueness here
  189. return 0;
  190. }
  191. // update an entire record
  192. //
  193. int DB_BASE::update() {
  194. char vals[MAX_QUERY_LEN], query[MAX_QUERY_LEN];
  195. db_print(vals);
  196. sprintf(query, "update %s set %s where id=%d", table_name, vals, get_id());
  197. int retval = db->do_query(query);
  198. if (retval) return retval;
  199. if (db->affected_rows() != 1) return ERR_DB_NOT_FOUND;
  200. return 0;
  201. }
  202. // update one or more fields
  203. // "clause" is something like "foo=5, blah='xxx'" or "foo=foo+5"
  204. //
  205. int DB_BASE::update_field(const char* clause, const char* where_clause) {
  206. char query[MAX_QUERY_LEN];
  207. if (where_clause) {
  208. sprintf(query, "update %s set %s where id=%d and %s", table_name, clause, get_id(), where_clause);
  209. } else {
  210. sprintf(query, "update %s set %s where id=%d", table_name, clause, get_id());
  211. }
  212. return db->do_query(query);
  213. }
  214. // delete record
  215. //
  216. int DB_BASE::delete_from_db() {
  217. char vals[MAX_QUERY_LEN], query[MAX_QUERY_LEN];
  218. db_print(vals);
  219. sprintf(query, "delete from %s where id=%d", table_name, get_id());
  220. return db->do_query(query);
  221. }
  222. int DB_BASE::get_field_int(const char* field, int& val) {
  223. char query[MAX_QUERY_LEN];
  224. int retval;
  225. MYSQL_ROW row;
  226. MYSQL_RES* rp;
  227. sprintf(query, "select %s from %s where id=%d", field, table_name, get_id());
  228. retval = db->do_query(query);
  229. if (retval) return retval;
  230. rp = mysql_store_result(db->mysql);
  231. if (!rp) return -1;
  232. row = mysql_fetch_row(rp);
  233. if (row) val = atoi(row[0]);
  234. mysql_free_result(rp);
  235. if (row == 0) return ERR_DB_NOT_FOUND;
  236. return 0;
  237. }
  238. int DB_BASE::get_field_str(const char* field, char* buf, int buflen) {
  239. char query[MAX_QUERY_LEN];
  240. int retval;
  241. MYSQL_ROW row;
  242. MYSQL_RES* rp;
  243. sprintf(query, "select %s from %s where id=%d", field, table_name, get_id());
  244. retval = db->do_query(query);
  245. if (retval) return retval;
  246. rp = mysql_store_result(db->mysql);
  247. if (!rp) return -1;
  248. row = mysql_fetch_row(rp);
  249. if (row && row[0]) {
  250. strlcpy(buf, row[0], buflen);
  251. }
  252. mysql_free_result(rp);
  253. if (row == 0) return ERR_DB_NOT_FOUND;
  254. return 0;
  255. }
  256. int DB_BASE::max_id(int& n, const char* clause) {
  257. char query[MAX_QUERY_LEN];
  258. sprintf(query, "select max(id) from %s %s", table_name, clause);
  259. return get_integer(query, n);
  260. }
  261. /////////////// FUNCTIONS THAT DON'T REQUIRE AN ID FIELD ///////////////
  262. int DB_BASE::lookup(const char* clause) {
  263. char query[MAX_QUERY_LEN];
  264. int retval;
  265. MYSQL_ROW row;
  266. MYSQL_RES* rp;
  267. sprintf(query, "select * from %s %s", table_name, clause);
  268. retval = db->do_query(query);
  269. if (retval) return retval;
  270. rp = mysql_store_result(db->mysql);
  271. if (!rp) return -1;
  272. row = mysql_fetch_row(rp);
  273. if (row) db_parse(row);
  274. mysql_free_result(rp);
  275. if (row == 0) return ERR_DB_NOT_FOUND;
  276. return 0;
  277. }
  278. int DB_BASE::update_fields_noid(char* set_clause, char* where_clause) {
  279. char query[MAX_QUERY_LEN];
  280. sprintf(query,
  281. "update %s set %s where %s",
  282. table_name, set_clause, where_clause
  283. );
  284. int retval = db->do_query(query);
  285. if (retval) return retval;
  286. if (db->affected_rows() != 1) return ERR_DB_NOT_FOUND;
  287. return 0;
  288. }
  289. int DB_BASE::enumerate(const char* clause, bool use_use_result) {
  290. int x;
  291. char query[MAX_QUERY_LEN];
  292. MYSQL_ROW row;
  293. if (!cursor.active) {
  294. cursor.active = true;
  295. sprintf(query, "select * from %s %s", table_name, clause);
  296. x = db->do_query(query);
  297. if (x) return mysql_errno(db->mysql);
  298. // if you use mysql_use_result() here,
  299. // any other transactions will fail
  300. //
  301. if (use_use_result) {
  302. cursor.rp = mysql_use_result(db->mysql);
  303. } else {
  304. cursor.rp = mysql_store_result(db->mysql);
  305. }
  306. if (!cursor.rp) return mysql_errno(db->mysql);
  307. }
  308. row = mysql_fetch_row(cursor.rp);
  309. if (!row) {
  310. mysql_free_result(cursor.rp);
  311. cursor.active = false;
  312. x = mysql_errno(db->mysql);
  313. if (x) return x;
  314. return ERR_DB_NOT_FOUND;
  315. } else {
  316. db_parse(row);
  317. }
  318. return 0;
  319. }
  320. // call this to end an enumeration before reaching end
  321. //
  322. int DB_BASE::end_enumerate() {
  323. if (cursor.active) {
  324. mysql_free_result(cursor.rp);
  325. cursor.active = false;
  326. }
  327. return 0;
  328. }
  329. int DB_BASE::get_integer(const char* query, int& n) {
  330. int retval;
  331. MYSQL_ROW row;
  332. MYSQL_RES* resp;
  333. retval = db->do_query(query);
  334. if (retval) return retval;
  335. resp = mysql_store_result(db->mysql);
  336. if (!resp) return ERR_DB_NOT_FOUND;
  337. row = mysql_fetch_row(resp);
  338. if (!row || !row[0]) {
  339. retval = ERR_DB_NOT_FOUND;
  340. } else {
  341. n = atoi(row[0]);
  342. }
  343. mysql_free_result(resp);
  344. return retval;
  345. }
  346. int DB_BASE::get_double(const char* query, double& x) {
  347. int retval;
  348. MYSQL_ROW row;
  349. MYSQL_RES* resp;
  350. retval = db->do_query(query);
  351. if (retval) return retval;
  352. resp = mysql_store_result(db->mysql);
  353. if (!resp) return ERR_DB_NOT_FOUND;
  354. row = mysql_fetch_row(resp);
  355. if (!row || !row[0]) {
  356. retval = ERR_DB_NOT_FOUND;
  357. } else {
  358. x = atof(row[0]);
  359. }
  360. mysql_free_result(resp);
  361. return retval;
  362. }
  363. int DB_BASE::count(int& n, const char* clause) {
  364. char query[MAX_QUERY_LEN];
  365. sprintf(query, "select count(*) from %s %s", table_name, clause);
  366. return get_integer(query, n);
  367. }
  368. int DB_BASE::sum(double& x, const char* field, const char* clause) {
  369. char query[MAX_QUERY_LEN];
  370. sprintf(query, "select sum(%s) from %s %s", field, table_name, clause);
  371. return get_double(query, x);
  372. }
  373. DB_BASE_SPECIAL::DB_BASE_SPECIAL(DB_CONN* p) : db(p) {
  374. }
  375. // convert a string into a form that allows it to be used
  376. // in SQL queries delimited by single quotes:
  377. // replace ' with \', '\' with '\\'
  378. //
  379. void escape_string(char* field, int len) {
  380. char buf[MAX_QUERY_LEN];
  381. char* q = buf, *p = field;
  382. // Make sure that final result won't overflow field[].
  383. // Don't need to worry about overflowing buf[] since
  384. // in worst case string length only doubles.
  385. //
  386. while (*p && q < buf+len-2) {
  387. if (*p == '\'') {
  388. // this does ' to \' transformation
  389. //
  390. *q++ = '\\';
  391. *q++ = '\'';
  392. } else if (*p == '\\') {
  393. // this does \ to \\ transformation
  394. //
  395. *q++ = '\\';
  396. *q++ = '\\';
  397. } else {
  398. // this handles all other characters
  399. //
  400. *q++ = *p;
  401. }
  402. p++;
  403. }
  404. *q = 0;
  405. strlcpy(field, buf, len);
  406. }
  407. // undo the above process
  408. // (len not used because this doesn't expand the string)
  409. //
  410. void unescape_string(char* p, int /*len*/) {
  411. char* q = p;
  412. while (*p) {
  413. if (*p == '\\') {
  414. p++;
  415. if (!*p) break; // SHOULD NEVER HAPPEN!
  416. }
  417. *q++ = *p++;
  418. }
  419. *q='\0';
  420. }
  421. // replace _ with \\_, % with \\%
  422. //
  423. void escape_mysql_like_pattern(const char* in, char* out) {
  424. while (*in) {
  425. if (*in == '_' || *in == '%') {
  426. *out++ = '\\';
  427. *out++ = '\\';
  428. }
  429. *out++ = *in++;
  430. }
  431. }
  432. const char *BOINC_RCSID_43d919556b = "$Id: db_base.cpp 21109 2010-04-05 23:12:02Z boincadm $";