--- res/res_odbc.c.orig	2006-01-06 10:45:43.000000000 -0500
+++ res/res_odbc.c	2006-01-10 08:18:28.000000000 -0500
@@ -107,7 +107,7 @@
 static char *tdesc = "ODBC Resource";
 /* internal stuff */
 
-SQLHSTMT odbc_prepare_and_execute(odbc_obj *obj, SQLHSTMT (*prepare_cb)(odbc_obj *obj, void *data), void *data)
+SQLHSTMT odbc_prepare_and_execute(odbc_obj *obj, odbc_obj_con *obj_con, SQLHSTMT (*prepare_cb)(odbc_obj *obj, void *data), void *data)
 {
 	int res = 0, i, attempt;
 	SQLINTEGER nativeerror=0, numfields=0;
@@ -141,11 +141,11 @@
 				ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res);
 				SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 
-				ast_mutex_lock(&obj->lock);
-				obj->up = 0;
-				ast_mutex_unlock(&obj->lock);
-				odbc_obj_disconnect(obj);
-				odbc_obj_connect(obj);
+				ast_mutex_lock(&obj_con->lock);
+				obj_con->up = 0;
+				ast_mutex_unlock(&obj_con->lock);
+				odbc_obj_disconnect(obj, obj_con);
+				odbc_obj_connect(obj, obj_con);
 				continue;
 			}
 			break;
@@ -155,13 +155,18 @@
 	return stmt;
 }
 
-int odbc_smart_execute(odbc_obj *obj, SQLHSTMT stmt) 
+int odbc_smart_execute(odbc_obj *obj, odbc_obj_con *obj_con, SQLHSTMT stmt) 
 {
 	int res = 0, i;
 	SQLINTEGER nativeerror=0, numfields=0;
 	SQLSMALLINT diagbytes=0;
 	unsigned char state[10], diagnostic[256];
 
+	ast_mutex_lock(&obj->lock);
+	obj->executes++;
+	ast_mutex_unlock(&obj->lock);
+	
+
 	res = SQLExecute(stmt);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
 		if (res == SQL_ERROR) {
@@ -190,56 +195,67 @@
 }
 
 
-int odbc_smart_direct_execute(odbc_obj *obj, SQLHSTMT stmt, char *sql) 
+int odbc_smart_direct_execute(odbc_obj *obj, odbc_obj_con *obj_con, SQLHSTMT stmt, char *sql) 
 {
 	int res = 0;
 
+	ast_mutex_lock(&obj->lock);
+	obj->executes++;
+	ast_mutex_unlock(&obj->lock);
+
 	res = SQLExecDirect (stmt, (unsigned char *)sql, SQL_NTS);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Execute error! Attempting a reconnect...\n");
-		ast_mutex_lock(&obj->lock);
-		obj->up = 0;
-		ast_mutex_unlock(&obj->lock);
-		odbc_obj_disconnect(obj);
-		odbc_obj_connect(obj);
+		ast_mutex_lock(&obj_con->lock);
+		obj_con->up = 0;
+		ast_mutex_unlock(&obj_con->lock);
+		odbc_obj_disconnect(obj, obj_con);
+		odbc_obj_connect(obj, obj_con);
 		res = SQLExecDirect (stmt, (unsigned char *)sql, SQL_NTS);
 	}
 	
 	return res;
 }
 
-int odbc_sanity_check(odbc_obj *obj) 
+int odbc_sanity_check(odbc_obj *obj, odbc_obj_con *obj_con) 
 {
 	char *test_sql = "select 1";
 	SQLHSTMT stmt;
 	int res = 0;
 
-	ast_mutex_lock(&obj->lock);
-	if(obj->up) { /* so you say... let's make sure */
-		res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
+	ast_mutex_lock(&obj_con->lock);
+	if(obj_con->up) { /* so you say... let's make sure */
+		res = SQLAllocHandle (SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-			obj->up = 0; /* Liar!*/
+			obj_con->up = 0; /* Liar!*/
 		} else {
 			res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS);
 			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-				obj->up = 0; /* Liar!*/
+				obj_con->up = 0; /* Liar!*/
 			} else {
 				res = SQLExecute(stmt);
 				if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-					obj->up = 0; /* Liar!*/
+					obj_con->up = 0; /* Liar!*/
 				}
 			}
 		}
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
 	}
-	ast_mutex_unlock(&obj->lock);
+	ast_mutex_unlock(&obj_con->lock);
 
-	if(!obj->up) { /* Try to reconnect! */
+	if(!obj_con->up) { /* Try to reconnect! */
 		ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n");
-		odbc_obj_disconnect(obj);
-		odbc_obj_connect(obj);
+		odbc_obj_disconnect(obj, obj_con);
+		odbc_obj_connect(obj, obj_con);
 	}
-	return obj->up;
+	return obj_con->up;
+}
+
+void odbc_sanity_check_all(odbc_obj *obj)
+{
+	int i;
+	for(i = 0; i < obj->poolsize; i++)
+		odbc_sanity_check(obj, &obj->pool[i]);
 }
 
 static int load_odbc_config(void)
@@ -249,6 +265,8 @@
 	struct ast_variable *v;
 	char *cat, *dsn, *username, *password;
 	int enabled;
+	int pooled = 0;
+	int poolsize = 0;
 	int connect = 0;
 	char *env_var;
 
@@ -285,15 +303,20 @@
 					username = v->value;
 				if (!strcmp(v->name, "password"))
 					password = v->value;
+				if (!strcmp(v->name, "pooled"))
+					pooled = ast_true(v->value);
+				if (!strcmp(v->name, "poolsize"))
+					if(sscanf(v->value, "%d", &poolsize) < 1)
+						ast_log(LOG_WARNING, "Unable to convert '%s' to a number\n", v->value);	
 			}
 
 			if (enabled && dsn) {
-				obj = new_odbc_obj(cat, dsn, username, password);
+				obj = new_odbc_obj(cat, dsn, username, password, pooled ? poolsize : 0);
 				if (obj) {
 					register_odbc_obj(cat, obj);
 					ast_log(LOG_NOTICE, "registered database handle '%s' dsn->[%s]\n", cat, obj->dsn);
 					if (connect) {
-						odbc_obj_connect(obj);
+						odbc_obj_connect_all(obj);
 					}
 				} else {
 					ast_log(LOG_WARNING, "Addition of obj %s failed.\n", cat);
@@ -306,11 +329,63 @@
 	return 0;
 }
 
-int odbc_dump_fd(int fd, odbc_obj *obj)
+int odbc_dump_fd(int fd, odbc_obj *obj, int showpool)
 {
+	ast_mutex_lock(&obj->poollock);	
+
 	/* make sure the connection is up before we lie to our master.*/
-	odbc_sanity_check(obj);
-	ast_cli(fd, "Name: %s\nDSN: %s\nConnected: %s\n\n", obj->name, obj->dsn, obj->up ? "yes" : "no");
+	odbc_sanity_check_all(obj);
+	//ast_cli(fd, "Name: %s\nDSN: %s\nConnected: %s\n\n", obj->name, obj->dsn, obj->up ? "yes" : "no");
+	ast_cli(fd, 
+		"Name     : %s\n"
+		"DSN      : %s\n"
+		"Pooled   : %s\n", 
+		obj->name, obj->dsn, obj->pooled ? "Yes" : "No");
+	
+	ast_mutex_lock(&obj->lock);
+	if(ast_startuptime)
+	{
+		time_t now, diff;
+		time(&now);
+		
+		diff = now - ast_startuptime;
+
+		ast_cli(fd, "Executes : %.2f per second (%d total)\n", (double) obj->executes / diff, obj->executes);
+	}
+	else
+	{
+		ast_cli(fd, "Executes : %d\n", obj->executes);
+	}
+	ast_mutex_unlock(&obj->lock);
+
+	if(obj->pooled)
+		ast_cli(fd, "Available: %d/%d\n", obj->poolavailable, obj->poolsize);
+
+	char name[10];
+	int i;
+	
+	if(showpool || !obj->pooled) {
+		for(i = 0; i < obj->poolsize; i++) {
+			odbc_obj_con *obj_con = &obj->pool[i];
+			
+			if(obj->pooled)
+				snprintf(name, 10, "%9d", obj_con->id);	
+			else
+				strcpy(name, "Status   ");
+
+			if(!obj_con->up)
+				ast_cli(fd, "%s: Disconnected\n", name);
+			else if(obj_con->available)
+				ast_cli(fd, "%s: Available\n", name);
+			else
+				ast_cli(fd, "%s: Locked (%s:%d:%s)\n", name, 
+					obj_con->owner_file, obj_con->owner_line, obj_con->owner_func);
+		}
+	}
+
+	ast_cli(fd, "\n");
+	ast_mutex_unlock(&obj->poollock);
+
 	return 0;
 }
 
@@ -330,19 +405,22 @@
 {
 	odbc_obj *obj;
 	int x = 0;
+	int showpool = !strcmp(argv[1], "showpool");
 	
-	if (!strcmp(argv[1], "show")) {
+	if (!strcmp(argv[1], "show") || showpool) {
 		if (!argv[2] || (argv[2] && !strcmp(argv[2], "all"))) {
 			for (x = 0; x < MAX_ODBC_HANDLES; x++) {
 				if (!ODBC_REGISTRY[x].used)
 					break;
-				if (ODBC_REGISTRY[x].obj)
-					odbc_dump_fd(fd, ODBC_REGISTRY[x].obj);
+
+				if (ODBC_REGISTRY[x].obj) {
+					odbc_dump_fd(fd, ODBC_REGISTRY[x].obj, showpool);
+				}
 			}
 		} else {
 			obj = odbc_read(ODBC_REGISTRY, argv[2]);
 			if (obj)
-				odbc_dump_fd(fd, obj);
+				odbc_dump_fd(fd, obj, showpool);
 		}
 	}
 	return 0;
@@ -357,7 +435,7 @@
 
 		obj = odbc_read(ODBC_REGISTRY, argv[2]);
 		if (obj) {
-			odbc_obj_disconnect(obj);
+			odbc_obj_disconnect_all(obj);
 		}
 	} 
 	return 0;
@@ -375,7 +453,7 @@
 
 		obj = odbc_read(ODBC_REGISTRY, argv[2]);
 		if (obj) {
-			odbc_obj_connect(obj);
+			odbc_obj_connect_all(obj);
 		}
 	}
 	return 0;
@@ -395,6 +473,11 @@
 "       Show ODBC {DSN}\n"
 "       Specifying DSN will show that DSN else, all DSNs are shown\n";
 
+static char showpool_usage[] =
+"Usage: odbc showpool\n"
+"       Show pool info\n"
+"       Specifying DSN will show info for that DSN else, info for all DSNs are shown\n";
+
 static struct ast_cli_entry odbc_connect_struct =
         { { "odbc", "connect", NULL }, odbc_connect_command, "Connect to ODBC DSN", connect_usage };
 
@@ -405,6 +488,9 @@
 static struct ast_cli_entry odbc_show_struct =
         { { "odbc", "show", NULL }, odbc_show_command, "Show ODBC DSN(s)", show_usage };
 
+static struct ast_cli_entry odbc_showpool_struct =
+        { { "odbc", "showpool", NULL }, odbc_show_command, "Show pool info", showpool_usage };
+
 /* api calls */
 
 int register_odbc_obj(char *name, odbc_obj *obj)
@@ -419,20 +505,150 @@
 	odbc_obj *obj = NULL;
 	if((obj = (odbc_obj *) odbc_read(ODBC_REGISTRY, name))) {
 		if(check)
-			odbc_sanity_check(obj);
+			odbc_sanity_check_all(obj);
 	}
 	return obj;
 }
 
-odbc_obj *new_odbc_obj(char *name, char *dsn, char *username, char *password)
+static odbc_obj_con *take_available_con(odbc_obj *obj)
+{
+	odbc_obj_con *obj_con_available = NULL;
+	int i;
+
+	for(i = 0; i < obj->poolsize; i++) {
+		odbc_obj_con *obj_con = &obj->pool[i];
+		//ast_log(LOG_NOTICE, "Is %d Available: %d\n", obj_con->id, obj_con->available);
+		if(obj_con->available) {
+			obj_con->available = 0;
+			obj_con_available = obj_con;
+			//ast_log(LOG_NOTICE, "Returning connection '%d'\n", obj_con->id);
+			break;
+		}
+	}
+
+	if(obj_con_available) {
+		obj->poolavailable--;
+		return obj_con_available;
+	} else {
+		//ast_log(LOG_WARNING, "A connection in the pool should have been available but it was not\n");
+		return NULL;
+	}
+}
+
+static void check_connections(odbc_obj *obj)
+{
+	int i;
+
+	for(i = 0; i < obj->poolsize; i++) {
+		odbc_obj_con *con = &obj->pool[i];
+		if(!con->available) {
+			time_t now;
+			time(&now);
+			if(now - con->lock_time > 3) {
+				ast_log(LOG_WARNING, "Connection has been locked by '%s' in '%s:%d' for more than 3 seconds\n", 
+					con->owner_func, con->owner_file, con->owner_line);
+				time(&con->lock_time);
+			}	
+		}
+	}
+}
+
+odbc_obj_con *__fetch_odbc_con(const char *file, int line, const char *function, odbc_obj *obj)
+{
+	odbc_obj_con *con = NULL;
+
+	if(obj == NULL)
+		return NULL;
+
+	//ast_log(LOG_NOTICE, "Request for a connection by '%s' at '%s:%d'\n", function, file, line);
+
+	if(!obj->pooled)
+	{
+		//ast_log(LOG_NOTICE, "Not pooled (%s) (%d)!\n", obj->dsn, obj->poolsize);
+		return &obj->pool[0];
+	}
+
+	ast_mutex_lock(&obj->poollock);
+
+	check_connections(obj);
+
+	if(obj->poolavailable)
+	{
+		//ast_log(LOG_NOTICE, "Connections available: %d\n", obj->poolavailable);
+		con = take_available_con(obj);
+		if(con)
+		{
+			//ast_log(LOG_NOTICE, "Connection locked (%d), connections available: %d\n", con->id, obj->poolavailable);
+			ast_mutex_unlock(&obj->poollock);
+			
+			con->owner_file = file;
+			con->owner_line = line;
+			con->owner_func = function;
+			time(&con->lock_time);
+
+			return con;
+		}
+	}
+
+	while(con == NULL)
+	{
+		time_t time_start, time_end;
+		time(&time_start);
+
+		//ast_log(LOG_NOTICE, "Waiting for an available connection\n");
+		ast_cond_wait(&obj->poolcond, &obj->poollock);
+
+		time(&time_end);
+		if(time_end - time_start > 3)
+			ast_log(LOG_WARNING, "Waited more than 3 second to obtain a connection\n");
+
+		con = take_available_con(obj);
+	}
+
+	//ast_log(LOG_NOTICE, "Got a connection\n");
+
+	con->owner_file = file;
+	con->owner_line = line;
+	con->owner_func = function;
+	time(&con->lock_time);
+	
+	ast_mutex_unlock(&obj->poollock);
+
+	return con;
+}
+
+void release_odbc_con(odbc_obj *obj, odbc_obj_con *obj_con)
+{
+	if(!obj->pooled)
+		return;
+
+	ast_mutex_lock(&obj->poollock);
+
+	if(obj_con->available)
+	{
+		ast_log(LOG_WARNING, "Trying to release an available connection\n");
+		ast_mutex_unlock(&obj->poollock);
+		return;
+	}
+
+	obj_con->available = 1;
+	obj->poolavailable++;
+	//ast_log(LOG_NOTICE, "Releasing connection (%d), now available: %d\n", obj_con->id, obj->poolavailable);
+	ast_mutex_unlock(&obj->poollock);
+
+	//ast_log(LOG_NOTICE, "Signaling waiting callers\n");
+	ast_cond_signal(&obj->poolcond);
+}
+
+odbc_obj *new_odbc_obj(char *name, char *dsn, char *username, char *password, int poolsize)
 {
 	static odbc_obj *new;
+	int i;
 
 	new = malloc(sizeof(odbc_obj));
 	if (!new)
 		return NULL;
 	memset(new, 0, sizeof(odbc_obj));
-	new->env = SQL_NULL_HANDLE;
 
 	new->name = malloc(strlen(name) + 1);
 	if (new->name == NULL)
@@ -456,39 +672,81 @@
 		strcpy(new->password, password);
 	}
 
+	if(poolsize != 0) {
+		new->poolsize = poolsize;
+		new->pooled = 1;
+	}
+	else {
+		new->poolsize = 1;
+		new->pooled = 0;
+	}
+	new->poolavailable = poolsize;
+		
+	new->pool = malloc(sizeof(struct odbc_obj_con) * new->poolsize);
+	new->executes = 0;
+
+	for(i = 0; i < new->poolsize; i++) {
+		odbc_obj_con *obj_con = &new->pool[i];
+		
+		obj_con->env = SQL_NULL_HANDLE;
+		obj_con->up = 0;
+		obj_con->available = 1;
+		obj_con->id = i;
+		ast_mutex_init(&obj_con->lock);
+	}
+
+	ast_mutex_init(&new->lock);
+	ast_mutex_init(&new->poollock);
+	ast_cond_init(&new->poolcond, NULL);
+
 	strcpy(new->name, name);
 	strcpy(new->dsn, dsn);
-	new->up = 0;
-	ast_mutex_init(&new->lock);
 	return new;
 }
 
 void destroy_odbc_obj(odbc_obj **obj)
 {
-	odbc_obj_disconnect(*obj);
+	int i;
+	odbc_obj_disconnect_all(*obj);
+
+	ast_mutex_lock(&(*obj)->poollock);
+
+	for(i = 0; i < (*obj)->poolsize; i++) {
+		odbc_obj_con *obj_con = &(*obj)->pool[i];
+
+		ast_mutex_lock(&obj_con->lock);
+		
+		SQLFreeHandle(SQL_HANDLE_STMT,obj_con->stmt);
+		SQLFreeHandle(SQL_HANDLE_DBC, obj_con->con);
+		SQLFreeHandle(SQL_HANDLE_ENV, obj_con->env);
 
-	ast_mutex_lock(&(*obj)->lock);
-	SQLFreeHandle(SQL_HANDLE_STMT, (*obj)->stmt);
-	SQLFreeHandle(SQL_HANDLE_DBC, (*obj)->con);
-	SQLFreeHandle(SQL_HANDLE_ENV, (*obj)->env);
+		ast_mutex_unlock(&obj_con->lock);
 
+		ast_mutex_destroy(&obj_con->lock);
+	}
+
+	free((*obj)->pool);	
 	free((*obj)->name);
 	free((*obj)->dsn);
 	if ((*obj)->username)
 		free((*obj)->username);
 	if ((*obj)->password)
 		free((*obj)->password);
-	ast_mutex_unlock(&(*obj)->lock);
+
+	ast_mutex_unlock(&(*obj)->poollock);
+
+	ast_mutex_destroy(&(*obj)->poollock);
 	ast_mutex_destroy(&(*obj)->lock);
+
 	free(*obj);
 }
 
-odbc_status odbc_obj_disconnect(odbc_obj *obj)
+odbc_status odbc_obj_disconnect(odbc_obj *obj, odbc_obj_con *obj_con)
 {
 	int res;
-	ast_mutex_lock(&obj->lock);
+	ast_mutex_lock(&obj_con->lock);
 
-	res = SQLDisconnect(obj->con);
+	res = SQLDisconnect(obj_con->con);
 
 
 	if (res == ODBC_SUCCESS) {
@@ -497,81 +755,102 @@
 		ast_log(LOG_WARNING, "res_odbc: %s [%s] already disconnected\n",
 		obj->name, obj->dsn);
 	}
-	obj->up = 0;
-	ast_mutex_unlock(&obj->lock);
+	obj_con->up = 0;
+	ast_mutex_unlock(&obj_con->lock);
 	return ODBC_SUCCESS;
 }
 
-odbc_status odbc_obj_connect(odbc_obj *obj)
+void odbc_obj_disconnect_all(odbc_obj *obj)
+{
+	int i;
+	for(i = 0; i < obj->poolsize; i++) {
+		odbc_obj_con *obj_con = &obj->pool[i];
+		odbc_obj_disconnect(obj, obj_con);
+	}
+}
+
+odbc_status odbc_obj_connect(odbc_obj *obj, odbc_obj_con *obj_con)
 {
 	int res;
 	SQLINTEGER err;
 	short int mlen;
 	unsigned char msg[200], stat[10];
 
-	ast_mutex_lock(&obj->lock);
+	ast_mutex_lock(&obj_con->lock);
 
-	if (obj->env == SQL_NULL_HANDLE) {
-		res = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &obj->env);
+	if (obj_con->env == SQL_NULL_HANDLE) {
+		res = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &obj_con->env);
 
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			if (option_verbose > 3)
 				ast_log(LOG_WARNING, "res_odbc: Error AllocHandle\n");
-			ast_mutex_unlock(&obj->lock);
+			ast_mutex_unlock(&obj_con->lock);
 			return ODBC_FAIL;
 		}
 
-		res = SQLSetEnvAttr(obj->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
+		res = SQLSetEnvAttr(obj_con->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
 
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			if (option_verbose > 3)
 				ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n");
-			SQLFreeHandle(SQL_HANDLE_ENV, obj->env);
-			ast_mutex_unlock(&obj->lock);
+			SQLFreeHandle(SQL_HANDLE_ENV, obj_con->env);
+			ast_mutex_unlock(&obj_con->lock);
 			return ODBC_FAIL;
 		}
 
-		res = SQLAllocHandle(SQL_HANDLE_DBC, obj->env, &obj->con);
+		res = SQLAllocHandle(SQL_HANDLE_DBC, obj_con->env, &obj_con->con);
 
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 
 			if (option_verbose > 3)
 				ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res);
-			SQLFreeHandle(SQL_HANDLE_ENV, obj->env);
+			SQLFreeHandle(SQL_HANDLE_ENV, obj_con->env);
 
-			ast_mutex_unlock(&obj->lock);
+			ast_mutex_unlock(&obj_con->lock);
 			return ODBC_FAIL;
 		}
-		SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
+		SQLSetConnectAttr(obj_con->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
 	}
-	if(obj->up) {
-		odbc_obj_disconnect(obj);
+	if(obj_con->up) {
+		odbc_obj_disconnect(obj, obj_con);
 		ast_log(LOG_NOTICE,"Re-connecting %s\n", obj->name);
 	}
 
+	if(obj->pooled)
+		ast_log(LOG_NOTICE, "Connecting %s [%d]\n", obj->name, obj_con->id);
+	else
 	ast_log(LOG_NOTICE, "Connecting %s\n", obj->name);
 
-	res = SQLConnect(obj->con,
+	res = SQLConnect(obj_con->con,
 		   (SQLCHAR *) obj->dsn, SQL_NTS,
 		   (SQLCHAR *) obj->username, SQL_NTS,
 		   (SQLCHAR *) obj->password, SQL_NTS);
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen);
-		SQLFreeHandle(SQL_HANDLE_ENV, obj->env);
-		ast_mutex_unlock(&obj->lock);
+		SQLGetDiagRec(SQL_HANDLE_DBC, obj_con->con, 1, stat, &err, msg, 100, &mlen);
+		SQLFreeHandle(SQL_HANDLE_ENV, obj_con->env);
+		ast_mutex_unlock(&obj_con->lock);
 		ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg);
 		return ODBC_FAIL;
 	} else {
 
 		ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->name, obj->dsn);
-		obj->up = 1;
+		obj_con->up = 1;
 	}
 
-	ast_mutex_unlock(&obj->lock);
+	ast_mutex_unlock(&obj_con->lock);
 	return ODBC_SUCCESS;
 }
 
+void odbc_obj_connect_all(odbc_obj *obj)
+{
+	int i;
+	for(i = 0; i < obj->poolsize; i++) {
+		odbc_obj_con *obj_con = &obj->pool[i];
+		odbc_obj_connect(obj, obj_con);
+	}
+}
+
 STANDARD_LOCAL_USER;
 
 LOCAL_USER_DECL;
@@ -583,6 +862,7 @@
 	ast_cli_unregister(&odbc_disconnect_struct);
 	ast_cli_unregister(&odbc_connect_struct);
 	ast_cli_unregister(&odbc_show_struct);
+	ast_cli_unregister(&odbc_showpool_struct);
 	ast_log(LOG_NOTICE, "res_odbc unloaded.\n");
 	return 0;
 }
@@ -594,6 +874,7 @@
 	ast_cli_register(&odbc_disconnect_struct);
 	ast_cli_register(&odbc_connect_struct);
 	ast_cli_register(&odbc_show_struct);
+	ast_cli_register(&odbc_showpool_struct);
 	ast_log(LOG_NOTICE, "res_odbc loaded.\n");
 	return 0;
 }
--- include/asterisk/res_odbc.h.orig	2006-01-06 10:57:44.000000000 -0500
+++ include/asterisk/res_odbc.h	2006-01-09 07:23:16.000000000 -0500
@@ -30,33 +30,60 @@
 #include <sqltypes.h>
 
 typedef struct odbc_obj odbc_obj;
+typedef struct odbc_obj_con odbc_obj_con;
 
 typedef enum { ODBC_SUCCESS=0,ODBC_FAIL=-1} odbc_status;
 
-struct odbc_obj {
-	char *name;
-	char *dsn;
-	char *username;
-	char *password;
+struct odbc_obj_con {
 	SQLHENV  env;                   /* ODBC Environment */
 	SQLHDBC  con;                   /* ODBC Connection Handle */
 	SQLHSTMT stmt;                  /* ODBC Statement Handle */
 	ast_mutex_t lock;
+	int id;
 	int up;
+	int available;
+	
+	const char *owner_func;
+	const char *owner_file;
+	int owner_line;
 
+	time_t lock_time;
+};
+
+struct odbc_obj {
+	char *name;
+	char *dsn;
+	char *username;
+	char *password;
+	int pooled;
+	int poolsize;
+	int poolavailable;
+	int executes;
+	odbc_obj_con *pool;
+	ast_mutex_t poollock;
+	ast_cond_t poolcond;
+	ast_mutex_t lock;
 };
 
 /* functions */
-odbc_obj *new_odbc_obj(char *name,char *dsn,char *username, char *password);
-odbc_status odbc_obj_connect(odbc_obj *obj);
-odbc_status odbc_obj_disconnect(odbc_obj *obj);
+odbc_obj *new_odbc_obj(char *name,char *dsn,char *username, char *password, int poolsize);
+odbc_status odbc_obj_connect(odbc_obj *obj, odbc_obj_con *obj_con);
+void odbc_obj_connect_all(odbc_obj *obj);
+odbc_status odbc_obj_disconnect(odbc_obj *obj, odbc_obj_con *obj_con);
+void odbc_obj_disconnect_all(odbc_obj *obj);
 void destroy_odbc_obj(odbc_obj **obj);
 int register_odbc_obj(char *name,odbc_obj *obj);
+//odbc_obj_con *fetch_odbc_con(odbc_obj *obj);
 odbc_obj *fetch_odbc_obj(const char *name, int check);
-int odbc_dump_fd(int fd,odbc_obj *obj);
-int odbc_sanity_check(odbc_obj *obj);
-SQLHSTMT odbc_prepare_and_execute(odbc_obj *obj, SQLHSTMT (*prepare_cb)(odbc_obj *obj, void *data), void *data);
-int odbc_smart_execute(odbc_obj *obj, SQLHSTMT stmt);
-int odbc_smart_direct_execute(odbc_obj *obj, SQLHSTMT stmt, char *sql);
+void release_odbc_con(odbc_obj *obj, odbc_obj_con *obj_con);
+int odbc_dump_fd(int fd,odbc_obj *obj, int showpool);
+int odbc_sanity_check(odbc_obj *obj, odbc_obj_con *obj_con);
+void odbc_sanity_check_all(odbc_obj *obj);
+SQLHSTMT odbc_prepare_and_execute(odbc_obj *obj, odbc_obj_con *obj_con, SQLHSTMT (*prepare_cb)(odbc_obj *obj, void *data), void *data);
+int odbc_smart_execute(odbc_obj *obj, odbc_obj_con *obj_con, SQLHSTMT stmt);
+int odbc_smart_direct_execute(odbc_obj *obj, odbc_obj_con *obj_con,SQLHSTMT stmt, char *sql);
+
+odbc_obj_con *__fetch_odbc_con(const char *file, int line, const char *function, odbc_obj *obj);
+#define fetch_odbc_con(obj) __fetch_odbc_con(__FILE__, __LINE__, __PRETTY_FUNCTION__, obj)
 
 #endif /* _ASTERISK_RES_ODBC_H */
--- apps/app_voicemail.c.orig	2005-12-03 14:55:05.000000000 -0500
+++ apps/app_voicemail.c	2006-01-09 13:27:21.000000000 -0500
@@ -818,8 +824,10 @@
 	char msgnums[80];
 	
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
+	obj_con = fetch_odbc_con(obj);
+	if (obj && obj_con) {
 		ast_copy_string(fmt, vmfmts, sizeof(fmt));
 		c = strchr(fmt, '|');
 		if (c)
@@ -834,7 +842,7 @@
 		snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
 		f = fopen(full_fn, "w+");
 		snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
@@ -848,7 +856,7 @@
 		}
 		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
 		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -926,6 +934,8 @@
 	} else
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 yuck:	
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
 	if (f)
 		fclose(f);
 	if (fdm)
@@ -961,9 +971,11 @@
 	char rowdata[20];
 	
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+	obj_con = fetch_odbc_con(obj);
+	if (obj && obj_con) {
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
@@ -976,7 +988,7 @@
 			goto yuck;
 		}
 		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -1000,6 +1012,9 @@
 	} else
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 yuck:	
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
+
 	return x - 1;
 }
 
@@ -1013,10 +1028,12 @@
 	char msgnums[20];
 	
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
+	obj_con = fetch_odbc_con(obj);
+	if (obj && obj_con) {
 		snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
@@ -1030,7 +1047,7 @@
 		}
 		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
 		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -1054,6 +1071,9 @@
 	} else
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 yuck:	
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
+
 	return x;
 }
 
@@ -1070,10 +1090,12 @@
 	char msgnums[20];
 	
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
+	obj_con = fetch_odbc_con(obj);
+	if (obj && obj_con) {
 		snprintf(msgnums, sizeof(msgnums), "%d", smsg);
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
@@ -1087,7 +1109,7 @@
 		}
 		SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
 		SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -1097,6 +1119,9 @@
 	} else
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 yuck:
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
+
 	return;	
 }
 
@@ -1108,13 +1133,15 @@
 	char msgnums[20];
 	char msgnumd[20];
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 
 	delete_file(ddir, dmsg);
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
+	obj_con = fetch_odbc_con(obj);
+	if (obj && obj_con) {
 		snprintf(msgnums, sizeof(msgnums), "%d", smsg);
 		snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
@@ -1141,7 +1168,7 @@
  		SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
  		SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
 #endif		 
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -1151,6 +1178,9 @@
 	} else
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 yuck:
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
+
 	return;	
 }
 
@@ -1173,10 +1203,12 @@
 	char *category = "";
 	struct ast_config *cfg=NULL;
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 
 	delete_file(dir, msgnum);
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
+	obj_con = fetch_odbc_con(obj);
+	if (obj && obj_con) {
 		ast_copy_string(fmt, vmfmts, sizeof(fmt));
 		c = strchr(fmt, '|');
 		if (c)
@@ -1218,7 +1250,7 @@
 			ast_log(LOG_WARNING, "Memory map failed!\n");
 			goto yuck;
 		} 
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
@@ -1259,7 +1291,7 @@
  		if (!ast_strlen_zero(category))
  			SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(category), 0, (void *)category, 0, NULL);
 #endif
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -1269,6 +1301,8 @@
 	} else
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 yuck:	
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
 	if (cfg)
 		ast_config_destroy(cfg);
 	if (fdm)
@@ -1286,13 +1320,15 @@
 	char msgnums[20];
 	char msgnumd[20];
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 
 	delete_file(ddir, dmsg);
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
+	obj_con = fetch_odbc_con(obj);
+	if (obj && obj_con) {
 		snprintf(msgnums, sizeof(msgnums), "%d", smsg);
 		snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
@@ -1319,7 +1355,7 @@
  		SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
  		SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
 #endif		 
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -1329,6 +1365,8 @@
 	} else
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 yuck:
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
 	return;	
 }
 
@@ -1998,21 +2036,25 @@
                 context = "default";
 	
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
+
 	obj = fetch_odbc_obj(odbc_database, 0);
-	if (obj) {
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+	obj_con = fetch_odbc_con(obj);
+
+	if (obj && obj_con) {
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
 		}
		snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir like \"%%%s/%s/%s\"%c", odbc_table, context, tmp, "INBOX", '\0');
 		res = SQLPrepare(stmt, sql, SQL_NTS);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
 			goto yuck;
 		}
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -2033,19 +2075,19 @@
 		*newmsgs = atoi(rowdata);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
 
-		res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+		res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
 			goto yuck;
 		}
		snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir like \"%%%s/%s/%s\"%c", odbc_table, context, tmp, "Old", '\0');
 		res = SQLPrepare(stmt, sql, SQL_NTS);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
 			goto yuck;
 		}
-		res = odbc_smart_execute(obj, stmt);
+		res = odbc_smart_execute(obj, obj_con, stmt);
 		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 			ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 			SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -2070,6 +2112,8 @@
 		ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 		
 yuck:	
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
 	return x;
 }
 
@@ -2098,21 +2142,23 @@
                 context = "default";
 
         odbc_obj *obj;
+	odbc_obj_con *obj_con;
         obj = fetch_odbc_obj(odbc_database, 0);
-        if (obj) {
-                res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
+	obj_con = fetch_odbc_con(obj);
+        if (obj && obj_con) {
+                res = SQLAllocHandle(SQL_HANDLE_STMT, obj_con->con, &stmt);
                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                         ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
                         goto yuck;
                 }
		snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir like \"%%%s/%s/%s\"%c", odbc_table, context, tmp, "INBOX", '\0');
                 res = SQLPrepare(stmt, sql, SQL_NTS);
                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {  
                         ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
                         SQLFreeHandle (SQL_HANDLE_STMT, stmt);
                         goto yuck;
                 }
-                res = odbc_smart_execute(obj, stmt);
+                res = odbc_smart_execute(obj, obj_con, stmt);
                 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
                         ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
                         SQLFreeHandle (SQL_HANDLE_STMT, stmt);
@@ -2136,6 +2182,8 @@
                 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
 
 yuck:
+	if(obj && obj_con)
+		release_odbc_con(obj, obj_con);
 	if (nummsgs>=1)
 		return 1;
 	else
--- res/res_config_odbc.c.orig	2006-01-06 14:43:58.000000000 -0500
+++ res/res_config_odbc.c	2006-01-06 15:18:29.000000000 -0500
@@ -53,6 +53,7 @@
 static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
 {
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	SQLHSTMT stmt;
 	char sql[1024];
 	char coltitle[256];
@@ -83,15 +84,21 @@
 	if (!obj)
 		return NULL;
 
-	res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
+	obj_con = fetch_odbc_con(obj);
+	if (!obj_con)
+		return NULL;
+
+	res = SQLAllocHandle (SQL_HANDLE_STMT, obj_con->con, &stmt);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
 	newparam = va_arg(aq, const char *);
 	if (!newparam)  {
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 	newval = va_arg(aq, const char *);
@@ -103,10 +110,14 @@
 		newval = va_arg(aq, const char *);
 	}
 	va_end(aq);
+
+	//ast_log(LOG_NOTICE, "realtime engine query: %s\n", sql);
+
 	res = SQLPrepare(stmt, sql, SQL_NTS);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 	
@@ -116,13 +127,15 @@
 	while((newparam = va_arg(ap, const char *))) {
 		newval = va_arg(ap, const char *);
 		SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
+		//ast_log(LOG_NOTICE, "bind parameter %d to %s\n", x, newval);
 	}
 	
-	res = odbc_smart_execute(obj, stmt);
+	res = odbc_smart_execute(obj, obj_con, stmt);
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
@@ -130,17 +143,20 @@
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
 	res = SQLFetch(stmt);
 	if (res == SQL_NO_DATA) {
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
                 return NULL;
 	}
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 	for (x=0;x<colcount;x++) {
@@ -152,6 +168,7 @@
 			ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
 			if (var)
 				ast_variables_destroy(var);
+			release_odbc_con(obj, obj_con);
 			return NULL;
 		}
 
@@ -164,6 +181,7 @@
 			ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
 			if (var)
 				ast_variables_destroy(var);
+			release_odbc_con(obj, obj_con);
 			return NULL;
 		}
 		stringp = rowdata;
@@ -183,12 +201,16 @@
 
 
 	SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+
+	release_odbc_con(obj, obj_con);
+
 	return var;
 }
 
 static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
 {
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	SQLHSTMT stmt;
 	char sql[1024];
 	char coltitle[256];
@@ -224,15 +246,21 @@
 	if (!obj)
 		return NULL;
 
-	res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
+	obj_con = fetch_odbc_con(obj);
+	if (!obj_con)
+		return NULL;
+
+	res = SQLAllocHandle (SQL_HANDLE_STMT, obj_con->con, &stmt);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
 	newparam = va_arg(aq, const char *);
 	if (!newparam)  {
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 	initfield = ast_strdupa(newparam);
@@ -253,6 +281,7 @@
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 	
@@ -264,11 +293,12 @@
 		SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
 	}
 		
-	res = odbc_smart_execute(obj, stmt);
+	res = odbc_smart_execute(obj, obj_con, stmt);
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
@@ -276,6 +306,7 @@
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
@@ -283,6 +314,7 @@
 	if (!cfg) {
 		ast_log(LOG_WARNING, "Out of memory!\n");
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
@@ -333,12 +365,16 @@
 	}
 
 	SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+
+	release_odbc_con(obj, obj_con);
+
 	return cfg;
 }
 
 static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
 {
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	SQLHSTMT stmt;
 	char sql[256];
 	SQLLEN rowcount=0;
@@ -356,15 +392,21 @@
 	if (!obj)
 		return -1;
 
-	res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
+	obj_con = fetch_odbc_con (obj);
+	if (!obj_con)
+		return -1;
+
+	res = SQLAllocHandle (SQL_HANDLE_STMT, obj_con->con, &stmt);
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
+		release_odbc_con(obj, obj_con);
 		return -1;
 	}
 
 	newparam = va_arg(aq, const char *);
 	if (!newparam)  {
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return -1;
 	}
 	newval = va_arg(aq, const char *);
@@ -380,6 +422,7 @@
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return -1;
 	}
 	
@@ -393,11 +436,12 @@
 		
 	SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL);
 
-	res = odbc_smart_execute(obj, stmt);
+	res = odbc_smart_execute(obj, obj_con, stmt);
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return -1;
 	}
 
@@ -406,9 +450,12 @@
 
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
+		release_odbc_con(obj, obj_con);
 		return -1;
 	}
 
+	release_odbc_con(obj, obj_con);
+
        if (rowcount >= 0)
                return (int)rowcount;
 
@@ -421,6 +468,7 @@
 	struct ast_category *cur_cat;
 	int res = 0;
 	odbc_obj *obj;
+	odbc_obj_con *obj_con;
 	SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0;
 	SQLBIGINT id;
 	char sql[255] = "", filename[128], category[128], var_name[128], var_val[512];
@@ -435,7 +483,11 @@
 	if (!obj)
 		return NULL;
 
-	res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
+	obj_con = fetch_odbc_con(obj);
+	if (!obj_con)
+		return NULL;
+
+	res = SQLAllocHandle (SQL_HANDLE_STMT, obj_con->con, &stmt);
 
 	SQLBindCol (stmt, 1, SQL_C_ULONG, &id, sizeof (id), &err);
 	SQLBindCol (stmt, 2, SQL_C_ULONG, &cat_metric, sizeof (cat_metric), &err);
@@ -448,11 +500,12 @@
 	
 	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE filename='%s' and commented=0 ORDER BY filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file);
 
-	res = odbc_smart_direct_execute(obj, stmt, sql);
+	res = odbc_smart_direct_execute(obj, obj_con, stmt, sql);
 	
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log (LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
@@ -461,11 +514,13 @@
 	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
 		ast_log (LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
 		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		release_odbc_con(obj, obj_con);
 		return NULL;
 	}
 
 	if (!rowcount) {
 		ast_log (LOG_NOTICE, "found nothing\n");
+		release_odbc_con(obj, obj_con);
 		return cfg;
 	}
 
@@ -475,6 +530,7 @@
 		if (!strcmp (var_name, "#include")) {
 			if (!ast_config_internal_load(var_val, cfg)) {
 				SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+				release_odbc_con(obj, obj_con);
 				return NULL;
 			}
 			continue;
@@ -495,6 +551,9 @@
 	}
 
 	SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+
+	release_odbc_con(obj, obj_con);
+	
 	return cfg;
 }
 
