[asterisk-commits] twilson: trunk r326589 - in /trunk: ./ main/ main/db1-ast/ tests/ utils/ util...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jul 6 15:58:18 CDT 2011


Author: twilson
Date: Wed Jul  6 15:58:12 2011
New Revision: 326589

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=326589
Log:
Replace Berkeley DB with SQLite 3

There were some bugs in the very ancient version of Berkeley DB that Asterisk
used. Instead of spending the time tracking down the bugs in the Berekeley code
we move to the much better documented SQLite 3.

Conversion of the old astdb happens at runtime by running the included
astdb2sqlite3 utility. The ast_db API with SQLite 3 backend should behave
identically to the old Berkeley backend, but in the future we could offer a
much more robust interface.

We do not include the SQLite 3 library in the source tree, but instead rely
upon the distribution-provided libraries. SQLite is so ubiquitous that this
should not place undue burden on administrators.

Added:
    trunk/utils/astdb2sqlite3.c
      - copied, changed from r326587, team/twilson/sqlite_astdb/utils/astdb2sqlite3.c
    trunk/utils/db1-ast/   (props changed)
      - copied from r326587, team/twilson/sqlite_astdb/utils/db1-ast/
    trunk/utils/db1-ast/Makefile
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/Makefile
    trunk/utils/db1-ast/btree/   (props changed)
      - copied from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/
    trunk/utils/db1-ast/btree/bt_close.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_close.c
    trunk/utils/db1-ast/btree/bt_conv.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_conv.c
    trunk/utils/db1-ast/btree/bt_debug.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_debug.c
    trunk/utils/db1-ast/btree/bt_delete.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_delete.c
    trunk/utils/db1-ast/btree/bt_get.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_get.c
    trunk/utils/db1-ast/btree/bt_open.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_open.c
    trunk/utils/db1-ast/btree/bt_overflow.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_overflow.c
    trunk/utils/db1-ast/btree/bt_page.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_page.c
    trunk/utils/db1-ast/btree/bt_put.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_put.c
    trunk/utils/db1-ast/btree/bt_search.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_search.c
    trunk/utils/db1-ast/btree/bt_seq.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_seq.c
    trunk/utils/db1-ast/btree/bt_split.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_split.c
    trunk/utils/db1-ast/btree/bt_utils.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/bt_utils.c
    trunk/utils/db1-ast/btree/btree.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/btree.h
    trunk/utils/db1-ast/btree/extern.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/btree/extern.h
    trunk/utils/db1-ast/db/   (props changed)
      - copied from r326587, team/twilson/sqlite_astdb/utils/db1-ast/db/
    trunk/utils/db1-ast/db/db.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/db/db.c
    trunk/utils/db1-ast/hash/   (props changed)
      - copied from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/
    trunk/utils/db1-ast/hash/README
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/README
    trunk/utils/db1-ast/hash/extern.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/extern.h
    trunk/utils/db1-ast/hash/hash.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hash.c
    trunk/utils/db1-ast/hash/hash.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hash.h
    trunk/utils/db1-ast/hash/hash_bigkey.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hash_bigkey.c
    trunk/utils/db1-ast/hash/hash_buf.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hash_buf.c
    trunk/utils/db1-ast/hash/hash_func.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hash_func.c
    trunk/utils/db1-ast/hash/hash_log2.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hash_log2.c
    trunk/utils/db1-ast/hash/hash_page.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hash_page.c
    trunk/utils/db1-ast/hash/hsearch.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/hsearch.c
    trunk/utils/db1-ast/hash/ndbm.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/ndbm.c
    trunk/utils/db1-ast/hash/page.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/page.h
    trunk/utils/db1-ast/hash/search.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/hash/search.h
    trunk/utils/db1-ast/include/
      - copied from r326587, team/twilson/sqlite_astdb/utils/db1-ast/include/
    trunk/utils/db1-ast/include/circ-queue.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/include/circ-queue.h
    trunk/utils/db1-ast/include/compat.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/include/compat.h
    trunk/utils/db1-ast/include/db.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/include/db.h
    trunk/utils/db1-ast/include/mpool.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/include/mpool.h
    trunk/utils/db1-ast/include/ndbm.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/include/ndbm.h
    trunk/utils/db1-ast/libdb.map
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/libdb.map
    trunk/utils/db1-ast/mpool/   (props changed)
      - copied from r326587, team/twilson/sqlite_astdb/utils/db1-ast/mpool/
    trunk/utils/db1-ast/mpool/README
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/mpool/README
    trunk/utils/db1-ast/mpool/mpool.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/mpool/mpool.c
    trunk/utils/db1-ast/recno/   (props changed)
      - copied from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/
    trunk/utils/db1-ast/recno/extern.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/extern.h
    trunk/utils/db1-ast/recno/rec_close.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_close.c
    trunk/utils/db1-ast/recno/rec_delete.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_delete.c
    trunk/utils/db1-ast/recno/rec_get.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_get.c
    trunk/utils/db1-ast/recno/rec_open.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_open.c
    trunk/utils/db1-ast/recno/rec_put.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_put.c
    trunk/utils/db1-ast/recno/rec_search.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_search.c
    trunk/utils/db1-ast/recno/rec_seq.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_seq.c
    trunk/utils/db1-ast/recno/rec_utils.c
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/rec_utils.c
    trunk/utils/db1-ast/recno/recno.h
      - copied unchanged from r326587, team/twilson/sqlite_astdb/utils/db1-ast/recno/recno.h
Removed:
    trunk/main/db1-ast/
Modified:
    trunk/CHANGES
    trunk/Makefile
    trunk/UPGRADE.txt
    trunk/configure
    trunk/configure.ac
    trunk/main/Makefile
    trunk/main/asterisk.c
    trunk/main/db.c
    trunk/tests/test_db.c
    trunk/utils/   (props changed)
    trunk/utils/Makefile
    trunk/utils/utils.xml

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=326589&r1=326588&r2=326589
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Wed Jul  6 15:58:12 2011
@@ -187,6 +187,14 @@
    a MeetMe conference
  * Added ability to include '@parkinglot' to ParkedCall extension in order to specify
    a specific parkinglot on which to search the extension.
+
+Asterisk Database
+-----------------
+ * The internal Asterisk database has been switched from Berkeley DB 1.86 to
+   SQLite 3. An existing Berkeley astdb file can be converted with the astdb2sqlite3
+   utility in the UTILS section of menuselect. If an existing astdb is found and no
+   astdb.sqlite3 exists, astdb2sqlite3 will be compiled automatically. Asterisk will
+   convert an existing astdb to the SQLite3 version automatically at runtime.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.6.2 to Asterisk 1.8 ----------------

Modified: trunk/Makefile
URL: http://svnview.digium.com/svn/asterisk/trunk/Makefile?view=diff&rev=326589&r1=326588&r2=326589
==============================================================================
--- trunk/Makefile (original)
+++ trunk/Makefile Wed Jul  6 15:58:12 2011
@@ -838,6 +838,7 @@
 
 cleantest:
 	@cmp -s .cleancount .lastclean || $(MAKE) clean
+	@[ -f "$(DESTDIR)$(ASTDBDIR)/astdb.sqlite3" ] || [ ! -f "$(DESTDIR)$(ASTDBDIR)/astdb" ] || [ ! -f menuselect.makeopts ] || grep -q MENUSELECT_UTILS=.*astdb2sqlite3 menuselect.makeopts || (sed -i.orig -e's/MENUSELECT_UTILS=\(.*\)/MENUSELECT_UTILS=\1 astdb2sqlite3/' menuselect.makeopts && echo "Updating menuselect.makeopts to include astdb2sqlite3" && echo "Original version backed up to menuselect.makeopts.orig")
 
 $(SUBDIRS_UNINSTALL):
 	+@$(SUBMAKE) -C $(@:-uninstall=) uninstall

Modified: trunk/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/trunk/UPGRADE.txt?view=diff&rev=326589&r1=326588&r2=326589
==============================================================================
--- trunk/UPGRADE.txt (original)
+++ trunk/UPGRADE.txt Wed Jul  6 15:58:12 2011
@@ -54,5 +54,12 @@
  - Mark QUEUE_MEMBER_PENALTY Deprecated it never worked for realtime members
  - QUEUE_MEMBER is now R/W supporting setting paused, ignorebusy and penalty.
 
+ Asterisk Database:
+ - The internal Asterisk database has been switched from Berkeley DB 1.86 to
+   SQLite 3. An existing Berkeley astdb file can be converted with the astdb2sqlite3
+   utility in the UTILS section of menuselect. If an existing astdb is found and no
+   astdb.sqlite3 exists, astdb2sqlite3 will be compiled automatically. Asterisk will
+   convert an existing astdb to the SQLite3 version automatically at runtime.
+
 ===========================================================
 ===========================================================

Modified: trunk/configure.ac
URL: http://svnview.digium.com/svn/asterisk/trunk/configure.ac?view=diff&rev=326589&r1=326588&r2=326589
==============================================================================
--- trunk/configure.ac (original)
+++ trunk/configure.ac Wed Jul  6 15:58:12 2011
@@ -1970,6 +1970,12 @@
 
 AST_EXT_LIB_CHECK([SQLITE3], [sqlite3], [sqlite3_open], [sqlite3.h], [${PTHREAD_LIBS}], [${PTHREAD_CFLAGS}])
 
+if test "${PBX_SQLITE3}" != 1; then
+	AC_MSG_WARN(*** Asterisk now uses SQLite3 for the internal Asterisk database.)
+	AC_MSG_WARN(*** Please install the SQLite3 development package.)
+	exit 1
+fi
+
 AST_EXT_LIB_CHECK([CRYPTO], [crypto], [AES_encrypt], [openssl/aes.h])
 
 if test "$PBX_CRYPTO" = "1";

Modified: trunk/main/Makefile
URL: http://svnview.digium.com/svn/asterisk/trunk/main/Makefile?view=diff&rev=326589&r1=326588&r2=326589
==============================================================================
--- trunk/main/Makefile (original)
+++ trunk/main/Makefile Wed Jul  6 15:58:12 2011
@@ -33,6 +33,7 @@
 AST_LIBS += $(OPENSSL_LIB)
 AST_LIBS += $(BKTR_LIB)
 AST_LIBS += $(LIBXML2_LIB) 
+AST_LIBS += $(SQLITE3_LIB)
 
 ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc linux-gnueabi kfreebsd-gnu),)
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
@@ -110,9 +111,6 @@
 editline/libedit.a: CHECK_SUBDIR
 	cd editline && test -f config.h || CFLAGS="$(PTHREAD_CFLAGS) $(subst $(ASTTOPDIR),../../,$(_ASTCFLAGS:-Werror=) $(ASTCFLAGS))" LDFLAGS="$(_ASTLDFLAGS) $(ASTLDFLAGS)" ./configure --build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM) --with-ncurses=$(NCURSES_DIR) --with-curses=$(CURSES_DIR) --with-termcap=$(TERMCAP_DIR) --with-tinfo=$(TINFO_DIR)
 	$(MAKE) -C editline libedit.a
-
-db1-ast/libdb1.a: CHECK_SUBDIR
-	_ASTCFLAGS="$(_ASTCFLAGS) -Wno-strict-aliasing" ASTCFLAGS="$(ASTCFLAGS)" $(MAKE) -C db1-ast libdb1.a
 
 ifneq ($(findstring REBUILD_PARSERS,$(MENUSELECT_CFLAGS)),)
 ast_expr2.c ast_expr2.h: ast_expr2.y
@@ -143,6 +141,8 @@
 	$(CC) -g -o testexpr2 ast_expr2f.o ast_expr2.o -lm
 	rm ast_expr2.o ast_expr2f.o 
 
+db.o: _ASTCFLAGS+=$(SQLITE3_INCLUDE)
+
 ifneq ($(findstring ENABLE_UPLOADS,$(MENUSELECT_CFLAGS)),)
 http.o: _ASTCFLAGS+=$(GMIME_INCLUDE)
 endif
@@ -177,13 +177,13 @@
 
 $(OBJS): _ASTCFLAGS+=-DAST_MODULE=\"core\"
 
-$(MAIN_TGT): $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
+$(MAIN_TGT): $(OBJS) editline/libedit.a $(AST_EMBED_LDSCRIPTS)
 	@$(CC) -c -o buildinfo.o $(_ASTCFLAGS) buildinfo.c $(ASTCFLAGS)
-	$(ECHO_PREFIX) echo "   [LD] $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) -> $@"
+	$(ECHO_PREFIX) echo "   [LD] $(OBJS) editline/libedit.a $(AST_EMBED_LDSCRIPTS) -> $@"
 ifneq ($(findstring chan_h323,$(MENUSELECT_CHANNELS)),)
-	$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS)
-else
-	$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS) $(GMIMELDFLAGS)
+	$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(OBJS) editline/libedit.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(GMIMELDFLAGS)
+else
+	$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(_ASTLDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $(OBJS) editline/libedit.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS) $(GMIMELDFLAGS)
 endif
 
 ifeq ($(GNU_LD),1)
@@ -194,9 +194,7 @@
 
 clean::
 	rm -f asterisk
-	rm -f db1-ast/.*.d
 	rm -f asterisk.exports
 	@if [ -f editline/Makefile ]; then $(MAKE) -C editline distclean ; fi
-	@$(MAKE) -C db1-ast clean
 	@$(MAKE) -C stdtime clean
 	rm -f libresample/src/*.o

Modified: trunk/main/asterisk.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/asterisk.c?view=diff&rev=326589&r1=326588&r2=326589
==============================================================================
--- trunk/main/asterisk.c (original)
+++ trunk/main/asterisk.c Wed Jul  6 15:58:12 2011
@@ -3759,6 +3759,11 @@
 	ast_xmldoc_load_documentation();
 #endif
 
+	if (astdb_init()) {
+		printf("%s", term_quit());
+		exit(1);
+	}
+
 	if (ast_msg_init()) {
 		printf("%s", term_quit());
 		exit(1);
@@ -3830,11 +3835,6 @@
 	ast_features_init();
 
 	if (init_framer()) {
-		printf("%s", term_quit());
-		exit(1);
-	}
-
-	if (astdb_init()) {
 		printf("%s", term_quit());
 		exit(1);
 	}

Modified: trunk/main/db.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/db.c?view=diff&rev=326589&r1=326588&r2=326589
==============================================================================
--- trunk/main/db.c (original)
+++ trunk/main/db.c Wed Jul  6 15:58:12 2011
@@ -20,11 +20,11 @@
  *
  * \brief ASTdb Management
  *
- * \author Mark Spencer <markster at digium.com> 
+ * \author Mark Spencer <markster at digium.com>
  *
  * \note DB3 is licensed under Sleepycat Public License and is thus incompatible
- * with GPL.  To avoid having to make another exception (and complicate 
- * licensing even further) we elect to use DB1 which is BSD licensed 
+ * with GPL.  To avoid having to make another exception (and complicate
+ * licensing even further) we elect to use DB1 which is BSD licensed
  */
 
 #include "asterisk.h"
@@ -34,8 +34,12 @@
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"	/* use ast_config_AST_DB */
 #include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <signal.h>
 #include <dirent.h>
+#include <sqlite3.h>
 
 #include "asterisk/channel.h"
 #include "asterisk/file.h"
@@ -44,9 +48,7 @@
 #include "asterisk/astdb.h"
 #include "asterisk/cli.h"
 #include "asterisk/utils.h"
-#include "asterisk/lock.h"
 #include "asterisk/manager.h"
-#include "db1-ast/include/db.h"
 
 /*** DOCUMENTATION
 	<manager name="DBGet" language="en_US">
@@ -101,242 +103,362 @@
  ***/
 
 #define MAX_DB_FIELD 256
-
-static DB *astdb;
 AST_MUTEX_DEFINE_STATIC(dblock);
 static ast_cond_t dbcond;
-typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data);
+static sqlite3 *astdb;
+static pthread_t syncthread;
+static int doexit;
 
 static void db_sync(void);
 
-static int dbinit(void) 
-{
-	if (!astdb && !(astdb = dbopen(ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
-		ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-
-static inline int keymatch(const char *key, const char *prefix)
-{
-	int preflen = strlen(prefix);
-	if (!preflen)
-		return 1;
-	if (!strcasecmp(key, prefix))
-		return 1;
-	if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
-		if (key[preflen] == '/')
-			return 1;
-	}
-	return 0;
-}
-
-static inline int subkeymatch(const char *key, const char *suffix)
-{
-	int suffixlen = strlen(suffix);
-	if (suffixlen) {
-		const char *subkey = key + strlen(key) - suffixlen;
-		if (subkey < key)
-			return 0;
-		if (!strcasecmp(subkey, suffix))
-			return 1;
-	}
-	return 0;
-}
-
-static const char *dbt_data2str(DBT *dbt)
-{
-	char *data = "";
-
-	if (dbt->size) {
-		data = dbt->data;
-		data[dbt->size - 1] = '\0';
-	}
-
-	return data;
-}
-
-static inline const char *dbt_data2str_full(DBT *dbt, const char *def)
-{
-	return S_OR(dbt_data2str(dbt), def);
-}
-
-static int process_db_keys(process_keys_cb cb, void *data, const char *filter, int sync)
-{
-	DBT key = { 0, }, value = { 0, }, last_key = { 0, };
-	int counter = 0;
-	int res, last = 0;
-	char last_key_s[MAX_DB_FIELD];
-
-	ast_mutex_lock(&dblock);
-	if (dbinit()) {
+#define DEFINE_SQL_STATEMENT(stmt,sql) static sqlite3_stmt *stmt; \
+	const char stmt##_sql[] = sql;
+
+DEFINE_SQL_STATEMENT(put_stmt, "INSERT OR REPLACE INTO astdb (key, value) VALUES (?, ?)")
+DEFINE_SQL_STATEMENT(get_stmt, "SELECT value FROM astdb WHERE key=?")
+DEFINE_SQL_STATEMENT(del_stmt, "DELETE FROM astdb WHERE key=?")
+DEFINE_SQL_STATEMENT(deltree_stmt, "DELETE FROM astdb WHERE key LIKE ? || '/' || '%'")
+DEFINE_SQL_STATEMENT(deltree_all_stmt, "DELETE FROM astdb")
+DEFINE_SQL_STATEMENT(gettree_stmt, "SELECT key, value FROM astdb WHERE key LIKE ? || '/' || '%'")
+DEFINE_SQL_STATEMENT(gettree_all_stmt, "SELECT key, value FROM astdb")
+DEFINE_SQL_STATEMENT(showkey_stmt, "SELECT key, value FROM astdb WHERE key LIKE '%' || '/' || ?")
+DEFINE_SQL_STATEMENT(create_astdb_stmt, "CREATE TABLE IF NOT EXISTS astdb(key VARCHAR(256), value VARCHAR(256), PRIMARY KEY(key))")
+
+static int init_stmt(sqlite3_stmt **stmt, const char *sql, size_t len)
+{
+	ast_mutex_lock(&dblock);
+	if (sqlite3_prepare_v2(astdb, sql, len, stmt, NULL) != SQLITE_OK) {
+		ast_log(LOG_WARNING, "Couldn't prepare statement '%s': %s\n", sql, sqlite3_errmsg(astdb));
 		ast_mutex_unlock(&dblock);
 		return -1;
 	}
-
-	/* Somehow, the database can become corrupted such that astdb->seq will continue looping through
-	 * the database indefinitely. The pointer to last_key.data ends up getting re-used by the BDB lib
-	 * so this specifically queries for the last entry, makes a copy of the key, and then uses it as
-	 * a sentinel to avoid repeatedly looping over the list. */
-
-	if (astdb->seq(astdb, &last_key, &value, R_LAST)) {
-		/* Empty database */
-		ast_mutex_unlock(&dblock);
-		return 0;
-	}
-
-	memcpy(last_key_s, last_key.data, MIN(last_key.size - 1, sizeof(last_key_s)));
-	last_key_s[last_key.size - 1] = '\0';
-	for (res = astdb->seq(astdb, &key, &value, R_FIRST);
-			!res;
-			res = astdb->seq(astdb, &key, &value, R_NEXT)) {
-		/* The callback might delete the key, so we have to check it before calling */
-		last = !strcmp(dbt_data2str_full(&key, "<bad key>"), last_key_s);
-		counter += cb(&key, &value, filter, data);
-		if (last) {
-			break;
-		}
-	}
-
-	if (sync) {
-		db_sync();
-	}
-
-	ast_mutex_unlock(&dblock);
-
-	return counter;
-}
-
-static int db_deltree_cb(DBT *key, DBT *value, const char *filter, void *data)
+	ast_mutex_unlock(&dblock);
+
+	return 0;
+}
+
+static int init_statements(void)
+{
+	/* Don't initialize create_astdb_statment here as the astdb table needs to exist
+	 * brefore these statments can be initialized */
+	return init_stmt(&get_stmt, get_stmt_sql, sizeof(get_stmt_sql))
+	|| init_stmt(&del_stmt, del_stmt_sql, sizeof(del_stmt_sql))
+	|| init_stmt(&deltree_stmt, deltree_stmt_sql, sizeof(deltree_stmt_sql))
+	|| init_stmt(&deltree_all_stmt, deltree_all_stmt_sql, sizeof(deltree_all_stmt_sql))
+	|| init_stmt(&gettree_stmt, gettree_stmt_sql, sizeof(gettree_stmt_sql))
+	|| init_stmt(&gettree_all_stmt, gettree_all_stmt_sql, sizeof(gettree_all_stmt_sql))
+	|| init_stmt(&showkey_stmt, showkey_stmt_sql, sizeof(showkey_stmt_sql))
+	|| init_stmt(&put_stmt, put_stmt_sql, sizeof(put_stmt_sql));
+}
+
+static int convert_bdb_to_sqlite3(void)
+{
+	char *cmd;
+	int res;
+
+	ast_asprintf(&cmd, "astdb2sqlite3 '%s'\n", ast_config_AST_DB);
+	res = ast_safe_system(cmd);
+	ast_free(cmd);
+
+	return res;
+}
+
+static int db_create_astdb(void)
 {
 	int res = 0;
 
-	if (keymatch(dbt_data2str_full(key, "<bad key>"), filter)) {
-		astdb->del(astdb, key, 0);
-		res = 1;
-	}
+	if (!create_astdb_stmt) {
+		init_stmt(&create_astdb_stmt, create_astdb_stmt_sql, sizeof(create_astdb_stmt_sql));
+	}
+
+	ast_mutex_lock(&dblock);
+	if (sqlite3_step(create_astdb_stmt) != SQLITE_DONE) {
+		ast_log(LOG_WARNING, "Couldn't create astdb table: %s\n", sqlite3_errmsg(astdb));
+		res = -1;
+	}
+	sqlite3_reset(create_astdb_stmt);
+	db_sync();
+	ast_mutex_unlock(&dblock);
+
 	return res;
 }
 
-int ast_db_deltree(const char *family, const char *keytree)
-{
-	char prefix[MAX_DB_FIELD];
-
-	if (family) {
-		if (keytree) {
-			snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
+static int db_open(void)
+{
+	char *dbname;
+	struct stat dont_care;
+
+	if (!(dbname = alloca(strlen(ast_config_AST_DB) + sizeof(".sqlite3")))) {
+		return -1;
+	}
+	strcpy(dbname, ast_config_AST_DB);
+	strcat(dbname, ".sqlite3");
+
+	if (stat(dbname, &dont_care) && !stat(ast_config_AST_DB, &dont_care)) {
+		if (convert_bdb_to_sqlite3()) {
+			ast_log(LOG_ERROR, "*** Database conversion failed!\n");
+			ast_log(LOG_ERROR, "*** Asterisk now uses SQLite3 for its internal\n");
+			ast_log(LOG_ERROR, "*** database. Conversion from the old astdb\n");
+			ast_log(LOG_ERROR, "*** failed. Most likely the astdb2sqlite3 utility\n");
+			ast_log(LOG_ERROR, "*** was not selected for build. To convert the\n");
+			ast_log(LOG_ERROR, "*** old astdb, please delete '%s'\n", dbname);
+			ast_log(LOG_ERROR, "*** and re-run 'make menuselect' and select astdb2sqlite3\n");
+			ast_log(LOG_ERROR, "*** in the Utilities section, then 'make && make install'.\n");
+			sleep(5);
 		} else {
-			snprintf(prefix, sizeof(prefix), "/%s", family);
-		}
-	} else if (keytree) {
-		return -1;
-	} else {
-		prefix[0] = '\0';
-	}
-
-	return process_db_keys(db_deltree_cb, NULL, prefix, 1);
-}
-
-int ast_db_put(const char *family, const char *keys, const char *value)
-{
-	char fullkey[MAX_DB_FIELD];
-	DBT key, data;
-	int res, fullkeylen;
-
-	ast_mutex_lock(&dblock);
-	if (dbinit()) {
+			ast_log(LOG_NOTICE, "Database conversion succeeded!\n");
+		}
+	}
+
+	ast_mutex_lock(&dblock);
+	if (sqlite3_open_v2(dbname, &astdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, NULL) != SQLITE_OK) {
+		ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", dbname, sqlite3_errmsg(astdb));
+		sqlite3_close(astdb);
 		ast_mutex_unlock(&dblock);
 		return -1;
 	}
-
-	fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
-	memset(&key, 0, sizeof(key));
-	memset(&data, 0, sizeof(data));
-	key.data = fullkey;
-	key.size = fullkeylen + 1;
-	data.data = (char *) value;
-	data.size = strlen(value) + 1;
-	res = astdb->put(astdb, &key, &data, 0);
+	ast_mutex_unlock(&dblock);
+
+	return 0;
+}
+
+static int db_init(void)
+{
+	if (astdb) {
+		return 0;
+	}
+
+	if (db_open() || db_create_astdb() || init_statements()) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/* We purposely don't lock around the sqlite3 call because the transaction
+ * calls will be called with the database lock held. For any other use, make
+ * sure to take the dblock yourself. */
+static int db_execute_sql(const char *sql, int (*callback)(void *, int, char **, char **), void *arg)
+{
+	char *errmsg = NULL;
+	int res =0;
+
+	sqlite3_exec(astdb, sql, callback, arg, &errmsg);
+	if (errmsg) {
+		ast_log(LOG_WARNING, "Error executing SQL: %s\n", errmsg);
+		sqlite3_free(errmsg);
+		res = -1;
+	}
+
+	return res;
+}
+
+static int ast_db_begin_transaction(void)
+{
+	return db_execute_sql("BEGIN TRANSACTION", NULL, NULL);
+}
+
+static int ast_db_commit_transaction(void)
+{
+	return db_execute_sql("COMMIT", NULL, NULL);
+}
+
+static int ast_db_rollback_transaction(void)
+{
+	return db_execute_sql("ROLLBACK", NULL, NULL);
+}
+
+int ast_db_put(const char *family, const char *key, const char *value)
+{
+	char fullkey[MAX_DB_FIELD];
+	size_t fullkey_len;
+	int res = 0;
+
+	if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
+		ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
+		return -1;
+	}
+
+	fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
+
+	ast_mutex_lock(&dblock);
+	if (sqlite3_bind_text(put_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
+		ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
+		res = -1;
+	} else if (sqlite3_bind_text(put_stmt, 2, value, -1, SQLITE_STATIC) != SQLITE_OK) {
+		ast_log(LOG_WARNING, "Couldn't bind value to stmt: %s\n", sqlite3_errmsg(astdb));
+		res = -1;
+	} else if (sqlite3_step(put_stmt) != SQLITE_DONE) {
+		ast_log(LOG_WARNING, "Couldn't execute statment: %s\n", sqlite3_errmsg(astdb));
+		res = -1;
+	}
+
+	sqlite3_reset(put_stmt);
 	db_sync();
 	ast_mutex_unlock(&dblock);
-	if (res)
-		ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
 
 	return res;
 }
 
-int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
-{
-	char fullkey[MAX_DB_FIELD] = "";
-	DBT key, data;
-	int res, fullkeylen;
-
-	ast_mutex_lock(&dblock);
-	if (dbinit()) {
+int ast_db_get(const char *family, const char *key, char *value, int valuelen)
+{
+	const unsigned char *result;
+	char fullkey[MAX_DB_FIELD];
+	size_t fullkey_len;
+	int res = 0;
+
+	if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
+		ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
+		return -1;
+	}
+
+	fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
+
+	ast_mutex_lock(&dblock);
+	if (sqlite3_bind_text(get_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
+		ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
+		res = -1;
+	} else if (sqlite3_step(get_stmt) != SQLITE_ROW) {
+		ast_debug(1, "Unable to find key '%s' in family '%s'\n", key, family);
+		res = -1;
+	} else if (!(result = sqlite3_column_text(get_stmt, 0))) {
+		ast_log(LOG_WARNING, "Couldn't get value\n");
+		res = -1;
+	} else {
+		strncpy(value, (const char *) result, valuelen);
+	}
+	sqlite3_reset(get_stmt);
+	ast_mutex_unlock(&dblock);
+
+	return res;
+}
+
+int ast_db_del(const char *family, const char *key)
+{
+	char fullkey[MAX_DB_FIELD];
+	size_t fullkey_len;
+	int res = 0;
+
+	if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
+		ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
+		return -1;
+	}
+
+	fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
+
+	ast_mutex_lock(&dblock);
+	if (sqlite3_bind_text(del_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
+		ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
+		res = -1;
+	} else if (sqlite3_step(del_stmt) != SQLITE_DONE) {
+		ast_debug(1, "Unable to find key '%s' in family '%s'\n", key, family);
+		res = -1;
+	}
+	sqlite3_reset(del_stmt);
+	db_sync();
+	ast_mutex_unlock(&dblock);
+
+	return res;
+}
+
+int ast_db_deltree(const char *family, const char *subfamily)
+{
+	sqlite3_stmt *stmt = deltree_stmt;
+	char prefix[MAX_DB_FIELD];
+	int res = 0;
+
+	if (!ast_strlen_zero(family)) {
+		if (!ast_strlen_zero(subfamily)) {
+			/* Family and key tree */
+			snprintf(prefix, sizeof(prefix), "/%s/%s", family, subfamily);
+		} else {
+			/* Family only */
+			snprintf(prefix, sizeof(prefix), "/%s", family);
+		}
+	} else {
+		prefix[0] = '\0';
+		stmt = deltree_all_stmt;
+	}
+
+	ast_mutex_lock(&dblock);
+	if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
+		ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
+		res = -1;
+	} else if (sqlite3_step(stmt) != SQLITE_DONE) {
+		ast_log(LOG_WARNING, "Couldn't execute stmt: %s\n", sqlite3_errmsg(astdb));
+		res = -1;
+	}
+	res = sqlite3_changes(astdb);
+	sqlite3_reset(stmt);
+	db_sync();
+	ast_mutex_unlock(&dblock);
+
+	return res;
+}
+
+struct ast_db_entry *ast_db_gettree(const char *family, const char *subfamily)
+{
+	char prefix[MAX_DB_FIELD];
+	sqlite3_stmt *stmt = gettree_stmt;
+	struct ast_db_entry *cur, *last = NULL, *ret = NULL;
+
+	if (!ast_strlen_zero(family)) {
+		if (!ast_strlen_zero(subfamily)) {
+			/* Family and key tree */
+			snprintf(prefix, sizeof(prefix), "/%s/%s", family, subfamily);
+		} else {
+			/* Family only */
+			snprintf(prefix, sizeof(prefix), "/%s", family);
+		}
+	} else {
+		prefix[0] = '\0';
+		stmt = gettree_all_stmt;
+	}
+
+	ast_mutex_lock(&dblock);
+	if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
+		ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
+		sqlite3_reset(stmt);
 		ast_mutex_unlock(&dblock);
-		return -1;
-	}
-
-	fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
-	memset(&key, 0, sizeof(key));
-	memset(&data, 0, sizeof(data));
-	memset(value, 0, valuelen);
-	key.data = fullkey;
-	key.size = fullkeylen + 1;
-
-	res = astdb->get(astdb, &key, &data, 0);
-
-	/* Be sure to NULL terminate our data either way */
-	if (res) {
-		ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
-	} else {
-#if 0
-		printf("Got value of size %d\n", data.size);
-#endif
-		if (data.size) {
-			((char *)data.data)[data.size - 1] = '\0';
-			/* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
-			ast_copy_string(value, data.data, (valuelen > data.size) ? data.size : valuelen);
+		return NULL;
+	}
+
+	while (sqlite3_step(stmt) == SQLITE_ROW) {
+		const char *key_s, *value_s;
+		if (!(key_s = (const char *) sqlite3_column_text(stmt, 0))) {
+			break;
+		}
+		if (!(value_s = (const char *) sqlite3_column_text(stmt, 1))) {
+			break;
+		}
+		if (!(cur = ast_malloc(sizeof(*cur) + strlen(key_s) + strlen(value_s) + 2))) {
+			break;
+		}
+		cur->next = NULL;
+		cur->key = cur->data + strlen(value_s) + 1;
+		strcpy(cur->data, value_s);
+		strcpy(cur->key, key_s);
+		if (last) {
+			last->next = cur;
 		} else {
-			ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
-		}
-	}
-
-	/* Data is not fully isolated for concurrency, so the lock must be extended
-	 * to after the copy to the output buffer. */
-	ast_mutex_unlock(&dblock);
-
-	return res;
-}
-
-int ast_db_del(const char *family, const char *keys)
-{
-	char fullkey[MAX_DB_FIELD];
-	DBT key;
-	int res, fullkeylen;
-
-	ast_mutex_lock(&dblock);
-	if (dbinit()) {
-		ast_mutex_unlock(&dblock);
-		return -1;
-	}
-	
-	fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
-	memset(&key, 0, sizeof(key));
-	key.data = fullkey;
-	key.size = fullkeylen + 1;
-	
-	res = astdb->del(astdb, &key, 0);
-	db_sync();
-	
-	ast_mutex_unlock(&dblock);
-
-	if (res) {
-		ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
-	}
-	return res;
+			ret = cur;
+		}
+		last = cur;
+	}
+	sqlite3_reset(stmt);
+	ast_mutex_unlock(&dblock);
+
+	return ret;
+}
+
+void ast_db_freetree(struct ast_db_entry *dbe)
+{
+	struct ast_db_entry *last;
+	while (dbe) {
+		last = dbe;
+		dbe = dbe->next;
+		ast_free(last);
+	}
 }
 
 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
@@ -429,8 +551,8 @@
 	case CLI_INIT:
 		e->command = "database deltree";
 		e->usage =
-			"Usage: database deltree <family> [keytree]\n"
-			"       Deletes a family or specific keytree within a family\n"
+			"Usage: database deltree <family> [subfamily]\n"
+			"       Deletes a family or specific subfamily within a family\n"
 			"       in the Asterisk database.\n";
 		return NULL;
 	case CLI_GENERATE:
@@ -452,32 +574,19 @@
 	return CLI_SUCCESS;
 }
 
-static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data)
-{
-	struct ast_cli_args *a = data;
-	const char *key_s = dbt_data2str_full(key, "<bad key>");
-	const char *value_s = dbt_data2str_full(value, "<bad value>");
-
-	if (keymatch(key_s, filter)) {
-		ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
-		return 1;
-	}
-
-	return 0;
-}
-
 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
 	char prefix[MAX_DB_FIELD];
 	int counter = 0;
+	sqlite3_stmt *stmt = gettree_stmt;
 
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "database show";
 		e->usage =
-			"Usage: database show [family [keytree]]\n"
+			"Usage: database show [family [subfamily]]\n"
 			"       Shows Asterisk database contents, optionally restricted\n"
-			"       to a given family, or family and keytree.\n";
+			"       to a given family, or family and subfamily.\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
@@ -492,118 +601,123 @@
 	} else if (a->argc == 2) {
 		/* Neither */
 		prefix[0] = '\0';
+		stmt = gettree_all_stmt;
+
 	} else {
 		return CLI_SHOWUSAGE;
 	}
 
-	if((counter = process_db_keys(db_show_cb, a, prefix, 0)) < 0) {
-		ast_cli(a->fd, "Database unavailable\n");
-		return CLI_SUCCESS;
-	}
+	ast_mutex_lock(&dblock);
+	if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
+		ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
+		sqlite3_reset(stmt);
+		ast_mutex_unlock(&dblock);
+		return NULL;
+	}
+
+	while (sqlite3_step(stmt) == SQLITE_ROW) {
+		const char *key_s, *value_s;
+		if (!(key_s = (const char *) sqlite3_column_text(stmt, 0))) {
+			ast_log(LOG_WARNING, "Skipping invalid key!\n");
+			continue;
+		}
+		if (!(value_s = (const char *) sqlite3_column_text(stmt, 1))) {
+			ast_log(LOG_WARNING, "Skipping invalid value!\n");
+			continue;
+		}
+		++counter;
+		ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
+	}
+
+	sqlite3_reset(stmt);
+	ast_mutex_unlock(&dblock);
 
 	ast_cli(a->fd, "%d results found.\n", counter);
 	return CLI_SUCCESS;
 }
 
-static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data)
-{
-	struct ast_cli_args *a = data;
-	const char *key_s = dbt_data2str_full(key, "<bad key>");
-	const char *value_s = dbt_data2str_full(value, "<bad value>");
-
-	if (subkeymatch(key_s, filter)) {
-		ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
-		return 1;
-	}
-
-	return 0;
-}
-
 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-	char suffix[MAX_DB_FIELD];
 	int counter = 0;
 
 	switch (cmd) {
 	case CLI_INIT:
 		e->command = "database showkey";
 		e->usage =
-			"Usage: database showkey <keytree>\n"
+			"Usage: database showkey <subfamily>\n"
 			"       Shows Asterisk database contents, restricted to a given key.\n";
 		return NULL;
 	case CLI_GENERATE:
 		return NULL;
 	}
 
-	if (a->argc == 3) {
-		/* Key only */
-		snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
-	} else {
+	if (a->argc != 3) {
 		return CLI_SHOWUSAGE;
 	}
 
-	if ((counter = process_db_keys(db_showkey_cb, a, suffix, 0)) < 0) {
-		ast_cli(a->fd, "Database unavailable\n");
-		return CLI_SUCCESS;
-	}
+	ast_mutex_lock(&dblock);
+	if (!ast_strlen_zero(a->argv[2]) && (sqlite3_bind_text(showkey_stmt, 1, a->argv[2], -1, SQLITE_STATIC) != SQLITE_OK)) {
+		ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", a->argv[2], sqlite3_errmsg(astdb));
+		sqlite3_reset(showkey_stmt);
+		ast_mutex_unlock(&dblock);
+		return NULL;
+	}
+
+	while (sqlite3_step(showkey_stmt) == SQLITE_ROW) {
+		const char *key_s, *value_s;
+		if (!(key_s = (const char *) sqlite3_column_text(showkey_stmt, 0))) {
+			break;
+		}
+		if (!(value_s = (const char *) sqlite3_column_text(showkey_stmt, 1))) {
+			break;
+		}
+		++counter;
+		ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
+	}
+	sqlite3_reset(showkey_stmt);
+	ast_mutex_unlock(&dblock);
 
 	ast_cli(a->fd, "%d results found.\n", counter);
 	return CLI_SUCCESS;
 }
 
-static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data)
-{
-	struct ast_db_entry **ret = data;
-	struct ast_db_entry *cur;
-	const char *key_s = dbt_data2str_full(key, "<bad key>");
-	const char *value_s = dbt_data2str_full(value, "<bad value>");
-	size_t key_slen = strlen(key_s) + 1, value_slen = strlen(value_s) + 1;
-
-	if (keymatch(key_s, filter) && (cur = ast_malloc(sizeof(*cur) + key_slen + value_slen))) {
-		cur->next = *ret;
-		cur->key = cur->data + value_slen;
-		strcpy(cur->data, value_s);
-		strcpy(cur->key, key_s);
-		*ret = cur;
-		return 1;
-	}
+static int display_results(void *arg, int columns, char **values, char **colnames)
+{
+	struct ast_cli_args *a = arg;
+	size_t x;
+
+	for (x = 0; x < columns; x++) {
+		ast_cli(a->fd, "%-5s: %-50s\n", colnames[x], values[x]);
+	}
+	ast_cli(a->fd, "\n");
 
 	return 0;
 }
 
-struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
-{
-	char prefix[MAX_DB_FIELD];
-	struct ast_db_entry *ret = NULL;
-
-	if (!ast_strlen_zero(family)) {
-		if (!ast_strlen_zero(keytree)) {
-			/* Family and key tree */
-			snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
-		} else {
-			/* Family only */
-			snprintf(prefix, sizeof(prefix), "/%s", family);
-		}
-	} else {
-		prefix[0] = '\0';
-	}
-

[... 297 lines stripped ...]



More information about the asterisk-commits mailing list