0

I'm developing on Delphi application that communicate with remote MariaDB database (via ADO and ODBC driver). Find out that on some computers cannot add Cyrillic strings to DB. Error message like this: [MySQL][ODBC 8.0(w) Driver][mysqld-5.5.5-10.3.29-MariaDB]Incorrect string value: '\xC2\xC2\xC8 \xF1\xE8…' for column <here's target tables and columns name> at row 1
Charset is utf8, collate - utf8_bin. It works perfect on my computer with Windows 10, but error fired on computers with Windows 8 and Vista. So, as I understand, problem not in database settings, but in OS. What it can be? Maybe regional settings or something this?

Update

Table:

SHOW CREATE TABLE equip;

CREATE TABLE `equip` (
 `eqid` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `eqname` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Наименование оборудования',
 PRIMARY KEY (`eqid`),
 UNIQUE KEY `eqname_UNIQUE` (`eqname`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

Connect to DB:

  procedure OpenDBConnection;
  begin
    dmMain.dbConnection.Connected := False;
    dmMain.dbConnection.ConnectionString := Format(
      'Driver={MySQL ODBC 8.0 Unicode Driver};Port=%s;Server=%s;Database=%s;User=%s;Password=%s;',
      [Port, Server, Database, User, Password]);
    dmMain.dbConnection.Connected := True;
  end;

Insert data to DB:

const
  tblEquip = 'equip';
  colEquipName = 'eqname';

  queryInsertEquipment =
    ' INSERT INTO ' + tblEquip + '(' +
    colEquipName + ') ' +
    'VALUES(:' +
    colEquipName + '); ';


function TdmMain.AddEquipment(const Equip: TEquipment;
  const RefreshEquipmentListDataSet: Boolean): Integer;
begin
  Result := 0;

  try
    cmdTemp.CommandText := queryInsertEquipment;
    cmdTemp.Parameters.ParamByName(colEquipName).Value := Equip.Name;
    cmdTemp.Execute;
    Result := GetLastID;

    if RefreshEquipmentListDataSet then
      RefreshDataSet(dsetEquipment, colEquipID, Result);
  except on E: Exception do
    fmMessage.ShowMessage(msgErrorAddEquipment, mtError);
  end;
end;
m1know
  • 189
  • 1
  • 14
  • 1
    Include code where you connect with the DB and ensure that you're talking in UTF-8 to your DB. If you don't do the latter it's most likely up to the driver's default. This looks like [ISO-8859-5](https://en.wikipedia.org/wiki/ISO/IEC_8859-5): `ТТШ ёш` – AmigoJack Jun 09 '21 at 13:04
  • @AmigoJack, thank you for reply, I update question with code. – m1know Jun 10 '21 at 05:19
  • Also today try on other virtual machine with Windows 10 - it works, but on Windows 7 or Vista - no. Plus update on these machines MDAC to 2.8 - no result. – m1know Jun 10 '21 at 05:25
  • Just as I feared: you nowhere tell that you're using UTF-8. Consider executing [`SET NAMES utf8mb4`](https://stackoverflow.com/q/2159434/4299358) after having established the connection to the DB. Read also [UTF-8 all the way through](https://stackoverflow.com/a/279279/4299358). – AmigoJack Jun 10 '21 at 08:17
  • If set parameter type to `ftWideString` by code `cmdTemp.Parameters.ParamByName(colEquipName).DataType := ftWideString;` then it works OK. But although it strange - the same code work on Windows 10, but don't work on old OS. – m1know Jun 10 '21 at 10:02
  • Again: define in your program/driver what you want instead of assuming it. Always, everywhere. You can't expect every driver installation to come with the same defaults. – AmigoJack Jun 10 '21 at 11:16
  • Yes, for example I try to add `charset=utf8;` (also even with `utf8mb4` but my DB in `utf8mb3`) in connection string but with nothing result. I'm trying to avoid using `SET NAMES` because of that will be affect server but not client side, right? We need something like `mysqli::set_charset` in PHP, but for Delphi. – m1know Jun 10 '21 at 14:15

1 Answers1

2

You have to define the encoding of the communication between client and database. If you don't, then the database assumes an encoding and the client may assume a different one. Most likely older installations don't use UTF-8 by default. Just because all your database tables are defined with Unicode charsets and collations it doesn't mean data written to and read from those is communicated in that same encoding.

  • MySQL's SET NAMES is a convenient way to set multiple variables at once. Using an encoding like utf8 does not convert anything - it tells the database to interpret all the incoming bytes in that encoding (and to use that encoding when sending out bytes for all your results).
  • PHP's mysqli_set_charset() is internally doing the same but provides this function to also be aware of your choice for other convenient functions (such as mysqli_real_escape_string()).

After you made sure the communication actually happens in UTF-8 only your client itself is left: does the driver do the conversion for you if you hand over a Delphi Widestring? Or do you have to provide actual UTF-8 encoded bytes as your query? The links are not for fun: the documentations tell you enough facts that can be checked and tested - there's no need to question them and make wild assumptions - that only makes you understand it wrong.

AmigoJack
  • 5,234
  • 1
  • 15
  • 31
  • I was trying use `SET NAMES`, but get an error `SET NAMES not allowed by driver` as it is not supported by ODBC (look at https://stackoverflow.com/a/6417321/813350). Also trying direct set variables `character_set_client`, `character_set_results` and `character_set_connection` to `utf8` but no result. – m1know Jun 11 '21 at 06:05
  • Are you sure always choosing `charset=utf8;` in the connection is even correct? Have you tried using the actual locale encoding of the user, i.e. `cp1251`? What's the default value of the driver? This looks like [shotgun debugging](https://en.wikipedia.org/wiki/Shotgun_debugging) and I can't help you with that. – AmigoJack Jun 11 '21 at 12:06