【问题标题】:How to get a MySQL blob as binary data using SQLGetData in C++如何在 C++ 中使用 SQLGetData 获取 MySQL blob 作为二进制数据
【发布时间】:2016-06-29 23:58:01
【问题描述】:

我有一个带有 mediumblob 列的 MySQL 数据库。我想在 Windows 上使用 ODBC 将二进制数据从 blob 字段转换为 C++ 字符串流。

我首先调用SQLDescribeCol,它表明它的类型是SQL_LONGVARBINARY

然后我拨打SQLGetData如下:

SQLLEN indicator;
SQLCHAR SqlChar[8000];
SQLGetData(m_sqlstatementhandle, i, SQL_CHAR, &SqlChar, sizeof(SqlChar), (SQLLEN*)&indicator);

然后我继续将数据写入stringstream

stringstream ss;
ss.write((char*)&SqlChar, indicator);

这确实给了我 blob 数据,但它以十六进制字符串的形式存储在 SqlChar 中。

我的程序希望字符串流中的数据以二进制形式存储。现在我可以先将 HEX 字符串转换为二进制,然后将其写入字符串流,但这对我来说感觉不对。我真的很想直接从SQLGetData 获得二进制文件。

有几个问题:

  1. 我是否正确地将 SQLGetData 用于 blob 类型?
  2. SQLCHAR 数组是正确的写入容器吗?
  3. 有没有办法通过 ODBC 直接从 MySQL 获取二进制数据?

谢谢。

【问题讨论】:

  • 但它作为 HEX 字符串存储在 SqlChar 中。 -- 你怎么知道数据真的是一个十六进制字符串?也许是您的调试器向您显示数据 as 十六进制字符串,而不是数据实际上是十六进制字符串。此外,您应该在调用 ODBC 函数时检查您的返回码。调用SQLGetData后的返回值是多少?
  • @PaulMcKenzie 感谢您的评论。以上只是一些使问题清晰的最小代码。我确实在我的实际代码中检查了返回代码。事实证明,一旦我找到它,修复就非常简单。

标签: c++ mysql odbc blob


【解决方案1】:

提供SQL_BINARY 作为参数是错误的(即使它在这里有效,因为SQL_BINARYSQL_C_BINARY 似乎被定义为相同的值)。来自SQLGetData 的文档,关于第三个参数TargetType

[Input] *TargetValuePtr 的 C 数据类型的类型标识符 缓冲。有关有效 C 数据类型和类型标识符的列表,请参阅 附录 D:数据类型中的 C 数据类型部分。

见:https://msdn.microsoft.com/en-us/library/ms715441%28v=vs.85%29.aspx

输入标识符需要标识所用缓冲区的 C 类型。 c 类型标识符都命名为SQL_C_foobar

因此,您应该将SQL_C_BINARY 作为参数传递(如果您想告诉驱动程序获取纯二进制数据)或SQL_C_CHAR(如果您想告诉驱动程序将数据转换为一些“字符数据”)。请注意,SQL_C_CHARSQL_CHAR 都定义为 1

关于驱动程序将数据转换为“字符串”的情况的更多解释:从 C 数据类型列表中可以看出,缓冲区类型 SQLCHAR 可用于多个“C 类型标识符” :如果您使用SQLCHAR 缓冲区,并将SQL_C_CHAR 作为InputType 传递,则驱动程序“知道”缓冲区的类型为SQLCHAR,并且您希望将数据作为“字符数据”获取。因此,在您的情况下,MySql 会将二进制数据转换为人类可读的内容,例如十六进制字符串。另一方面,如果您将SQL_C_BINARY 传递为InputType,则驱动程序“知道”缓冲区的类型为SQLCHAR,并且您对纯二进制值感兴趣,因此驱动程序无需转换将二进制数据转换为人类可读的字符串,它只会用纯二进制数据填充缓冲区。

有关 c 类型及其对应缓冲区类型的列表,请参见此处:https://msdn.microsoft.com/en-us/library/ms714556%28v=vs.85%29.aspx

作为一般说明:注意文档中是否谈到“Sql C 类型”或“Sql 类型”。第一个用于标识缓冲区的C类型,另一个用于标识列的逻辑数据库类型。

【讨论】:

  • 很好地解释了为什么它给了我十六进制数据。
【解决方案2】:

您是否曾经花一整天的时间试图找出答案,然后在发布问题 20 分钟后终于找到答案?我愿意。

我在this question 上注意到海报使用SQL_C_BINARYSQL_BINARY 相同。因此,当我按如下方式调用SQLGetData 时,我得到了我的期望。

SQLGetData(m_sqlstatementhandle, i, SQL_C_BINARY, &SqlChar, sizeof(SqlChar), (SQLLEN*)&indicator);

所以归结为提供了错误的目标类型。

编辑: 已编辑以反映@erg 帖子中的正确信息。

【讨论】:

    猜你喜欢
    • 2015-09-10
    • 2020-10-23
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 2014-02-09
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    相关资源
    最近更新 更多