brianmario / mysql2

A modern, simple and very fast Mysql library for Ruby - binding to libmysql
http://github.com/brianmario/mysql2
MIT License
2.25k stars 550 forks source link

MariaDB client version vs. package version error #1348

Open chadmyers opened 9 months ago

chadmyers commented 9 months ago

Ruby: 3.1.3.1 Platform: Windows, msys2, mingw64 MariaDB Connector/C version: 3.3.8 mysql2 gem version: 0.5.5

My MariaDB client lib install command: ridk exec sh -c "pacman -S --needed --noconfirm mingw-w64-x86_64-libmariadbclient"

My Gem install command:

& C:\tools\ruby31\bin\gem.cmd install mysql2 --no-document --no-post-install-message -q -- --with-mysql-lib=C:\tools\msys64\mingw64\lib --with-mysql-include=C:\tools\msys64\mingw64\include

I've also tried with the same effect:

& C:\tools\ruby31\bin\gem.cmd install mysql2 --no-document --no-post-install-message -q -- --with-mysql-dir=C:\tools\msys64\mingw64

I can successfully gem install/compile the mysql2 gem but when I try to use it, I get the error:

Gem Load Error is: Incorrect MySQL client library version! This gem was compiled for 10.8.8 but the client library is 3.3.8.

I noticed in mysql2/ext/mysql2/client.c file it has (lines 52-58)

#if defined(MARIADB_CLIENT_VERSION_STR)
  #define MYSQL_LINK_VERSION MARIADB_CLIENT_VERSION_STR
#elif defined(LIBMYSQL_VERSION)
  #define MYSQL_LINK_VERSION LIBMYSQL_VERSION
#else
  #define MYSQL_LINK_VERSION MYSQL_SERVER_VERSION
#endif

Then (lines 1514 - 1526):

const char *lib = mysql_get_client_info();

...

    if (lib[i] != MYSQL_LINK_VERSION[i]) {
      rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_LINK_VERSION, lib);

My msys64\mingw64\include\mysql\mariadb_version.h file has:

#define MARIADB_CLIENT_VERSION_STR      "10.8.8"
...
#define MARIADB_PACKAGE_VERSION "3.3.8"

MariaDB client's mysql_get_client_info() function returns MARIADB_PACKAGE_VERSION, but mysql2 gem is comparing that against the MARIADB_CLIENT_VERSION_STR.

What I don't understand is that this stuff has been there for 3 years, but my mysql2 gem installation only just started breaking within the last 30 days or so. It worked in December when I rebuilt an AMI in AWS using the latest mysql2 gem (0.5.4) and MariaDB client (I think it was 3.3.7 or maybe 3.3.8).

Any thoughts on why this worked and why it's not working now? Thanks in advance!

chadmyers commented 9 months ago

New information: I was able to get mysql2 0.5.5 gem to successfully install and work in a running application by using the old 3.1.13 ucrt64 version of the mariadb client. So I think the mariadb client folks changed how the versioning worked out from underneath the mysql2 gem, so you might need to add some extra logic to handle the difference

cocco111 commented 8 months ago

I can confirm the issue. Alternative solution to work with last gem version on windows:

Specifing mysql-dir in which mariadbclient resides, is needed to avoid this error:

`block in find_library': undefined method `split' for nil:NilClass (NoMethodError)
 paths = paths.flat_map {|path| path.split(File::PATH_SEPARATOR)}
Whaat commented 7 months ago

Thanks @cocco111, I'm trying to use your solution but struggling probably due to my inexperience working with gems.

  • download gem and rebuild without this line

I assuming this means, download the gem source code from github, comment out the 'line' in the source code you referenced and rebuild using: gem build mysql2.gemspec This creates a new file mysql2-0.5.6.gem in the working directory. Next I ran

  • gem install mysql2-0.5.6.gem -- --with-mysql-dir=c:/<Ruby-install-dir>/msys64/ucrt64

However, this failed for me with the error:

        ERROR: Failed to build gem native extension.

    No such file or directory @ dir_s_mkdir - C:/Ruby32-x64/lib/ruby/gems/3.2.0/gems/mysql2-0.5.6/ext/mysql2/.gem.20240411-17300-dt82ue

Any help is greatly appreciated. I am wondering if this is some sort of caching issue or maybe I need to update the version number of the gem for it to work...?

cocco111 commented 7 months ago

Hello @Whaat , almost correct but I suggest to

This to avoid starting from source code, that for sure has additional building steps, deps, etc... Hope it helps you!

Whaat commented 7 months ago

Thanks, but unfortunately that approach does not seem to work. First problem is that the gemspec file did not exist inside the uncompressed .gem / tar. So I tried downloading it from github. But when running gem build I got fatal: not a git repository (or any of the parent directories)

It's OK though I was able to build it now using my original approach. I re-cloned the repo and made sure to checkout the proper release tag (0.5.6). I also made sure to gem uninstall mysql2 before I installed my modified version. Perhaps I forgot that step last time, who knows.

cocco111 commented 7 months ago

@Whaat try this way: if you already have mysql2 installed, put .gemspec inside mysql2-0.5.6 installation dir (in gems folder), modify .c file and do a gem build The result should be a .gem with these folders as data : ext, lib, support Then, as you said, uninstall mysql2 and try to install your new gem

jwalkerbg commented 5 months ago

Same to me. What I did:

  1. Cloned https://github.com/brianmario/mysql2.git
  2. Switched to tag v0.5.6
  3. Edited mysql2/ext/mysql2/client.c (commented the if operator) at lines 1541-1543: if (lib[i] != MYSQL_LINK_VERSION[i]) { ... }
  4. Executed gem build mysql2.gemspec
  5. Uninstalled before installed mysql2 gems.
  6. Installed the gem built in point 4.

My command to install mysql2 is

gem install mysql2-0.5.6.gem --platform=ruby -- '--with-mysql-lib="C:\Program%20Files\MySQL\MySQL%20Server%205.7\lib" --with-mysql-include="C:\Program%20Files\MySQL\MySQL%20Server%205.7\include" --with-mysql-dir="C:\Program%20Files\MySQL\MySQL%20Server%205.7"'

MySQL is installed at C:\Program Files\MySQL\MySQL Server 5.7.

zawhtutwin commented 5 months ago

git clone https://github.com/brianmario/mysql2.git

cd mysql2

git checkout 0.5.6

cd ext

open client.c and comment the following line

   /* 
   if (lib[i] != MYSQL_LINK_VERSION[i]) {
      rb_raise(rb_eRuntimeError, "Incorrect MySQL client library version! This gem was compiled for %s but the client library is %s.", MYSQL_LINK_VERSION, lib);
    }*/

go to the project root dir and do

gem build mysql2.gemspec

copy mysql2-0.5.6.gem to your rails project folder and do

gem install mysql2-0.5.6.gem -- --with-mysql-dir="E:\Ruby32-x64" (assumed libmysql.dll is already in this folder)

sampenguin commented 4 months ago

Can confirm this issue still appears in mysql2 0.5.6 with Ruby 3.3.3 on Windows. Just like OP, mine was working fine with both 0.5.5 and 0.5.6 and then suddenly stopped, however I think in my case it was related to either upgrading Ruby from 3.2.x and/or upgrading RubyGems in my project.

@zawhtutwin 's workaround steps solved the problem in my case.

chadmyers commented 4 months ago

@sampenguin I see the issue on both Ruby 3.1 and Ruby 3.3.3.1 on Windows and Linux. It's definitely an issue with the mysql2 gem and how it does version checking which has been messed up now that the libmariadb-client folks changed how their version constants work.

sodabrew commented 4 months ago

Sounds to me that CI config using latest Ubuntu with MariaDB libs would help. For some of the CI configs, MySQL proper is fetched rather than using the distro package

The OP comment explains how Mariadb is using the constants in a manner that's confusing the check login. I'll see about improving this.

On the flip side, this error may be revealing that some folks are using different packages in your CI builds vs prod runtime environments. I urge double checking this as well. There is a high degree of compatibility of MySQL client libraries, but not perfect, which is what I recall (vaguely over the years now) this check was added for.

LeonardoEckertMarques commented 2 months ago

Thanks guys @zawhtutwin @chadmyers