Skip to content

Commit 297bfd9

Browse files
committed
Add UTF-32 hack for iODBC + Teradata.
I'm not sure if the issue is iODBC (which Apple doesn't ship anymore) is using a 4-byte SQLWCHAR or if Teradata is returning UCS4/UTF-32LE for column names in SQLDescribeColW. Either way I've added a hack that assumes 4-byte chars if the decoding for SQL_WMETADATA (a pyodbc specific constant) is set to any of the UTF-32 encodings. The encoding is then actually used. cnxn.setdecoding(pyodbc.SQL_WMETADATA, encoding='utf-32le') Fixes #194
1 parent 6e1793e commit 297bfd9

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

src/connection.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,21 @@ static bool SetTextEncCommon(TextEnc& enc, const char* encoding, int ctype, bool
11461146
enc.optenc = OPTENC_UTF16LE;
11471147
enc.ctype = (SQLSMALLINT)(ctype ? ctype : SQL_C_WCHAR);
11481148
}
1149+
else if (strstr("|utf-32|utf32|", lower))
1150+
{
1151+
enc.optenc = OPTENC_UTF32;
1152+
enc.ctype = (SQLSMALLINT)(ctype ? ctype : SQL_C_WCHAR);
1153+
}
1154+
else if (strstr("|utf-32-be|utf-32be|utf32be|", lower))
1155+
{
1156+
enc.optenc = OPTENC_UTF32BE;
1157+
enc.ctype = (SQLSMALLINT)(ctype ? ctype : SQL_C_WCHAR);
1158+
}
1159+
else if (strstr("|utf-32-le|utf-32le|utf32le|", lower))
1160+
{
1161+
enc.optenc = OPTENC_UTF32LE;
1162+
enc.ctype = (SQLSMALLINT)(ctype ? ctype : SQL_C_WCHAR);
1163+
}
11491164
else if (strstr("|latin-1|latin1|iso-8859-1|iso8859-1|", lower))
11501165
{
11511166
enc.optenc = OPTENC_LATIN1;

src/cursor.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,28 @@ static bool create_name_map(Cursor* cur, SQLSMALLINT field_count, bool lower)
178178
goto done;
179179
}
180180

181+
const TextEnc& enc = cur->cnxn->metadata_enc;
182+
183+
// HACK: I don't know the exact issue, but iODBC + Teradata results in either UCS4 data
184+
// or 4-byte SQLWCHAR. I'm going to use UTF-32 as an indication that's what we have.
185+
186+
Py_ssize_t cbName = cchName;
187+
switch (enc.optenc)
188+
{
189+
case OPTENC_UTF32:
190+
case OPTENC_UTF32LE:
191+
case OPTENC_UTF32BE:
192+
cbName *= 4;
193+
break;
194+
default:
195+
if (enc.ctype == SQL_C_WCHAR)
196+
cbName *= 2;
197+
break;
198+
}
199+
181200
TRACE("Col %d: type=%s (%d) colsize=%d\n", (i+1), SqlTypeName(nDataType), (int)nDataType, (int)nColSize);
182201

183-
const TextEnc& enc = cur->cnxn->metadata_enc;
184-
Object name(TextBufferToObject(enc, szName, (Py_ssize_t)(cchName * sizeof(ODBCCHAR))));
202+
Object name(TextBufferToObject(enc, szName, cbName));
185203

186204
if (!name)
187205
goto done;

src/textenc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ enum {
1414
OPTENC_UTF16BE = 4,
1515
OPTENC_UTF16LE = 5,
1616
OPTENC_LATIN1 = 6,
17+
OPTENC_UTF32 = 7,
18+
OPTENC_UTF32LE = 8,
19+
OPTENC_UTF32BE = 9,
1720

1821
#if PY_MAJOR_VERSION < 3
1922
TO_UNICODE = 1,

0 commit comments

Comments
 (0)