my_cmd.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2001-2003 FhG Fokus
  5. * Copyright (C) 2006-2007 iptelorg GmbH
  6. *
  7. * This file is part of ser, a free SIP server.
  8. *
  9. * ser is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version
  13. *
  14. * For a license to use the ser software under conditions
  15. * other than those described here, or to purchase support for this
  16. * software, please contact iptel.org by e-mail at the following addresses:
  17. * [email protected]
  18. *
  19. * ser is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  27. */
  28. #define _XOPEN_SOURCE 4 /* bsd */
  29. #define _XOPEN_SOURCE_EXTENDED 1 /* solaris */
  30. #define _SVID_SOURCE 1 /* timegm */
  31. #include <strings.h>
  32. #include <stdio.h>
  33. #include <time.h> /*strptime, XOPEN issue must be >=4 */
  34. #include <string.h>
  35. #include "../../mem/mem.h"
  36. #include "../../str.h"
  37. #include "../../db/db_cmd.h"
  38. #include "../../ut.h"
  39. #include "my_con.h"
  40. #include "my_fld.h"
  41. #include "my_cmd.h"
  42. #define STR_BUF_SIZE 256
  43. enum {
  44. STR_DELETE,
  45. STR_INSERT,
  46. STR_UPDATE,
  47. STR_SELECT,
  48. STR_REPLACE,
  49. STR_WHERE,
  50. STR_IS,
  51. STR_AND,
  52. STR_OR,
  53. STR_ESC,
  54. STR_OP_EQ,
  55. STR_OP_LT,
  56. STR_OP_GT,
  57. STR_OP_LEQ,
  58. STR_OP_GEQ,
  59. STR_VALUES,
  60. STR_FROM
  61. };
  62. static str strings[] = {
  63. STR_STATIC_INIT("delete from "),
  64. STR_STATIC_INIT("insert into "),
  65. STR_STATIC_INIT("update "),
  66. STR_STATIC_INIT("select "),
  67. STR_STATIC_INIT("replace "),
  68. STR_STATIC_INIT(" where "),
  69. STR_STATIC_INIT(" is "),
  70. STR_STATIC_INIT(" and "),
  71. STR_STATIC_INIT(" or "),
  72. STR_STATIC_INIT("?"),
  73. STR_STATIC_INIT("="),
  74. STR_STATIC_INIT("<"),
  75. STR_STATIC_INIT(">"),
  76. STR_STATIC_INIT("<="),
  77. STR_STATIC_INIT(">="),
  78. STR_STATIC_INIT(") values ("),
  79. STR_STATIC_INIT(" from ")
  80. };
  81. #define APPEND_STR(p, str) do { \
  82. memcpy((p), (str).s, (str).len); \
  83. (p) += (str).len; \
  84. } while(0)
  85. #define APPEND_CSTR(p, cstr) do { \
  86. int _len = strlen(cstr); \
  87. memcpy((p), (cstr), _len); \
  88. (p) += _len; \
  89. } while(0)
  90. static int my_cmd_free(db_cmd_t* cmd, struct my_cmd* payload)
  91. {
  92. db_drv_free(&payload->gen);
  93. if (payload->query.s) pkg_free(payload->query.s);
  94. if (payload->st) mysql_stmt_close(payload->st);
  95. pkg_free(payload);
  96. }
  97. static int build_delete_query(str* query, db_cmd_t* cmd)
  98. {
  99. db_fld_t* fld;
  100. int i;
  101. char* p;
  102. query->len = strings[STR_DELETE].len;
  103. query->len += cmd->table.len;
  104. if (!DB_FLD_EMPTY(cmd->params)) {
  105. query->len += strings[STR_WHERE].len;
  106. for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
  107. query->len += strlen(fld[i].name);
  108. switch(fld[i].op) {
  109. case DB_EQ: query->len += strings[STR_OP_EQ].len; break;
  110. case DB_LT: query->len += strings[STR_OP_LT].len; break;
  111. case DB_GT: query->len += strings[STR_OP_GT].len; break;
  112. case DB_LEQ: query->len += strings[STR_OP_LEQ].len; break;
  113. case DB_GEQ: query->len += strings[STR_OP_GEQ].len; break;
  114. default:
  115. ERR("Unsupported db_fld operator %d\n", fld[i].op);
  116. return -1;
  117. }
  118. query->len += strings[STR_ESC].len;
  119. if (!DB_FLD_LAST(fld[i + 1])) query->len += strings[STR_AND].len;
  120. }
  121. }
  122. query->s = pkg_malloc(query->len + 1);
  123. if (query->s == NULL) {
  124. ERR("No memory left\n");
  125. return -1;
  126. }
  127. p = query->s;
  128. APPEND_STR(p, strings[STR_DELETE]);
  129. APPEND_STR(p, cmd->table);
  130. if (!DB_FLD_EMPTY(cmd->params)) {
  131. APPEND_STR(p, strings[STR_WHERE]);
  132. for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
  133. APPEND_CSTR(p, fld[i].name);
  134. switch(fld[i].op) {
  135. case DB_EQ: APPEND_STR(p, strings[STR_OP_EQ]); break;
  136. case DB_LT: APPEND_STR(p, strings[STR_OP_LT]); break;
  137. case DB_GT: APPEND_STR(p, strings[STR_OP_GT]); break;
  138. case DB_LEQ: APPEND_STR(p, strings[STR_OP_LEQ]); break;
  139. case DB_GEQ: APPEND_STR(p, strings[STR_OP_GEQ]); break;
  140. }
  141. APPEND_STR(p, strings[STR_ESC]);
  142. if (!DB_FLD_LAST(fld[i + 1])) APPEND_STR(p, strings[STR_AND]);
  143. }
  144. }
  145. *p = '\0';
  146. return 0;
  147. }
  148. static int build_select_query(str* query, db_cmd_t* cmd)
  149. {
  150. db_fld_t* fld;
  151. int i;
  152. char* p;
  153. query->len = strings[STR_SELECT].len;
  154. if (DB_FLD_EMPTY(cmd->result)) {
  155. query->len += 1; /* "*" */
  156. } else {
  157. for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
  158. query->len += strlen(fld[i].name);
  159. if (!DB_FLD_LAST(fld[i + 1])) query->len += 1; /* , */
  160. }
  161. }
  162. query->len += strings[STR_FROM].len;
  163. query->len += cmd->table.len;
  164. if (!DB_FLD_EMPTY(cmd->params)) {
  165. query->len += strings[STR_WHERE].len;
  166. for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
  167. query->len += strlen(fld[i].name);
  168. switch(fld[i].op) {
  169. case DB_EQ: query->len += strings[STR_OP_EQ].len; break;
  170. case DB_LT: query->len += strings[STR_OP_LT].len; break;
  171. case DB_GT: query->len += strings[STR_OP_GT].len; break;
  172. case DB_LEQ: query->len += strings[STR_OP_LEQ].len; break;
  173. case DB_GEQ: query->len += strings[STR_OP_GEQ].len; break;
  174. default:
  175. ERR("Unsupported db_fld operator %d\n", fld[i].op);
  176. return -1;
  177. }
  178. query->len += strings[STR_ESC].len;
  179. if (!DB_FLD_LAST(fld[i + 1])) query->len += strings[STR_AND].len;
  180. }
  181. }
  182. query->s = pkg_malloc(query->len + 1);
  183. if (query->s == NULL) {
  184. ERR("No memory left\n");
  185. return -1;
  186. }
  187. p = query->s;
  188. APPEND_STR(p, strings[STR_SELECT]);
  189. if (DB_FLD_EMPTY(cmd->result)) {
  190. *p++ = '*';
  191. } else {
  192. for(i = 0, fld = cmd->result; !DB_FLD_LAST(fld[i]); i++) {
  193. APPEND_CSTR(p, fld[i].name);
  194. if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
  195. }
  196. }
  197. APPEND_STR(p, strings[STR_FROM]);
  198. APPEND_STR(p, cmd->table);
  199. if (!DB_FLD_EMPTY(cmd->params)) {
  200. APPEND_STR(p, strings[STR_WHERE]);
  201. for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
  202. APPEND_CSTR(p, fld[i].name);
  203. switch(fld[i].op) {
  204. case DB_EQ: APPEND_STR(p, strings[STR_OP_EQ]); break;
  205. case DB_LT: APPEND_STR(p, strings[STR_OP_LT]); break;
  206. case DB_GT: APPEND_STR(p, strings[STR_OP_GT]); break;
  207. case DB_LEQ: APPEND_STR(p, strings[STR_OP_LEQ]); break;
  208. case DB_GEQ: APPEND_STR(p, strings[STR_OP_GEQ]); break;
  209. }
  210. APPEND_STR(p, strings[STR_ESC]);
  211. if (!DB_FLD_LAST(fld[i + 1])) APPEND_STR(p, strings[STR_AND]);
  212. }
  213. }
  214. *p = '\0';
  215. return 0;
  216. }
  217. static int build_replace_query(str* query, db_cmd_t* cmd)
  218. {
  219. db_fld_t* fld;
  220. int i;
  221. char* p;
  222. query->len = strings[STR_REPLACE].len;
  223. query->len += cmd->table.len;
  224. query->len += 2; /* " (" */
  225. for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
  226. query->len += strlen(fld[i].name);
  227. query->len += strings[STR_ESC].len;
  228. if (!DB_FLD_LAST(fld[i + 1])) query->len += 2; /* , twice */
  229. }
  230. query->len += strings[STR_VALUES].len;
  231. query->len += 1; /* ) */
  232. query->s = pkg_malloc(query->len + 1);
  233. if (query->s == NULL) {
  234. ERR("No memory left\n");
  235. return -1;
  236. }
  237. p = query->s;
  238. APPEND_STR(p, strings[STR_REPLACE]);
  239. APPEND_STR(p, cmd->table);
  240. *p++ = ' ';
  241. *p++ = '(';
  242. for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
  243. APPEND_CSTR(p, fld[i].name);
  244. if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
  245. }
  246. APPEND_STR(p, strings[STR_VALUES]);
  247. for(i = 0, fld = cmd->params; !DB_FLD_LAST(fld[i]); i++) {
  248. APPEND_STR(p, strings[STR_ESC]);
  249. if (!DB_FLD_LAST(fld[i + 1])) *p++ = ',';
  250. }
  251. *p++ = ')';
  252. *p = '\0';
  253. return 0;
  254. }
  255. static inline int update_params(MYSQL_STMT* st, db_fld_t* params)
  256. {
  257. int i;
  258. struct db_fld* f; /* Current field */
  259. struct my_fld* fp; /* Current field payload */
  260. struct tm* t;
  261. /* Iterate through all the query parameters and update
  262. * their values if needed
  263. */
  264. /* FIXME: We are updating internals of the prepared statement here,
  265. * this is probably not nice but I could not find another way of
  266. * updating the pointer to the buffer without the need to run
  267. * mysql_stmt_bind_param again (which would be innefficient
  268. */
  269. for(i = 0; i < st->param_count; i++) {
  270. fp = DB_GET_PAYLOAD(params + i);
  271. fp->is_null = params[i].flags & DB_NULL;
  272. if (fp->is_null) continue;
  273. switch(params[i].type) {
  274. case DB_STR:
  275. st->params[i].buffer = params[i].v.str.s;
  276. fp->length = params[i].v.str.len;
  277. break;
  278. case DB_BLOB:
  279. st->params[i].buffer = params[i].v.blob.s;
  280. fp->length = params[i].v.blob.len;
  281. break;
  282. case DB_CSTR:
  283. st->params[i].buffer = (char*)params[i].v.cstr;
  284. fp->length = strlen(params[i].v.cstr);
  285. break;
  286. case DB_DATETIME:
  287. t = gmtime(&params[i].v.time);
  288. fp->time.second = t->tm_sec;
  289. fp->time.minute = t->tm_min;
  290. fp->time.hour = t->tm_hour;
  291. fp->time.day = t->tm_mday;
  292. fp->time.month = t->tm_mon + 1;
  293. fp->time.year = t->tm_year + 1900;
  294. break;
  295. }
  296. }
  297. return 0;
  298. }
  299. static inline int update_result(db_fld_t* result, MYSQL_STMT* st)
  300. {
  301. int i;
  302. struct db_fld* r; /* Current field in the result */
  303. struct my_fld* rp; /* Payload of the current field in result */
  304. struct tm t;
  305. /* Iterate through all the query parameters and update
  306. * their values if needed
  307. */
  308. for(i = 0; i < st->field_count; i++) {
  309. rp = DB_GET_PAYLOAD(result + i);
  310. if (rp->is_null) {
  311. result[i].flags |= DB_NULL;
  312. continue;
  313. } else {
  314. result[i].flags &= ~DB_NULL;
  315. }
  316. switch(result[i].type) {
  317. case DB_STR:
  318. result[i].v.str.len = rp->length;
  319. break;
  320. case DB_BLOB:
  321. result[i].v.blob.len = rp->length;
  322. break;
  323. case DB_CSTR:
  324. result[i].v.cstr[rp->length] = '\0';
  325. break;
  326. case DB_DATETIME:
  327. memset(&t, '\0', sizeof(struct tm));
  328. t.tm_sec = rp->time.second;
  329. t.tm_min = rp->time.minute;
  330. t.tm_hour = rp->time.hour;
  331. t.tm_mday = rp->time.day;
  332. t.tm_mon = rp->time.month - 1;
  333. t.tm_year = rp->time.year - 1900;;
  334. /* Daylight saving information got lost in the database
  335. * so let timegm to guess it. This eliminates the bug when
  336. * contacts reloaded from the database have different time
  337. * of expiration by one hour when daylight saving is used
  338. */
  339. t.tm_isdst = -1;
  340. #ifdef HAVE_TIMEGM
  341. result[i].v.time = timegm(&t);
  342. #else
  343. result[i].v.time = _timegm(&t);
  344. #endif /* HAVE_TIMEGM */
  345. break;
  346. }
  347. }
  348. return 0;
  349. }
  350. int my_cmd_write(db_res_t* res, db_cmd_t* cmd)
  351. {
  352. struct my_cmd* mcmd;
  353. mcmd = DB_GET_PAYLOAD(cmd);
  354. if (mcmd->st->param_count && update_params(mcmd->st, cmd->params) < 0) return -1;
  355. if (mysql_stmt_execute(mcmd->st)) {
  356. ERR("Error while executing query: %s\n", mysql_stmt_error(mcmd->st));
  357. return -1;
  358. }
  359. return 0;
  360. }
  361. int my_cmd_read(db_res_t* res, db_cmd_t* cmd)
  362. {
  363. db_res_t* r;
  364. struct my_cmd* mcmd;
  365. mcmd = DB_GET_PAYLOAD(cmd);
  366. if (mcmd->st->param_count && update_params(mcmd->st, cmd->params) < 0) return -1;
  367. if (mysql_stmt_execute(mcmd->st)) {
  368. ERR("Error while executing query: %s\n", mysql_stmt_error(mcmd->st));
  369. return -1;
  370. }
  371. return 0;
  372. }
  373. static int bind_params(MYSQL_STMT* st, db_fld_t* fld)
  374. {
  375. int i, n;
  376. struct my_fld* f;
  377. MYSQL_BIND* params;
  378. /* Calculate the number of parameters */
  379. for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
  380. params = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
  381. if (params == NULL) {
  382. ERR("No memory left\n");
  383. return -1;
  384. }
  385. memset(params, '\0', sizeof(MYSQL_BIND) * n);
  386. for(i = 0; i < n; i++) {
  387. f = DB_GET_PAYLOAD(fld + i);
  388. params[i].is_null = &f->is_null;
  389. /* We can do it for all the types here, mysql will ignore it
  390. * for fixed-size types such as MYSQL_TYPE_LONG
  391. */
  392. params[i].length = &f->length;
  393. switch(fld[i].type) {
  394. case DB_INT:
  395. case DB_BITMAP:
  396. params[i].buffer_type = MYSQL_TYPE_LONG;
  397. params[i].buffer = &fld[i].v.int4;
  398. break;
  399. case DB_FLOAT:
  400. params[i].buffer_type = MYSQL_TYPE_FLOAT;
  401. params[i].buffer = &fld[i].v.flt;
  402. break;
  403. case DB_DOUBLE:
  404. params[i].buffer_type = MYSQL_TYPE_DOUBLE;
  405. params[i].buffer = &fld[i].v.dbl;
  406. break;
  407. case DB_DATETIME:
  408. params[i].buffer_type = MYSQL_TYPE_DATETIME;
  409. params[i].buffer = &f->time;
  410. break;
  411. case DB_STR:
  412. case DB_CSTR:
  413. params[i].buffer_type = MYSQL_TYPE_VAR_STRING;
  414. params[i].buffer = ""; /* Updated on runtime */
  415. break;
  416. case DB_BLOB:
  417. params[i].buffer_type = MYSQL_TYPE_BLOB;
  418. params[i].buffer = ""; /* Updated on runtime */
  419. break;
  420. }
  421. }
  422. if (mysql_stmt_bind_param(st, params)) {
  423. ERR("Error while binding parameters: %s\n", mysql_stmt_error(st));
  424. goto error;
  425. }
  426. /* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
  427. * creates a copy in the statement and we will update it there
  428. */
  429. pkg_free(params);
  430. return 0;
  431. error:
  432. if (params) pkg_free(params);
  433. return -1;
  434. }
  435. static int bind_result(MYSQL_STMT* st, db_fld_t* fld)
  436. {
  437. int i, n;
  438. struct my_fld* f;
  439. MYSQL_BIND* result;
  440. /* Calculate the number of fields in the result */
  441. for(n = 0; !DB_FLD_EMPTY(fld) && !DB_FLD_LAST(fld[n]); n++);
  442. result = (MYSQL_BIND*)pkg_malloc(sizeof(MYSQL_BIND) * n);
  443. if (result == NULL) {
  444. ERR("No memory left\n");
  445. return -1;
  446. }
  447. memset(result, '\0', sizeof(MYSQL_BIND) * n);
  448. for(i = 0; i < n; i++) {
  449. f = DB_GET_PAYLOAD(fld + i);
  450. result[i].is_null = &f->is_null;
  451. /* We can do it for all the types here, mysql will ignore it
  452. * for fixed-size types such as MYSQL_TYPE_LONG
  453. */
  454. result[i].length = &f->length;
  455. switch(fld[i].type) {
  456. case DB_INT:
  457. case DB_BITMAP:
  458. result[i].buffer_type = MYSQL_TYPE_LONG;
  459. result[i].buffer = &fld[i].v.int4;
  460. break;
  461. case DB_FLOAT:
  462. result[i].buffer_type = MYSQL_TYPE_FLOAT;
  463. result[i].buffer = &fld[i].v.flt;
  464. break;
  465. case DB_DOUBLE:
  466. result[i].buffer_type = MYSQL_TYPE_DOUBLE;
  467. result[i].buffer = &fld[i].v.dbl;
  468. break;
  469. case DB_DATETIME:
  470. result[i].buffer_type = MYSQL_TYPE_DATETIME;
  471. result[i].buffer = &f->time;
  472. break;
  473. case DB_STR:
  474. result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
  475. f->buf.s = pkg_malloc(STR_BUF_SIZE);
  476. if (f->buf.s == NULL) {
  477. ERR("No memory left\n");
  478. return -1;
  479. }
  480. result[i].buffer = f->buf.s;
  481. fld[i].v.str.s = f->buf.s;
  482. result[i].buffer_length = STR_BUF_SIZE - 1;
  483. break;
  484. case DB_CSTR:
  485. result[i].buffer_type = MYSQL_TYPE_VAR_STRING;
  486. f->buf.s = pkg_malloc(STR_BUF_SIZE);
  487. if (f->buf.s == NULL) {
  488. ERR("No memory left\n");
  489. return -1;
  490. }
  491. result[i].buffer = f->buf.s;
  492. fld[i].v.cstr = f->buf.s;
  493. result[i].buffer_length = STR_BUF_SIZE - 1;
  494. break;
  495. case DB_BLOB:
  496. result[i].buffer_type = MYSQL_TYPE_BLOB;
  497. f->buf.s = pkg_malloc(STR_BUF_SIZE);
  498. if (f->buf.s == NULL) {
  499. ERR("No memory left\n");
  500. return -1;
  501. }
  502. result[i].buffer = f->buf.s;
  503. fld[i].v.blob.s = f->buf.s;
  504. result[i].buffer_length = STR_BUF_SIZE - 1;
  505. break;
  506. }
  507. }
  508. if (mysql_stmt_bind_result(st, result)) {
  509. ERR("Error while binding result: %s\n", mysql_stmt_error(st));
  510. goto error;
  511. }
  512. /* We do not need the array of MYSQL_BIND anymore, mysql_stmt_bind_param
  513. * creates a copy in the statement and we will update it there
  514. */
  515. pkg_free(result);
  516. return 0;
  517. error:
  518. if (result) pkg_free(result);
  519. return -1;
  520. }
  521. int my_cmd(db_cmd_t* cmd)
  522. {
  523. struct my_cmd* res;
  524. struct my_con* mcon;
  525. res = (struct my_cmd*)pkg_malloc(sizeof(struct my_cmd));
  526. if (res == NULL) {
  527. ERR("No memory left\n");
  528. goto error;
  529. }
  530. memset(res, '\0', sizeof(struct my_cmd));
  531. if (db_drv_init(&res->gen, my_cmd_free) < 0) goto error;
  532. /* FIXME */
  533. mcon = DB_GET_PAYLOAD(cmd->ctx->con[db_payload_idx]);
  534. res->st = mysql_stmt_init(mcon->con);
  535. if (res->st == NULL) {
  536. ERR("No memory left\n");
  537. goto error;
  538. }
  539. switch(cmd->type) {
  540. case DB_PUT:
  541. if (DB_FLD_EMPTY(cmd->params)) {
  542. ERR("BUG: No parameters provided for DB_PUT in context '%.*s'\n",
  543. cmd->ctx->id.len, ZSW(cmd->ctx->id.s));
  544. goto error;
  545. }
  546. if (build_replace_query(&res->query, cmd) < 0) goto error;
  547. if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
  548. ERR("Error while preparing replace query: %s\n",
  549. mysql_stmt_error(res->st));
  550. goto error;
  551. }
  552. if (bind_params(res->st, cmd->params) < 0) goto error;
  553. break;
  554. case DB_DEL:
  555. if (build_delete_query(&res->query, cmd) < 0) goto error;
  556. if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
  557. ERR("Error while preparing delete query: %s\n",
  558. mysql_stmt_error(res->st));
  559. goto error;
  560. }
  561. if (!DB_FLD_EMPTY(cmd->params)) {
  562. if (bind_params(res->st, cmd->params) < 0) goto error;
  563. }
  564. break;
  565. case DB_GET:
  566. if (build_select_query(&res->query, cmd) < 0) goto error;
  567. if (mysql_stmt_prepare(res->st, res->query.s, res->query.len)) {
  568. ERR("Error while preparing select query: %s\n",
  569. mysql_stmt_error(res->st));
  570. goto error;
  571. }
  572. if (!DB_FLD_EMPTY(cmd->params)) {
  573. if (bind_params(res->st, cmd->params) < 0) goto error;
  574. }
  575. if (bind_result(res->st, cmd->result) < 0) goto error;
  576. break;
  577. }
  578. DB_SET_PAYLOAD(cmd, res);
  579. return 0;
  580. error:
  581. if (res) {
  582. db_drv_free(&res->gen);
  583. if (res->query.s) pkg_free(res->query.s);
  584. if (res->st) mysql_stmt_close(res->st);
  585. pkg_free(res);
  586. }
  587. return -1;
  588. }
  589. int my_cmd_next(db_res_t* res)
  590. {
  591. int ret;
  592. struct my_cmd* mcmd;
  593. mcmd = DB_GET_PAYLOAD(res->cmd);
  594. ret = mysql_stmt_fetch(mcmd->st);
  595. if (ret == MYSQL_NO_DATA) return 1;
  596. if (ret != 0) {
  597. ERR("Error in mysql_stmt_fetch: %s\n", mysql_stmt_error(mcmd->st));
  598. return -1;
  599. }
  600. if (update_result(res->cmd->result, mcmd->st) < 0) {
  601. mysql_stmt_free_result(mcmd->st);
  602. return -1;
  603. }
  604. res->cur_rec->fld = res->cmd->result;
  605. return 0;
  606. }