bdb_cmd.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. /*
  2. * $Id$
  3. *
  4. * BDB Database Driver for SIP-router
  5. *
  6. * Copyright (C) 2008 iptelorg GmbH
  7. *
  8. * This file is part of SIP-router, a free SIP server.
  9. *
  10. * SIP-router is free software; you can redistribute it and/or modify it under the
  11. * terms of the GNU General Public License as published by the Free Software
  12. * Foundation; either version 2 of the License, or (at your option) any later
  13. * version.
  14. *
  15. * SIP-router is distributed in the hope that it will be useful, but WITHOUT ANY
  16. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  17. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  18. * details.
  19. *
  20. * You should have received a copy of the GNU General Public License along
  21. * with this program; if not, write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  23. */
  24. /*! \addtogroup bdb
  25. * @{
  26. */
  27. /*! \file
  28. * Berkeley DB : Implementation of functions related to database commands.
  29. *
  30. * \ingroup database
  31. */
  32. #include <string.h>
  33. #include "../../mem/mem.h"
  34. #include "../../dprint.h"
  35. #include "../../ut.h"
  36. #include "bdb_cmd.h"
  37. #include "bdb_fld.h"
  38. #include "bdb_con.h"
  39. #include "bdb_uri.h"
  40. #include "bdb_res.h"
  41. #include "bdb_lib.h"
  42. #include "bdb_crs_compat.h"
  43. #define BDB_BUF_SIZE 1024
  44. /** Destroys a bdb_cmd structure.
  45. * This function frees all memory used by ld_cmd structure.
  46. * @param cmd A pointer to generic db_cmd command being freed.
  47. * @param payload A pointer to ld_cmd structure to be freed.
  48. */
  49. static void bdb_cmd_free(db_cmd_t* cmd, bdb_cmd_t* payload)
  50. {
  51. db_drv_free(&payload->gen);
  52. if (payload->dbcp)
  53. payload->dbcp->CLOSE_CURSOR(payload->dbcp);
  54. if(payload->skey.s)
  55. pkg_free(payload->skey.s);
  56. pkg_free(payload);
  57. }
  58. int bdb_prepare_query(db_cmd_t* cmd, bdb_cmd_t *bcmd)
  59. {
  60. bdb_tcache_t *tbc = NULL;
  61. bdb_table_t *tp = NULL;
  62. bdb_fld_t *f;
  63. db_fld_t *fld;
  64. int mode;
  65. int i;
  66. if(bcmd->bcon==NULL || bcmd->bcon->dbp==NULL)
  67. return -1;
  68. tbc = bdblib_get_table(bcmd->bcon->dbp, &cmd->table);
  69. if(tbc==NULL)
  70. {
  71. ERR("bdb: table does not exist!\n");
  72. return -1;
  73. }
  74. tp = tbc->dtp;
  75. if(tp==NULL || tp->db==NULL)
  76. {
  77. ERR("bdb: table not loaded!\n");
  78. return -1;
  79. }
  80. mode = 0;
  81. if (!DB_FLD_EMPTY(cmd->result))
  82. { /* columns to be returned provided */
  83. if (cmd->result_count > tp->ncols)
  84. {
  85. ERR("bdb: too many columns in query\n");
  86. goto error;
  87. }
  88. } else {
  89. mode = 1;
  90. cmd->result = db_fld(tp->ncols + 1);
  91. cmd->result_count = tp->ncols;
  92. for(i = 0; i < cmd->result_count; i++) {
  93. if (bdb_fld(cmd->result + i, cmd->table.s) < 0)
  94. goto error;
  95. }
  96. }
  97. for (i = 0; i < cmd->result_count; i++) {
  98. fld = cmd->result + i;
  99. f = DB_GET_PAYLOAD(fld);
  100. if(mode==1)
  101. {
  102. DBG("bdb: column name [%.*s]\n", tp->colp[i]->name.len,
  103. tp->colp[i]->name.s);
  104. f->name = pkg_malloc(tp->colp[i]->name.len+1);
  105. if (f->name == NULL) {
  106. ERR("bdb: Out of private memory\n");
  107. goto error;
  108. }
  109. strncpy(f->name, tp->colp[i]->name.s, tp->colp[i]->name.len);
  110. f->name[tp->colp[i]->name.len] = '\0';
  111. fld->name = f->name;
  112. fld->type = tp->colp[i]->type;
  113. f->col_pos = i;
  114. } else {
  115. f->col_pos = bdb_get_colpos(tp, fld->name);
  116. if(f->col_pos == -1)
  117. {
  118. ERR("bdb: Column not found\n");
  119. goto error;
  120. }
  121. }
  122. switch(fld->type) {
  123. case DB_INT:
  124. case DB_BITMAP:
  125. case DB_FLOAT:
  126. case DB_DOUBLE:
  127. case DB_DATETIME:
  128. case DB_STR:
  129. if (!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE);
  130. if (f->buf.s == NULL) {
  131. ERR("bdb: No memory left\n");
  132. goto error;
  133. }
  134. fld[i].v.lstr.s = f->buf.s;
  135. break;
  136. case DB_CSTR:
  137. if (!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE);
  138. if (f->buf.s == NULL) {
  139. ERR("bdb: No memory left\n");
  140. goto error;
  141. }
  142. fld[i].v.cstr = f->buf.s;
  143. break;
  144. case DB_BLOB:
  145. if (!f->buf.s) f->buf.s = pkg_malloc(BDB_BUF_SIZE);
  146. if (f->buf.s == NULL) {
  147. ERR("mysql: No memory left\n");
  148. goto error;
  149. }
  150. fld[i].v.blob.s = f->buf.s;
  151. break;
  152. case DB_NONE:
  153. /* Eliminates gcc warning */
  154. break;
  155. }
  156. }
  157. if (!DB_FLD_EMPTY(cmd->match))
  158. {
  159. if (cmd->match_count > tp->ncols)
  160. {
  161. ERR("bdb: too many columns in match struct of query\n");
  162. goto error;
  163. }
  164. for (i = 0; i < cmd->match_count; i++) {
  165. fld = cmd->result + i;
  166. f = DB_GET_PAYLOAD(fld);
  167. f->col_pos = bdb_get_colpos(tp, fld->name);
  168. if(f->col_pos == -1)
  169. {
  170. ERR("bdb: Match column not found\n");
  171. goto error;
  172. }
  173. }
  174. }
  175. return 0;
  176. error:
  177. return -1;
  178. }
  179. int bdb_query(db_cmd_t* cmd, bdb_cmd_t *bcmd)
  180. {
  181. DBT key;
  182. DB *db;
  183. static char kbuf[MAX_ROW_SIZE];
  184. int klen;
  185. bdb_tcache_t *tbc = NULL;
  186. bdb_table_t *tp = NULL;
  187. if(bcmd->bcon==NULL || bcmd->bcon->dbp==NULL)
  188. return -1;
  189. tbc = bdblib_get_table(bcmd->bcon->dbp, &cmd->table);
  190. if(tbc==NULL)
  191. {
  192. ERR("bdb: table does not exist!\n");
  193. return -1;
  194. }
  195. tp = tbc->dtp;
  196. if(tp==NULL)
  197. {
  198. ERR("bdb: table not loaded!\n");
  199. return -1;
  200. }
  201. db = tp->db;
  202. if(db==NULL)
  203. {
  204. ERR("bdb: db structure not intialized!\n");
  205. return -1;
  206. }
  207. if (DB_FLD_EMPTY(cmd->match))
  208. { /* no match constraint */
  209. if (db->cursor(db, NULL, &bcmd->dbcp, 0) != 0)
  210. {
  211. ERR("bdb: error creating cursor\n");
  212. goto error;
  213. }
  214. bcmd->skey.len = 0;
  215. return 0;
  216. }
  217. memset(&key, 0, sizeof(DBT));
  218. memset(kbuf, 0, MAX_ROW_SIZE);
  219. klen=MAX_ROW_SIZE;
  220. if(bdblib_valtochar(tp, cmd->match, cmd->match_count,
  221. kbuf, &klen, BDB_KEY)!=0)
  222. {
  223. ERR("bdb: error creating key\n");
  224. goto error;
  225. }
  226. if(klen > bcmd->skey_size || bcmd->skey.s==NULL)
  227. {
  228. if(bcmd->skey.s!=NULL)
  229. pkg_free(bcmd->skey.s);
  230. bcmd->skey.s = (char*)pkg_malloc(klen*sizeof(char));
  231. if(bcmd->skey.s == NULL)
  232. {
  233. ERR("bdb: no pkg memory\n");
  234. goto error;
  235. }
  236. bcmd->skey_size = klen;
  237. }
  238. memcpy(bcmd->skey.s, kbuf, klen);
  239. bcmd->skey.len = klen;
  240. return 0;
  241. error:
  242. return -1;
  243. }
  244. int bdb_cmd(db_cmd_t* cmd)
  245. {
  246. bdb_cmd_t *bcmd;
  247. db_con_t *con;
  248. bdb_con_t *bcon;
  249. bcmd = (bdb_cmd_t*)pkg_malloc(sizeof(bdb_cmd_t));
  250. if (bcmd == NULL) {
  251. ERR("bdb: No memory left\n");
  252. goto error;
  253. }
  254. memset(bcmd, '\0', sizeof(bdb_cmd_t));
  255. if (db_drv_init(&bcmd->gen, bdb_cmd_free) < 0) goto error;
  256. con = cmd->ctx->con[db_payload_idx];
  257. bcon = DB_GET_PAYLOAD(con);
  258. bcmd->bcon = bcon;
  259. switch(cmd->type) {
  260. case DB_PUT:
  261. case DB_DEL:
  262. case DB_UPD:
  263. ERR("bdb: The driver does not support DB modifications yet.\n");
  264. goto error;
  265. break;
  266. case DB_GET:
  267. if(bdb_prepare_query(cmd, bcmd)!=0)
  268. {
  269. ERR("bdb: error preparing query.\n");
  270. goto error;
  271. }
  272. break;
  273. case DB_SQL:
  274. ERR("bdb: The driver does not support raw queries yet.\n");
  275. goto error;
  276. }
  277. DB_SET_PAYLOAD(cmd, bcmd);
  278. return 0;
  279. error:
  280. if (bcmd) {
  281. DB_SET_PAYLOAD(cmd, NULL);
  282. db_drv_free(&bcmd->gen);
  283. pkg_free(bcmd);
  284. }
  285. return -1;
  286. }
  287. int bdb_cmd_exec(db_res_t* res, db_cmd_t* cmd)
  288. {
  289. db_con_t* con;
  290. bdb_cmd_t *bcmd;
  291. bdb_con_t *bcon;
  292. /* First things first: retrieve connection info from the currently active
  293. * connection and also mysql payload from the database command
  294. */
  295. con = cmd->ctx->con[db_payload_idx];
  296. bcmd = DB_GET_PAYLOAD(cmd);
  297. bcon = DB_GET_PAYLOAD(con);
  298. if ((bcon->flags & BDB_CONNECTED)==0) {
  299. ERR("bdb: not connected\n");
  300. return -1;
  301. }
  302. bcmd->next_flag = -1;
  303. switch(cmd->type) {
  304. case DB_DEL:
  305. case DB_PUT:
  306. case DB_UPD:
  307. /* no result expected - cleanup */
  308. DBG("bdb: query with no result.\n");
  309. break;
  310. case DB_GET:
  311. return bdb_query(cmd, bcmd);
  312. break;
  313. default:
  314. /* result expected - no cleanup */
  315. DBG("bdb: query with result.\n");
  316. }
  317. return 0;
  318. }
  319. int bdb_update_result(db_cmd_t *cmd, DBT *data)
  320. {
  321. bdb_fld_t *f;
  322. db_fld_t *fld;
  323. int i;
  324. int col;
  325. char *s;
  326. static str col_map[MAX_NUM_COLS];
  327. memset(col_map, 0, MAX_NUM_COLS*sizeof(str));
  328. col = 0;
  329. s = (char*)data->data;
  330. col_map[col].s = s;
  331. while(*s!='\0')
  332. {
  333. if(*s == *DELIM)
  334. {
  335. col_map[col].len = s - col_map[col].s;
  336. col++;
  337. col_map[col].s = s+1;
  338. }
  339. s++;
  340. }
  341. col_map[col].len = s - col_map[col].s;
  342. for (i = 0; i < cmd->result_count; i++) {
  343. fld = cmd->result + i;
  344. f = DB_GET_PAYLOAD(fld);
  345. if(col_map[f->col_pos].len == 0)
  346. {
  347. fld->flags |= DB_NULL;
  348. continue;
  349. }
  350. fld->flags &= ~DB_NULL;
  351. switch(fld->type) {
  352. case DB_STR:
  353. fld->v.lstr.s = f->buf.s;
  354. if(col_map[f->col_pos].len < BDB_BUF_SIZE)
  355. {
  356. fld->v.lstr.len = col_map[f->col_pos].len;
  357. } else {
  358. /* truncate ?!? */
  359. fld->v.lstr.len = BDB_BUF_SIZE - 1;
  360. }
  361. memcpy(fld->v.lstr.s, col_map[f->col_pos].s, fld->v.lstr.len);
  362. break;
  363. case DB_BLOB:
  364. fld->v.blob.s = f->buf.s;
  365. if(col_map[f->col_pos].len < BDB_BUF_SIZE)
  366. {
  367. fld->v.blob.len = col_map[f->col_pos].len;
  368. } else {
  369. /* truncate ?!? */
  370. fld->v.blob.len = BDB_BUF_SIZE - 1;
  371. }
  372. memcpy(fld->v.blob.s, col_map[f->col_pos].s, fld->v.blob.len);
  373. break;
  374. case DB_CSTR:
  375. fld->v.cstr = f->buf.s;
  376. if(col_map[f->col_pos].len < BDB_BUF_SIZE)
  377. {
  378. memcpy(fld->v.cstr, col_map[f->col_pos].s,
  379. col_map[f->col_pos].len);
  380. fld->v.cstr[col_map[f->col_pos].len] = '\0';
  381. } else {
  382. /* truncate ?!? */
  383. memcpy(fld->v.cstr, col_map[f->col_pos].s,
  384. BDB_BUF_SIZE - 1);
  385. fld->v.cstr[BDB_BUF_SIZE - 1] = '\0';;
  386. }
  387. break;
  388. case DB_DATETIME:
  389. /* str to time */
  390. col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
  391. if (bdb_str2time(col_map[f->col_pos].s, &fld->v.time) < 0)
  392. {
  393. ERR("Error while converting INT value from string\n");
  394. return -1;
  395. }
  396. break;
  397. case DB_INT:
  398. /* str to int */
  399. col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
  400. if (bdb_str2int(col_map[f->col_pos].s, &fld->v.int4) < 0)
  401. {
  402. ERR("Error while converting INT value from string\n");
  403. return -1;
  404. }
  405. break;
  406. case DB_FLOAT:
  407. case DB_DOUBLE:
  408. /* str to dowuble */
  409. col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
  410. if (bdb_str2double(col_map[f->col_pos].s, &fld->v.dbl) < 0)
  411. {
  412. ERR("Error while converting DOUBLE value from string\n");
  413. return -1;
  414. }
  415. break;
  416. case DB_BITMAP:
  417. /* str to int */
  418. col_map[f->col_pos].s[col_map[f->col_pos].len]='\0';
  419. if (bdb_str2int(col_map[f->col_pos].s, &fld->v.int4) < 0)
  420. {
  421. ERR("Error while converting BITMAP value from string\n");
  422. return -1;
  423. }
  424. break;
  425. case DB_NONE:
  426. break;
  427. }
  428. }
  429. return 0;
  430. }
  431. int bdb_cmd_first(db_res_t* res)
  432. {
  433. bdb_cmd_t *bcmd;
  434. bcmd = DB_GET_PAYLOAD(res->cmd);
  435. switch (bcmd->next_flag) {
  436. case -2: /* table is empty */
  437. return 1;
  438. case 0: /* cursor position is 0 */
  439. return 0;
  440. case 1: /* next row */
  441. case 2: /* EOF */
  442. ERR("bdb: no next row.\n");
  443. return -1;
  444. default:
  445. return bdb_cmd_next(res);
  446. }
  447. }
  448. int bdb_cmd_next(db_res_t* res)
  449. {
  450. db_con_t *con;
  451. bdb_res_t *bres;
  452. bdb_con_t *bcon;
  453. bdb_cmd_t *bcmd;
  454. DBT key, data;
  455. int ret;
  456. static char dbuf[MAX_ROW_SIZE];
  457. con = res->cmd->ctx->con[db_payload_idx];
  458. bres = DB_GET_PAYLOAD(res);
  459. bcon = DB_GET_PAYLOAD(con);
  460. bcmd = DB_GET_PAYLOAD(res->cmd);
  461. if (bcmd->next_flag == 2 || bcmd->next_flag == -2) return 1;
  462. memset(&key, 0, sizeof(DBT));
  463. memset(&data, 0, sizeof(DBT));
  464. memset(dbuf, 0, MAX_ROW_SIZE);
  465. data.data = dbuf;
  466. data.ulen = MAX_ROW_SIZE;
  467. data.flags = DB_DBT_USERMEM;
  468. ret = 0;
  469. if(bcmd->skey.len==0)
  470. {
  471. while((ret = bcmd->dbcp->c_get(bcmd->dbcp, &key, &data, DB_NEXT))==0)
  472. {
  473. if(!strncasecmp((char*)key.data,"METADATA",8))
  474. continue;
  475. break;
  476. }
  477. if(ret!=0)
  478. {
  479. bcmd->next_flag = bcmd->next_flag<0?-2:2;
  480. return 1;
  481. }
  482. } else {
  483. key.data = bcmd->skey.s;
  484. key.ulen = bcmd->skey_size;
  485. key.flags = DB_DBT_USERMEM;
  486. key.size = bcmd->skey.len;
  487. ret = bcmd->dbcp->c_get(bcmd->dbcp, &key, &data, DB_NEXT);
  488. if(ret!=0)
  489. {
  490. bcmd->next_flag = bcmd->next_flag<0?-2:2;
  491. return 1;
  492. }
  493. }
  494. if (bcmd->next_flag <= 0) {
  495. bcmd->next_flag++;
  496. }
  497. if (bdb_update_result(res->cmd, &data) < 0) {
  498. return -1;
  499. }
  500. res->cur_rec->fld = res->cmd->result;
  501. return 0;
  502. }
  503. /** @} */