43 #include "asterisk/file.h"
158 .
type =
"ODBC_Transaction",
173 unsigned int active:1;
179 #define DATA_EXPORT_ODBC_CLASS(MEMBER) \
180 MEMBER(odbc_class, name, AST_DATA_STRING) \
181 MEMBER(odbc_class, dsn, AST_DATA_STRING) \
182 MEMBER(odbc_class, username, AST_DATA_STRING) \
183 MEMBER(odbc_class, password, AST_DATA_PASSWORD) \
184 MEMBER(odbc_class, limit, AST_DATA_INTEGER) \
185 MEMBER(odbc_class, count, AST_DATA_INTEGER) \
186 MEMBER(odbc_class, forcecommit, AST_DATA_BOOLEAN)
192 if (iso == SQL_TXN_READ_COMMITTED) {
193 return "read_committed";
194 }
else if (iso == SQL_TXN_READ_UNCOMMITTED) {
195 return "read_uncommitted";
196 }
else if (iso == SQL_TXN_SERIALIZABLE) {
197 return "serializable";
198 }
else if (iso == SQL_TXN_REPEATABLE_READ) {
199 return "repeatable_read";
207 if (strncasecmp(txt,
"read_", 5) == 0) {
208 if (strncasecmp(txt + 5,
"c", 1) == 0) {
209 return SQL_TXN_READ_COMMITTED;
210 }
else if (strncasecmp(txt + 5,
"u", 1) == 0) {
211 return SQL_TXN_READ_UNCOMMITTED;
215 }
else if (strncasecmp(txt,
"ser", 3) == 0) {
216 return SQL_TXN_SERIALIZABLE;
217 }
else if (strncasecmp(txt,
"rep", 3) == 0) {
218 return SQL_TXN_REPEATABLE_READ;
239 oldlist = txn_store->
data;
243 ast_log(
LOG_ERROR,
"Unable to allocate a new datastore. Cannot create a new transaction.\n");
248 if (!(oldlist =
ast_calloc(1,
sizeof(*oldlist)))) {
249 ast_log(
LOG_ERROR,
"Unable to allocate datastore list head. Cannot create a new transaction.\n");
255 txn_store->
data = oldlist;
264 if (obj != NULL || active == 1) {
275 if (!strcasecmp(txn->
name, name)) {
283 if (name && obj && (txn =
ast_calloc(1,
sizeof(*txn) + strlen(name) + 1))) {
286 strcpy(txn->
name, name);
313 ast_debug(2,
"release_transaction(%p) called (tx->obj = %p, tx->obj->txf = %p)\n", tx, tx->
obj, tx->
obj ? tx->
obj->
txf : NULL);
322 oldlist = txn_store->
data;
348 ast_debug(2,
"odbc_txn_free(%p) called\n", vdata);
365 if (!chan && tx && tx->
owner) {
379 oldlist = txn_store->
data;
391 return active ? 0 : -1;
400 if (class->username) {
403 if (class->password) {
406 if (class->sanitysql) {
409 ao2_ref(class->obj_container, -1);
410 SQLFreeHandle(SQL_HANDLE_ENV, class->env);
455 SQLHSTMT stmt = NULL;
456 int res = 0, error = 0,
try = 0;
461 if (strcmp(tableptr->
connection, database) == 0 && strcmp(tableptr->
table, tablename) == 0) {
475 ast_log(
LOG_WARNING,
"Unable to retrieve database handle for table description '%s@%s'\n", tablename, database);
483 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
484 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
494 res = SQLColumns(stmt, NULL, 0, NULL, 0, (
unsigned char *)tablename, SQL_NTS, (
unsigned char *)
"%", SQL_NTS);
495 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
498 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
502 ast_log(
LOG_ERROR,
"Unable to query database columns on connection '%s'.\n", database);
506 if (!(tableptr =
ast_calloc(
sizeof(
char),
sizeof(*tableptr) + strlen(database) + 1 + strlen(tablename) + 1))) {
507 ast_log(
LOG_ERROR,
"Out of memory creating entry for table '%s' on connection '%s'\n", tablename, database);
511 tableptr->
connection = (
char *)tableptr +
sizeof(*tableptr);
512 tableptr->
table = (
char *)tableptr +
sizeof(*tableptr) + strlen(database) + 1;
514 strcpy(tableptr->
table, tablename);
517 while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
518 SQLGetData(stmt, 4, SQL_C_CHAR, columnname,
sizeof(columnname), &sqlptr);
520 if (!(entry =
ast_calloc(
sizeof(
char),
sizeof(*entry) + strlen(columnname) + 1))) {
521 ast_log(
LOG_ERROR,
"Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, tablename, database);
525 entry->
name = (
char *)entry +
sizeof(*entry);
526 strcpy(entry->
name, columnname);
528 SQLGetData(stmt, 5, SQL_C_SHORT, &entry->
type,
sizeof(entry->
type), NULL);
529 SQLGetData(stmt, 7, SQL_C_LONG, &entry->
size,
sizeof(entry->
size), NULL);
530 SQLGetData(stmt, 9, SQL_C_SHORT, &entry->
decimals,
sizeof(entry->
decimals), NULL);
531 SQLGetData(stmt, 10, SQL_C_SHORT, &entry->
radix,
sizeof(entry->
radix), NULL);
532 SQLGetData(stmt, 11, SQL_C_SHORT, &entry->
nullable,
sizeof(entry->
nullable), NULL);
533 SQLGetData(stmt, 16, SQL_C_LONG, &entry->
octetlen,
sizeof(entry->
octetlen), NULL);
542 ast_verb(10,
"Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->
name, entry->
type, (
long) entry->
size, (
long) entry->
octetlen, entry->
decimals, entry->
radix);
546 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
570 if (strcasecmp(col->
name, colname) == 0) {
583 if (strcmp(tableptr->
connection, database) == 0 && strcmp(tableptr->
table, tablename) == 0) {
591 return tableptr ? 0 : -1;
601 for (attempt = 0; attempt < 2; attempt++) {
602 stmt = exec_cb(obj, data);
606 }
else if (obj->
tx) {
607 ast_log(
LOG_WARNING,
"Failed to execute, but unable to reconnect, as we're transactional.\n");
609 }
else if (attempt == 0) {
624 int res = 0, i, attempt;
625 SQLINTEGER nativeerror=0, numfields=0;
626 SQLSMALLINT diagbytes=0;
627 unsigned char state[10], diagnostic[256];
632 for (attempt = 0; attempt < 2; attempt++) {
638 stmt = prepare_cb(obj, data);
641 res = SQLExecute(stmt);
642 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
643 if (res == SQL_ERROR) {
644 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
645 for (i = 0; i < numfields; i++) {
646 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
647 ast_log(
LOG_WARNING,
"SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
649 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
656 ast_log(
LOG_WARNING,
"SQL Execute error, but unable to reconnect, as we're transactional.\n");
660 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
677 }
else if (attempt == 0) {
690 SQLINTEGER nativeerror=0, numfields=0;
691 SQLSMALLINT diagbytes=0;
692 unsigned char state[10], diagnostic[256];
696 res = SQLExecute(stmt);
697 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
698 if (res == SQL_ERROR) {
699 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
700 for (i = 0; i < numfields; i++) {
701 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
702 ast_log(
LOG_WARNING,
"SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
704 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
723 if (SQLGetData(StatementHandle, ColumnNumber, TargetType,
ast_str_buffer(*buf), 0, StrLen_or_Ind) == SQL_SUCCESS_WITH_INFO) {
726 }
else if (pmaxlen > 0) {
737 char *test_sql =
"select 1";
745 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
746 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
749 res = SQLPrepare(stmt, (
unsigned char *)test_sql, SQL_NTS);
750 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
753 res = SQLExecute(stmt);
754 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
759 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
762 if (!obj->
up && !obj->
tx) {
772 static char *cfg =
"res_odbc.conf";
778 struct timeval ncache = { 0, 0 };
780 int preconnect = 0, res = 0;
791 if (!strcasecmp(cat,
"ENV")) {
798 dsn = username = password = sanitysql = NULL;
800 preconnect = idlecheck = 0;
806 allow_empty_strings = 1;
807 isolation = SQL_TXN_READ_COMMITTED;
809 if (!strcasecmp(v->
name,
"pooling")) {
812 }
else if (!strncasecmp(v->
name,
"share", 5)) {
816 }
else if (!strcasecmp(v->
name,
"limit")) {
817 sscanf(v->
value,
"%30d", &limit);
819 ast_log(
LOG_WARNING,
"Limit should be a number, not a boolean: '%s'. Setting limit to 1023 for ODBC class '%s'.\n", v->
value, cat);
822 ast_log(
LOG_WARNING,
"Limit should be a number, not a boolean: '%s'. Disabling ODBC class '%s'.\n", v->
value, cat);
826 }
else if (!strcasecmp(v->
name,
"idlecheck")) {
827 sscanf(v->
value,
"%30u", &idlecheck);
828 }
else if (!strcasecmp(v->
name,
"enabled")) {
830 }
else if (!strcasecmp(v->
name,
"pre-connect")) {
832 }
else if (!strcasecmp(v->
name,
"dsn")) {
834 }
else if (!strcasecmp(v->
name,
"username")) {
836 }
else if (!strcasecmp(v->
name,
"password")) {
838 }
else if (!strcasecmp(v->
name,
"sanitysql")) {
839 sanitysql = v->
value;
840 }
else if (!strcasecmp(v->
name,
"backslash_is_escape")) {
842 }
else if (!strcasecmp(v->
name,
"allow_empty_string_in_nontext")) {
844 }
else if (!strcasecmp(v->
name,
"connect_timeout")) {
845 if (sscanf(v->
value,
"%d", &conntimeout) != 1 || conntimeout < 1) {
849 }
else if (!strcasecmp(v->
name,
"negative_connection_cache")) {
851 if (sscanf(v->
value,
"%lf", &dncache) != 1 || dncache < 0) {
857 ncache.tv_sec = (int)dncache;
858 ncache.tv_usec = (dncache - ncache.tv_sec) * 1000000;
860 }
else if (!strcasecmp(v->
name,
"forcecommit")) {
862 }
else if (!strcasecmp(v->
name,
"isolation")) {
865 isolation = SQL_TXN_READ_COMMITTED;
878 SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &new->env);
879 res = SQLSetEnvAttr(new->env, SQL_ATTR_ODBC_VERSION, (
void *) SQL_OV_ODBC3, 0);
881 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
890 new->haspool = pooling;
894 ast_log(
LOG_WARNING,
"Pooling without also setting a limit is pointless. Changing limit from 0 to 5.\n");
899 new->backslash_is_escape = bse ? 1 : 0;
900 new->forcecommit = forcecommit ? 1 : 0;
904 new->negative_connection_cache = ncache;
905 new->allow_empty_strings = allow_empty_strings ? 1 : 0;
911 if (username && !(new->username =
ast_strdup(username))) {
915 if (password && !(new->password =
ast_strdup(password))) {
919 if (sanitysql && !(new->sanitysql =
ast_strdup(sanitysql))) {
948 "Usage: odbc show [class]\n"
949 " List settings of a particular ODBC class or,\n"
950 " if not specified, all classes.\n";
955 length = strlen(a->
word);
958 if (!strncasecmp(a->
word, class->name, length) && ++which > a->
n) {
967 if (!ret && !strncasecmp(a->
word,
"all", length) && ++which > a->
n) {
977 if ((a->
argc == 2) || (a->
argc == 3 && !strcmp(a->
argv[2],
"all")) || (!strcmp(a->
argv[2], class->name))) {
983 ast_strftime(timestr,
sizeof(timestr),
"%Y-%m-%d %T", &tm);
984 ast_cli(a->
fd,
" Name: %s\n DSN: %s\n", class->name, class->dsn);
985 ast_cli(a->
fd,
" Last connection attempt: %s\n", timestr);
987 if (class->haspool) {
990 ast_cli(a->
fd,
" Pooled: Yes\n Limit: %u\n Connections in use: %d\n", class->limit, class->count);
995 ast_cli(a->
fd,
" - Connection %d: %s (%s:%d %s)\n", ++count,
996 current->
used ?
"in use" :
998 current->file, current->lineno, current->function);
1000 ast_cli(a->
fd,
" - Connection %d: %s\n", ++count,
1001 current->
used ?
"in use" :
1012 ast_cli(a->
fd,
" Pooled: No\n Connected: %s\n", current->
used ?
"In use" :
1055 SQLINTEGER nativeerror=0, numfields=0;
1056 SQLSMALLINT diagbytes=0, i;
1057 unsigned char state[10], diagnostic[256];
1059 ast_debug(2,
"odbc_release_obj2(%p) called (obj->txf = %p)\n", obj, obj->
txf);
1061 ast_debug(1,
"called on a transactional handle with %s\n", tx->
forcecommit ?
"COMMIT" :
"ROLLBACK");
1062 if (SQLEndTran(SQL_HANDLE_DBC, obj->
con, tx->
forcecommit ? SQL_COMMIT : SQL_ROLLBACK) == SQL_ERROR) {
1064 SQLGetDiagField(SQL_HANDLE_DBC, obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1065 for (i = 0; i < numfields; i++) {
1066 SQLGetDiagRec(SQL_HANDLE_DBC, obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1068 if (!strcmp((
char *)state,
"25S02") || !strcmp((
char *)state,
"08007")) {
1072 SQLEndTran(SQL_HANDLE_DBC, obj->
con, SQL_ROLLBACK);
1075 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1082 if (SQLSetConnectAttr(obj->
con, SQL_ATTR_AUTOCOMMIT, (
void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1083 SQLGetDiagField(SQL_HANDLE_DBC, obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1084 for (i = 0; i < numfields; i++) {
1085 SQLGetDiagRec(SQL_HANDLE_DBC, obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1086 ast_log(
LOG_WARNING,
"SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1088 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1095 #ifdef DEBUG_THREADS
1096 obj->file[0] =
'\0';
1097 obj->function[0] =
'\0';
1131 SQLINTEGER nativeerror=0, numfields=0;
1132 SQLSMALLINT diagbytes=0, i;
1133 unsigned char state[10], diagnostic[256];
1144 if (SQLEndTran(SQL_HANDLE_DBC, tx->
obj->
con, SQL_COMMIT) == SQL_ERROR) {
1149 SQLGetDiagField(SQL_HANDLE_DBC, tx->
obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1150 for (i = 0; i < numfields; i++) {
1151 SQLGetDiagRec(SQL_HANDLE_DBC, tx->
obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1155 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1168 SQLINTEGER nativeerror=0, numfields=0;
1169 SQLSMALLINT diagbytes=0, i;
1170 unsigned char state[10], diagnostic[256];
1181 if (SQLEndTran(SQL_HANDLE_DBC, tx->
obj->
con, SQL_ROLLBACK) == SQL_ERROR) {
1186 SQLGetDiagField(SQL_HANDLE_DBC, tx->
obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1187 for (i = 0; i < numfields; i++) {
1188 SQLGetDiagRec(SQL_HANDLE_DBC, tx->
obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1192 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1206 if (!strcmp(class->name, name) && !class->delme) {
1212 #define USE_TX (void *)(long)1
1213 #define NO_TX (void *)(long)2
1214 #define EOR_TX (void *)(long)3
1245 SQLINTEGER nativeerror=0, numfields=0;
1246 SQLSMALLINT diagbytes=0, i;
1247 unsigned char state[10], diagnostic[256];
1250 ast_debug(1,
"Class '%s' not found!\n", name);
1256 if (class->haspool) {
1264 (time(NULL) > class->last_negative_connect.tv_sec + class->negative_connection_cache.tv_sec)) {
1269 ast_debug(3,
"Unable to allocate object\n");
1307 if (SQLSetConnectAttr(obj->
con, SQL_ATTR_AUTOCOMMIT, (
void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1308 SQLGetDiagField(SQL_HANDLE_DBC, obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1309 for (i = 0; i < numfields; i++) {
1310 SQLGetDiagRec(SQL_HANDLE_DBC, obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1311 ast_log(
LOG_WARNING,
"SQLSetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1313 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1326 ast_debug(3,
"Unable to allocate object\n");
1350 if (SQLSetConnectAttr(obj->
con, SQL_ATTR_AUTOCOMMIT, (
void *)SQL_AUTOCOMMIT_OFF, 0) == SQL_ERROR) {
1351 SQLGetDiagField(SQL_HANDLE_DBC, obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1352 for (i = 0; i < numfields; i++) {
1353 SQLGetDiagRec(SQL_HANDLE_DBC, obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1354 ast_log(
LOG_WARNING,
"SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1356 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1373 ast_debug(3,
"Unable to allocate object\n");
1396 if (SQLSetConnectAttr(obj->
con, SQL_ATTR_AUTOCOMMIT, (
void *)SQL_AUTOCOMMIT_ON, 0) == SQL_ERROR) {
1397 SQLGetDiagField(SQL_HANDLE_DBC, obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1398 for (i = 0; i < numfields; i++) {
1399 SQLGetDiagRec(SQL_HANDLE_DBC, obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1400 ast_log(
LOG_WARNING,
"SetConnectAttr (Autocommit) returned an error: %s: %s\n", state, diagnostic);
1402 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1412 if (SQLSetConnectAttr(obj->
con, SQL_ATTR_TXN_ISOLATION, (
void *)(
long)obj->
parent->
isolation, 0) == SQL_ERROR) {
1413 SQLGetDiagField(SQL_HANDLE_DBC, obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1414 for (i = 0; i < numfields; i++) {
1415 SQLGetDiagRec(SQL_HANDLE_DBC, obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1416 ast_log(
LOG_WARNING,
"SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1418 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1435 #ifdef DEBUG_THREADS
1438 obj->lineno = lineno;
1469 oldlist = txn_store->
data;
1493 unsigned char msg[200],
state[10];
1503 res = SQLDisconnect(con);
1506 if (res == SQL_SUCCESS || res == SQL_SUCCESS_WITH_INFO) {
1513 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con) == SQL_SUCCESS)) {
1516 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1517 ast_log(
LOG_WARNING,
"Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (
int)err, msg);
1529 unsigned char msg[200],
state[10];
1531 SQLINTEGER enable = 1;
1532 char *tracefile =
"/tmp/odbc.trace";
1544 res = SQLAllocHandle(SQL_HANDLE_DBC, obj->
parent->
env, &con);
1546 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1551 SQLSetConnectAttr(con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)(
long) obj->
parent->
conntimeout, 0);
1552 SQLSetConnectAttr(con, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER *)(
long) obj->
parent->
conntimeout, 0);
1554 SQLSetConnectAttr(con, SQL_ATTR_TRACE, &enable, SQL_IS_INTEGER);
1555 SQLSetConnectAttr(con, SQL_ATTR_TRACEFILE, tracefile, strlen(tracefile));
1558 res = SQLConnect(con,
1563 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1564 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1566 ast_log(
LOG_WARNING,
"res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (
int)err, msg);
1567 if ((res = SQLFreeHandle(SQL_HANDLE_DBC, con) != SQL_SUCCESS)) {
1568 SQLGetDiagRec(SQL_HANDLE_DBC, con, 1, state, &err, msg, 100, &mlen);
1569 ast_log(
LOG_WARNING,
"Unable to deallocate database handle %p? %d errno=%d %s\n", con, res, (
int)err, msg);
1591 if (strcasecmp(
args.property,
"transaction") == 0) {
1596 }
else if (strcasecmp(
args.property,
"isolation") == 0) {
1606 }
else if (strcasecmp(
args.property,
"forcecommit") == 0) {
1627 SQLINTEGER nativeerror=0, numfields=0;
1628 SQLSMALLINT diagbytes=0, i;
1629 unsigned char state[10], diagnostic[256];
1632 if (strcasecmp(
args.property,
"transaction") == 0) {
1653 }
else if (strcasecmp(
args.property,
"forcecommit") == 0) {
1676 }
else if (strcasecmp(
args.property,
"isolation") == 0) {
1688 if (isolation == 0) {
1691 }
else if (SQLSetConnectAttr(tx->
obj->
con, SQL_ATTR_TXN_ISOLATION, (
void *)(
long)isolation, 0) == SQL_ERROR) {
1693 SQLGetDiagField(SQL_HANDLE_DBC, tx->
obj->
con, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
1694 for (i = 0; i < numfields; i++) {
1695 SQLGetDiagRec(SQL_HANDLE_DBC, tx->
obj->
con, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
1696 ast_log(
LOG_WARNING,
"SetConnectAttr (Txn isolation) returned an error: %s: %s\n", state, diagnostic);
1698 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
1732 struct ast_data *data_odbc_class, *data_odbc_connections, *data_odbc_connection;
1739 if (!data_odbc_class) {
1752 if (!data_odbc_connections) {
1771 if (!data_odbc_connection) {
1782 if (class->haspool) {
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
Checks if the database natively supports backslash as an escape character.
#define ast_channel_lock(chan)
Main Channel structure associated with a channel.
#define AST_CLI_DEFINE(fn, txt,...)
#define AST_RWLIST_HEAD_DESTROY(head)
Destroys an rwlist head structure.
struct odbc_obj * ast_odbc_retrieve_transaction_obj(struct ast_channel *chan, const char *objname)
Retrieve a stored ODBC object, if a transaction has been started.
static void odbc_class_destructor(void *data)
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_link(arg1, arg2)
struct ao2_container * obj_container
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
static int null_hash_fn(const void *obj, const int flags)
static const char config[]
The data tree to be returned by the callbacks and managed by functions local to this file...
static int load_odbc_config(void)
unsigned int active
Is this record the current active transaction within the channel? Note that the active flag is really...
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
static struct odbc_txn_frame * release_transaction(struct odbc_txn_frame *tx)
struct odbc_class::@337 list
String manipulation functions.
struct odbc_obj * _ast_odbc_request_obj2(const char *name, struct ast_flags flags, const char *file, const char *function, int lineno)
Retrieves a connected ODBC object.
#define ast_test_flag(p, flag)
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Time-related functions and macros.
static int aoro2_obj_cb(void *vobj, void *arg, int flags)
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
#define ao2_iterator_next(arg1)
descriptor for a cli entry.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
static struct ast_custom_function odbc_function
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
int64_t ast_tvdiff_sec(struct timeval end, struct timeval start)
Computes the difference (in seconds) between two struct timeval instances.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
static int aoro2_class_cb(void *obj, void *arg, int flags)
This entries are for multiple registers.
Structure for variables, used for configurations and for channel variables.
static struct ast_data_handler odbc_provider
Structure for a data store type.
Configuration File Parser.
static struct ast_threadstorage errors_buf
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define ast_odbc_request_obj2(a, b)
struct ast_data * ast_data_add_bool(struct ast_data *root, const char *childname, unsigned int boolean)
Add a boolean node type.
static struct ast_datastore_info txn_info
#define ast_mutex_lock(a)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
static const char *const app_rollback
Structure for a data store object.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
#define AST_RWLIST_HEAD_INIT(head)
Initializes an rwlist head structure.
struct ast_channel * owner
Definitions to aid in the use of thread local storage.
void ast_cli(int fd, const char *fmt,...)
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
struct odbc_obj * _ast_odbc_request_obj(const char *name, int check, const char *file, const char *function, int lineno)
static char * handle_cli_odbc_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void destroy_table_cache(struct odbc_cache_tables *table)
#define AST_DATA_ENTRY(__path, __handler)
These structures are used for adaptive capabilities.
struct timeval negative_connection_cache
#define ast_verb(level,...)
void ast_config_destroy(struct ast_config *config)
Destroys a config.
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
static const char *const app_commit
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
#define CONFIG_STATUS_FILEMISSING
static void odbc_obj_destructor(void *data)
static void odbc_txn_free(void *data)
int ast_odbc_smart_execute(struct odbc_obj *obj, SQLHSTMT stmt)
Executes a prepared statement handle.
static struct ast_cli_entry cli_odbc[]
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_DATA_HANDLER_VERSION
The Data API structures version.
General Asterisk PBX channel definitions.
static int acf_transaction_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
int ast_str_make_space(struct ast_str **buf, size_t new_len)
struct odbc_cache_columns * ast_odbc_find_column(struct odbc_cache_tables *table, const char *colname)
Find a column entry within a cached table structure.
static void odbc_release_obj2(struct odbc_obj *obj, struct odbc_txn_frame *tx)
#define ast_config_load(filename, flags)
Load a config file.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Data structure associated with a custom dialplan function.
struct ast_data * ast_data_add_node(struct ast_data *root, const char *childname)
Add a container child.
#define AST_RWLIST_TRAVERSE
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
#define ao2_ref(o, delta)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define ast_data_register_multiple(data_entries, entries)
struct odbc_class * parent
Core PBX routines and definitions.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define ast_data_add_structure(structure_name, root, structure)
The list of nodes with their search requirement.
struct odbc_cache_tables * ast_odbc_find_table(const char *database, const char *tablename)
Find or create an entry describing the table specified.
static odbc_status odbc_obj_connect(struct odbc_obj *obj)
#define DATA_EXPORT_ODBC_CLASS(MEMBER)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
Executes an non prepared statement and returns the resulting statement handle.
unsigned int backslash_is_escape
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj)
Checks if the database natively supports implicit conversion from an empty string to a number (0)...
void ast_data_remove_node(struct ast_data *root, struct ast_data *child)
Remove a node that was added using ast_data_add_.
struct odbc_txn_frame * txf
int setenv(const char *name, const char *value, int overwrite)
static int data_odbc_provider_handler(const struct ast_data_search *search, struct ast_data *root)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
static odbc_status odbc_obj_disconnect(struct odbc_obj *obj)
#define ao2_alloc(data_size, destructor_fn)
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define ast_channel_unlock(chan)
static int mark_transaction_active(struct ast_channel *chan, struct odbc_txn_frame *tx)
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
static const char * isolation2text(int iso)
#define ast_odbc_request_obj(a, b)
int ast_odbc_clear_cache(const char *database, const char *tablename)
Remove a cache entry from memory This function may be called to clear entries created and cached by t...
#define AST_RWLIST_REMOVE_HEAD
int ast_odbc_sanity_check(struct odbc_obj *obj)
Checks an ODBC object to ensure it is still connected.
static int rollback_exec(struct ast_channel *chan, const char *data)
static struct odbc_txn_frame * find_transaction(struct ast_channel *chan, struct odbc_obj *obj, const char *name, int active)
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
static int text2isolation(const char *txt)
static int odbc_register_class(struct odbc_class *class, int connect)
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Structure used to handle boolean flags.
ao2_callback_fn ao2_match_by_addr
a very common callback is one that matches by address.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
static int acf_transaction_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
#define AST_RWLIST_INSERT_TAIL
SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
Prepares, executes, and returns the resulting statement handle.
unsigned int allow_empty_strings
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define ao2_container_alloc(arg1, arg2, arg3)
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
static int unload_module(void)
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
static int load_module(void)
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define AST_DATA_STRUCTURE(__struct, __name)
static struct ast_data_entry odbc_providers[]
SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind)
Wrapper for SQLGetData to use with dynamic strings.
#define AST_APP_ARG(name)
Define an application argument.
struct ast_variable * next
#define ast_mutex_init(pmutex)
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define CONFIG_STATUS_FILEINVALID
#define ast_mutex_destroy(a)
struct timeval last_negative_connect
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
#define ASTERISK_GPL_KEY
The text the key() function should return.
struct ast_data * ast_data_add_str(struct ast_data *root, const char *childname, const char *string)
Add a string node type.
Asterisk module definitions.
static int commit_exec(struct ast_channel *chan, const char *data)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
struct ast_data * ast_data_add_int(struct ast_data *root, const char *childname, int value)
Add an integer node type.
#define ao2_unlink(arg1, arg2)
int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data)
Check the current generated node to know if it matches the search condition.
#define ast_custom_function_register(acf)
Register a custom function.
static struct ao2_container * class_container
#define AST_RWLIST_TRAVERSE_SAFE_END
uint32_t version
Structure version.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
The structure of the node handler.
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
#define ast_mutex_unlock(a)
static int aoro2_obj_notx_cb(void *vobj, void *arg, int flags)
struct odbc_cache_tables::_columns columns