浏览代码

db_mongodb: new module offering DB APIv1 connector for MongoDB NoSQL server

- initial version, tested for INSERT (e.g., can be used with acc module)
- UPDATE and DELETE implemented as well, no option to test them yet
  alone
- SELECT implemented for basic queries, but store result not implemented
  yet -- needs to map the requested fields and types (to be fixed very
  soon)
- no raw query yet (an ndb alternative to follow)
Daniel-Constantin Mierla 11 年之前
父节点
当前提交
53771bd598

+ 27 - 0
modules/db_mongodb/Makefile

@@ -0,0 +1,27 @@
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=db_mongodb.so
+
+ifeq ($(CROSS_COMPILE),)
+MONGODBC_BUILDER=$(shell \
+	if pkg-config --exists libmongoc-1.0; then \
+		echo 'pkg-config libmongoc-1.0'; \
+	fi)
+endif
+
+ifneq ($(MONGODBC_BUILDER),)
+	DEFS += $(shell $(MONGODBC_BUILDER) --cflags)
+	LIBS += $(shell $(MONGODBC_BUILDER) --libs)
+else
+	DEFS += -I$(LOCALBASE)/include
+	LIBS= -L$(LOCALBASE)/lib -lmongoc
+endif
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
+include ../../Makefile.modules

+ 97 - 0
modules/db_mongodb/README

@@ -0,0 +1,97 @@
+DB_MONGODB Module
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+Edited by
+
+Daniel-Constantin Mierla
+
+   <[email protected]>
+
+   Copyright © 2014 asipto.com
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+
+              1.1. Limitations
+
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Usage
+
+   List of Examples
+
+   1.1. Usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+
+        1.1. Limitations
+
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Usage
+
+1. Overview
+
+   1.1. Limitations
+
+   This module provides DB APIv1 connector for MongoDB NoSQL server.
+
+   It can be used as a replacement for other database modules such as
+   db_mysql, db_postgres, a.s.o. Not all the specs of DB APIv1 are
+   implemented, thus the usage of this module might be restricted to
+   specific modules.
+
+   You can read more about MongoDB at: http://www.mongodb.org.
+
+1.1. Limitations
+
+     * This module has implemented INSERT, UPDATE and DELETE. Query
+       (SELECT) is not yet storing the result.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The following modules must be loaded before this module:
+     * none.
+
+2.2. External Libraries or Applications
+
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
+     * mongo-c-driver - available at
+       https://github.com/mongodb/mongo-c-driver
+
+3. Usage
+
+   Load the module and set the the DB URL for specific modules to:
+   mongodb://username:password@host:port/database. Username, password and
+   port are optional.
+
+   Example 1.1. Usage
+...
+loadmodule "db_mongodb.so"
+...
+#!define DBURL "mongodb://localhost/kamailio"
+modparam("acc", "db_url", DBURL)
+...

+ 101 - 0
modules/db_mongodb/db_mongodb_mod.c

@@ -0,0 +1,101 @@
+/**
+ * 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../../sr_module.h"
+#include "../../dprint.h"
+#include "../../lib/srdb1/db.h"
+#include "../../lib/srdb1/db_query.h"
+
+#include "mongodb_dbase.h"
+
+MODULE_VERSION
+
+static int db_mongodb_bind_api(db_func_t *dbb);
+static int mod_init(void);
+
+static cmd_export_t cmds[] = {
+	{"db_bind_api",    (cmd_function)db_mongodb_bind_api,    0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0}
+};
+
+
+/*
+ * Exported parameters
+ */
+static param_export_t params[] = {
+	{0, 0, 0}
+};
+
+
+struct module_exports exports = {	
+	"db_mongodb",
+	DEFAULT_DLFLAGS, /* dlopen flags */
+	cmds,
+	params,             /*  module parameters */
+	0,                  /* exported statistics */
+	0,                  /* exported MI functions */
+	0,                  /* exported pseudo-variables */
+	0,                  /* extra processes */
+	mod_init,           /* module initialization function */
+	0,                  /* response function*/
+	0,                  /* destroy function */
+	0                   /* per-child init function */
+};
+
+static int db_mongodb_bind_api(db_func_t *dbb)
+{
+	if(dbb==NULL)
+		return -1;
+
+	memset(dbb, 0, sizeof(db_func_t));
+
+	dbb->use_table        = db_mongodb_use_table;
+	dbb->init             = db_mongodb_init;
+	dbb->close            = db_mongodb_close;
+	dbb->query            = db_mongodb_query;
+	dbb->fetch_result     = db_mongodb_fetch_result;
+	dbb->raw_query        = db_mongodb_raw_query;
+	dbb->free_result      = db_mongodb_free_result;
+	dbb->insert           = db_mongodb_insert;
+	dbb->delete           = db_mongodb_delete; 
+	dbb->update           = db_mongodb_update;
+	dbb->replace          = db_mongodb_replace;
+
+	return 0;
+}
+
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
+{
+	if(db_api_init()<0)
+		return -1;
+	return 0;
+}
+
+static int mod_init(void)
+{
+	LM_DBG("module initializing\n");
+	return 0;
+}
+

+ 4 - 0
modules/db_mongodb/doc/Makefile

@@ -0,0 +1,4 @@
+docs = db_mongodb.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 37 - 0
modules/db_mongodb/doc/db_mongodb.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+    <bookinfo>
+	<title>DB_MONGODB Module</title>
+	<productname class="trade">kamailio.org</productname>
+	<authorgroup>
+	    <author>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </author>
+	    <editor>
+		<firstname>Daniel-Constantin</firstname>
+		<surname>Mierla</surname>
+		<email>[email protected]</email>
+	    </editor>
+	</authorgroup>
+	<copyright>
+	    <year>2014</year>
+	    <holder>asipto.com</holder>
+	</copyright>
+    </bookinfo>
+    <toc></toc>
+    
+    <xi:include href="db_mongodb_admin.xml"/>
+    
+    
+</book>

+ 96 - 0
modules/db_mongodb/doc/db_mongodb_admin.xml

@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+<!-- Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+		This module provides DB APIv1 connector for MongoDB NoSQL server.
+	</para>
+	<para>
+	It can be used as a replacement for other database modules such as
+	db_mysql, db_postgres, a.s.o. Not all the specs of DB APIv1 are
+	implemented, thus the usage of this module might be restricted to
+	specific modules.
+	</para>
+	<para>
+		You can read more about MongoDB at:
+		<ulink url="http://www.mongodb.org">http://www.mongodb.org</ulink>.
+	</para>
+
+	<section>
+	<title>Limitations</title>
+	<itemizedlist>
+	<listitem>
+	<para>
+		This module has implemented INSERT, UPDATE and DELETE. Query
+		(SELECT) is not yet storing the result.
+	</para>
+	</listitem>
+	</itemizedlist>
+	</section>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The following modules must be loaded before this module:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>none</emphasis>.
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries or applications must be installed before running
+		&kamailio; with this module loaded:
+			<itemizedlist>
+			<listitem>
+			<para>
+				<emphasis>mongo-c-driver</emphasis> - available at
+				<ulink url="https://github.com/mongodb/mongo-c-driver">https://github.com/mongodb/mongo-c-driver</ulink>
+			</para>
+			</listitem>
+			</itemizedlist>
+		</para>
+	</section>
+	</section>
+	<section>
+	<title>Usage</title>
+		<para>
+			Load the module and set the the DB URL for specific modules to:
+			mongodb://username:password@host:port/database. Username, password
+			and port are optional.
+		</para>
+		<example>
+		<title>Usage</title>
+		<programlisting format="linespecific">
+...
+loadmodule "db_mongodb.so"
+...
+#!define DBURL "mongodb://localhost/kamailio"
+modparam("acc", "db_url", DBURL)
+...
+</programlisting>
+		</example>
+	</section>
+</chapter>
+

+ 82 - 0
modules/db_mongodb/mongodb_connection.c

@@ -0,0 +1,82 @@
+/* 
+ * 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 "../../ut.h"
+#include "mongodb_connection.h"
+
+/*! \brief
+ * Create a new connection structure,
+ * open the mongodb connection and set reference count to 1
+ */
+km_mongodb_con_t* db_mongodb_new_connection(const struct db_id* id)
+{
+	km_mongodb_con_t *ptr;
+
+	if (!id) {
+		LM_ERR("invalid parameter value\n");
+		return 0;
+	}
+
+	ptr = (km_mongodb_con_t*)pkg_malloc(sizeof(km_mongodb_con_t));
+	if (!ptr) {
+		LM_ERR("no private memory left\n");
+		return 0;
+	}
+
+	memset(ptr, 0, sizeof(km_mongodb_con_t));
+	ptr->ref = 1;
+
+	mongoc_init();
+	ptr->con = mongoc_client_new (id->url.s);
+	if (!ptr->con) {
+		LM_ERR("cannot open connection: %.*s\n", id->url.len, id->url.s);
+		goto err;
+	}
+
+	LM_DBG("connection open to: %.*s\n", id->url.len, id->url.s);
+
+	ptr->id = (struct db_id*)id;
+	return ptr;
+
+ err:
+	if (ptr) pkg_free(ptr);
+	return 0;
+}
+
+
+/*! \brief
+ * Close the connection and release memory
+ */
+void db_mongodb_free_connection(struct pool_con* con)
+{
+	km_mongodb_con_t * _c;
+	
+	if (!con) return;
+
+	_c = (km_mongodb_con_t*) con;
+
+	if (_c->id) free_db_id(_c->id);
+	if (_c->con) {
+		mongoc_client_destroy(_c->con);
+	}
+	pkg_free(_c);
+}

+ 44 - 0
modules/db_mongodb/mongodb_connection.h

@@ -0,0 +1,44 @@
+/**
+ * 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
+ *
+ */
+
+
+#ifndef _MONGODB_CONNECTION_H_
+#define _MONGODB_CONNECTION_H_
+
+#include <mongoc.h>
+#include <bson.h>
+
+#include "../../lib/srdb1/db_pool.h"
+#include "../../lib/srdb1/db_id.h"
+
+typedef struct km_mongodb_con {
+	struct db_id* id;        /*!< Connection identifier */
+    unsigned int ref;        /*!< Reference count */
+    struct pool_con* next;   /*!< Next connection in the pool */
+
+    mongoc_client_t *con;              /*!< Connection representation */
+} km_mongodb_con_t;
+
+#define MONGODB_CON(db_con)  ((km_mongodb_con_t*)((db_con)->tail))
+
+km_mongodb_con_t* db_mongodb_new_connection(const struct db_id* id);
+void db_mongodb_free_connection(struct pool_con* con);
+#endif

+ 516 - 0
modules/db_mongodb/mongodb_dbase.c

@@ -0,0 +1,516 @@
+/*
+ * 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"
+
+
+/*
+ * 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, int vtype, const db_key_t _k, const db_val_t *_v, int idx)
+{
+	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;
+	}
+
+	return 0;
+error:
+	return -1;
+}
+/*
+ * Retrieve result set
+ */
+static int db_mongodb_store_result(const db1_con_t* _h, db1_res_t** _r)
+{
+	if(_r) *_r = NULL;
+
+	return 0;
+}
+
+/*
+ * Release a result set from memory
+ */
+int db_mongodb_free_result(db1_con_t* _h, db1_res_t* _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;
+	mongoc_collection_t *collection = NULL;
+	bson_t *doc = NULL;
+	const bson_t *itdoc;
+	mongoc_cursor_t *cursor = 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;
+	}
+	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, VAL_TYPE(_v + i), _k[i], _v+i, i)<0)
+			goto error;
+	}
+
+	cursor = mongoc_collection_find (collection, MONGOC_QUERY_NONE, 0, 0, 0,
+			doc, NULL, NULL);
+	while (mongoc_cursor_more (cursor) && mongoc_cursor_next (cursor, &itdoc)) {
+		jstr = bson_as_json (itdoc, NULL);
+		LM_DBG("selected document: %s\n", jstr);
+		if(db_mongodb_store_result(_h, _r)<0) {
+			LM_ERR("failed to store result\n");
+			bson_free (jstr);
+			goto error;
+		}
+		bson_free (jstr);
+	}
+	mongoc_cursor_destroy (cursor);
+	bson_destroy (doc);
+	mongoc_collection_destroy (collection);
+	
+	return 0;
+error:
+	if(cursor) mongoc_cursor_destroy (cursor);
+	if(doc) bson_destroy (doc);
+	if(collection) mongoc_collection_destroy (collection);
+	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 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, VAL_TYPE(_v + i), _k[i], _v+i, i)<0)
+			goto error;
+	}
+
+	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 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, VAL_TYPE(_v + i), _k[i], _v+i, i)<0)
+			goto error;
+	}
+
+	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, VAL_TYPE(_uv + i), _uk[i], _uv+i, i)<0)
+			goto error;
+	}
+
+	for(i = 0; i < _n; i++) {
+		if(db_mongodb_bson_add(mdoc, VAL_TYPE(_v + i), _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);
+}

+ 92 - 0
modules/db_mongodb/mongodb_dbase.h

@@ -0,0 +1,92 @@
+/*
+ * 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
+ *
+ */
+
+
+#ifndef _MONGODB_DBASE_H_
+#define _MONGODB_DBASE_H_
+
+#include "../../lib/srdb1/db_con.h"
+#include "../../lib/srdb1/db_res.h"
+#include "../../lib/srdb1/db_key.h"
+#include "../../lib/srdb1/db_op.h"
+#include "../../lib/srdb1/db_val.h"
+
+/*
+ * Initialize database connection
+ */
+db1_con_t* db_mongodb_init(const str* _sqlurl);
+
+/*
+ * Close a database connection
+ */
+void db_mongodb_close(db1_con_t* _h);
+
+/*
+ * Free all memory allocated by get_result
+ */
+int db_mongodb_free_result(db1_con_t* _h, db1_res_t* _r);
+
+/*
+ * Do a query
+ */
+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);
+
+/*
+ * Fetch rows from a result
+ */
+int db_mongodb_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows);
+
+/*
+ * Raw SQL query
+ */
+int db_mongodb_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r);
+
+/*
+ * Insert a row into table
+ */
+int db_mongodb_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n);
+
+/*
+ * Delete a row from table
+ */
+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);
+
+/*
+ * Update a row in table
+ */
+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);
+
+/*
+ * Just like insert, but replace the row if it exists
+ */
+int db_mongodb_replace(const db1_con_t* handle, const db_key_t* keys, const db_val_t* vals,
+		const int n, const int _un, const int _m);
+
+/*
+ * Store name of table that will be used by
+ * subsequent database functions
+ */
+int db_mongodb_use_table(db1_con_t* _h, const str* _t);
+
+#endif  /* _MONGODB_BASE_H_ */