mongodb_dbase.c 31 KB

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