sqlite driver

"Tim Tessier" <[email protected]> Fri, 1 Jan 2010 13:47:52 -0500
Newsgroups gmane.network.dns.bind9.dlz
Message-ID <8891C28C2E38482DA5CF4C99215649EA@lappy>
I have modified the mysql driver to support sqlite. I left the original copyright in the top of the file and a mention of myself in the file.
I have used this successfully with bind 9.4.3 on windows and will be porting to solaris/linux which should require minimal effort

Thanks,
Tim Tessier

------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev

_______________________________________________
Bind-dlz-testers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/bind-dlz-testers
dlz_sqlite_driver.h (text/plain, 1.8 KB)
/*
 * Copyright (C) 2002 Stichting NLnet, Netherlands, [email protected].
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
 * USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
 * conceived and contributed by Rob Butler.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
 * USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef DLZ_SQLITE_DRIVER_H
#define DLZ_SQLITE_DRIVER_H
isc_result_t dlz_sqlite_init(void);
void dlz_sqlite_clear(void);
#endif
dlz_sqlite_driver.c (text/plain, 26.9 KB)
/*
 * Copyright (C) 2002 Stichting NLnet, Netherlands, [email protected].
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
 * USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
 * conceived and contributed by Rob Butler.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the
 * above copyright notice and this permission notice appear in all
 * copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
 * USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * Copyright (C) 1999-2001  Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*
	This driver is based on the mysql driver and contains the original copyright above
	Modified by Tim Tessier to provide sqlite database driver.
*/

#ifdef DLZ_SQLITE

#include <config.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <dns/log.h>
#include <dns/sdlz.h>
#include <dns/result.h>

#include <isc/mem.h>
#include <isc/platform.h>
#include <isc/print.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>

#include <named/globals.h>

#include <sqlite3.h>
#include <dlz/sdlz_helper.h>
#include <dlz/dlz_sqlite_driver.h>

#define dbc_search_limit 30
#define ALLNODES 1
#define ALLOWXFR 2
#define AUTHORITY 3
#define FINDZONE 4
#define COUNTZONE 5
#define LOOKUP 6

#define safeGet(in,v) in[v] == NULL ? "" : in[v]

static dns_sdlzimplementation_t *dlz_sqlite = NULL;

typedef struct config_data {
	char		*myzone;
	char		*myname;
	char		*myip;
	isc_mem_t	*mctx;
} config_data_t;

typedef struct st_sqlite_rs{
	const char *zSql;     /* SQL to be evaluated */
	char **pzResult;    /* Results of the query */
	unsigned int pnRow;           /* Number of result rows written here */
	unsigned int pnColumn;        /* Number of result columns written here */
	unsigned int curRow;
	char *pzErrmsg; /* Error msg written here */
}SQLITE_RS, * LPSQLITE_RS;

/*
 * SDLZ methods
 */
static char * sqlitedrv_unescape_string(const char * instr){
	char *outstr;
	char * ptr ;
	unsigned int len;
	unsigned int tlen = 0 ;
	unsigned int atlen = 0 ;
	unsigned int i = 0 ;

	if (instr == NULL)
		return NULL;
	
	len = strlen(instr);
	atlen  = (len * sizeof(char)) + 1 ;
	outstr = ( char * ) isc_mem_allocate(ns_g_mctx ,atlen);
	if (outstr == NULL)
		return NULL;
	ptr = outstr ;
	for ( i = 0 ; i < len ; i++ ){
		if ( tlen >= atlen ){
			break ;
		}
		if ( instr[i] == '\'' && instr[i+1] == '\'' ){
			i++;
			tlen ++ ;
		}
		*ptr = instr[i] ;
		ptr++ ;
		tlen ++ ;
		if ( instr=='\0' ){
			break ;
		}
	}
	*ptr = '\0' ;
	return outstr;
}

static char * sqlitedrv_escape_string(const char *instr) {
	char *outstr;
	char * ptr ;
	unsigned int len;
	unsigned int tlen = 0 ;
	unsigned int atlen = 0 ;
	unsigned int i = 0 ;

	if (instr == NULL)
		return NULL;
	
	len = strlen(instr);
	atlen  = (2 * len * sizeof(char)) + 1 ;
	outstr = ( char * ) isc_mem_allocate(ns_g_mctx ,atlen);
	if (outstr == NULL)
		return NULL;
	ptr = outstr ;
	for ( i = 0 ; i < len ; i++ ){
		if ( tlen >= atlen ){
			break ;
		}
		if ( instr[i] == '\'' ){
			*ptr = '\'' ;
			ptr++ ;
			tlen ++ ;
		}
		*ptr = instr[i] ;
		ptr++ ;
		tlen ++ ;
		if ( instr=='\0' ){
			break ;
		}
	}
	*ptr = '\0' ;
	return outstr;
}

static isc_result_t
sqlite_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, SQLITE_RS **rs)
{
	isc_result_t result;
	dbinstance_t *dbi = NULL;
	char *querystring = NULL;
	unsigned int i = 0;
	unsigned int j = 0;
	int qres = 0;

	if ( !rs || rs && *rs ){
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				"Result set is not null before query or result set ptr invalid");
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	if (query != COUNTZONE)
		REQUIRE(*rs == NULL);
	else
		REQUIRE(rs == NULL);

	/* get db instance / connection */
	dbi =  (dbinstance_t *) dbdata;

	/* if DBI is null, can't do anything else */
	if (dbi == NULL) {
		result = ISC_R_FAILURE;
		goto cleanup;
	}

	switch(query) {
	case ALLNODES:
		if (dbi->allnodes_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case ALLOWXFR:
		if (dbi->allowxfr_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case AUTHORITY:
		if (dbi->authority_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case FINDZONE:
		/* this is required.  It's the whole point of DLZ! */
		if (dbi->findzone_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				"No query specified for findzone.  "
				"Findzone requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		}
		break;
	case COUNTZONE:
		if (dbi->countzone_q == NULL) {
			result = ISC_R_NOTIMPLEMENTED;
			goto cleanup;
		}
		break;
	case LOOKUP:
		/* this is required.  It's also a major point of DLZ! */
		if (dbi->lookup_q == NULL) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
				"No query specified for lookup.  "
				"Lookup requires a query");
			result = ISC_R_FAILURE;
			goto cleanup;
		}
		break;
	default:
		/*	this should never happen.  If it does, the code is
			screwed up! */
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "Incorrect query flag passed to "
				 "sqlite_get_resultset");
		result = ISC_R_UNEXPECTED;
		goto cleanup;
	}

	/*	was a zone string passed?  If so, make it safe for use in
		queries.*/
	if (zone != NULL) {
		dbi->zone = sqlitedrv_escape_string(zone);
		if (dbi->zone == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {
		dbi->zone = NULL;
	}

	/*	was a record string passed?  If so, make it safe for use in
		queries. */
	if (record != NULL) {
		dbi->record = sqlitedrv_escape_string(record);
		if (dbi->record == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {
		dbi->record = NULL;
	}

	/*	was a client string passed?  If so, make it safe for use in
		queries.*/
	if (client != NULL) {
		dbi->client = sqlitedrv_escape_string(client);
		if (dbi->client == NULL) {
			result = ISC_R_NOMEMORY;
			goto cleanup;
		}
	} else {
		dbi->client = NULL;
	}

	switch(query) {
		case ALLNODES:
			querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
			break;
		case ALLOWXFR:
			querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
			break;
		case AUTHORITY:
			querystring = build_querystring(ns_g_mctx, dbi->authority_q);
			break;
		case FINDZONE:
			querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
			break;
		case COUNTZONE:
			querystring = build_querystring(ns_g_mctx, dbi->countzone_q);
			break;
		case LOOKUP:
			querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
			break;
		default:
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "Incorrect query flag passed to "
					 "sqlite_get_resultset");
			result = ISC_R_UNEXPECTED;
		goto cleanup;
	}

	if (querystring == NULL) {
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}

	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
		"\nQuery String: %s\n", querystring);

	(*rs)= isc_mem_allocate(ns_g_mctx , sizeof ( SQLITE_RS ) ) ;
	if ( !*rs ){
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
		"\nFailed to allocate result set\n");
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}
	memset ( (*rs),0, sizeof ( SQLITE_RS ) ) ;
	(*rs)->zSql = querystring ;
	for (i=0; i < 10; i++) {
		
		qres = sqlite3_get_table ( dbi->dbconn, querystring, &(*rs)->pzResult, &(*rs)->pnRow, &(*rs)->pnColumn, &(*rs)->pzErrmsg ) ;
		if (qres == SQLITE_OK)
			break;
#ifdef WIN32
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
			"\nFailed query: %s\n",(*rs)->pzErrmsg?(*rs)->pzErrmsg:"NULL");
		sqlite3_free ( (*rs)->pzErrmsg ) ;
		(*rs)->pzErrmsg = NULL ;
		Sleep ( 100 ) ;
#else
		
#endif
	}
	if ( (*rs)->pzErrmsg ){
		sqlite3_free ( (*rs)->pzErrmsg ) ;
		(*rs)->pzErrmsg = NULL ;
	}
	if (qres == SQLITE_OK) {
		result = ISC_R_SUCCESS;
		if (query == COUNTZONE) {
			sqlite3_free_table ( (*rs)->pzResult ) ;
		}
	} else {
		result = ISC_R_FAILURE;
	}

 cleanup:
	/* it's always good to cleanup after yourself */

	/* if we couldn't even get DBI, just return NULL */
	if (dbi == NULL)
		return ISC_R_FAILURE;

	/* free dbi->zone string */
	if (dbi->zone != NULL)
		isc_mem_free(ns_g_mctx, dbi->zone);

	/* free dbi->record string */
	if (dbi->record != NULL)
		isc_mem_free(ns_g_mctx, dbi->record);

	/* free dbi->client string */
	if (dbi->client != NULL)
		isc_mem_free(ns_g_mctx, dbi->client);

	/* release query string */
	if (querystring  != NULL)
		isc_mem_free(ns_g_mctx, querystring);

	/* return result */
	return result;
}

char ** sqlite_fetch_row(SQLITE_RS * rs){
	char ** result = NULL ;
	if ( rs != NULL ){
		if ( rs->pnRow > (unsigned int )0 && rs->curRow < rs->pnRow ){
			result = &rs->pzResult[(rs->curRow+1)*rs->pnColumn];
			rs->curRow++ ;
		}
	}
	return result ;
}

unsigned int sqlite_num_fields(SQLITE_RS * rs){
	unsigned int result = 0 ;
	if ( rs != NULL ){
		result = rs->pnColumn ;
	}
	return result ;
}

unsigned int sqlite_num_rows(SQLITE_RS *rs){
	unsigned int result = 0 ;
	if ( rs != NULL ){
		result = rs->pnRow;
	}
	return result ;
}

void sqlite_free_result ( SQLITE_RS * rs ) {
	if ( rs != NULL ){
		sqlite3_free_table ( rs->pzResult ) ;
		isc_mem_free(ns_g_mctx, rs ) ;
	}
}

static isc_result_t
sqlite_process_rs(dns_sdlzlookup_t *lookup, SQLITE_RS *rs)
{
	isc_result_t result = ISC_R_NOTFOUND;
	char ** row;
	unsigned int fields;
	unsigned int j;
	unsigned int len;
	unsigned int i = 0 ;
	char *tmpString;
	char *endp;
	int ttl;
	
	row = sqlite_fetch_row(rs);		/* get a row from the result set */
	fields = sqlite_num_fields(rs);	/* how many columns in result set */
	while (row != NULL) {
		for ( i = 0 ; i < fields ; i++ ){
			char * f = safeGet(row,i ) ;
			isc_log_write(dns_lctx,
				DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
				"%s\n", f );
		}
		switch(fields) {
			case 1:
				/*	default type A record, 
					default TTL 86400 */
				result = dns_sdlz_putrr(lookup, "a", 86400, safeGet(row,0));
				break;
			case 2:
				/*	data field, and data type.
					use default TTL of 86400.*/
				result = dns_sdlz_putrr(lookup, safeGet(row,0), 86400, safeGet(row,1));
				break;
			case 3:
				/*	all data no defaults.
					convert text to int, make sure it worked */
				ttl = strtol(safeGet(row,0), &endp, 10);
				if (*endp != '\0' || ttl < 0) {
					isc_log_write(dns_lctx,
						DNS_LOGCATEGORY_DATABASE,
						DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
						"sqlite driver ttl must be "
						"a postive number");
			}
			result = dns_sdlz_putrr(lookup, safeGet(row,1), ttl, safeGet(row,2));
			break;
		default:
			/*
			 * more than 3 fields, concatenate the last
			 * ones together.  figure out how long to make
			 * string.
			 */
			for (j=2, len=0; j < fields; j++) {
				len += strlen(safeGet(row,j)) + 1;
			}
			/*
			 * allocate string memory, allow for NULL to
			 * term string
			 */
			tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
			if (tmpString == NULL) {
				/* major bummer, need more ram */
				isc_log_write(dns_lctx,
					DNS_LOGCATEGORY_DATABASE,
					DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
					"sqlite driver unable "
					"to allocate memory for "
					"temporary string");
				sqlite_free_result(rs);
				return (ISC_R_FAILURE);	/* Yeah, I'd say! */
			}
			/* copy field to tmpString */
			strcpy(tmpString, safeGet(row,2));
			/*	concat the rest of fields together, space
				between each one.*/
			for (j=3; j < fields; j++) {
				strcat(tmpString, " ");
				strcat(tmpString, safeGet(row,j));
			}
			/* convert text to int, make sure it worked right */
			ttl = strtol(safeGet(row,0), &endp, 10);
			if (*endp != '\0' || ttl < 0) {
				isc_log_write(dns_lctx,
					DNS_LOGCATEGORY_DATABASE,
					DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
					"sqlite driver ttl must be "
					"a postive number");
			}
			/* ok, now tell Bind about it. */
			result = dns_sdlz_putrr(lookup, safeGet(row,1),ttl, tmpString);
			/* done, get rid of this thing. */
			isc_mem_free(ns_g_mctx, tmpString);
		}
		/* I sure hope we were successful */
		if (result != ISC_R_SUCCESS) {
			/* nope, get rid of the Result set, and log a msg */
			sqlite_free_result(rs);
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				"dns_sdlz_putrr returned error. "
				"Error code was: %s",
				isc_result_totext(result));
			return (ISC_R_FAILURE);
		}
		row = sqlite_fetch_row(rs);	/* get next row */
	}

	/* free result set memory */
	sqlite_free_result(rs);
	/* return result code */
	return result;
}

static isc_result_t
sqlite_findzone(void *driverarg, void *dbdata, const char *name)
{
	isc_result_t result;
	SQLITE_RS *rs = NULL;
	unsigned long long rows;
	UNUSED(driverarg);
	/* run the query and get the result set from the database. */
	result = sqlite_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &rs);
	/* if we didn't get a result set, log an err msg. */
	if (result != ISC_R_SUCCESS || rs == NULL) {
		if (rs != NULL)
			sqlite_free_result(rs);
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver unable to return "
			"result set for findzone query");
		return (ISC_R_FAILURE);
	}
	/* count how many rows in result set */
	rows = sqlite_num_rows(rs);
	/* get rid of result set, we are done with it. */
	sqlite_free_result(rs);

	/* if we returned any rows, zone is supported. */
	if (rows > 0) {
		sqlite_get_resultset(name, NULL, NULL, COUNTZONE, dbdata, NULL);
		return (ISC_R_SUCCESS);
	}

	/* no rows returned, zone is not supported. */
	return (ISC_R_NOTFOUND);
}

/*% Determine if the client is allowed to perform a zone transfer */
static isc_result_t
sqlite_allowzonexfr(void *driverarg, void *dbdata, const char *name, const char *client)
{
	isc_result_t result;
	SQLITE_RS *rs = NULL;
	unsigned long long rows;

	UNUSED(driverarg);

	/* first check if the zone is supported by the database. */
	result = sqlite_findzone(driverarg, dbdata, name);
	if (result != ISC_R_SUCCESS)
		return (ISC_R_NOTFOUND);

	/*	if we get to this point we know the zone is supported by
		the database the only questions now are; is the zone
		transfer allowed for this client and did the config file
		have an allow zone xfr query.
		Run our query, and get a result set from the database.*/
	result = sqlite_get_resultset(name, NULL, client, ALLOWXFR,dbdata, &rs);
	/* if we get "not implemented", send it along. */
	if (result == ISC_R_NOTIMPLEMENTED)
		return result;
	/* if we didn't get a result set, log an err msg. */
	if (result != ISC_R_SUCCESS || rs == NULL) {
		if (rs != NULL)
			sqlite_free_result(rs);
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver unable to return "
			"result set for allow xfr query");
		return (ISC_R_FAILURE);
	}
	/* count how many rows in result set */
	rows = sqlite_num_rows(rs);
	/* get rid of result set, we are done with it. */
	sqlite_free_result(rs);

	/* if we returned any rows, zone xfr is allowed. */
	if (rows > 0)
		return (ISC_R_SUCCESS);

	/* no rows returned, zone xfr not allowed */
	return (ISC_R_NOPERM);
}



/*%
 * If the client is allowed to perform a zone transfer, the next order of
 * business is to get all the nodes in the zone, so bind can respond to the
 * query.
 */
static isc_result_t
sqlite_allnodes(const char *zone, void *driverarg, void *dbdata, dns_sdlzallnodes_t *allnodes)
{
	isc_result_t result;
	SQLITE_RS *rs = NULL;
	char ** row;
	unsigned int fields;
	unsigned int j;
	unsigned int len;
	char *tmpString;
	char *endp;
	int ttl;

	UNUSED(driverarg);

	/* run the query and get the result set from the database. */
	result = sqlite_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &rs);
	/* if we get "not implemented", send it along */
	if (result == ISC_R_NOTIMPLEMENTED)
		return result;
	/* if we didn't get a result set, log an err msg. */
	if (result != ISC_R_SUCCESS) {
		if (rs != NULL)
			sqlite_free_result(rs);
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver unable to return "
			"result set for all nodes query");
		return (ISC_R_FAILURE);
	}

	result = ISC_R_NOTFOUND;

	row = sqlite_fetch_row(rs);	/* get a row from the result set */
	fields = sqlite_num_fields(rs);	/* how many columns in result set */
	while (row != NULL) {
		if (fields < 4) {	/* gotta have at least 4 columns */
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				"sqlite driver too few fields returned "
				"by all nodes query");
		}
		/* convert text to int, make sure it worked right  */
		ttl = strtol(safeGet(row,0), &endp, 10);
		if (*endp != '\0' || ttl < 0) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				"sqlite driver ttl must be "
				"a postive number");
		}
		if (fields == 4) {
			/* tell Bind about it. */
			result = dns_sdlz_putnamedrr(allnodes, safeGet(row,2),safeGet(row,1), ttl,safeGet(row,3));
		} else {
			/*
			 * more than 4 fields, concatenate the last
			 * ones together.  figure out how long to make
			 * string.
			 */
			for (j=3, len=0; j < fields; j++) {
				len += strlen(safeGet(row,j)) + 1;
			}
			/* allocate memory, allow for NULL to term string */
			tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
			if (tmpString == NULL) {	/* we need more ram. */
				isc_log_write(dns_lctx,
					DNS_LOGCATEGORY_DATABASE,
					DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
					"sqlite driver unable "
					"to allocate memory for "
					"temporary string");
				sqlite_free_result(rs);
				return (ISC_R_FAILURE);
			}
			/* copy this field to tmpString */
			strcpy(tmpString, safeGet(row,3));
			/* concatonate the rest, with spaces between */
			for (j=4; j < fields; j++) {
				strcat(tmpString, " ");
				strcat(tmpString, safeGet(row,j));
			}
			/* tell Bind about it. */
			result = dns_sdlz_putnamedrr(allnodes, safeGet(row,2),safeGet(row,1),ttl, tmpString);
			isc_mem_free(ns_g_mctx, tmpString);
		}
		/* if we weren't successful, log err msg */
		if (result != ISC_R_SUCCESS) {
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
				DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
				"dns_sdlz_putnamedrr returned error. "
				"Error code was: %s",
				isc_result_totext(result));
			result = ISC_R_FAILURE;
			break;
		}
		/* get next row from the result set */
		row = sqlite_fetch_row(rs);
	}
	/* free result set memory */
	sqlite_free_result(rs);
	return result;
}

static isc_result_t
sqlite_authority(const char *zone, void *driverarg, void *dbdata,dns_sdlzlookup_t *lookup)
{
	isc_result_t result;
	SQLITE_RS *rs = NULL;

	UNUSED(driverarg);

	/* run the query and get the result set from the database. */
	result = sqlite_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata, &rs);
	/* if we get "not implemented", send it along */
	if (result == ISC_R_NOTIMPLEMENTED)
		return result;
	/* if we didn't get a result set, log an err msg. */
	if (result != ISC_R_SUCCESS) {
		if (rs != NULL)
			sqlite_free_result(rs);
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver unable to return "
			"result set for authority query");
		return (ISC_R_FAILURE);
	}
	/*	lookup and authority result sets are processed in the same
		manner sqlite_process_rs does the job for both functions.*/
	return sqlite_process_rs(lookup, rs);
}

/*% if zone is supported, lookup up a (or multiple) record(s) in it */
static isc_result_t
sqlite_lookup(const char *zone, const char *name, void *driverarg, void *dbdata, dns_sdlzlookup_t *lookup)
{
	isc_result_t result;
	SQLITE_RS *rs = NULL;

	UNUSED(driverarg);

	/* run the query and get the result set from the database. */
	result = sqlite_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
	/* if we didn't get a result set, log an err msg. */
	if (result != ISC_R_SUCCESS) {
		if (rs != NULL)
			sqlite_free_result(rs);
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver unable to return "
			"result set for lookup query");
		return (ISC_R_FAILURE);
	}
	/*
	 * lookup and authority result sets are processed in the same manner
	 * sqlite_process_rs does the job for both functions.
	 */
	return sqlite_process_rs(lookup, rs);
}

/*%
 * create an instance of the driver.  Remember, only 1 copy of the driver's
 * code is ever loaded, the driver has to remember which context it's
 * operating in.  This is done via use of the dbdata argument which is
 * passed into all query functions.
 */
static isc_result_t
sqlite_create(const char *dlzname, unsigned int argc, char *argv[],void *driverarg, void **dbdata)
{
	isc_result_t result;
	dbinstance_t *dbi = NULL;
	char *tmp = NULL;
	char *dbname = NULL;
	char *host = NULL;
	sqlite3 * dbc;
	unsigned int flags = 0;

	UNUSED(driverarg);
	UNUSED(dlzname);

	/* verify we have at least 4 arg's passed to the driver */
	if (argc < 4) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver requires "
			"at least 4 command line args.");
		return (ISC_R_FAILURE);
	}

	/* no more than 8 arg's should be passed to the driver */
	if (argc > 8) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver cannot accept "
			"more than 7 command line args.");
		return (ISC_R_FAILURE);
	}

	/* parse connection string and get paramters. */

	/* get db name - required */
	dbname = getParameterValue(argv[1], "dbname=");
	if (dbname == NULL) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver requires a dbname parameter.");
		result = ISC_R_FAILURE;
		goto full_cleanup;
	}

	/* how many queries were passed in from config file? */
	switch(argc) {
	case 4:
		result = build_sqldbinstance(ns_g_mctx, NULL, NULL, NULL, argv[2], argv[3], NULL, &dbi);
		break;
	case 5:
		result = build_sqldbinstance(ns_g_mctx, NULL, NULL, argv[4],argv[2], argv[3], NULL, &dbi);
		break;
	case 6:
		result = build_sqldbinstance(ns_g_mctx, argv[5], NULL, argv[4],argv[2], argv[3], NULL, &dbi);
		break;
	case 7:
		result = build_sqldbinstance(ns_g_mctx, argv[5],argv[6], argv[4],argv[2], argv[3], NULL, &dbi);
		break;
	case 8:
		result = build_sqldbinstance(ns_g_mctx, argv[5],argv[6], argv[4],argv[2], argv[3], argv[7], &dbi);
		break;
	default:
		/* not really needed, should shut up compiler. */
		result = ISC_R_FAILURE;
	}

	/* unsuccessful?, log err msg and cleanup. */
	if (result != ISC_R_SUCCESS) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver could not create "
			"database instance object.");
		result = ISC_R_FAILURE;
		goto full_cleanup;
	}

	/* create and set db connection */
	if ( sqlite3_initialize ( ) == SQLITE_OK ){
		if ( sqlite3_open( dbname, ( sqlite3**)&dbi->dbconn ) == SQLITE_OK ){
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver opened successfully ");
		}else{
			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver could not open the db: %s",dbname);
			result = ISC_R_FAILURE;
			goto full_cleanup;
		}
	}else{
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
			"sqlite driver could not create failed to initialize");
		result = ISC_R_FAILURE;
		goto full_cleanup;
	}

	/* if db connection cannot be created, log err msg and cleanup. */
	if (dbi->dbconn == NULL) {
		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
			DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
			"sqlite driver could not allocate "
			"memory for database connection");
		result = ISC_R_FAILURE;
		goto full_cleanup;
	}

	dbc = NULL;
	host = getParameterValue(argv[1], "host=");

	/* return db connection via dbdata */
	*dbdata = dbi;

	result = ISC_R_SUCCESS;
	goto cleanup;

 full_cleanup:

	destroy_sqldbinstance(dbi);

 cleanup:
	if (dbname != NULL)
		isc_mem_free(ns_g_mctx, dbname);
	if (host != NULL)
		isc_mem_free(ns_g_mctx, host);
	return result;
}

static void
sqlite_destroy(void *driverarg, void *dbdata)
{
	dbinstance_t *dbi;
	UNUSED(driverarg);
	dbi = (dbinstance_t *) dbdata;
	/* release DB connection */
	if (dbi->dbconn != NULL){
		if ( sqlite3_close((sqlite3 *) dbi->dbconn)!= SQLITE_OK ){

		}
	}
	if ( sqlite3_shutdown() != SQLITE_OK ){
		
	}
	/* destroy DB instance */
	destroy_sqldbinstance(dbi);
}


static dns_sdlzmethods_t dlz_sqlite_methods = {
	sqlite_create,
	sqlite_destroy,
	sqlite_findzone,
	sqlite_lookup,
	sqlite_authority,
	sqlite_allnodes,
	sqlite_allowzonexfr
};

/*	Wrapper around dns_sdlzregister(). */
isc_result_t
dlz_sqlite_init(void) {
	isc_result_t result;

	/* Write debugging message to log*/
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
		DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
		"Registering DLZ_sqlite driver.");
	result = dns_sdlzregister("dlz_sqlite", &dlz_sqlite_methods, NULL,
		DNS_SDLZFLAG_RELATIVEOWNER |
		DNS_SDLZFLAG_RELATIVERDATA,
		ns_g_mctx, &dlz_sqlite);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
			"dns_sdlzregister() failed: %s",
			isc_result_totext(result));
		result = ISC_R_UNEXPECTED;
	}
	return result;
}

/*
 * Wrapper around dns_sdlzunregister().
 */
void
dlz_sqlite_clear(void) {
	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),"Unregistering DLZ_sqlite driver.");

	if (dlz_sqlite != NULL)
		dns_sdlzunregister(&dlz_sqlite);
}

#endif