在找到bug in MySQL ODBC 5.3.6之后,我还有一个问题,使用MySQL ODBC 5.3.4时也会遇到这个问题。
我有一个MS Access应用程序(Office 2016 ProPlus 32位),它使用ADODB和MySQL ODBC(5.3.4 32位)连接到Windows 10 Pro 64位计算机上的本地MySQL数据库服务器(5.7.16 64位)。在MySQL数据库中插入非ASCII字符失败,错误为“字符串值不正确”,但是如果我再次尝试同一语句,SQL语句将正确执行,并且将正确的值插入到数据库表中!
为了隔离问题,我创建了下表:
CREATE TABLE test2 (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(100) CHARACTER SET utf8mb4,
PRIMARY KEY (id));
以及包含以下VBA代码的测试MS Access数据库(以及对Microsoft ActiveX数据对象6.1库的引用):
Public Function dbTestIt2() as Long
Dim dbConn As New ADODB.Connection
Dim dbCmd As New ADODB.Command
Dim dbParams As New ADODB.Parameter
Dim l As Long
dbConn.ConnectionString = "Driver={MySQL ODBC 5.3 Unicode Driver};option=3;database=xxx;user=yyy;password=zzz;"
dbConn.Open
With dbCmd
.ActiveConnection = dbConn
.CommandType = adCmdText
.CommandText = " INSERT INTO test2 (name) VALUES (?);"
dbParams.Type = adVarChar
dbParams.Size = 100
dbParams.Value = "abcdèfgh"
dbParams.Direction = adParamInput
.Parameters.Append dbParams
.Execute l, , adExecuteNoRecords
End With
dbConn.Close
dbTestIt2 = l
End Function
my.ini中的相关行:
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
以下是测试结果:
执行在.Execute语句处停止,错误为80004005:[MySQL][ODBC 5.3(w)Driver][mysqld-5.7.16-log]字符串值不正确:第1行列“name”的“\xE8gh”;
如果我继续调试(F8),则正确执行SQL语句并将正确的值插入数据库表;
如果我使用“ANSI”ODBC驱动程序而不是“Unicode”驱动程序,则此测试第一次成功,但随后更复杂(如中文)的非ASCII字符将被问号替换;
我相信VBA内部使用Unicode,但MySQLdoes not support UTF16 for clients和在ODBC连接字符串中指定“charset=utf8mb4”或先执行“SET CHARACTER SET utf8mb4”都没有帮助,也不支持“SET NAMES utf8mb4”;
如果我使用INSERT IGNORE而不是INSERT,那么第一次执行似乎成功了,但是值实际上在“è”处被截断(因此只插入了“abcd”);
MySQL ODBC 5.3.6也会出现这种情况
我做错什么了吗?或者这是MySQL ODBC驱动程序中的另一个bug?
最佳答案
声明。。。
dbParams.Type = adVarChar
... 告诉ADODB.Parameter对象其值将是一个单字节字符字符串。这些单字节字符将传递给ODBC驱动程序,ODBC驱动程序将依次传递给MySQL数据库引擎。如果数据库引擎需要UTF-8字符,则会发生错误,因为
0xE8
(在许多“拉丁-1”类型的代码页(如Windows-1252)中è
)不是有效的UTF-8字节序列。将上述语句更改为。。。
dbParams.Type = adVarWChar
... 告诉ADODB.Parameter对象其值将是多字节(“宽”)字符字符串。当使用VBA字符串文字指定值时。。。
dbParams.Value = "dèf"
... ADODB将字符串从其单字节表示形式(基于当前的Windows区域设置)转换为Unicode,并将其传递给ODBC驱动程序。ODBC驱动程序能够将字符串从原始Unicode(
U+0064 U+00E8 U+0066
)重新打包为UTF-8编码(0x64 0xC3 0xA8 0x66
),并将其传递给数据库引擎。