Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 31 additions & 27 deletions driver/convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -1332,9 +1332,11 @@ SQLRETURN sql2c_double(esodbc_rec_st *arec, esodbc_rec_st *irec,

case SQL_C_FLOAT:
REJECT_IF_NULL_DEST_BUFF(stmt, data_ptr);
udbl = dbl < 0 ? -dbl : dbl;
if (udbl < FLT_MIN || FLT_MAX < udbl) {
REJECT_AS_OOR(stmt, dbl, /* is fixed */FALSE, SQLREAL);
if (dbl) {
udbl = dbl < 0 ? -dbl : dbl;
if (udbl < FLT_MIN || FLT_MAX < udbl) {
REJECT_AS_OOR(stmt, dbl, /* is fixed */FALSE, SQLREAL);
}
}
*(SQLREAL *)data_ptr = (SQLREAL)dbl;
write_out_octets(octet_len_ptr, sizeof(SQLREAL), irec);
Expand Down Expand Up @@ -1382,15 +1384,38 @@ static SQLRETURN wstr_to_cstr(esodbc_rec_st *arec, esodbc_rec_st *irec,

gd_offset_apply(stmt, &xstr);

assert(xstr.w.str[xstr.w.cnt] == L'\0');
/* how much space would the converted string take? */
in_bytes = WCS2U8(xstr.w.str, (int)xstr.w.cnt + 1, NULL, 0);
if (in_bytes <= 0) {
ERRNH(stmt, "failed to convert wchar* to char* for string `"
LWPDL "`.", LWSTR(&xstr.w));
RET_HDIAGS(stmt, SQL_STATE_22018);
}
/* out length needs to be provided with no (potential) truncation. */
if (octet_len_ptr) {
/* chars_0 accounts for 0-terminator, so WCS2U8 will count that in
* the output as well => trim it, since we must not count it when
* indicating the length to the application */
out_bytes = in_bytes - 1;
write_out_octets(octet_len_ptr, out_bytes, irec);
} else {
DBGH(stmt, "REC@0x%p, NULL octet_len_ptr.", arec);
}

if (data_ptr) {
charp = (char *)data_ptr;

in_bytes = (int)buff_octet_size((xstr.w.cnt + 1) * sizeof(SQLWCHAR),
sizeof(SQLCHAR), arec, irec, &state);
/* calculate how much of original data could possibly be copied in
* provided buffer; this will be given as a limitation to W-to-C
* conversion function. */
in_bytes = (int)buff_octet_size(in_bytes, sizeof(SQLCHAR), arec, irec,
&state);
/* trim the original string until it fits in output buffer, with given
* length limitation */
for (c = (int)xstr.w.cnt + 1; 0 < c; c --) {
out_bytes = WCS2U8(xstr.w.str, c, charp, in_bytes);
/* if user gives 0 as buffer size, out_bytes will also be 0 */
if (out_bytes <= 0) {
if (WCS2U8_BUFF_INSUFFICIENT) {
continue;
Expand All @@ -1404,10 +1429,7 @@ static SQLRETURN wstr_to_cstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
}
}

/* if 0's present => 0 < out_bytes */
assert(xstr.w.str[xstr.w.cnt] == L'\0');
assert(0 < out_bytes);
/* if user gives 0 as buffer size, out_bytes will also be 0 */
if (charp[out_bytes - 1]) {
/* ran out of buffer => not 0-terminated and truncated already */
charp[out_bytes - 1] = 0;
Expand All @@ -1418,30 +1440,12 @@ static SQLRETURN wstr_to_cstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
/* only update offset if data is copied out */
gd_offset_update(stmt, xstr.w.cnt, c);

DBGH(stmt, "REC@0x%p, data_ptr@0x%p, copied %zd bytes: `" LWPD "`.",
DBGH(stmt, "REC@0x%p, data_ptr@0x%p, copied %d bytes: `" LCPD "`.",
arec, data_ptr, out_bytes, charp);
} else {
DBGH(stmt, "REC@0x%p, NULL data_ptr.", arec);
}

/* if length needs to be given, calculate it (not truncated) & converted */
if (octet_len_ptr) {
out_bytes = (size_t)WCS2U8(xstr.w.str, (int)xstr.w.cnt + 1, NULL, 0);
if (out_bytes <= 0) {
ERRNH(stmt, "failed to convert wchar* to char* for string `"
LWPDL "`.", LWSTR(&xstr.w));
RET_HDIAGS(stmt, SQL_STATE_22018);
} else {
/* chars_0 accounts for 0-terminator, so WCS2U8 will count that in
* the output as well => trim it, since we must not count it when
* indicating the length to the application */
out_bytes --;
}
write_out_octets(octet_len_ptr, out_bytes, irec);
} else {
DBGH(stmt, "REC@0x%p, NULL octet_len_ptr.", arec);
}

if (state != SQL_STATE_00000) {
RET_HDIAGS(stmt, state);
}
Expand Down
2 changes: 1 addition & 1 deletion driver/queries.c
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ SQLRETURN copy_one_row(esodbc_stmt_st *stmt, SQLULEN pos)
case UJT_Long:
case UJT_LongLong:
ll = UJNumericLongLong(obj);
DBGH(stmt, "value [%zd, %d] is numeric: %lld.", rowno, i + 1,
DBGH(stmt, "value [%zd, %d] is integer: %lld.", rowno, i + 1,
ll);
ret = sql2c_longlong(arec, irec, pos, ll);
break;
Expand Down
33 changes: 33 additions & 0 deletions test/test_conversion_sql2c_floats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,39 @@ TEST_F(ConvertSQL2C_Floats, Float2Long) {
}


TEST_F(ConvertSQL2C_Floats, Double_zero2Float) {

#undef SQL_RAW
#undef SQL_VAL
#undef SQL
#define SQL_RAW 0.0
#define SQL_VAL STR(SQL_RAW)
#define SQL "CAST(" SQL_VAL " AS DOUBLE)"

const char json_answer[] = "\
{\
\"columns\": [\
{\"name\": \"" SQL "\", \"type\": \"double\"}\
],\
\"rows\": [\
[" SQL_VAL "]\
]\
}\
";
prepareStatement(json_answer);

SQLREAL val;
ret = SQLBindCol(stmt, /*col#*/1, SQL_C_FLOAT, &val, sizeof(val), &ind_len);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

ret = SQLFetch(stmt);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

EXPECT_EQ(ind_len, sizeof(val));
EXPECT_LE(SQL_RAW, val);
}


TEST_F(ConvertSQL2C_Floats, Double2Float) {

#undef SQL_RAW
Expand Down
33 changes: 33 additions & 0 deletions test/test_conversion_sql2c_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ TEST_F(ConvertSQL2C_String, String2Char) {

ret = SQLFetch(stmt);
ASSERT_TRUE(SQL_SUCCEEDED(ret));
assertState(L"00000");

EXPECT_EQ(ind_len, sizeof(SQL_VAL) - /*\0*/1);
EXPECT_STREQ((char/*4gtest*/*)buff, SQL_VAL);
Expand Down Expand Up @@ -114,6 +115,38 @@ TEST_F(ConvertSQL2C_String, String2Char_zero_copy) {
}


TEST_F(ConvertSQL2C_String, String2Char_truncate) {

#undef SQL_VAL
#undef SQL
#define SQL_VAL "abcdef"
#define SQL "CAST(" SQL_VAL " AS TEXT)"

const char json_answer[] = "\
{\
\"columns\": [\
{\"name\": \"" SQL "\", \"type\": \"text\"}\
],\
\"rows\": [\
[\"" SQL_VAL "\"]\
]\
}\
";
prepareStatement(json_answer);

SQLCHAR buff[(sizeof(SQL_VAL) - 1)/2 + 1];
ret = SQLBindCol(stmt, /*col#*/1, SQL_C_CHAR, &buff, sizeof(buff), &ind_len);
ASSERT_TRUE(SQL_SUCCEEDED(ret));

ret = SQLFetch(stmt);
ASSERT_TRUE(SQL_SUCCEEDED(ret));
assertState(L"01004");

EXPECT_EQ(ind_len, sizeof(SQL_VAL) - /*\0*/1);
EXPECT_STREQ((char/*4gtest*/*)buff, "abc");
}


TEST_F(ConvertSQL2C_String, String2SLong) {

#undef SQL_RAW
Expand Down