mongodb_dbase.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  1. /*
  2. * Copyright (C) 2014 Daniel-Constantin Mierla (asipto.com)
  3. *
  4. * This file is part of Kamailio, a free SIP server.
  5. *
  6. * Kamailio 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. * Kamailio 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, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. *
  20. */
  21. #include "../../mem/mem.h"
  22. #include "../../dprint.h"
  23. #include "../../lib/srdb1/db_ut.h"
  24. #include "../../lib/srdb1/db_query.h"
  25. #include "mongodb_connection.h"
  26. #include "mongodb_dbase.h"
  27. #define DB_MONGODB_ROWS_STEP 1000
  28. typedef struct db_mongodb_result {
  29. mongoc_collection_t *collection; /*!< Collection link */
  30. mongoc_cursor_t *cursor; /*!< Cursor link */
  31. bson_t *rdoc;
  32. int idx;
  33. bson_t *colsdoc;
  34. int nrcols;
  35. int maxrows;
  36. } db_mongodb_result_t;
  37. /*
  38. * Initialize database module
  39. * No function should be called before this
  40. */
  41. db1_con_t* db_mongodb_init(const str* _url)
  42. {
  43. return db_do_init(_url, (void *)db_mongodb_new_connection);
  44. }
  45. /*
  46. * Shut down database module
  47. * No function should be called after this
  48. */
  49. void db_mongodb_close(db1_con_t* _h)
  50. {
  51. db_do_close(_h, db_mongodb_free_connection);
  52. }
  53. int db_mongodb_bson_add(bson_t *doc, const db_key_t _k, const db_val_t *_v, int idx)
  54. {
  55. int vtype;
  56. vtype = VAL_TYPE(_v);
  57. if(VAL_NULL(_v)) {
  58. if(!bson_append_null(doc, _k->s, _k->len)) {
  59. LM_ERR("failed to append int to bson doc %.*s = %d [%d]\n",
  60. _k->len, _k->s, VAL_INT(_v), idx);
  61. goto error;
  62. }
  63. goto done;
  64. }
  65. switch(vtype) {
  66. case DB1_INT:
  67. if(!bson_append_int32(doc, _k->s, _k->len,
  68. VAL_INT(_v))) {
  69. LM_ERR("failed to append int to bson doc %.*s = %d [%d]\n",
  70. _k->len, _k->s, VAL_INT(_v), idx);
  71. goto error;
  72. }
  73. break;
  74. case DB1_BIGINT:
  75. if(!bson_append_int64(doc, _k->s, _k->len,
  76. VAL_BIGINT(_v ))) {
  77. LM_ERR("failed to append bigint to bson doc %.*s = %lld [%d]\n",
  78. _k->len, _k->s, VAL_BIGINT(_v), idx);
  79. goto error;
  80. }
  81. return -1;
  82. case DB1_DOUBLE:
  83. if(!bson_append_double(doc, _k->s, _k->len,
  84. VAL_DOUBLE(_v))) {
  85. LM_ERR("failed to append double to bson doc %.*s = %f [%d]\n",
  86. _k->len, _k->s, VAL_DOUBLE(_v), idx);
  87. goto error;
  88. }
  89. break;
  90. case DB1_STRING:
  91. if(!bson_append_utf8(doc, _k->s, _k->len,
  92. VAL_STRING(_v), strlen(VAL_STRING(_v))) ) {
  93. LM_ERR("failed to append string to bson doc %.*s = %s [%d]\n",
  94. _k->len, _k->s, VAL_STRING(_v), idx);
  95. goto error;
  96. }
  97. break;
  98. case DB1_STR:
  99. if(!bson_append_utf8(doc, _k->s, _k->len,
  100. VAL_STR(_v).s, VAL_STR(_v).len) ) {
  101. LM_ERR("failed to append str to bson doc %.*s = %.*s [%d]\n",
  102. _k->len, _k->s, VAL_STR(_v).len, VAL_STR(_v).s, idx);
  103. goto error;
  104. }
  105. break;
  106. case DB1_DATETIME:
  107. if(!bson_append_time_t(doc, _k->s, _k->len,
  108. VAL_TIME(_v))) {
  109. LM_ERR("failed to append time to bson doc %.*s = %ld [%d]\n",
  110. _k->len, _k->s, VAL_TIME(_v), idx);
  111. goto error;
  112. }
  113. break;
  114. case DB1_BLOB:
  115. if(!bson_append_binary(doc, _k->s, _k->len,
  116. BSON_SUBTYPE_BINARY,
  117. (const uint8_t *)VAL_BLOB(_v).s, VAL_BLOB(_v).len) ) {
  118. LM_ERR("failed to append blob to bson doc %.*s = [bin] [%d]\n",
  119. _k->len, _k->s, idx);
  120. goto error;
  121. }
  122. break;
  123. case DB1_BITMAP:
  124. if(!bson_append_int32(doc, _k->s, _k->len,
  125. VAL_INT(_v))) {
  126. LM_ERR("failed to append bitmap to bson doc %.*s = %d [%d]\n",
  127. _k->len, _k->s, VAL_INT(_v), idx);
  128. goto error;
  129. }
  130. break;
  131. default:
  132. LM_ERR("val type [%d] not supported\n", vtype);
  133. return -1;
  134. }
  135. done:
  136. return 0;
  137. error:
  138. return -1;
  139. }
  140. /*!
  141. * \brief Get and convert columns from a result
  142. *
  143. * Get and convert columns from a result, fills the result structure
  144. * with data from the database.
  145. * \param _h database connection
  146. * \param _r database result set
  147. * \return 0 on success, negative on failure
  148. */
  149. int db_mongodb_get_columns(const db1_con_t* _h, db1_res_t* _r)
  150. {
  151. int col;
  152. db_mongodb_result_t *mgres;
  153. bson_iter_t riter;
  154. bson_iter_t citer;
  155. bson_t *cdoc;
  156. const char *colname;
  157. bson_type_t coltype;
  158. if ((!_h) || (!_r)) {
  159. LM_ERR("invalid parameter\n");
  160. return -1;
  161. }
  162. mgres = (db_mongodb_result_t*)RES_PTR(_r);
  163. if(!mgres->rdoc) {
  164. mgres->nrcols = 0;
  165. return 0;
  166. }
  167. if(mgres->nrcols==0 || mgres->colsdoc==NULL) {
  168. mgres->nrcols = (int)bson_count_keys(mgres->rdoc);
  169. if(mgres->nrcols==0) {
  170. LM_ERR("no keys in bson document\n");
  171. return -1;
  172. }
  173. cdoc = mgres->rdoc;
  174. } else {
  175. cdoc = mgres->colsdoc;
  176. }
  177. RES_COL_N(_r) = mgres->nrcols;
  178. if (!RES_COL_N(_r)) {
  179. LM_ERR("no columns returned from the query\n");
  180. return -2;
  181. } else {
  182. LM_DBG("%d columns returned from the query\n", RES_COL_N(_r));
  183. }
  184. if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) {
  185. RES_COL_N(_r) = 0;
  186. LM_ERR("could not allocate columns\n");
  187. return -3;
  188. }
  189. if (!bson_iter_init (&citer, cdoc)) {
  190. LM_ERR("failed to initialize columns iterator\n");
  191. return -3;
  192. }
  193. if(mgres->colsdoc) {
  194. if (!bson_iter_init (&riter, mgres->rdoc)) {
  195. LM_ERR("failed to initialize result iterator\n");
  196. return -3;
  197. }
  198. }
  199. col = 0;
  200. while (bson_iter_next (&citer)) {
  201. if(col >= RES_COL_N(_r)) {
  202. LM_ERR("invalid number of columns (%d/%d)\n", col, RES_COL_N(_r));
  203. return -4;
  204. }
  205. colname = bson_iter_key (&citer);
  206. LM_DBG("Found a field[%d] named: %s\n", col, colname);
  207. if(mgres->colsdoc) {
  208. if(!bson_iter_find(&riter, colname)) {
  209. LM_ERR("field [%s] not found in result iterator\n",
  210. colname);
  211. return -4;
  212. }
  213. coltype = bson_iter_type(&riter);
  214. } else {
  215. coltype = bson_iter_type(&citer);
  216. }
  217. RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str));
  218. if (! RES_NAMES(_r)[col]) {
  219. LM_ERR("no private memory left\n");
  220. db_free_columns(_r);
  221. return -4;
  222. }
  223. LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n",
  224. (unsigned long)sizeof(str), col, RES_NAMES(_r)[col]);
  225. /* pointer linked here is part of the result structure */
  226. RES_NAMES(_r)[col]->s = (char*)colname;
  227. RES_NAMES(_r)[col]->len = strlen(colname);
  228. switch(coltype) {
  229. case BSON_TYPE_BOOL:
  230. case BSON_TYPE_INT32:
  231. case BSON_TYPE_TIMESTAMP:
  232. LM_DBG("use DB1_INT result type\n");
  233. RES_TYPES(_r)[col] = DB1_INT;
  234. break;
  235. case BSON_TYPE_INT64:
  236. LM_DBG("use DB1_BIGINT result type\n");
  237. RES_TYPES(_r)[col] = DB1_BIGINT;
  238. break;
  239. case BSON_TYPE_DOUBLE:
  240. LM_DBG("use DB1_DOUBLE result type\n");
  241. RES_TYPES(_r)[col] = DB1_DOUBLE;
  242. break;
  243. case BSON_TYPE_DATE_TIME:
  244. LM_DBG("use DB1_DATETIME result type\n");
  245. RES_TYPES(_r)[col] = DB1_DATETIME;
  246. break;
  247. case BSON_TYPE_BINARY:
  248. LM_DBG("use DB1_BLOB result type\n");
  249. RES_TYPES(_r)[col] = DB1_BLOB;
  250. break;
  251. case BSON_TYPE_UTF8:
  252. LM_DBG("use DB1_STRING result type\n");
  253. RES_TYPES(_r)[col] = DB1_STRING;
  254. break;
  255. #if 0
  256. case BSON_TYPE_EOD:
  257. case BSON_TYPE_DOCUMENT:
  258. case BSON_TYPE_ARRAY:
  259. case BSON_TYPE_UNDEFINED:
  260. case BSON_TYPE_OID:
  261. case BSON_TYPE_NULL:
  262. case BSON_TYPE_REGEX:
  263. case BSON_TYPE_DBPOINTER:
  264. case BSON_TYPE_CODE:
  265. case BSON_TYPE_SYMBOL:
  266. case BSON_TYPE_CODEWSCOPE:
  267. case BSON_TYPE_MAXKEY:
  268. case BSON_TYPE_MINKEY:
  269. #endif
  270. default:
  271. LM_WARN("unhandled data type column (%.*s) type id (%d), "
  272. "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
  273. RES_NAMES(_r)[col]->s, coltype);
  274. RES_TYPES(_r)[col] = DB1_STRING;
  275. break;
  276. }
  277. LM_DBG("RES_NAMES(%p)[%d]=[%.*s] (%d)\n", RES_NAMES(_r)[col], col,
  278. RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, coltype);
  279. col++;
  280. }
  281. return 0;
  282. }
  283. /*!
  284. * \brief Convert rows from mongodb to db API representation
  285. * \param _h database connection
  286. * \param _r database result set
  287. * \return 0 on success, negative on failure
  288. */
  289. static int db_mongdob_convert_bson(const db1_con_t* _h, db1_res_t* _r,
  290. int _row, const bson_t *_rdoc)
  291. {
  292. static str dummy_string = {"", 0};
  293. int col;
  294. db_mongodb_result_t *mgres;
  295. const char *colname;
  296. bson_type_t coltype;
  297. bson_iter_t riter;
  298. bson_iter_t citer;
  299. bson_iter_t *piter;
  300. db_val_t* dval;
  301. uint32_t i32tmp;
  302. bson_subtype_t subtype;
  303. bson_t *cdoc;
  304. mgres = (db_mongodb_result_t*)RES_PTR(_r);
  305. if(mgres->nrcols==0) {
  306. LM_ERR("no fields to convert\n");
  307. return -1;
  308. }
  309. if(mgres->colsdoc==NULL) {
  310. cdoc = (bson_t*)_rdoc;
  311. } else {
  312. cdoc = (bson_t*)mgres->colsdoc;
  313. }
  314. if (!bson_iter_init (&citer, cdoc)) {
  315. LM_ERR("failed to initialize columns iterator\n");
  316. return -3;
  317. }
  318. if(mgres->colsdoc) {
  319. if (!bson_iter_init (&riter, _rdoc)) {
  320. LM_ERR("failed to initialize result iterator\n");
  321. return -3;
  322. }
  323. }
  324. if (db_allocate_row(_r, &(RES_ROWS(_r)[_row])) != 0) {
  325. LM_ERR("could not allocate row: %d\n", _row);
  326. return -2;
  327. }
  328. col = 0;
  329. while (bson_iter_next (&citer)) {
  330. if(col >= RES_COL_N(_r)) {
  331. LM_ERR("invalid number of columns (%d/%d)\n", col, RES_COL_N(_r));
  332. return -4;
  333. }
  334. colname = bson_iter_key (&citer);
  335. LM_DBG("looking for field[%d] named: %s\n", col, colname);
  336. if(mgres->colsdoc) {
  337. if(!bson_iter_find(&riter, colname)) {
  338. LM_ERR("field [%s] not found in result iterator\n",
  339. colname);
  340. return -4;
  341. }
  342. piter = &riter;
  343. } else {
  344. piter = &citer;
  345. }
  346. coltype = bson_iter_type(piter);
  347. dval = &(ROW_VALUES(&(RES_ROWS(_r)[_row]))[col]);
  348. VAL_TYPE(dval) = RES_TYPES(_r)[col];
  349. switch(coltype) {
  350. case BSON_TYPE_BOOL:
  351. VAL_INT(dval) = (int)bson_iter_bool (piter);
  352. break;
  353. case BSON_TYPE_INT32:
  354. VAL_INT(dval) = bson_iter_int32 (piter);
  355. break;
  356. case BSON_TYPE_TIMESTAMP:
  357. bson_iter_timestamp (piter,
  358. (uint32_t*)&VAL_INT(dval), &i32tmp);
  359. break;
  360. case BSON_TYPE_INT64:
  361. VAL_BIGINT(dval) = bson_iter_int64 (piter);
  362. break;
  363. case BSON_TYPE_DOUBLE:
  364. VAL_DOUBLE(dval) = bson_iter_double (piter);
  365. break;
  366. case BSON_TYPE_DATE_TIME:
  367. VAL_TIME(dval) = (time_t)(bson_iter_date_time (piter)/1000);
  368. break;
  369. case BSON_TYPE_BINARY:
  370. bson_iter_binary (piter, &subtype,
  371. (uint32_t*)&VAL_BLOB(dval).len, (const uint8_t**)&VAL_BLOB(dval).s);
  372. break;
  373. case BSON_TYPE_UTF8:
  374. VAL_STRING(dval) = (char*)bson_iter_utf8 (piter, &i32tmp);
  375. break;
  376. case BSON_TYPE_OID:
  377. break;
  378. case BSON_TYPE_NULL:
  379. memset(dval, 0, sizeof(db_val_t));
  380. /* Initialize the string pointers to a dummy empty
  381. * string so that we do not crash when the NULL flag
  382. * is set but the module does not check it properly
  383. */
  384. VAL_STRING(dval) = dummy_string.s;
  385. VAL_STR(dval) = dummy_string;
  386. VAL_BLOB(dval) = dummy_string;
  387. VAL_TYPE(dval) = RES_TYPES(_r)[col];
  388. VAL_NULL(dval) = 1;
  389. break;
  390. #if 0
  391. case BSON_TYPE_EOD:
  392. case BSON_TYPE_DOCUMENT:
  393. case BSON_TYPE_ARRAY:
  394. case BSON_TYPE_UNDEFINED:
  395. case BSON_TYPE_REGEX:
  396. case BSON_TYPE_DBPOINTER:
  397. case BSON_TYPE_CODE:
  398. case BSON_TYPE_SYMBOL:
  399. case BSON_TYPE_CODEWSCOPE:
  400. case BSON_TYPE_MAXKEY:
  401. case BSON_TYPE_MINKEY:
  402. #endif
  403. default:
  404. LM_WARN("unhandled data type column (%.*s) type id (%d), "
  405. "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
  406. RES_NAMES(_r)[col]->s, coltype);
  407. RES_TYPES(_r)[col] = DB1_STRING;
  408. break;
  409. }
  410. LM_DBG("RES_NAMES(%p)[%d]=[%.*s] (%d)\n", RES_NAMES(_r)[col], col,
  411. RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, coltype);
  412. col++;
  413. }
  414. return 0;
  415. }
  416. /*!
  417. * \brief Convert rows from mongodb to db API representation
  418. * \param _h database connection
  419. * \param _r database result set
  420. * \return 0 on success, negative on failure
  421. */
  422. static int db_mongdob_convert_result(const db1_con_t* _h, db1_res_t* _r)
  423. {
  424. int row;
  425. db_mongodb_result_t *mgres;
  426. const bson_t *itdoc;
  427. char *jstr;
  428. if ((!_h) || (!_r)) {
  429. LM_ERR("invalid parameter\n");
  430. return -1;
  431. }
  432. mgres = (db_mongodb_result_t*)RES_PTR(_r);
  433. if(!mgres->rdoc) {
  434. mgres->nrcols = 0;
  435. return 0;
  436. }
  437. if(mgres->nrcols==0) {
  438. LM_DBG("no fields to return\n");
  439. return 0;
  440. }
  441. if(!mongoc_cursor_more (mgres->cursor)) {
  442. RES_ROW_N(_r) = 1;
  443. mgres->maxrows = 1;
  444. } else {
  445. RES_ROW_N(_r) = DB_MONGODB_ROWS_STEP;
  446. mgres->maxrows = DB_MONGODB_ROWS_STEP;
  447. }
  448. if (db_allocate_rows(_r) < 0) {
  449. LM_ERR("could not allocate rows\n");
  450. RES_ROW_N(_r) = 0;
  451. return -2;
  452. }
  453. itdoc = mgres->rdoc;
  454. row = 0;
  455. do {
  456. if(row >= RES_ROW_N(_r)) {
  457. if (db_reallocate_rows(_r,
  458. RES_ROW_N(_r)+DB_MONGODB_ROWS_STEP) < 0) {
  459. LM_ERR("could not reallocate rows\n");
  460. return -2;
  461. }
  462. mgres->maxrows = RES_ROW_N(_r);
  463. }
  464. if(is_printable(L_DBG)) {
  465. jstr = bson_as_json (itdoc, NULL);
  466. LM_DBG("selected document: %s\n", jstr);
  467. bson_free (jstr);
  468. }
  469. if(db_mongdob_convert_bson(_h, _r, row, itdoc)) {
  470. LM_ERR("failed to convert bson at pos %d\n", row);
  471. return -1;
  472. }
  473. row++;
  474. } while (mongoc_cursor_more (mgres->cursor)
  475. && mongoc_cursor_next (mgres->cursor, &itdoc));
  476. RES_ROW_N(_r) = row;
  477. LM_DBG("retrieved number of rows: %d\n", row);
  478. return 0;
  479. }
  480. db1_res_t* db_mongodb_new_result(void)
  481. {
  482. db1_res_t* obj;
  483. obj = db_new_result();
  484. if (!obj)
  485. return NULL;
  486. RES_PTR(obj) = pkg_malloc(sizeof(db_mongodb_result_t));
  487. if (!RES_PTR(obj)) {
  488. db_free_result(obj);
  489. return NULL;
  490. }
  491. memset(RES_PTR(obj), 0, sizeof(db_mongodb_result_t));
  492. return obj;
  493. }
  494. /*
  495. * Retrieve result set
  496. */
  497. static int db_mongodb_store_result(const db1_con_t* _h, db1_res_t** _r)
  498. {
  499. km_mongodb_con_t *mgcon;
  500. db_mongodb_result_t *mgres;
  501. const bson_t *itdoc;
  502. mgcon = MONGODB_CON(_h);
  503. if(!_r) {
  504. LM_ERR("invalid result parameter\n");
  505. return -1;
  506. }
  507. *_r = db_mongodb_new_result();
  508. if (!*_r) {
  509. LM_ERR("no memory left for result \n");
  510. goto error;
  511. }
  512. mgres = (db_mongodb_result_t*)RES_PTR(*_r);
  513. mgres->collection = mgcon->collection;
  514. mgcon->collection = NULL;
  515. mgres->cursor = mgcon->cursor;
  516. mgcon->cursor = NULL;
  517. mgres->colsdoc = mgcon->colsdoc;
  518. mgcon->colsdoc = NULL;
  519. mgres->nrcols = mgcon->nrcols;
  520. mgcon->nrcols = 0;
  521. if(!mongoc_cursor_more (mgres->cursor)
  522. || !mongoc_cursor_next (mgres->cursor, &itdoc)
  523. || !itdoc) {
  524. LM_DBG("no result from mongodb\n");
  525. return 0;
  526. }
  527. /* first document linked internally in result to get columns */
  528. mgres->rdoc = (bson_t*)itdoc;
  529. if(db_mongodb_get_columns(_h, *_r)<0) {
  530. LM_ERR("failed to set the columns\n");
  531. goto error;
  532. }
  533. if(db_mongdob_convert_result(_h, *_r)<0) {
  534. LM_ERR("failed to set the rows in result\n");
  535. goto error;
  536. }
  537. return 0;
  538. error:
  539. if(mgcon->colsdoc) {
  540. bson_destroy (mgcon->colsdoc);
  541. mgcon->colsdoc = NULL;
  542. }
  543. mgcon->nrcols = 0;
  544. if(mgcon->cursor) {
  545. mongoc_cursor_destroy (mgcon->cursor);
  546. mgcon->cursor = NULL;
  547. }
  548. if(mgcon->collection) {
  549. mongoc_collection_destroy (mgcon->collection);
  550. mgcon->collection = NULL;
  551. }
  552. return -1;
  553. }
  554. /*
  555. * Release a result set from memory
  556. */
  557. int db_mongodb_free_result(db1_con_t* _h, db1_res_t* _r)
  558. {
  559. if(!_r)
  560. return -1;
  561. if(RES_PTR(_r)) {
  562. if(((db_mongodb_result_t*)RES_PTR(_r))->rdoc) {
  563. bson_destroy(((db_mongodb_result_t*)RES_PTR(_r))->rdoc);
  564. ((db_mongodb_result_t*)RES_PTR(_r))->rdoc = NULL;
  565. }
  566. if(((db_mongodb_result_t*)RES_PTR(_r))->colsdoc) {
  567. bson_destroy (((db_mongodb_result_t*)RES_PTR(_r))->colsdoc);
  568. ((db_mongodb_result_t*)RES_PTR(_r))->colsdoc = NULL;
  569. }
  570. ((db_mongodb_result_t*)RES_PTR(_r))->nrcols = 0;
  571. if(((db_mongodb_result_t*)RES_PTR(_r))->cursor) {
  572. mongoc_cursor_destroy (((db_mongodb_result_t*)RES_PTR(_r))->cursor);
  573. ((db_mongodb_result_t*)RES_PTR(_r))->cursor = NULL;
  574. }
  575. if(((db_mongodb_result_t*)RES_PTR(_r))->collection) {
  576. mongoc_collection_destroy (((db_mongodb_result_t*)RES_PTR(_r))->collection);
  577. ((db_mongodb_result_t*)RES_PTR(_r))->collection = NULL;
  578. }
  579. pkg_free(RES_PTR(_r));
  580. }
  581. db_free_result(_r);
  582. return 0;
  583. }
  584. /*
  585. * Query table for specified rows
  586. * _h: structure representing database connection
  587. * _k: key names
  588. * _op: operators
  589. * _v: values of the keys that must match
  590. * _c: column names to return
  591. * _n: number of key=values pairs to compare
  592. * _nc: number of columns to return
  593. * _o: order by the specified column
  594. */
  595. int db_mongodb_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
  596. const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
  597. const db_key_t _o, db1_res_t** _r)
  598. {
  599. int i;
  600. km_mongodb_con_t *mgcon;
  601. mongoc_client_t *client;
  602. bson_t *seldoc = NULL;
  603. char *cname;
  604. char b1;
  605. char *jstr;
  606. mgcon = MONGODB_CON(_h);
  607. if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
  608. LM_ERR("connection to server is null\n");
  609. return -1;
  610. }
  611. if(mgcon->collection) {
  612. mongoc_collection_destroy (mgcon->collection);
  613. mgcon->collection = NULL;
  614. }
  615. if(mgcon->cursor) {
  616. mongoc_cursor_destroy (mgcon->cursor);
  617. mgcon->cursor = NULL;
  618. }
  619. if(mgcon->colsdoc) {
  620. bson_destroy (mgcon->colsdoc);
  621. mgcon->colsdoc = NULL;
  622. }
  623. mgcon->nrcols = 0;
  624. client = mgcon->con;
  625. if(CON_TABLE(_h)->s==NULL) {
  626. LM_ERR("collection (table) name not set\n");
  627. return -1;
  628. }
  629. if(_r) *_r = NULL;
  630. b1 = '\0';
  631. if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
  632. b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
  633. CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
  634. }
  635. cname = CON_TABLE(_h)->s;
  636. LM_DBG("query to collection [%s]\n", cname);
  637. mgcon->collection = mongoc_client_get_collection(client, mgcon->id->database, cname);
  638. if(mgcon->collection==NULL) {
  639. LM_ERR("cannot get collection (table): %s\n", cname);
  640. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  641. return -1;
  642. }
  643. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  644. seldoc = bson_new();
  645. if(seldoc==NULL) {
  646. LM_ERR("cannot initialize query bson document\n");
  647. goto error;
  648. }
  649. for(i = 0; i < _n; i++) {
  650. if(db_mongodb_bson_add(seldoc, _k[i], _v+i, i)<0)
  651. goto error;
  652. }
  653. if(is_printable(L_DBG)) {
  654. jstr = bson_as_json (seldoc, NULL);
  655. LM_DBG("query filter: %s\n", jstr);
  656. bson_free (jstr);
  657. }
  658. if(_nc > 0) {
  659. mgcon->colsdoc = bson_new();
  660. if(mgcon->colsdoc==NULL) {
  661. LM_ERR("cannot initialize columns bson document\n");
  662. goto error;
  663. }
  664. for(i = 0; i < _nc; i++) {
  665. if(!bson_append_int32(mgcon->colsdoc, _c[i]->s, _c[i]->len, 1))
  666. {
  667. LM_ERR("failed to append int to columns bson %.*s = %d [%d]\n",
  668. _c[i]->len, _c[i]->s, 1, i);
  669. goto error;
  670. }
  671. }
  672. if(is_printable(L_DBG)) {
  673. jstr = bson_as_json (mgcon->colsdoc, NULL);
  674. LM_DBG("columns filter: %s\n", jstr);
  675. bson_free (jstr);
  676. }
  677. mgcon->nrcols = _nc;
  678. }
  679. mgcon->cursor = mongoc_collection_find (mgcon->collection,
  680. MONGOC_QUERY_NONE, 0, 0, 0,
  681. seldoc, mgcon->colsdoc, NULL);
  682. if(!_r) {
  683. goto done;
  684. }
  685. if(db_mongodb_store_result(_h, _r)<0) {
  686. LM_ERR("failed to store result\n");
  687. goto error;
  688. }
  689. done:
  690. bson_destroy (seldoc);
  691. return 0;
  692. error:
  693. LM_ERR("failed to do the query\n");
  694. if(seldoc) bson_destroy (seldoc);
  695. if(mgcon->colsdoc) {
  696. bson_destroy (mgcon->colsdoc);
  697. mgcon->colsdoc = NULL;
  698. }
  699. mgcon->nrcols = 0;
  700. if(mgcon->collection) {
  701. mongoc_collection_destroy (mgcon->collection);
  702. mgcon->collection = NULL;
  703. }
  704. if(mgcon->cursor) {
  705. mongoc_cursor_destroy (mgcon->cursor);
  706. mgcon->cursor = NULL;
  707. }
  708. if(_r && *_r) { db_mongodb_free_result((db1_con_t*)_h, *_r); *_r = NULL; }
  709. return -1;
  710. }
  711. /*!
  712. * \brief Gets a partial result set, fetch rows from a result
  713. *
  714. * Gets a partial result set, fetch a number of rows from a databae result.
  715. * This function initialize the given result structure on the first run, and
  716. * fetches the nrows number of rows. On subsequenting runs, it uses the
  717. * existing result and fetches more rows, until it reaches the end of the
  718. * result set. Because of this the result needs to be null in the first
  719. * invocation of the function. If the number of wanted rows is zero, the
  720. * function returns anything with a result of zero.
  721. * \param _h structure representing the database connection
  722. * \param _r pointer to a structure representing the result
  723. * \param nrows number of fetched rows
  724. * \return return zero on success, negative value on failure
  725. */
  726. int db_mongodb_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows)
  727. {
  728. return -1;
  729. }
  730. /*
  731. * Execute a raw SQL query
  732. */
  733. int db_mongodb_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r)
  734. {
  735. return -1;
  736. }
  737. /*
  738. * Insert a row into specified table
  739. * _h: structure representing database connection
  740. * _k: key names
  741. * _v: values of the keys
  742. * _n: number of key=value pairs
  743. */
  744. int db_mongodb_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n)
  745. {
  746. int i;
  747. km_mongodb_con_t *mgcon;
  748. mongoc_client_t *client;
  749. mongoc_collection_t *collection = NULL;
  750. bson_error_t error;
  751. bson_t *doc = NULL;
  752. char *cname;
  753. char *jstr;
  754. char b1;
  755. mgcon = MONGODB_CON(_h);
  756. if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
  757. LM_ERR("connection to server is null\n");
  758. return -1;
  759. }
  760. client = mgcon->con;
  761. if(CON_TABLE(_h)->s==NULL) {
  762. LM_ERR("collection (table) name not set\n");
  763. return -1;
  764. }
  765. b1 = '\0';
  766. if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
  767. b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
  768. CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
  769. }
  770. cname = CON_TABLE(_h)->s;
  771. collection = mongoc_client_get_collection(client, mgcon->id->database, cname);
  772. if(collection==NULL) {
  773. LM_ERR("cannot get collection (table): %s\n", cname);
  774. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  775. return -1;
  776. }
  777. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  778. doc = bson_new();
  779. if(doc==NULL) {
  780. LM_ERR("cannot initialize bson document\n");
  781. goto error;
  782. }
  783. for(i = 0; i < _n; i++) {
  784. if(db_mongodb_bson_add(doc, _k[i], _v+i, i)<0)
  785. goto error;
  786. }
  787. if(is_printable(L_DBG)) {
  788. jstr = bson_as_json (doc, NULL);
  789. LM_DBG("insert document: %s\n", jstr);
  790. bson_free (jstr);
  791. }
  792. if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) {
  793. LM_ERR("failed to insert in collection: %s\n", error.message);
  794. goto error;
  795. }
  796. bson_destroy (doc);
  797. mongoc_collection_destroy (collection);
  798. return 0;
  799. error:
  800. if(doc) bson_destroy (doc);
  801. if(collection) mongoc_collection_destroy (collection);
  802. return -1;
  803. }
  804. /*
  805. * Delete a row from the specified table
  806. * _h: structure representing database connection
  807. * _k: key names
  808. * _o: operators
  809. * _v: values of the keys that must match
  810. * _n: number of key=value pairs
  811. */
  812. int db_mongodb_delete(const db1_con_t* _h, const db_key_t* _k,
  813. const db_op_t* _o, const db_val_t* _v, const int _n)
  814. {
  815. int i;
  816. km_mongodb_con_t *mgcon;
  817. mongoc_client_t *client;
  818. mongoc_collection_t *collection = NULL;
  819. bson_error_t error;
  820. bson_t *doc = NULL;
  821. char *cname;
  822. char *jstr;
  823. char b1;
  824. mgcon = MONGODB_CON(_h);
  825. if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
  826. LM_ERR("connection to server is null\n");
  827. return -1;
  828. }
  829. client = mgcon->con;
  830. if(CON_TABLE(_h)->s==NULL) {
  831. LM_ERR("collection (table) name not set\n");
  832. return -1;
  833. }
  834. b1 = '\0';
  835. if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
  836. b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
  837. CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
  838. }
  839. cname = CON_TABLE(_h)->s;
  840. collection = mongoc_client_get_collection(client, mgcon->id->database,
  841. cname);
  842. if(collection==NULL) {
  843. LM_ERR("cannot get collection (table): %s\n", cname);
  844. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  845. return -1;
  846. }
  847. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  848. doc = bson_new();
  849. if(doc==NULL) {
  850. LM_ERR("cannot initialize bson document\n");
  851. goto error;
  852. }
  853. for(i = 0; i < _n; i++) {
  854. if(db_mongodb_bson_add(doc, _k[i], _v+i, i)<0)
  855. goto error;
  856. }
  857. if(is_printable(L_DBG)) {
  858. jstr = bson_as_json (doc, NULL);
  859. LM_DBG("delete filter document: %s\n", jstr);
  860. bson_free (jstr);
  861. }
  862. if (!mongoc_collection_remove (collection, MONGOC_REMOVE_NONE,
  863. doc, NULL, &error)) {
  864. LM_ERR("failed to delete in collection: %s\n", error.message);
  865. goto error;
  866. }
  867. bson_destroy (doc);
  868. mongoc_collection_destroy (collection);
  869. return 0;
  870. error:
  871. if(doc) bson_destroy (doc);
  872. if(collection) mongoc_collection_destroy (collection);
  873. return -1;
  874. }
  875. /*
  876. * Update some rows in the specified table
  877. * _h: structure representing database connection
  878. * _k: key names
  879. * _o: operators
  880. * _v: values of the keys that must match
  881. * _uk: updated columns
  882. * _uv: updated values of the columns
  883. * _n: number of key=value pairs
  884. * _un: number of columns to update
  885. */
  886. int db_mongodb_update(const db1_con_t* _h, const db_key_t* _k,
  887. const db_op_t* _o, const db_val_t* _v, const db_key_t* _uk,
  888. const db_val_t* _uv, const int _n, const int _un)
  889. {
  890. int i;
  891. km_mongodb_con_t *mgcon;
  892. mongoc_client_t *client;
  893. mongoc_collection_t *collection = NULL;
  894. bson_error_t error;
  895. bson_t *mdoc = NULL;
  896. bson_t *udoc = NULL;
  897. char *cname;
  898. char b1;
  899. mgcon = MONGODB_CON(_h);
  900. if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
  901. LM_ERR("connection to server is null\n");
  902. return -1;
  903. }
  904. client = mgcon->con;
  905. if(CON_TABLE(_h)->s==NULL) {
  906. LM_ERR("collection (table) name not set\n");
  907. return -1;
  908. }
  909. b1 = '\0';
  910. if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
  911. b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
  912. CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
  913. }
  914. cname = CON_TABLE(_h)->s;
  915. collection = mongoc_client_get_collection(client, mgcon->id->database,
  916. cname);
  917. if(collection==NULL) {
  918. LM_ERR("cannot get collection (table): %s\n", cname);
  919. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  920. return -1;
  921. }
  922. if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
  923. udoc = bson_new();
  924. if(udoc==NULL) {
  925. LM_ERR("cannot initialize update bson document\n");
  926. goto error;
  927. }
  928. mdoc = bson_new();
  929. if(mdoc==NULL) {
  930. LM_ERR("cannot initialize match bson document\n");
  931. goto error;
  932. }
  933. for(i = 0; i < _un; i++) {
  934. if(db_mongodb_bson_add(udoc, _uk[i], _uv+i, i)<0)
  935. goto error;
  936. }
  937. for(i = 0; i < _n; i++) {
  938. if(db_mongodb_bson_add(mdoc, _k[i], _v+i, i)<0)
  939. goto error;
  940. }
  941. if (!mongoc_collection_find_and_modify (collection, mdoc, NULL, udoc, NULL,
  942. false, false, false, NULL, &error)) {
  943. LM_ERR("failed to update in collection: %s\n", error.message);
  944. goto error;
  945. }
  946. bson_destroy (mdoc);
  947. bson_destroy (udoc);
  948. mongoc_collection_destroy (collection);
  949. return 0;
  950. error:
  951. if(mdoc) bson_destroy (mdoc);
  952. if(udoc) bson_destroy (udoc);
  953. if(collection) mongoc_collection_destroy (collection);
  954. return -1;
  955. }
  956. /*
  957. * Just like insert, but replace the row if it exists
  958. */
  959. int db_mongodb_replace(const db1_con_t* _h, const db_key_t* _k,
  960. const db_val_t* _v, const int _n, const int _un, const int _m)
  961. {
  962. return -1;
  963. }
  964. /*
  965. * Store name of table that will be used by
  966. * subsequent database functions
  967. */
  968. int db_mongodb_use_table(db1_con_t* _h, const str* _t)
  969. {
  970. return db_use_table(_h, _t);
  971. }