Skip to Content.
Sympa Menu

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

freetds AT lists.ibiblio.org

Subject: FreeTDS Development Group

List archive

Chronological Thread  
  • From: Norbert Matzke <matzke AT geopp.de>
  • To: freetds AT lists.ibiblio.org
  • Subject: [freetds] SQLBindParameter() does not work with UTF-8 ?!
  • Date: Fri, 10 Oct 2008 16:07:08 +0200

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

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)




Archive powered by MHonArc 2.6.24.

Top of Page