]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Various code and documentation cleanups for res_config_sqlite
authorRussell Bryant <russell@russellbryant.com>
Thu, 13 Sep 2007 15:26:40 +0000 (15:26 +0000)
committerRussell Bryant <russell@russellbryant.com>
Thu, 13 Sep 2007 15:26:40 +0000 (15:26 +0000)
(closes issue #10711, rbraun_proformatique)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@82321 65c4cc65-6c06-0410-ace0-fbb531ad65f3

configs/res_config_sqlite.conf
doc/res_config_sqlite.txt
include/asterisk/doxyref.h
res/res_config_sqlite.c

index 87f1e08bfebce9a89ca06da8e996e04d074147be..04e6ae2e74dfd24e262f36de8f46531c1ebfc4aa 100644 (file)
@@ -9,7 +9,3 @@ dbfile => /var/lib/asterisk/sqlite.db
 ; support is simply disabled.
 config_table => ast_config
 cdr_table => ast_cdr
-
-; This parameter controls the registration of the SQLITE() Dialplan application.
-app_enable => yes
-
index 682dbaa732775acfbb1c5e25ecef1b3d0299d79c..9f1794429cd037c3215b125c34cbb7e2207f56be 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * res_sqlite - SQLite 2 support for Asterisk
- * 
+ * res_config_sqlite - SQLite 2 support for Asterisk
+ *
  * This module can be used as a static/RealTime configuration module, and a CDR
- * handler.  See the Doxygen documentation for a detailed description of the 
+ * handler.  See the Doxygen documentation for a detailed description of the
  * module, and the configs/ directory for the sample configuration file.
  */
 
 /*
  * RealTime static table.
  */
-CREATE TABLE ast_config
-(
id INTEGER PRIMARY KEY,
commented INT(11) NOT NULL DEFAULT '0',
filename VARCHAR(128) NOT NULL,
category VARCHAR(128) NOT NULL,
var_name VARCHAR(128) NOT NULL,
- var_val VARCHAR(128) NOT NULL
+CREATE TABLE ast_config (
+       id              INTEGER,
      commented       TINYINT(1)      NOT NULL        DEFAULT 0,
      filename        VARCHAR(128)    NOT NULL        DEFAULT '',
      category        VARCHAR(128)    NOT NULL        DEFAULT 'default',
      var_name        VARCHAR(128)    NOT NULL        DEFAULT '',
      var_val         TEXT            NOT NULL        DEFAULT '',
+       PRIMARY KEY     (id)
 );
 
-CREATE INDEX ast_config_filename_commented ON ast_config(filename, commented);
+CREATE INDEX ast_config__idx__filename_commented       ON ast_config(filename, commented);
+CREATE INDEX ast_config__idx__category                 ON ast_config(category);
 
 /*
  * CDR table (this table is automatically created if non existent).
- * 
- * CREATE TABLE ast_cdr
- * (
- *  id INTEGER PRIMARY KEY,
- *  clid VARCHAR(80) NOT NULL DEFAULT '',
- *  src VARCHAR(80) NOT NULL DEFAULT '',
- *  dst VARCHAR(80) NOT NULL DEFAULT '',
- *  dcontext VARCHAR(80) NOT NULL DEFAULT '',
- *  channel VARCHAR(80) NOT NULL DEFAULT '',
- *  dstchannel VARCHAR(80) NOT NULL DEFAULT '',
- *  lastapp VARCHAR(80) NOT NULL DEFAULT '',
- *  lastdata VARCHAR(80) NOT NULL DEFAULT '',
- *  start CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',
- *  answer CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',
- *  end CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',
- *  duration INT(11) NOT NULL DEFAULT '0',
- *  billsec INT(11) NOT NULL DEFAULT '0',
- *  disposition INT(11) NOT NULL DEFAULT '0',
- *  amaflags INT(11) NOT NULL DEFAULT '0',
- *  accountcode VARCHAR(20) NOT NULL DEFAULT '',
- *  uniqueid VARCHAR(32) NOT NULL DEFAULT '',
- *  userfield VARCHAR(255) NOT NULL DEFAULT ''
- * );
  */
+CREATE TABLE ast_cdr (
+       id              INTEGER,
+       clid            VARCHAR(80)     NOT NULL        DEFAULT '',
+       src             VARCHAR(80)     NOT NULL        DEFAULT '',
+       dst             VARCHAR(80)     NOT NULL        DEFAULT '',
+       dcontext        VARCHAR(80)     NOT NULL        DEFAULT '',
+       channel         VARCHAR(80)     NOT NULL        DEFAULT '',
+       dstchannel      VARCHAR(80)     NOT NULL        DEFAULT '',
+       lastapp         VARCHAR(80)     NOT NULL        DEFAULT '',
+       lastdata        VARCHAR(80)     NOT NULL        DEFAULT '',
+       start           DATETIME        NOT NULL        DEFAULT '0000-00-00 00:00:00',
+       answer          DATETIME        NOT NULL        DEFAULT '0000-00-00 00:00:00',
+       end             DATETIME        NOT NULL        DEFAULT '0000-00-00 00:00:00',
+       duration        INT(11)         NOT NULL        DEFAULT 0,
+       billsec         INT(11)         NOT NULL        DEFAULT 0,
+       disposition     VARCHAR(45)     NOT NULL        DEFAULT '',
+       amaflags        INT(11)         NOT NULL        DEFAULT 0,
+       accountcode     VARCHAR(20)     NOT NULL        DEFAULT '',
+       uniqueid        VARCHAR(32)     NOT NULL        DEFAULT '',
+       userfield       VARCHAR(255)    NOT NULL        DEFAULT '',
+       PRIMARY KEY     (id)
+);
 
 /*
  * SIP RealTime table.
  */
-CREATE TABLE ast_sip
-(
- id INTEGER PRIMARY KEY,
- commented INT(11) NOT NULL DEFAULT '0',
- name VARCHAR(80) NOT NULL,
- accountcode VARCHAR(20),
- amaflags VARCHAR(13),
- callgroup VARCHAR(10),
- callerid VARCHAR(80),
- canreinvite CHAR(3),
- context VARCHAR(80),
- defaultip VARCHAR(15),
- dtmfmode VARCHAR(7),
- fromuser VARCHAR(80),
- fromdomain VARCHAR(80),
- fullcontact VARCHAR(80),
- host VARCHAR(31) NOT NULL,
- insecure VARCHAR(4),
- language CHAR(2),
- mailbox VARCHAR(50),
- md5secret VARCHAR(80),
- nat VARCHAR(5) NOT NULL DEFAULT 'no',
- deny VARCHAR(95),
- permit VARCHAR(95),
- mask VARCHAR(95),
- pickupgroup VARCHAR(10),
- port VARCHAR(5) NOT NULL,
- qualify CHAR(3),
- restrictcid CHAR(1),
- rtptimeout CHAR(3),
- rtpholdtimeout CHAR(3),
- secret VARCHAR(80),
- type VARCHAR(6) NOT NULL DEFAULT 'friend',
- username VARCHAR(80) NOT NULL,
- disallow VARCHAR(100),
- allow VARCHAR(100),
- musiconhold VARCHAR(100),
- regseconds INT(11) NOT NULL DEFAULT '0',
- ipaddr VARCHAR(15) NOT NULL,
- regexten VARCHAR(80) NOT NULL,
- cancallforward CHAR(3),
- setvar VARCHAR(100) NOT NULL
+CREATE TABLE ast_sip (
+       id              INTEGER,
+       commented       TINYINT(1)      NOT NULL        DEFAULT 0,
+       name            VARCHAR(80)     NOT NULL        DEFAULT '',
+       host            VARCHAR(31)     NOT NULL        DEFAULT '',
+       nat             VARCHAR(5)      NOT NULL        DEFAULT 'no',
+       type            VARCHAR(6)      NOT NULL        DEFAULT 'friend',
+       accountcode     VARCHAR(20)                     DEFAULT NULL,
+       amaflags        VARCHAR(13)                     DEFAULT NULL,
+       callgroup       VARCHAR(10)                     DEFAULT NULL,
+       callerid        VARCHAR(80)                     DEFAULT NULL,
+       cancallforward  CHAR(3)                         DEFAULT 'yes',
+       canreinvite     CHAR(3)                         DEFAULT 'yes',
+       context         VARCHAR(80)                     DEFAULT NULL,
+       defaultip       VARCHAR(15)                     DEFAULT NULL,
+       dtmfmode        VARCHAR(7)                      DEFAULT NULL,
+       fromuser        VARCHAR(80)                     DEFAULT NULL,
+       fromdomain      VARCHAR(80)                     DEFAULT NULL,
+       insecure        VARCHAR(4)                      DEFAULT NULL,
+       language        CHAR(2)                         DEFAULT NULL,
+       mailbox         VARCHAR(50)                     DEFAULT NULL,
+       md5secret       VARCHAR(80)                     DEFAULT NULL,
+       deny            VARCHAR(95)                     DEFAULT NULL,
+       permit          VARCHAR(95)                     DEFAULT NULL,
+       mask            VARCHAR(95)                     DEFAULT NULL,
+       musiconhold     VARCHAR(100)                    DEFAULT NULL,
+       pickupgroup     VARCHAR(10)                     DEFAULT NULL,
+       qualify         CHAR(3)                         DEFAULT NULL,
+       regexten        VARCHAR(80)                     DEFAULT NULL,
+       restrictcid     CHAR(3)                         DEFAULT NULL,
+       rtptimeout      CHAR(3)                         DEFAULT NULL,
+       rtpholdtimeout  CHAR(3)                         DEFAULT NULL,
+       secret          VARCHAR(80)                     DEFAULT NULL,
+       setvar          VARCHAR(100)                    DEFAULT NULL,
+       disallow        VARCHAR(100)                    DEFAULT 'all',
+       allow           VARCHAR(100)                    DEFAULT 'g729,ilbc,gsm,ulaw,alaw',
+       fullcontact     VARCHAR(80)     NOT NULL        DEFAULT '',
+       ipaddr          VARCHAR(15)     NOT NULL        DEFAULT '',
+       port            INT(11)         NOT NULL        DEFAULT 0,
+       regserver       VARCHAR(100)                    DEFAULT NULL,
+       regseconds      INT(11)         NOT NULL        DEFAULT 0,
+       username        VARCHAR(80)     NOT NULL        DEFAULT '',
+       PRIMARY KEY     (id)
+       UNIQUE          (name)
 );
 
-CREATE UNIQUE INDEX ast_sip_name ON ast_sip(name);
+CREATE INDEX ast_sip__idx__commented ON ast_sip(commented);
 
 /*
  * Dialplan RealTime table.
  */
-CREATE TABLE ast_exten
-(
id INTEGER PRIMARY KEY,
commented INT(11) NOT NULL DEFAULT '0',
context VARCHAR(20) NOT NULL,
exten VARCHAR(20) NOT NULL,
priority TINYINT(4) NOT NULL,
app VARCHAR(20) NOT NULL,
- appdata VARCHAR(128) NOT NULL
+CREATE TABLE ast_exten (
+       id              INTEGER,
      commented       TINYINT(1)      NOT NULL        DEFAULT 0,
      context         VARCHAR(80)     NOT NULL        DEFAULT '',
      exten           VARCHAR(40)     NOT NULL        DEFAULT '',
      priority        INT(11)         NOT NULL        DEFAULT 0,
      app             VARCHAR(128)    NOT NULL        DEFAULT '',
      appdata         VARCHAR(128)    NOT NULL        DEFAULT '',
+       PRIMARY KEY     (id)
 );
 
+CREATE INDEX ast_exten__idx__commented                 ON ast_exten(commented);
+CREATE INDEX ast_exten__idx__context_exten_priority    ON ast_exten(context, exten, priority);
index bf538c6d8459f7829d03caccba5a9f8daf920a39..3a0094c0cbab6b04862a9b71d1d5e538defb14e2 100644 (file)
@@ -252,6 +252,7 @@ DUNDi is not itself a Voice-over IP signaling or media protocol. Instead, it pub
  * \arg \link Config_enum ENUM configuration  \endlink
  * \arg \link Config_moh Music on Hold configuration  \endlink
  * \arg \link Config_vm Voicemail configuration  \endlink
+ * \arg \link res_config_sqlite SQLite Resource driver configuration \endlink
  */
 
 /*! \page Config_ast Asterisk.conf
@@ -551,3 +552,13 @@ DUNDi is not itself a Voice-over IP signaling or media protocol. Instead, it pub
  *  \arg \link Config_ami Configuration file \endlink
  *  \verbinclude ajam.txt
  */
+
+/*! \page res_config_sqlite SQLite Resource driver configuration
+ * \arg Implemented in \ref res_config_sqlite.c
+ * \arg Configuration file:
+ * \verbinclude res_config_sqlite.conf
+ * \arg SQL tables:
+ * \verbinclude res_config_sqlite.txt
+ * \arg See also:
+ * http://www.sqlite.org
+ */
index 5797ba6f0ed7f26a994e22eb8cf05fb48d00a251..3cfb41648446df4150c8555d8c510279a292d5c9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Written by Richard Braun <rbraun@proformatique.com>
  *
- * Based on res_sqlite3 by Anthony Minessale II, 
+ * Based on res_sqlite3 by Anthony Minessale II,
  * and res_config_mysql by Matthew Boehm
  *
  * See http://www.asterisk.org for more information about
 
 /*!
  * \page res_config_sqlite
- * 
+ *
  * \section intro_sec Presentation
- * 
- * res_config_sqlite is a module for the Asterisk Open Source PBX to 
- * support SQLite 2 databases. It can be used to fetch configuration 
- * from a database (static configuration files and/or using the Asterisk 
+ *
+ * res_config_sqlite is a module for the Asterisk Open Source PBX to
+ * support SQLite 2 databases. It can be used to fetch configuration
+ * from a database (static configuration files and/or using the Asterisk
  * RealTime Architecture - ARA).
  * It can also be used to log CDR entries. Finally, it can be used for simple
  * queries in the Dialplan. Note that Asterisk already comes with a module
- * named cdr_sqlite. There are two reasons for including it in res_sqlite:
+ * named cdr_sqlite. There are two reasons for including it in res_config_sqlite:
  * the first is that rewriting it was a training to learn how to write a
  * simple module for Asterisk, the other is to have the same database open for
  * all kinds of operations, which improves reliability and performance.
- * 
+ *
  * There is already a module for SQLite 3 (named res_sqlite3) in the Asterisk
- * addons. res_sqlite was developed because we, at Proformatique, are using
+ * addons. res_config_sqlite was developed because we, at Proformatique, are using
  * PHP 4 in our embedded systems, and PHP 4 has no stable support for SQLite 3
  * at this time. We also needed RealTime support.
- * 
+ *
  * \section conf_sec Configuration
- * 
+ *
  * The main configuration file is res_config_sqlite.conf. It must be readable or
- * res_sqlite will fail to start. It is suggested to use the sample file
+ * res_config_sqlite will fail to start. It is suggested to use the sample file
  * in this package as a starting point. The file has only one section
  * named <code>general</code>. Here are the supported parameters :
- * 
+ *
  * <dl>
  *     <dt><code>dbfile</code></dt>
  *     <dd>The absolute path to the SQLite database (the file can be non existent,
- *                     res_sqlite will create it if is has the appropriate rights)</dd>
+ *                     res_config_sqlite will create it if it has the appropriate rights)</dd>
  *     <dt><code>config_table</code></dt>
  *     <dd>The table used for static configuration</dd>
  *     <dt><code>cdr_table</code></dt>
  *     <dd>The table used to store CDR entries (if ommitted, CDR support is
  *                     disabled)</dd>
  * </dl>
- * 
- * To use res_sqlite for static and/or RealTime configuration, refer to the
+ *
+ * To use res_config_sqlite for static and/or RealTime configuration, refer to the
  * Asterisk documentation. The file tables.sql can be used to create the
  * needed tables.
- * 
- * The SQLITE() application is very similar to the MYSQL() application. You
- * can find more details at
- * <a href="http://voip-info.org/wiki/view/Asterisk+cmd+MYSQL">http://voip-info.org/wiki/view/Asterisk+cmd+MYSQL</a>.
- * The main difference is that you cannot choose your database - it's the
- * file set in the <code>dbfile</code> parameter. As a result, there is no
- * Connect or Disconnect command, and there is no connid variable.
- * 
+ *
  * \section status_sec Driver status
- * 
+ *
  * The CLI command <code>show sqlite status</code> returns status information
- * about the running driver. One information is more important than others:
- * the number of registered virtual machines. A SQLite virtual machine is
- * created each time a SQLITE() query command is used. If the number of
- * registered virtual machines isn't 0 (or near 0, since one or more SQLITE()
- * commands can be running when requesting the module status) and increases
- * over time, this probably means that you're badly using the application
- * and you're creating resource leaks. You should check your Dialplan and
- * reload res_sqlite (by unloading and then loading again - reloading isn't
- * supported)
- * 
+ * about the running driver.
+ *
  * \section credits_sec Credits
- * 
+ *
  * res_config_sqlite was developed by Richard Braun at the Proformatique company.
  */
 
 /*!
- * \file 
- * \brief res_sqlite module.
+ * \file
+ * \brief res_config_sqlite module.
  */
 
 /*** MODULEINFO
 #include "asterisk/options.h"
 #include "asterisk/linkedlists.h"
 
-#define RES_SQLITE_NAME "res_sqlite"
-#define RES_SQLITE_DRIVER "sqlite"
-#define RES_SQLITE_APP_DRIVER "SQLITE"
-#define RES_SQLITE_DESCRIPTION "Resource Module for SQLite 2"
-#define RES_SQLITE_CONF_FILE "res_config_sqlite.conf"
-#define RES_SQLITE_APP_SYNOPSIS "Dialplan access to SQLite 2"
-#define RES_SQLITE_APP_DESCRIPTION \
-"SQLITE(): " RES_SQLITE_APP_SYNOPSIS "\n"
-#define RES_SQLITE_STATUS_SUMMARY \
-"Show status information about the SQLite 2 driver"
-#define RES_SQLITE_STATUS_USAGE \
-"Usage: show sqlite status\n" \
-"      " RES_SQLITE_STATUS_SUMMARY "\n"
+#define MACRO_BEGIN    do {
+#define MACRO_END      } while (0)
+
+#define RES_CONFIG_SQLITE_NAME "res_config_sqlite"
+#define RES_CONFIG_SQLITE_DRIVER "sqlite"
+#define RES_CONFIG_SQLITE_DESCRIPTION "Resource Module for SQLite 2"
+#define RES_CONFIG_SQLITE_CONF_FILE "res_config_sqlite.conf"
+#define RES_CONFIG_SQLITE_STATUS_SUMMARY "Show status information about the SQLite 2 driver"
+#define RES_CONFIG_SQLITE_STATUS_USAGE                 \
+       "Usage: show sqlite status\n"                   \
+       "       " RES_CONFIG_SQLITE_STATUS_SUMMARY "\n"
 
 enum {
-       RES_SQLITE_CONFIG_ID,
-       RES_SQLITE_CONFIG_COMMENTED,
-       RES_SQLITE_CONFIG_FILENAME,
-       RES_SQLITE_CONFIG_CATEGORY,
-       RES_SQLITE_CONFIG_VAR_NAME,
-       RES_SQLITE_CONFIG_VAR_VAL,
-       RES_SQLITE_CONFIG_COLUMNS,
+       RES_CONFIG_SQLITE_CONFIG_ID,
+       RES_CONFIG_SQLITE_CONFIG_COMMENTED,
+       RES_CONFIG_SQLITE_CONFIG_FILENAME,
+       RES_CONFIG_SQLITE_CONFIG_CATEGORY,
+       RES_CONFIG_SQLITE_CONFIG_VAR_NAME,
+       RES_CONFIG_SQLITE_CONFIG_VAR_VAL,
+       RES_CONFIG_SQLITE_CONFIG_COLUMNS,
 };
 
-/*!
- * Limit the number of maximum simultaneous registered SQLite VMs to avoid
- * a denial of service attack.
- */
-#define RES_SQLITE_VM_MAX 1024
-
-#define SET_VAR(config, to, from) \
-do \
-       { \
-               int __error; \
-               __error = set_var(&to, #to, from->value); \
-               if (__error) \
-                       { \
-                               ast_config_destroy(config); \
-                               unload_config(); \
-                               return 1; \
-                       } \
-       } \
-while (0)
+#define SET_VAR(config, to, from)                      \
+MACRO_BEGIN                                            \
+       int __error;                                    \
+                                                       \
+       __error = set_var(&to, #to, from->value);       \
+                                                       \
+       if (__error) {                                  \
+               ast_config_destroy(config);             \
+               unload_config();                        \
+               return 1;                               \
+       }                                               \
+MACRO_END
 
 /*!
  * Maximum number of loops before giving up executing a query. Calls to
  * sqlite_xxx() functions which can return SQLITE_BUSY or SQLITE_LOCKED
- * are enclosed by RES_SQLITE_BEGIN and RES_SQLITE_END, e.g.
+ * are enclosed by RES_CONFIG_SQLITE_BEGIN and RES_CONFIG_SQLITE_END, e.g.
  * <pre>
  * char *errormsg;
  * int error;
- * 
- * RES_SQLITE_BEGIN
+ *
+ * RES_CONFIG_SQLITE_BEGIN
  *      error = sqlite_exec(db, query, NULL, NULL, &errormsg);
- * RES_SQLITE_END(error)
- * 
+ * RES_CONFIG_SQLITE_END(error)
+ *
  * if (error)
  *      ...;
  * </pre>
  */
-#define RES_SQLITE_MAX_LOOPS 10
+#define RES_CONFIG_SQLITE_MAX_LOOPS 10
 
 /*!
  * Macro used before executing a query.
- * 
- * \see RES_SQLITE_MAX_LOOPS.
+ *
+ * \see RES_CONFIG_SQLITE_MAX_LOOPS.
  */
-#define RES_SQLITE_BEGIN \
-{ \
-       int __i; \
-       for (__i = 0; __i < RES_SQLITE_MAX_LOOPS; __i++) \
-               {
+#define RES_CONFIG_SQLITE_BEGIN                                                \
+MACRO_BEGIN                                                            \
+       int __i;                                                        \
+                                                                       \
+       for (__i = 0; __i < RES_CONFIG_SQLITE_MAX_LOOPS; __i++) {
 
 /*!
  * Macro used after executing a query.
- * 
- * \see RES_SQLITE_MAX_LOOPS.
+ *
+ * \see RES_CONFIG_SQLITE_MAX_LOOPS.
  */
-#define RES_SQLITE_END(error) \
-                       if (error != SQLITE_BUSY && error != SQLITE_LOCKED) \
-                               break; \
-                       usleep(1000); \
-               } \
-}
+#define RES_CONFIG_SQLITE_END(error)                                   \
+               if (error != SQLITE_BUSY && error != SQLITE_LOCKED)     \
+                       break;                                          \
+               usleep(1000);                                           \
+       }                                                               \
+MACRO_END;
 
 /*!
  * Structure sent to the SQLite callback function for static configuration.
- * 
+ *
  * \see add_cfg_entry()
  */
 struct cfg_entry_args {
@@ -212,7 +188,7 @@ struct cfg_entry_args {
 
 /*!
  * Structure sent to the SQLite callback function for RealTime configuration.
- * 
+ *
  * \see add_rt_cfg_entry()
  */
 struct rt_cfg_entry_args {
@@ -223,7 +199,7 @@ struct rt_cfg_entry_args {
 /*!
  * Structure sent to the SQLite callback function for RealTime configuration
  * (realtime_multi_handler()).
- * 
+ *
  * \see add_rt_multi_cfg_entry()
  */
 struct rt_multi_cfg_entry_args {
@@ -244,10 +220,10 @@ static int set_var(char **var, char *name, char *value);
 /*!
  * \brief Load the configuration file.
  * \see unload_config()
- * 
+ *
  * This function sets dbfile, config_table, and cdr_table. It calls
  * check_vars() before returning, and unload_config() if an error occurred.
- * 
+ *
  * \retval 0 on success
  * \retval 1 if an error occurred
  */
@@ -262,10 +238,10 @@ static void unload_config(void);
 /*!
  * \brief Asterisk callback function for CDR support.
  * \param cdr the CDR entry Asterisk sends us.
- * 
+ *
  * Asterisk will call this function each time a CDR entry must be logged if
  * CDR support is enabled.
- * 
+ *
  * \retval 0 on success
  * \retval 1 if an error occurred
  */
@@ -273,11 +249,11 @@ static int cdr_handler(struct ast_cdr *cdr);
 
 /*!
  * \brief SQLite callback function for static configuration.
- * 
+ *
  * This function is passed to the SQLite engine as a callback function to
  * parse a row and store it in a struct ast_config object. It relies on
- * resulting rows      being sorted by category.
- * 
+ * resulting rows being sorted by category.
+ *
  * \param arg a pointer to a struct cfg_entry_args object
  * \param argc number of columns
  * \param argv values in the row
@@ -292,10 +268,10 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames);
 
 /*!
  * \brief Asterisk callback function for static configuration.
- * 
+ *
  * Asterisk will call this function when it loads its static configuration,
  * which usually happens at startup and reload.
- * 
+ *
  * \param database the database to use (ignored)
  * \param table the table to use
  * \param file the file to load from the database
@@ -307,24 +283,24 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames);
  * \see add_cfg_entry()
  */
 static struct ast_config * config_handler(const char *database, const char *table, const char *file,
-struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl);
+       struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl);
 
 /*!
  * \brief Helper function to parse a va_list object into 2 dynamic arrays of
  * strings, parameters and values.
- * 
+ *
  * ap must have the following format : param1 val1 param2 val2 param3 val3 ...
  * arguments will be extracted to create 2 arrays:
- * 
+ *
  * <ul>
  *     <li>params : param1 param2 param3 ...</li>
  *     <li>vals : val1 val2 val3 ...</li>
  * </ul>
- * 
+ *
  * The address of these arrays are stored in params_ptr and vals_ptr. It
  * is the responsibility of the caller to release the memory of these arrays.
  * It is considered an error that va_list has a null or odd number of strings.
- * 
+ *
  * \param ap the va_list object to parse
  * \param params_ptr where the address of the params array is stored
  * \param vals_ptr where the address of the vals array is stored
@@ -336,10 +312,10 @@ static size_t get_params(va_list ap, const char ***params_ptr,
 
 /*!
  * \brief SQLite callback function for RealTime configuration.
- * 
+ *
  * This function is passed to the SQLite engine as a callback function to
  * parse a row and store it in a linked list of struct ast_variable objects.
- * 
+ *
  * \param arg a pointer to a struct rt_cfg_entry_args object
  * \param argc number of columns
  * \param argv values in the row
@@ -354,16 +330,16 @@ static int add_rt_cfg_entry(void *arg, int argc, char **argv,
 
 /*!
  * Asterisk callback function for RealTime configuration.
- * 
+ *
  * Asterisk will call this function each time it requires a variable
  * through the RealTime architecture. ap is a list of parameters and
  * values used to find a specific row, e.g one parameter "name" and
  * one value "123" so that the SQL query becomes <code>SELECT * FROM
  * table WHERE name = '123';</code>.
- * 
+ *
  * \param database the database to use (ignored)
- * \param table                the table to use
- * \param ap                    list of parameters and values to match
+ * \param table the table to use
+ * \param ap list of parameters and values to match
  *
  * \retval a linked list of struct ast_variable objects
  * \retval NULL if an error occurred
@@ -374,11 +350,11 @@ static struct ast_variable * realtime_handler(const char *database,
 
 /*!
  * \brief SQLite callback function for RealTime configuration.
- * 
+ *
  * This function performs the same actions as add_rt_cfg_entry() except
  * that the rt_multi_cfg_entry_args structure is designed to store
- * categories in addition of variables.
- * 
+ * categories in addition to variables.
+ *
  * \param arg a pointer to a struct rt_multi_cfg_entry_args object
  * \param argc number of columns
  * \param argv values in the row
@@ -393,11 +369,11 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv,
 
 /*!
  * \brief Asterisk callback function for RealTime configuration.
- * 
+ *
  * This function performs the same actions as realtime_handler() except
  * that it can store variables per category, and can return several
  * categories.
- * 
+ *
  * \param database the database to use (ignored)
  * \param table the table to use
  * \param ap list of parameters and values to match
@@ -407,19 +383,18 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv,
  * \see add_rt_multi_cfg_entry()
  */
 static struct ast_config * realtime_multi_handler(const char *database,
-       const char *table,
-       va_list ap);
+       const char *table, va_list ap);
 
 /*!
  * \brief Asterisk callback function for RealTime configuration (variable
  * update).
- * 
+ *
  * Asterisk will call this function each time a variable has been modified
  * internally and must be updated in the backend engine. keyfield and entity
  * are used to find the row to update, e.g. <code>UPDATE table SET ... WHERE
  * keyfield = 'entity';</code>. ap is a list of parameters and values with the
  * same format as the other realtime functions.
- * 
+ *
  * \param database the database to use (ignored)
  * \param table the table to use
  * \param keyfield the column of the matching cell
@@ -429,18 +404,17 @@ static struct ast_config * realtime_multi_handler(const char *database,
  * \retval -1 if an error occurred.
  */
 static int realtime_update_handler(const char *database, const char *table,
-       const char *keyfield, const char *entity,
-       va_list ap);
+       const char *keyfield, const char *entity, va_list ap);
 
 /*!
  * \brief Asterisk callback function for RealTime configuration (variable
  * create/store).
- * 
+ *
  * Asterisk will call this function each time a variable has been created
- * internally and must be stored in the backend engine. 
- * are used to find the row to update, e.g. ap is a list of parameters and 
+ * internally and must be stored in the backend engine.
+ * are used to find the row to update, e.g. ap is a list of parameters and
  * values with the same format as the other realtime functions.
- * 
+ *
  * \param database the database to use (ignored)
  * \param table the table to use
  * \param ap list of parameters and new values to insert into the database
@@ -451,15 +425,15 @@ static int realtime_store_handler(const char *database, const char *table,
        va_list ap);
 
 /*!
- * \brief Asterisk callback function for RealTime configuration (destroys 
+ * \brief Asterisk callback function for RealTime configuration (destroys
  * variable).
- * 
+ *
  * Asterisk will call this function each time a variable has been destroyed
  * internally and must be removed from the backend engine. keyfield and entity
  * are used to find the row to delete, e.g. <code>DELETE FROM table WHERE
  * keyfield = 'entity';</code>. ap is a list of parameters and values with the
  * same format as the other realtime functions.
- * 
+ *
  * \param database the database to use (ignored)
  * \param table the table to use
  * \param keyfield the column of the matching cell
@@ -469,12 +443,11 @@ static int realtime_store_handler(const char *database, const char *table,
  * \retval -1 if an error occurred.
  */
 static int realtime_destroy_handler(const char *database, const char *table,
-       const char *keyfield, const char *entity,
-       va_list ap);
+       const char *keyfield, const char *entity, va_list ap);
 
 /*!
  * \brief Asterisk callback function for the CLI status command.
- * 
+ *
  * \param fd file descriptor provided by Asterisk to use with ast_cli()
  * \param argc number of arguments
  * \param argv arguments list
@@ -503,16 +476,13 @@ static char *config_table;
 /*! The name of the table used to store CDR entries. */
 static char *cdr_table;
 
-/*! The number of registered virtual machines. */
-static int vm_count;
-
 /*!
  * The structure specifying all callback functions used by Asterisk for static
  * and RealTime configuration.
  */
 static struct ast_config_engine sqlite_engine =
 {
-       .name = RES_SQLITE_DRIVER,
+       .name = RES_CONFIG_SQLITE_DRIVER,
        .load_func = config_handler,
        .realtime_func = realtime_handler,
        .realtime_multi_func = realtime_multi_handler,
@@ -523,7 +493,6 @@ static struct ast_config_engine sqlite_engine =
 
 /*!
  * The mutex used to prevent simultaneous access to the SQLite database.
- * SQLite isn't always compiled with thread safety.
  */
 AST_MUTEX_DEFINE_STATIC(mutex);
 
@@ -535,8 +504,8 @@ static struct ast_cli_entry cli_status_cmd =
 {
        .cmda = {"show", "sqlite", "status", NULL},
        .handler = cli_status,
-       .summary = RES_SQLITE_STATUS_SUMMARY,
-       .usage = RES_SQLITE_STATUS_USAGE
+       .summary = RES_CONFIG_SQLITE_STATUS_SUMMARY,
+       .usage = RES_CONFIG_SQLITE_STATUS_USAGE
 };
 
 /*
@@ -545,32 +514,33 @@ static struct ast_cli_entry cli_status_cmd =
 
 /*! SQL query format to create the CDR table if non existent. */
 static char *sql_create_cdr_table =
-"CREATE TABLE '%q' ("
-"      id              INTEGER PRIMARY KEY,"
-"      clid            VARCHAR(80) NOT NULL DEFAULT '',"
-"      src             VARCHAR(80) NOT NULL DEFAULT '',"
-"      dst             VARCHAR(80) NOT NULL DEFAULT '',"
-"      dcontext        VARCHAR(80) NOT NULL DEFAULT '',"
-"      channel         VARCHAR(80) NOT NULL DEFAULT '',"
-"      dstchannel      VARCHAR(80) NOT NULL DEFAULT '',"
-"      lastapp         VARCHAR(80) NOT NULL DEFAULT '',"
-"      lastdata        VARCHAR(80) NOT NULL DEFAULT '',"
-"      start           CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',"
-"      answer          CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',"
-"      end             CHAR(19) NOT NULL DEFAULT '0000-00-00 00:00:00',"
-"      duration        INT(11) NOT NULL DEFAULT '0',"
-"      billsec         INT(11) NOT NULL DEFAULT '0',"
-"      disposition     INT(11) NOT NULL DEFAULT '0',"
-"      amaflags        INT(11) NOT NULL DEFAULT '0',"
-"      accountcode     VARCHAR(20) NOT NULL DEFAULT '',"
-"      uniqueid        VARCHAR(32) NOT NULL DEFAULT '',"
-"      userfield       VARCHAR(255) NOT NULL DEFAULT ''"
+"CREATE TABLE '%q' (\n"
+"      id              INTEGER,\n"
+"      clid            VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      src             VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      dst             VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      dcontext        VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      channel         VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      dstchannel      VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      lastapp         VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      lastdata        VARCHAR(80)     NOT NULL        DEFAULT '',\n"
+"      start           DATETIME        NOT NULL        DEFAULT '0000-00-00 00:00:00',\n"
+"      answer          DATETIME        NOT NULL        DEFAULT '0000-00-00 00:00:00',\n"
+"      end             DATETIME        NOT NULL        DEFAULT '0000-00-00 00:00:00',\n"
+"      duration        INT(11)         NOT NULL        DEFAULT 0,\n"
+"      billsec         INT(11)         NOT NULL        DEFAULT 0,\n"
+"      disposition     VARCHAR(45)     NOT NULL        DEFAULT '',\n"
+"      amaflags        INT(11)         NOT NULL        DEFAULT 0,\n"
+"      accountcode     VARCHAR(20)     NOT NULL        DEFAULT '',\n"
+"      uniqueid        VARCHAR(32)     NOT NULL        DEFAULT '',\n"
+"      userfield       VARCHAR(255)    NOT NULL        DEFAULT '',\n"
+"      PRIMARY KEY     (id)\n"
 ");";
 
 /*! SQL query format to insert a CDR entry. */
 static char *sql_add_cdr_entry =
 "INSERT INTO '%q' ("
-"                       clid,"
+"      clid,"
 "      src,"
 "      dst,"
 "      dcontext,"
@@ -612,7 +582,7 @@ static char *sql_add_cdr_entry =
 /*!
  * SQL query format to fetch the static configuration of a file.
  * Rows must be sorted by category.
- * 
+ *
  * \see add_cfg_entry()
  */
 static char *sql_get_config_table =
@@ -655,10 +625,10 @@ static int load_config(void)
        int error;
        struct ast_flags config_flags = { 0 };
 
-       config = ast_config_load(RES_SQLITE_CONF_FILE, config_flags);
+       config = ast_config_load(RES_CONFIG_SQLITE_CONF_FILE, config_flags);
 
        if (!config) {
-               ast_log(LOG_ERROR, "Unable to load " RES_SQLITE_CONF_FILE "\n");
+               ast_log(LOG_ERROR, "Unable to load " RES_CONFIG_SQLITE_CONF_FILE "\n");
                return 1;
        }
 
@@ -696,27 +666,37 @@ static void unload_config(void)
 
 static int cdr_handler(struct ast_cdr *cdr)
 {
-       char *errormsg;
+       char *query, *errormsg;
        int error;
 
+       query = sqlite_mprintf(sql_add_cdr_entry, cdr_table, cdr->clid,
+                       cdr->src, cdr->dst, cdr->dcontext, cdr->channel,
+                       cdr->dstchannel, cdr->lastapp, cdr->lastdata,
+                       cdr->start.tv_sec, cdr->answer.tv_sec,
+                       cdr->end.tv_sec, cdr->duration, cdr->billsec,
+                       cdr->disposition, cdr->amaflags, cdr->accountcode,
+                       cdr->uniqueid, cdr->userfield);
+
+       if (!query) {
+               ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
+               return 1;
+       }
+
+       ast_debug(1, "SQL query: %s\n", query);
+
        ast_mutex_lock(&mutex);
 
-       RES_SQLITE_BEGIN
-               error = sqlite_exec_printf(db, sql_add_cdr_entry, NULL, NULL, &errormsg,
-                                        cdr_table, cdr->clid, cdr->src, cdr->dst,
-                                        cdr->dcontext, cdr->channel, cdr->dstchannel,
-                                        cdr->lastapp, cdr->lastdata, cdr->start.tv_sec,
-                                        cdr->answer.tv_sec, cdr->end.tv_sec,
-                                        cdr->duration, cdr->billsec, cdr->disposition,
-                                        cdr->amaflags, cdr->accountcode, cdr->uniqueid,
-                                        cdr->userfield);
-       RES_SQLITE_END(error)
+       RES_CONFIG_SQLITE_BEGIN
+               error = sqlite_exec(db, query, NULL, NULL, &errormsg);
+       RES_CONFIG_SQLITE_END(error)
 
        ast_mutex_unlock(&mutex);
 
+       sqlite_freemem(query);
+
        if (error) {
                ast_log(LOG_ERROR, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
                return 1;
        }
 
@@ -728,15 +708,15 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
        struct cfg_entry_args *args;
        struct ast_variable *var;
 
-       if (argc != RES_SQLITE_CONFIG_COLUMNS) {
+       if (argc != RES_CONFIG_SQLITE_CONFIG_COLUMNS) {
                ast_log(LOG_WARNING, "Corrupt table\n");
                return 1;
        }
 
        args = arg;
 
-       if (!args->cat_name || strcmp(args->cat_name, argv[RES_SQLITE_CONFIG_CATEGORY])) {
-               args->cat = ast_category_new(argv[RES_SQLITE_CONFIG_CATEGORY], "", 99999);
+       if (!args->cat_name || strcmp(args->cat_name, argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY])) {
+               args->cat = ast_category_new(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY], "", 99999);
 
                if (!args->cat) {
                        ast_log(LOG_WARNING, "Unable to allocate category\n");
@@ -744,7 +724,7 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
                }
 
                ast_free(args->cat_name);
-               args->cat_name = ast_strdup(argv[RES_SQLITE_CONFIG_CATEGORY]);
+               args->cat_name = ast_strdup(argv[RES_CONFIG_SQLITE_CONFIG_CATEGORY]);
 
                if (!args->cat_name) {
                        ast_category_destroy(args->cat);
@@ -754,8 +734,7 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
                ast_category_append(args->cfg, args->cat);
        }
 
-       var = ast_variable_new(argv[RES_SQLITE_CONFIG_VAR_NAME],
-                                                  argv[RES_SQLITE_CONFIG_VAR_VAL], "");
+       var = ast_variable_new(argv[RES_CONFIG_SQLITE_CONFIG_VAR_NAME], argv[RES_CONFIG_SQLITE_CONFIG_VAR_VAL], "");
 
        if (!var) {
                ast_log(LOG_WARNING, "Unable to allocate variable");
@@ -763,15 +742,15 @@ static int add_cfg_entry(void *arg, int argc, char **argv, char **columnNames)
        }
 
        ast_variable_append(args->cat, var);
-       
+
        return 0;
 }
 
 static struct ast_config *config_handler(const char *database, const char *table, const char *file,
-struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl)
+       struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl)
 {
        struct cfg_entry_args args;
-       char *errormsg;
+       char *query, *errormsg;
        int error;
 
        if (!config_table) {
@@ -782,24 +761,32 @@ struct ast_config *cfg, struct ast_flags flags, const char *suggested_incl)
        } else
                table = config_table;
 
+       query = sqlite_mprintf(sql_get_config_table, table, file);
+
+       if (!query) {
+               ast_log(LOG_WARNING, "Unable to allocate SQL query\n");
+               return NULL;
+       }
+
+       ast_debug(1, "SQL query: %s\n", query);
        args.cfg = cfg;
        args.cat = NULL;
        args.cat_name = NULL;
 
        ast_mutex_lock(&mutex);
 
-       RES_SQLITE_BEGIN
-               error = sqlite_exec_printf(db, sql_get_config_table, add_cfg_entry,
-                                       &args, &errormsg, table, file);
-       RES_SQLITE_END(error)
+       RES_CONFIG_SQLITE_BEGIN
+               error = sqlite_exec(db, query, add_cfg_entry, &args, &errormsg);
+       RES_CONFIG_SQLITE_END(error)
 
        ast_mutex_unlock(&mutex);
 
        ast_free(args.cat_name);
+       sqlite_freemem(query);
 
        if (error) {
                ast_log(LOG_ERROR, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
                return NULL;
        }
 
@@ -873,8 +860,7 @@ static int add_rt_cfg_entry(void *arg, int argc, char **argv, char **columnNames
        return 0;
 }
 
-static struct ast_variable *
-realtime_handler(const char *database, const char *table, va_list ap)
+static struct ast_variable * realtime_handler(const char *database, const char *table, va_list ap)
 {
        char *query, *errormsg, *op, *tmp_str;
        struct rt_cfg_entry_args args;
@@ -913,8 +899,7 @@ realtime_handler(const char *database, const char *table, va_list ap)
 
                for (i = 1; i < params_count; i++) {
                        op = (strchr(params[i], ' ') == NULL) ? " =" : "";
-                       tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op,
-                                                                                                                        vals[i]);
+                       tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op, vals[i]);
                        sqlite_freemem(query);
 
                        if (!tmp_str) {
@@ -946,9 +931,9 @@ realtime_handler(const char *database, const char *table, va_list ap)
 
        ast_mutex_lock(&mutex);
 
-       RES_SQLITE_BEGIN
+       RES_CONFIG_SQLITE_BEGIN
                error = sqlite_exec(db, query, add_rt_cfg_entry, &args, &errormsg);
-       RES_SQLITE_END(error)
+       RES_CONFIG_SQLITE_END(error)
 
        ast_mutex_unlock(&mutex);
 
@@ -956,7 +941,7 @@ realtime_handler(const char *database, const char *table, va_list ap)
 
        if (error) {
                ast_log(LOG_WARNING, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
                ast_variables_destroy(args.var);
                return NULL;
        }
@@ -972,7 +957,7 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv, char **colum
        char *cat_name;
        size_t i;
 
-       args = (struct rt_multi_cfg_entry_args *)arg;
+       args = arg;
        cat_name = NULL;
 
        /*
@@ -1012,7 +997,7 @@ static int add_rt_multi_cfg_entry(void *arg, int argc, char **argv, char **colum
        return 0;
 }
 
-static struct ast_config *realtime_multi_handler(const char *database, 
+static struct ast_config *realtime_multi_handler(const char *database,
        const char *table, va_list ap)
 {
        char *query, *errormsg, *op, *tmp_str, *initfield;
@@ -1076,8 +1061,7 @@ static struct ast_config *realtime_multi_handler(const char *database,
 
                for (i = 1; i < params_count; i++) {
                        op = (!strchr(params[i], ' ')) ? " =" : "";
-                       tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op,
-                                                                                                                        vals[i]);
+                       tmp_str = sqlite_mprintf("%s AND %q%s '%q'", query, params[i], op, vals[i]);
                        sqlite_freemem(query);
 
                        if (!tmp_str) {
@@ -1111,9 +1095,9 @@ static struct ast_config *realtime_multi_handler(const char *database,
 
        ast_mutex_lock(&mutex);
 
-       RES_SQLITE_BEGIN
+       RES_CONFIG_SQLITE_BEGIN
                error = sqlite_exec(db, query, add_rt_multi_cfg_entry, &args, &errormsg);
-       RES_SQLITE_END(error)
+       RES_CONFIG_SQLITE_END(error)
 
        ast_mutex_unlock(&mutex);
 
@@ -1122,7 +1106,7 @@ static struct ast_config *realtime_multi_handler(const char *database,
 
        if (error) {
                ast_log(LOG_WARNING, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
                ast_config_destroy(cfg);
                return NULL;
        }
@@ -1131,8 +1115,7 @@ static struct ast_config *realtime_multi_handler(const char *database,
 }
 
 static int realtime_update_handler(const char *database, const char *table,
-       const char *keyfield, const char *entity,
-       va_list ap)
+       const char *keyfield, const char *entity, va_list ap)
 {
        char *query, *errormsg, *tmp_str;
        const char **params, **vals;
@@ -1163,8 +1146,7 @@ static int realtime_update_handler(const char *database, const char *table,
                size_t i;
 
                for (i = 1; i < params_count; i++) {
-                       tmp_str = sqlite_mprintf("%s, %q = '%q'", query, params[i],
-                                                                                                                        vals[i]);
+                       tmp_str = sqlite_mprintf("%s, %q = '%q'", query, params[i], vals[i]);
                        sqlite_freemem(query);
 
                        if (!tmp_str) {
@@ -1192,9 +1174,9 @@ static int realtime_update_handler(const char *database, const char *table,
 
        ast_mutex_lock(&mutex);
 
-       RES_SQLITE_BEGIN
+       RES_CONFIG_SQLITE_BEGIN
                error = sqlite_exec(db, query, NULL, NULL, &errormsg);
-       RES_SQLITE_END(error)
+       RES_CONFIG_SQLITE_END(error)
 
        if (!error)
                rows_num = sqlite_changes(db);
@@ -1207,7 +1189,7 @@ static int realtime_update_handler(const char *database, const char *table,
 
        if (error) {
                ast_log(LOG_WARNING, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
        }
 
        return rows_num;
@@ -1282,9 +1264,9 @@ static int realtime_store_handler(const char *database, const char *table, va_li
 
        ast_mutex_lock(&mutex);
 
-       RES_SQLITE_BEGIN
+       RES_CONFIG_SQLITE_BEGIN
                error = sqlite_exec(db, tmp_str, NULL, NULL, &errormsg);
-       RES_SQLITE_END(error)
+       RES_CONFIG_SQLITE_END(error)
 
        if (!error) {
                rows_id = sqlite_last_insert_rowid(db);
@@ -1298,15 +1280,14 @@ static int realtime_store_handler(const char *database, const char *table, va_li
 
        if (error) {
                ast_log(LOG_WARNING, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
        }
 
        return rows_id;
 }
 
 static int realtime_destroy_handler(const char *database, const char *table,
-       const char *keyfield, const char *entity,
-       va_list ap)
+       const char *keyfield, const char *entity, va_list ap)
 {
        char *query, *errormsg, *tmp_str;
        const char **params, **vals;
@@ -1356,14 +1337,13 @@ static int realtime_destroy_handler(const char *database, const char *table,
        }
        sqlite_freemem(query);
        query = tmp_str;
-
        ast_debug(1, "SQL query: %s\n", query);
 
        ast_mutex_lock(&mutex);
 
-       RES_SQLITE_BEGIN
+       RES_CONFIG_SQLITE_BEGIN
                error = sqlite_exec(db, query, NULL, NULL, &errormsg);
-       RES_SQLITE_END(error)
+       RES_CONFIG_SQLITE_END(error)
 
        if (!error)
                rows_num = sqlite_changes(db);
@@ -1376,7 +1356,7 @@ static int realtime_destroy_handler(const char *database, const char *table,
 
        if (error) {
                ast_log(LOG_WARNING, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
        }
 
        return rows_num;
@@ -1409,7 +1389,7 @@ static int unload_module(void)
                ast_cli_unregister(&cli_status_cmd);
 
        if (cdr_registered)
-               ast_cdr_unregister(RES_SQLITE_NAME);
+               ast_cdr_unregister(RES_CONFIG_SQLITE_NAME);
 
        ast_config_engine_deregister(&sqlite_engine);
 
@@ -1432,7 +1412,6 @@ static int load_module(void)
        dbfile = NULL;
        config_table = NULL;
        cdr_table = NULL;
-       vm_count = 0;
        error = load_config();
 
        if (error)
@@ -1440,7 +1419,7 @@ static int load_module(void)
 
        if (!(db = sqlite_open(dbfile, 0660, &errormsg))) {
                ast_log(LOG_ERROR, "%s\n", errormsg);
-               ast_free(errormsg);
+               sqlite_freemem(errormsg);
                unload_module();
                return 1;
        }
@@ -1448,10 +1427,28 @@ static int load_module(void)
        ast_config_engine_register(&sqlite_engine);
 
        if (use_cdr) {
-               RES_SQLITE_BEGIN
-                       error = sqlite_exec_printf(db, "SELECT COUNT(id) FROM %Q;", NULL, NULL,
-                                                                                                                                &errormsg, cdr_table);
-               RES_SQLITE_END(error)
+               char *query;
+
+/* \cond DOXYGEN_CAN_PARSE_THIS */
+#undef QUERY
+#define QUERY "SELECT COUNT(id) FROM %Q;"
+/* \endcond */
+
+               query = sqlite_mprintf(QUERY, cdr_table);
+
+               if (!query) {
+                       ast_log(LOG_ERROR, "Unable to allocate SQL query\n");
+                       unload_module();
+                       return 1;
+               }
+
+               ast_debug(1, "SQL query: %s\n", query);
+
+               RES_CONFIG_SQLITE_BEGIN
+                       error = sqlite_exec(db, query, NULL, NULL, &errormsg);
+               RES_CONFIG_SQLITE_END(error)
+
+               sqlite_freemem(query);
 
                if (error) {
                        /*
@@ -1459,26 +1456,37 @@ static int load_module(void)
                         */
                        if (error != SQLITE_ERROR) {
                                ast_log(LOG_ERROR, "%s\n", errormsg);
-                               ast_free(errormsg);
+                               sqlite_freemem(errormsg);
+                               unload_module();
+                               return 1;
+                       }
+
+                       sqlite_freemem(errormsg);
+                       query = sqlite_mprintf(sql_create_cdr_table, cdr_table);
+
+                       if (!query) {
+                               ast_log(LOG_ERROR, "Unable to allocate SQL query\n");
                                unload_module();
                                return 1;
                        }
 
-                       RES_SQLITE_BEGIN
-                               error = sqlite_exec_printf(db, sql_create_cdr_table, NULL, NULL,
-                                                               &errormsg, cdr_table);
-                       RES_SQLITE_END(error)
+                       ast_debug(1, "SQL query: %s\n", query);
+
+                       RES_CONFIG_SQLITE_BEGIN
+                               error = sqlite_exec(db, query, NULL, NULL, &errormsg);
+                       RES_CONFIG_SQLITE_END(error)
+
+                       sqlite_freemem(query);
 
                        if (error) {
                                ast_log(LOG_ERROR, "%s\n", errormsg);
-                               ast_free(errormsg);
+                               sqlite_freemem(errormsg);
                                unload_module();
                                return 1;
                        }
                }
 
-               error = ast_cdr_register(RES_SQLITE_NAME, RES_SQLITE_DESCRIPTION,
-                                                                                                                cdr_handler);
+               error = ast_cdr_register(RES_CONFIG_SQLITE_NAME, RES_CONFIG_SQLITE_DESCRIPTION, cdr_handler);
 
                if (error) {
                        unload_module();