/*! * \brief Allocate new result set with private structure * \return db1_res_t object on success, NULL on failure */ db1_res_t* db_mysql_new_result(void) { db1_res_t* obj; obj = db_new_result(); if (!obj) return NULL; RES_PTR(obj) = pkg_malloc(sizeof(struct my_res)); if (!RES_PTR(obj)) { db_free_result(obj); return NULL; } return obj; }
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_mongodb_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. * \param _h handle to the database * \param _r result set that should be freed * \return zero on success, negative value on failure */ int db_mysql_free_result(const db1_con_t* _h, db1_res_t* _r) { if ((!_h) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } mysql_free_result(RES_RESULT(_r)); RES_RESULT(_r) = 0; pkg_free(RES_PTR(_r)); if (db_free_result(_r) < 0) { LM_ERR("unable to free result structure\n"); return -1; } return 0; }
/* * 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; }
/*! * \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_mongodb_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_mongodb_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; }
/*! * \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_mongodb_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 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_INFO("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; }