Skip to content

Commit 23d48e9

Browse files
committed
Change DBCLOB+GetSubString to work from first null instead of backwards
GetSubString with an oversized buffer (like from i5_dbcs_alloc) can sometimes add garbage to the end of the buffer when using DBCLOB locators with SQL_C_CHAR outputs. The old code seemed to scan backwards, which is bad if it hits the garbage. As such, try to scan from the first null and then clear out spaces only after getting everything after the null. Since the PASE driver implies DBCLOB is for strings and not binary data, this should be OK?
1 parent eab0066 commit 23d48e9

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

ibm_db2.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5708,10 +5708,35 @@ static RETCODE _php_db2_get_data2(stmt_handle *stmt_res, SQLUSMALLINT col_num, S
57085708
}
57095709
#ifdef PASE /* trim i5/OS SQLGetSubString DBCLOB cases extra nulls -- no harm to simply remove */
57105710
else if (*out_length > 1 && stmt_res->column_info[col_num-1].loc_type == SQL_DBCLOB_LOCATOR) {
5711-
int ib = *out_length - 1;
5712-
char * ibc = (char *) buff;
5713-
for (; ib && (ibc[ib] == 0x00 || ibc[ib] == 0x20); ib--) ibc[ib] = '\0';
5714-
*out_length = ib + 1;
5711+
/*
5712+
* CB 201210111: The combination of using *LOCAL (but DRDA to localhost
5713+
* is OK) and i5_dbcs_alloc causes garbage in addition to the nulls,
5714+
* usually 0x1A (ASCII replacement) and some @. I suspect there might
5715+
* be a buffer overrun kind of situation going on. However, this did
5716+
* impact users using i5_dbcs_alloc, so we'll just clean up the nulls.
5717+
* Tony wrote one, but it went backwards from the end, so the garbage
5718+
* after the first null would confuse it. Since the PASE version of the
5719+
* driver seems to treat DBCLOBs as strings, it should be OK as unlike
5720+
* a binary, trimming nulls should be safe.
5721+
*/
5722+
char *str_buff = (char *) buff;
5723+
int i = 0, first_null;
5724+
while (str_buff[i] != '\0' && i < *out_length) {
5725+
i++;
5726+
}
5727+
first_null = i;
5728+
while (i < *out_length) {
5729+
str_buff[i++] = '\0';
5730+
}
5731+
*out_length = first_null;
5732+
/* avoid a regression in db2_statistics tests, trim end spaces */
5733+
for (i = first_null - 1; i >= 0; i--) {
5734+
if (str_buff[i] != ' ') {
5735+
*out_length = i + 1; /* XXX: ok to assume +1? */
5736+
break;
5737+
}
5738+
str_buff[i] = '\0';
5739+
}
57155740
}
57165741
#endif /* PASE */
57175742
SQLFreeHandle(SQL_HANDLE_STMT, new_hstmt);

0 commit comments

Comments
 (0)