39 #include "asterisk/module.h"
110 char readhandle[5][30];
111 char writehandle[5][30];
174 res = SQLAllocHandle (SQL_HANDLE_STMT, obj->
con, &stmt);
175 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
180 res = SQLExecDirect(stmt, (
unsigned char *)sql, SQL_NTS);
181 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) {
182 if (res == SQL_ERROR) {
184 SQLINTEGER nativeerror=0, numfields=0;
185 SQLSMALLINT diagbytes=0;
186 unsigned char state[10], diagnostic[256];
188 SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
189 for (i = 0; i < numfields; i++) {
190 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic,
sizeof(diagnostic), &diagbytes);
191 ast_log(
LOG_WARNING,
"SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
193 ast_log(
LOG_WARNING,
"Oh, that was good. There are really %d diagnostics?\n", (
int)numfields);
200 SQLCloseCursor(stmt);
201 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
215 char *t, varname[15];
216 int i,
dsn, bogus_chan = 0;
217 int transactional = 0;
224 SQLHSTMT stmt = NULL;
228 const char *
status =
"FAILURE";
230 if (!buf || !insertbuf) {
236 if (!strcmp(query->acf->name, cmd)) {
264 if (query->sql_insert) {
284 for (i = 0; i <
args.argc; i++) {
285 snprintf(varname,
sizeof(varname),
"ARG%d", i + 1);
291 for (i = 0; i <
values.argc; i++) {
292 snprintf(varname,
sizeof(varname),
"VAL%d", i + 1);
300 if (query->sql_insert) {
308 for (i = 0; i <
args.argc; i++) {
309 snprintf(varname,
sizeof(varname),
"ARG%d", i + 1);
313 for (i = 0; i <
values.argc; i++) {
314 snprintf(varname,
sizeof(varname),
"VAL%d", i + 1);
326 for (dsn = 0; dsn < 5; dsn++) {
330 ast_log(
LOG_WARNING,
"Transactions do not work well with multiple DSNs for 'writehandle'\n");
344 if (obj && !transactional) {
352 SQLRowCount(stmt, &rows);
353 SQLCloseCursor(stmt);
354 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
359 }
else if (query->sql_insert) {
360 if (obj && !transactional) {
365 for (transactional = 0, dsn = 0; dsn < 5; dsn++) {
369 ast_log(
LOG_WARNING,
"Transactions do not work well with multiple DSNs for 'writehandle'\n");
387 SQLRowCount(stmt, &rows);
388 SQLCloseCursor(stmt);
389 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
403 snprintf(varname,
sizeof(varname),
"%d", (
int)rows);
408 if (obj && !transactional) {
424 char varname[15], rowcount[12] =
"-1";
426 int res, x, y, buflen = 0, escapecommas, rowlimit = 1, multirow = 0,
dsn, bogus_chan = 0;
430 SQLHSTMT stmt = NULL;
431 SQLSMALLINT colcount=0;
433 SQLSMALLINT collength;
437 const char *
status =
"FAILURE";
439 if (!sql || !colnames) {
450 if (!strcmp(query->acf->name, cmd)) {
478 for (x = 0; x <
args.argc; x++) {
479 snprintf(varname,
sizeof(varname),
"ARG%d", x + 1);
489 for (x = 0; x <
args.argc; x++) {
490 snprintf(varname,
sizeof(varname),
"ARG%d", x + 1);
498 if (!(resultset =
ast_calloc(1,
sizeof(*resultset)))) {
505 if (query->rowlimit) {
506 rowlimit = query->rowlimit;
511 }
else if (!bogus_chan) {
512 if (query->rowlimit > 1) {
513 rowlimit = query->rowlimit;
514 if (!(resultset =
ast_calloc(1,
sizeof(*resultset)))) {
555 res = SQLNumResultCols(stmt, &colcount);
556 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
558 SQLCloseCursor(stmt);
559 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
570 res = SQLFetch(stmt);
571 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
573 if (res == SQL_NO_DATA) {
581 status =
"FETCHERROR";
583 SQLCloseCursor(stmt);
584 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
598 for (y = 0; y < rowlimit; y++) {
600 for (x = 0; x < colcount; x++) {
607 SQLCloseCursor(stmt);
608 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
622 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *)colname,
sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
623 ast_debug(3,
"Got collength of %d and maxcol of %d for column '%s' (offset %d)\n", (
int)collength, (
int)maxcol, colname, x);
624 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
625 snprintf(colname,
sizeof(colname),
"field%d", x);
640 SQLCloseCursor(stmt);
641 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
652 strcpy((
char *)resultset +
sizeof(*resultset),
ast_str_buffer(colnames));
656 buflen = strlen(buf);
658 if (indicator == SQL_NULL_DATA) {
664 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
680 if (escapecommas && (ptrcoldata[i] ==
'\\' || ptrcoldata[i] ==
',')) {
681 buf[buflen++] =
'\\';
683 buf[buflen++] = ptrcoldata[i];
685 if (buflen >= len - 2) {
689 if (ptrcoldata[i] ==
'\0') {
695 ast_debug(2,
"buf is now set to '%s'\n", buf);
697 ast_debug(2,
"buf is now set to '%s'\n", buf);
700 row =
ast_calloc(1,
sizeof(*row) + buflen + 1);
702 ast_log(
LOG_ERROR,
"Unable to allocate space for more rows in this resultset.\n");
706 strcpy((
char *)row +
sizeof(*row), buf);
710 res = SQLFetch(stmt);
711 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
712 if (res != SQL_NO_DATA) {
724 snprintf(rowcount,
sizeof(rowcount),
"%d", y);
733 snprintf(buf, len,
"%d", uid);
748 ast_log(
LOG_ERROR,
"Rows retrieved, but unable to store it in the channel. Results fail.\n");
750 SQLCloseCursor(stmt);
751 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
758 odbc_store->
data = resultset;
764 SQLCloseCursor(stmt);
765 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
768 if (resultset && !multirow) {
770 if (!
acf_fetch(chan,
"", buf, buf, len)) {
784 for (; *data && out - buf <
len; data++) {
820 resultset = store->
data;
841 .
name =
"ODBC_FETCH",
866 if (query->acf->name)
889 if (!(*query =
ast_calloc(1,
sizeof(**query)))) {
899 for (i = 0; i < 5; i++) {
901 ast_copy_string((*query)->writehandle[i], writeconf.dsn[i],
sizeof((*query)->writehandle[i]));
911 for (i = 0; i < 5; i++) {
913 ast_copy_string((*query)->readhandle[i], readconf.dsn[i],
sizeof((*query)->readhandle[i]));
917 for (i = 0; i < 5; i++) {
919 ast_copy_string((*query)->readhandle[i], (*query)->writehandle[i],
sizeof((*query)->readhandle[i]));
926 ast_log(
LOG_WARNING,
"Parameter 'read' is deprecated for category %s. Please use 'readsql' instead.\n", catg);
930 if (!((*query)->sql_read =
ast_strdup(tmp))) {
941 ast_log(
LOG_ERROR,
"There is SQL, but no ODBC class to be used for reading: %s\n", catg);
948 ast_log(
LOG_WARNING,
"Parameter 'write' is deprecated for category %s. Please use 'writesql' instead.\n", catg);
952 if (!((*query)->sql_write =
ast_strdup(tmp))) {
960 if ((*query)->sql_write &&
ast_strlen_zero((*query)->writehandle[0])) {
963 ast_log(
LOG_ERROR,
"There is SQL, but no ODBC class to be used for writing: %s\n", catg);
969 if (!((*query)->sql_insert =
ast_strdup(tmp))) {
985 if (strcasecmp(tmp,
"multirow") == 0)
988 sscanf(tmp,
"%30d", &((*query)->rowlimit));
992 if (!(*query)->acf) {
1004 if (
ast_asprintf((
char **)&((*query)->acf->name),
"%s_%s", tmp, catg) < 0) {
1005 (*query)->acf->name = NULL;
1008 if (
ast_asprintf((
char **)&((*query)->acf->name),
"ODBC_%s", catg) < 0) {
1009 (*query)->acf->name = NULL;
1013 if (!(*query)->acf->name) {
1043 if ((*query)->sql_read && (*query)->sql_write) {
1045 "Runs the following query, as defined in func_odbc.conf, performing\n"
1046 "substitution of the arguments into the query as specified by ${ARG1},\n"
1047 "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n"
1048 "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1050 "\nRead:\n%s\n\nWrite:\n%s%s%s",
1051 (*query)->sql_insert ?
1052 "If the write query affects no rows, the insert query will be\n"
1053 "performed.\n" :
"",
1055 (*query)->sql_write,
1056 (*query)->sql_insert ?
"\n\nInsert:\n" :
"",
1057 (*query)->sql_insert ? (*query)->sql_insert :
"");
1058 }
else if ((*query)->sql_read) {
1060 "Runs the following query, as defined in func_odbc.conf, performing\n"
1061 "substitution of the arguments into the query as specified by ${ARG1},\n"
1062 "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s",
1063 (*query)->sql_read);
1064 }
else if ((*query)->sql_write) {
1066 "Runs the following query, as defined in func_odbc.conf, performing\n"
1067 "substitution of the arguments into the query as specified by ${ARG1},\n"
1068 "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n"
1069 "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
1070 "This function may only be set.\n%s\nSQL:\n%s%s%s",
1071 (*query)->sql_insert ?
1072 "If the write query affects no rows, the insert query will be\n"
1073 "performed.\n" :
"",
1074 (*query)->sql_write,
1075 (*query)->sql_insert ?
"\n\nInsert:\n" :
"",
1076 (*query)->sql_insert ? (*query)->sql_insert :
"");
1080 ast_log(
LOG_WARNING,
"Section '%s' was found, but there was no SQL to execute. Ignoring.\n", catg);
1090 if ((*query)->sql_read) {
1094 if ((*query)->sql_write) {
1107 char *char_args, varname[10];
1116 "Usage: odbc read <name> <args> [exec]\n"
1117 " Evaluates the SQL provided in the ODBC function <name>, and\n"
1118 " optionally executes the function. This function is intended for\n"
1119 " testing purposes. Remember to quote arguments containing spaces.\n";
1123 int wordlen = strlen(a->
word), which = 0;
1127 if (!strncasecmp(query->acf->name, a->
word, wordlen)) {
1128 if (++which > a->
n) {
1137 }
else if (a->
pos == 4) {
1155 if (!strcmp(query->acf->name, a->
argv[2])) {
1166 if (!query->sql_read) {
1167 ast_cli(a->
fd,
"The function %s has no readsql parameter.\n", a->
argv[2]);
1184 for (i = 0; i <
args.argc; i++) {
1185 snprintf(varname,
sizeof(varname),
"ARG%d", i + 1);
1192 if (a->
argc == 5 && !strcmp(a->
argv[4],
"exec")) {
1195 int dsn, executed = 0;
1197 int rows = 0, res, x;
1198 SQLSMALLINT colcount = 0, collength;
1209 for (dsn = 0; dsn < 5; dsn++) {
1213 ast_debug(1,
"Found handle %s\n", query->readhandle[dsn]);
1227 res = SQLNumResultCols(stmt, &colcount);
1228 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1230 SQLCloseCursor(stmt);
1231 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1238 res = SQLFetch(stmt);
1239 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1240 SQLCloseCursor(stmt);
1241 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1244 if (res == SQL_NO_DATA) {
1245 ast_cli(a->
fd,
"Returned %d rows. Query executed on handle %d:%s [%s]\n", rows, dsn, query->readhandle[dsn],
ast_str_buffer(sql));
1254 for (x = 0; x < colcount; x++) {
1257 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *)colname,
sizeof(colname), &collength, NULL, &maxcol, NULL, NULL);
1258 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || collength == 0) {
1259 snprintf(colname,
sizeof(colname),
"field%d", x);
1263 if (indicator == SQL_NULL_DATA) {
1268 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1270 SQLCloseCursor(stmt);
1271 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1283 res = SQLFetch(stmt);
1284 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1287 ast_cli(a->
fd,
"%-20.20s %s\n",
"----------",
"----------");
1289 SQLCloseCursor(stmt);
1290 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1293 ast_cli(a->
fd,
"Returned %d row%s. Query executed on handle %d [%s]\n", rows, rows == 1 ?
"" :
"s", dsn, query->readhandle[dsn]);
1320 char *char_args, *char_values, varname[10];
1329 "Usage: odbc write <name> <args> <value> [exec]\n"
1330 " Evaluates the SQL provided in the ODBC function <name>, and\n"
1331 " optionally executes the function. This function is intended for\n"
1332 " testing purposes. Remember to quote arguments containing spaces.\n";
1336 int wordlen = strlen(a->
word), which = 0;
1340 if (!strncasecmp(query->acf->name, a->
word, wordlen)) {
1341 if (++which > a->
n) {
1350 }
else if (a->
pos == 5) {
1368 if (!strcmp(query->acf->name, a->
argv[2])) {
1379 if (!query->sql_write) {
1380 ast_cli(a->
fd,
"The function %s has no writesql parameter.\n", a->
argv[2]);
1401 for (i = 0; i <
args.argc; i++) {
1402 snprintf(varname,
sizeof(varname),
"ARG%d", i + 1);
1408 for (i = 0; i <
values.argc; i++) {
1409 snprintf(varname,
sizeof(varname),
"VAL%d", i + 1);
1420 if (a->
argc == 6 && !strcmp(a->
argv[5],
"exec")) {
1423 int dsn, executed = 0;
1427 for (dsn = 0; dsn < 5; dsn++) {
1440 SQLRowCount(stmt, &rows);
1441 SQLCloseCursor(stmt);
1442 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
1445 ast_cli(a->
fd,
"Affected %d rows. Query executed on handle %d [%s]\n", (
int)rows, dsn, query->writehandle[dsn]);
1451 ast_cli(a->
fd,
"Failed to execute query.\n");
1492 else if (err == EINVAL)
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
#define ast_channel_lock(chan)
Main Channel structure associated with a channel.
#define AST_CLI_DEFINE(fn, txt,...)
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.
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk main include file. File version handling, generic pbx functions.
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
static char * app_odbcfinish
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
String manipulation functions.
static struct ast_custom_function fetch_function
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define ast_channel_unref(c)
Decrease channel reference count.
#define ast_test_flag(p, flag)
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
#define ast_set_flag(p, flag)
descriptor for a cli entry.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static int unload_module(void)
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
static struct ast_threadstorage sql_buf
static int exec_odbcfinish(struct ast_channel *chan, const char *data)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Structure for a data store type.
char * ast_str_append_escapecommas(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string, with escaping of commas...
Configuration File Parser.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
static int acf_escape(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
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.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value...
void ast_cli(int fd, const char *fmt,...)
struct odbc_datastore_row::@136 list
static SQLHSTMT generic_execute(struct odbc_obj *obj, void *data)
int ast_unregister_application(const char *app)
Unregister an application.
#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_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
static struct ast_custom_function escape_function
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
#define ast_asprintf(a, b, c...)
#define AST_RWLIST_INSERT_HEAD
#define ast_debug(level,...)
Log a DEBUG message.
static struct ast_datastore_info odbc_info
General Asterisk PBX channel definitions.
static int acf_odbc_write(struct ast_channel *chan, const char *cmd, char *s, const char *value)
int ast_str_make_space(struct ast_str **buf, size_t new_len)
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#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.
#define AST_RWLIST_TRAVERSE
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
static int load_module(void)
static struct ast_threadstorage coldata_buf
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
static char * cli_odbc_read(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Core PBX routines and definitions.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
static int acf_odbc_read(struct ast_channel *chan, const char *cmd, char *s, char *buf, size_t len)
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
static int acf_fetch(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
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.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
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 struct ast_threadstorage sql2_buf
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
static char * cli_odbc_write(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
static void odbc_datastore_free(void *data)
#define ast_channel_unlock(chan)
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
#define ast_odbc_request_obj(a, b)
#define AST_RWLIST_REMOVE_HEAD
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
Structure used to handle boolean flags.
#define ast_clear_flag(p, flag)
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...
static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
static struct ast_cli_entry cli_func_odbc[]
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
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.
#define ast_realloc(a, b)
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
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_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
struct ast_channel * ast_dummy_channel_alloc(void)
Create a fake channel structure.
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.
static struct ast_threadstorage colnames_buf
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
#define ast_custom_function_register(acf)
Register a custom function.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
#define CONFIG_STATUS_FILEUNCHANGED
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
static int free_acf_query(struct acf_odbc_query *query)