Index: cel/cel_odbc.c
===================================================================
--- cel/cel_odbc.c	(revision 75)
+++ cel/cel_odbc.c	(working copy)
@@ -40,6 +40,7 @@
 #include <sql.h>
 #include <sqlext.h>
 #include <sqltypes.h>
+#include <sqlucode.h>
 
 #include "asterisk/config.h"
 #include "asterisk/channel.h"
@@ -398,10 +399,22 @@
 				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.%q", &tm);
 				colptr = colbuf;
 			} else {
-				if (strcmp(entry->celname, "userdeftype") == 0) {
+				if (strcmp(entry->celname, "eventtype") == 0) {
+					snprintf(colbuf, sizeof(colbuf), "%d", record.event_type);
+				} else if (strcmp(entry->celname, "userdeftype") == 0) {
 					ast_copy_string(colbuf, record.user_defined_name, sizeof(colbuf));
 				} else if (strcmp(entry->celname, "cid_name") == 0) {
 					ast_copy_string(colbuf, record.caller_id_name, sizeof(colbuf));
@@ -465,6 +478,9 @@
 				case SQL_CHAR:
 				case SQL_VARCHAR:
 				case SQL_LONGVARCHAR:
+				case SQL_WCHAR:
+				case SQL_WVARCHAR:
+				case SQL_WLONGVARCHAR:
 				case SQL_BINARY:
 				case SQL_VARBINARY:
 				case SQL_LONGVARBINARY:
@@ -504,24 +520,32 @@
 						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 (strcasecmp(entry->name, "eventdate") == 0) {
+							struct ast_tm tm;
+							ast_localtime(&record.event_time, &tm, 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;
+							}
 						}
 
-						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);
+						LENGTHEN_BUF2(15);
+						ast_str_append(&sql2, 0, "%s{d '%04d-%02d-%02d'}", first ? "" : ",", year, month, day);
 					}
 					break;
 				case SQL_TYPE_TIME:
@@ -529,16 +553,25 @@
 						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, NULL);
+							hour = tm.tm_hour;
+							minute = tm.tm_min;
+							second = 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 > 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);
+						LENGTHEN_BUF2(16);
+						ast_str_append(&sql2, 0, "%s{t '%02d:%02d:%02d'}", first ? "" : ",", hour, minute, second);
 					}
 					break;
 				case SQL_TYPE_TIMESTAMP:
@@ -547,27 +580,38 @@
 						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 (strcasecmp(entry->name, "eventdate") == 0) {
+							struct ast_tm tm;
+							ast_localtime(&record.event_time, &tm, NULL);
+							year = tm.tm_year + 1900;
+							month = tm.tm_mon + 1;
+							day = tm.tm_mday;
+							hour = tm.tm_hour;
+							minute = tm.tm_min;
+							second = tm.tm_sec < 60 ? tm.tm_sec : 59;
+						} else {
+							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 ((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;
+							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'}", first ? "" : ",", year, month, day, hour, minute, second);
 					}
 					break;
 				case SQL_INTEGER:
@@ -575,11 +619,7 @@
 						continue;
 					} else {
 						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;
 						}
@@ -594,11 +634,7 @@
 						continue;
 					} else {
 						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) {
+						if (sscanf(colptr, "%30lld", &integer) != 1) {
 							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
 							continue;
 						}
@@ -613,17 +649,13 @@
 						continue;
 					} else {
 						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;
@@ -632,11 +664,7 @@
 						continue;
 					} else {
 						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) {
+						if (sscanf(colptr, "%30hhd", &integer) != 1) {
 							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
 							continue;
 						}
@@ -651,11 +679,7 @@
 						continue;
 					} else {
 						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) {
+						if (sscanf(colptr, "%30hhd", &integer) != 1) {
 							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
 							continue;
 						}
@@ -673,17 +697,13 @@
 						continue;
 					} else {
 						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;
@@ -694,11 +714,7 @@
 						continue;
 					} else {
 						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;
 						}
