dbt_base.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /*
  2. * $Id$
  3. *
  4. * DBText module core functions
  5. *
  6. * Copyright (C) 2001-2003 FhG Fokus
  7. *
  8. * This file is part of Kamailio, a free SIP server.
  9. *
  10. * Kamailio is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * Kamailio is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * History:
  25. * --------
  26. * 2009-03-01 added support for ORDER-BY clause by Edgar Holleis
  27. * 2003-01-30 created by Daniel
  28. *
  29. */
  30. #include <string.h>
  31. #include "../../str.h"
  32. #include "../../mem/mem.h"
  33. #include "../../mem/shm_mem.h"
  34. #include "dbtext.h"
  35. #include "dbt_res.h"
  36. #include "dbt_api.h"
  37. #ifndef CFG_DIR
  38. #define CFG_DIR "/tmp"
  39. #endif
  40. #define DBT_ID "text://"
  41. #define DBT_ID_LEN (sizeof(DBT_ID)-1)
  42. #define DBT_PATH_LEN 256
  43. /*
  44. * Initialize database connection
  45. */
  46. db1_con_t* dbt_init(const str* _sqlurl)
  47. {
  48. db1_con_t* _res;
  49. str _s;
  50. char dbt_path[DBT_PATH_LEN];
  51. if (!_sqlurl || !_sqlurl->s)
  52. {
  53. LM_ERR("invalid parameter value\n");
  54. return NULL;
  55. }
  56. _s.s = _sqlurl->s;
  57. _s.len = _sqlurl->len;
  58. if(_s.len <= DBT_ID_LEN || strncmp(_s.s, DBT_ID, DBT_ID_LEN)!=0)
  59. {
  60. LM_ERR("invalid database URL - should be:"
  61. " <%s[/]path/to/directory> Current: %s\n", DBT_ID, _s.s);
  62. return NULL;
  63. }
  64. /*
  65. * it would be possible to use the _sqlurl here, but the core API is
  66. * defined with a const str*, so this code would be not valid.
  67. */
  68. _s.s += DBT_ID_LEN;
  69. _s.len -= DBT_ID_LEN;
  70. if(_s.s[0]!='/')
  71. {
  72. if(sizeof(CFG_DIR)+_s.len+2 > DBT_PATH_LEN)
  73. {
  74. LM_ERR("path to database is too long\n");
  75. return NULL;
  76. }
  77. strcpy(dbt_path, CFG_DIR);
  78. dbt_path[sizeof(CFG_DIR)] = '/';
  79. strncpy(&dbt_path[sizeof(CFG_DIR)+1], _s.s, _s.len);
  80. _s.len += sizeof(CFG_DIR);
  81. _s.s = dbt_path;
  82. }
  83. _res = pkg_malloc(sizeof(db1_con_t)+sizeof(dbt_con_t));
  84. if (!_res)
  85. {
  86. LM_ERR("no pkg memory left\n");
  87. return NULL;
  88. }
  89. memset(_res, 0, sizeof(db1_con_t) + sizeof(dbt_con_t));
  90. _res->tail = (unsigned long)((char*)_res+sizeof(db1_con_t));
  91. LM_INFO("using database at: %.*s", _s.len, _s.s);
  92. DBT_CON_CONNECTION(_res) = dbt_cache_get_db(&_s);
  93. if (!DBT_CON_CONNECTION(_res))
  94. {
  95. LM_ERR("cannot get the link to database\n");
  96. return NULL;
  97. }
  98. return _res;
  99. }
  100. /*
  101. * Close a database connection
  102. */
  103. void dbt_close(db1_con_t* _h)
  104. {
  105. if (!_h)
  106. {
  107. LM_ERR("invalid parameter value\n");
  108. return;
  109. }
  110. pkg_free(_h);
  111. return;
  112. }
  113. /*
  114. * Free all memory allocated by get_result
  115. */
  116. int dbt_free_result(db1_con_t* _h, db1_res_t* _r)
  117. {
  118. if ((!_h) || (!_r))
  119. {
  120. LM_ERR("invalid parameter value\n");
  121. return -1;
  122. }
  123. if(dbt_result_free((dbt_result_p)_r->ptr) < 0)
  124. {
  125. LM_ERR("unable to free internal structure\n");
  126. }
  127. if(db_free_result(_r) < 0)
  128. {
  129. LM_ERR("unable to free result structure\n");
  130. return -1;
  131. }
  132. return 0;
  133. }
  134. /*
  135. * Query table for specified rows
  136. * _h: structure representing database connection
  137. * _k: key names
  138. * _op: operators
  139. * _v: values of the keys that must match
  140. * _c: column names to return
  141. * _n: number of key=values pairs to compare
  142. * _nc: number of columns to return
  143. * _o: order by the specified column
  144. */
  145. int dbt_query(db1_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v,
  146. db_key_t* _c, int _n, int _nc, db_key_t _o, db1_res_t** _r)
  147. {
  148. dbt_table_p _tbc = NULL;
  149. dbt_row_p _drp = NULL;
  150. dbt_result_p _dres = NULL;
  151. int result = 0;
  152. int *lkey=NULL, *lres=NULL;
  153. db_key_t *_o_k=NULL; /* columns in order-by */
  154. char *_o_op=NULL; /* operators for oder-by */
  155. int _o_n; /* no of elements in order-by */
  156. int *_o_l=NULL; /* column selection for order-by */
  157. int _o_nc; /* no of elements in _o_l but not lres */
  158. if ((!_h) || (!_r) || !CON_TABLE(_h))
  159. {
  160. LM_ERR("invalid parameters\n");
  161. return -1;
  162. }
  163. *_r = NULL;
  164. if (_o)
  165. {
  166. if (dbt_parse_orderbyclause(&_o_k, &_o_op, &_o_n, _o) < 0)
  167. return -1;
  168. }
  169. /* lock database */
  170. _tbc = dbt_db_get_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  171. if(!_tbc)
  172. {
  173. LM_ERR("table %.*s does not exist!\n", CON_TABLE(_h)->len, CON_TABLE(_h)->s);
  174. return -1;
  175. }
  176. if(!_tbc || _tbc->nrcols < _nc)
  177. {
  178. LM_ERR("table %s not loaded! (too few columns)\n", CON_TABLE(_h)->s);
  179. goto error;
  180. }
  181. if(_k)
  182. {
  183. lkey = dbt_get_refs(_tbc, _k, _n);
  184. if(!lkey)
  185. goto error;
  186. }
  187. if(_c)
  188. {
  189. lres = dbt_get_refs(_tbc, _c, _nc);
  190. if(!lres)
  191. goto error;
  192. }
  193. if(_o_k)
  194. {
  195. _o_l = dbt_get_refs(_tbc, _o_k, _o_n);
  196. if (!_o_l)
  197. goto error;
  198. /* enlarge select-columns lres by all order-by columns, _o_nc is how many */
  199. if (dbt_mangle_columnselection(&lres, &_nc, &_o_nc, _o_l, _o_n) < 0)
  200. goto error;
  201. }
  202. LM_DBG("new res with %d cols\n", _nc);
  203. _dres = dbt_result_new(_tbc, lres, _nc);
  204. if(!_dres)
  205. goto error;
  206. _drp = _tbc->rows;
  207. while(_drp)
  208. {
  209. if(dbt_row_match(_tbc, _drp, lkey, _op, _v, _n))
  210. {
  211. if(dbt_result_extract_fields(_tbc, _drp, lres, _dres))
  212. {
  213. LM_ERR("failed to extract result fields!\n");
  214. goto clean;
  215. }
  216. }
  217. _drp = _drp->next;
  218. }
  219. dbt_table_update_flags(_tbc, DBT_TBFL_ZERO, DBT_FL_IGN, 1);
  220. /* unlock database */
  221. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  222. if (_o_l)
  223. {
  224. if (_dres->nrrows > 1)
  225. {
  226. if (dbt_sort_result(_dres, _o_l, _o_op, _o_n, lres, _nc) < 0)
  227. goto error_nounlock;
  228. }
  229. /* last but not least, remove surplus columns */
  230. if (_o_nc)
  231. dbt_project_result(_dres, _o_nc);
  232. }
  233. /* dbt_result_print(_dres); */
  234. if(lkey)
  235. pkg_free(lkey);
  236. if(lres)
  237. pkg_free(lres);
  238. if(_o_k)
  239. pkg_free(_o_k);
  240. if(_o_op)
  241. pkg_free(_o_op);
  242. if(_o_l)
  243. pkg_free(_o_l);
  244. result = dbt_get_result(_r, _dres);
  245. if(result != 0)
  246. dbt_result_free(_dres);
  247. return result;
  248. error:
  249. /* unlock database */
  250. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  251. error_nounlock:
  252. if(lkey)
  253. pkg_free(lkey);
  254. if(lres)
  255. pkg_free(lres);
  256. if(_o_k)
  257. pkg_free(_o_k);
  258. if(_o_op)
  259. pkg_free(_o_op);
  260. if(_o_l)
  261. pkg_free(_o_l);
  262. if(_dres)
  263. dbt_result_free(_dres);
  264. LM_ERR("failed to query the table!\n");
  265. return -1;
  266. clean:
  267. /* unlock database */
  268. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  269. if(lkey)
  270. pkg_free(lkey);
  271. if(lres)
  272. pkg_free(lres);
  273. if(_o_k)
  274. pkg_free(_o_k);
  275. if(_o_op)
  276. pkg_free(_o_op);
  277. if(_o_l)
  278. pkg_free(_o_l);
  279. if(_dres)
  280. dbt_result_free(_dres);
  281. return -1;
  282. }
  283. /*
  284. * Raw SQL query -- is not the case to have this method
  285. */
  286. int dbt_raw_query(db1_con_t* _h, char* _s, db1_res_t** _r)
  287. {
  288. *_r = NULL;
  289. return -1;
  290. }
  291. /*
  292. * Insert a row into table
  293. */
  294. int dbt_insert(db1_con_t* _h, db_key_t* _k, db_val_t* _v, int _n)
  295. {
  296. dbt_table_p _tbc = NULL;
  297. dbt_row_p _drp = NULL;
  298. int *lkey=NULL, i, j;
  299. if (!_h || !CON_TABLE(_h))
  300. {
  301. LM_ERR("invalid parameter\n");
  302. return -1;
  303. }
  304. if(!_k || !_v || _n<=0)
  305. {
  306. LM_ERR("no key-value to insert\n");
  307. return -1;
  308. }
  309. /* lock database */
  310. _tbc = dbt_db_get_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  311. if(!_tbc)
  312. {
  313. LM_ERR("table %.*s does not exist!\n", CON_TABLE(_h)->len, CON_TABLE(_h)->s);
  314. return -1;
  315. }
  316. if(_tbc->nrcols<_n)
  317. {
  318. LM_ERR("more values than columns!!\n");
  319. goto error;
  320. }
  321. if(_k)
  322. {
  323. lkey = dbt_get_refs(_tbc, _k, _n);
  324. if(!lkey)
  325. goto error;
  326. }
  327. _drp = dbt_row_new(_tbc->nrcols);
  328. if(!_drp)
  329. {
  330. LM_ERR("no shm memory for a new row!!\n");
  331. goto error;
  332. }
  333. for(i=0; i<_n; i++)
  334. {
  335. j = (lkey)?lkey[i]:i;
  336. if(dbt_is_neq_type(_tbc->colv[j]->type, _v[i].type))
  337. {
  338. LM_ERR("incompatible types v[%d] - c[%d]!\n", i, j);
  339. goto clean;
  340. }
  341. if(_v[i].type == DB1_STRING && !_v[i].nul)
  342. _v[i].val.str_val.len = strlen(_v[i].val.string_val);
  343. if(dbt_row_set_val(_drp, &(_v[i]), _tbc->colv[j]->type, j))
  344. {
  345. LM_ERR("cannot set v[%d] in c[%d]!\n", i, j);
  346. goto clean;
  347. }
  348. }
  349. if(dbt_table_add_row(_tbc, _drp))
  350. {
  351. LM_ERR("cannot insert the new row!!\n");
  352. goto clean;
  353. }
  354. /* dbt_print_table(_tbc, NULL); */
  355. /* unlock databse */
  356. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  357. if(lkey)
  358. pkg_free(lkey);
  359. return 0;
  360. error:
  361. /* unlock database */
  362. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  363. if(lkey)
  364. pkg_free(lkey);
  365. LM_ERR("failed to insert row in table!\n");
  366. return -1;
  367. clean:
  368. if(lkey)
  369. pkg_free(lkey);
  370. if(_drp) // free row
  371. dbt_row_free(_tbc, _drp);
  372. /* unlock database */
  373. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  374. return -1;
  375. }
  376. /*
  377. * Delete a row from table
  378. */
  379. int dbt_delete(db1_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v, int _n)
  380. {
  381. dbt_table_p _tbc = NULL;
  382. dbt_row_p _drp = NULL, _drp0 = NULL;
  383. int *lkey = NULL;
  384. if (!_h || !CON_TABLE(_h))
  385. {
  386. LM_ERR("invalid parameters\n");
  387. return -1;
  388. }
  389. /* lock database */
  390. _tbc = dbt_db_get_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  391. if(!_tbc)
  392. {
  393. LM_ERR("failed to load table <%.*s>!\n", CON_TABLE(_h)->len,
  394. CON_TABLE(_h)->s);
  395. return -1;
  396. }
  397. if(!_k || !_v || _n<=0)
  398. {
  399. LM_DBG("deleting all records\n");
  400. dbt_table_free_rows(_tbc);
  401. /* unlock databse */
  402. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  403. return 0;
  404. }
  405. lkey = dbt_get_refs(_tbc, _k, _n);
  406. if(!lkey)
  407. goto error;
  408. _drp = _tbc->rows;
  409. while(_drp)
  410. {
  411. _drp0 = _drp->next;
  412. if(dbt_row_match(_tbc, _drp, lkey, _o, _v, _n))
  413. {
  414. // delete row
  415. if(_drp->prev)
  416. (_drp->prev)->next = _drp->next;
  417. else
  418. _tbc->rows = _drp->next;
  419. if(_drp->next)
  420. (_drp->next)->prev = _drp->prev;
  421. _tbc->nrrows--;
  422. // free row
  423. dbt_row_free(_tbc, _drp);
  424. }
  425. _drp = _drp0;
  426. }
  427. dbt_table_update_flags(_tbc, DBT_TBFL_MODI, DBT_FL_SET, 1);
  428. /* dbt_print_table(_tbc, NULL); */
  429. /* unlock database */
  430. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  431. if(lkey)
  432. pkg_free(lkey);
  433. return 0;
  434. error:
  435. /* unlock database */
  436. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  437. LM_ERR("failed to delete from table!\n");
  438. return -1;
  439. }
  440. /*
  441. * Update a row in table
  442. */
  443. int dbt_update(db1_con_t* _h, db_key_t* _k, db_op_t* _o, db_val_t* _v,
  444. db_key_t* _uk, db_val_t* _uv, int _n, int _un)
  445. {
  446. dbt_table_p _tbc = NULL;
  447. dbt_row_p _drp = NULL;
  448. int i;
  449. int *lkey=NULL, *lres=NULL;
  450. if (!_h || !CON_TABLE(_h) || !_uk || !_uv || _un <= 0)
  451. {
  452. LM_ERR("invalid parameters\n");
  453. return -1;
  454. }
  455. /* lock database */
  456. _tbc = dbt_db_get_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  457. if(!_tbc)
  458. {
  459. LM_ERR("table %.*s does not exist!\n", CON_TABLE(_h)->len, CON_TABLE(_h)->s);
  460. return -1;
  461. }
  462. if(_k)
  463. {
  464. lkey = dbt_get_refs(_tbc, _k, _n);
  465. if(!lkey)
  466. goto error;
  467. }
  468. lres = dbt_get_refs(_tbc, _uk, _un);
  469. if(!lres)
  470. goto error;
  471. _drp = _tbc->rows;
  472. while(_drp)
  473. {
  474. if(dbt_row_match(_tbc, _drp, lkey, _o, _v, _n))
  475. { // update fields
  476. for(i=0; i<_un; i++)
  477. {
  478. if(dbt_is_neq_type(_tbc->colv[lres[i]]->type, _uv[i].type))
  479. {
  480. LM_ERR("incompatible types!\n");
  481. goto error;
  482. }
  483. if(dbt_row_update_val(_drp, &(_uv[i]),
  484. _tbc->colv[lres[i]]->type, lres[i]))
  485. {
  486. LM_ERR("cannot set v[%d] in c[%d]!\n",
  487. i, lres[i]);
  488. goto error;
  489. }
  490. }
  491. }
  492. _drp = _drp->next;
  493. }
  494. dbt_table_update_flags(_tbc, DBT_TBFL_MODI, DBT_FL_SET, 1);
  495. /* dbt_print_table(_tbc, NULL); */
  496. /* unlock database */
  497. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  498. if(lkey)
  499. pkg_free(lkey);
  500. if(lres)
  501. pkg_free(lres);
  502. return 0;
  503. error:
  504. /* unlock database */
  505. dbt_release_table(DBT_CON_CONNECTION(_h), CON_TABLE(_h));
  506. if(lkey)
  507. pkg_free(lkey);
  508. if(lres)
  509. pkg_free(lres);
  510. LM_ERR("failed to update the table!\n");
  511. return -1;
  512. }