]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-10801: [core] Add a database interface to the FreeSWITCH Core.
authorAndrey Volk <andywolk@gmail.com>
Mon, 2 Apr 2018 11:02:19 +0000 (14:02 +0300)
committerAndrey Volk <andywolk@gmail.com>
Mon, 15 Jul 2019 18:18:19 +0000 (22:18 +0400)
src/include/private/switch_core_pvt.h
src/include/switch_core.h
src/include/switch_loadable_module.h
src/include/switch_module_interfaces.h
src/include/switch_types.h
src/switch_core.c
src/switch_core_sqldb.c
src/switch_loadable_module.c

index 8f8076a5bf34f5a2688e295fbfc15cadb5afef75..6057734123b1eeb5e01d7b5fc9b8f83b8cf14c32 100644 (file)
@@ -24,6 +24,7 @@
  * Contributor(s):
  *
  * Anthony Minessale II <anthm@freeswitch.org>
+ * Andrey Volk <andywolk@gmail.com>
  *
  *
  * switch_core.h -- Core Library Private Data (not to be installed into the system)
@@ -334,6 +335,8 @@ extern struct switch_session_manager session_manager;
 
 
 
+switch_status_t switch_core_sqldb_init(const char **err);
+void switch_core_sqldb_destroy();
 switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_t manage);
 void switch_core_sqldb_stop(void);
 void switch_core_session_init(switch_memory_pool_t *pool);
index 7631fc287fe6006354b54bc5a6e07efabfacc3d8..e82690dfef8da230a0bd74892d740a5e0a618a8e 100644 (file)
@@ -27,6 +27,7 @@
  * Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
  * Joseph Sullivan <jossulli@amazon.com>
  * Emmanuel Schmidbauer <eschmidbauer@gmail.com>
+ * Andrey Volk <andywolk@gmail.com>
  *
  * switch_core.h -- Core Library
  *
@@ -2474,13 +2475,15 @@ typedef enum {
 typedef enum {
        SCDB_TYPE_CORE_DB,
        SCDB_TYPE_ODBC,
-       SCDB_TYPE_PGSQL
+       SCDB_TYPE_PGSQL,
+       SCDB_TYPE_DATABASE_INTERFACE
 } switch_cache_db_handle_type_t;
 
 typedef union {
        switch_core_db_t *core_db_dbh;
        switch_odbc_handle_t *odbc_dbh;
        switch_pgsql_handle_t *pgsql_dbh;
+       switch_database_interface_handle_t *database_interface_dbh;
 } switch_cache_db_native_handle_t;
 
 typedef struct {
@@ -2497,10 +2500,18 @@ typedef struct {
        char *dsn;
 } switch_cache_db_pgsql_options_t;
 
+typedef struct {
+       char *dsn;
+       char prefix[16];
+       switch_database_interface_t *database_interface;
+       switch_bool_t make_module_no_unloadable;
+} switch_cache_db_database_interface_options_t;
+
 typedef union {
        switch_cache_db_core_db_options_t core_db_options;
        switch_cache_db_odbc_options_t odbc_options;
        switch_cache_db_pgsql_options_t pgsql_options;
+       switch_cache_db_database_interface_options_t database_interface_options;
 } switch_cache_db_connection_options_t;
 
 struct switch_cache_db_handle;
@@ -2511,6 +2522,11 @@ static inline const char *switch_cache_db_type_name(switch_cache_db_handle_type_
        const char *type_str = "INVALID";
 
        switch (type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       type_str = "DATABASE_INTERFACE";
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        type_str = "PGSQL";
@@ -2559,6 +2575,8 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
                                                                                                                           const char *file, const char *func, int line);
 #define switch_cache_db_get_db_handle(_a, _b, _c) _switch_cache_db_get_db_handle(_a, _b, _c, __FILE__, __SWITCH_FUNC__, __LINE__)
 
+SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn_ex(switch_cache_db_handle_t **dbh, const char *dsn, switch_bool_t make_module_no_unloadable,
+                                                                                                                                         const char *file, const char *func, int line);
 SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn(switch_cache_db_handle_t **dbh, const char *dsn,
                                                                                                                                   const char *file, const char *func, int line);
 #define switch_cache_db_get_db_handle_dsn(_a, _b) _switch_cache_db_get_db_handle_dsn(_a, _b, __FILE__, __SWITCH_FUNC__, __LINE__)
@@ -2643,6 +2661,13 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw
                                                                                                                                                          const char *inner_post_trans_execute);
 #define switch_cache_db_persistant_execute_trans(_d, _s, _r) switch_cache_db_persistant_execute_trans_full(_d, _s, _r, NULL, NULL, NULL, NULL)
 
+SWITCH_DECLARE(void) switch_cache_db_database_interface_flush_handles(switch_database_interface_t *database_interface);
+
+/*!
+\brief Returns error if no suitable database interface found to serve core db dsn.
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_check_core_db_dsn();
+
 SWITCH_DECLARE(void) switch_core_set_signal_handlers(void);
 SWITCH_DECLARE(uint32_t) switch_core_debug_level(void);
 SWITCH_DECLARE(int32_t) switch_core_sps(void);
index 87295a641bf73b8de8ebc0ecb8e009eb6b9c655d..be32c99e2ecbf25d0b26be2aabcea33954db57fc 100644 (file)
@@ -24,6 +24,7 @@
  * Contributor(s):
  *
  * Anthony Minessale II <anthm@freeswitch.org>
+ * Andrey Volk <andywolk@gmail.com>
  *
  *
  * switch_loadable_module.h -- Loadable Modules
@@ -51,6 +52,14 @@ SWITCH_BEGIN_EXTERN_C
   \ingroup core1
   \{
 */
+
+/*! \brief List of loadable module types */
+       typedef enum {
+               SWITCH_LOADABLE_MODULE_TYPE_PRELOAD,
+               SWITCH_LOADABLE_MODULE_TYPE_COMMON,
+               SWITCH_LOADABLE_MODULE_TYPE_POSTLOAD
+       } switch_loadable_module_type_t;
+
 /*! \brief The abstraction of a loadable module */
        struct switch_loadable_module_interface {
        /*! the name of the module */
@@ -87,6 +96,8 @@ SWITCH_BEGIN_EXTERN_C
        switch_management_interface_t *management_interface;
        /*! the table of limit interfaces the module has implemented */
        switch_limit_interface_t *limit_interface;
+       /*! the table of database interfaces the module has implemented */
+       switch_database_interface_t *database_interface;
        switch_thread_rwlock_t *rwlock;
        int refs;
        switch_memory_pool_t *pool;
@@ -205,6 +216,13 @@ SWITCH_DECLARE(switch_json_api_interface_t *) switch_loadable_module_get_json_ap
  */
 SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interface(const char *name, const char *modname);
 
+/*!
+\brief Retrieve the database interface by it's registered name
+\param name the name of the dsn prefix
+\return the desired database format interface
+*/
+SWITCH_DECLARE(switch_database_interface_t *) switch_loadable_module_get_database_interface(const char *name, const char *modname);
+
 /*!
   \brief Retrieve the speech interface by it's registered name
   \param name the name of the speech interface
@@ -311,6 +329,13 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_load_module(const char *d
 */
 SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod);
 
+/*!
+\brief Protect module from beeing unloaded
+\param mod the module name
+\return the status
+*/
+SWITCH_DECLARE(switch_status_t) switch_loadable_module_protect(const char *mod);
+
 /*!
   \brief Unoad a module
   \param dir the directory where the module resides
index 798695d090c76a750ae295ac700b26e9c18daab8..54cd7b2de29ac18762ef7e32a7c4be91b04b3ce2 100644 (file)
@@ -25,6 +25,7 @@
  *
  * Anthony Minessale II <anthm@freeswitch.org>
  * Luke Dashjr <luke@openmethods.com> (OpenMethods, LLC)
+ * Andrey Volk <andywolk@gmail.com>
  *
  *
  * switch_module_interfaces.h -- Module Interface Definitions
@@ -614,6 +615,38 @@ struct switch_directory_handle {
        void *private_info;
 };
 
+/*! \brief Abstract interface to a database module */
+struct switch_database_interface {
+       /*! the name of the interface */
+       const char *interface_name;
+       switch_status_t(*handle_new)(char *dsn, switch_database_interface_handle_t **dih);
+       switch_status_t(*handle_destroy)(switch_database_interface_handle_t **dih); 
+       switch_status_t(*flush)(switch_database_interface_handle_t *dih);
+       switch_status_t(*exec_detailed)(const char *file, const char *func, int line, 
+               switch_database_interface_handle_t *dih, const char *sql, char **err);
+       switch_status_t(*exec_string)(switch_database_interface_handle_t *dih, const char *sql, char *resbuf, size_t len, char **err);
+       switch_status_t(*sql_set_auto_commit_attr)(switch_database_interface_handle_t *dih, switch_bool_t on);
+       switch_status_t(*commit)(switch_database_interface_handle_t *dih);
+       switch_status_t(*rollback)(switch_database_interface_handle_t *dih);
+       switch_status_t(*callback_exec_detailed)(const char *file, const char *func, int line,
+               switch_database_interface_handle_t *dih, const char *sql, switch_core_db_callback_func_t callback, void *pdata, char **err);
+       switch_status_t(*affected_rows)(switch_database_interface_handle_t *dih, int *affected_rows);
+
+       /*! list of supported dsn prefixes */
+       char **prefixes;
+       switch_thread_rwlock_t *rwlock;
+       int refs;
+       switch_mutex_t *reflock;
+       switch_loadable_module_interface_t *parent;
+       struct switch_database_interface *next;
+};
+
+/*! an abstract representation of a database interface. */
+struct switch_database_interface_handle {
+       switch_cache_db_database_interface_options_t connection_options;
+       void *handle;
+};
+
 struct switch_audio_codec_settings {
        int unused;
 };
index 53c25c395c25157c50d8903eda20e19ff9c7d55a..de2effd336750023668967a3a79de0205d8077bd 100644 (file)
@@ -28,6 +28,7 @@
  * Joseph Sullivan <jossulli@amazon.com>
  * Raymond Chandler <intralanman@freeswitch.org>
  * Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
+ * Andrey Volk <andywolk@gmail.com>
  *
  * switch_types.h -- Data Types
  *
@@ -400,6 +401,7 @@ typedef enum {
        SWITCH_LIMIT_INTERFACE,
        SWITCH_CHAT_APPLICATION_INTERFACE,
        SWITCH_JSON_API_INTERFACE,
+       SWITCH_DATABASE_INTERFACE,
 } switch_module_interface_name_t;
 
 typedef enum {
@@ -2290,6 +2292,7 @@ typedef struct switch_codec_fmtp switch_codec_fmtp_t;
 typedef struct switch_odbc_handle switch_odbc_handle_t;
 typedef struct switch_pgsql_handle switch_pgsql_handle_t;
 typedef struct switch_pgsql_result switch_pgsql_result_t;
+typedef struct switch_database_interface_handle switch_database_interface_handle_t;
 
 typedef struct switch_io_routines switch_io_routines_t;
 typedef struct switch_speech_handle switch_speech_handle_t;
@@ -2313,6 +2316,7 @@ typedef struct switch_management_interface switch_management_interface_t;
 typedef struct switch_core_port_allocator switch_core_port_allocator_t;
 typedef struct switch_media_bug switch_media_bug_t;
 typedef struct switch_limit_interface switch_limit_interface_t;
+typedef struct switch_database_interface switch_database_interface_t;
 
 typedef void (*hashtable_destructor_t)(void *ptr);
 
index b4128cc19a02516e5bbbf9ee0d2ca9265b3258fa..d81b7e520c4f1a52affc69cca6cc1d2352a55f07 100644 (file)
@@ -29,6 +29,7 @@
  * Marcel Barbulescu <marcelbarbulescu@gmail.com>
  * Joseph Sullivan <jossulli@amazon.com>
  * Seven Du <dujinfang@gmail.com>
+ * Andrey Volk <andywolk@gmail.com>
  *
  * switch_core.c -- Main Core Library
  *
@@ -2015,10 +2016,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc
 
        switch_core_state_machine_init(runtime.memory_pool);
 
-       if (switch_core_sqldb_start(runtime.memory_pool, switch_test_flag((&runtime), SCF_USE_SQL) ? SWITCH_TRUE : SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
-               *err = "Error activating database";
-               return SWITCH_STATUS_FALSE;
-       }
        switch_core_media_init();
        switch_scheduler_task_thread_start();
 
@@ -2343,11 +2340,7 @@ static void switch_load_core_config(const char *file)
                                } else if (!strcasecmp(var, "core-db-name") && !zstr(val)) {
                                        runtime.dbname = switch_core_strdup(runtime.memory_pool, val);
                                } else if (!strcasecmp(var, "core-db-dsn") && !zstr(val)) {
-                                       if (switch_odbc_available() || switch_pgsql_available()) {
-                                               runtime.odbc_dsn = switch_core_strdup(runtime.memory_pool, val);
-                                       } else {
-                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ODBC AND PGSQL ARE NOT AVAILABLE!\n");
-                                       }
+                                       runtime.odbc_dsn = switch_core_strdup(runtime.memory_pool, val);
                                } else if (!strcasecmp(var, "core-non-sqlite-db-required") && !zstr(val)) {
                                        switch_set_flag((&runtime), SCF_CORE_NON_SQLITE_DB_REQ);
                                } else if (!strcasecmp(var, "core-dbtype") && !zstr(val)) {
@@ -2425,6 +2418,20 @@ SWITCH_DECLARE(const char *) switch_core_banner(void)
                        "\n");
 }
 
+switch_status_t switch_core_sqldb_init(const char **err)
+{
+       if (switch_core_check_core_db_dsn() != SWITCH_STATUS_SUCCESS) {
+               *err = "NO SUITABLE DATABASE INTERFACE IS AVAILABLE TO SERVE 'core-db-dsn'!\n";
+               return SWITCH_STATUS_GENERR;
+       }
+
+       if (switch_core_sqldb_start(runtime.memory_pool, switch_test_flag((&runtime), SCF_USE_SQL) ? SWITCH_TRUE : SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
+               *err = "Error activating database";
+               return SWITCH_STATUS_GENERR;
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
 
 SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(switch_core_flag_t flags, switch_bool_t console, const char **err)
 {
@@ -2969,6 +2976,13 @@ SWITCH_DECLARE(switch_bool_t) switch_core_ready_outbound(void)
        return (switch_test_flag((&runtime), SCF_SHUTTING_DOWN) || switch_test_flag((&runtime), SCF_NO_NEW_OUTBOUND_SESSIONS)) ? SWITCH_FALSE : SWITCH_TRUE;
 }
 
+void switch_core_sqldb_destroy()
+{
+       if (switch_test_flag((&runtime), SCF_USE_SQL)) {
+               switch_core_sqldb_stop();
+       }
+}
+
 SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
 {
        switch_event_t *event;
@@ -2989,9 +3003,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
 
        switch_ssl_destroy_ssl_locks();
 
-       if (switch_test_flag((&runtime), SCF_USE_SQL)) {
-               switch_core_sqldb_stop();
-       }
        switch_scheduler_task_thread_stop();
 
        switch_rtp_shutdown();
index feb69d6b8e9ebfda6f7f38487d5bc6427bcd1fe1..9c6dc1ab55cc0538f3c0104e23a12d28e6fa74fd 100644 (file)
@@ -27,6 +27,7 @@
  * Michael Jerris <mike@jerris.com>
  * Paul D. Tinsley <pdt at jackhammer.org>
  * Emmanuel Schmidbauer <eschmidbauer@gmail.com>
+ * Andrey Volk <andywolk@gmail.com>
  *
  *
  * switch_core_sqldb.c -- Main Core Library (statistics tracker)
@@ -77,6 +78,9 @@ static struct {
 static void switch_core_sqldb_start_thread(void);
 static void switch_core_sqldb_stop_thread(void);
 
+#define database_interface_handle_callback_exec(database_interface, dih, sql, callback, pdata, err) database_interface->callback_exec_detailed(__FILE__, (char *)__SWITCH_FUNC__, __LINE__, dih, sql, callback, pdata, err)
+#define database_interface_handle_exec(database_interface, dih, sql, err) database_interface->exec_detailed(__FILE__, (char *)__SWITCH_FUNC__, __LINE__, dih, sql, err)
+
 static switch_cache_db_handle_t *create_handle(switch_cache_db_handle_type_t type)
 {
        switch_cache_db_handle_t *new_dbh = NULL;
@@ -135,6 +139,35 @@ static void del_handle(switch_cache_db_handle_t *dbh)
        switch_mutex_unlock(sql_manager.dbh_mutex);
 }
 
+SWITCH_DECLARE(void) switch_cache_db_database_interface_flush_handles(switch_database_interface_t *database_interface)
+{
+       switch_cache_db_handle_t *dbh_ptr = NULL;
+
+       switch_mutex_lock(sql_manager.dbh_mutex);
+
+       for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) {
+               if (switch_mutex_trylock(dbh_ptr->mutex) == SWITCH_STATUS_SUCCESS) {
+                       if (dbh_ptr->type != SCDB_TYPE_DATABASE_INTERFACE) {
+                               continue;
+                       }
+
+                       if (dbh_ptr->native_handle.database_interface_dbh->connection_options.database_interface != database_interface) {
+                               continue;
+                       }
+
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Dropping DB connection %s\n", dbh_ptr->name);
+
+                       database_interface->handle_destroy(&dbh_ptr->native_handle.database_interface_dbh);
+
+                       del_handle(dbh_ptr);
+                       switch_mutex_unlock(dbh_ptr->mutex);
+                       switch_core_destroy_memory_pool(&dbh_ptr->pool);
+               }
+       }
+
+       switch_mutex_unlock(sql_manager.dbh_mutex);
+}
+
 static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user_str, const char *thread_str)
 {
        switch_ssize_t hlen = -1;
@@ -155,7 +188,7 @@ static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user
 
        if (!r) {
                for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) {
-                       if (dbh_ptr->hash == hash && (dbh_ptr->type != SCDB_TYPE_PGSQL || !dbh_ptr->use_count) && !switch_test_flag(dbh_ptr, CDF_PRUNE) &&
+                       if (dbh_ptr->hash == hash && ((dbh_ptr->type != SCDB_TYPE_PGSQL && dbh_ptr->type != SCDB_TYPE_DATABASE_INTERFACE) || !dbh_ptr->use_count) && !switch_test_flag(dbh_ptr, CDF_PRUNE) &&
                                switch_mutex_trylock(dbh_ptr->mutex) == SWITCH_STATUS_SUCCESS) {
                                r = dbh_ptr;
                                break;
@@ -198,7 +231,7 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t
                dsn = "core";
        }
 
-       if ((r = _switch_cache_db_get_db_handle_dsn(dbh, dsn, file, func, line)) != SWITCH_STATUS_SUCCESS) {
+       if ((r = _switch_cache_db_get_db_handle_dsn_ex(dbh, dsn, SWITCH_TRUE, file, func, line)) != SWITCH_STATUS_SUCCESS) {
                *dbh = NULL;
        }
 
@@ -234,6 +267,12 @@ static void sql_close(time_t prune)
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Dropping idle DB connection %s\n", dbh->name);
 
                        switch (dbh->type) {
+                               case SCDB_TYPE_DATABASE_INTERFACE:
+                               {
+                                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                                       database_interface->handle_destroy(&dbh->native_handle.database_interface_dbh);
+                               }
+                               break;
                        case SCDB_TYPE_PGSQL:
                                {
                                        switch_pgsql_handle_destroy(&dbh->native_handle.pgsql_dbh);
@@ -299,6 +338,12 @@ SWITCH_DECLARE(void) switch_cache_db_release_db_handle(switch_cache_db_handle_t
        if (dbh && *dbh) {
 
                switch((*dbh)->type) {
+               case SCDB_TYPE_DATABASE_INTERFACE:
+                       {
+                               switch_database_interface_t *database_interface = (*dbh)->native_handle.database_interface_dbh->connection_options.database_interface;
+                               database_interface->flush((*dbh)->native_handle.database_interface_dbh);
+                       }
+               break;
                case SCDB_TYPE_PGSQL:
                        {
                                switch_pgsql_flush((*dbh)->native_handle.pgsql_dbh);
@@ -331,46 +376,115 @@ SWITCH_DECLARE(void) switch_cache_db_dismiss_db_handle(switch_cache_db_handle_t
        switch_cache_db_release_db_handle(dbh);
 }
 
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+SWITCH_DECLARE(switch_status_t) switch_core_check_core_db_dsn()
+{
+       switch_status_t status = SWITCH_STATUS_FALSE;
+       switch_database_interface_t *database_interface;
+
+       if (!runtime.odbc_dsn) {
+               status = SWITCH_STATUS_SUCCESS;
+       } else {
+               char *colon_slashes = NULL;
+               if (NULL != (colon_slashes = strstr(runtime.odbc_dsn, "://")))
+               {
+                       char prefix[16] = "";
+                       strncpy(prefix, runtime.odbc_dsn, MIN(colon_slashes - runtime.odbc_dsn, 15));
+
+                       if (!strncasecmp(prefix, "odbc", 4)) {
+                               if (switch_odbc_available()) status = SWITCH_STATUS_SUCCESS;
+                       }
+                       else if (!strncasecmp(prefix, "sqlite", 6)) {
+                               status = SWITCH_STATUS_SUCCESS;
+                       }
+                       else if (!strncasecmp(prefix, "pgsql", 5)) {
+                               if (switch_pgsql_available()) status = SWITCH_STATUS_SUCCESS;
+                       }
+                       else if ((database_interface = switch_loadable_module_get_database_interface(prefix, NULL))) {
+                               status = SWITCH_STATUS_SUCCESS;
+                               UNPROTECT_INTERFACE(database_interface);
+                       }
+               }
+               else if (strchr(runtime.odbc_dsn + 2, ':')) {
+                       status = SWITCH_STATUS_SUCCESS;
+               }
+       }
+
+       return status;
+}
 
 SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn(switch_cache_db_handle_t **dbh, const char *dsn,
+       const char *file, const char *func, int line)
+{
+       return _switch_cache_db_get_db_handle_dsn_ex(dbh, dsn, SWITCH_FALSE, file, func, line);
+}
+
+SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle_dsn_ex(switch_cache_db_handle_t **dbh, const char *dsn, switch_bool_t make_module_no_unloadable,
                                                                                                                                   const char *file, const char *func, int line)
 {
        switch_cache_db_connection_options_t connection_options = { {0} };
        switch_cache_db_handle_type_t type;
+       switch_database_interface_t *database_interface = NULL;
        char tmp[256] = "";
        char *p;
        switch_status_t status = SWITCH_STATUS_FALSE;
        int i;
 
-       if (!strncasecmp(dsn, "pgsql://", 8)) {
-               type = SCDB_TYPE_PGSQL;
-               connection_options.pgsql_options.dsn = (char *)(dsn + 8);
-       } else if (!strncasecmp(dsn, "sqlite://", 9)) {
-               type = SCDB_TYPE_CORE_DB;
-               connection_options.core_db_options.db_path = (char *)(dsn + 9);
-       } else if ((!(i = strncasecmp(dsn, "odbc://", 7))) || strchr(dsn+2, ':')) {
-               type = SCDB_TYPE_ODBC;
-
-               if (i) {
-                       switch_set_string(tmp, dsn);
-               } else {
-                       switch_set_string(tmp, dsn+7);
+       char *colon_slashes = NULL;
+       if ( NULL != (colon_slashes = strstr(dsn, "://")) )
+       {
+               char prefix[16] = "";
+               strncpy(prefix, dsn, MIN(colon_slashes - dsn, 15));
+
+               if ((database_interface = switch_loadable_module_get_database_interface(prefix, NULL))) {
+                       type = SCDB_TYPE_DATABASE_INTERFACE;
+                       connection_options.database_interface_options.make_module_no_unloadable = make_module_no_unloadable;
+                       connection_options.database_interface_options.database_interface = database_interface;
+                       connection_options.database_interface_options.dsn = colon_slashes + 3;
+                       strcpy(connection_options.database_interface_options.prefix, prefix);
+                       UNPROTECT_INTERFACE(database_interface);
                }
+       }
+
+       if (!connection_options.database_interface_options.dsn)
+       {               
+               if (!strncasecmp(dsn, "pgsql://", 8)) {
+                       type = SCDB_TYPE_PGSQL;
+                       connection_options.pgsql_options.dsn = (char *)(dsn + 8);
+               }
+               else if (!strncasecmp(dsn, "sqlite://", 9)) {
+                       type = SCDB_TYPE_CORE_DB;
+                       connection_options.core_db_options.db_path = (char *)(dsn + 9);
+               }
+               else if ((!(i = strncasecmp(dsn, "odbc://", 7))) || (strchr(dsn + 2, ':') && !colon_slashes)) {
+                       type = SCDB_TYPE_ODBC;
 
-               connection_options.odbc_options.dsn = tmp;
+                       if (i) {
+                               switch_set_string(tmp, dsn);
+                       }
+                       else {
+                               switch_set_string(tmp, dsn + 7);
+                       }
 
-               if ((p = strchr(tmp, ':'))) {
-                       *p++ = '\0';
-                       connection_options.odbc_options.user = p;
+                       connection_options.odbc_options.dsn = tmp;
 
-                       if ((p = strchr(connection_options.odbc_options.user, ':'))) {
+                       if ((p = strchr(tmp, ':'))) {
                                *p++ = '\0';
-                               connection_options.odbc_options.pass = p;
+                               connection_options.odbc_options.user = p;
+
+                               if ((p = strchr(connection_options.odbc_options.user, ':'))) {
+                                       *p++ = '\0';
+                                       connection_options.odbc_options.pass = p;
+                               }
                        }
                }
-       } else {
-               type = SCDB_TYPE_CORE_DB;
-               connection_options.core_db_options.db_path = (char *)dsn;
+               else {
+                       type = SCDB_TYPE_CORE_DB;
+                       connection_options.core_db_options.db_path = (char *)dsn;
+               }
        }
 
        status = _switch_cache_db_get_db_handle(dbh, type, &connection_options, file, func, line);
@@ -416,6 +530,14 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
        }
 
        switch (type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       db_name = connection_options->database_interface_options.dsn;
+                       odbc_user = NULL;
+                       odbc_pass = NULL;
+                       db_type = "database_interface";
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        db_name = connection_options->pgsql_options.dsn;
@@ -423,6 +545,7 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
                        odbc_pass = NULL;
                        db_type = "pgsql";
                }
+               break;
        case SCDB_TYPE_ODBC:
                {
                        db_name = connection_options->odbc_options.dsn;
@@ -454,14 +577,41 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
        snprintf(thread_str, sizeof(thread_str) - 1, "thread=\"%lu\"",  (unsigned long) (intptr_t) self);
 
        if ((new_dbh = get_handle(db_str, db_callsite_str, thread_str))) {
-               switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
-                                                 "Reuse Unused Cached DB handle %s [%s]\n", new_dbh->name, switch_cache_db_type_name(new_dbh->type));
+               if (type == SCDB_TYPE_DATABASE_INTERFACE) {
+                       switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
+                               "Reuse Unused Cached DB handle %s [Database interface prefix: %s]\n", new_dbh->name, connection_options->database_interface_options.prefix);
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
+                               "Reuse Unused Cached DB handle %s [%s]\n", new_dbh->name, switch_cache_db_type_name(new_dbh->type));
+               }
        } else {
                switch_core_db_t *db = NULL;
                switch_odbc_handle_t *odbc_dbh = NULL;
                switch_pgsql_handle_t *pgsql_dbh = NULL;
+               switch_database_interface_handle_t *database_interface_dbh = NULL;              
 
                switch (type) {
+               case SCDB_TYPE_DATABASE_INTERFACE:
+                       {
+                               switch_database_interface_t *database_interface = connection_options->database_interface_options.database_interface;
+
+                               if (SWITCH_STATUS_SUCCESS != database_interface->handle_new(connection_options->database_interface_options.dsn, &database_interface_dbh)) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! Can't create new handle! Can't connect to DSN %s\n", connection_options->database_interface_options.dsn);
+                                       goto end;
+                               }
+
+                               if (database_interface_dbh) {
+                                       database_interface_dbh->connection_options = connection_options->database_interface_options;
+                               
+                                       if (connection_options->database_interface_options.make_module_no_unloadable == SWITCH_TRUE)
+                                       {
+                                               PROTECT_INTERFACE(database_interface)
+                                                       switch_loadable_module_protect(database_interface->parent->module_name);
+                                               UNPROTECT_INTERFACE(database_interface)
+                                       }
+                               }
+                       }
+                       break;
                case SCDB_TYPE_PGSQL:
                        {
                                if (!switch_pgsql_available()) {
@@ -478,7 +628,6 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
                        break;
                case SCDB_TYPE_ODBC:
                        {
-
                                if (!switch_odbc_available()) {
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure! ODBC NOT AVAILABLE! Can't connect to DSN %s\n", connection_options->odbc_options.dsn);
                                        goto end;
@@ -490,8 +639,6 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
                                                switch_odbc_handle_destroy(&odbc_dbh);
                                        }
                                }
-
-
                        }
                        break;
                case SCDB_TYPE_CORE_DB:
@@ -504,7 +651,7 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
                        goto end;
                }
 
-               if (!db && !odbc_dbh && !pgsql_dbh) {
+               if (!db && !odbc_dbh && !pgsql_dbh && !database_interface_dbh) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failure to connect to %s %s!\n", switch_cache_db_type_name(type), db_name);
                        goto end;
                }
@@ -514,7 +661,9 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h
                switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10,
                                                  "Create Cached DB handle %s [%s] %s:%d\n", new_dbh->name, switch_cache_db_type_name(type), file, line);
 
-               if (db) {
+               if (database_interface_dbh) {
+                       new_dbh->native_handle.database_interface_dbh = database_interface_dbh;
+               } else if (db) {
                        new_dbh->native_handle.core_db_dbh = db;
                } else if (odbc_dbh) {
                        new_dbh->native_handle.odbc_dbh = odbc_dbh;
@@ -552,6 +701,13 @@ static switch_status_t switch_cache_db_execute_sql_real(switch_cache_db_handle_t
        }
 
        switch (dbh->type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       type = (char *)dbh->native_handle.database_interface_dbh->connection_options.prefix;
+                       status = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, &errmsg);
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        type = "PGSQL";
@@ -698,6 +854,13 @@ SWITCH_DECLARE(int) switch_cache_db_affected_rows(switch_cache_db_handle_t *dbh)
                        return switch_odbc_handle_affected_rows(dbh->native_handle.odbc_dbh);
                }
                break;
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       int affected_rows = 0;
+                       database_interface->affected_rows(dbh->native_handle.database_interface_dbh, &affected_rows);
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        return switch_pgsql_handle_affected_rows(dbh->native_handle.pgsql_dbh);
@@ -721,6 +884,11 @@ SWITCH_DECLARE(int) switch_cache_db_load_extension(switch_cache_db_handle_t *dbh
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type ODBC!\n");
                }
                break;
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type DATABASE_INTERFACE!\n");
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "load extension not supported by type PGSQL!\n");
@@ -783,6 +951,12 @@ SWITCH_DECLARE(char *) switch_cache_db_execute_sql2str(switch_cache_db_handle_t
                        status = switch_odbc_handle_exec_string(dbh->native_handle.odbc_dbh, sql, str, len, err);
                }
                break;
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       status = database_interface->exec_string(dbh->native_handle.database_interface_dbh, sql, str, len, err);
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        status = switch_pgsql_handle_exec_string(dbh->native_handle.pgsql_dbh, sql, str, len, err);
@@ -887,6 +1061,18 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw
                                }
                        }
                        break;
+               case SCDB_TYPE_DATABASE_INTERFACE:
+                       {
+                               switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                               switch_status_t result;
+
+                               if ((result = database_interface->sql_set_auto_commit_attr(dbh->native_handle.database_interface_dbh, 0)) != SWITCH_STATUS_SUCCESS) {
+                                       char tmp[100];
+                                       switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
+                                       errmsg = strdup(tmp);
+                               }                                       
+                       }
+                       break;
                case SCDB_TYPE_PGSQL:
                        {
                                switch_pgsql_status_t result;
@@ -922,6 +1108,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw
                                                switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
                                        }
                                        break;
+                               case SCDB_TYPE_DATABASE_INTERFACE:
+                                       {
+                                               switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                                               switch_status_t result;
+
+                                               if ((result = database_interface->commit(dbh->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+                                                       char tmp[100];
+                                                       switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+                                               }
+                                       }
+                                       break;
                                case SCDB_TYPE_PGSQL:
                                        {
                                                switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1);
@@ -997,6 +1194,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_persistant_execute_trans_full(sw
                        switch_odbc_SQLSetAutoCommitAttr(dbh->native_handle.odbc_dbh, 1);
                }
                break;
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+       
+                       if ((result = database_interface->commit(dbh->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        switch_pgsql_SQLEndTran(dbh->native_handle.pgsql_dbh, 1);
@@ -1058,6 +1266,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_event_callback(switc
        h.pdata = pdata;
 
        switch (dbh->type) {
+               case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+
+                       if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, helper_callback, &h, err)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_event_callback", result);
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, helper_callback, &h, err);
@@ -1113,6 +1332,21 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_event_callback_err(s
        h.pdata = pdata;
 
        switch (dbh->type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+
+                       if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, helper_callback, &h, err)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_event_callback_err", result);
+                       } else {
+                               if (err && *err) {
+                                       (*err_callback)(pdata, (const char*)*err);
+                               }
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, helper_callback, &h, err);
@@ -1173,6 +1407,17 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_callback(switch_cach
 
 
        switch (dbh->type) {
+               case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+
+                       if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, callback, pdata, err)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_callback", result);
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, callback, pdata, err);
@@ -1223,6 +1468,21 @@ SWITCH_DECLARE(switch_status_t) switch_cache_db_execute_sql_callback_err(switch_
 
 
        switch (dbh->type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+
+                       if ((result = database_interface_handle_callback_exec(database_interface, dbh->native_handle.database_interface_dbh, sql, callback, pdata, err)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to execute_sql_callback_err", result);
+                       } else {
+                               if (err && *err) {
+                                       (*err_callback)(pdata, (const char*)*err);
+                               }
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        status = switch_pgsql_handle_callback_exec(dbh->native_handle.pgsql_dbh, sql, callback, pdata, err);
@@ -1318,6 +1578,31 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand
        if (io_mutex) switch_mutex_lock(io_mutex);
 
        switch (dbh->type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+
+                       if ((result = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, test_sql, NULL)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to test_reactive with test_sql", result);
+
+                               if (drop_sql) {
+                                       if ((result = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, drop_sql, NULL)) != SWITCH_STATUS_SUCCESS) {
+                                               char tmp[100];
+                                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to test_reactive with drop_sql", result);
+                                       }
+
+                                       if ((result = database_interface_handle_exec(database_interface, dbh->native_handle.database_interface_dbh, reactive_sql, NULL)) != SWITCH_STATUS_SUCCESS) {
+                                               char tmp[100];
+                                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to test_reactive with reactive_sql", result);
+                                       }
+
+                                       r = result;
+                               }
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        if (switch_pgsql_handle_exec(dbh->native_handle.pgsql_dbh, test_sql, NULL) != SWITCH_PGSQL_SUCCESS) {
@@ -1940,6 +2225,18 @@ static uint32_t do_trans(switch_sql_queue_manager_t *qm)
                        }
                }
                break;
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = qm->event_db->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+
+                       if ((result = database_interface->sql_set_auto_commit_attr(qm->event_db->native_handle.database_interface_dbh, 0)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
+                               errmsg = strdup(tmp);
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        switch_pgsql_status_t result;
@@ -2016,6 +2313,17 @@ static uint32_t do_trans(switch_sql_queue_manager_t *qm)
                        switch_odbc_SQLSetAutoCommitAttr(qm->event_db->native_handle.odbc_dbh, 1);
                }
                break;
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               {
+                       switch_database_interface_t *database_interface = qm->event_db->native_handle.database_interface_dbh->connection_options.database_interface;
+                       switch_status_t result;
+
+                       if ((result = database_interface->commit(qm->event_db->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+                               char tmp[100];
+                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+                       }
+               }
+               break;
        case SCDB_TYPE_PGSQL:
                {
                        switch_pgsql_SQLEndTran(qm->event_db->native_handle.pgsql_dbh, 1);
@@ -2072,6 +2380,8 @@ static void *SWITCH_THREAD_FUNC switch_user_sql_thread(switch_thread_t *thread,
        switch_mutex_lock(qm->cond_mutex);
 
        switch (qm->event_db->type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
+               break;
        case SCDB_TYPE_PGSQL:
                break;
        case SCDB_TYPE_ODBC:
@@ -3390,6 +3700,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening DB\n");
 
        switch (sql_manager.dbh->type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
        case SCDB_TYPE_PGSQL:
        case SCDB_TYPE_ODBC:
                if (switch_test_flag((&runtime), SCF_CLEAR_SQL)) {
@@ -3440,6 +3751,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
 
 
        switch (sql_manager.dbh->type) {
+       case SCDB_TYPE_DATABASE_INTERFACE:
        case SCDB_TYPE_PGSQL:
        case SCDB_TYPE_ODBC:
                {
@@ -3481,6 +3793,18 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
                                        }
                                }
                                break;
+                       case SCDB_TYPE_DATABASE_INTERFACE:
+                               {
+                                       switch_database_interface_t *database_interface = sql_manager.dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                                       switch_status_t result;
+
+                                       if ((result = database_interface->sql_set_auto_commit_attr(sql_manager.dbh->native_handle.database_interface_dbh, 0)) != SWITCH_STATUS_SUCCESS) {
+                                               char tmp[100];
+                                               switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to Set AutoCommit Off", result);
+                                               err = strdup(tmp);
+                                       }
+                               }
+                               break;
                        case SCDB_TYPE_PGSQL:
                                {
                                        switch_pgsql_status_t result;
@@ -3514,6 +3838,18 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_
                                                }
                                        }
                                        break;
+                               case SCDB_TYPE_DATABASE_INTERFACE:
+                                       {
+                                               switch_database_interface_t *database_interface = sql_manager.dbh->native_handle.database_interface_dbh->connection_options.database_interface;
+                                               switch_status_t result;
+
+                                               if ((result = database_interface->commit(sql_manager.dbh->native_handle.database_interface_dbh)) != SWITCH_STATUS_SUCCESS) {
+                                                       char tmp[100];
+                                                       switch_snprintfv(tmp, sizeof(tmp), "%q-%i", "Unable to commit transaction", result);
+                                                       err = strdup(tmp);
+                                               }
+                                       }
+                                       break;
                                case SCDB_TYPE_PGSQL:
                                        {
                                                if (switch_pgsql_SQLEndTran(sql_manager.dbh->native_handle.pgsql_dbh, 1) != SWITCH_PGSQL_SUCCESS ||
index 38de325d2cf37dc6307988591985d323264e247b..dfd8f310a9c8c71d6c1d0d5e08fa8bb96c04e264 100644 (file)
  *
  * Anthony Minessale II <anthm@freeswitch.org>
  * Seven Du <dujinfang@gmail.com>
+ * Andrey Volk <andywolk@gmail.com>
  *
  * switch_loadable_module.c -- Loadable Modules
  *
  */
 
 #include <switch.h>
+#include "private/switch_core_pvt.h"
 
 /* for apr_pstrcat */
 #include <apr_strings.h>
@@ -47,6 +49,12 @@ typedef struct switch_file_node_s {
        struct switch_file_node_s *next;
 } switch_file_node_t;
 
+typedef struct switch_database_node_s {
+       const switch_database_interface_t *ptr;
+       const char *interface_name;
+       struct switch_database_node_s *next;
+} switch_database_node_t;
+
 typedef struct switch_codec_node_s {
        const switch_codec_interface_t *ptr;
        const char *interface_name;
@@ -67,6 +75,7 @@ struct switch_loadable_module {
        switch_status_t status;
        switch_thread_t *thread;
        switch_bool_t shutting_down;
+       switch_loadable_module_type_t type;
 };
 
 struct switch_loadable_module_container {
@@ -87,6 +96,7 @@ struct switch_loadable_module_container {
        switch_hash_t *say_hash;
        switch_hash_t *management_hash;
        switch_hash_t *limit_hash;
+       switch_hash_t *database_hash;
        switch_hash_t *secondary_recover_hash;
        switch_mutex_t *mutex;
        switch_memory_pool_t *pool;
@@ -95,7 +105,7 @@ struct switch_loadable_module_container {
 static struct switch_loadable_module_container loadable_modules;
 static switch_status_t do_shutdown(switch_loadable_module_t *module, switch_bool_t shutdown, switch_bool_t unload, switch_bool_t fail_if_busy,
                                                                   const char **err);
-static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err);
+static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err, switch_loadable_module_type_t type, switch_hash_t *event_hash);
 
 static void *SWITCH_THREAD_FUNC switch_loadable_module_exec(switch_thread_t *thread, void *obj)
 {
@@ -143,11 +153,28 @@ static void switch_loadable_module_runtime(void)
        switch_mutex_unlock(loadable_modules.mutex);
 }
 
-static switch_status_t switch_loadable_module_process(char *key, switch_loadable_module_t *new_module)
+static switch_status_t switch_loadable_module_process(char *key, switch_loadable_module_t *new_module, switch_hash_t *event_hash)
 {
        switch_event_t *event;
+       int *event_num = NULL;
+       char str_event_num[10];
+       void *val;
        int added = 0;
 
+       if (event_hash) {
+               if ((val = switch_core_hash_find(event_hash, "0"))) {
+                       event_num = (int*)val;
+               } else {
+                       if (!(event_num = malloc(sizeof(int)))) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Allocation error.\n");
+                               return SWITCH_STATUS_MEMERR;
+                       }
+
+                       *event_num = 0;
+                       switch_core_hash_insert(event_hash, "0", (const void*)event_num);
+               }
+       }
+
        new_module->key = switch_core_strdup(new_module->pool, key);
 
        switch_mutex_lock(loadable_modules.mutex);
@@ -166,7 +193,14 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+                                       
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       } else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                        }
@@ -232,7 +266,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
-                                               switch_event_fire(&event);
+
+                                               if (!event_hash) {
+                                                       switch_event_fire(&event);
+                                               }
+                                               else {
+                                                       sprintf(str_event_num, "%i", ++*event_num);
+                                                       switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                               }
+
                                                added++;
                                        }
                                }
@@ -253,7 +295,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.dialplan_hash, ptr->interface_name, (const void *) ptr);
@@ -274,7 +324,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.timer_hash, ptr->interface_name, (const void *) ptr);
@@ -297,7 +355,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.application_hash, ptr->interface_name, (const void *) ptr);
@@ -320,7 +386,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.chat_application_hash, ptr->interface_name, (const void *) ptr);
@@ -343,7 +417,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.api_hash, ptr->interface_name, (const void *) ptr);
@@ -366,7 +448,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "syntax", switch_str_nil(ptr->syntax));
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.json_api_hash, ptr->interface_name, (const void *) ptr);
@@ -394,7 +484,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
-                                               switch_event_fire(&event);
+
+                                               if (!event_hash) {
+                                                       switch_event_fire(&event);
+                                               }
+                                               else {
+                                                       sprintf(str_event_num, "%i", ++*event_num);
+                                                       switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                               }
+
                                                added++;
                                        }
                                        node = switch_core_alloc(new_module->pool, sizeof(*node));
@@ -410,6 +508,52 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                }
        }
 
+       if (new_module->module_interface->database_interface) {
+               const switch_database_interface_t *ptr;
+
+               for (ptr = new_module->module_interface->database_interface; ptr; ptr = ptr->next) {
+                       if (!ptr->interface_name) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load database interface from %s due to no interface name.\n", key);
+                       }
+                       else if (!ptr->prefixes) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load database interface from %s due to no prefixes.\n", key);
+                       }
+                       else {
+                               int i;
+                               switch_database_node_t *node, *head;
+
+                               for (i = 0; ptr->prefixes[i]; i++) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding dsn prefix '%s'\n", ptr->prefixes[i]);
+                                       if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "database");
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->prefixes[i]);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", new_module->module_interface->module_name);
+
+                                               if (!event_hash) {
+                                                       switch_event_fire(&event);
+                                               }
+                                               else {
+                                                       sprintf(str_event_num, "%i", ++*event_num);
+                                                       switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                               }
+
+                                               added++;
+                                       }
+                                       node = switch_core_alloc(new_module->pool, sizeof(*node));
+                                       node->ptr = ptr;
+                                       node->interface_name = switch_core_strdup(new_module->pool, new_module->module_interface->module_name);
+                                       if ((head = switch_core_hash_find(loadable_modules.database_hash, ptr->prefixes[i]))) {
+                                               node->next = head;
+                                       }
+
+                                       switch_core_hash_insert(loadable_modules.database_hash, ptr->prefixes[i], (const void *)node);
+                               }
+                       }
+               }
+       }
+
        if (new_module->module_interface->speech_interface) {
                const switch_speech_interface_t *ptr;
 
@@ -423,7 +567,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.speech_hash, ptr->interface_name, (const void *) ptr);
@@ -444,7 +596,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.asr_hash, ptr->interface_name, (const void *) ptr);
@@ -465,7 +625,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.directory_hash, ptr->interface_name, (const void *) ptr);
@@ -486,7 +654,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.chat_hash, ptr->interface_name, (const void *) ptr);
@@ -507,7 +683,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                       switch_event_fire(&event);
+
+                                       if (!event_hash) {
+                                               switch_event_fire(&event);
+                                       }
+                                       else {
+                                               sprintf(str_event_num, "%i", ++*event_num);
+                                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                       }
+
                                        added++;
                                }
                                switch_core_hash_insert(loadable_modules.say_hash, ptr->interface_name, (const void *) ptr);
@@ -534,7 +718,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->relative_oid);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                               switch_event_fire(&event);
+
+                                               if (!event_hash) {
+                                                       switch_event_fire(&event);
+                                               }
+                                               else {
+                                                       sprintf(str_event_num, "%i", ++*event_num);
+                                                       switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                               }
+
                                                added++;
                                        }
                                }
@@ -561,7 +753,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                                               switch_event_fire(&event);
+
+                                               if (!event_hash) {
+                                                       switch_event_fire(&event);
+                                               }
+                                               else {
+                                                       sprintf(str_event_num, "%i", ++*event_num);
+                                                       switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                                               }
+
                                                added++;
                                        }
                                }
@@ -576,7 +776,15 @@ static switch_status_t switch_loadable_module_process(char *key, switch_loadable
                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", new_module->key);
                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
-                       switch_event_fire(&event);
+
+                       if (!event_hash) {
+                               switch_event_fire(&event);
+                       }
+                       else {
+                               sprintf(str_event_num, "%i", ++*event_num);
+                               switch_core_hash_insert(event_hash, (const char*)str_event_num, (const void*)event);
+                       }
+
                        added++;
                }
        }
@@ -1215,6 +1423,62 @@ static switch_status_t switch_loadable_module_unprocess(switch_loadable_module_t
                }
        }
 
+       if (old_module->module_interface->database_interface) {
+               const switch_database_interface_t *ptr;
+               switch_database_node_t *node, *head, *last = NULL;
+
+               for (ptr = old_module->module_interface->database_interface; ptr; ptr = ptr->next) {
+                       if (ptr->interface_name) {
+                               int i;
+
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write lock interface '%s' to wait for existing references.\n",
+                                       ptr->interface_name);
+
+                               if (switch_thread_rwlock_trywrlock_timeout(ptr->rwlock, 10) == SWITCH_STATUS_SUCCESS) {
+                                       switch_thread_rwlock_unlock(ptr->rwlock);
+                               }
+                               else {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Giving up on '%s' waiting for existing references.\n", ptr->interface_name);
+                               }
+
+                               for (i = 0; ptr->prefixes[i]; i++) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Deleting dsn prefix '%s'\n", ptr->prefixes[i]);
+                                       if (switch_event_create(&event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) {
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "database");
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->prefixes[i]);
+                                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "module", old_module->module_interface->module_name);
+                                               switch_event_fire(&event);
+                                               removed++;
+                                       }
+
+                                       if ((head = switch_core_hash_find(loadable_modules.database_hash, ptr->prefixes[i]))) {
+                                               for (node = head; node; node = node->next) {
+                                                       if (!strcmp(node->interface_name, old_module->module_interface->module_name)) {
+                                                               if (node == head) {
+                                                                       if ((node = node->next)) {
+                                                                               switch_core_hash_insert(loadable_modules.database_hash, ptr->prefixes[i], (const void *)node);
+                                                                       }
+                                                                       else {
+                                                                               switch_core_hash_delete(loadable_modules.database_hash, ptr->prefixes[i]);
+                                                                       }
+                                                               }
+                                                               else {
+                                                                       if (last) {
+                                                                               last->next = node->next;
+                                                                       }
+                                                               }
+                                                               break;
+                                                       }
+                                                       last = node;
+                                               }
+                                       }
+                               }
+
+                               switch_cache_db_database_interface_flush_handles(old_module->module_interface->database_interface);
+                       }
+               }
+       }
+
        if (old_module->module_interface->speech_interface) {
                const switch_speech_interface_t *ptr;
 
@@ -1546,10 +1810,10 @@ static switch_status_t switch_loadable_module_load_file(char *path, char *filena
 }
 SWITCH_DECLARE(switch_status_t) switch_loadable_module_load_module(const char *dir, const char *fname, switch_bool_t runtime, const char **err)
 {
-       return switch_loadable_module_load_module_ex(dir, fname, runtime, SWITCH_FALSE, err);
+       return switch_loadable_module_load_module_ex(dir, fname, runtime, SWITCH_FALSE, err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, NULL);
 }
 
-static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err)
+static switch_status_t switch_loadable_module_load_module_ex(const char *dir, const char *fname, switch_bool_t runtime, switch_bool_t global, const char **err, switch_loadable_module_type_t type, switch_hash_t *event_hash)
 {
        switch_size_t len = 0;
        char *path;
@@ -1593,7 +1857,9 @@ static switch_status_t switch_loadable_module_load_module_ex(const char *dir, co
                *err = "Module already loaded";
                status = SWITCH_STATUS_FALSE;
        } else if ((status = switch_loadable_module_load_file(path, file, global, &new_module)) == SWITCH_STATUS_SUCCESS) {
-               if ((status = switch_loadable_module_process(file, new_module)) == SWITCH_STATUS_SUCCESS && runtime) {
+               new_module->type = type;
+
+               if ((status = switch_loadable_module_process(file, new_module, event_hash)) == SWITCH_STATUS_SUCCESS && runtime) {
                        if (new_module->switch_module_runtime) {
                                new_module->thread = switch_core_launch_thread(switch_loadable_module_exec, new_module, new_module->pool);
                        }
@@ -1628,6 +1894,30 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod)
        return status;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_loadable_module_protect(const char *mod)
+{
+       switch_loadable_module_t *module = NULL;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       if (zstr(mod)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_mutex_lock(loadable_modules.mutex);
+       if ((module = switch_core_hash_find(loadable_modules.module_hash, mod))) {
+               if (!module->perm) {
+                       module->perm++;
+               }
+               status = SWITCH_STATUS_SUCCESS;
+       }
+       else {
+               status = SWITCH_STATUS_FALSE;
+       }
+       switch_mutex_unlock(loadable_modules.mutex);
+
+       return status;
+}
+
 SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(const char *dir, const char *fname, switch_bool_t force, const char **err)
 {
        switch_loadable_module_t *module = NULL;
@@ -1801,7 +2091,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_build_dynamic(char *filen
                module->thread = switch_core_launch_thread(switch_loadable_module_exec, module, module->pool);
        }
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Successfully Loaded [%s]\n", module_interface->module_name);
-       return switch_loadable_module_process((char *) module->filename, module);
+       return switch_loadable_module_process((char *) module->filename, module, NULL);
 }
 
 #ifdef WIN32
@@ -1826,12 +2116,17 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo
        apr_finfo_t finfo = { 0 };
        apr_dir_t *module_dir_handle = NULL;
        apr_int32_t finfo_flags = APR_FINFO_DIRENT | APR_FINFO_TYPE | APR_FINFO_NAME;
+       char *precf = "pre_load_modules.conf";
        char *cf = "modules.conf";
        char *pcf = "post_load_modules.conf";
        switch_xml_t cfg, xml;
        unsigned char all = 0;
        unsigned int count = 0;
        const char *err;
+       switch_hash_t *event_hash;
+       switch_hash_index_t *hi;
+       void *hash_val;
+       switch_event_t *event;
 
 
 #ifdef WIN32
@@ -1869,21 +2164,94 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo
        switch_core_hash_init_nocase(&loadable_modules.say_hash);
        switch_core_hash_init_nocase(&loadable_modules.management_hash);
        switch_core_hash_init_nocase(&loadable_modules.limit_hash);
+       switch_core_hash_init_nocase(&loadable_modules.database_hash);
        switch_core_hash_init_nocase(&loadable_modules.dialplan_hash);
        switch_core_hash_init(&loadable_modules.secondary_recover_hash);
        switch_mutex_init(&loadable_modules.mutex, SWITCH_MUTEX_NESTED, loadable_modules.pool);
 
        if (!autoload) return SWITCH_STATUS_SUCCESS;
+       
+       /*
+               switch_core_sqldb_init() is not yet ready and is executed after starting modules from pre_load_modules.conf
+               Modules loading procedure generates events used by sqldb.
+               This is why we should hold those events (storing in the event_hash) not firing them until sqldb is ready.
+       */
+       switch_core_hash_init(&event_hash);
 
-       switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, &err);
-       switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_FALSE, &err);
-       switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_FALSE, &err);
+       switch_loadable_module_load_module_ex("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
+       switch_loadable_module_load_module_ex("", "CORE_PCM_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
+       switch_loadable_module_load_module_ex("", "CORE_SPEEX_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
 #ifdef SWITCH_HAVE_YUV
 #ifdef SWITCH_HAVE_VPX
-       switch_loadable_module_load_module("", "CORE_VPX_MODULE", SWITCH_FALSE, &err);
+       switch_loadable_module_load_module_ex("", "CORE_VPX_MODULE", SWITCH_FALSE, SWITCH_FALSE, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, event_hash);
 #endif
 #endif
 
+       if ((xml = switch_xml_open_cfg(precf, &cfg, NULL))) {
+               switch_xml_t mods, ld;
+               if ((mods = switch_xml_child(cfg, "modules"))) {
+                       for (ld = switch_xml_child(mods, "load"); ld; ld = ld->next) {
+                               switch_bool_t global = SWITCH_FALSE;
+                               const char *val = switch_xml_attr_soft(ld, "module");
+                               const char *path = switch_xml_attr_soft(ld, "path");
+                               const char *critical = switch_xml_attr_soft(ld, "critical");
+                               const char *sglobal = switch_xml_attr_soft(ld, "global");
+
+                               if (zstr(val) || (strchr(val, '.') && !strstr(val, ext) && !strstr(val, EXT))) {
+                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Invalid extension for %s\n", val);
+                                       continue;
+                               }
+                               global = switch_true(sglobal);
+
+                               if (path && zstr(path)) {
+                                       path = SWITCH_GLOBAL_dirs.mod_dir;
+                               }
+                               if (switch_loadable_module_load_module_ex((char *)path, (char *)val, SWITCH_FALSE, global, &err, SWITCH_LOADABLE_MODULE_TYPE_PRELOAD, event_hash) == SWITCH_STATUS_GENERR) {
+                                       if (critical && switch_true(critical)) {
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load critical module '%s', abort()\n", val);
+
+                                               if ((hash_val = switch_core_hash_find(event_hash, "0"))) {
+                                                       switch_safe_free(hash_val);
+                                               }
+                                               switch_core_hash_destroy(&event_hash);
+
+                                               abort();
+                                       }
+                               }
+                               count++;
+                       }
+               }
+               switch_xml_free(xml);
+
+       }
+       else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "open of %s failed\n", cf);
+       }
+
+       if (switch_core_sqldb_init(&err) != SWITCH_STATUS_SUCCESS)
+       {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Loading modules interrupted. [Error: %s]\n", err);
+               if ((hash_val = switch_core_hash_find(event_hash, "0"))) {
+                       switch_safe_free(hash_val);
+               }
+               switch_core_hash_destroy(&event_hash);
+               return SWITCH_STATUS_GENERR;
+       }
+
+       /* sqldb is ready. Fire holding events! */
+       if ((hash_val = switch_core_hash_find(event_hash, "0"))) {
+               switch_safe_free(hash_val);
+               switch_core_hash_delete(event_hash, "0");
+       }
+
+       for (hi = switch_core_hash_first(event_hash); hi; hi = switch_core_hash_next(&hi)) {
+               switch_core_hash_this(hi, NULL, NULL, &hash_val);
+               event = (switch_event_t *)hash_val;
+               switch_event_fire(&event);
+       }
+
+       switch_core_hash_destroy(&event_hash);
+
        if ((xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
                switch_xml_t mods, ld;
                if ((mods = switch_xml_child(cfg, "modules"))) {
@@ -1902,7 +2270,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo
                                if (path && zstr(path)) {
                                        path = SWITCH_GLOBAL_dirs.mod_dir;
                                }
-                               if (switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err) == SWITCH_STATUS_GENERR) {
+                               if (switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err, SWITCH_LOADABLE_MODULE_TYPE_COMMON, NULL) == SWITCH_STATUS_GENERR) {
                                        if (critical && switch_true(critical)) {
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load critical module '%s', abort()\n", val);
                                                abort();
@@ -1935,7 +2303,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_init(switch_bool_t autolo
                                if (path && zstr(path)) {
                                        path = SWITCH_GLOBAL_dirs.mod_dir;
                                }
-                               switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err);
+                               switch_loadable_module_load_module_ex(path, val, SWITCH_FALSE, global, &err, SWITCH_LOADABLE_MODULE_TYPE_POSTLOAD, NULL);
                                count++;
                        }
                }
@@ -2047,6 +2415,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void)
 {
        switch_hash_index_t *hi;
        void *val;
+       const void *key;
        switch_loadable_module_t *module;
        int i;
 
@@ -2068,19 +2437,47 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void)
 
        for (hi = switch_core_hash_first(loadable_modules.module_hash); hi; hi = switch_core_hash_next(&hi)) {
                switch_core_hash_this(hi, NULL, NULL, &val);
-               module = (switch_loadable_module_t *) val;
-               if (!module->perm) {
+               module = (switch_loadable_module_t *)val;
+               if (module->type != SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
                        do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE, SWITCH_FALSE, NULL);
                }
        }
 
        switch_yield(1000000);
 
+       for (hi = switch_core_hash_first(loadable_modules.module_hash); hi;) {
+               switch_core_hash_this(hi, &key, NULL, &val);
+               module = (switch_loadable_module_t *)val;
+
+               hi = switch_core_hash_next(&hi);
+
+               if (module->type != SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
+                       if (do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL) == SWITCH_STATUS_SUCCESS)
+                       {
+                               switch_core_hash_delete(loadable_modules.module_hash, key);
+                       }
+               }
+       }
+
+       switch_core_sqldb_destroy();
+
        for (hi = switch_core_hash_first(loadable_modules.module_hash); hi; hi = switch_core_hash_next(&hi)) {
                switch_core_hash_this(hi, NULL, NULL, &val);
-               module = (switch_loadable_module_t *) val;
-               if (!module->perm) {
-                       do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL);
+               if ((module = (switch_loadable_module_t *)val)) {
+                       if (module->type == SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
+                               do_shutdown(module, SWITCH_TRUE, SWITCH_FALSE, SWITCH_FALSE, NULL);
+                       }
+               }
+       }
+
+       switch_yield(1000000);
+
+       for (hi = switch_core_hash_first(loadable_modules.module_hash); hi; hi = switch_core_hash_next(&hi)) {
+               switch_core_hash_this(hi, NULL, NULL, &val);
+               if ((module = (switch_loadable_module_t *)val)) {
+                       if (module->type == SWITCH_LOADABLE_MODULE_TYPE_PRELOAD && !module->perm) {
+                               do_shutdown(module, SWITCH_FALSE, SWITCH_TRUE, SWITCH_FALSE, NULL);
+                       }
                }
        }
 
@@ -2100,6 +2497,7 @@ SWITCH_DECLARE(void) switch_loadable_module_shutdown(void)
        switch_core_hash_destroy(&loadable_modules.say_hash);
        switch_core_hash_destroy(&loadable_modules.management_hash);
        switch_core_hash_destroy(&loadable_modules.limit_hash);
+       switch_core_hash_destroy(&loadable_modules.database_hash);
        switch_core_hash_destroy(&loadable_modules.dialplan_hash);
 
        switch_core_destroy_memory_pool(&loadable_modules.pool);
@@ -2147,6 +2545,34 @@ SWITCH_DECLARE(switch_file_interface_t *) switch_loadable_module_get_file_interf
        return i;
 }
 
+SWITCH_DECLARE(switch_database_interface_t *) switch_loadable_module_get_database_interface(const char *name, const char *modname)
+{
+       switch_database_interface_t *i = NULL;
+       switch_database_node_t *node, *head;
+
+       switch_mutex_lock(loadable_modules.mutex);
+
+       if ((head = switch_core_hash_find(loadable_modules.database_hash, name))) {
+               if (modname) {
+                       for (node = head; node; node = node->next) {
+                               if (!strcasecmp(node->interface_name, modname)) {
+                                       i = (switch_database_interface_t *)node->ptr;
+                                       break;
+                               }
+                       }
+               }
+               else {
+                       i = (switch_database_interface_t *)head->ptr;
+               }
+       }
+
+       switch_mutex_unlock(loadable_modules.mutex);
+
+       if (i) PROTECT_INTERFACE(i);
+
+       return i;
+}
+
 SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name, const char *modname)
 {
        switch_codec_interface_t *codec = NULL;
@@ -2711,6 +3137,9 @@ SWITCH_DECLARE(void *) switch_loadable_module_create_interface(switch_loadable_m
        case SWITCH_LIMIT_INTERFACE:
                ALLOC_INTERFACE(limit)
 
+       case SWITCH_DATABASE_INTERFACE:
+               ALLOC_INTERFACE(database)
+
        default:
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Module Type!\n");
                return NULL;