"Incorrect string value" 在 MS Access (VBA) 中使用 ADODB 将非 ASCII 插入 MySQL 数据库时,但重试有效

"Incorrect string value" when inserting non-ASCII into MySQL database using ADODB in MS Access (VBA), but retry works

找到 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 位)连接到本地 MySQL 数据库服务器( 5.7.16 64 位)在 Windows 10 Pro 64 位计算机上。在 MySQL 数据库中插入非 ASCII 字符失败并出现错误 "Incorrect string value" 但如果我再次尝试相同的语句, SQL 语句将正确执行并将正确的值插入数据库table!

为了隔离问题,我创建了以下 table:

  CREATE TABLE test2 (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(100) CHARACTER SET utf8mb4,
    PRIMARY KEY (id));

以及包含以下 VBA 代码(以及对 Microsoft ActiveX 数据对象 6.1 库的引用)的测试 MS Access 数据库:

  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

测试结果如下:

  1. 执行在 .Execute 语句处停止,错误为 80004005:[MySQL][ODBC 5.3(w) Driver][mysqld-5.7.16-log]不正确的字符串值:'\xE8gh' for第 1 行的 'name' 列;
  2. 如果我继续调试 (F8),SQL 语句会正确执行并将正确的值插入数据库 table;
  3. 如果我使用 "ANSI" ODBC 驱动程序而不是 "Unicode" 驱动程序,此测试第一次成功,但随后更复杂(例如中文)的非 ASCII 字符被问号替换;
  4. 我相信 VBA 内部使用 Unicode 但 MySQL does not support UTF16 for clients 并在 ODBC 连接字符串中指定 "charset=utf8mb4" 或首先执行 "SET CHARACTER SET utf8mb4" 没有帮助"SET NAMES utf8mb4" 不受支持;
  5. 如果我使用 INSERT IGNORE 而不是 INSERT,第一次执行似乎成功了,但值实际上在“è”处被截断了(所以只插入了 "abcd");
  6. 它也发生在 MySQL ODBC 5.3.6

我是不是做错了什么,或者这是 MySQL ODBC 驱动程序中的另一个错误?

声明...

dbParams.Type = adVarChar

... 告诉 ADODB.Parameter 对象它的值将是一个单字节字符串。这些单字节字符将被传递给 ODBC 驱动程序,后者又将它们传递给 MySQL 数据库引擎。如果数据库引擎需要 UTF-8 字符,则会发生错误,因为 0xE8è 在许多 "latin-1" 类型的代码页中,如 Windows-1252)不是有效的 UTF-8 字节序列。

将上述语句更改为...

dbParams.Type = adVarWChar

... 告诉 ADODB.Parameter 对象它的值将是一个多字节 ("Wide") 字符的字符串。使用 VBA 字符串文字赋值时 ...

dbParams.Value = "dèf"

... ADODB 会将字符串从其单字节表示形式(基于当前 Windows 语言环境)转换为 Unicode,并将其传递给 ODBC 驱动程序。 ODBC 驱动程序能够 "repackage" 将原始 Unicode (U+0064 U+00E8 U+0066) 中的字符串转换为 UTF-8 编码 (0x64 0xC3 0xA8 0x66),并将其传递给数据库引擎。