El 02/06/14 12:31, Alex Villací­s Lasso escribió:
El 31/05/14 01:30, Daniel-Constantin Mierla escribió:

On 30/05/14 22:02, Alex Villací­s Lasso wrote:
[...] The xml document retrieval is failing again. Now it is because retrieval 
is truncating the MEDIUMTEXT field at 1024 characters:
Adjust the value of parameter:

http://kamailio.org/docs/modules/stable/modules/xcap_server.html#idm7128

Cheers,
Daniel

Did not work. Same symptoms as before.

I see that the file modules/db_unixodbc/connection.h defines a strn structure 
with a hardcoded limit of  STRN_LEN=1024 bytes per field.

_______________________________________________
SIP Express Router (SER) and Kamailio (OpenSER) - sr-users mailing list
sr-users@lists.sip-router.org
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users

I have solved this issue. In order to make it work with unixodbc, I need to apply the attached patch. This patch removes the hardcoded 1024-byte limit for field data that exists in current kamailio-4.1.3. What the patch does is replace the embedded array in the 'struct strn' with a pointer and a field for allocated size. The patch also introduces three functions for manipulation of the modified 'struct strn'. When the SQLGetData function returns SQL_SUCCESS_WITH_INFO, the SQLSTATE is queried for the "data truncated" method. Then the rest of the data is fetched in a loop.

Please review this patch for inclusion. The actual detection of the truncation 
could need some work.

Also, the ODBC implementation could trip on true binary data (containing 
embedded binary zeroes) because it is not binary-safe. Are there scenarios in 
which the rest of Kamailio might need to retrieve or store data with a 
binary-safe implementation?
diff -ur kamailio-4.1.3-bak/modules/db_unixodbc/connection.c kamailio-4.1.3/modules/db_unixodbc/connection.c
--- kamailio-4.1.3-bak/modules/db_unixodbc/connection.c	2014-06-03 12:01:21.612730787 -0500
+++ kamailio-4.1.3/modules/db_unixodbc/connection.c	2014-06-03 12:03:22.394730696 -0500
@@ -223,3 +223,107 @@
 	}
 	while( ret == SQL_SUCCESS );
 }
+
+/*
+ * Allocate a new row of cells, without any data
+ */
+strn * db_unixodbc_new_cellrow(size_t ncols)
+{
+	strn * temp_row;
+	
+	temp_row = (strn *)pkg_malloc(ncols * sizeof(strn));
+	if (temp_row) memset(temp_row, 0, ncols * sizeof(strn));
+	return temp_row;
+}
+
+/*
+ * Free row of cells and all associated memory
+ */
+void db_unixodbc_free_cellrow(size_t ncols, strn * row)
+{
+	size_t i;
+	
+	for (i = 0; i < ncols; i++) {
+		if (row[i].s != NULL) pkg_free(row[i].s);
+	}
+	pkg_free(row);
+}
+
+/*
+ * Load ODBC cell data into a single cell
+ */
+void db_unixodbc_load_cell(const db1_con_t* _h, int colindex, strn * cell)
+{
+	SQLRETURN ret = 0;
+
+	do {
+		SQLLEN indicator;
+		int chunklen;
+		char * s;	/* Pointer to available area for next chunk */
+		char * ns;
+
+		if (cell->buflen > 0) {
+			ns = (char *)pkg_realloc(cell->s, cell->buflen + STRN_LEN);
+			if (ns == NULL) {
+				LM_ERR("no memory left\n");
+				return;
+			}
+			cell->s = ns;
+
+			/* Overwrite the previous null terminator */
+			s = cell->s + cell->buflen - 1;
+			chunklen = STRN_LEN + 1;
+		} else {
+			ns = (char *)pkg_malloc(STRN_LEN);
+			if (ns == NULL) {
+				LM_ERR("no memory left\n");
+				return;
+			}
+			cell->s = ns;
+			s = cell->s;
+			chunklen = STRN_LEN;
+		}
+		cell->buflen += STRN_LEN;
+		
+		ret = SQLGetData(CON_RESULT(_h), colindex, SQL_C_CHAR,
+					s, chunklen, &indicator);
+		if (ret == SQL_SUCCESS) {
+			if (indicator == SQL_NULL_DATA) strcpy(cell->s, "NULL");
+		} else if (ret == SQL_SUCCESS_WITH_INFO) {
+			SQLINTEGER   i = 0;
+			SQLINTEGER   native;
+			SQLCHAR  state[ 7 ];
+			SQLCHAR  text[256];
+			SQLSMALLINT  len;
+			SQLRETURN	ret2;
+
+			/* Check whether field data was truncated */
+			do
+			{
+				ret2 = SQLGetDiagRec(SQL_HANDLE_STMT, CON_RESULT(_h), ++i, state, &native, text,
+					sizeof(text), &len );
+				if (SQL_SUCCEEDED(ret2)) {
+					if (!strcmp("00000", state)) break;
+					if (strcmp("01004", state) != 0) {
+						/* Not a string truncation */
+						LM_ERR("SQLGetData failed unixodbc:  =%s:%ld:%ld:%s\n", state, (long)i, 
+							(long)native, text);
+						return;
+					}
+				} else if (ret2 == SQL_NO_DATA) {
+					break;
+				} else {
+					/* Failed to get diagnostics */
+					LM_ERR("SQLGetData failed, failed to get diagnostics (ret2=%d i=%d)\n",
+						ret2, i);
+					return;
+				}
+			}
+			while( ret2 == SQL_SUCCESS );
+		} else {
+			LM_ERR("SQLGetData failed\n");
+		}
+	} while (ret == SQL_SUCCESS_WITH_INFO);
+}
+
+
diff -ur kamailio-4.1.3-bak/modules/db_unixodbc/connection.h kamailio-4.1.3/modules/db_unixodbc/connection.h
--- kamailio-4.1.3-bak/modules/db_unixodbc/connection.h	2014-06-03 12:01:21.612730787 -0500
+++ kamailio-4.1.3/modules/db_unixodbc/connection.h	2014-06-03 12:00:42.893730815 -0500
@@ -47,7 +47,8 @@
 
 typedef struct strn
 {
-	char s[STRN_LEN];
+	unsigned int buflen;
+	char *s;
 } strn;
 
 
@@ -90,4 +91,19 @@
 
 void db_unixodbc_extract_error(const char *fn, const SQLHANDLE handle, const SQLSMALLINT type, char* stret);
 
+/*
+ * Allocate a new row of cells, without any data
+ */
+strn * db_unixodbc_new_cellrow(size_t ncols);
+
+/*
+ * Free row of cells and all associated memory
+ */
+void db_unixodbc_free_cellrow(size_t ncols, strn * row);
+
+/*
+ * Load ODBC cell data into a single cell
+ */
+void db_unixodbc_load_cell(const db1_con_t* _h, int colindex, strn * cell);
+
 #endif  /* MY_CON_H */
diff -ur kamailio-4.1.3-bak/modules/db_unixodbc/dbase.c kamailio-4.1.3/modules/db_unixodbc/dbase.c
--- kamailio-4.1.3-bak/modules/db_unixodbc/dbase.c	2014-06-03 12:01:21.616730787 -0500
+++ kamailio-4.1.3/modules/db_unixodbc/dbase.c	2014-06-03 12:00:42.899730815 -0500
@@ -321,18 +321,10 @@
 
 	SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns);
 
-	/* Allocate a temporary row */
-	temp_row = (strn*)pkg_malloc( columns*sizeof(strn) );
-	if(!temp_row) {
-		LM_ERR("no private memory left\n");
-		return -1;
-	}
-
 	/* Now fetch nrows at most */
 	len = sizeof(db_row_t) * nrows;
 	RES_ROWS(*_r) = (struct db_row*)pkg_malloc(len);
 	if (!RES_ROWS(*_r)) {
-		pkg_free(temp_row);
 		LM_ERR("no memory left\n");
 		return -5;
 	}
@@ -340,20 +332,20 @@
 
 	LM_DBG("Now fetching %i rows at most\n", nrows);
 	while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h)))) {
+		/* Allocate a temporary row */
+		temp_row = db_unixodbc_new_cellrow(columns);
+		if (!temp_row) {
+			LM_ERR("no private memory left\n");
+			pkg_free(RES_ROWS(*_r));
+			pkg_free(*_r);
+			*_r = 0;
+			return -1;
+		}		
+		
 		LM_DBG("fetching %d columns for row %d...\n",columns, row_n);
 		for(i=0; i < columns; i++) {
-			SQLLEN indicator;
 			LM_DBG("fetching column %d\n",i);
-
-			ret = SQLGetData(CON_RESULT(_h), i+1, SQL_C_CHAR,
-					temp_row[i].s, STRN_LEN, &indicator);
-
-			if (SQL_SUCCEEDED(ret)) {
-				if (indicator == SQL_NULL_DATA)
-					strcpy(temp_row[i].s, "NULL");
-			} else {
-				LM_ERR("SQLGetData failed\n");
-			}
+			db_unixodbc_load_cell(_h, i+1, temp_row + i);
 		}
 
 		LM_DBG("got temp_row at %p\n", temp_row);
@@ -361,22 +353,23 @@
 		if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) {
 			LM_ERR("SQL result row insert failed\n");
 			pkg_free(RES_ROWS(*_r));
-			pkg_free(temp_row);
-			temp_row= NULL;
+			db_unixodbc_free_cellrow(columns, temp_row);
 			pkg_free(*_r);
 			*_r = 0;
 			return -5;
 		}
 
+		/* Free temporary row data */
+		LM_DBG("freeing temp_row at %p\n", temp_row);
+		db_unixodbc_free_cellrow(columns, temp_row);
+		temp_row = NULL;
+
 		row_n++;
 		if (row_n == nrows) {
 			break;
 		}
 	}
 	
-	/* Free temporary row data */
-	LM_DBG("freeing temp_row at %p\n", temp_row);
-	pkg_free(temp_row);
 	CON_ROW(_h) = NULL;
 
 	RES_ROW_N(*_r) = row_n;
diff -ur kamailio-4.1.3-bak/modules/db_unixodbc/res.c kamailio-4.1.3/modules/db_unixodbc/res.c
--- kamailio-4.1.3-bak/modules/db_unixodbc/res.c	2014-06-03 12:01:21.619730786 -0500
+++ kamailio-4.1.3/modules/db_unixodbc/res.c	2014-06-03 12:00:42.904730814 -0500
@@ -178,38 +178,31 @@
 	}
 
 	SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns);
-	temp_row = (strn*)pkg_malloc( columns*sizeof(strn) );
-	if(!temp_row) {
-		LM_ERR("no private memory left\n");
-		return -1;
-	}
 
 	while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h))))
 	{
+		temp_row = db_unixodbc_new_cellrow(columns);
+		if (!temp_row) {
+			LM_ERR("no private memory left\n");
+			return -1;
+		}		
+
 		for(i=0; i < columns; i++)
 		{
-			SQLLEN indicator;
-			ret = SQLGetData(CON_RESULT(_h), i+1, SQL_C_CHAR,
-				temp_row[i].s, STRN_LEN, &indicator);
-			if (SQL_SUCCEEDED(ret)) {
-				if (indicator == SQL_NULL_DATA)
-					strcpy(temp_row[i].s, "NULL");
-			}
-			else {
-				LM_ERR("SQLGetData failed\n");
-			}
+			db_unixodbc_load_cell(_h, i+1, temp_row + i);
 		}
 
 		if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) {
 			LM_ERR("insert failed\n");
-			pkg_free(temp_row);
-			temp_row= NULL;
+			db_unixodbc_free_cellrow(columns, temp_row);
 			return -5;
 		}
 		RES_ROW_N(_r)++;
+
+		/* free temporary row data */
+		db_unixodbc_free_cellrow(columns, temp_row);
+		temp_row = NULL;
 	}
-	/* free temporary row data */
-	pkg_free(temp_row);
 	CON_ROW(_h) = NULL;
 
 	if (!RES_ROW_N(_r)) {
_______________________________________________
SIP Express Router (SER) and Kamailio (OpenSER) - sr-users mailing list
sr-users@lists.sip-router.org
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-users

Reply via email to