1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  *
28  * switch_odbc.c -- ODBC
29  *
30  */
31 
32 #include <switch.h>
33 
34 #ifdef SWITCH_HAVE_ODBC
35 #include <sql.h>
36 #ifdef _MSC_VER
37 #pragma warning(push)
38 #pragma warning(disable:4201)
39 #include <sqlext.h>
40 #pragma warning(pop)
41 #else
42 #include <sqlext.h>
43 #endif
44 #include <sqltypes.h>
45 
46 #if (ODBCVER < 0x0300)
47 #define SQL_NO_DATA SQL_SUCCESS
48 #endif
49 
50 struct switch_odbc_handle {
51 	char *dsn;
52 	char *username;
53 	char *password;
54 	SQLHENV env;
55 	SQLHDBC con;
56 	switch_odbc_state_t state;
57 	char odbc_driver[256];
58 	BOOL is_firebird;
59 	BOOL is_oracle;
60 	int affected_rows;
61 	int num_retries;
62 };
63 #endif
64 
switch_odbc_handle_new(const char * dsn,const char * username,const char * password)65 SWITCH_DECLARE(switch_odbc_handle_t *) switch_odbc_handle_new(const char *dsn, const char *username, const char *password)
66 {
67 #ifdef SWITCH_HAVE_ODBC
68 	switch_odbc_handle_t *new_handle;
69 
70 	if (!(new_handle = malloc(sizeof(*new_handle)))) {
71 		goto err;
72 	}
73 
74 	memset(new_handle, 0, sizeof(*new_handle));
75 
76 	if (!(new_handle->dsn = strdup(dsn))) {
77 		goto err;
78 	}
79 
80 	if (username) {
81 		if (!(new_handle->username = strdup(username))) {
82 			goto err;
83 		}
84 	}
85 
86 	if (password) {
87 		if (!(new_handle->password = strdup(password))) {
88 			goto err;
89 		}
90 	}
91 
92 	new_handle->env = SQL_NULL_HANDLE;
93 	new_handle->state = SWITCH_ODBC_STATE_INIT;
94 	new_handle->affected_rows = 0;
95 	new_handle->num_retries = DEFAULT_ODBC_RETRIES;
96 
97 	return new_handle;
98 
99   err:
100 	if (new_handle) {
101 		switch_safe_free(new_handle->dsn);
102 		switch_safe_free(new_handle->username);
103 		switch_safe_free(new_handle->password);
104 		switch_safe_free(new_handle);
105 	}
106 #endif
107 	return NULL;
108 }
109 
switch_odbc_set_num_retries(switch_odbc_handle_t * handle,int num_retries)110 SWITCH_DECLARE(void) switch_odbc_set_num_retries(switch_odbc_handle_t *handle, int num_retries)
111 {
112 #ifdef SWITCH_HAVE_ODBC
113 	if (handle) {
114 		handle->num_retries = num_retries;
115 	}
116 #endif
117 }
118 
switch_odbc_handle_disconnect(switch_odbc_handle_t * handle)119 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_disconnect(switch_odbc_handle_t *handle)
120 {
121 #ifdef SWITCH_HAVE_ODBC
122 
123 	int result;
124 
125 	if (!handle) {
126 		return SWITCH_ODBC_FAIL;
127 	}
128 
129 	if (handle->state == SWITCH_ODBC_STATE_CONNECTED) {
130 		result = SQLDisconnect(handle->con);
131 		if (result == SWITCH_ODBC_SUCCESS) {
132 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Disconnected %d from [%s]\n", result, handle->dsn);
133 		} else {
134 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Disconnecting [%s]\n", handle->dsn);
135 		}
136 	}
137 
138 	handle->state = SWITCH_ODBC_STATE_DOWN;
139 
140 	return SWITCH_ODBC_SUCCESS;
141 #else
142 	return SWITCH_ODBC_FAIL;
143 #endif
144 }
145 
146 
147 #ifdef SWITCH_HAVE_ODBC
init_odbc_handles(switch_odbc_handle_t * handle,switch_bool_t do_reinit)148 static switch_odbc_status_t init_odbc_handles(switch_odbc_handle_t *handle, switch_bool_t do_reinit)
149 {
150 	int result;
151 
152 	if (!handle) {
153 		return SWITCH_ODBC_FAIL;
154 	}
155 
156 	/* if handle is already initialized, and we're supposed to reinit - free old handle first */
157 	if (do_reinit == SWITCH_TRUE && handle->env != SQL_NULL_HANDLE) {
158 		SQLFreeHandle(SQL_HANDLE_DBC, handle->con);
159 		SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
160 		handle->env = SQL_NULL_HANDLE;
161 	}
162 
163 	if (handle->env == SQL_NULL_HANDLE) {
164 		result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handle->env);
165 
166 		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
167 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHandle\n");
168 			handle->env = SQL_NULL_HANDLE; /* Reset handle value, just in case */
169 			return SWITCH_ODBC_FAIL;
170 		}
171 
172 		result = SQLSetEnvAttr(handle->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
173 
174 		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
175 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error SetEnv\n");
176 			SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
177 			handle->env = SQL_NULL_HANDLE; /* Reset handle value after it's freed */
178 			return SWITCH_ODBC_FAIL;
179 		}
180 
181 		result = SQLAllocHandle(SQL_HANDLE_DBC, handle->env, &handle->con);
182 
183 		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
184 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHDB %d\n", result);
185 			SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
186 			handle->env = SQL_NULL_HANDLE; /* Reset handle value after it's freed */
187 			return SWITCH_ODBC_FAIL;
188 		}
189 		SQLSetConnectAttr(handle->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
190 	}
191 
192 	return SWITCH_ODBC_SUCCESS;
193 }
194 
db_is_up(switch_odbc_handle_t * handle)195 static int db_is_up(switch_odbc_handle_t *handle)
196 {
197 	int ret = 0;
198 	SQLHSTMT stmt = NULL;
199 	SQLLEN m = 0;
200 	int result;
201 	switch_event_t *event;
202 	switch_odbc_status_t recon = 0;
203 	char *err_str = NULL;
204 	SQLCHAR sql[255] = "";
205 	int max_tries = DEFAULT_ODBC_RETRIES;
206 	int code = 0;
207 	SQLRETURN rc;
208 	SQLSMALLINT nresultcols;
209 
210 
211 	if (handle) {
212 		max_tries = handle->num_retries;
213 		if (max_tries < 1)
214 			max_tries = DEFAULT_ODBC_RETRIES;
215 	}
216 
217   top:
218 
219 	if (!handle) {
220 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "No DB Handle\n");
221 		goto done;
222 	}
223 
224 	if (handle->is_oracle) {
225 		strcpy((char *) sql, "select 1 from dual");
226 	} else if (handle->is_firebird) {
227 		strcpy((char *) sql, "select first 1 * from RDB$RELATIONS");
228 	} else {
229 		strcpy((char *) sql, "select 1");
230 	}
231 
232 	if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) {
233 		code = __LINE__;
234 		goto error;
235 	}
236 
237 	SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)30, 0);
238 
239 	if (SQLPrepare(stmt, sql, SQL_NTS) != SQL_SUCCESS) {
240 		code = __LINE__;
241 		goto error;
242 	}
243 
244 	result = SQLExecute(stmt);
245 
246 	if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
247 		code = __LINE__;
248 		goto error;
249 	}
250 
251 	SQLRowCount(stmt, &m);
252 	rc = SQLNumResultCols(stmt, &nresultcols);
253 	if (rc != SQL_SUCCESS) {
254 		code = __LINE__;
255 		goto error;
256 	}
257 	ret = (int) nresultcols;
258 	/* determine statement type */
259 	if (nresultcols <= 0) {
260 		/* statement is not a select statement */
261 		code = __LINE__;
262 		goto error;
263 	}
264 
265 	goto done;
266 
267   error:
268 	err_str = switch_odbc_handle_get_error(handle, stmt);
269 
270 	/* Make sure to free the handle before we try to reconnect */
271 	if (stmt) {
272 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
273 		stmt = NULL;
274 	}
275 
276 	recon = switch_odbc_handle_connect(handle);
277 
278 	max_tries--;
279 
280 	if (switch_event_create(&event, SWITCH_EVENT_TRAP) == SWITCH_STATUS_SUCCESS) {
281 		switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Failure-Message", "The sql server is not responding for DSN %s [%s][%d]",
282 								switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
283 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The sql server is not responding for DSN %s [%s][%d]\n",
284 						  switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
285 
286 		if (recon == SWITCH_ODBC_SUCCESS) {
287 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection has been re-established");
288 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "The connection has been re-established\n");
289 		} else {
290 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection could not be re-established");
291 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The connection could not be re-established\n");
292 		}
293 		if (!max_tries) {
294 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "Giving up!");
295 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Giving up!\n");
296 		}
297 
298 		switch_event_fire(&event);
299 	}
300 
301 	if (!max_tries) {
302 		goto done;
303 	}
304 
305 	switch_safe_free(err_str);
306 	switch_yield(1000000);
307 	goto top;
308 
309   done:
310 
311 	switch_safe_free(err_str);
312 
313 	if (stmt) {
314 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
315 	}
316 
317 	return ret;
318 }
319 #endif
320 
switch_odbc_statement_handle_free(switch_odbc_statement_handle_t * stmt)321 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_statement_handle_free(switch_odbc_statement_handle_t *stmt)
322 {
323 	if (!stmt || !*stmt) {
324 		return SWITCH_ODBC_FAIL;
325 	}
326 #ifdef SWITCH_HAVE_ODBC
327 	SQLFreeHandle(SQL_HANDLE_STMT, *stmt);
328 	*stmt = NULL;
329 	return SWITCH_ODBC_SUCCESS;
330 #else
331 	return SWITCH_ODBC_FAIL;
332 #endif
333 }
334 
335 
switch_odbc_handle_connect(switch_odbc_handle_t * handle)336 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_connect(switch_odbc_handle_t *handle)
337 {
338 #ifdef SWITCH_HAVE_ODBC
339 	int result;
340 	SQLINTEGER err;
341 	int16_t mlen;
342 	unsigned char msg[200] = "", stat[10] = "";
343 	SQLSMALLINT valueLength = 0;
344 	int i = 0;
345 
346 	init_odbc_handles(handle, SWITCH_FALSE); /* Init ODBC handles, if they are already initialized, don't do it again */
347 
348 	if (handle->state == SWITCH_ODBC_STATE_CONNECTED) {
349 		switch_odbc_handle_disconnect(handle);
350 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Re-connecting %s\n", handle->dsn);
351 	}
352 
353 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connecting %s\n", handle->dsn);
354 
355 	if (!strstr(handle->dsn, "DRIVER")) {
356 		result = SQLConnect(handle->con, (SQLCHAR *) handle->dsn, SQL_NTS, (SQLCHAR *) handle->username, SQL_NTS, (SQLCHAR *) handle->password, SQL_NTS);
357 	} else {
358 		SQLCHAR outstr[1024] = { 0 };
359 		SQLSMALLINT outstrlen = 0;
360 		result =
361 			SQLDriverConnect(handle->con, NULL, (SQLCHAR *) handle->dsn, (SQLSMALLINT) strlen(handle->dsn), outstr, sizeof(outstr), &outstrlen,
362 							 SQL_DRIVER_NOPROMPT);
363 	}
364 
365 	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
366 		char *err_str;
367 		if ((err_str = switch_odbc_handle_get_error(handle, NULL))) {
368 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err_str);
369 			free(err_str);
370 		} else {
371 			SQLGetDiagRec(SQL_HANDLE_DBC, handle->con, 1, stat, &err, msg, sizeof(msg), &mlen);
372 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error SQLConnect=%d errno=%d [%s]\n", result, (int) err, msg);
373 		}
374 
375 		/* Deallocate handles again, more chanses to succeed when reconnecting */
376 		init_odbc_handles(handle, SWITCH_TRUE); /* Reinit ODBC handles */
377 		return SWITCH_ODBC_FAIL;
378 	}
379 
380 	result = SQLGetInfo(handle->con, SQL_DRIVER_NAME, (SQLCHAR *) handle->odbc_driver, 255, &valueLength);
381 	if (result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO) {
382 		for (i = 0; i < valueLength; ++i)
383 			handle->odbc_driver[i] = (char) toupper(handle->odbc_driver[i]);
384 	}
385 
386 	if (strstr(handle->odbc_driver, "SQORA32.DLL") != 0 || strstr(handle->odbc_driver, "SQORA64.DLL") != 0) {
387 		handle->is_firebird = FALSE;
388 		handle->is_oracle = TRUE;
389 	} else if (strstr(handle->odbc_driver, "FIREBIRD") != 0 || strstr(handle->odbc_driver, "FB32") != 0 || strstr(handle->odbc_driver, "FB64") != 0) {
390 		handle->is_firebird = TRUE;
391 		handle->is_oracle = FALSE;
392 	} else {
393 		handle->is_firebird = FALSE;
394 		handle->is_oracle = FALSE;
395 	}
396 
397 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connected to [%s]\n", handle->dsn);
398 	handle->state = SWITCH_ODBC_STATE_CONNECTED;
399 	return SWITCH_ODBC_SUCCESS;
400 #else
401 	return SWITCH_ODBC_FAIL;
402 #endif
403 }
404 
switch_odbc_handle_exec_string(switch_odbc_handle_t * handle,const char * sql,char * resbuf,size_t len,char ** err)405 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_exec_string(switch_odbc_handle_t *handle, const char *sql, char *resbuf, size_t len, char **err)
406 {
407 #ifdef SWITCH_HAVE_ODBC
408 	switch_odbc_status_t sstatus = SWITCH_ODBC_FAIL;
409 	switch_odbc_statement_handle_t stmt = NULL;
410 	SQLCHAR name[1024];
411 	SQLLEN m = 0;
412 
413 	handle->affected_rows = 0;
414 
415 	if (switch_odbc_handle_exec(handle, sql, &stmt, err) == SWITCH_ODBC_SUCCESS) {
416 		SQLSMALLINT NameLength, DataType, DecimalDigits, Nullable;
417 		SQLULEN ColumnSize;
418 		int result;
419 
420 		SQLRowCount(stmt, &m);
421 		handle->affected_rows = (int) m;
422 
423 		if (m == 0) {
424 			goto done;
425 		}
426 
427 		result = SQLFetch(stmt);
428 
429 		if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO && result != SQL_NO_DATA) {
430 			goto done;
431 		}
432 
433 		SQLDescribeCol(stmt, 1, name, sizeof(name), &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable);
434 		SQLGetData(stmt, 1, SQL_C_CHAR, (SQLCHAR *) resbuf, (SQLLEN) len, NULL);
435 
436 		sstatus = SWITCH_ODBC_SUCCESS;
437 	}
438 
439 	done:
440 
441 	switch_odbc_statement_handle_free(&stmt);
442 
443 	return sstatus;
444 #else
445 	return SWITCH_ODBC_FAIL;
446 #endif
447 }
448 
switch_odbc_handle_exec(switch_odbc_handle_t * handle,const char * sql,switch_odbc_statement_handle_t * rstmt,char ** err)449 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_exec(switch_odbc_handle_t *handle, const char *sql, switch_odbc_statement_handle_t *rstmt,
450 															 char **err)
451 {
452 #ifdef SWITCH_HAVE_ODBC
453 	SQLHSTMT stmt = NULL;
454 	int result;
455 	char *err_str = NULL, *err2 = NULL;
456 	SQLLEN m = 0;
457 
458 	handle->affected_rows = 0;
459 
460 	if (!db_is_up(handle)) {
461 		goto error;
462 	}
463 
464 	if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) {
465 		err2 = "SQLAllocHandle failed.";
466 		goto error;
467 	}
468 
469 	if (SQLPrepare(stmt, (unsigned char *) sql, SQL_NTS) != SQL_SUCCESS) {
470 		err2 = "SQLPrepare failed.";
471 		goto error;
472 	}
473 
474 	result = SQLExecute(stmt);
475 
476 	switch (result) {
477 	case SQL_SUCCESS:
478 	case SQL_SUCCESS_WITH_INFO:
479 	case SQL_NO_DATA:
480 		break;
481 	case SQL_ERROR:
482 		err2 = "SQLExecute returned SQL_ERROR.";
483 		goto error;
484 		break;
485 	case SQL_NEED_DATA:
486 		err2 = "SQLExecute returned SQL_NEED_DATA.";
487 		goto error;
488 		break;
489 	default:
490 		err2 = "SQLExecute returned unknown result code.";
491 		goto error;
492 	}
493 
494 	SQLRowCount(stmt, &m);
495 	handle->affected_rows = (int) m;
496 
497 	if (rstmt) {
498 		*rstmt = stmt;
499 	} else {
500 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
501 	}
502 
503 	return SWITCH_ODBC_SUCCESS;
504 
505   error:
506 
507 
508 	if (stmt) {
509 		err_str = switch_odbc_handle_get_error(handle, stmt);
510 	}
511 
512 	if (zstr(err_str)) {
513 		if (err2) {
514 			err_str = strdup(err2);
515 		} else {
516 			err_str = strdup((char *)"SQL ERROR!");
517 		}
518 	}
519 
520 	if (err_str) {
521 		if (!switch_stristr("already exists", err_str) && !switch_stristr("duplicate key name", err_str)) {
522 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
523 		}
524 		if (err) {
525 			*err = err_str;
526 		} else {
527 			free(err_str);
528 		}
529 	}
530 
531 	if (rstmt) {
532 		*rstmt = stmt;
533 	} else if (stmt) {
534 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
535 	}
536 #endif
537 	return SWITCH_ODBC_FAIL;
538 }
539 
switch_odbc_handle_callback_exec_detailed(const char * file,const char * func,int line,switch_odbc_handle_t * handle,const char * sql,switch_core_db_callback_func_t callback,void * pdata,char ** err)540 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_handle_callback_exec_detailed(const char *file, const char *func, int line,
541 																			   switch_odbc_handle_t *handle,
542 																			   const char *sql, switch_core_db_callback_func_t callback, void *pdata,
543 																			   char **err)
544 {
545 #ifdef SWITCH_HAVE_ODBC
546 	SQLHSTMT stmt = NULL;
547 	SQLSMALLINT c = 0, x = 0;
548 	SQLLEN m = 0;
549 	char *x_err = NULL, *err_str = NULL;
550 	int result;
551 	int err_cnt = 0;
552 	int done = 0;
553 
554 	handle->affected_rows = 0;
555 
556 	switch_assert(callback != NULL);
557 
558 	if (!db_is_up(handle)) {
559 		x_err = "DB is not up!";
560 		goto error;
561 	}
562 
563 	if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) {
564 		x_err = "Unable to SQL allocate handle!";
565 		goto error;
566 	}
567 
568 	if (SQLPrepare(stmt, (unsigned char *) sql, SQL_NTS) != SQL_SUCCESS) {
569 		x_err = "Unable to prepare SQL statement!";
570 		goto error;
571 	}
572 
573 	result = SQLExecute(stmt);
574 
575 	if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO && result != SQL_NO_DATA) {
576 		x_err = "execute error!";
577 		goto error;
578 	}
579 
580 	SQLNumResultCols(stmt, &c);
581 	SQLRowCount(stmt, &m);
582 	handle->affected_rows = (int) m;
583 
584 
585 	while (!done) {
586 		int name_len = 256;
587 		char **names;
588 		char **vals;
589 		int y = 0;
590 
591 		result = SQLFetch(stmt);
592 
593 		if (result != SQL_SUCCESS) {
594 			if (result != SQL_NO_DATA) {
595 				err_cnt++;
596 			}
597 			break;
598 		}
599 
600 		names = calloc(c, sizeof(*names));
601 		vals = calloc(c, sizeof(*vals));
602 
603 		switch_assert(names && vals);
604 
605 		for (x = 1; x <= c; x++) {
606 			SQLSMALLINT NameLength = 0, DataType = 0, DecimalDigits = 0, Nullable = 0;
607 			SQLULEN ColumnSize = 0;
608 			names[y] = malloc(name_len);
609 			switch_assert(names[y]);
610 			memset(names[y], 0, name_len);
611 
612 			SQLDescribeCol(stmt, x, (SQLCHAR *) names[y], (SQLSMALLINT) name_len, &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable);
613 
614 			if (!ColumnSize) {
615 				SQLCHAR val[16384] = { 0 };
616 				ColumnSize = 16384;
617 				SQLGetData(stmt, x, SQL_C_CHAR, val, ColumnSize, NULL);
618 				vals[y] = strdup((char *)val);
619 			} else {
620 				ColumnSize++;
621 
622 				vals[y] = malloc(ColumnSize);
623 				switch_assert(vals[y]);
624 				memset(vals[y], 0, ColumnSize);
625 				SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *) vals[y], ColumnSize, NULL);
626 			}
627 			y++;
628 		}
629 
630 		if (callback(pdata, y, vals, names)) {
631 			done = 1;
632 		}
633 
634 		for (x = 0; x < y; x++) {
635 			free(names[x]);
636 			free(vals[x]);
637 		}
638 		free(names);
639 		free(vals);
640 	}
641 
642 	SQLFreeHandle(SQL_HANDLE_STMT, stmt);
643 	stmt = NULL; /* Make sure we don't try to free this handle again */
644 
645 	if (!err_cnt) {
646 		return SWITCH_ODBC_SUCCESS;
647 	}
648 
649   error:
650 
651 	if (stmt) {
652 		err_str = switch_odbc_handle_get_error(handle, stmt);
653 	}
654 
655 	if (zstr(err_str) && !zstr(x_err)) {
656 		err_str = strdup(x_err);
657 	}
658 
659 	if (err_str) {
660 		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
661 		if (err) {
662 			*err = err_str;
663 		} else {
664 			free(err_str);
665 		}
666 	}
667 
668 	if (stmt) {
669 		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
670 	}
671 
672 
673 #endif
674 	return SWITCH_ODBC_FAIL;
675 }
676 
switch_odbc_handle_destroy(switch_odbc_handle_t ** handlep)677 SWITCH_DECLARE(void) switch_odbc_handle_destroy(switch_odbc_handle_t **handlep)
678 {
679 #ifdef SWITCH_HAVE_ODBC
680 
681 	switch_odbc_handle_t *handle = NULL;
682 
683 	if (!handlep) {
684 		return;
685 	}
686 	handle = *handlep;
687 
688 	if (handle) {
689 		switch_odbc_handle_disconnect(handle);
690 
691 		if (handle->env != SQL_NULL_HANDLE) {
692 			SQLFreeHandle(SQL_HANDLE_DBC, handle->con);
693 			SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
694 		}
695 		switch_safe_free(handle->dsn);
696 		switch_safe_free(handle->username);
697 		switch_safe_free(handle->password);
698 		free(handle);
699 	}
700 	*handlep = NULL;
701 #else
702 	return;
703 #endif
704 }
705 
switch_odbc_handle_get_state(switch_odbc_handle_t * handle)706 SWITCH_DECLARE(switch_odbc_state_t) switch_odbc_handle_get_state(switch_odbc_handle_t *handle)
707 {
708 #ifdef SWITCH_HAVE_ODBC
709 	return handle ? handle->state : SWITCH_ODBC_STATE_INIT;
710 #else
711 	return SWITCH_ODBC_STATE_ERROR;
712 #endif
713 }
714 
switch_odbc_handle_get_error(switch_odbc_handle_t * handle,switch_odbc_statement_handle_t stmt)715 SWITCH_DECLARE(char *) switch_odbc_handle_get_error(switch_odbc_handle_t *handle, switch_odbc_statement_handle_t stmt)
716 {
717 #ifdef SWITCH_HAVE_ODBC
718 
719 	char buffer[SQL_MAX_MESSAGE_LENGTH + 1] = "";
720 	char sqlstate[SQL_SQLSTATE_SIZE + 1] = "";
721 	SQLINTEGER sqlcode;
722 	SQLSMALLINT length;
723 	char *ret = NULL;
724 
725 	if (SQLError(handle->env, handle->con, stmt, (SQLCHAR *) sqlstate, &sqlcode, (SQLCHAR *) buffer, sizeof(buffer), &length) == SQL_SUCCESS) {
726 		ret = switch_mprintf("STATE: %s CODE %ld ERROR: %s\n", sqlstate, sqlcode, buffer);
727 	};
728 
729 	return ret;
730 #else
731 	return NULL;
732 #endif
733 }
734 
switch_odbc_handle_affected_rows(switch_odbc_handle_t * handle)735 SWITCH_DECLARE(int) switch_odbc_handle_affected_rows(switch_odbc_handle_t *handle)
736 {
737 #ifdef SWITCH_HAVE_ODBC
738 	return handle->affected_rows;
739 #else
740 	return 0;
741 #endif
742 }
743 
switch_odbc_available(void)744 SWITCH_DECLARE(switch_bool_t) switch_odbc_available(void)
745 {
746 #ifdef SWITCH_HAVE_ODBC
747 	return SWITCH_TRUE;
748 #else
749 	return SWITCH_FALSE;
750 #endif
751 }
752 
switch_odbc_SQLSetAutoCommitAttr(switch_odbc_handle_t * handle,switch_bool_t on)753 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_SQLSetAutoCommitAttr(switch_odbc_handle_t *handle, switch_bool_t on)
754 {
755 #ifdef SWITCH_HAVE_ODBC
756 	if (on) {
757 		return SQLSetConnectAttr(handle->con, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER *) SQL_AUTOCOMMIT_ON, 0 );
758 	} else {
759 		return SQLSetConnectAttr(handle->con, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER *) SQL_AUTOCOMMIT_OFF, 0 );
760 	}
761 #else
762 	return (switch_odbc_status_t) SWITCH_FALSE;
763 #endif
764 }
765 
switch_odbc_SQLEndTran(switch_odbc_handle_t * handle,switch_bool_t commit)766 SWITCH_DECLARE(switch_odbc_status_t) switch_odbc_SQLEndTran(switch_odbc_handle_t *handle, switch_bool_t commit)
767 {
768 #ifdef SWITCH_HAVE_ODBC
769 	if (commit) {
770 		return SQLEndTran(SQL_HANDLE_DBC, handle->con, SQL_COMMIT);
771 	} else {
772 		return SQLEndTran(SQL_HANDLE_DBC, handle->con, SQL_ROLLBACK);
773 	}
774 #else
775 	return (switch_odbc_status_t) SWITCH_FALSE;
776 #endif
777 }
778 
779 
780 /* For Emacs:
781  * Local Variables:
782  * mode:c
783  * indent-tabs-mode:t
784  * tab-width:4
785  * c-basic-offset:4
786  * End:
787  * For VIM:
788  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
789  */
790