Skip to content

Commit af34711

Browse files
committed
Fix: SQLGetData: only update offset if C-string data copied out (#226)
* Fix: SQLGetData: only update offset if data copied This commit fixes a defect manifesting when getting C-strings with SQLGetData, in two steps: a first invocation with a 0-space buffer, to fetch the lenght of data available, then a subsequent one, with appropriate buffer size, to actually fetch the data. The second call would so far fail with "no data available anymore", since the offset of so-far-read-data was incorrectly updated, also in the case when no data was actually copied. This commit fixes it, only updating the offset if there's space in output buffer to copy. (cherry picked from commit 6096873)
1 parent 6932e75 commit af34711

File tree

2 files changed

+46
-32
lines changed

2 files changed

+46
-32
lines changed

driver/convert.c

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -673,12 +673,12 @@ static SQLRETURN transfer_xstr0(esodbc_rec_st *arec, esodbc_rec_st *irec,
673673

674674
if (state != SQL_STATE_00000) {
675675
/* 0-term the buffer */
676-
dst_w[in_chars] = 0;
676+
dst_w[in_chars] = L'\0';
677677
DBGH(stmt, "aREC@0x%p: `" LWPDL "` transfered truncated "
678678
"as `" LWPDL "` at data_ptr@0x%p.", arec,
679679
LWSTR(&xsrc->w), in_chars, dst_w, dst_w);
680680
} else {
681-
assert(dst_w[in_chars] == 0);
681+
assert(dst_w[in_chars] == L'\0');
682682
DBGH(stmt, "aREC@0x%p: `" LWPDL "` transfered at "
683683
"data_ptr@0x%p.", arec, LWSTR(&xsrc->w), dst_w);
684684
}
@@ -688,19 +688,22 @@ static SQLRETURN transfer_xstr0(esodbc_rec_st *arec, esodbc_rec_st *irec,
688688

689689
if (state != SQL_STATE_00000) {
690690
/* 0-term the buffer */
691-
dst_c[in_chars] = 0;
691+
dst_c[in_chars] = '\0';
692692
DBGH(stmt, "aREC@0x%p: `" LCPDL "` transfered truncated "
693693
"as `" LCPDL "` at data_ptr@0x%p.", arec,
694694
LCSTR(&xsrc->w), in_chars, dst_c, dst_c);
695695
} else {
696-
assert(dst_c[in_chars] == 0);
696+
assert(dst_c[in_chars] == '\0');
697697
DBGH(stmt, "aREC@0x%p: `" LCPDL "` transfered at "
698698
"data_ptr@0x%p.", arec, LCSTR(&xsrc->c), dst_c);
699699
}
700700
}
701701

702702
/* only update offset if data is copied out */
703703
gd_offset_update(stmt, xsrc->w.cnt, in_chars); /*==->c.cnt*/
704+
} else {
705+
DBGH(stmt, "aREC@0x%p, data_ptr@0x%p, no room to copy bytes out.",
706+
arec, data_ptr);
704707
}
705708
} else {
706709
DBGH(stmt, "aREC@0x%p: NULL transfer buffer.", arec);
@@ -1472,37 +1475,37 @@ static SQLRETURN wstr_to_cstr(esodbc_rec_st *arec, esodbc_rec_st *irec,
14721475
* conversion function. */
14731476
in_bytes = (int)buff_octet_size(in_bytes, sizeof(SQLCHAR), arec, irec,
14741477
&state);
1475-
/* trim the original string until it fits in output buffer, with given
1476-
* length limitation */
1477-
for (c = (int)xstr.w.cnt + 1; 0 < c; c --) {
1478-
out_bytes = U16WC_TO_MBU8(xstr.w.str, c, charp, in_bytes);
1479-
/* if user gives 0 as buffer size, out_bytes will also be 0 */
1480-
if (out_bytes <= 0) {
1481-
if (WAPI_ERR_EBUFF()) {
1482-
continue;
1483-
}
1484-
ERRNH(stmt, "failed to convert wchar_t* to char* for string `"
1485-
LWPDL "`.", c, xstr.w.str);
1486-
RET_HDIAGS(stmt, SQL_STATE_22018);
1487-
} else {
1488-
/* conversion succeeded */
1489-
break;
1478+
if (in_bytes) {
1479+
/* trim the original string until it fits in output buffer, with
1480+
* given length limitation */
1481+
for (c = (int)xstr.w.cnt + 1; 0 < c; c --) {
1482+
out_bytes = U16WC_TO_MBU8(xstr.w.str, c, charp, in_bytes);
1483+
if (0 < out_bytes) {
1484+
break; /* conversion succeeded */
1485+
} // else: out_bytes <= 0
1486+
if (! WAPI_ERR_EBUFF()) {
1487+
ERRNH(stmt, "failed to convert wchar_t* to char* for "
1488+
"string `" LWPDL "`.", c, xstr.w.str);
1489+
RET_HDIAGS(stmt, SQL_STATE_22018);
1490+
} // else: buffer too small for full string: trim further
14901491
}
1491-
}
14921492

1493-
assert(0 < out_bytes);
1494-
if (charp[out_bytes - 1]) {
1495-
/* ran out of buffer => not 0-terminated and truncated already */
1496-
charp[out_bytes - 1] = 0;
1497-
state = SQL_STATE_01004; /* indicate truncation */
1498-
c --; /* last char was overwritten with 0 -> dec xfed count */
1499-
}
1500-
1501-
/* only update offset if data is copied out */
1502-
gd_offset_update(stmt, xstr.w.cnt, c);
1493+
assert(0 < out_bytes);
1494+
if (charp[out_bytes - 1] != '\0') {
1495+
/* ran out of buffer => not 0-term'd and truncated already */
1496+
charp[out_bytes - 1] = '\0';
1497+
state = SQL_STATE_01004; /* indicate truncation */
1498+
c --; /* last char was overwritten with 0 -> dec xfed count */
1499+
}
15031500

1504-
DBGH(stmt, "REC@0x%p, data_ptr@0x%p, copied %d bytes: `" LCPD "`.",
1505-
arec, data_ptr, out_bytes, charp);
1501+
/* only update offset if data is copied out */
1502+
gd_offset_update(stmt, xstr.w.cnt, c);
1503+
DBGH(stmt, "REC@0x%p, data_ptr@0x%p, copied %d bytes: `" LCPD "`.",
1504+
arec, data_ptr, out_bytes, charp);
1505+
} else {
1506+
DBGH(stmt, "REC@0x%p, data_ptr@0x%p, no room to copy bytes out.",
1507+
arec, data_ptr);
1508+
}
15061509
} else {
15071510
DBGH(stmt, "REC@0x%p, NULL data_ptr.", arec);
15081511
}

test/test_sqlgetdata.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ TEST_F(GetData, String2Char_zero_copy) {
133133
ret = SQLGetData(stmt, /*col*/1, SQL_C_CHAR, buff, 0, &ind_len);
134134
ASSERT_TRUE(SQL_SUCCEEDED(ret));
135135
EXPECT_EQ(ind_len, sizeof(SQL_VAL) - /*\0*/1);
136+
137+
/* check if data is still available */
138+
ret = SQLGetData(stmt, /*col*/1, SQL_C_CHAR, buff, sizeof(buff), NULL);
139+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
140+
ASSERT_STREQ(SQL_VAL, (char *)buff);
136141
}
137142

138143

@@ -257,6 +262,12 @@ TEST_F(GetData, String2WChar_zero_copy) {
257262
ret = SQLGetData(stmt, /*col*/1, SQL_C_WCHAR, buff, 0, &ind_len);
258263
ASSERT_TRUE(SQL_SUCCEEDED(ret));
259264
EXPECT_EQ(ind_len/sizeof(*buff), sizeof(SQL_VAL) - /*\0*/1);
265+
266+
/* check if data is still available */
267+
ret = SQLGetData(stmt, /*col*/1, SQL_C_WCHAR, buff,
268+
sizeof(buff)/sizeof(buff[0]), NULL);
269+
ASSERT_TRUE(SQL_SUCCEEDED(ret));
270+
EXPECT_STREQ(MK_WPTR(SQL_VAL), (wchar_t *)buff);
260271
}
261272

262273
TEST_F(GetData, String2SLong) {

0 commit comments

Comments
 (0)