[asterisk-commits] mjordan: branch 12 r411512 - in /branches/12: ./ configs/ include/asterisk/ res/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Mar 28 11:48:40 CDT 2014


Author: mjordan
Date: Fri Mar 28 11:48:32 2014
New Revision: 411512

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=411512
Log:
res_config_odbc/res_odbc: Fix handling of non-text columns updates with empty values.

This patch fixes setting nullable integer columns to NULL instead of an empty
string, which fails for PostgreSQL, for example. The current code is supposed
to do so, but the check is broken. The patch also allows the first column in
the list to be a nullable integer.

This patch also adds a compatibility setting in res_odbc.conf,
allow_empty_string_in_nontext. It is enabled by default. It should be disabled
for database backends (such as PostgreSQL) that require NULL instead of an
empty string for Integer columns.

Review: https://reviewboard.asterisk.org/r/3375

(issue ASTERISK-23459)
Reported by: zvision
patches:
  res_config_odbc.diff uploaded by zvision (License 5755)
........

Merged revisions 411399 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 411408 from http://svn.asterisk.org/svn/asterisk/branches/11

Modified:
    branches/12/   (props changed)
    branches/12/UPGRADE.txt
    branches/12/configs/res_odbc.conf.sample
    branches/12/include/asterisk/res_odbc.h
    branches/12/res/res_config_odbc.c
    branches/12/res/res_odbc.c
    branches/12/res/res_odbc.exports.in

Propchange: branches/12/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Modified: branches/12/UPGRADE.txt
URL: http://svnview.digium.com/svn/asterisk/branches/12/UPGRADE.txt?view=diff&rev=411512&r1=411511&r2=411512
==============================================================================
--- branches/12/UPGRADE.txt (original)
+++ branches/12/UPGRADE.txt Fri Mar 28 11:48:32 2014
@@ -21,6 +21,24 @@
 ===
 ===========================================================
 From 12.1.0 to 12.2.0:
+IAX2:
+ - When communicating with a peer on an Asterisk 1.4 or earlier system, the
+   chan_iax2 parameter 'connectedline' must be set to "no" in iax.conf. This
+   prevents an incompatible connected line frame from an Astersik 1.8 or later
+   system from causing a hangup in an Asterisk 1.4 or earlier system. Note that
+   this particular incompatibility has always existed between 1.4 and 1.8 and
+   later versions; this upgrade note is simply informing users of its existance.
+
+ODBC:
+- A compatibility setting, allow_empty_string_in_nontext, has been added to
+  res_odbc.conf. When enabled (default behavior), empty column values are
+  stored as empty strings during realtime updates. Disabling this option
+  causes empty column values to be stored as NULLs for non-text columns.
+
+  Disable it for PostgreSQL backends in order to avoid errors caused by
+  updating integer columns with an empty string instead of NULL
+  (sipppeers,sipregs)
+
 PJSIP:
  - The PJSIP registrar now stores the contents of the User-Agent header of incoming
    REGISTER requests for each contact that is registered. If using realtime for
@@ -30,14 +48,6 @@
  - PJSIP endpoints now have a "message_context" option that can be used to determine
    where to route incoming MESSAGE requests from the endpoint.
 
-IAX2:
- - When communicating with a peer on an Asterisk 1.4 or earlier system, the
-   chan_iax2 parameter 'connectedline' must be set to "no" in iax.conf. This
-   prevents an incompatible connected line frame from an Astersik 1.8 or later
-   system from causing a hangup in an Asterisk 1.4 or earlier system. Note that
-   this particular incompatibility has always existed between 1.4 and 1.8 and
-   later versions; this upgrade note is simply informing users of its existance.
-
 Realtime Configuration:
  - PJSIP endpoint columns 'tos_audio' and 'tos_video' have been changed from yes/no
    enumerators to string values. 'cos_audio' and 'cos_video' have been changed from
@@ -46,7 +56,7 @@
    a yes/no enumerator to an integer value.
 
 From 12.0.0 to 12.1.0:
-* The sound_place_into_conference sound used in Confbridge is now deprecated
+- The sound_place_into_conference sound used in Confbridge is now deprecated
   and is no longer functional since it has been broken since its inception
   and the fix involved using a different method to achieve the same goal. The
   new method to achieve this functionality is by using sound_begin to play

Modified: branches/12/configs/res_odbc.conf.sample
URL: http://svnview.digium.com/svn/asterisk/branches/12/configs/res_odbc.conf.sample?view=diff&rev=411512&r1=411511&r2=411512
==============================================================================
--- branches/12/configs/res_odbc.conf.sample (original)
+++ branches/12/configs/res_odbc.conf.sample Fri Mar 28 11:48:32 2014
@@ -64,6 +64,14 @@
 ; MS SQL Server, the answer is no.
 ;backslash_is_escape => yes
 ;
+; When enabled (default behavior), empty column values are stored as empty strings
+; during realtime updates. Disabling this option causes empty column values to be
+; stored as NULLs for non-text columns.
+; Disable it for PostgreSQL backend in order to avoid errors caused by updating
+; integer columns with an empty string instead of NULL (sipppeers,sipregs)
+; NOTE: This option will be removed in asterisk 13. At that point, it will always behave as if it was set to 'no'.
+;allow_empty_string_in_nontext => yes
+;
 ; How long (in seconds) should we attempt to connect before considering the
 ; connection dead?  The default is 10 seconds, but you may wish to reduce it,
 ; to increase responsiveness.

Modified: branches/12/include/asterisk/res_odbc.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/res_odbc.h?view=diff&rev=411512&r1=411511&r2=411512
==============================================================================
--- branches/12/include/asterisk/res_odbc.h (original)
+++ branches/12/include/asterisk/res_odbc.h Fri Mar 28 11:48:32 2014
@@ -223,4 +223,10 @@
  */
 SQLRETURN ast_odbc_ast_str_SQLGetData(struct ast_str **buf, int pmaxlen, SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber, SQLSMALLINT TargetType, SQLLEN *StrLen_or_Ind);
 
+/*! \brief Checks if the database natively supports implicit conversion from an empty string to a number (0).
+ * \param obj The ODBC object
+ * \return Returns 1 if the implicit conversion is valid and non-text columns can take empty strings, 0 if the conversion is not valid and NULLs should be used instead '\'
+ */
+int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj);
+
 #endif /* _ASTERISK_RES_ODBC_H */

Modified: branches/12/res/res_config_odbc.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_config_odbc.c?view=diff&rev=411512&r1=411511&r2=411512
==============================================================================
--- branches/12/res/res_config_odbc.c (original)
+++ branches/12/res/res_config_odbc.c Fri Mar 28 11:48:32 2014
@@ -67,6 +67,12 @@
 			memmove(chunk + 1, chunk + 3, strlen(chunk + 3) + 1);
 		}
 	}
+}
+
+static inline int is_text(const struct odbc_cache_columns *column)
+{
+	return column->type == SQL_CHAR || column->type == SQL_VARCHAR || column->type == SQL_LONGVARCHAR
+		|| column->type == SQL_WCHAR || column->type == SQL_WVARCHAR || column->type == SQL_WLONGVARCHAR;
 }
 
 static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
@@ -457,13 +463,13 @@
 	char sql[256];
 	SQLLEN rowcount=0;
 	const struct ast_variable *field = fields;
-	int res, count = 1;
+	int res, count = 0, paramcount = 0;
 	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
 	struct odbc_cache_tables *tableptr;
 	struct odbc_cache_columns *column = NULL;
 	struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
 
-	if (!table || !field) {
+	if (!table || !field || !keyfield) {
 		return -1;
 	}
 
@@ -478,27 +484,30 @@
 		return -1;
 	}
 
-	if (tableptr && !ast_odbc_find_column(tableptr, field->name)) {
-		ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", field->name, table, database);
-	}
-
-	snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, field->name);
+
+	if (tableptr && !ast_odbc_find_column(tableptr, keyfield)) {
+		ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'.  Update will fail\n", keyfield, table, database);
+	}
+
+	snprintf(sql, sizeof(sql), "UPDATE %s SET ", table);
 	while ((field = field->next)) {
-		if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count > 63) {
-			/* NULL test for integer-based columns */
-			if (ast_strlen_zero(field->name) && tableptr && column && column->nullable && count < 64 &&
-				(column->type == SQL_INTEGER || column->type == SQL_BIGINT ||
-				 column->type == SQL_SMALLINT || column->type == SQL_TINYINT ||
-				 column->type == SQL_NUMERIC || column->type == SQL_DECIMAL)) {
-				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=NULL", field->name);
+		if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count >= 64) {
+			if (paramcount++) {
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", ");
+			}
+			/* NULL test for non-text columns */
+			if (count < 64 && ast_strlen_zero(field->value) && column->nullable && !is_text(column) && !ast_odbc_allow_empty_string_in_nontext(obj)) {
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=NULL", field->name);
 				cps.skip |= (1LL << count);
 			} else {
-				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", field->name);
+				/* Value is not an empty string, or column accepts empty strings, or we couldn't fit any more into cps.skip (count >= 64 ?!). */
+				snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", field->name);
 			}
 		} else { /* the column does not exist in the table */
 			cps.skip |= (1LL << count);
 		}
-		count++;
+		++count;
+		field = field->next;
 	}
 	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
 	ast_odbc_release_table(tableptr);

Modified: branches/12/res/res_odbc.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_odbc.c?view=diff&rev=411512&r1=411511&r2=411512
==============================================================================
--- branches/12/res/res_odbc.c (original)
+++ branches/12/res/res_odbc.c Fri Mar 28 11:48:32 2014
@@ -137,6 +137,7 @@
 	unsigned int delme:1;                /*!< Purge the class */
 	unsigned int backslash_is_escape:1;  /*!< On this database, the backslash is a native escape sequence */
 	unsigned int forcecommit:1;          /*!< Should uncommitted transactions be auto-committed on handle release? */
+	unsigned int allow_empty_strings:1;  /*!< Implicit conversion from an empty string to a number is valid for this database */
 	unsigned int isolation;              /*!< Flags for how the DB should deal with data in other, uncommitted transactions */
 	unsigned int limit;                  /*!< Maximum number of database handles we will allow */
 	int count;                           /*!< Running count of pooled connections */
@@ -781,7 +782,7 @@
 	struct ast_variable *v;
 	char *cat;
 	const char *dsn, *username, *password, *sanitysql;
-	int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation;
+	int enabled, pooling, limit, bse, conntimeout, forcecommit, isolation, allow_empty_strings;
 	struct timeval ncache = { 0, 0 };
 	unsigned int idlecheck;
 	int preconnect = 0, res = 0;
@@ -810,6 +811,7 @@
 			bse = 1;
 			conntimeout = 10;
 			forcecommit = 0;
+			allow_empty_strings = 1;
 			isolation = SQL_TXN_READ_COMMITTED;
 			for (v = ast_variable_browse(config, cat); v; v = v->next) {
 				if (!strcasecmp(v->name, "pooling")) {
@@ -845,6 +847,8 @@
 					sanitysql = v->value;
 				} else if (!strcasecmp(v->name, "backslash_is_escape")) {
 					bse = ast_true(v->value);
+				} else if (!strcasecmp(v->name, "allow_empty_string_in_nontext")) {
+					allow_empty_strings = ast_true(v->value);
 				} else if (!strcasecmp(v->name, "connect_timeout")) {
 					if (sscanf(v->value, "%d", &conntimeout) != 1 || conntimeout < 1) {
 						ast_log(LOG_WARNING, "connect_timeout must be a positive integer\n");
@@ -906,6 +910,7 @@
 				new->idlecheck = idlecheck;
 				new->conntimeout = conntimeout;
 				new->negative_connection_cache = ncache;
+				new->allow_empty_strings = allow_empty_strings ? 1 : 0;
 
 				if (cat)
 					ast_copy_string(new->name, cat, sizeof(new->name));
@@ -1121,6 +1126,11 @@
 int ast_odbc_backslash_is_escape(struct odbc_obj *obj)
 {
 	return obj->parent->backslash_is_escape;
+}
+
+int ast_odbc_allow_empty_string_in_nontext(struct odbc_obj *obj)
+{
+	return obj->parent->allow_empty_strings;
 }
 
 static int commit_exec(struct ast_channel *chan, const char *data)

Modified: branches/12/res/res_odbc.exports.in
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_odbc.exports.in?view=diff&rev=411512&r1=411511&r2=411512
==============================================================================
--- branches/12/res/res_odbc.exports.in (original)
+++ branches/12/res/res_odbc.exports.in Fri Mar 28 11:48:32 2014
@@ -2,6 +2,7 @@
 	global:
 		LINKER_SYMBOL_PREFIXast_odbc_ast_str_SQLGetData;
 		LINKER_SYMBOL_PREFIXast_odbc_backslash_is_escape;
+		LINKER_SYMBOL_PREFIXast_odbc_allow_empty_string_in_nontext;
 		LINKER_SYMBOL_PREFIXast_odbc_clear_cache;
 		LINKER_SYMBOL_PREFIXast_odbc_direct_execute;
 		LINKER_SYMBOL_PREFIXast_odbc_find_column;




More information about the asterisk-commits mailing list