【问题标题】:SQLDescribeCol() returns SQL_VARCHAR for BINARY, BLOB, WCHAR, DECIMALSQLDescribeCol() 为 BINARY、BLOB、WCHAR、DECIMAL 返回 SQL_VARCHAR
【发布时间】:2019-10-17 18:07:30
【问题描述】:

在 unixodbc 下使用 ODBC driver for SQLite,我经常从 SQLDescribeCol 得到无用的结果。

例如,在使用以下命令创建的表中:

CREATE TABLE `test_table` (
    id INTEGER PRIMARY KEY NOT NULL,
    `value` BINARY(3) NOT NULL
)

我执行简单的无参数 ODBC 查询:

SELECT value FROM `test_table`

它返回一个包含一列的结果集,其中我的 C 代码说明了以下内容:

SQLWCHAR title[COLUMN_TITLE_SIZE];
SQLSMALLINT title_length;
SQLSMALLINT sql_type;  
SQLULEN column_size;
SQLSMALLINT precision;  
SQLSMALLINT nullable;

SQLRETURN rc = SQLDescribeColW(
    hstmt,
    column_index,  // 1 in this case
    &title[0],
    COLUMN_TITLE_SIZE,
    &title_length,
    &sql_type,
    &column_size,
    &precision,
    &nullable
);

尽管表定义中有 BINARY,但它返回 sql_type == SQL_VARCHAR。某些类型不存在此问题...例如整数或时间/日期、SQL_BIT 或大多数浮点数。但同样的事情也会发生在 BLOB 列、NCHAR 列,尤其是 DECIMAL 上。

我正在尝试为从语言绑定中的列返回的值自动选择正确的类型,因此区分这种类型很重要。

【问题讨论】:

    标签: sqlite odbc unixodbc


    【解决方案1】:

    这似乎是 SQLite unixodbc 驱动程序中的一个错误(或未实现的功能)。似乎问题在于,对于它必须malloc() 任意缓冲区的任何类型,其内部类型都是相同的。

    这里有一个建议的解决方法:驱动程序确实知道列类型的字符串名称...您可以通过 SQLColAttribute 传递 SQL_DESC_TYPE_NAME 来获取它。

    char type_name[100];  // Note: `typename` is a C++ keyword
    SQLSMALLINT type_name_len;
    rc = SQLColAttribute(  // or SQLColAttributeW--see NOTE below
        hstmt,  // StatementHandle
        column_index,  // ColumnNumber
        SQL_DESC_TYPE_NAME,  // FieldIdentifier, see SQL_DESC_XXX list
        &type_name,  // CharacterAttributePtr
        100,  // BufferLength
        &type_name_len,  // StringLengthPtr
        nullptr  // NumericAttributePtr, not needed w/string attribute
    );
    

    注意:以上内容适用于 unixodbc。但是报告回来了,Windows SQLite 驱动程序返回一个宽字符串作为 type_name,即使调用的是 SQLColAttribute 而不是 SQLColAttributeW。如果有人对此有更多要说的,请插话。

    type_name 将返回并为您提供 BINARY 等区别,因此如果您在其中寻找所需类型的模式,您可以生成所需的 SQL_BINARY 等类型。

    注意:驱动中有代码可以做mappings of strings to SQL_TYPEs。但它似乎没有在 SELECT 中使用它,只在 INSERT 上使用。

    【讨论】:

    • SqlColAttribute 是一个简单的 #defineSqlColAttributeWSqlColAttributeA,其中 W 函数用于“Unicode”字符集(使用 wstring / SQLWCHAR),而 A -function 用于“多字节字符集”(使用 strind / SQLCHAR)。如果定义了UNICODE,通常会启用 W 功能。这适用于(几乎)所有 Windows 功能,请参阅docs.microsoft.com/en-us/windows/win32/learnwin32/… 了解一般情况,或查看此处了解 odbc:github.com/microsoft/ODBC-Specification/blob/master/Windows/inc/…
    • @erg 嗯...哦。那么 SqlColAttributeA 是否保证在 unix odbc 上定义?我实际上是在 Linux 而不是 Windows 上编译的,但 this patch 对 Windows 用户产生了影响......这表明可能定义了 UNICODE,因此“SqlColAttribute”正在获得 W 版本,我猜......
    • 我(大部分)在 Windows 上,永远不会直接针对任何“A”或“W”版本进行编码,只是感觉不对。因此,我也不会依赖定义任何“A”变体的 UnixOdbc。您可能可以依赖 Windows 上存在的 A 函数并做一些丑陋的事情,如 #ifdef WIN32 .. #endif。前段时间,我为我们的一个项目编写了一个跨平台的 odbc 包装器,我只是在任何地方都使用了 std::string(utf-8 编码),无论涉及到 Windows API 边界,我都从 utf- 8 到 wstring 持有 unicode:exodbc.elisium.ch/trac
    • @erg 感谢您的洞察力......我想我现在只会坚持使用 W 版本,因为在迄今为止的测试中,这似乎是最一致的(例如,有没有混淆,W API 总是宽字符)。
    猜你喜欢
    • 2021-11-27
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    • 2022-12-19
    • 1970-01-01
    • 2019-11-26
    • 2011-10-27
    相关资源
    最近更新 更多