File freetds-0.82-odbc-csa2.patch of Package freetds
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");