git migration: Refactor the ASTERISK_FILE_VERSION macro
[asterisk/asterisk.git] / cel / cel_odbc.c
index 223cb18..4803444 100644 (file)
@@ -22,7 +22,7 @@
  *
  * \brief ODBC CEL backend
  *
- * \author Tilghman Lesher <tlesher AT digium DOT com>
+ * \author Tilghman Lesher \verbatim <tlesher AT digium DOT com> \endverbatim
  * \ingroup cel_drivers
  */
 
@@ -33,7 +33,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ASTERISK_REGISTER_FILE()
 
 #include <sys/types.h>
 #include <time.h>
@@ -51,7 +51,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/module.h"
 
 #define        CONFIG  "cel_odbc.conf"
-static struct ast_event_sub *event_sub = NULL;
+
+#define ODBC_BACKEND_NAME "ODBC CEL backend"
+
+/*! \brief show_user_def is off by default */
+#define CEL_SHOW_USERDEF_DEFAULT       0
+
+/*! TRUE if we should set the eventtype field to USER_DEFINED on user events. */
+static unsigned char cel_show_user_def;
 
 /* Optimization to reduce number of memory allocations */
 static int maxsize = 512, maxsize2 = 512;
@@ -74,6 +81,7 @@ struct tables {
        char *connection;
        char *table;
        unsigned int usegmtime:1;
+       unsigned int allowleapsec:1;
        AST_LIST_HEAD_NOLOCK(odbc_columns, columns) columns;
        AST_RWLIST_ENTRY(tables) list;
 };
@@ -91,7 +99,7 @@ static int load_config(void)
        char columnname[80];
        char connection[40];
        char table[40];
-       int lenconnection, lentable, usegmtime = 0;
+       int lenconnection, lentable;
        SQLLEN sqlptr;
        int res = 0;
        SQLHSTMT stmt = NULL;
@@ -103,7 +111,20 @@ static int load_config(void)
                return -1;
        }
 
+       /* Process the general category */
+       cel_show_user_def = CEL_SHOW_USERDEF_DEFAULT;
+       for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
+               if (!strcasecmp(var->name, "show_user_defined")) {
+                       cel_show_user_def = ast_true(var->value) ? 1 : 0;
+               } else {
+                       /* Unknown option name. */
+               }
+       }
+
        for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
+               if (!strcasecmp(catg, "general")) {
+                       continue;
+               }
                var = ast_variable_browse(cfg, catg);
                if (!var)
                        continue;
@@ -115,10 +136,6 @@ static int load_config(void)
                ast_copy_string(connection, tmp, sizeof(connection));
                lenconnection = strlen(connection);
 
-               if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "usegmtime"))) {
-                       usegmtime = ast_true(tmp);
-               }
-
                /* When loading, we want to be sure we can connect. */
                obj = ast_odbc_request_obj(connection, 1);
                if (!obj) {
@@ -155,12 +172,21 @@ static int load_config(void)
                        break;
                }
 
-               tableptr->usegmtime = usegmtime;
                tableptr->connection = (char *)tableptr + sizeof(*tableptr);
                tableptr->table = (char *)tableptr + sizeof(*tableptr) + lenconnection + 1;
                ast_copy_string(tableptr->connection, connection, lenconnection + 1);
                ast_copy_string(tableptr->table, table, lentable + 1);
 
+               tableptr->usegmtime = 0;
+               if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "usegmtime"))) {
+                       tableptr->usegmtime = ast_true(tmp);
+               }
+
+               tableptr->allowleapsec = 1;
+               if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "allowleapsecond"))) {
+                       tableptr->allowleapsec = ast_true(tmp);
+               }
+
                ast_verb(3, "Found CEL table %s@%s.\n", tableptr->table, tableptr->connection);
 
                /* Check for filters first */
@@ -342,7 +368,7 @@ static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
                                }                                                                                                                               \
                        } while (0)
 
-static void odbc_log(const struct ast_event *event, void *userdata)
+static void odbc_log(struct ast_event *event)
 {
        struct tables *tableptr;
        struct columns *entry;
@@ -388,6 +414,7 @@ static void odbc_log(const struct ast_event *event, void *userdata)
 
                AST_LIST_TRAVERSE(&(tableptr->columns), entry, list) {
                        int datefield = 0;
+                       int unknown = 0;
                        if (strcasecmp(entry->celname, "eventtime") == 0) {
                                datefield = 1;
                        }
@@ -399,7 +426,17 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                struct timeval date_tv = record.event_time;
                                struct ast_tm tm = { 0, };
                                ast_localtime(&date_tv, &tm, tableptr->usegmtime ? "UTC" : NULL);
-                               ast_strftime(colbuf, sizeof(colbuf), "%Y-%m-%d %H:%M:%S", &tm);
+                               /* SQL server 2008 added datetime2 and datetimeoffset data types, that
+                                  are reported to SQLColumns() as SQL_WVARCHAR, according to "Enhanced
+                                  Date/Time Type Behavior with Previous SQL Server Versions (ODBC)".
+                                  Here we format the event time with fraction seconds, so these new
+                                  column types will be set to high-precision event time. However, 'date'
+                                  and 'time' columns, also newly introduced, reported as SQL_WVARCHAR
+                                  too, and insertion of the value formatted here into these will fail.
+                                  This should be ok, however, as nobody is going to store just event
+                                  date or just time for CDR purposes.
+                                */
+                               ast_strftime(colbuf, sizeof(colbuf), "%Y-%m-%d %H:%M:%S.%6q", &tm);
                                colptr = colbuf;
                        } else {
                                if (strcmp(entry->celname, "userdeftype") == 0) {
@@ -437,16 +474,19 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                } else if (strcmp(entry->celname, "peer") == 0) {
                                        ast_copy_string(colbuf, record.peer, sizeof(colbuf));
                                } else if (strcmp(entry->celname, "amaflags") == 0) {
-                                       snprintf(colbuf, sizeof(colbuf), "%d", record.amaflag);
+                                       snprintf(colbuf, sizeof(colbuf), "%u", record.amaflag);
                                } else if (strcmp(entry->celname, "extra") == 0) {
                                        ast_copy_string(colbuf, record.extra, sizeof(colbuf));
+                               } else if (strcmp(entry->celname, "eventtype") == 0) {
+                                       snprintf(colbuf, sizeof(colbuf), "%u", record.event_type);
                                } else {
                                        colbuf[0] = 0;
+                                       unknown = 1;
                                }
                                colptr = colbuf;
                        }
 
-                       if (colptr) {
+                       if (colptr && !unknown) {
                                /* Check first if the column filters this entry.  Note that this
                                 * is very specifically NOT ast_strlen_zero(), because the filter
                                 * could legitimately specify that the field is blank, which is
@@ -468,6 +508,11 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                case SQL_CHAR:
                                case SQL_VARCHAR:
                                case SQL_LONGVARCHAR:
+#ifdef HAVE_ODBC_WCHAR
+                               case SQL_WCHAR:
+                               case SQL_WVARCHAR:
+                               case SQL_WLONGVARCHAR:
+#endif
                                case SQL_BINARY:
                                case SQL_VARBINARY:
                                case SQL_LONGVARBINARY:
@@ -476,7 +521,12 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                         * form (but only when we're dealing with a character-based field).
                                         */
                                        if (strcasecmp(entry->name, "eventtype") == 0) {
-                                               snprintf(colbuf, sizeof(colbuf), "%s", record.event_name);
+                                               const char *event_name;
+
+                                               event_name = (!cel_show_user_def
+                                                       && record.event_type == AST_CEL_USER_DEFINED)
+                                                       ? record.user_defined_name : record.event_name;
+                                               snprintf(colbuf, sizeof(colbuf), "%s", event_name);
                                        }
 
                                        /* Truncate too-long fields */
@@ -507,24 +557,32 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                                continue;
                                        } else {
                                                int year = 0, month = 0, day = 0;
-                                               if (sscanf(colptr, "%4d-%2d-%2d", &year, &month, &day) != 3 || year <= 0 ||
-                                                       month <= 0 || month > 12 || day < 0 || day > 31 ||
-                                                       ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
-                                                       (month == 2 && year % 400 == 0 && day > 29) ||
-                                                       (month == 2 && year % 100 == 0 && day > 28) ||
-                                                       (month == 2 && year % 4 == 0 && day > 29) ||
-                                                       (month == 2 && year % 4 != 0 && day > 28)) {
-                                                       ast_log(LOG_WARNING, "CEL variable %s is not a valid date ('%s').\n", entry->name, colptr);
-                                                       continue;
-                                               }
-
-                                               if (year > 0 && year < 100) {
-                                                       year += 2000;
+                                               if (strcasecmp(entry->name, "eventdate") == 0) {
+                                                       struct ast_tm tm;
+                                                       ast_localtime(&record.event_time, &tm, tableptr->usegmtime ? "UTC" : NULL);
+                                                       year = tm.tm_year + 1900;
+                                                       month = tm.tm_mon + 1;
+                                                       day = tm.tm_mday;
+                                               } else {
+                                                       if (sscanf(colptr, "%4d-%2d-%2d", &year, &month, &day) != 3 || year <= 0 ||
+                                                               month <= 0 || month > 12 || day < 0 || day > 31 ||
+                                                               ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
+                                                               (month == 2 && year % 400 == 0 && day > 29) ||
+                                                               (month == 2 && year % 100 == 0 && day > 28) ||
+                                                               (month == 2 && year % 4 == 0 && day > 29) ||
+                                                               (month == 2 && year % 4 != 0 && day > 28)) {
+                                                               ast_log(LOG_WARNING, "CEL variable %s is not a valid date ('%s').\n", entry->name, colptr);
+                                                               continue;
+                                                       }
+
+                                                       if (year > 0 && year < 100) {
+                                                               year += 2000;
+                                                       }
                                                }
 
                                                ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(17);
-                                               ast_str_append(&sql2, 0, "%s{ d '%04d-%02d-%02d' }", first ? "" : ",", year, month, day);
+                                               ast_str_append(&sql2, 0, "%s{d '%04d-%02d-%02d'}", first ? "" : ",", year, month, day);
                                        }
                                        break;
                                case SQL_TYPE_TIME:
@@ -532,16 +590,24 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                                continue;
                                        } else {
                                                int hour = 0, minute = 0, second = 0;
-                                               int count = sscanf(colptr, "%2d:%2d:%2d", &hour, &minute, &second);
+                                               if (strcasecmp(entry->name, "eventdate") == 0) {
+                                                       struct ast_tm tm;
+                                                       ast_localtime(&record.event_time, &tm, tableptr->usegmtime ? "UTC" : NULL);
+                                                       hour = tm.tm_hour;
+                                                       minute = tm.tm_min;
+                                                       second = (tableptr->allowleapsec || tm.tm_sec < 60) ? tm.tm_sec : 59;
+                                               } else {
+                                                       int count = sscanf(colptr, "%2d:%2d:%2d", &hour, &minute, &second);
 
-                                               if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
-                                                       ast_log(LOG_WARNING, "CEL variable %s is not a valid time ('%s').\n", entry->name, colptr);
-                                                       continue;
+                                                       if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > (tableptr->allowleapsec ? 60 : 59)) {
+                                                               ast_log(LOG_WARNING, "CEL variable %s is not a valid time ('%s').\n", entry->name, colptr);
+                                                               continue;
+                                                       }
                                                }
 
                                                ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
                                                LENGTHEN_BUF2(15);
-                                               ast_str_append(&sql2, 0, "%s{ t '%02d:%02d:%02d' }", first ? "" : ",", hour, minute, second);
+                                               ast_str_append(&sql2, 0, "%s{t '%02d:%02d:%02d'}", first ? "" : ",", hour, minute, second);
                                        }
                                        break;
                                case SQL_TYPE_TIMESTAMP:
@@ -549,38 +615,46 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                        if (ast_strlen_zero(colptr)) {
                                                continue;
                                        } else {
-                                               int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
-                                               int count = sscanf(colptr, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &minute, &second);
-
-                                               if ((count != 3 && count != 5 && count != 6) || year <= 0 ||
-                                                       month <= 0 || month > 12 || day < 0 || day > 31 ||
-                                                       ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
-                                                       (month == 2 && year % 400 == 0 && day > 29) ||
-                                                       (month == 2 && year % 100 == 0 && day > 28) ||
-                                                       (month == 2 && year % 4 == 0 && day > 29) ||
-                                                       (month == 2 && year % 4 != 0 && day > 28) ||
-                                                       hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) {
-                                                       ast_log(LOG_WARNING, "CEL variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
-                                                       continue;
-                                               }
-
-                                               if (year > 0 && year < 100) {
-                                                       year += 2000;
+                                               int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, fraction = 0;
+                                               if (strcasecmp(entry->name, "eventdate") == 0) {
+                                                       struct ast_tm tm;
+                                                       ast_localtime(&record.event_time, &tm, tableptr->usegmtime ? "UTC" : NULL);
+                                                       year = tm.tm_year + 1900;
+                                                       month = tm.tm_mon + 1;
+                                                       day = tm.tm_mday;
+                                                       hour = tm.tm_hour;
+                                                       minute = tm.tm_min;
+                                                       second = (tableptr->allowleapsec || tm.tm_sec < 60) ? tm.tm_sec : 59;
+                                                       fraction = tm.tm_usec;
+                                               } else {
+                                                       int count = sscanf(colptr, "%4d-%2d-%2d %2d:%2d:%2d.%6d", &year, &month, &day, &hour, &minute, &second, &fraction);
+
+                                                       if ((count != 3 && count != 5 && count != 6 && count != 7) || year <= 0 ||
+                                                               month <= 0 || month > 12 || day < 0 || day > 31 ||
+                                                               ((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
+                                                               (month == 2 && year % 400 == 0 && day > 29) ||
+                                                               (month == 2 && year % 100 == 0 && day > 28) ||
+                                                               (month == 2 && year % 4 == 0 && day > 29) ||
+                                                               (month == 2 && year % 4 != 0 && day > 28) ||
+                                                               hour > 23 || minute > 59 || second > (tableptr->allowleapsec ? 60 : 59) || hour < 0 || minute < 0 || second < 0 || fraction < 0) {
+                                                               ast_log(LOG_WARNING, "CEL variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
+                                                               continue;
+                                                       }
+
+                                                       if (year > 0 && year < 100) {
+                                                               year += 2000;
+                                                       }
                                                }
 
                                                ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
-                                               LENGTHEN_BUF2(26);
-                                               ast_str_append(&sql2, 0, "%s{ ts '%04d-%02d-%02d %02d:%02d:%02d' }", first ? "" : ",", year, month, day, hour, minute, second);
+                                               LENGTHEN_BUF2(27);
+                                               ast_str_append(&sql2, 0, "%s{ts '%04d-%02d-%02d %02d:%02d:%02d.%d'}", first ? "" : ",", year, month, day, hour, minute, second, fraction);
                                        }
                                        break;
                                case SQL_INTEGER:
                                        {
                                                int integer = 0;
-                                               if (strcasecmp(entry->name, "eventtype") == 0) {
-                                                       integer = (int) record.event_type;
-                                               } else if (ast_strlen_zero(colptr)) {
-                                                       continue;
-                                               } else if (sscanf(colptr, "%30d", &integer) != 1) {
+                                               if (sscanf(colptr, "%30d", &integer) != 1) {
                                                        ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
                                                        continue;
                                                }
@@ -593,12 +667,9 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                case SQL_BIGINT:
                                        {
                                                long long integer = 0;
-                                               if (strcasecmp(entry->name, "eventtype") == 0) {
-                                                       integer = (long long) record.event_type;
-                                               } else if (ast_strlen_zero(colptr)) {
-                                                       continue;
-                                               } else if (sscanf(colptr, "%30lld", &integer) != 1) {
-                                                       ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
+                                               int ret;
+                                               if ((ret = sscanf(colptr, "%30lld", &integer)) != 1) {
+                                                       ast_log(LOG_WARNING, "CEL variable %s is not an integer. (%d - '%s')\n", entry->name, ret, colptr);
                                                        continue;
                                                }
 
@@ -610,28 +681,20 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                case SQL_SMALLINT:
                                        {
                                                short integer = 0;
-                                               if (strcasecmp(entry->name, "eventtype") == 0) {
-                                                       integer = (short) record.event_type;
-                                               } else if (ast_strlen_zero(colptr)) {
-                                                       continue;
-                                               } else if (sscanf(colptr, "%30hd", &integer) != 1) {
+                                               if (sscanf(colptr, "%30hd", &integer) != 1) {
                                                        ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
                                                        continue;
                                                }
 
                                                ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
-                                               LENGTHEN_BUF2(6);
+                                               LENGTHEN_BUF2(7);
                                                ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
                                        }
                                        break;
                                case SQL_TINYINT:
                                        {
-                                               char integer = 0;
-                                               if (strcasecmp(entry->name, "eventtype") == 0) {
-                                                       integer = (char) record.event_type;
-                                               } else if (ast_strlen_zero(colptr)) {
-                                                       continue;
-                                               } else if (sscanf(colptr, "%30hhd", &integer) != 1) {
+                                               signed char integer = 0;
+                                               if (sscanf(colptr, "%30hhd", &integer) != 1) {
                                                        ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
                                                        continue;
                                                }
@@ -643,12 +706,8 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                        break;
                                case SQL_BIT:
                                        {
-                                               char integer = 0;
-                                               if (strcasecmp(entry->name, "eventtype") == 0) {
-                                                       integer = (char) record.event_type;
-                                               } else if (ast_strlen_zero(colptr)) {
-                                                       continue;
-                                               } else if (sscanf(colptr, "%30hhd", &integer) != 1) {
+                                               signed char integer = 0;
+                                               if (sscanf(colptr, "%30hhd", &integer) != 1) {
                                                        ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
                                                        continue;
                                                }
@@ -664,17 +723,13 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                case SQL_DECIMAL:
                                        {
                                                double number = 0.0;
-                                               if (strcasecmp(entry->name, "eventtype") == 0) {
-                                                       number = (double)record.event_type;
-                                               } else if (ast_strlen_zero(colptr)) {
-                                                       continue;
-                                               } else if (sscanf(colptr, "%30lf", &number) != 1) {
+                                               if (sscanf(colptr, "%30lf", &number) != 1) {
                                                        ast_log(LOG_WARNING, "CEL variable %s is not an numeric type.\n", entry->name);
                                                        continue;
                                                }
 
                                                ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
-                                               LENGTHEN_BUF2(entry->decimals);
+                                               LENGTHEN_BUF2(entry->decimals + 2);
                                                ast_str_append(&sql2, 0, "%s%*.*lf", first ? "" : ",", entry->decimals, entry->radix, number);
                                        }
                                        break;
@@ -683,11 +738,7 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                                case SQL_DOUBLE:
                                        {
                                                double number = 0.0;
-                                               if (strcasecmp(entry->name, "eventtype") == 0) {
-                                                       number = (double) record.event_type;
-                                               } else if (ast_strlen_zero(colptr)) {
-                                                       continue;
-                                               } else if (sscanf(colptr, "%30lf", &number) != 1) {
+                                               if (sscanf(colptr, "%30lf", &number) != 1) {
                                                        ast_log(LOG_WARNING, "CEL variable %s is not an numeric type.\n", entry->name);
                                                        continue;
                                                }
@@ -711,8 +762,7 @@ static void odbc_log(const struct ast_event *event, void *userdata)
                ast_str_append(&sql2, 0, ")");
                ast_str_append(&sql, 0, "%s", ast_str_buffer(sql2));
 
-               ast_verb(11, "[%s]\n", ast_str_buffer(sql));
-
+               ast_debug(3, "Executing SQL statement: [%s]\n", ast_str_buffer(sql));
                stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, ast_str_buffer(sql));
                if (stmt) {
                        SQLRowCount(stmt, &rows);
@@ -740,18 +790,12 @@ early_release:
 
 static int unload_module(void)
 {
-       if (event_sub) {
-               event_sub = ast_event_unsubscribe(event_sub);
-       }
        if (AST_RWLIST_WRLOCK(&odbc_tables)) {
-               event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "ODBC CEL backend", NULL, AST_EVENT_IE_END);
-               if (!event_sub) {
-                       ast_log(LOG_ERROR, "Unable to subscribe to CEL events\n");
-               }
                ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
                return -1;
        }
 
+       ast_cel_backend_unregister(ODBC_BACKEND_NAME);
        free_config();
        AST_RWLIST_UNLOCK(&odbc_tables);
        AST_RWLIST_HEAD_DESTROY(&odbc_tables);
@@ -765,13 +809,13 @@ static int load_module(void)
 
        if (AST_RWLIST_WRLOCK(&odbc_tables)) {
                ast_log(LOG_ERROR, "Unable to lock column list.  Load failed.\n");
-               return 0;
+               return AST_MODULE_LOAD_FAILURE;
        }
        load_config();
        AST_RWLIST_UNLOCK(&odbc_tables);
-       event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "ODBC CEL backend", NULL, AST_EVENT_IE_END);
-       if (!event_sub) {
+       if (ast_cel_backend_register(ODBC_BACKEND_NAME, odbc_log)) {
                ast_log(LOG_ERROR, "Unable to subscribe to CEL events\n");
+               return AST_MODULE_LOAD_FAILURE;
        }
        return AST_MODULE_LOAD_SUCCESS;
 }
@@ -780,7 +824,7 @@ static int reload(void)
 {
        if (AST_RWLIST_WRLOCK(&odbc_tables)) {
                ast_log(LOG_ERROR, "Unable to lock column list.  Reload failed.\n");
-               return -1;
+               return AST_MODULE_LOAD_FAILURE;
        }
 
        free_config();
@@ -789,7 +833,8 @@ static int reload(void)
        return AST_MODULE_LOAD_SUCCESS;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "ODBC CEL backend",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, ODBC_BACKEND_NAME,
+       .support_level = AST_MODULE_SUPPORT_CORE,
        .load = load_module,
        .unload = unload_module,
        .reload = reload,