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

Reply via email to