RTS API Documentation  1.10.11
switch_odbc.c
Go to the documentation of this file.
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;
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 
66 
68 {
70 }
71 
72 SWITCH_DECLARE(switch_odbc_handle_t *) switch_odbc_handle_new(const char *dsn, const char *username, const char *password)
73 {
74 #ifdef SWITCH_HAVE_ODBC
75  switch_odbc_handle_t *new_handle;
76 
77  if (!(new_handle = malloc(sizeof(*new_handle)))) {
78  goto err;
79  }
80 
81  memset(new_handle, 0, sizeof(*new_handle));
82 
83  if (!(new_handle->dsn = strdup(dsn))) {
84  goto err;
85  }
86 
87  if (username) {
88  if (!(new_handle->username = strdup(username))) {
89  goto err;
90  }
91  }
92 
93  if (password) {
94  if (!(new_handle->password = strdup(password))) {
95  goto err;
96  }
97  }
98 
99  new_handle->env = SQL_NULL_HANDLE;
100  new_handle->state = SWITCH_ODBC_STATE_INIT;
101  new_handle->affected_rows = 0;
102  new_handle->num_retries = DEFAULT_ODBC_RETRIES;
103 
104  return new_handle;
105 
106  err:
107  if (new_handle) {
108  switch_safe_free(new_handle->dsn);
109  switch_safe_free(new_handle->username);
110  switch_safe_free(new_handle->password);
111  switch_safe_free(new_handle);
112  }
113 #endif
114  return NULL;
115 }
116 
118 {
119 #ifdef SWITCH_HAVE_ODBC
120  if (handle) {
121  handle->num_retries = num_retries;
122  }
123 #endif
124 }
125 
127 {
128 #ifdef SWITCH_HAVE_ODBC
129 
130  int result;
131 
132  if (!handle) {
133  return SWITCH_ODBC_FAIL;
134  }
135 
136  if (handle->state == SWITCH_ODBC_STATE_CONNECTED) {
137  result = SQLDisconnect(handle->con);
138  if (result == SWITCH_ODBC_SUCCESS) {
139  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "Disconnected %d from [%s]\n", result, handle->dsn);
140  } else {
141  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Disconnecting [%s]\n", handle->dsn);
142  }
143  }
144 
145  handle->state = SWITCH_ODBC_STATE_DOWN;
146 
147  return SWITCH_ODBC_SUCCESS;
148 #else
149  return SWITCH_ODBC_FAIL;
150 #endif
151 }
152 
153 
154 #ifdef SWITCH_HAVE_ODBC
155 static switch_odbc_status_t init_odbc_handles(switch_odbc_handle_t *handle, switch_bool_t do_reinit)
156 {
157  int result;
158 
159  if (!handle) {
160  return SWITCH_ODBC_FAIL;
161  }
162 
163  /* if handle is already initialized, and we're supposed to reinit - free old handle first */
164  if (do_reinit == SWITCH_TRUE && handle->env != SQL_NULL_HANDLE) {
165  SQLFreeHandle(SQL_HANDLE_DBC, handle->con);
166  SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
167  handle->env = SQL_NULL_HANDLE;
168  }
169 
170  if (handle->env == SQL_NULL_HANDLE) {
171  result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handle->env);
172 
173  if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
174  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHandle\n");
175  handle->env = SQL_NULL_HANDLE; /* Reset handle value, just in case */
176  return SWITCH_ODBC_FAIL;
177  }
178 
179  result = SQLSetEnvAttr(handle->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
180 
181  if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
183  SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
184  handle->env = SQL_NULL_HANDLE; /* Reset handle value after it's freed */
185  return SWITCH_ODBC_FAIL;
186  }
187 
188  result = SQLAllocHandle(SQL_HANDLE_DBC, handle->env, &handle->con);
189 
190  if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
191  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error AllocHDB %d\n", result);
192  SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
193  handle->env = SQL_NULL_HANDLE; /* Reset handle value after it's freed */
194  return SWITCH_ODBC_FAIL;
195  }
196  SQLSetConnectAttr(handle->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0);
197  }
198 
199  return SWITCH_ODBC_SUCCESS;
200 }
201 
202 static int db_is_up(switch_odbc_handle_t *handle)
203 {
204  int ret = 0;
205  SQLHSTMT stmt = NULL;
206  SQLLEN m = 0;
207  int result;
208  switch_event_t *event;
209  switch_odbc_status_t recon = 0;
210  char *err_str = NULL;
211  SQLCHAR sql[255] = "";
212  int max_tries = DEFAULT_ODBC_RETRIES;
213  int code = 0;
214  SQLRETURN rc;
215  SQLSMALLINT nresultcols;
216 
217 
218  if (handle) {
219  max_tries = handle->num_retries;
220  if (max_tries < 1)
221  max_tries = DEFAULT_ODBC_RETRIES;
222  }
223 
224  top:
225 
226  if (!handle) {
228  goto done;
229  }
230 
231  if (handle->is_oracle) {
232  strcpy((char *) sql, "select 1 from dual");
233  } else if (handle->is_firebird) {
234  strcpy((char *) sql, "select first 1 * from RDB$RELATIONS");
235  } else {
236  strcpy((char *) sql, "select 1");
237  }
238 
239  if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) {
240  code = __LINE__;
241  goto error;
242  }
243 
244  SQLSetStmtAttr(stmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)30, 0);
245 
246  if (SQLPrepare(stmt, sql, SQL_NTS) != SQL_SUCCESS) {
247  code = __LINE__;
248  goto error;
249  }
250 
251  result = SQLExecute(stmt);
252 
253  if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) {
254  code = __LINE__;
255  goto error;
256  }
257 
258  SQLRowCount(stmt, &m);
259  rc = SQLNumResultCols(stmt, &nresultcols);
260  if (rc != SQL_SUCCESS) {
261  code = __LINE__;
262  goto error;
263  }
264  ret = (int) nresultcols;
265  /* determine statement type */
266  if (nresultcols <= 0) {
267  /* statement is not a select statement */
268  code = __LINE__;
269  goto error;
270  }
271 
272  goto done;
273 
274  error:
275  err_str = switch_odbc_handle_get_error(handle, stmt);
276 
277  /* Make sure to free the handle before we try to reconnect */
278  if (stmt) {
279  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
280  stmt = NULL;
281  }
282 
283  recon = switch_odbc_handle_connect(handle);
284 
285  max_tries--;
286 
288  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Failure-Message", "The sql server is not responding for DSN %s [%s][%d]",
289  switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
290  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The sql server is not responding for DSN %s [%s][%d]\n",
291  switch_str_nil(handle->dsn), switch_str_nil(err_str), code);
292 
293  if (recon == SWITCH_ODBC_SUCCESS) {
294  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection has been re-established");
295  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "The connection has been re-established\n");
296  } else {
297  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "The connection could not be re-established");
298  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "The connection could not be re-established\n");
299  }
300  if (!max_tries) {
301  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Additional-Info", "Giving up!");
303  }
304 
305  switch_event_fire(&event);
306  }
307 
308  if (!max_tries) {
309  goto done;
310  }
311 
312  switch_safe_free(err_str);
313  switch_yield(1000000);
314  goto top;
315 
316  done:
317 
318  switch_safe_free(err_str);
319 
320  if (stmt) {
321  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
322  }
323 
324  return ret;
325 }
326 #endif
327 
329 {
330  if (!stmt || !*stmt) {
331  return SWITCH_ODBC_FAIL;
332  }
333 #ifdef SWITCH_HAVE_ODBC
334  SQLFreeHandle(SQL_HANDLE_STMT, *stmt);
335  *stmt = NULL;
336  return SWITCH_ODBC_SUCCESS;
337 #else
338  return SWITCH_ODBC_FAIL;
339 #endif
340 }
341 
342 
344 {
345 #ifdef SWITCH_HAVE_ODBC
346  int result;
347  SQLINTEGER err;
348  int16_t mlen;
349  unsigned char msg[200] = "", stat[10] = "";
350  SQLSMALLINT valueLength = 0;
351  int i = 0;
352 
353  init_odbc_handles(handle, SWITCH_FALSE); /* Init ODBC handles, if they are already initialized, don't do it again */
354 
355  if (handle->state == SWITCH_ODBC_STATE_CONNECTED) {
357  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Re-connecting %s\n", handle->dsn);
358  }
359 
360  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connecting %s\n", handle->dsn);
361 
362  if (!strstr(handle->dsn, "DRIVER")) {
363  result = SQLConnect(handle->con, (SQLCHAR *) handle->dsn, SQL_NTS, (SQLCHAR *) handle->username, SQL_NTS, (SQLCHAR *) handle->password, SQL_NTS);
364  } else {
365  SQLCHAR outstr[1024] = { 0 };
366  SQLSMALLINT outstrlen = 0;
367  result =
368  SQLDriverConnect(handle->con, NULL, (SQLCHAR *) handle->dsn, (SQLSMALLINT) strlen(handle->dsn), outstr, sizeof(outstr), &outstrlen,
369  SQL_DRIVER_NOPROMPT);
370  }
371 
372  if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
373  char *err_str;
374  if ((err_str = switch_odbc_handle_get_error(handle, NULL))) {
376  free(err_str);
377  } else {
378  SQLGetDiagRec(SQL_HANDLE_DBC, handle->con, 1, stat, &err, msg, sizeof(msg), &mlen);
379  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error SQLConnect=%d errno=%d [%s]\n", result, (int) err, msg);
380  }
381 
382  /* Deallocate handles again, more chanses to succeed when reconnecting */
383  init_odbc_handles(handle, SWITCH_TRUE); /* Reinit ODBC handles */
384  return SWITCH_ODBC_FAIL;
385  }
386 
387  result = SQLGetInfo(handle->con, SQL_DRIVER_NAME, (SQLCHAR *) handle->odbc_driver, 255, &valueLength);
388  if (result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO) {
389  for (i = 0; i < valueLength; ++i)
390  handle->odbc_driver[i] = (char) toupper(handle->odbc_driver[i]);
391  }
392 
393  if (strstr(handle->odbc_driver, "SQORA32.DLL") != 0 || strstr(handle->odbc_driver, "SQORA64.DLL") != 0) {
394  handle->is_firebird = FALSE;
395  handle->is_oracle = TRUE;
396  } else if (strstr(handle->odbc_driver, "FIREBIRD") != 0 || strstr(handle->odbc_driver, "FB32") != 0 || strstr(handle->odbc_driver, "FB64") != 0) {
397  handle->is_firebird = TRUE;
398  handle->is_oracle = FALSE;
399  } else {
400  handle->is_firebird = FALSE;
401  handle->is_oracle = FALSE;
402  }
403 
404  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Connected to [%s]\n", handle->dsn);
405  handle->state = SWITCH_ODBC_STATE_CONNECTED;
406  return SWITCH_ODBC_SUCCESS;
407 #else
408  return SWITCH_ODBC_FAIL;
409 #endif
410 }
411 
412 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)
413 {
414 #ifdef SWITCH_HAVE_ODBC
416  switch_odbc_statement_handle_t stmt = NULL;
417  SQLCHAR name[1024];
418  SQLLEN m = 0;
419 
420  handle->affected_rows = 0;
421 
422  if (switch_odbc_handle_exec(handle, sql, &stmt, err) == SWITCH_ODBC_SUCCESS) {
423  SQLSMALLINT NameLength, DataType, DecimalDigits, Nullable;
424  SQLULEN ColumnSize;
425  int result;
426 
427  SQLRowCount(stmt, &m);
428  handle->affected_rows = (int) m;
429 
430  if (m == 0) {
431  goto done;
432  }
433 
434  result = SQLFetch(stmt);
435 
436  if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO && result != SQL_NO_DATA) {
437  goto done;
438  }
439 
440  SQLDescribeCol(stmt, 1, name, sizeof(name), &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable);
441  SQLGetData(stmt, 1, SQL_C_CHAR, (SQLCHAR *) resbuf, (SQLLEN) len, NULL);
442 
443  sstatus = SWITCH_ODBC_SUCCESS;
444  }
445 
446  done:
447 
449 
450  return sstatus;
451 #else
452  return SWITCH_ODBC_FAIL;
453 #endif
454 }
455 
457  char **err)
458 {
459 #ifdef SWITCH_HAVE_ODBC
460  SQLHSTMT stmt = NULL;
461  int result;
462  char *err_str = NULL, *err2 = NULL;
463  SQLLEN m = 0;
464 
465  handle->affected_rows = 0;
466 
467  if (!db_is_up(handle)) {
468  goto error;
469  }
470 
471  if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) {
472  err2 = "SQLAllocHandle failed.";
473  goto error;
474  }
475 
476  if (SQLPrepare(stmt, (unsigned char *) sql, SQL_NTS) != SQL_SUCCESS) {
477  err2 = "SQLPrepare failed.";
478  goto error;
479  }
480 
481  result = SQLExecute(stmt);
482 
483  switch (result) {
484  case SQL_SUCCESS:
485  case SQL_SUCCESS_WITH_INFO:
486  case SQL_NO_DATA:
487  break;
488  case SQL_ERROR:
489  err2 = "SQLExecute returned SQL_ERROR.";
490  goto error;
491  break;
492  case SQL_NEED_DATA:
493  err2 = "SQLExecute returned SQL_NEED_DATA.";
494  goto error;
495  break;
496  default:
497  err2 = "SQLExecute returned unknown result code.";
498  goto error;
499  }
500 
501  SQLRowCount(stmt, &m);
502  handle->affected_rows = (int) m;
503 
504  if (rstmt) {
505  *rstmt = stmt;
506  } else {
507  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
508  }
509 
510  return SWITCH_ODBC_SUCCESS;
511 
512  error:
513 
514 
515  if (stmt) {
516  err_str = switch_odbc_handle_get_error(handle, stmt);
517  }
518 
519  if (zstr(err_str)) {
520  if (err2) {
521  err_str = strdup(err2);
522  } else {
523  err_str = strdup((char *)"SQL ERROR!");
524  }
525  }
526 
527  if (err_str) {
528  if (!switch_stristr("already exists", err_str) && !switch_stristr("duplicate key name", err_str)) {
529  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERR: [%s]\n[%s]\n", sql, switch_str_nil(err_str));
530  }
531  if (err) {
532  *err = err_str;
533  } else {
534  free(err_str);
535  }
536  }
537 
538  if (rstmt) {
539  *rstmt = stmt;
540  } else if (stmt) {
541  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
542  }
543 #endif
544  return SWITCH_ODBC_FAIL;
545 }
546 
548  switch_odbc_handle_t *handle,
549  const char *sql, switch_core_db_callback_func_t callback, void *pdata,
550  char **err)
551 {
552 #ifdef SWITCH_HAVE_ODBC
553  SQLHSTMT stmt = NULL;
554  SQLSMALLINT c = 0, x = 0;
555  SQLLEN m = 0;
556  char *x_err = NULL, *err_str = NULL;
557  int result;
558  int err_cnt = 0;
559  int done = 0;
560 
561  handle->affected_rows = 0;
562 
563  switch_assert(callback != NULL);
564 
565  if (!db_is_up(handle)) {
566  x_err = "DB is not up!";
567  goto error;
568  }
569 
570  if (SQLAllocHandle(SQL_HANDLE_STMT, handle->con, &stmt) != SQL_SUCCESS) {
571  x_err = "Unable to SQL allocate handle!";
572  goto error;
573  }
574 
575  if (SQLPrepare(stmt, (unsigned char *) sql, SQL_NTS) != SQL_SUCCESS) {
576  x_err = "Unable to prepare SQL statement!";
577  goto error;
578  }
579 
580  result = SQLExecute(stmt);
581 
582  if (result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO && result != SQL_NO_DATA) {
583  x_err = "execute error!";
584  goto error;
585  }
586 
587  SQLNumResultCols(stmt, &c);
588  SQLRowCount(stmt, &m);
589  handle->affected_rows = (int) m;
590 
591 
592  while (!done) {
593  int name_len = 256;
594  char **names;
595  char **vals;
596  int y = 0;
597 
598  result = SQLFetch(stmt);
599 
600  if (result != SQL_SUCCESS) {
601  if (result != SQL_NO_DATA) {
602  err_cnt++;
603  }
604  break;
605  }
606 
607  names = calloc(c, sizeof(*names));
608  vals = calloc(c, sizeof(*vals));
609 
610  switch_assert(names && vals);
611 
612  for (x = 1; x <= c; x++) {
613  SQLSMALLINT NameLength = 0, DataType = 0, DecimalDigits = 0, Nullable = 0;
614  SQLULEN ColumnSize = 0;
615  SQLLEN numRecs = 0;
616  SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
617  SQLINTEGER NativeError;
618  SQLSMALLINT diagCount, MsgLen;
619  names[y] = malloc(name_len);
620  switch_assert(names[y]);
621  memset(names[y], 0, name_len);
622 
623  SQLDescribeCol(stmt, x, (SQLCHAR *) names[y], (SQLSMALLINT) name_len, &NameLength, &DataType, &ColumnSize, &DecimalDigits, &Nullable);
624 
625  if (ColumnSize <= 16383 || ColumnSize == 2147483647) {
626  SQLCHAR val[16384] = { 0 };
627  SQLLEN StrLen_or_IndPtr;
628  SQLRETURN rc;
629  ColumnSize = 16384;
630 
631  /* check diag record and see if we can get real size
632  * https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/using-sqlgetdiagrec-and-sqlgetdiagfield?view=sql-server-ver15
633  * szSqlState = "01004" and StrLen_or_IndPtr=15794
634  */
635  rc = SQLGetData(stmt, x, SQL_C_CHAR, val, ColumnSize, &StrLen_or_IndPtr);
636 
637  if (rc == SQL_SUCCESS_WITH_INFO) {
638  int truncated = 0;
639  diagCount = 1;
640 
641  SQLGetDiagField(SQL_HANDLE_STMT, stmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
642 
643  while (diagCount <= numRecs) {
644  SQLGetDiagRec(SQL_HANDLE_STMT, stmt, diagCount, SqlState, &NativeError,Msg, sizeof(Msg), &MsgLen);
645  if (!strcmp((char*)SqlState,"01004")){
646  truncated = 1;
647  break;
648  }
649 
650  diagCount++;
651  }
652 
653  if (truncated) {
654  if (StrLen_or_IndPtr && StrLen_or_IndPtr <= 268435456) {
655  int ValLen = strlen((char*)val);
656  ColumnSize = StrLen_or_IndPtr + 1;
657  vals[y] = malloc(ColumnSize);
658  switch_assert(vals[y]);
659  memset(vals[y], 0, ColumnSize);
660  strcpy(vals[y], (char*)val);
661  rc = SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *)vals[y] + ValLen, ColumnSize - ValLen, NULL);
662  if (rc != SQL_SUCCESS
663 #if (ODBCVER >= 0x0300)
664  && rc != SQL_NO_DATA
665 #endif
666  ) {
667  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData was truncated and failed to complete.\n");
668  switch_safe_free(vals[y]);
669  }
670  } else {
671  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql data truncated - %s\n",SqlState);
672  vals[y] = NULL;
673  }
674  } else {
675  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed\n");
676  vals[y] = NULL;
677  }
678  } else if (rc == SQL_SUCCESS){
679  vals[y] = strdup((char *)val);
680  } else {
681  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQLGetData failed\n");
682  vals[y] = NULL;
683  }
684  } else {
685  ColumnSize++;
686 
687  vals[y] = malloc(ColumnSize);
688  switch_assert(vals[y]);
689  memset(vals[y], 0, ColumnSize);
690  SQLGetData(stmt, x, SQL_C_CHAR, (SQLCHAR *) vals[y], ColumnSize, NULL);
691  }
692  y++;
693  }
694 
695  if (callback(pdata, y, vals, names)) {
696  done = 1;
697  }
698 
699  for (x = 0; x < y; x++) {
700  free(names[x]);
701  switch_safe_free(vals[x]);
702  }
703  free(names);
704  free(vals);
705  }
706 
707  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
708  stmt = NULL; /* Make sure we don't try to free this handle again */
709 
710  if (!err_cnt) {
711  return SWITCH_ODBC_SUCCESS;
712  }
713 
714  error:
715 
716  if (stmt) {
717  err_str = switch_odbc_handle_get_error(handle, stmt);
718  }
719 
720  if (zstr(err_str) && !zstr(x_err)) {
721  err_str = strdup(x_err);
722  }
723 
724  if (err_str) {
725  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));
726  if (err) {
727  *err = err_str;
728  } else {
729  free(err_str);
730  }
731  }
732 
733  if (stmt) {
734  SQLFreeHandle(SQL_HANDLE_STMT, stmt);
735  }
736 
737 
738 #endif
739  return SWITCH_ODBC_FAIL;
740 }
741 
743 {
744 #ifdef SWITCH_HAVE_ODBC
745 
746  switch_odbc_handle_t *handle = NULL;
747 
748  if (!handlep) {
749  return;
750  }
751  handle = *handlep;
752 
753  if (handle) {
755 
756  if (handle->env != SQL_NULL_HANDLE) {
757  SQLFreeHandle(SQL_HANDLE_DBC, handle->con);
758  SQLFreeHandle(SQL_HANDLE_ENV, handle->env);
759  }
760  switch_safe_free(handle->dsn);
761  switch_safe_free(handle->username);
762  switch_safe_free(handle->password);
763  free(handle);
764  }
765  *handlep = NULL;
766 #else
767  return;
768 #endif
769 }
770 
772 {
773 #ifdef SWITCH_HAVE_ODBC
774  return handle ? handle->state : SWITCH_ODBC_STATE_INIT;
775 #else
777 #endif
778 }
779 
781 {
782 #ifdef SWITCH_HAVE_ODBC
783 
784  char buffer[SQL_MAX_MESSAGE_LENGTH + 1] = "";
785  char sqlstate[SQL_SQLSTATE_SIZE + 1] = "";
786  SQLINTEGER sqlcode;
787  SQLSMALLINT length;
788  char *ret = NULL;
789 
790  if (SQLError(handle->env, handle->con, stmt, (SQLCHAR *) sqlstate, &sqlcode, (SQLCHAR *) buffer, sizeof(buffer), &length) == SQL_SUCCESS) {
791  ret = switch_mprintf("STATE: %s CODE %ld ERROR: %s\n", sqlstate, sqlcode, buffer);
792  };
793 
794  return ret;
795 #else
796  return NULL;
797 #endif
798 }
799 
801 {
802 #ifdef SWITCH_HAVE_ODBC
803  return handle->affected_rows;
804 #else
805  return 0;
806 #endif
807 }
808 
810 {
811 #ifdef SWITCH_HAVE_ODBC
812  return SWITCH_TRUE;
813 #else
814  return SWITCH_FALSE;
815 #endif
816 }
817 
819 {
820 #ifdef SWITCH_HAVE_ODBC
821  if (skip_autocommit_flip) {
822  return SWITCH_ODBC_SUCCESS;
823  }
824 
825  if (on) {
826  return SQLSetConnectAttr(handle->con, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER *) SQL_AUTOCOMMIT_ON, 0 );
827  } else {
828  return SQLSetConnectAttr(handle->con, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER *) SQL_AUTOCOMMIT_OFF, 0 );
829  }
830 #else
832 #endif
833 }
834 
836 {
837 #ifdef SWITCH_HAVE_ODBC
838  if (commit) {
839  return SQLEndTran(SQL_HANDLE_DBC, handle->con, SQL_COMMIT);
840  } else {
841  return SQLEndTran(SQL_HANDLE_DBC, handle->con, SQL_ROLLBACK);
842  }
843 #else
845 #endif
846 }
847 
848 
849 /* For Emacs:
850  * Local Variables:
851  * mode:c
852  * indent-tabs-mode:t
853  * tab-width:4
854  * c-basic-offset:4
855  * End:
856  * For VIM:
857  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
858  */
#define switch_event_fire(event)
Fire an event filling in most of the arguements with obvious values.
Definition: switch_event.h:413
switch_odbc_status_t switch_odbc_handle_disconnect(switch_odbc_handle_t *handle)
Definition: switch_odbc.c:126
switch_odbc_handle_t * switch_odbc_handle_new(const char *dsn, const char *username, const char *password)
Definition: switch_odbc.c:72
switch_odbc_status_t
Definition: switch_odbc.h:49
switch_odbc_state_t
Definition: switch_odbc.h:42
#define SWITCH_CHANNEL_LOG
void switch_odbc_set_num_retries(switch_odbc_handle_t *handle, int num_retries)
Definition: switch_odbc.c:117
struct switch_odbc_handle switch_odbc_handle_t
switch_odbc_status_t switch_odbc_SQLSetAutoCommitAttr(switch_odbc_handle_t *handle, switch_bool_t on)
Definition: switch_odbc.c:818
switch_odbc_status_t switch_odbc_handle_exec_string(switch_odbc_handle_t *handle, const char *sql, char *resbuf, size_t len, char **err)
Definition: switch_odbc.c:412
int switch_odbc_handle_affected_rows(switch_odbc_handle_t *handle)
Definition: switch_odbc.c:800
switch_bool_t
Definition: switch_types.h:437
switch_odbc_status_t switch_odbc_handle_exec(switch_odbc_handle_t *handle, const char *sql, switch_odbc_statement_handle_t *rstmt, char **err)
Definition: switch_odbc.c:456
switch_status_t switch_event_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *fmt,...) PRINTF_FUNCTION(4
Add a header to an event.
Representation of an event.
Definition: switch_event.h:80
void switch_odbc_handle_destroy(switch_odbc_handle_t **handlep)
Definition: switch_odbc.c:742
switch_bool_t switch_odbc_available(void)
Definition: switch_odbc.c:809
#define zstr(x)
Definition: switch_utils.h:314
Definition: cJSON.c:68
#define switch_yield(ms)
Wait a desired number of microseconds and yield the CPU.
Definition: switch_utils.h:998
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:885
char const int length
Definition: switch_cJSON.h:153
int(* switch_core_db_callback_func_t)(void *pArg, int argc, char **argv, char **columnNames)
#define DEFAULT_ODBC_RETRIES
Definition: switch_odbc.h:37
uint8_t skip_autocommit_flip
Definition: switch_odbc.c:65
#define switch_str_nil(s)
Make a null string a blank string instead.
Definition: switch_utils.h:993
switch_odbc_status_t switch_odbc_SQLEndTran(switch_odbc_handle_t *handle, switch_bool_t commit)
Definition: switch_odbc.c:835
switch_odbc_status_t 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)
Execute the sql query and issue a callback for each row returned.
Definition: switch_odbc.c:547
#define FALSE
Main Library Header.
#define switch_event_create(event, id)
Create a new event assuming it will not be custom event and therefore hiding the unused parameters...
Definition: switch_event.h:384
#define SWITCH_DECLARE(type)
void switch_odbc_skip_autocommit_flip(void)
Definition: switch_odbc.c:67
char * buffer
Definition: switch_cJSON.h:153
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
const char * switch_stristr(const char *instr, const char *str)
void * switch_odbc_statement_handle_t
Definition: switch_odbc.h:39
const char *const name
Definition: switch_cJSON.h:250
#define TRUE
switch_odbc_status_t switch_odbc_handle_connect(switch_odbc_handle_t *handle)
Definition: switch_odbc.c:343
switch_odbc_state_t switch_odbc_handle_get_state(switch_odbc_handle_t *handle)
Definition: switch_odbc.c:771
#define switch_assert(expr)
SWITCH_BEGIN_EXTERN_C char * switch_mprintf(const char *zFormat,...)
char * switch_odbc_handle_get_error(switch_odbc_handle_t *handle, switch_odbc_statement_handle_t stmt)
Definition: switch_odbc.c:780
memset(buf, 0, buflen)
switch_odbc_status_t switch_odbc_statement_handle_free(switch_odbc_statement_handle_t *stmt)
Definition: switch_odbc.c:328