Changeset: 0e5f6d9e85f5 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=0e5f6d9e85f5
Modified Files:
clients/odbc/driver/ODBCConvert.c
Branch: Aug2018
Log Message:
Fix retrieving binary data.
If the SQL type is SQL_BINARY and the C type SQL_C_CHAR/SQL_C_WCHAR,
the result should be a list of hex digits of even length (excluding
NULL byte). If the SQL type is SQL_BINARY and the C type
SQL_C_BINARY, we should return a list of binary bytes.
Also, no need for allocating extra memory just to make a copy of the
data to be converted to wide characters.
diffs (248 lines):
diff --git a/clients/odbc/driver/ODBCConvert.c
b/clients/odbc/driver/ODBCConvert.c
--- a/clients/odbc/driver/ODBCConvert.c
+++ b/clients/odbc/driver/ODBCConvert.c
@@ -1232,25 +1232,44 @@ ODBCFetch(ODBCStmt *stmt,
origlenp = lenp;
if (type == SQL_C_WCHAR) {
/* allocate temporary space */
- buflen = 511; /* should be enough for most types */
- if (data != NULL &&
- (sql_type == SQL_CHAR ||
- sql_type == SQL_VARCHAR ||
- sql_type == SQL_LONGVARCHAR ||
- sql_type == SQL_WCHAR ||
- sql_type == SQL_WVARCHAR ||
- sql_type == SQL_WLONGVARCHAR))
- buflen = (SQLLEN) datalen + 1; /* but this is
certainly enough for strings */
- ptr = malloc(buflen);
- if (ptr == NULL) {
- /* Memory allocation error */
- addStmtError(stmt, "HY001", NULL, 0);
- return SQL_ERROR;
+ switch (sql_type) {
+ case SQL_CHAR:
+ case SQL_VARCHAR:
+ case SQL_LONGVARCHAR:
+ case SQL_WCHAR:
+ case SQL_WVARCHAR:
+ case SQL_WLONGVARCHAR:
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+ case SQL_GUID:
+ /* this is certainly enough for strings */
+ buflen = (SQLLEN) datalen + 1;
+ ptr = NULL;
+ break;
+ default:
+ /* should be enough for most types */
+ buflen = 511;
+ ptr = malloc(buflen);
+ if (ptr == NULL) {
+ /* Memory allocation error */
+ addStmtError(stmt, "HY001", NULL, 0);
+ return SQL_ERROR;
+ }
+ break;
}
-
lenp = NULL;
}
switch (sql_type) {
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+ if (buflen > 0 && (buflen & 1) == 0) {
+ /* return even number of bytes + NULL
+ * (i.e. buflen must be odd) */
+ buflen--;
+ }
+ /* fall through */
default:
case SQL_CHAR:
case SQL_VARCHAR:
@@ -1261,71 +1280,22 @@ ODBCFetch(ODBCStmt *stmt,
case SQL_GUID:
if (irdrec->already_returned >= datalen) {
/* no more data to return */
- if (type == SQL_C_WCHAR)
- free(ptr);
- return SQL_NO_DATA;
- }
- data += irdrec->already_returned;
- datalen -= irdrec->already_returned;
- copyString(data, datalen, ptr, buflen, lenp, SQLLEN,
- addStmtError, stmt, return SQL_ERROR);
- if (datalen < (size_t) buflen)
- irdrec->already_returned += datalen;
- else
- irdrec->already_returned += buflen - 1;
- break;
- case SQL_BINARY:
- case SQL_VARBINARY:
- case SQL_LONGVARBINARY: {
- size_t k;
- int n;
- unsigned char c = 0;
- SQLLEN j;
- unsigned char *p = ptr;
-
- if (irdrec->already_returned >= datalen) {
- /* no more data to return */
- if (type == SQL_C_WCHAR)
+ if (type == SQL_C_WCHAR && ptr)
free(ptr);
return SQL_NO_DATA;
}
data += irdrec->already_returned;
datalen -= irdrec->already_returned;
- for (k = 0, j = 0; k < datalen && j < buflen; k++) {
- if ('0' <= data[k] && data[k] <= '9')
- n = data[k] - '0';
- else if ('A' <= data[k] && data[k] <= 'F')
- n = data[k] - 'A' + 10;
- else if ('a' <= data[k] && data[k] <= 'f')
- n = data[k] - 'a' + 10;
- else {
- /* should not happen */
- /* General error */
- addStmtError(stmt, "HY000", "Unexpected
data from server", 0);
- if (type == SQL_C_WCHAR)
- free(ptr);
- return SQL_ERROR;
- }
- if (k & 1) {
- c |= n;
- p[j] = c;
- j++;
- } else
- c = n << 4;
+ if (ptr) {
+ copyString(data, datalen, ptr, buflen, lenp,
+ SQLLEN, addStmtError, stmt,
+ return SQL_ERROR);
}
- if (k & 1) {
- /* should not happen: uneven length */
- /* General error */
- addStmtError(stmt, "HY000", "Unexpected data
from server", 0);
- if (type == SQL_C_WCHAR)
- free(ptr);
- return SQL_ERROR;
- }
- irdrec->already_returned += k;
- if (lenp)
- *lenp = datalen / 2;
+ if (datalen < (size_t) buflen)
+ irdrec->already_returned += datalen;
+ else
+ irdrec->already_returned += buflen - 1;
break;
- }
case SQL_TINYINT:
case SQL_SMALLINT:
case SQL_INTEGER:
@@ -1864,9 +1834,18 @@ ODBCFetch(ODBCStmt *stmt,
SQLSMALLINT n;
size_t i;
- ODBCutf82wchar((SQLCHAR *) ptr, SQL_NTS,
- (SQLWCHAR *) origptr,
- origbuflen / sizeof(SQLWCHAR), &n, &i);
+ if (ptr) {
+ ODBCutf82wchar((SQLCHAR *) ptr, SQL_NTS,
+ (SQLWCHAR *) origptr,
+ origbuflen / sizeof(SQLWCHAR),
+ &n, &i);
+ free(ptr);
+ } else {
+ ODBCutf82wchar((SQLCHAR *) data, SQL_NTS,
+ (SQLWCHAR *) origptr,
+ origbuflen / sizeof(SQLWCHAR),
+ &n, &i);
+ }
#ifdef ODBCDEBUG
ODBCLOG("Writing %d bytes to %p\n",
(int) (n * sizeof(SQLWCHAR)),
@@ -1875,7 +1854,6 @@ ODBCFetch(ODBCStmt *stmt,
if (origlenp)
*origlenp = n * sizeof(SQLWCHAR); /* # of
bytes, not chars */
- free(ptr);
irdrec->already_returned -= datalen;
irdrec->already_returned += i;
if (i < datalen) {
@@ -1889,7 +1867,7 @@ ODBCFetch(ODBCStmt *stmt,
#endif
break;
}
- case SQL_C_BINARY:
+ case SQL_C_BINARY: {
if (buflen < 0) {
/* Invalid string or buffer length */
addStmtError(stmt, "HY090", NULL, 0);
@@ -1932,8 +1910,63 @@ ODBCFetch(ODBCStmt *stmt,
/* Restricted data type attribute violation */
addStmtError(stmt, "07006", NULL, 0);
return SQL_ERROR;
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+ break;
}
- /* break; -- not reached */
+ if (irdrec->already_returned >= datalen) {
+ /* no more data to return */
+ return SQL_NO_DATA;
+ }
+ data += irdrec->already_returned;
+ datalen -= irdrec->already_returned;
+
+ size_t k;
+ SQLLEN j;
+ unsigned char *p = ptr;
+
+ for (k = 0, j = 0; k < datalen && j < buflen; k++) {
+ unsigned int n;
+
+ if (isdigit(data[k]))
+ n = data[k] - '0';
+ else if ('A' <= data[k] && data[k] <= 'F')
+ n = data[k] - 'A' + 10;
+ else if ('a' <= data[k] && data[k] <= 'f')
+ n = data[k] - 'a' + 10;
+ else {
+ /* should not happen: not a hex character */
+ /* General error */
+ addStmtError(stmt, "HY000", "Unexpected data
from server", 0);
+ if (type == SQL_C_WCHAR)
+ free(ptr);
+ return SQL_ERROR;
+ }
+ if (k & 1) {
+ p[j] |= n;
+ j++;
+ } else {
+ p[j] = n << 4;
+ }
+ }
+ if (k & 1) {
+ /* should not happen: uneven length */
+ /* General error */
+ addStmtError(stmt, "HY000", "Unexpected data from
server", 0);
+ if (type == SQL_C_WCHAR)
+ free(ptr);
+ return SQL_ERROR;
+ }
+ irdrec->already_returned += k;
+ if (lenp)
+ *lenp = datalen / 2;
+ if (k < datalen) {
+ /* String data, right-truncated */
+ addStmtError(stmt, "01004", NULL, 0);
+ }
+ break;
+ }
case SQL_C_BIT:
if (ardrec && row > 0)
ptr = (SQLPOINTER) ((char *) ptr + row * (bind_type ==
SQL_BIND_BY_COLUMN ? (SQLINTEGER) sizeof(unsigned char) : bind_type));
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list