Re: FreeTDS 1.0 Release Candidate 1 is out!
Richard Hughes <[email protected]>
| Newsgroups | gmane.comp.db.tds.freetds |
|---|---|
| Message-ID | <[email protected]> |
On Sun, 17 Apr 2016 19:37:41 +0100, Frediano Ziglio wrote: > - ODBC BCP support; On that subject, I found a couple of bugs in my code - fixes are in the attached. Sorry for being so late giving them to you. Note that I haven't tested the change to src/dblib/bcp.c - it just looked like the right thing to do. Richard. _______________________________________________ FreeTDS mailing list [email protected] http://lists.ibiblio.org/mailman/listinfo/freetds
0001-fix-bugs-in-ODBC-BCP-and-augment-unit-tests-accordin.patch
(application/octet-stream, 7.8 KB)
From 45c1d2ad92ec9ed2b4006dd845e0fdede0c8e30c Mon Sep 17 00:00:00 2001 From: Richard Hughes <[email protected]> Date: Mon, 18 Apr 2016 14:55:50 +0100 Subject: [PATCH] fix bugs in ODBC BCP, and augment unit tests accordingly: incorrect assert fired when inserting a zero-character string. 'prefixlen' parameter to bcp_bind() was totally non-functional (this problem also affected the original dblib code from which this code was derived). --- src/dblib/bcp.c | 1 + src/odbc/bcp.c | 2 +- src/odbc/unittests/bcp.c | 69 +++++++++++++++++++++++++++++------------------- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/dblib/bcp.c b/src/dblib/bcp.c index a8b554c..f86c8da 100644 --- a/src/dblib/bcp.c +++ b/src/dblib/bcp.c @@ -2075,6 +2075,7 @@ bcp_bind(DBPROCESS * dbproc, BYTE * varaddr, int prefixlen, DBINT varlen, colinfo->column_varaddr = (char *)varaddr; colinfo->column_bindtype = vartype; colinfo->column_bindlen = varlen; + colinfo->bcp_prefix_len = prefixlen; TDS_ZERO_FREE(colinfo->bcp_terminator); colinfo->bcp_term_len = 0; diff --git a/src/odbc/bcp.c b/src/odbc/bcp.c index c433bcf..cbd22ea 100644 --- a/src/odbc/bcp.c +++ b/src/odbc/bcp.c @@ -390,6 +390,7 @@ odbc_bcp_bind(TDS_DBC *dbc, const BYTE * varaddr, int prefixlen, int varlen, colinfo->column_varaddr = (char *)varaddr; colinfo->column_bindtype = vartype; colinfo->column_bindlen = varlen; + colinfo->bcp_prefix_len = prefixlen; TDS_ZERO_FREE(colinfo->bcp_terminator); colinfo->bcp_term_len = 0; @@ -634,7 +635,6 @@ _bcp_get_col_data(TDSBCPINFO *bcpinfo, TDSCOLUMN *bindcol, int offset) bindcol->bcp_column_data->datalen = converted_data_size; bindcol->bcp_column_data->is_null = 0; - assert(converted_data_size > 0); } return TDS_SUCCESS; diff --git a/src/odbc/unittests/bcp.c b/src/odbc/unittests/bcp.c index 5e896ee..2a96e9d 100644 --- a/src/odbc/unittests/bcp.c +++ b/src/odbc/unittests/bcp.c @@ -9,24 +9,34 @@ typedef SQLWCHAR bcp_init_char_t; typedef char bcp_init_char_t; #endif +struct prefixed_int { + ODBCINT64 prefix; + int value; +}; +struct prefixed_str { + ODBCINT64 prefix; + char value[64]; +}; + /* * Static data for insertion */ -static int not_null_bit = 1; -static char not_null_char[] = "a char"; -static char not_null_varchar[] = "a varchar"; -static char not_null_datetime[] = "2003-12-17 15:44:00.000"; -static char not_null_smalldatetime[] = "2003-12-17 15:44:00"; -static char not_null_money[] = "12.34"; -static char not_null_smallmoney[] = "12.34"; -static char not_null_float[] = "12.34"; -static char not_null_real[] = "12.34"; -static char not_null_decimal[] = "12.34"; -static char not_null_numeric[] = "12.34"; -static int not_null_int = 1234; -static int not_null_smallint = 1234; -static int not_null_tinyint = 123; -static char not_null_nvarchar[] = "a wide var"; +static struct prefixed_int not_null_bit = {4, 1}; +static struct prefixed_str not_null_char = {64, "a char"}; +static struct prefixed_str not_null_varchar = {64, "a varchar"}; +static struct prefixed_str not_null_datetime = {64, "2003-12-17 15:44:00.000"}; +static struct prefixed_str not_null_smalldatetime = {64, "2003-12-17 15:44:00"}; +static struct prefixed_str not_null_money = {64, "12.34"}; +static struct prefixed_str not_null_smallmoney = {64, "12.34"}; +static struct prefixed_str not_null_float = {64, "12.34"}; +static struct prefixed_str not_null_real = {64, "12.34"}; +static struct prefixed_str not_null_decimal = {64, "12.34"}; +static struct prefixed_str not_null_numeric = {64, "12.34"}; +static struct prefixed_int not_null_int = {4, 1234}; +static struct prefixed_int not_null_smallint = {4, 1234}; +static struct prefixed_int not_null_tinyint = {4, 123}; +static struct prefixed_str not_null_nvarchar = {64, "a wide var"}; +static ODBCINT64 null_prefix = -1; static const char *expected[] = { "1", @@ -42,6 +52,7 @@ static const char *expected_special[] = { "2015-03-14 15:26:53.589793", "3.141593000", "3.141593", /* MS driver has "3141593" here. Bug? Should we be bug-compatible? */ + "", }; static int tds_version; @@ -115,25 +126,24 @@ init(void) "dt2 datetime2(6) not null," "num decimal(19,9) not null," "numstr varchar(64) not null," + "empty varchar(64) not null," "bitnull bit null" ")"); } #define VARCHAR_BIND(x) \ - bcp_bind( odbc_conn, (unsigned char *) &x, prefixlen, strlen(x), NULL, termlen, BCP_TYPE_SQLVARCHAR, col++ ) + bcp_bind( odbc_conn, (unsigned char *) (prefixlen == 0 ? (void*)&x.value : &x), prefixlen, strlen(x.value), NULL, termlen, BCP_TYPE_SQLVARCHAR, col++ ) #define INT_BIND(x) \ - bcp_bind( odbc_conn, (unsigned char *) &x, prefixlen, SQL_VARLEN_DATA, NULL, termlen, BCP_TYPE_SQLINT4, col++ ) + bcp_bind( odbc_conn, (unsigned char *) (prefixlen == 0 ? (void*)&x.value : &x), prefixlen, SQL_VARLEN_DATA, NULL, termlen, BCP_TYPE_SQLINT4, col++ ) #define NULL_BIND(x, type) \ - bcp_bind( odbc_conn, (unsigned char *) &x, prefixlen, SQL_NULL_DATA, NULL, termlen, type, col++ ) + bcp_bind( odbc_conn, (unsigned char *) (prefixlen == 0 ? (void*)&x.value : &null_prefix), prefixlen, prefixlen == 0 ? SQL_NULL_DATA : SQL_VARLEN_DATA, NULL, termlen, type, col++ ) static void -test_bind(void) +test_bind(int prefixlen) { - enum { prefixlen = 0 }; enum { termlen = 0 }; - enum NullValue { IsNull, IsNotNull }; RETCODE fOK; int col=1; @@ -227,7 +237,7 @@ report_bcp_error(const char *errmsg, int line, const char *file) odbc_report_error(errmsg, line, file); } -static void normal_inserts(void); +static void normal_inserts(int prefixlen); static void normal_select(void); static void special_inserts(void); static void special_select(void); @@ -246,13 +256,17 @@ main(int argc, char *argv[]) init(); - normal_inserts(); + normal_inserts(0); if (tds_version >= 0x703) special_inserts(); normal_select(); if (tds_version >= 0x703) special_select(); + odbc_command("delete from all_types_bcp_unittest"); + normal_inserts(8); + normal_select(); + if ((s = getenv("BCP")) != NULL && 0 == strcmp(s, "nodrop")) { fprintf(stdout, "BCP=nodrop: '%s' kept\n", table_name); } else { @@ -268,7 +282,7 @@ main(int argc, char *argv[]) return 0; } -static void normal_inserts(void) +static void normal_inserts(int prefixlen) { int i; int rows_sent; @@ -279,7 +293,7 @@ static void normal_inserts(void) report_bcp_error("bcp_init", __LINE__, __FILE__); fprintf(stdout, "OK\n"); - test_bind(); + test_bind(prefixlen); fprintf(stdout, "Sending same row 10 times... \n"); for (i=0; i<10; i++) @@ -338,7 +352,8 @@ static void special_inserts(void) bcp_bind(odbc_conn, (unsigned char *) ×tamp, 0, sizeof(timestamp), NULL, 0, BCP_TYPE_SQLDATETIME2, 2); bcp_bind(odbc_conn, (unsigned char *) &numeric, 0, sizeof(numeric), NULL, 0, BCP_TYPE_SQLDECIMAL, 3); bcp_bind(odbc_conn, (unsigned char *) &numeric, 0, sizeof(numeric), NULL, 0, BCP_TYPE_SQLDECIMAL, 4); - bcp_bind(odbc_conn, (unsigned char *) ¬_null_bit, 0, SQL_NULL_DATA, NULL, 0, BCP_TYPE_SQLINT4, 5); + bcp_bind(odbc_conn, (unsigned char *) "", 0, 0, NULL, 0, BCP_TYPE_SQLVARCHAR, 5); + bcp_bind(odbc_conn, (unsigned char *) ¬_null_bit, 0, SQL_NULL_DATA, NULL, 0, BCP_TYPE_SQLINT4, 6); if (bcp_sendrow(odbc_conn) == FAIL) report_bcp_error("bcp_sendrow", __LINE__, __FILE__); @@ -402,7 +417,7 @@ static void special_select(void) char output[128]; SQLLEN dataSize; CHKGetData(i + 1, SQL_C_CHAR, output, sizeof(output), &dataSize, "S"); - if (strcmp(output, expected_special[i]) || dataSize <= 0) { + if (strcmp(output, expected_special[i]) || (dataSize <= 0 && expected_special[i][0] != '\0')) { fprintf(stderr, "Invalid returned col %d: '%s'!='%s'\n", i, expected_special[i], output); ok = 0; } -- 2.1.4