如何在 C++ 中使用 SQLGetData 获取 MySQL blob 作为二进制数据
How to get a MySQL blob as binary data using SQLGetData in C++
我有一个包含 mediumblob
列的 MySQL 数据库。我想在 Windows.
上使用 ODBC 将二进制数据从 blob 字段获取到 C++ stringstream
我先调用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 数据,但它作为 HEX 字符串存储在 SqlChar
中。
我的程序希望字符串流中的数据以二进制形式存储。现在我可以先将 HEX 字符串转换为二进制,然后将其写入字符串流,但这对我来说并不合适。我真的很想直接从 SQLGetData
.
得到它的二进制文件
所以有几个问题:
- 我对 blob 类型使用
SQLGetData
正确吗?
SQLCHAR
数组是写入的正确容器吗?
- 有没有办法通过 ODBC 直接从 MySQL 获取二进制数据?
谢谢。
您是否曾经花一整天的时间试图弄清楚一些事情,然后在 post 提出您的问题 20 分钟后终于找到答案?我愿意。
我在 this question 上注意到 poster 使用 SQL_C_BINARY
, 与 SQL_BINARY
相同。因此,当我按如下方式调用 SQLGetData
时,我得到了我期望的结果。
SQLGetData(m_sqlstatementhandle, i, SQL_C_BINARY, &SqlChar, sizeof(SqlChar), (SQLLEN*)&indicator);
归结为提供了错误的目标类型。
编辑:
编辑以反映来自@erg post.
的正确信息
提供 SQL_BINARY
作为参数是错误的(即使它在这里有效,因为 SQL_BINARY
和 SQL_C_BINARY
似乎被定义为相同的值)。来自 SQLGetData
的文档,关于第三个参数 TargetType
:
[Input] The type identifier of the C data type of the *TargetValuePtr
buffer. For a list of valid C data types and type identifiers, see the
C Data Types section in Appendix D: Data Types.
参见:https://msdn.microsoft.com/en-us/library/ms715441%28v=vs.85%29.aspx
输入标识符需要标识所用缓冲区的C 类型。 c 类型标识符的名称都类似于 SQL_C_foobar
。
所以,你应该传递 SQL_C_BINARY
作为参数(如果你想告诉驱动程序获取纯二进制数据)或 SQL_C_CHAR
(如果你想告诉驱动程序转换一些 "character data") 的数据。请注意,SQL_C_CHAR
和 SQL_CHAR
都定义为 1
.
关于驱动程序将数据转换为 "string" 的情况的更多解释:正如您从 C 数据类型列表中看到的那样,缓冲区类型 SQLCHAR
可用于multiple "C type identifiers": 如果你使用 SQLCHAR
缓冲区,并且将 SQL_C_CHAR
作为 InputType
传递,驱动程序 "knows" 缓冲区的类型为 SQLCHAR
并且您希望获取 "character data" 形式的数据。因此,在您的情况下, MySql 会将二进制数据转换为人类可读的内容,例如十六进制字符串。另一方面,如果您将 SQL_C_BINARY
作为 InputType
传递,驱动程序 "knows" 认为缓冲区的类型是 SQLCHAR
并且您对纯二进制值感兴趣,所以有驱动程序不需要将二进制数据转换为人类可读的字符串,它只会用普通二进制数据填充缓冲区。
在这里查看 c 类型列表及其对应的缓冲区类型:https://msdn.microsoft.com/en-us/library/ms714556%28v=vs.85%29.aspx
作为一般注意事项:注意文档是否谈到 "Sql C Type" 或 "Sql Type"。第一个用于标识缓冲区的 C 类型,另一个用于标识列的逻辑数据库类型。
我有一个包含 mediumblob
列的 MySQL 数据库。我想在 Windows.
我先调用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 数据,但它作为 HEX 字符串存储在 SqlChar
中。
我的程序希望字符串流中的数据以二进制形式存储。现在我可以先将 HEX 字符串转换为二进制,然后将其写入字符串流,但这对我来说并不合适。我真的很想直接从 SQLGetData
.
所以有几个问题:
- 我对 blob 类型使用
SQLGetData
正确吗? SQLCHAR
数组是写入的正确容器吗?- 有没有办法通过 ODBC 直接从 MySQL 获取二进制数据?
谢谢。
您是否曾经花一整天的时间试图弄清楚一些事情,然后在 post 提出您的问题 20 分钟后终于找到答案?我愿意。
我在 this question 上注意到 poster 使用 SQL_C_BINARY
, 与 相同。因此,当我按如下方式调用 SQL_BINARY
SQLGetData
时,我得到了我期望的结果。
SQLGetData(m_sqlstatementhandle, i, SQL_C_BINARY, &SqlChar, sizeof(SqlChar), (SQLLEN*)&indicator);
归结为提供了错误的目标类型。
编辑: 编辑以反映来自@erg post.
的正确信息提供 SQL_BINARY
作为参数是错误的(即使它在这里有效,因为 SQL_BINARY
和 SQL_C_BINARY
似乎被定义为相同的值)。来自 SQLGetData
的文档,关于第三个参数 TargetType
:
[Input] The type identifier of the C data type of the *TargetValuePtr buffer. For a list of valid C data types and type identifiers, see the C Data Types section in Appendix D: Data Types.
参见:https://msdn.microsoft.com/en-us/library/ms715441%28v=vs.85%29.aspx
输入标识符需要标识所用缓冲区的C 类型。 c 类型标识符的名称都类似于 SQL_C_foobar
。
所以,你应该传递 SQL_C_BINARY
作为参数(如果你想告诉驱动程序获取纯二进制数据)或 SQL_C_CHAR
(如果你想告诉驱动程序转换一些 "character data") 的数据。请注意,SQL_C_CHAR
和 SQL_CHAR
都定义为 1
.
关于驱动程序将数据转换为 "string" 的情况的更多解释:正如您从 C 数据类型列表中看到的那样,缓冲区类型 SQLCHAR
可用于multiple "C type identifiers": 如果你使用 SQLCHAR
缓冲区,并且将 SQL_C_CHAR
作为 InputType
传递,驱动程序 "knows" 缓冲区的类型为 SQLCHAR
并且您希望获取 "character data" 形式的数据。因此,在您的情况下, MySql 会将二进制数据转换为人类可读的内容,例如十六进制字符串。另一方面,如果您将 SQL_C_BINARY
作为 InputType
传递,驱动程序 "knows" 认为缓冲区的类型是 SQLCHAR
并且您对纯二进制值感兴趣,所以有驱动程序不需要将二进制数据转换为人类可读的字符串,它只会用普通二进制数据填充缓冲区。
在这里查看 c 类型列表及其对应的缓冲区类型:https://msdn.microsoft.com/en-us/library/ms714556%28v=vs.85%29.aspx
作为一般注意事项:注意文档是否谈到 "Sql C Type" 或 "Sql Type"。第一个用于标识缓冲区的 C 类型,另一个用于标识列的逻辑数据库类型。