12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070 |
- /*
- * Copyright (C) 2014 Daniel-Constantin Mierla (asipto.com)
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
- #include "../../mem/mem.h"
- #include "../../dprint.h"
- #include "../../lib/srdb1/db_ut.h"
- #include "../../lib/srdb1/db_query.h"
- #include "mongodb_connection.h"
- #include "mongodb_dbase.h"
- #define DB_MONGODB_ROWS_STEP 1000
- typedef struct db_mongodb_result {
- mongoc_collection_t *collection; /*!< Collection link */
- mongoc_cursor_t *cursor; /*!< Cursor link */
- bson_t *rdoc;
- int idx;
- bson_t *colsdoc;
- int nrcols;
- int maxrows;
- } db_mongodb_result_t;
- /*
- * Initialize database module
- * No function should be called before this
- */
- db1_con_t* db_mongodb_init(const str* _url)
- {
- return db_do_init(_url, (void *)db_mongodb_new_connection);
- }
- /*
- * Shut down database module
- * No function should be called after this
- */
- void db_mongodb_close(db1_con_t* _h)
- {
- db_do_close(_h, db_mongodb_free_connection);
- }
- int db_mongodb_bson_add(bson_t *doc, const db_key_t _k, const db_val_t *_v, int idx)
- {
- int vtype;
- vtype = VAL_TYPE(_v);
- if(VAL_NULL(_v)) {
- if(!bson_append_null(doc, _k->s, _k->len)) {
- LM_ERR("failed to append int to bson doc %.*s = %d [%d]\n",
- _k->len, _k->s, VAL_INT(_v), idx);
- goto error;
- }
- goto done;
- }
- switch(vtype) {
- case DB1_INT:
- if(!bson_append_int32(doc, _k->s, _k->len,
- VAL_INT(_v))) {
- LM_ERR("failed to append int to bson doc %.*s = %d [%d]\n",
- _k->len, _k->s, VAL_INT(_v), idx);
- goto error;
- }
- break;
- case DB1_BIGINT:
- if(!bson_append_int64(doc, _k->s, _k->len,
- VAL_BIGINT(_v ))) {
- LM_ERR("failed to append bigint to bson doc %.*s = %lld [%d]\n",
- _k->len, _k->s, VAL_BIGINT(_v), idx);
- goto error;
- }
- return -1;
- case DB1_DOUBLE:
- if(!bson_append_double(doc, _k->s, _k->len,
- VAL_DOUBLE(_v))) {
- LM_ERR("failed to append double to bson doc %.*s = %f [%d]\n",
- _k->len, _k->s, VAL_DOUBLE(_v), idx);
- goto error;
- }
- break;
- case DB1_STRING:
- if(!bson_append_utf8(doc, _k->s, _k->len,
- VAL_STRING(_v), strlen(VAL_STRING(_v))) ) {
- LM_ERR("failed to append string to bson doc %.*s = %s [%d]\n",
- _k->len, _k->s, VAL_STRING(_v), idx);
- goto error;
- }
- break;
- case DB1_STR:
- if(!bson_append_utf8(doc, _k->s, _k->len,
- VAL_STR(_v).s, VAL_STR(_v).len) ) {
- LM_ERR("failed to append str to bson doc %.*s = %.*s [%d]\n",
- _k->len, _k->s, VAL_STR(_v).len, VAL_STR(_v).s, idx);
- goto error;
- }
- break;
- case DB1_DATETIME:
- if(!bson_append_time_t(doc, _k->s, _k->len,
- VAL_TIME(_v))) {
- LM_ERR("failed to append time to bson doc %.*s = %ld [%d]\n",
- _k->len, _k->s, VAL_TIME(_v), idx);
- goto error;
- }
- break;
- case DB1_BLOB:
- if(!bson_append_binary(doc, _k->s, _k->len,
- BSON_SUBTYPE_BINARY,
- (const uint8_t *)VAL_BLOB(_v).s, VAL_BLOB(_v).len) ) {
- LM_ERR("failed to append blob to bson doc %.*s = [bin] [%d]\n",
- _k->len, _k->s, idx);
- goto error;
- }
- break;
- case DB1_BITMAP:
- if(!bson_append_int32(doc, _k->s, _k->len,
- VAL_INT(_v))) {
- LM_ERR("failed to append bitmap to bson doc %.*s = %d [%d]\n",
- _k->len, _k->s, VAL_INT(_v), idx);
- goto error;
- }
- break;
- default:
- LM_ERR("val type [%d] not supported\n", vtype);
- return -1;
- }
- done:
- return 0;
- error:
- return -1;
- }
- /*!
- * \brief Get and convert columns from a result
- *
- * Get and convert columns from a result, fills the result structure
- * with data from the database.
- * \param _h database connection
- * \param _r database result set
- * \return 0 on success, negative on failure
- */
- int db_mongodb_get_columns(const db1_con_t* _h, db1_res_t* _r)
- {
- int col;
- db_mongodb_result_t *mgres;
- bson_iter_t riter;
- bson_iter_t citer;
- bson_t *cdoc;
- const char *colname;
- bson_type_t coltype;
- if ((!_h) || (!_r)) {
- LM_ERR("invalid parameter\n");
- return -1;
- }
- mgres = (db_mongodb_result_t*)RES_PTR(_r);
- if(!mgres->rdoc) {
- mgres->nrcols = 0;
- return 0;
- }
- if(mgres->nrcols==0 || mgres->colsdoc==NULL) {
- mgres->nrcols = (int)bson_count_keys(mgres->rdoc);
- if(mgres->nrcols==0) {
- LM_ERR("no keys in bson document\n");
- return -1;
- }
- cdoc = mgres->rdoc;
- } else {
- cdoc = mgres->colsdoc;
- }
- RES_COL_N(_r) = mgres->nrcols;
- if (!RES_COL_N(_r)) {
- LM_ERR("no columns returned from the query\n");
- return -2;
- } else {
- LM_DBG("%d columns returned from the query\n", RES_COL_N(_r));
- }
- if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) {
- RES_COL_N(_r) = 0;
- LM_ERR("could not allocate columns\n");
- return -3;
- }
- if (!bson_iter_init (&citer, cdoc)) {
- LM_ERR("failed to initialize columns iterator\n");
- return -3;
- }
- if(mgres->colsdoc) {
- if (!bson_iter_init (&riter, mgres->rdoc)) {
- LM_ERR("failed to initialize result iterator\n");
- return -3;
- }
- }
- col = 0;
- while (bson_iter_next (&citer)) {
- if(col >= RES_COL_N(_r)) {
- LM_ERR("invalid number of columns (%d/%d)\n", col, RES_COL_N(_r));
- return -4;
- }
- colname = bson_iter_key (&citer);
- LM_DBG("Found a field[%d] named: %s\n", col, colname);
- if(mgres->colsdoc) {
- if(!bson_iter_find(&riter, colname)) {
- LM_ERR("field [%s] not found in result iterator\n",
- colname);
- return -4;
- }
- coltype = bson_iter_type(&riter);
- } else {
- coltype = bson_iter_type(&citer);
- }
- RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str));
- if (! RES_NAMES(_r)[col]) {
- LM_ERR("no private memory left\n");
- db_free_columns(_r);
- return -4;
- }
- LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n",
- (unsigned long)sizeof(str), col, RES_NAMES(_r)[col]);
- /* pointer linked here is part of the result structure */
- RES_NAMES(_r)[col]->s = (char*)colname;
- RES_NAMES(_r)[col]->len = strlen(colname);
- switch(coltype) {
- case BSON_TYPE_BOOL:
- case BSON_TYPE_INT32:
- case BSON_TYPE_TIMESTAMP:
- LM_DBG("use DB1_INT result type\n");
- RES_TYPES(_r)[col] = DB1_INT;
- break;
- case BSON_TYPE_INT64:
- LM_DBG("use DB1_BIGINT result type\n");
- RES_TYPES(_r)[col] = DB1_BIGINT;
- break;
- case BSON_TYPE_DOUBLE:
- LM_DBG("use DB1_DOUBLE result type\n");
- RES_TYPES(_r)[col] = DB1_DOUBLE;
- break;
- case BSON_TYPE_DATE_TIME:
- LM_DBG("use DB1_DATETIME result type\n");
- RES_TYPES(_r)[col] = DB1_DATETIME;
- break;
- case BSON_TYPE_BINARY:
- LM_DBG("use DB1_BLOB result type\n");
- RES_TYPES(_r)[col] = DB1_BLOB;
- break;
- case BSON_TYPE_UTF8:
- LM_DBG("use DB1_STRING result type\n");
- RES_TYPES(_r)[col] = DB1_STRING;
- break;
- #if 0
- case BSON_TYPE_EOD:
- case BSON_TYPE_DOCUMENT:
- case BSON_TYPE_ARRAY:
- case BSON_TYPE_UNDEFINED:
- case BSON_TYPE_OID:
- case BSON_TYPE_NULL:
- case BSON_TYPE_REGEX:
- case BSON_TYPE_DBPOINTER:
- case BSON_TYPE_CODE:
- case BSON_TYPE_SYMBOL:
- case BSON_TYPE_CODEWSCOPE:
- case BSON_TYPE_MAXKEY:
- case BSON_TYPE_MINKEY:
- #endif
- default:
- LM_WARN("unhandled data type column (%.*s) type id (%d), "
- "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
- RES_NAMES(_r)[col]->s, coltype);
- RES_TYPES(_r)[col] = DB1_STRING;
- break;
- }
- LM_DBG("RES_NAMES(%p)[%d]=[%.*s] (%d)\n", RES_NAMES(_r)[col], col,
- RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, coltype);
- col++;
- }
- return 0;
- }
- /*!
- * \brief Convert rows from mongodb to db API representation
- * \param _h database connection
- * \param _r database result set
- * \return 0 on success, negative on failure
- */
- static int db_mongdob_convert_bson(const db1_con_t* _h, db1_res_t* _r,
- int _row, const bson_t *_rdoc)
- {
- static str dummy_string = {"", 0};
- int col;
- db_mongodb_result_t *mgres;
- const char *colname;
- bson_type_t coltype;
- bson_iter_t riter;
- bson_iter_t citer;
- bson_iter_t *piter;
- db_val_t* dval;
- uint32_t i32tmp;
- bson_subtype_t subtype;
- bson_t *cdoc;
- mgres = (db_mongodb_result_t*)RES_PTR(_r);
- if(mgres->nrcols==0) {
- LM_ERR("no fields to convert\n");
- return -1;
- }
- if(mgres->colsdoc==NULL) {
- cdoc = (bson_t*)_rdoc;
- } else {
- cdoc = (bson_t*)mgres->colsdoc;
- }
- if (!bson_iter_init (&citer, cdoc)) {
- LM_ERR("failed to initialize columns iterator\n");
- return -3;
- }
- if(mgres->colsdoc) {
- if (!bson_iter_init (&riter, _rdoc)) {
- LM_ERR("failed to initialize result iterator\n");
- return -3;
- }
- }
- if (db_allocate_row(_r, &(RES_ROWS(_r)[_row])) != 0) {
- LM_ERR("could not allocate row: %d\n", _row);
- return -2;
- }
- col = 0;
- while (bson_iter_next (&citer)) {
- if(col >= RES_COL_N(_r)) {
- LM_ERR("invalid number of columns (%d/%d)\n", col, RES_COL_N(_r));
- return -4;
- }
- colname = bson_iter_key (&citer);
- LM_DBG("looking for field[%d] named: %s\n", col, colname);
- if(mgres->colsdoc) {
- if(!bson_iter_find(&riter, colname)) {
- LM_ERR("field [%s] not found in result iterator\n",
- colname);
- return -4;
- }
- piter = &riter;
- } else {
- piter = &citer;
- }
- coltype = bson_iter_type(piter);
- dval = &(ROW_VALUES(&(RES_ROWS(_r)[_row]))[col]);
- VAL_TYPE(dval) = RES_TYPES(_r)[col];
- switch(coltype) {
- case BSON_TYPE_BOOL:
- VAL_INT(dval) = (int)bson_iter_bool (piter);
- break;
- case BSON_TYPE_INT32:
- VAL_INT(dval) = bson_iter_int32 (piter);
- break;
- case BSON_TYPE_TIMESTAMP:
- bson_iter_timestamp (piter,
- (uint32_t*)&VAL_INT(dval), &i32tmp);
- break;
- case BSON_TYPE_INT64:
- VAL_BIGINT(dval) = bson_iter_int64 (piter);
- break;
- case BSON_TYPE_DOUBLE:
- VAL_DOUBLE(dval) = bson_iter_double (piter);
- break;
- case BSON_TYPE_DATE_TIME:
- VAL_TIME(dval) = (time_t)(bson_iter_date_time (piter)/1000);
- break;
- case BSON_TYPE_BINARY:
- bson_iter_binary (piter, &subtype,
- (uint32_t*)&VAL_BLOB(dval).len, (const uint8_t**)&VAL_BLOB(dval).s);
- break;
- case BSON_TYPE_UTF8:
- VAL_STRING(dval) = (char*)bson_iter_utf8 (piter, &i32tmp);
- break;
- case BSON_TYPE_OID:
- break;
- case BSON_TYPE_NULL:
- memset(dval, 0, sizeof(db_val_t));
- /* Initialize the string pointers to a dummy empty
- * string so that we do not crash when the NULL flag
- * is set but the module does not check it properly
- */
- VAL_STRING(dval) = dummy_string.s;
- VAL_STR(dval) = dummy_string;
- VAL_BLOB(dval) = dummy_string;
- VAL_TYPE(dval) = RES_TYPES(_r)[col];
- VAL_NULL(dval) = 1;
- break;
- #if 0
- case BSON_TYPE_EOD:
- case BSON_TYPE_DOCUMENT:
- case BSON_TYPE_ARRAY:
- case BSON_TYPE_UNDEFINED:
- case BSON_TYPE_REGEX:
- case BSON_TYPE_DBPOINTER:
- case BSON_TYPE_CODE:
- case BSON_TYPE_SYMBOL:
- case BSON_TYPE_CODEWSCOPE:
- case BSON_TYPE_MAXKEY:
- case BSON_TYPE_MINKEY:
- #endif
- default:
- LM_WARN("unhandled data type column (%.*s) type id (%d), "
- "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
- RES_NAMES(_r)[col]->s, coltype);
- RES_TYPES(_r)[col] = DB1_STRING;
- break;
- }
- LM_DBG("RES_NAMES(%p)[%d]=[%.*s] (%d)\n", RES_NAMES(_r)[col], col,
- RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, coltype);
- col++;
- }
- return 0;
- }
- /*!
- * \brief Convert rows from mongodb to db API representation
- * \param _h database connection
- * \param _r database result set
- * \return 0 on success, negative on failure
- */
- static int db_mongdob_convert_result(const db1_con_t* _h, db1_res_t* _r)
- {
- int row;
- db_mongodb_result_t *mgres;
- const bson_t *itdoc;
- char *jstr;
- if ((!_h) || (!_r)) {
- LM_ERR("invalid parameter\n");
- return -1;
- }
- mgres = (db_mongodb_result_t*)RES_PTR(_r);
- if(!mgres->rdoc) {
- mgres->nrcols = 0;
- return 0;
- }
- if(mgres->nrcols==0) {
- LM_DBG("no fields to return\n");
- return 0;
- }
- if(!mongoc_cursor_more (mgres->cursor)) {
- RES_ROW_N(_r) = 1;
- mgres->maxrows = 1;
- } else {
- RES_ROW_N(_r) = DB_MONGODB_ROWS_STEP;
- mgres->maxrows = DB_MONGODB_ROWS_STEP;
- }
- if (db_allocate_rows(_r) < 0) {
- LM_ERR("could not allocate rows\n");
- RES_ROW_N(_r) = 0;
- return -2;
- }
- itdoc = mgres->rdoc;
- row = 0;
- do {
- if(row >= RES_ROW_N(_r)) {
- if (db_reallocate_rows(_r,
- RES_ROW_N(_r)+DB_MONGODB_ROWS_STEP) < 0) {
- LM_ERR("could not reallocate rows\n");
- return -2;
- }
- mgres->maxrows = RES_ROW_N(_r);
- }
- if(is_printable(L_DBG)) {
- jstr = bson_as_json (itdoc, NULL);
- LM_DBG("selected document: %s\n", jstr);
- bson_free (jstr);
- }
- if(db_mongdob_convert_bson(_h, _r, row, itdoc)) {
- LM_ERR("failed to convert bson at pos %d\n", row);
- return -1;
- }
- row++;
- } while (mongoc_cursor_more (mgres->cursor)
- && mongoc_cursor_next (mgres->cursor, &itdoc));
- RES_ROW_N(_r) = row;
- LM_DBG("retrieved number of rows: %d\n", row);
- return 0;
- }
- db1_res_t* db_mongodb_new_result(void)
- {
- db1_res_t* obj;
- obj = db_new_result();
- if (!obj)
- return NULL;
- RES_PTR(obj) = pkg_malloc(sizeof(db_mongodb_result_t));
- if (!RES_PTR(obj)) {
- db_free_result(obj);
- return NULL;
- }
- memset(RES_PTR(obj), 0, sizeof(db_mongodb_result_t));
- return obj;
- }
- /*
- * Retrieve result set
- */
- static int db_mongodb_store_result(const db1_con_t* _h, db1_res_t** _r)
- {
- km_mongodb_con_t *mgcon;
- db_mongodb_result_t *mgres;
- const bson_t *itdoc;
- mgcon = MONGODB_CON(_h);
- if(!_r) {
- LM_ERR("invalid result parameter\n");
- return -1;
- }
- *_r = db_mongodb_new_result();
- if (!*_r) {
- LM_ERR("no memory left for result \n");
- goto error;
- }
- mgres = (db_mongodb_result_t*)RES_PTR(*_r);
- mgres->collection = mgcon->collection;
- mgcon->collection = NULL;
- mgres->cursor = mgcon->cursor;
- mgcon->cursor = NULL;
- mgres->colsdoc = mgcon->colsdoc;
- mgcon->colsdoc = NULL;
- mgres->nrcols = mgcon->nrcols;
- mgcon->nrcols = 0;
- if(!mongoc_cursor_more (mgres->cursor)
- || !mongoc_cursor_next (mgres->cursor, &itdoc)
- || !itdoc) {
- LM_DBG("no result from mongodb\n");
- return 0;
- }
- /* first document linked internally in result to get columns */
- mgres->rdoc = (bson_t*)itdoc;
- if(db_mongodb_get_columns(_h, *_r)<0) {
- LM_ERR("failed to set the columns\n");
- goto error;
- }
- if(db_mongdob_convert_result(_h, *_r)<0) {
- LM_ERR("failed to set the rows in result\n");
- goto error;
- }
- return 0;
- error:
- if(mgcon->colsdoc) {
- bson_destroy (mgcon->colsdoc);
- mgcon->colsdoc = NULL;
- }
- mgcon->nrcols = 0;
- if(mgcon->cursor) {
- mongoc_cursor_destroy (mgcon->cursor);
- mgcon->cursor = NULL;
- }
- if(mgcon->collection) {
- mongoc_collection_destroy (mgcon->collection);
- mgcon->collection = NULL;
- }
- return -1;
- }
- /*
- * Release a result set from memory
- */
- int db_mongodb_free_result(db1_con_t* _h, db1_res_t* _r)
- {
- if(!_r)
- return -1;
- if(RES_PTR(_r)) {
- if(((db_mongodb_result_t*)RES_PTR(_r))->rdoc) {
- bson_destroy(((db_mongodb_result_t*)RES_PTR(_r))->rdoc);
- ((db_mongodb_result_t*)RES_PTR(_r))->rdoc = NULL;
- }
- if(((db_mongodb_result_t*)RES_PTR(_r))->colsdoc) {
- bson_destroy (((db_mongodb_result_t*)RES_PTR(_r))->colsdoc);
- ((db_mongodb_result_t*)RES_PTR(_r))->colsdoc = NULL;
- }
- ((db_mongodb_result_t*)RES_PTR(_r))->nrcols = 0;
- if(((db_mongodb_result_t*)RES_PTR(_r))->cursor) {
- mongoc_cursor_destroy (((db_mongodb_result_t*)RES_PTR(_r))->cursor);
- ((db_mongodb_result_t*)RES_PTR(_r))->cursor = NULL;
- }
- if(((db_mongodb_result_t*)RES_PTR(_r))->collection) {
- mongoc_collection_destroy (((db_mongodb_result_t*)RES_PTR(_r))->collection);
- ((db_mongodb_result_t*)RES_PTR(_r))->collection = NULL;
- }
- pkg_free(RES_PTR(_r));
- }
- db_free_result(_r);
- return 0;
- }
- /*
- * Query table for specified rows
- * _h: structure representing database connection
- * _k: key names
- * _op: operators
- * _v: values of the keys that must match
- * _c: column names to return
- * _n: number of key=values pairs to compare
- * _nc: number of columns to return
- * _o: order by the specified column
- */
- int db_mongodb_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
- const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
- const db_key_t _o, db1_res_t** _r)
- {
- int i;
- km_mongodb_con_t *mgcon;
- mongoc_client_t *client;
- bson_t *seldoc = NULL;
- char *cname;
- char b1;
- char *jstr;
- mgcon = MONGODB_CON(_h);
- if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
- LM_ERR("connection to server is null\n");
- return -1;
- }
- if(mgcon->collection) {
- mongoc_collection_destroy (mgcon->collection);
- mgcon->collection = NULL;
- }
- if(mgcon->cursor) {
- mongoc_cursor_destroy (mgcon->cursor);
- mgcon->cursor = NULL;
- }
- if(mgcon->colsdoc) {
- bson_destroy (mgcon->colsdoc);
- mgcon->colsdoc = NULL;
- }
- mgcon->nrcols = 0;
- client = mgcon->con;
- if(CON_TABLE(_h)->s==NULL) {
- LM_ERR("collection (table) name not set\n");
- return -1;
- }
- if(_r) *_r = NULL;
- b1 = '\0';
- if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
- b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
- CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
- }
- cname = CON_TABLE(_h)->s;
- LM_DBG("query to collection [%s]\n", cname);
- mgcon->collection = mongoc_client_get_collection(client, mgcon->id->database, cname);
- if(mgcon->collection==NULL) {
- LM_ERR("cannot get collection (table): %s\n", cname);
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- return -1;
- }
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- seldoc = bson_new();
- if(seldoc==NULL) {
- LM_ERR("cannot initialize query bson document\n");
- goto error;
- }
- for(i = 0; i < _n; i++) {
- if(db_mongodb_bson_add(seldoc, _k[i], _v+i, i)<0)
- goto error;
- }
- if(is_printable(L_DBG)) {
- jstr = bson_as_json (seldoc, NULL);
- LM_DBG("query filter: %s\n", jstr);
- bson_free (jstr);
- }
- if(_nc > 0) {
- mgcon->colsdoc = bson_new();
- if(mgcon->colsdoc==NULL) {
- LM_ERR("cannot initialize columns bson document\n");
- goto error;
- }
- for(i = 0; i < _nc; i++) {
- if(!bson_append_int32(mgcon->colsdoc, _c[i]->s, _c[i]->len, 1))
- {
- LM_ERR("failed to append int to columns bson %.*s = %d [%d]\n",
- _c[i]->len, _c[i]->s, 1, i);
- goto error;
- }
- }
- if(is_printable(L_DBG)) {
- jstr = bson_as_json (mgcon->colsdoc, NULL);
- LM_DBG("columns filter: %s\n", jstr);
- bson_free (jstr);
- }
- mgcon->nrcols = _nc;
- }
- mgcon->cursor = mongoc_collection_find (mgcon->collection,
- MONGOC_QUERY_NONE, 0, 0, 0,
- seldoc, mgcon->colsdoc, NULL);
- if(!_r) {
- goto done;
- }
- if(db_mongodb_store_result(_h, _r)<0) {
- LM_ERR("failed to store result\n");
- goto error;
- }
- done:
- bson_destroy (seldoc);
- return 0;
- error:
- LM_ERR("failed to do the query\n");
- if(seldoc) bson_destroy (seldoc);
- if(mgcon->colsdoc) {
- bson_destroy (mgcon->colsdoc);
- mgcon->colsdoc = NULL;
- }
- mgcon->nrcols = 0;
- if(mgcon->collection) {
- mongoc_collection_destroy (mgcon->collection);
- mgcon->collection = NULL;
- }
- if(mgcon->cursor) {
- mongoc_cursor_destroy (mgcon->cursor);
- mgcon->cursor = NULL;
- }
- if(_r && *_r) { db_mongodb_free_result((db1_con_t*)_h, *_r); *_r = NULL; }
- return -1;
- }
- /*!
- * \brief Gets a partial result set, fetch rows from a result
- *
- * Gets a partial result set, fetch a number of rows from a databae result.
- * This function initialize the given result structure on the first run, and
- * fetches the nrows number of rows. On subsequenting runs, it uses the
- * existing result and fetches more rows, until it reaches the end of the
- * result set. Because of this the result needs to be null in the first
- * invocation of the function. If the number of wanted rows is zero, the
- * function returns anything with a result of zero.
- * \param _h structure representing the database connection
- * \param _r pointer to a structure representing the result
- * \param nrows number of fetched rows
- * \return return zero on success, negative value on failure
- */
- int db_mongodb_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows)
- {
- return -1;
- }
- /*
- * Execute a raw SQL query
- */
- int db_mongodb_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r)
- {
- return -1;
- }
- /*
- * Insert a row into specified table
- * _h: structure representing database connection
- * _k: key names
- * _v: values of the keys
- * _n: number of key=value pairs
- */
- int db_mongodb_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n)
- {
- int i;
- km_mongodb_con_t *mgcon;
- mongoc_client_t *client;
- mongoc_collection_t *collection = NULL;
- bson_error_t error;
- bson_t *doc = NULL;
- char *cname;
- char *jstr;
- char b1;
- mgcon = MONGODB_CON(_h);
- if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
- LM_ERR("connection to server is null\n");
- return -1;
- }
- client = mgcon->con;
- if(CON_TABLE(_h)->s==NULL) {
- LM_ERR("collection (table) name not set\n");
- return -1;
- }
- b1 = '\0';
- if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
- b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
- CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
- }
- cname = CON_TABLE(_h)->s;
- collection = mongoc_client_get_collection(client, mgcon->id->database, cname);
- if(collection==NULL) {
- LM_ERR("cannot get collection (table): %s\n", cname);
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- return -1;
- }
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- doc = bson_new();
- if(doc==NULL) {
- LM_ERR("cannot initialize bson document\n");
- goto error;
- }
- for(i = 0; i < _n; i++) {
- if(db_mongodb_bson_add(doc, _k[i], _v+i, i)<0)
- goto error;
- }
- if(is_printable(L_DBG)) {
- jstr = bson_as_json (doc, NULL);
- LM_DBG("insert document: %s\n", jstr);
- bson_free (jstr);
- }
- if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) {
- LM_ERR("failed to insert in collection: %s\n", error.message);
- goto error;
- }
- bson_destroy (doc);
- mongoc_collection_destroy (collection);
-
- return 0;
- error:
- if(doc) bson_destroy (doc);
- if(collection) mongoc_collection_destroy (collection);
- return -1;
- }
- /*
- * Delete a row from the specified table
- * _h: structure representing database connection
- * _k: key names
- * _o: operators
- * _v: values of the keys that must match
- * _n: number of key=value pairs
- */
- int db_mongodb_delete(const db1_con_t* _h, const db_key_t* _k,
- const db_op_t* _o, const db_val_t* _v, const int _n)
- {
- int i;
- km_mongodb_con_t *mgcon;
- mongoc_client_t *client;
- mongoc_collection_t *collection = NULL;
- bson_error_t error;
- bson_t *doc = NULL;
- char *cname;
- char *jstr;
- char b1;
- mgcon = MONGODB_CON(_h);
- if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
- LM_ERR("connection to server is null\n");
- return -1;
- }
- client = mgcon->con;
- if(CON_TABLE(_h)->s==NULL) {
- LM_ERR("collection (table) name not set\n");
- return -1;
- }
- b1 = '\0';
- if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
- b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
- CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
- }
- cname = CON_TABLE(_h)->s;
- collection = mongoc_client_get_collection(client, mgcon->id->database,
- cname);
- if(collection==NULL) {
- LM_ERR("cannot get collection (table): %s\n", cname);
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- return -1;
- }
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- doc = bson_new();
- if(doc==NULL) {
- LM_ERR("cannot initialize bson document\n");
- goto error;
- }
- for(i = 0; i < _n; i++) {
- if(db_mongodb_bson_add(doc, _k[i], _v+i, i)<0)
- goto error;
- }
- if(is_printable(L_DBG)) {
- jstr = bson_as_json (doc, NULL);
- LM_DBG("delete filter document: %s\n", jstr);
- bson_free (jstr);
- }
- if (!mongoc_collection_remove (collection, MONGOC_REMOVE_NONE,
- doc, NULL, &error)) {
- LM_ERR("failed to delete in collection: %s\n", error.message);
- goto error;
- }
- bson_destroy (doc);
- mongoc_collection_destroy (collection);
-
- return 0;
- error:
- if(doc) bson_destroy (doc);
- if(collection) mongoc_collection_destroy (collection);
- return -1;
- }
- /*
- * Update some rows in the specified table
- * _h: structure representing database connection
- * _k: key names
- * _o: operators
- * _v: values of the keys that must match
- * _uk: updated columns
- * _uv: updated values of the columns
- * _n: number of key=value pairs
- * _un: number of columns to update
- */
- int db_mongodb_update(const db1_con_t* _h, const db_key_t* _k,
- const db_op_t* _o, const db_val_t* _v, const db_key_t* _uk,
- const db_val_t* _uv, const int _n, const int _un)
- {
- int i;
- km_mongodb_con_t *mgcon;
- mongoc_client_t *client;
- mongoc_collection_t *collection = NULL;
- bson_error_t error;
- bson_t *mdoc = NULL;
- bson_t *udoc = NULL;
- char *cname;
- char b1;
- mgcon = MONGODB_CON(_h);
- if(mgcon==NULL || mgcon->id== NULL || mgcon->con==NULL) {
- LM_ERR("connection to server is null\n");
- return -1;
- }
- client = mgcon->con;
- if(CON_TABLE(_h)->s==NULL) {
- LM_ERR("collection (table) name not set\n");
- return -1;
- }
- b1 = '\0';
- if(CON_TABLE(_h)->s[CON_TABLE(_h)->len]!='\0') {
- b1 = CON_TABLE(_h)->s[CON_TABLE(_h)->len];
- CON_TABLE(_h)->s[CON_TABLE(_h)->len] = '\0';
- }
- cname = CON_TABLE(_h)->s;
- collection = mongoc_client_get_collection(client, mgcon->id->database,
- cname);
- if(collection==NULL) {
- LM_ERR("cannot get collection (table): %s\n", cname);
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- return -1;
- }
- if(b1 != '\0') CON_TABLE(_h)->s[CON_TABLE(_h)->len] = b1;
- udoc = bson_new();
- if(udoc==NULL) {
- LM_ERR("cannot initialize update bson document\n");
- goto error;
- }
- mdoc = bson_new();
- if(mdoc==NULL) {
- LM_ERR("cannot initialize match bson document\n");
- goto error;
- }
- for(i = 0; i < _un; i++) {
- if(db_mongodb_bson_add(udoc, _uk[i], _uv+i, i)<0)
- goto error;
- }
- for(i = 0; i < _n; i++) {
- if(db_mongodb_bson_add(mdoc, _k[i], _v+i, i)<0)
- goto error;
- }
- if (!mongoc_collection_find_and_modify (collection, mdoc, NULL, udoc, NULL,
- false, false, false, NULL, &error)) {
- LM_ERR("failed to update in collection: %s\n", error.message);
- goto error;
- }
- bson_destroy (mdoc);
- bson_destroy (udoc);
- mongoc_collection_destroy (collection);
-
- return 0;
- error:
- if(mdoc) bson_destroy (mdoc);
- if(udoc) bson_destroy (udoc);
- if(collection) mongoc_collection_destroy (collection);
- return -1;
- }
- /*
- * Just like insert, but replace the row if it exists
- */
- int db_mongodb_replace(const db1_con_t* _h, const db_key_t* _k,
- const db_val_t* _v, const int _n, const int _un, const int _m)
- {
- return -1;
- }
- /*
- * Store name of table that will be used by
- * subsequent database functions
- */
- int db_mongodb_use_table(db1_con_t* _h, const str* _t)
- {
- return db_use_table(_h, _t);
- }
|