I have made modified OdbcGetDataString and OdbcGetDataStringByColName to make them more robust. Now they retrieve the length of the returned data instead of searching for a null terminator and check if the returned data is null.
FUNCTION OdbcGetDataString ALIAS "OdbcGetDataString" (BYVAL hStmt AS DWORD, BYVAL iCol AS INTEGER, OPTIONAL BYVAL lMaxChars AS LONG) EXPORT AS STRING
LOCAL s AS STRING, cbLen AS LONG
IF lMaxChars < 1 THEN lMaxChars = 256
s = SPACE$(lMaxChars + 1) ' Make room for the null character
ODBC_ERROR_HRESULT = SQLGetData(hStmt, iCol, %SQL_C_CHAR, BYVAL STRPTR(s), LEN(s), cbLen)
IF ODBC_ERROR_HRESULT = %SQL_SUCCESS OR ODBC_ERROR_HRESULT = %SQL_SUCCESS_WITH_INFO THEN
IF cbLen <> %SQL_NULL_DATA THEN FUNCTION = LEFT$(s, cbLen)
END IF
END FUNCTION
FUNCTION OdbcGetDataStringByColName ALIAS "OdbcGetDataStringByColName" (BYVAL hStmt AS DWORD, BYVAL ColumnName AS STRING, OPTIONAL BYVAL lMaxChars AS LONG) EXPORT AS STRING
LOCAL cbLen AS LONG
LOCAL NumCols AS INTEGER
LOCAL i AS LONG
LOCAL ColNumber AS INTEGER
LOCAL ColName AS ASCIIZ * 255
LOCAL s AS STRING
IF lMaxChars < 1 THEN lMaxChars = 256
ColName = UCASE$(TRIM$(ColumnName))
ODBC_ERROR_HRESULT = SQLNumResultCols(hStmt, NumCols)
IF NumCols < 1 THEN EXIT FUNCTION
DIM ucol(1 TO Numcols) AS ODBC_COL_DESC_TYPE
FOR i = 1 TO NumCols
ODBC_ERROR_HRESULT = SQLDescribeCol(hStmt, i, ucol(i).clName, SIZEOF(ucol(i).clName), _
ucol(i).clNameLen, ucol(i).clDataType, ucol(i).clSize, _
ucol(i).clDecimals, ucol(i).clNullable)
IF ODBC_ERROR_HRESULT <> %SQL_SUCCESS THEN EXIT FUNCTION
IF UCASE$(ucol(i).clName) = ColName THEN
ColNumber = i
EXIT FOR
END IF
NEXT i
IF ColNumber THEN
s = SPACE$(lMaxChars + 1) ' Make room for the null character
ODBC_ERROR_HRESULT = SQLGetData(hStmt, ColNumber, %SQL_C_CHAR, BYVAL STRPTR(s), LEN(s), cbLen)
IF ODBC_ERROR_HRESULT = %SQL_SUCCESS OR ODBC_ERROR_HRESULT = %SQL_SUCCESS_WITH_INFO THEN
IF cbLen <> %SQL_NULL_DATA THEN FUNCTION = LEFT$(s, cbLen)
END IF
END IF
END FUNCTION