SQLBindParameter() does not work with UTF-8 ?!

Norbert Matzke <[email protected]>
Newsgroups gmane.comp.db.tds.freetds
Message-ID <[email protected]>
Problem: My client ODBC application needs to bind parameters which are
UTF-8 encoded to SQL insert/update statements.
I have set ClientCharset to UTF-8 in freetds.conf.

I did some tests with Version 0.82 of FreeTDS and SQL Server 2005.
Seemed to work, but not with a short UTF-8 String like '€'.
'€' is 3 bytes long in UTF-8 encoding.

If I called
SQLBindParameter( , ,SQL_C_CHAR, SQL_WVARCHAR, n, 0, , , &ind )
with n=1 and *ind=3 I got an error message. iconv was not able to
convert '€' and SQL Server complains also ...

Calling with n=3 and *ind=3 succeeds but inserts the string '€  ' into
the database because the Server pads with 2 blanks to the requested size
of 3 CHARS.

Setting *ind=SQL_NTS did not help.

I have tested version 0.83dev 2008-10-09 also: It did not work at
all using UTF-8 strings with non single byte UTF-8 characters.

So I have had a look at what is going on inside the FreeTDS code
(ver. 0.83dev) and found that the problem arises due to insufficient
buffer space for the bounded parameter.

I solved the problem with very small changes to tds/mem.c and
odbc/sql2tds.c (see attached patch). For me it works now.

Any comments on this issue ?

Best regards,
Norbert

_______________________________________________
FreeTDS mailing list
[email protected]
http://lists.ibiblio.org/mailman/listinfo/freetds
patch_freetds_0.83dev20081009.diff (text/x-patch, 2.1 KB)
diff -r -b -B -U 5 freetds-0.83.dev.20081009/src/odbc/sql2tds.c freetds-0.83.dev.20081009_patched/src/odbc/sql2tds.c
--- freetds-0.83.dev.20081009/src/odbc/sql2tds.c	2008-09-11 17:09:50.000000000 +0200
+++ freetds-0.83.dev.20081009_patched/src/odbc/sql2tds.c	2008-10-10 14:42:35.000000000 +0200
@@ -296,10 +296,17 @@
 			curcol->column_cur_size = -1;
 			return SQL_SUCCESS;
 		}
 	}
 
+	/* will be re-set after tds_convert(), but we need enough space for utf-8 strings and
+	   column_size is currently set to SQLBindParmeter::ColumnSize, which is the number
+	   of displayable/encoded chars in case of NVARCHAR, ... columns, not the number of utf-8 bytes !
+	   tds_alloc_param() changed to allocate max( column_size, column_cur_size )
+	 */
+	if (len > 0) curcol->column_cur_size = len;
+
 	/* allocate given space */
 	if (!tds_alloc_param_data(curcol)) {
 		odbc_errs_add(&stmt->errs, "HY001", NULL);
 		return SQL_ERROR;
 	}
@@ -348,14 +355,12 @@
 	case XSYBVARCHAR:
 	case XSYBNVARCHAR:
 	case XSYBNCHAR:
 	case SYBNVARCHAR:
 		ores.cc.c = (TDS_CHAR*) dest;
-		ores.cc.len = curcol->column_size;
+		ores.cc.len = curcol->column_cur_size;  /* see modified tds_alloc_param_data() */
 		res = tds_convert(dbc->env->tds_ctx, src_type, src, len, TDS_CONVERT_CHAR, &ores);
-		if (res > curcol->column_size)
-			res = curcol->column_size;
 		break;
 	case SYBBINARY:
 	case SYBVARBINARY:
 	case XSYBBINARY:
 	case XSYBVARBINARY:

diff -r -b -B -U 5 freetds-0.83.dev.20081009/src/tds/mem.c freetds-0.83.dev.20081009_patched/src/tds/mem.c
--- freetds-0.83.dev.20081009/src/tds/mem.c	2008-09-14 09:45:25.000000000 +0200
+++ freetds-0.83.dev.20081009_patched/src/tds/mem.c	2008-10-10 13:47:41.000000000 +0200
@@ -274,11 +274,12 @@
 	if (is_numeric_type(curparam->column_type)) {
 		data_size = sizeof(TDS_NUMERIC);
 	} else if (is_blob_type(curparam->column_type)) {
 		data_size = sizeof(TDSBLOB);
 	} else {
-		data_size = curparam->column_size;
+		data_size = curparam->column_cur_size > curparam->column_size ?
+					curparam->column_cur_size : curparam->column_size;
 	}
 
 
 	/* allocate data */
 	if (curparam->column_data && curparam->column_data_free)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.