From ca9627e70852f6b2e835660df870fe3ab405882d Mon Sep 17 00:00:00 2001
From: "Suren A. Chilingaryan" <csa@suren.me>
Date: Sun, 1 Sep 2019 00:00:32 +0200
Subject: Initial import

---
 .../freetds/files/SQLGetData.utf8.odbc.c-r3.diff   | 196 +++++++++
 dev-db/freetds/files/SQLGetData.utf8.odbc.c.diff   | 199 +++++++++
 dev-db/freetds/files/SQLGetData_cvs.patch          |  67 +++
 dev-db/freetds/files/freetds-0.82-odbc-csa2.patch  | 484 +++++++++++++++++++++
 .../freetds/files/freetds-20080603-odbc-csa2.patch | 404 +++++++++++++++++
 .../freetds/files/freetds-ds-connect_timeout.patch |  12 +
 dev-db/freetds/files/freetds-ds-odbc.patch         | 222 ++++++++++
 7 files changed, 1584 insertions(+)
 create mode 100644 dev-db/freetds/files/SQLGetData.utf8.odbc.c-r3.diff
 create mode 100644 dev-db/freetds/files/SQLGetData.utf8.odbc.c.diff
 create mode 100644 dev-db/freetds/files/SQLGetData_cvs.patch
 create mode 100644 dev-db/freetds/files/freetds-0.82-odbc-csa2.patch
 create mode 100644 dev-db/freetds/files/freetds-20080603-odbc-csa2.patch
 create mode 100644 dev-db/freetds/files/freetds-ds-connect_timeout.patch
 create mode 100644 dev-db/freetds/files/freetds-ds-odbc.patch

(limited to 'dev-db/freetds/files')

diff --git a/dev-db/freetds/files/SQLGetData.utf8.odbc.c-r3.diff b/dev-db/freetds/files/SQLGetData.utf8.odbc.c-r3.diff
new file mode 100644
index 0000000..0039347
--- /dev/null
+++ b/dev-db/freetds/files/SQLGetData.utf8.odbc.c-r3.diff
@@ -0,0 +1,196 @@
+diff -dPNur freetds-0.82/src/odbc/odbc.c freetds-0.82-new-ds/src/odbc/odbc.c
+--- freetds-0.82/src/odbc/odbc.c	2008-05-06 04:57:26.000000000 +0200
++++ freetds-0.82-new-ds/src/odbc/odbc.c	2008-06-25 22:47:06.000000000 +0200
+@@ -4564,6 +4564,9 @@
+ 	SQLLEN dummy_cb;
+ 	int nSybType;
+ 
++	TDS_INT converted_column_cur_size;
++	int extra_bytes = 0;
++
+ 	INIT_HSTMT;
+ 
+ 	tdsdump_log(TDS_DBG_FUNC, "SQLGetData(%p, %u, %d, %p, %d, %p)\n", 
+@@ -4597,46 +4600,154 @@
+ 		ODBC_RETURN(stmt, SQL_ERROR);
+ 	}
+ 	colinfo = resinfo->columns[icol - 1];
++	converted_column_cur_size = colinfo->column_cur_size;
+ 
+ 	if (colinfo->column_cur_size < 0) {
+ 		*pcbValue = SQL_NULL_DATA;
+ 	} else {
++		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
++		if (fCType == SQL_C_DEFAULT)
++			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
++		if (fCType == SQL_ARD_TYPE) {
++			if (icol > stmt->ard->header.sql_desc_count) {
++				odbc_errs_add(&stmt->errs, "07009", NULL);
++				ODBC_RETURN(stmt, SQL_ERROR);
++			}
++			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
++		}
++		assert(fCType);
++
+ 		src = (TDS_CHAR *) colinfo->column_data;
+ 		if (is_variable_type(colinfo->column_type)) {
+-			if (colinfo->column_text_sqlgetdatapos > 0
+-			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+-				ODBC_RETURN(stmt, SQL_NO_DATA);
+-
++			int nread = 0;
++			
+ 			/* 2003-8-29 check for an old bug -- freddy77 */
+ 			assert(colinfo->column_text_sqlgetdatapos >= 0);
+ 			if (is_blob_type(colinfo->column_type))
+ 				src = ((TDSBLOB *) src)->textvalue;
+-			src += colinfo->column_text_sqlgetdatapos;
+-			srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++
++			if (fCType == SQL_C_CHAR) {
++				TDS_CHAR buf[3];
++				SQLLEN len;
++
++				switch (nSybType) {
++				case SYBLONGBINARY:
++				case SYBBINARY:
++				case SYBVARBINARY:
++				case SYBIMAGE:
++				case XSYBBINARY:
++				case XSYBVARBINARY:
++				case TDS_CONVERT_BINARY:
++					if (colinfo->column_text_sqlgetdatapos % 2) {
++						nread = (colinfo->column_text_sqlgetdatapos - 1) / 2;
++						if (nread >= colinfo->column_cur_size)
++							ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++						if (cbValueMax > 2) {
++							len = convert_tds2sql(context, nSybType, src + nread, 1, fCType, buf, sizeof(buf), NULL);
++							if (len < 2) {
++								if (len < 0) 
++									odbc_convert_err_set(&stmt->errs, len);
++								ODBC_RETURN(stmt, SQL_ERROR);
++							}
++							*(TDS_CHAR *) rgbValue = buf[1];
++							*((TDS_CHAR *) rgbValue + 1) = 0;
++						
++							rgbValue++;
++							cbValueMax--;
++						
++							extra_bytes = 1;
++							nread++;
++
++							if (nread >= colinfo->column_cur_size)
++								ODBC_RETURN_(stmt);
++						} else {
++							if (cbValueMax) 
++								*(TDS_CHAR *) rgbValue = 0;
++							odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
++							ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
++						}
++					} else {
++						nread = colinfo->column_text_sqlgetdatapos / 2;
++						
++						if (colinfo->column_text_sqlgetdatapos > 0
++						    && nread >= colinfo->column_cur_size)
++							ODBC_RETURN(stmt, SQL_NO_DATA);
++					}
++					
++					src += nread;
++					srclen = colinfo->column_cur_size - nread;
++					converted_column_cur_size *= 2;
++					break;
++				default:
++					if (colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++					src += colinfo->column_text_sqlgetdatapos;
++					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++
++				}
++			} else if (fCType == SQL_C_BINARY) {
++				switch (nSybType) {
++				case SYBCHAR:
++				case SYBVARCHAR:
++				case SYBTEXT:
++				case XSYBCHAR:
++				case XSYBVARCHAR:
++					nread = (src[0] == '0' && toupper(src[1]) == 'X')? 2 : 0;
++						
++					while ((nread < colinfo->column_cur_size) && (src[nread] == ' ' || src[nread] == '\0')) 
++						nread++;
++
++					nread += colinfo->column_text_sqlgetdatapos * 2;
++					
++					if (nread && nread >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++
++					src += nread;
++					srclen = colinfo->column_cur_size - nread;
++					
++					if (converted_column_cur_size%2)
++						converted_column_cur_size = (converted_column_cur_size + 1) / 2;
++					else
++						converted_column_cur_size /= 2;
++					
++					break;
++				default:
++					if (colinfo->column_text_sqlgetdatapos > 0
++					&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++					src += colinfo->column_text_sqlgetdatapos;
++					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++				}
++			} else {
++				if (colinfo->column_text_sqlgetdatapos > 0
++				&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++					ODBC_RETURN(stmt, SQL_NO_DATA);
++
++				src += colinfo->column_text_sqlgetdatapos;
++				srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++			}
+ 		} else {
+ 			if (colinfo->column_text_sqlgetdatapos > 0
+-			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++			&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+ 				ODBC_RETURN(stmt, SQL_NO_DATA);
+ 
+ 			srclen = colinfo->column_cur_size;
+ 		}
+-		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
+-		if (fCType == SQL_C_DEFAULT)
+-			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
+-		if (fCType == SQL_ARD_TYPE) {
+-			if (icol > stmt->ard->header.sql_desc_count) {
+-				odbc_errs_add(&stmt->errs, "07009", NULL);
+-				ODBC_RETURN(stmt, SQL_ERROR);
+-			}
+-			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
+-		}
+-		assert(fCType);
++
+ 		*pcbValue = convert_tds2sql(context, nSybType, src, srclen, fCType, (TDS_CHAR *) rgbValue, cbValueMax, NULL);
+ 		if (*pcbValue < 0) {
+ 			odbc_convert_err_set(&stmt->errs, *pcbValue);
+ 			ODBC_RETURN(stmt, SQL_ERROR);
+ 		}
+-
++		
++		if (extra_bytes) {
++			colinfo->column_text_sqlgetdatapos += extra_bytes;
++			*pcbValue += extra_bytes;
++		}
++		
+ 		if (is_variable_type(colinfo->column_type) && (fCType == SQL_C_CHAR || fCType == SQL_C_BINARY)) {
+ 			/* calc how many bytes was readed */
+ 			int readed = cbValueMax;
+@@ -4651,7 +4762,7 @@
+ 			if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
+ 				++colinfo->column_text_sqlgetdatapos;
+ 			/* not all readed ?? */
+-			if (colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size) {
++			if (colinfo->column_text_sqlgetdatapos < converted_column_cur_size) {
+ 				odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
+ 				ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
+ 			}
diff --git a/dev-db/freetds/files/SQLGetData.utf8.odbc.c.diff b/dev-db/freetds/files/SQLGetData.utf8.odbc.c.diff
new file mode 100644
index 0000000..91a8fca
--- /dev/null
+++ b/dev-db/freetds/files/SQLGetData.utf8.odbc.c.diff
@@ -0,0 +1,199 @@
+Index: src/odbc/odbc.c
+===================================================================
+RCS file: /cvsroot/freetds/freetds/src/odbc/odbc.c,v
+retrieving revision 1.481
+diff -u -r1.481 odbc.c
+--- src/odbc/odbc.c	5 Jun 2008 16:21:54 -0000	1.481
++++ src/odbc/odbc.c	12 Jun 2008 01:55:58 -0000
+@@ -4644,6 +4646,8 @@
+ 	SQLLEN dummy_cb;
+ 	int nSybType;
+ 
++	int extra_bytes = 0;
++
+ 	INIT_HSTMT;
+ 
+ 	tdsdump_log(TDS_DBG_FUNC, "SQLGetData(%p, %u, %d, %p, %d, %p)\n", 
+@@ -4684,42 +4688,140 @@
+ 	if (colinfo->column_cur_size < 0) {
+ 		*pcbValue = SQL_NULL_DATA;
+ 	} else {
++		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
++		if (fCType == SQL_C_DEFAULT)
++			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
++		if (fCType == SQL_ARD_TYPE) {
++			if (icol > stmt->ard->header.sql_desc_count) {
++				odbc_errs_add(&stmt->errs, "07009", NULL);
++				ODBC_RETURN(stmt, SQL_ERROR);
++			}
++			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
++		}
++		assert(fCType);
++
+ 		src = (TDS_CHAR *) colinfo->column_data;
+ 		if (is_variable_type(colinfo->column_type)) {
+-			if (colinfo->column_text_sqlgetdatapos > 0
+-			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+-				ODBC_RETURN(stmt, SQL_NO_DATA);
+-
++			int nread = 0;
++			
+ 			/* 2003-8-29 check for an old bug -- freddy77 */
+ 			assert(colinfo->column_text_sqlgetdatapos >= 0);
+ 			if (is_blob_type(colinfo->column_type))
+ 				src = ((TDSBLOB *) src)->textvalue;
+-			src += colinfo->column_text_sqlgetdatapos;
+-			srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++
++			if (fCType == SQL_C_CHAR && colinfo->column_text_sqlgetdatapos) {
++				TDS_CHAR buf[3];
++				SQLLEN len;
++
++				switch (nSybType) {
++				case SYBLONGBINARY:
++				case SYBBINARY:
++				case SYBVARBINARY:
++				case SYBIMAGE:
++				case XSYBBINARY:
++				case XSYBVARBINARY:
++				case TDS_CONVERT_BINARY:
++					if (colinfo->column_text_sqlgetdatapos % 2) {
++						nread = (colinfo->column_text_sqlgetdatapos - 1) / 2;
++						if (nread >= colinfo->column_cur_size)
++							ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++						if (cbValueMax > 2) {
++							len = convert_tds2sql(context, nSybType, src + nread, 1, fCType, buf, sizeof(buf), NULL);
++							if (len < 2) {
++								if (len < 0) 
++									odbc_convert_err_set(&stmt->errs, len);
++								ODBC_RETURN(stmt, SQL_ERROR);
++							}
++							*(TDS_CHAR *) rgbValue = buf[1];
++							*((TDS_CHAR *) rgbValue + 1) = 0;
++						
++							rgbValue++;
++							cbValueMax--;
++						
++							extra_bytes = 1;
++							nread++;
++
++							if (nread >= colinfo->column_cur_size)
++								ODBC_RETURN_(stmt);
++						} else {
++							if (cbValueMax) 
++								*(TDS_CHAR *) rgbValue = 0;
++							odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
++							ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
++						}
++					} else {
++						nread = colinfo->column_text_sqlgetdatapos / 2;
++						if (nread >= colinfo->column_cur_size)
++							ODBC_RETURN(stmt, SQL_NO_DATA);
++					}
++					
++					src += nread;
++					srclen = colinfo->column_cur_size - nread;
++					break;
++				default:
++					if (colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++					src += colinfo->column_text_sqlgetdatapos;
++					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++
++				}
++			} else if (fCType == SQL_C_BINARY) {
++				switch (nSybType) {
++				case SYBCHAR:
++				case SYBVARCHAR:
++				case SYBTEXT:
++				case XSYBCHAR:
++				case XSYBVARCHAR:
++					nread = (src[0] == '0' && toupper(src[1]) == 'X')? 2 : 0;
++						
++					while ((nread < colinfo->column_cur_size) && (src[nread] == ' ' || src[nread] == '\0')) 
++						nread++;
++
++					nread += colinfo->column_text_sqlgetdatapos * 2;
++					
++					if (nread && nread >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++
++					src += nread;
++					srclen = colinfo->column_cur_size - nread;
++					break;
++				default:
++					if (colinfo->column_text_sqlgetdatapos > 0
++					&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++					src += colinfo->column_text_sqlgetdatapos;
++					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++				}
++			} else {
++				if (colinfo->column_text_sqlgetdatapos > 0
++				&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++					ODBC_RETURN(stmt, SQL_NO_DATA);
++
++				src += colinfo->column_text_sqlgetdatapos;
++				srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++			}
+ 		} else {
+ 			if (colinfo->column_text_sqlgetdatapos > 0
+-			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++			&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+ 				ODBC_RETURN(stmt, SQL_NO_DATA);
+ 
+ 			srclen = colinfo->column_cur_size;
+ 		}
+-		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
+-		if (fCType == SQL_C_DEFAULT)
+-			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
+-		if (fCType == SQL_ARD_TYPE) {
+-			if (icol > stmt->ard->header.sql_desc_count) {
+-				odbc_errs_add(&stmt->errs, "07009", NULL);
+-				ODBC_RETURN(stmt, SQL_ERROR);
+-			}
+-			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
+-		}
+-		assert(fCType);
++
+ 		*pcbValue = convert_tds2sql(context, nSybType, src, srclen, fCType, (TDS_CHAR *) rgbValue, cbValueMax, NULL);
+ 		if (*pcbValue < 0) {
+ 			odbc_convert_err_set(&stmt->errs, *pcbValue);
+ 			ODBC_RETURN(stmt, SQL_ERROR);
+ 		}
+-
++		
++		if (extra_bytes) {
++			colinfo->column_text_sqlgetdatapos += extra_bytes;
++			*pcbValue += extra_bytes;
++		}
++		
+ 		if (is_variable_type(colinfo->column_type) && (fCType == SQL_C_CHAR || fCType == SQL_C_BINARY)) {
+ 			/* calculate how many bytes were read */
+ 			int remaining = cbValueMax;
+Index: src/odbc/unittests/getdata.c
+===================================================================
+RCS file: /cvsroot/freetds/freetds/src/odbc/unittests/getdata.c,v
+retrieving revision 1.6
+diff -u -r1.6 getdata.c
+--- src/odbc/unittests/getdata.c	29 Jan 2008 14:30:48 -0000	1.6
++++ src/odbc/unittests/getdata.c	12 Jun 2008 01:55:58 -0000
+@@ -11,7 +11,14 @@
+ {
+ 	memset(odbc_err, 0, sizeof(odbc_err));
+ 	memset(odbc_sqlstate, 0, sizeof(odbc_sqlstate));
+-	if (!SQL_SUCCEEDED(SQLGetDiagRec(SQL_HANDLE_STMT, Statement, 1, (SQLCHAR *) odbc_sqlstate, NULL, (SQLCHAR *) odbc_err, sizeof(odbc_err), NULL))) {
++	if (!SQL_SUCCEEDED(SQLGetDiagRec(SQL_HANDLE_STMT
++					, Statement
++					, 1
++					, (SQLCHAR *) odbc_sqlstate
++					, NULL
++					, (SQLCHAR *) odbc_err
++					, sizeof(odbc_err)
++					, NULL))) {
+ 		printf("SQLGetDiagRec should not fail\n");
+ 		exit(1);
+ 	}
diff --git a/dev-db/freetds/files/SQLGetData_cvs.patch b/dev-db/freetds/files/SQLGetData_cvs.patch
new file mode 100644
index 0000000..5631c22
--- /dev/null
+++ b/dev-db/freetds/files/SQLGetData_cvs.patch
@@ -0,0 +1,67 @@
+diff -dPNur freetds-0.82-ds1/src/odbc/odbc.c freetds-0.82-ds2/src/odbc/odbc.c
+--- freetds-0.82-ds1/src/odbc/odbc.c	2008-07-01 19:19:14.000000000 +0200
++++ freetds-0.82-ds2/src/odbc/odbc.c	2008-07-01 19:19:25.000000000 +0200
+@@ -4564,6 +4564,7 @@
+ 	SQLLEN dummy_cb;
+ 	int nSybType;
+ 
++	TDS_INT converted_column_cur_size;
+ 	int extra_bytes = 0;
+ 
+ 	INIT_HSTMT;
+@@ -4599,6 +4600,7 @@
+ 		ODBC_RETURN(stmt, SQL_ERROR);
+ 	}
+ 	colinfo = resinfo->columns[icol - 1];
++	converted_column_cur_size = colinfo->column_cur_size;
+ 
+ 	if (colinfo->column_cur_size < 0) {
+ 		*pcbValue = SQL_NULL_DATA;
+@@ -4624,7 +4626,7 @@
+ 			if (is_blob_type(colinfo->column_type))
+ 				src = ((TDSBLOB *) src)->textvalue;
+ 
+-			if (fCType == SQL_C_CHAR && colinfo->column_text_sqlgetdatapos) {
++			if (fCType == SQL_C_CHAR) {
+ 				TDS_CHAR buf[3];
+ 				SQLLEN len;
+ 
+@@ -4667,12 +4669,15 @@
+ 						}
+ 					} else {
+ 						nread = colinfo->column_text_sqlgetdatapos / 2;
+-						if (nread >= colinfo->column_cur_size)
++						
++						if (colinfo->column_text_sqlgetdatapos > 0
++						    && nread >= colinfo->column_cur_size)
+ 							ODBC_RETURN(stmt, SQL_NO_DATA);
+ 					}
+ 					
+ 					src += nread;
+ 					srclen = colinfo->column_cur_size - nread;
++					converted_column_cur_size *= 2;
+ 					break;
+ 				default:
+ 					if (colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+@@ -4701,6 +4706,12 @@
+ 
+ 					src += nread;
+ 					srclen = colinfo->column_cur_size - nread;
++					
++					if (converted_column_cur_size%2)
++						converted_column_cur_size = (converted_column_cur_size + 1) / 2;
++					else
++						converted_column_cur_size /= 2;
++					
+ 					break;
+ 				default:
+ 					if (colinfo->column_text_sqlgetdatapos > 0
+@@ -4751,7 +4762,7 @@
+ 			if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
+ 				++colinfo->column_text_sqlgetdatapos;
+ 			/* not all readed ?? */
+-			if (colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size) {
++			if (colinfo->column_text_sqlgetdatapos < converted_column_cur_size) {
+ 				odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
+ 				ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
+ 			}
diff --git a/dev-db/freetds/files/freetds-0.82-odbc-csa2.patch b/dev-db/freetds/files/freetds-0.82-odbc-csa2.patch
new file mode 100644
index 0000000..7487c7e
--- /dev/null
+++ b/dev-db/freetds/files/freetds-0.82-odbc-csa2.patch
@@ -0,0 +1,484 @@
+diff -dPNur freetds-0.82/include/tds.h freetds-0.82-new/include/tds.h
+--- freetds-0.82/include/tds.h	2007-12-27 14:45:22.000000000 +0100
++++ freetds-0.82-new/include/tds.h	2008-07-02 22:32:56.000000000 +0200
+@@ -1005,6 +1005,7 @@
+ 	TDS_INT *column_lenbind;
+ 	TDS_INT column_textpos;
+ 	TDS_INT column_text_sqlgetdatapos;
++	TDS_CHAR column_text_sqlputdatainfo;
+ 
+ 	BCPCOLDATA *bcp_column_data;
+ 	/**
+diff -dPNur freetds-0.82/src/odbc/odbc.c freetds-0.82-new/src/odbc/odbc.c
+--- freetds-0.82/src/odbc/odbc.c	2008-05-06 04:57:26.000000000 +0200
++++ freetds-0.82-new/src/odbc/odbc.c	2008-07-02 22:32:56.000000000 +0200
+@@ -4564,6 +4564,9 @@
+ 	SQLLEN dummy_cb;
+ 	int nSybType;
+ 
++	TDS_INT converted_column_cur_size;
++	int extra_bytes = 0;
++
+ 	INIT_HSTMT;
+ 
+ 	tdsdump_log(TDS_DBG_FUNC, "SQLGetData(%p, %u, %d, %p, %d, %p)\n", 
+@@ -4597,46 +4600,120 @@
+ 		ODBC_RETURN(stmt, SQL_ERROR);
+ 	}
+ 	colinfo = resinfo->columns[icol - 1];
++	converted_column_cur_size = colinfo->column_cur_size;
+ 
+ 	if (colinfo->column_cur_size < 0) {
+ 		*pcbValue = SQL_NULL_DATA;
+ 	} else {
++		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
++		if (fCType == SQL_C_DEFAULT)
++			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
++		if (fCType == SQL_ARD_TYPE) {
++			if (icol > stmt->ard->header.sql_desc_count) {
++				odbc_errs_add(&stmt->errs, "07009", NULL);
++				ODBC_RETURN(stmt, SQL_ERROR);
++			}
++			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
++		}
++		assert(fCType);
++
+ 		src = (TDS_CHAR *) colinfo->column_data;
+ 		if (is_variable_type(colinfo->column_type)) {
+-			if (colinfo->column_text_sqlgetdatapos > 0
+-			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+-				ODBC_RETURN(stmt, SQL_NO_DATA);
+-
++			int nread = 0;
++			
+ 			/* 2003-8-29 check for an old bug -- freddy77 */
+ 			assert(colinfo->column_text_sqlgetdatapos >= 0);
+ 			if (is_blob_type(colinfo->column_type))
+ 				src = ((TDSBLOB *) src)->textvalue;
+-			src += colinfo->column_text_sqlgetdatapos;
+-			srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++
++			if (fCType == SQL_C_CHAR) {
++				TDS_CHAR buf[3];
++				SQLLEN len;
++
++				switch (nSybType) {
++				case SYBLONGBINARY:
++				case SYBBINARY:
++				case SYBVARBINARY:
++				case SYBIMAGE:
++				case XSYBBINARY:
++				case XSYBVARBINARY:
++				case TDS_CONVERT_BINARY:
++					if (colinfo->column_text_sqlgetdatapos % 2) {
++						nread = (colinfo->column_text_sqlgetdatapos - 1) / 2;
++						if (nread >= colinfo->column_cur_size)
++							ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++						if (cbValueMax > 2) {
++							len = convert_tds2sql(context, nSybType, src + nread, 1, fCType, buf, sizeof(buf), NULL);
++							if (len < 2) {
++								if (len < 0) 
++									odbc_convert_err_set(&stmt->errs, len);
++								ODBC_RETURN(stmt, SQL_ERROR);
++							}
++							*(TDS_CHAR *) rgbValue = buf[1];
++							*((TDS_CHAR *) rgbValue + 1) = 0;
++						
++							rgbValue++;
++							cbValueMax--;
++						
++							extra_bytes = 1;
++							nread++;
++
++							if (nread >= colinfo->column_cur_size)
++								ODBC_RETURN_(stmt);
++						} else {
++							if (cbValueMax) 
++								*(TDS_CHAR *) rgbValue = 0;
++							odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
++							ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
++						}
++					} else {
++						nread = colinfo->column_text_sqlgetdatapos / 2;
++						
++						if (colinfo->column_text_sqlgetdatapos > 0
++						    && nread >= colinfo->column_cur_size)
++							ODBC_RETURN(stmt, SQL_NO_DATA);
++					}
++					
++					src += nread;
++					srclen = colinfo->column_cur_size - nread;
++					converted_column_cur_size *= 2;
++					break;
++				default:
++					if (colinfo->column_text_sqlgetdatapos > 0
++					&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++					src += colinfo->column_text_sqlgetdatapos;
++					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++				}
++			} else {
++				if (colinfo->column_text_sqlgetdatapos > 0
++				&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++					ODBC_RETURN(stmt, SQL_NO_DATA);
++
++				src += colinfo->column_text_sqlgetdatapos;
++				srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++			}
+ 		} else {
+ 			if (colinfo->column_text_sqlgetdatapos > 0
+-			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++			&&  colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+ 				ODBC_RETURN(stmt, SQL_NO_DATA);
+ 
+ 			srclen = colinfo->column_cur_size;
+ 		}
+-		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
+-		if (fCType == SQL_C_DEFAULT)
+-			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
+-		if (fCType == SQL_ARD_TYPE) {
+-			if (icol > stmt->ard->header.sql_desc_count) {
+-				odbc_errs_add(&stmt->errs, "07009", NULL);
+-				ODBC_RETURN(stmt, SQL_ERROR);
+-			}
+-			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
+-		}
+-		assert(fCType);
++
+ 		*pcbValue = convert_tds2sql(context, nSybType, src, srclen, fCType, (TDS_CHAR *) rgbValue, cbValueMax, NULL);
+ 		if (*pcbValue < 0) {
+ 			odbc_convert_err_set(&stmt->errs, *pcbValue);
+ 			ODBC_RETURN(stmt, SQL_ERROR);
+ 		}
+-
++		
++		if (extra_bytes) {
++			colinfo->column_text_sqlgetdatapos += extra_bytes;
++			*pcbValue += extra_bytes;
++		}
++		
+ 		if (is_variable_type(colinfo->column_type) && (fCType == SQL_C_CHAR || fCType == SQL_C_BINARY)) {
+ 			/* calc how many bytes was readed */
+ 			int readed = cbValueMax;
+@@ -4651,7 +4728,7 @@
+ 			if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
+ 				++colinfo->column_text_sqlgetdatapos;
+ 			/* not all readed ?? */
+-			if (colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size) {
++			if (colinfo->column_text_sqlgetdatapos < converted_column_cur_size) {
+ 				odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
+ 				ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
+ 			}
+diff -dPNur freetds-0.82/src/odbc/prepare_query.c freetds-0.82-new/src/odbc/prepare_query.c
+--- freetds-0.82/src/odbc/prepare_query.c	2007-04-18 16:29:24.000000000 +0200
++++ freetds-0.82-new/src/odbc/prepare_query.c	2008-07-02 22:32:56.000000000 +0200
+@@ -275,21 +275,110 @@
+ 	/* copy to destination */
+ 	if (blob) {
+ 		TDS_CHAR *p;
++		int dest_type, src_type, sql_src_type, res;
++		CONV_RESULT ores;
++		TDS_DBC * dbc = stmt->dbc;
++		void *free_ptr = NULL;
++		int start = 0;
++		SQLPOINTER extradata = NULL;
++		SQLLEN extralen = 0;
++		
++
++		dest_type = odbc_sql_to_server_type(dbc->tds_socket, drec_ipd->sql_desc_concise_type);
++		if (dest_type == TDS_FAIL)
++			return SQL_ERROR;
++			
++		/* get C type */
++		sql_src_type = drec_apd->sql_desc_concise_type;
++		if (sql_src_type == SQL_C_DEFAULT)
++			sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type);
++
++		/* test source type */
++		/* TODO test intervals */
++		src_type = odbc_c_to_server_type(sql_src_type);
++		if (src_type == TDS_FAIL)
++			return SQL_ERROR;
++		
++		if (sql_src_type == SQL_C_CHAR) {
++			switch (tds_get_conversion_type(curcol->column_type, curcol->column_size)) {
++			case SYBBINARY:
++			case SYBVARBINARY:
++			case XSYBBINARY:
++			case XSYBVARBINARY:
++			case SYBLONGBINARY:
++			case SYBIMAGE:
++				if (!*((char*)DataPtr+len-1))
++					--len;
++					
++				if (!len)
++					return SQL_SUCCESS;
++					
++				if (curcol->column_cur_size > 0
++				&&  curcol->column_text_sqlputdatainfo) {
++					TDS_CHAR data[2];
++					data[0] = curcol->column_text_sqlputdatainfo;
++					data[1] = *(char*)DataPtr;
++				    
++					res = tds_convert(dbc->env->tds_ctx, src_type, data, 2, dest_type, &ores);
++					if (res < 0)
++						return SQL_ERROR;
++				    
++					extradata = ores.ib;
++					extralen = res;
++					
++					start = 1;
++					--len;
++				}
++				
++			        if (len&1) {
++					--len;
++					curcol->column_text_sqlputdatainfo = *((char*)DataPtr+len);
++				}
++
++				res = tds_convert(dbc->env->tds_ctx, src_type, DataPtr+start, len, dest_type, &ores);
++				if (res < 0) {
++					if (extradata)
++						free(extradata);
++						
++					return SQL_ERROR;
++				}
++			    
++				DataPtr = free_ptr = ores.ib;
++				len = res;
++				break;
++			}
++		}
+ 
+ 		if (blob->textvalue)
+-			p = (TDS_CHAR *) realloc(blob->textvalue, len + curcol->column_cur_size);
++			p = (TDS_CHAR *) realloc(blob->textvalue, len + extralen + curcol->column_cur_size);
+ 		else {
+ 			assert(curcol->column_cur_size == 0);
+-			p = (TDS_CHAR *) malloc(len);
++			p = (TDS_CHAR *) malloc(len + extralen);
+ 		}
+-		if (!p)
++		if (!p) {
++			if (free_ptr)
++				free(free_ptr);
++			if (extradata)
++				free(extradata);
+ 			return SQL_ERROR;
++		}
+ 		blob->textvalue = p;
++		if (extralen) {
++			memcpy(blob->textvalue + curcol->column_cur_size, extradata, extralen);
++			curcol->column_cur_size += extralen;
++		}
+ 		memcpy(blob->textvalue + curcol->column_cur_size, DataPtr, len);
++		
++		if (extradata)
++			free(extradata);
++		if (free_ptr)
++			free(free_ptr);
+ 	} else {
+ 		memcpy(curcol->column_data + curcol->column_cur_size, DataPtr, len);
+ 	}
++	
+ 	curcol->column_cur_size += len;
++	
+ 	if (blob && curcol->column_cur_size > curcol->column_size)
+ 		curcol->column_size = curcol->column_cur_size;
+ 
+diff -dPNur freetds-0.82/src/odbc/unittests/blob1.c freetds-0.82-new/src/odbc/unittests/blob1.c
+--- freetds-0.82/src/odbc/unittests/blob1.c	2008-01-12 01:21:39.000000000 +0100
++++ freetds-0.82-new/src/odbc/unittests/blob1.c	2008-07-02 22:32:56.000000000 +0200
+@@ -47,6 +47,16 @@
+ 		buf[n] = 'a' + ((start+n) * step % ('z' - 'a' + 1));
+ }
+ 
++static void
++fill_hex(char *buf, size_t len, unsigned int start, unsigned int step)
++{
++	size_t n;
++
++	for (n = 0; n < len; ++n)
++		sprintf(buf + 2*n, "%2x", (unsigned int)('a' + ((start+n) * step % ('z' - 'a' + 1))));
++}
++
++
+ static int
+ check_chars(const char *buf, size_t len, unsigned int start, unsigned int step)
+ {
+@@ -60,6 +70,21 @@
+ }
+ 
+ static int
++check_hex(const char *buf, size_t len, unsigned int start, unsigned int step)
++{
++	size_t n;
++	char symbol[3];
++
++	for (n = 0; n < len; ++n) {
++		sprintf(symbol, "%2x", (unsigned int)('a' + ((start+n) / 2 * step % ('z' - 'a' + 1))));
++		if (buf[n] != symbol[(start+n) % 2])
++			return 0;
++	}
++
++	return 1;
++}
++
++static int
+ readBlob(SQLHSTMT * stmth, SQLUSMALLINT pos)
+ {
+ 	SQLRETURN rcode;
+@@ -93,6 +118,43 @@
+ 	return rcode;
+ }
+ 
++static int
++readBlobAsChar(SQLHSTMT * stmth, SQLUSMALLINT pos, int step)
++{
++	SQLRETURN rcode = SQL_SUCCESS_WITH_INFO;
++	char buf[8192];
++	SQLLEN len, total = 0;
++	int i = 0;
++	int check;
++	int bufsize;
++	
++	if (step%2) bufsize = sizeof(buf) - 1;
++	else bufsize = sizeof(buf);
++
++	printf(">> readBlobAsChar field %d\n", pos);
++	while (rcode == SQL_SUCCESS_WITH_INFO) {
++		i++;
++		rcode = SQLGetData(stmth, pos, SQL_C_CHAR, (SQLPOINTER) buf, (SQLINTEGER) bufsize, &len);
++		if (!SQL_SUCCEEDED(rcode) || len <= 0)
++			break;
++		if (len > (SQLLEN) bufsize)
++			len = (SQLLEN) bufsize - 1;
++		printf(">>     step %d: %d bytes readed\n", i, (int) len);
++		
++		check =	check_hex(buf, len, 2*987 + total, 25);
++		if (!check) {
++			fprintf(stderr, "Wrong buffer content\n");
++			failed = 1;
++		}
++		total += len;
++	}
++	printf(">>   total bytes read = %d \n", (int) total);
++	if (total != 20000)
++		failed = 1;
++	return rcode;
++}
++
++
+ int
+ main(int argc, char **argv)
+ {
+@@ -106,12 +168,14 @@
+ 	SQLLEN vind1;
+ 	char buf2[NBYTES];
+ 	SQLLEN vind2;
++	char buf3[NBYTES*2 + 1];
++	SQLLEN vind3;
+ 	int cnt = 2;
+ 
+ 	use_odbc_version3 = 1;
+ 	Connect();
+ 
+-	Command(Statement, "CREATE TABLE #tt ( k INT, t TEXT, b IMAGE, v INT )");
++	Command(Statement, "CREATE TABLE #tt ( k INT, t TEXT, b1 IMAGE, b2 IMAGE, v INT )");
+ 
+ 	/* Insert rows ... */
+ 
+@@ -121,7 +185,7 @@
+ 		rcode = SQLAllocHandle(SQL_HANDLE_STMT, Connection, &m_hstmt);
+ 		CHECK_RCODE(SQL_HANDLE_DBC, Connection, "SQLAllocHandle StmtH");
+ 
+-		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "INSERT INTO #tt VALUES ( ?, ?, ?, ? )", SQL_NTS);
++		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "INSERT INTO #tt VALUES ( ?, ?, ?, ?, ? )", SQL_NTS);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPrepare");
+ 
+ 		SQLBindParameter(m_hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0);
+@@ -133,9 +197,12 @@
+ 		SQLBindParameter(m_hstmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0x10000000, 0, buf2, 0, &vind2);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindParameter 3");
+ 
+-		SQLBindParameter(m_hstmt, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0);
++		SQLBindParameter(m_hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARBINARY, 0x10000000, 0, buf3, 0, &vind3);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindParameter 4");
+ 
++		SQLBindParameter(m_hstmt, 5, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0);
++		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindParameter 5");
++
+ 		key = i;
+ 		vind0 = 0;
+ 
+@@ -144,6 +211,10 @@
+ 
+ 		fill_chars(buf2, NBYTES, 987, 25);
+ 		vind2 = SQL_LEN_DATA_AT_EXEC(NBYTES);
++		
++		memset(buf3, 0, sizeof(buf3));
++		vind3 = SQL_LEN_DATA_AT_EXEC(2*NBYTES+1);
++		
+ 
+ 		printf(">> insert... %d\n", i);
+ 		rcode = SQLExecute(m_hstmt);
+@@ -155,10 +226,25 @@
+ 			CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLParamData StmtH");
+ 			printf(">> SQLParamData: ptr = %p  rcode = %d\n", (void *) p, rcode);
+ 			if (rcode == SQL_NEED_DATA) {
+-				SQLRETURN rcode = SQLPutData(m_hstmt, p, NBYTES);
++				SQLRETURN rcode;
++				if (p == buf3) {
++					fill_hex(buf3, NBYTES, 987, 25);
++					
++					rcode = SQLPutData(m_hstmt, p, NBYTES - (i&1));
+ 
+-				CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
+-				printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES);
++					CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
++					printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES - (i&1));
++					
++					rcode = SQLPutData(m_hstmt, p + NBYTES - (i&1), NBYTES + (i&1));
++
++					CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
++					printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES + (i&1));
++				} else {
++					rcode = SQLPutData(m_hstmt, p, NBYTES);
++
++					CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
++					printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES);
++				}
+ 			}
+ 		}
+ 
+@@ -182,7 +268,7 @@
+ 			CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLSetStmtAttr SQL_ATTR_CURSOR_SENSITIVITY");
+ 		}
+ 
+-		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "SELECT t, b, v FROM #tt WHERE k = ?", SQL_NTS);
++		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "SELECT t, b1, b2, v FROM #tt WHERE k = ?", SQL_NTS);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPrepare");
+ 
+ 		SQLBindParameter(m_hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &i, 0, &vind0);
+@@ -192,7 +278,9 @@
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 2");
+ 		SQLBindCol(m_hstmt, 2, SQL_C_BINARY, NULL, 0, &vind2);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 3");
+-		SQLBindCol(m_hstmt, 3, SQL_C_LONG, &key, 0, &vind0);
++		SQLBindCol(m_hstmt, 3, SQL_C_BINARY, NULL, 0, &vind3);
++		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 4");
++		SQLBindCol(m_hstmt, 4, SQL_C_LONG, &key, 0, &vind0);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 1");
+ 
+ 		vind0 = 0;
+@@ -210,6 +298,8 @@
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "readBlob 1");
+ 		rcode = readBlob(m_hstmt, 2);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "readBlob 2");
++		rcode = readBlobAsChar(m_hstmt, 3, i);
++		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "readBlob 3 as SQL_C_CHAR");
+ 
+ 		rcode = SQLCloseCursor(m_hstmt);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLCloseCursor StmtH");
diff --git a/dev-db/freetds/files/freetds-20080603-odbc-csa2.patch b/dev-db/freetds/files/freetds-20080603-odbc-csa2.patch
new file mode 100644
index 0000000..1615ddd
--- /dev/null
+++ b/dev-db/freetds/files/freetds-20080603-odbc-csa2.patch
@@ -0,0 +1,404 @@
+diff -dPNur freetds/include/tds.h freetds-ds/include/tds.h
+--- freetds/include/tds.h	2008-06-18 11:06:26.000000000 +0200
++++ freetds-ds/include/tds.h	2008-07-02 22:10:03.000000000 +0200
+@@ -1009,6 +1009,7 @@
+ 	TDS_INT *column_lenbind;
+ 	TDS_INT column_textpos;
+ 	TDS_INT column_text_sqlgetdatapos;
++	TDS_CHAR column_text_sqlputdatainfo;
+ 
+ 	BCPCOLDATA *bcp_column_data;
+ 	/**
+diff -dPNur freetds/src/odbc/odbc.c freetds-ds/src/odbc/odbc.c
+--- freetds/src/odbc/odbc.c	2008-06-18 11:06:26.000000000 +0200
++++ freetds-ds/src/odbc/odbc.c	2008-07-02 22:10:03.000000000 +0200
+@@ -4652,6 +4652,7 @@
+ 	SQLLEN dummy_cb;
+ 	int nSybType;
+ 
++	TDS_INT converted_column_cur_size;
+ 	int extra_bytes = 0;
+ 
+ 	INIT_HSTMT;
+@@ -4690,6 +4691,7 @@
+ 		ODBC_RETURN(stmt, SQL_ERROR);
+ 	}
+ 	colinfo = tds->current_results->columns[icol - 1];
++	converted_column_cur_size = colinfo->column_cur_size;
+ 
+ 	if (colinfo->column_cur_size < 0) {
+ 		*pcbValue = SQL_NULL_DATA;
+@@ -4715,7 +4717,7 @@
+ 			if (is_blob_type(colinfo->column_type))
+ 				src = ((TDSBLOB *) src)->textvalue;
+ 
+-			if (fCType == SQL_C_CHAR && colinfo->column_text_sqlgetdatapos) {
++			if (fCType == SQL_C_CHAR) {
+ 				TDS_CHAR buf[3];
+ 				SQLLEN len;
+ 
+@@ -4758,40 +4760,15 @@
+ 						}
+ 					} else {
+ 						nread = colinfo->column_text_sqlgetdatapos / 2;
+-						if (nread >= colinfo->column_cur_size)
++						
++						if (colinfo->column_text_sqlgetdatapos > 0
++						    && nread >= colinfo->column_cur_size)
+ 							ODBC_RETURN(stmt, SQL_NO_DATA);
+ 					}
+ 					
+ 					src += nread;
+ 					srclen = colinfo->column_cur_size - nread;
+-					break;
+-				default:
+-					if (colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+-						ODBC_RETURN(stmt, SQL_NO_DATA);
+-						
+-					src += colinfo->column_text_sqlgetdatapos;
+-					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
+-
+-				}
+-			} else if (fCType == SQL_C_BINARY) {
+-				switch (nSybType) {
+-				case SYBCHAR:
+-				case SYBVARCHAR:
+-				case SYBTEXT:
+-				case XSYBCHAR:
+-				case XSYBVARCHAR:
+-					nread = (src[0] == '0' && toupper(src[1]) == 'X')? 2 : 0;
+-						
+-					while ((nread < colinfo->column_cur_size) && (src[nread] == ' ' || src[nread] == '\0')) 
+-						nread++;
+-
+-					nread += colinfo->column_text_sqlgetdatapos * 2;
+-					
+-					if (nread && nread >= colinfo->column_cur_size)
+-						ODBC_RETURN(stmt, SQL_NO_DATA);
+-
+-					src += nread;
+-					srclen = colinfo->column_cur_size - nread;
++					converted_column_cur_size *= 2;
+ 					break;
+ 				default:
+ 					if (colinfo->column_text_sqlgetdatapos > 0
+@@ -4842,7 +4819,7 @@
+ 			if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
+ 				++colinfo->column_text_sqlgetdatapos;
+ 			
+-			if (colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size) {	/* not all read ?? */
++			if (colinfo->column_text_sqlgetdatapos < converted_column_cur_size) {	/* not all read ?? */
+ 				odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
+ 				ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
+ 			}
+diff -dPNur freetds/src/odbc/prepare_query.c freetds-ds/src/odbc/prepare_query.c
+--- freetds/src/odbc/prepare_query.c	2007-04-18 16:29:24.000000000 +0200
++++ freetds-ds/src/odbc/prepare_query.c	2008-07-02 22:10:03.000000000 +0200
+@@ -275,21 +275,110 @@
+ 	/* copy to destination */
+ 	if (blob) {
+ 		TDS_CHAR *p;
++		int dest_type, src_type, sql_src_type, res;
++		CONV_RESULT ores;
++		TDS_DBC * dbc = stmt->dbc;
++		void *free_ptr = NULL;
++		int start = 0;
++		SQLPOINTER extradata = NULL;
++		SQLLEN extralen = 0;
++		
++
++		dest_type = odbc_sql_to_server_type(dbc->tds_socket, drec_ipd->sql_desc_concise_type);
++		if (dest_type == TDS_FAIL)
++			return SQL_ERROR;
++			
++		/* get C type */
++		sql_src_type = drec_apd->sql_desc_concise_type;
++		if (sql_src_type == SQL_C_DEFAULT)
++			sql_src_type = odbc_sql_to_c_type_default(drec_ipd->sql_desc_concise_type);
++
++		/* test source type */
++		/* TODO test intervals */
++		src_type = odbc_c_to_server_type(sql_src_type);
++		if (src_type == TDS_FAIL)
++			return SQL_ERROR;
++		
++		if (sql_src_type == SQL_C_CHAR) {
++			switch (tds_get_conversion_type(curcol->column_type, curcol->column_size)) {
++			case SYBBINARY:
++			case SYBVARBINARY:
++			case XSYBBINARY:
++			case XSYBVARBINARY:
++			case SYBLONGBINARY:
++			case SYBIMAGE:
++				if (!*((char*)DataPtr+len-1))
++					--len;
++					
++				if (!len)
++					return SQL_SUCCESS;
++					
++				if (curcol->column_cur_size > 0
++				&&  curcol->column_text_sqlputdatainfo) {
++					TDS_CHAR data[2];
++					data[0] = curcol->column_text_sqlputdatainfo;
++					data[1] = *(char*)DataPtr;
++				    
++					res = tds_convert(dbc->env->tds_ctx, src_type, data, 2, dest_type, &ores);
++					if (res < 0)
++						return SQL_ERROR;
++				    
++					extradata = ores.ib;
++					extralen = res;
++					
++					start = 1;
++					--len;
++				}
++				
++			        if (len&1) {
++					--len;
++					curcol->column_text_sqlputdatainfo = *((char*)DataPtr+len);
++				}
++
++				res = tds_convert(dbc->env->tds_ctx, src_type, DataPtr+start, len, dest_type, &ores);
++				if (res < 0) {
++					if (extradata)
++						free(extradata);
++						
++					return SQL_ERROR;
++				}
++			    
++				DataPtr = free_ptr = ores.ib;
++				len = res;
++				break;
++			}
++		}
+ 
+ 		if (blob->textvalue)
+-			p = (TDS_CHAR *) realloc(blob->textvalue, len + curcol->column_cur_size);
++			p = (TDS_CHAR *) realloc(blob->textvalue, len + extralen + curcol->column_cur_size);
+ 		else {
+ 			assert(curcol->column_cur_size == 0);
+-			p = (TDS_CHAR *) malloc(len);
++			p = (TDS_CHAR *) malloc(len + extralen);
+ 		}
+-		if (!p)
++		if (!p) {
++			if (free_ptr)
++				free(free_ptr);
++			if (extradata)
++				free(extradata);
+ 			return SQL_ERROR;
++		}
+ 		blob->textvalue = p;
++		if (extralen) {
++			memcpy(blob->textvalue + curcol->column_cur_size, extradata, extralen);
++			curcol->column_cur_size += extralen;
++		}
+ 		memcpy(blob->textvalue + curcol->column_cur_size, DataPtr, len);
++		
++		if (extradata)
++			free(extradata);
++		if (free_ptr)
++			free(free_ptr);
+ 	} else {
+ 		memcpy(curcol->column_data + curcol->column_cur_size, DataPtr, len);
+ 	}
++	
+ 	curcol->column_cur_size += len;
++	
+ 	if (blob && curcol->column_cur_size > curcol->column_size)
+ 		curcol->column_size = curcol->column_cur_size;
+ 
+diff -dPNur freetds/src/odbc/unittests/blob1.c freetds-ds/src/odbc/unittests/blob1.c
+--- freetds/src/odbc/unittests/blob1.c	2008-01-12 01:14:11.000000000 +0100
++++ freetds-ds/src/odbc/unittests/blob1.c	2008-07-02 22:09:28.000000000 +0200
+@@ -47,6 +47,16 @@
+ 		buf[n] = 'a' + ((start+n) * step % ('z' - 'a' + 1));
+ }
+ 
++static void
++fill_hex(char *buf, size_t len, unsigned int start, unsigned int step)
++{
++	size_t n;
++
++	for (n = 0; n < len; ++n)
++		sprintf(buf + 2*n, "%2x", (unsigned int)('a' + ((start+n) * step % ('z' - 'a' + 1))));
++}
++
++
+ static int
+ check_chars(const char *buf, size_t len, unsigned int start, unsigned int step)
+ {
+@@ -60,6 +70,21 @@
+ }
+ 
+ static int
++check_hex(const char *buf, size_t len, unsigned int start, unsigned int step)
++{
++	size_t n;
++	char symbol[3];
++
++	for (n = 0; n < len; ++n) {
++		sprintf(symbol, "%2x", (unsigned int)('a' + ((start+n) / 2 * step % ('z' - 'a' + 1))));
++		if (buf[n] != symbol[(start+n) % 2])
++			return 0;
++	}
++
++	return 1;
++}
++
++static int
+ readBlob(SQLHSTMT * stmth, SQLUSMALLINT pos)
+ {
+ 	SQLRETURN rcode;
+@@ -93,6 +118,43 @@
+ 	return rcode;
+ }
+ 
++static int
++readBlobAsChar(SQLHSTMT * stmth, SQLUSMALLINT pos, int step)
++{
++	SQLRETURN rcode = SQL_SUCCESS_WITH_INFO;
++	char buf[8192];
++	SQLLEN len, total = 0;
++	int i = 0;
++	int check;
++	int bufsize;
++	
++	if (step%2) bufsize = sizeof(buf) - 1;
++	else bufsize = sizeof(buf);
++
++	printf(">> readBlobAsChar field %d\n", pos);
++	while (rcode == SQL_SUCCESS_WITH_INFO) {
++		i++;
++		rcode = SQLGetData(stmth, pos, SQL_C_CHAR, (SQLPOINTER) buf, (SQLINTEGER) bufsize, &len);
++		if (!SQL_SUCCEEDED(rcode) || len <= 0)
++			break;
++		if (len > (SQLLEN) bufsize)
++			len = (SQLLEN) bufsize - 1;
++		printf(">>     step %d: %d bytes readed\n", i, (int) len);
++		
++		check =	check_hex(buf, len, 2*987 + total, 25);
++		if (!check) {
++			fprintf(stderr, "Wrong buffer content\n");
++			failed = 1;
++		}
++		total += len;
++	}
++	printf(">>   total bytes read = %d \n", (int) total);
++	if (total != 20000)
++		failed = 1;
++	return rcode;
++}
++
++
+ int
+ main(int argc, char **argv)
+ {
+@@ -106,12 +168,14 @@
+ 	SQLLEN vind1;
+ 	char buf2[NBYTES];
+ 	SQLLEN vind2;
++	char buf3[NBYTES*2 + 1];
++	SQLLEN vind3;
+ 	int cnt = 2;
+ 
+ 	use_odbc_version3 = 1;
+ 	Connect();
+ 
+-	Command(Statement, "CREATE TABLE #tt ( k INT, t TEXT, b IMAGE, v INT )");
++	Command(Statement, "CREATE TABLE #tt ( k INT, t TEXT, b1 IMAGE, b2 IMAGE, v INT )");
+ 
+ 	/* Insert rows ... */
+ 
+@@ -121,7 +185,7 @@
+ 		rcode = SQLAllocHandle(SQL_HANDLE_STMT, Connection, &m_hstmt);
+ 		CHECK_RCODE(SQL_HANDLE_DBC, Connection, "SQLAllocHandle StmtH");
+ 
+-		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "INSERT INTO #tt VALUES ( ?, ?, ?, ? )", SQL_NTS);
++		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "INSERT INTO #tt VALUES ( ?, ?, ?, ?, ? )", SQL_NTS);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPrepare");
+ 
+ 		SQLBindParameter(m_hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0);
+@@ -133,9 +197,12 @@
+ 		SQLBindParameter(m_hstmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0x10000000, 0, buf2, 0, &vind2);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindParameter 3");
+ 
+-		SQLBindParameter(m_hstmt, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0);
++		SQLBindParameter(m_hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARBINARY, 0x10000000, 0, buf3, 0, &vind3);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindParameter 4");
+ 
++		SQLBindParameter(m_hstmt, 5, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &key, 0, &vind0);
++		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindParameter 5");
++
+ 		key = i;
+ 		vind0 = 0;
+ 
+@@ -144,6 +211,10 @@
+ 
+ 		fill_chars(buf2, NBYTES, 987, 25);
+ 		vind2 = SQL_LEN_DATA_AT_EXEC(NBYTES);
++		
++		memset(buf3, 0, sizeof(buf3));
++		vind3 = SQL_LEN_DATA_AT_EXEC(2*NBYTES+1);
++		
+ 
+ 		printf(">> insert... %d\n", i);
+ 		rcode = SQLExecute(m_hstmt);
+@@ -155,10 +226,25 @@
+ 			CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLParamData StmtH");
+ 			printf(">> SQLParamData: ptr = %p  rcode = %d\n", (void *) p, rcode);
+ 			if (rcode == SQL_NEED_DATA) {
+-				SQLRETURN rcode = SQLPutData(m_hstmt, p, NBYTES);
++				SQLRETURN rcode;
++				if (p == buf3) {
++					fill_hex(buf3, NBYTES, 987, 25);
++					
++					rcode = SQLPutData(m_hstmt, p, NBYTES - (i&1));
+ 
+-				CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
+-				printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES);
++					CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
++					printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES - (i&1));
++					
++					rcode = SQLPutData(m_hstmt, p + NBYTES - (i&1), NBYTES + (i&1));
++
++					CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
++					printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES + (i&1));
++				} else {
++					rcode = SQLPutData(m_hstmt, p, NBYTES);
++
++					CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPutData StmtH");
++					printf(">> param %p: total bytes written = %d\n", (void *) p, NBYTES);
++				}
+ 			}
+ 		}
+ 
+@@ -182,7 +268,7 @@
+ 			CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLSetStmtAttr SQL_ATTR_CURSOR_SENSITIVITY");
+ 		}
+ 
+-		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "SELECT t, b, v FROM #tt WHERE k = ?", SQL_NTS);
++		rcode = SQLPrepare(m_hstmt, (SQLCHAR *) "SELECT t, b1, b2, v FROM #tt WHERE k = ?", SQL_NTS);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLPrepare");
+ 
+ 		SQLBindParameter(m_hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &i, 0, &vind0);
+@@ -192,7 +278,9 @@
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 2");
+ 		SQLBindCol(m_hstmt, 2, SQL_C_BINARY, NULL, 0, &vind2);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 3");
+-		SQLBindCol(m_hstmt, 3, SQL_C_LONG, &key, 0, &vind0);
++		SQLBindCol(m_hstmt, 3, SQL_C_BINARY, NULL, 0, &vind3);
++		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 4");
++		SQLBindCol(m_hstmt, 4, SQL_C_LONG, &key, 0, &vind0);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLBindCol 1");
+ 
+ 		vind0 = 0;
+@@ -210,6 +298,8 @@
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "readBlob 1");
+ 		rcode = readBlob(m_hstmt, 2);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "readBlob 2");
++		rcode = readBlobAsChar(m_hstmt, 3, i);
++		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "readBlob 3 as SQL_C_CHAR");
+ 
+ 		rcode = SQLCloseCursor(m_hstmt);
+ 		CHECK_RCODE(SQL_HANDLE_STMT, m_hstmt, "SQLCloseCursor StmtH");
diff --git a/dev-db/freetds/files/freetds-ds-connect_timeout.patch b/dev-db/freetds/files/freetds-ds-connect_timeout.patch
new file mode 100644
index 0000000..013764e
--- /dev/null
+++ b/dev-db/freetds/files/freetds-ds-connect_timeout.patch
@@ -0,0 +1,12 @@
+diff -dPNur freetds-0.82/src/odbc/odbc.c freetds-0.82-ds/src/odbc/odbc.c
+--- freetds-0.82/src/odbc/odbc.c	2008-05-06 04:57:26.000000000 +0200
++++ freetds-0.82-ds/src/odbc/odbc.c	2008-06-26 12:20:43.000000000 +0200
+@@ -312,7 +312,7 @@
+ 
+ 	tds_fix_connection(connection);
+ 
+-	connection->connect_timeout = dbc->attr.connection_timeout;
++	connection->connect_timeout = dbc->attr.login_timeout;
+ 
+ 	if (tds_connect(dbc->tds_socket, connection) == TDS_FAIL) {
+ 		tds_free_socket(dbc->tds_socket);
diff --git a/dev-db/freetds/files/freetds-ds-odbc.patch b/dev-db/freetds/files/freetds-ds-odbc.patch
new file mode 100644
index 0000000..a7b6707
--- /dev/null
+++ b/dev-db/freetds/files/freetds-ds-odbc.patch
@@ -0,0 +1,222 @@
+diff -dPNur freetds-0.82/src/odbc/odbc.c freetds-0.82-new/src/odbc/odbc.c
+--- freetds-0.82/src/odbc/odbc.c	2008-05-06 04:57:26.000000000 +0200
++++ freetds-0.82-new/src/odbc/odbc.c	2008-06-09 13:12:51.000000000 +0200
+@@ -4564,6 +4564,8 @@
+ 	SQLLEN dummy_cb;
+ 	int nSybType;
+ 
++	int extra_bytes = 0;
++
+ 	INIT_HSTMT;
+ 
+ 	tdsdump_log(TDS_DBG_FUNC, "SQLGetData(%p, %u, %d, %p, %d, %p)\n", 
+@@ -4601,18 +4603,117 @@
+ 	if (colinfo->column_cur_size < 0) {
+ 		*pcbValue = SQL_NULL_DATA;
+ 	} else {
++		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
++		if (fCType == SQL_C_DEFAULT)
++			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
++		if (fCType == SQL_ARD_TYPE) {
++			if (icol > stmt->ard->header.sql_desc_count) {
++				odbc_errs_add(&stmt->errs, "07009", NULL);
++				ODBC_RETURN(stmt, SQL_ERROR);
++			}
++			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
++		}
++		assert(fCType);
++
+ 		src = (TDS_CHAR *) colinfo->column_data;
+ 		if (is_variable_type(colinfo->column_type)) {
+-			if (colinfo->column_text_sqlgetdatapos > 0
+-			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+-				ODBC_RETURN(stmt, SQL_NO_DATA);
+-
++			int readed = 0;
++			
+ 			/* 2003-8-29 check for an old bug -- freddy77 */
+ 			assert(colinfo->column_text_sqlgetdatapos >= 0);
+ 			if (is_blob_type(colinfo->column_type))
+ 				src = ((TDSBLOB *) src)->textvalue;
+-			src += colinfo->column_text_sqlgetdatapos;
+-			srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++
++			if ((fCType == SQL_C_CHAR)&&(colinfo->column_text_sqlgetdatapos)) {
++				TDS_CHAR buf[3];
++				SQLLEN len;
++
++				switch (nSybType) {
++				    case SYBLONGBINARY:
++				    case SYBBINARY:
++				    case SYBVARBINARY:
++				    case SYBIMAGE:
++				    case XSYBBINARY:
++				    case XSYBVARBINARY:
++				    case TDS_CONVERT_BINARY:
++					if (colinfo->column_text_sqlgetdatapos%2) {
++					    readed = (colinfo->column_text_sqlgetdatapos - 1) / 2;
++					    if (readed >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++					    
++					    if (cbValueMax > 2) {
++						len = convert_tds2sql(context, nSybType, src + readed, 1, fCType, buf, 3, NULL);
++						if (len < 2) {
++						    if (len < 0) odbc_convert_err_set(&stmt->errs, len);
++						    ODBC_RETURN(stmt, SQL_ERROR);
++						}
++						*(TDS_CHAR *) rgbValue = buf[1];
++						*((TDS_CHAR *) rgbValue + 1) = 0;
++						
++						rgbValue++;
++						cbValueMax--;
++						
++						extra_bytes = 1;
++						readed++;
++
++						if (readed >= colinfo->column_cur_size)
++						    ODBC_RETURN_(stmt);
++					    } else {
++						if (cbValueMax) *(TDS_CHAR *) rgbValue = 0;
++						odbc_errs_add(&stmt->errs, "01004", "String data, right truncated");
++						ODBC_RETURN(stmt, SQL_SUCCESS_WITH_INFO);
++					    }
++					} else {
++					    readed = colinfo->column_text_sqlgetdatapos / 2;
++					    if (readed >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++					}
++					
++					src += readed;
++					srclen = colinfo->column_cur_size - readed;
++				    break;
++				    default:
++					if (colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++					src += colinfo->column_text_sqlgetdatapos;
++					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++
++				}
++			} else if (fCType == SQL_C_BINARY) {
++				switch (nSybType) {
++				    case SYBCHAR:
++				    case SYBVARCHAR:
++				    case SYBTEXT:
++				    case XSYBCHAR:
++				    case XSYBVARCHAR:
++					if (src[0] == '0' && (src[1] == 'x' || src[1] == 'X')) readed = 2;
++					else readed = 0;
++					while ((readed < colinfo->column_cur_size) && (src[readed] == ' ' || src[readed] == '\0')) readed ++;
++					readed += colinfo->column_text_sqlgetdatapos * 2;
++					
++					if ((readed)&&(readed >= colinfo->column_cur_size))
++					    ODBC_RETURN(stmt, SQL_NO_DATA);
++
++					src += readed;
++					srclen = colinfo->column_cur_size - readed;
++				    break;
++				    default:
++					if (colinfo->column_text_sqlgetdatapos > 0
++					    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++						ODBC_RETURN(stmt, SQL_NO_DATA);
++						
++					src += colinfo->column_text_sqlgetdatapos;
++					srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++				}
++			} else {
++			    if (colinfo->column_text_sqlgetdatapos > 0
++				&& colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
++				    ODBC_RETURN(stmt, SQL_NO_DATA);
++
++				src += colinfo->column_text_sqlgetdatapos;
++				srclen = colinfo->column_cur_size - colinfo->column_text_sqlgetdatapos;
++			}
+ 		} else {
+ 			if (colinfo->column_text_sqlgetdatapos > 0
+ 			    && colinfo->column_text_sqlgetdatapos >= colinfo->column_cur_size)
+@@ -4620,23 +4721,18 @@
+ 
+ 			srclen = colinfo->column_cur_size;
+ 		}
+-		nSybType = tds_get_conversion_type(colinfo->column_type, colinfo->column_size);
+-		if (fCType == SQL_C_DEFAULT)
+-			fCType = odbc_sql_to_c_type_default(stmt->ird->records[icol - 1].sql_desc_concise_type);
+-		if (fCType == SQL_ARD_TYPE) {
+-			if (icol > stmt->ard->header.sql_desc_count) {
+-				odbc_errs_add(&stmt->errs, "07009", NULL);
+-				ODBC_RETURN(stmt, SQL_ERROR);
+-			}
+-			fCType = stmt->ard->records[icol - 1].sql_desc_concise_type;
+-		}
+-		assert(fCType);
++
+ 		*pcbValue = convert_tds2sql(context, nSybType, src, srclen, fCType, (TDS_CHAR *) rgbValue, cbValueMax, NULL);
+ 		if (*pcbValue < 0) {
+ 			odbc_convert_err_set(&stmt->errs, *pcbValue);
+ 			ODBC_RETURN(stmt, SQL_ERROR);
+ 		}
+-
++		
++		if (extra_bytes) {
++		    colinfo->column_text_sqlgetdatapos += extra_bytes;
++		    *pcbValue += extra_bytes;
++		}
++		
+ 		if (is_variable_type(colinfo->column_type) && (fCType == SQL_C_CHAR || fCType == SQL_C_BINARY)) {
+ 			/* calc how many bytes was readed */
+ 			int readed = cbValueMax;
+@@ -4644,9 +4740,54 @@
+ 			/* FIXME test on destination char ??? */
+ 			if (stmt->dbc->env->attr.output_nts != SQL_FALSE && fCType == SQL_C_CHAR && readed > 0)
+ 				--readed;
++			
+ 			if (readed > *pcbValue)
+ 				readed = *pcbValue;
++			
+ 			colinfo->column_text_sqlgetdatapos += readed;
++
++/*			
++			if (fCType == SQL_C_CHAR) {
++			    switch (nSybType) {
++				case SYBLONGBINARY:
++				case SYBBINARY:
++				case SYBVARBINARY:
++				case SYBIMAGE:
++				case XSYBBINARY:
++				case XSYBVARBINARY:
++				case TDS_CONVERT_BINARY:
++				    if (readed%2) {
++					readed--;
++					*((TDS_CHAR *)rgbValue + readed) = 0;
++				    }
++				    colinfo->column_text_sqlgetdatapos += readed / 2;
++				break;
++				default:
++				    colinfo->column_text_sqlgetdatapos += readed;
++			    }
++			} else if (fCType == SQL_C_BINARY) {
++			    switch (nSybType) {
++				case SYBCHAR:
++				case SYBVARCHAR:
++				case SYBTEXT:
++				case XSYBCHAR:
++				case XSYBVARCHAR:
++				    if (!colinfo->column_text_sqlgetdatapos) {
++					if (src[0] == '0' && (src[1] == 'x' || src[1] == 'X'))
++					    colinfo->column_text_sqlgetdatapos += 2;
++					
++					while ((colinfo->column_text_sqlgetdatapos < colinfo->column_cur_size) && (src[colinfo->column_text_sqlgetdatapos] == ' ' || src[colinfo->column_text_sqlgetdatapos] == '\0')) 
++					    colinfo->column_text_sqlgetdatapos ++;
++				    }
++				    colinfo->column_text_sqlgetdatapos += readed * 2;
++				break;
++				default:
++				    colinfo->column_text_sqlgetdatapos += readed;
++			    }
++			} else {
++				colinfo->column_text_sqlgetdatapos += readed;
++			}*/
++			
+ 			/* avoid infinite SQL_SUCCESS on empty strings */
+ 			if (colinfo->column_text_sqlgetdatapos == 0 && cbValueMax > 0)
+ 				++colinfo->column_text_sqlgetdatapos;
-- 
cgit v1.2.3