Skip to content

Commit

Permalink
Switch from DBD::mysql to DBD::MariaDB
Browse files Browse the repository at this point in the history
DBD::mysql 5 recently dropped support for building from MySQL client
libraries prior to v8. This creates challenges for people still using
earlier versions, as well as those using MariaDB.

DBD::MariaDB forked from DBD::mysql back in 2018, and maintains
compatibility with both MySQL and MariaDB. It remains compatible with
earlier versions of MySQL as well as the MariaDB client libraries. It
also includes bug fixes and more transparent support for Unicode
encoding.

So switch from DBD::mysql to DBD::MariaDB. It's largely a drop-in
replacement, with just a few additional changes:

*   Add `_dsn()` to DBIEngine and always use it to connect to the
    database. Override it in mysql.pm to replace `dbi:mysql` with
    `dbi:MariaDB`. Also override it in some other drivers that mangle
    the value returned by URI::db.
*   Remove incompatible config parameters `mysql_enable_utf8` (no longer
    needed due to the aforementioned Unicode bug fixes),
    `mysql_auto_reconnect`, and `mysql_use_result`.
*   Read DBI handle attributes starting with `mariadb_` instead of
    `mysql_`.
*   Add a `USE` statement to set the registry as the current database
    after it has been created. Not sure how this wasn't required when
    using DBD::mysql, but aligns more closely with the requirements of
    other engines.

Resolves #825.
  • Loading branch information
theory committed Jan 4, 2025
1 parent 33291bd commit d17dff9
Show file tree
Hide file tree
Showing 24 changed files with 94 additions and 69 deletions.
2 changes: 1 addition & 1 deletion .github/ubuntu/mysql.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ set -e
if [ -z "$SKIP_DEPENDS" ]; then
sudo apt-get update -qq
sudo apt-get remove -qq mysql-common # https://github.com/actions/virtual-environments/issues/5067#issuecomment-1038752575
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq mysql-client default-libmysqlclient-dev
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -qq mariadb-client libmariadbd-dev
fi
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ jobs:
.github/ubuntu/snowflake.sh
.github/ubuntu/vertica.sh
- run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile
- run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBI DBD::ODBC DBD::Firebird DBD::Oracle DBD::mysql DBD::Pg Devel::Cover Devel::Cover::Report::Coveralls
- run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBI DBD::ODBC DBD::Firebird DBD::Oracle DBD::MariaDB DBD::Pg Devel::Cover Devel::Cover::Report::Coveralls
- name: Run Tests
env:
PERL5LIB: "${{ github.workspace }}/local/lib/perl5"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/mysql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
runs-on: ubuntu-latest
services:
# Run the MySQL service in a container we can connect to. Means that the
# CLI and libraries DBD::mysql use are static to the version on the runner
# CLI and libraries DBD::MariaDB use are static to the version on the runner
# machine.
mysql:
image: "${{ matrix.image }}:${{ matrix.version }}"
Expand All @@ -63,7 +63,7 @@ jobs:
path: local
key: perl-${{ steps.perl.outputs.perl-hash }}
- run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends --cpanfile dist/cpanfile
- run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::mysql
- run: cpm install --verbose --show-build-log-on-failure --no-test --with-recommends DBD::MariaDB
- name: prove
env:
PERL5LIB: "${{ github.workspace }}/local/lib/perl5"
Expand Down
5 changes: 5 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ Revision history for Perl extension App::Sqitch
permission to create a schema and to skip the creation of the registry
schema. Useful for cases when the registry schema was created in
advance. Thanks to Peter Wimsey for the suggestion (#826).
- Switched the MySQL engine from DBD::mysql to DBD::MariaDB for better
compatibility with older versions of the MySQL client library and for
its Unicode improvements. Thanks to Mark Tyrrell for the report and
@tiberiusferreira and Perl Monks `1nickt` and`InfiniteSilence` for the
feedback (#825).

1.4.1 2024-02-04T16:35:32Z
- Removed the quoting of the role and warehouse identifiers that was
Expand Down
4 changes: 2 additions & 2 deletions dist.ini
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Test::Spelling = 0
Test::MockObject::Extends = 1.20180705
DBD::SQLite = 1.37
DBD::Pg = 2.0
DBD::mysql = 4.018
DBD::MariaDB = 1.0
MySQL::Config = 0
DBD::Firebird = 1.11
DBD::ODBC = 1.59
Expand Down Expand Up @@ -107,7 +107,7 @@ DBD::SQLite = 1.37
[OptionalFeature / mysql]
-description = Support for managing MySQL databases
-prompt = 0
DBD::mysql = 4.018
DBD::MariaDB = 1.0
MySQL::Config = 0

[OptionalFeature / firebird]
Expand Down
6 changes: 3 additions & 3 deletions dist/cpanfile
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ suggests "DBD::ODBC" => "1.59";
suggests "DBD::Oracle" => "1.23";
suggests "DBD::Pg" => "2.0";
suggests "DBD::SQLite" => "1.37";
suggests "DBD::mysql" => "4.018";
suggests "DBD::MariaDB" => "1.0";
suggests "MySQL::Config" => "0";
suggests "Time::HiRes" => "0";
suggests "Time::Local" => "0";
Expand Down Expand Up @@ -120,7 +120,7 @@ on 'develop' => sub {
requires "DBD::Oracle" => "1.23";
requires "DBD::Pg" => "2.0";
requires "DBD::SQLite" => "1.37";
requires "DBD::mysql" => "4.018";
requires "DBD::MariaDB" => "1.0";
requires "MySQL::Config" => "0";
requires "Time::HiRes" => "0";
requires "Time::Local" => "0";
Expand All @@ -131,7 +131,7 @@ on 'develop' => sub {
recommends "DBD::ODBC" => "1.59";
recommends "DBD::Pg" => "2.0";
recommends "DBD::SQLite" => "1.37";
recommends "DBD::mysql" => "4.018";
recommends "DBD::MariaDB" => "1.0";
recommends "Dist::Zilla" => "5";
recommends "Dist::Zilla::Plugin::AutoPrereqs" => "0";
recommends "Dist::Zilla::Plugin::CPANFile" => "0";
Expand Down
2 changes: 1 addition & 1 deletion dist/sqitch.spec
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ Group: Development/Libraries
Requires: sqitch >= %{version}
Requires: mysql >= 5.1.0
Requires: perl(DBI) >= 1.631
Requires: perl(DBD::mysql) >= 4.018
Requires: perl(DBD::MariaDB) >= 1.0
Requires: perl(MySQL::Config)
Provides: sqitch-mysql

Expand Down
2 changes: 1 addition & 1 deletion inc/Menlo/Sqitch.pm
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ Runtime-only dependencies
DBD-ODBC
DBD-Oracle
DBD-Pg
DBD-mysql
DBD-MariaDB
Data-OptList
DateTime
DateTime-Locale
Expand Down
3 changes: 1 addition & 2 deletions lib/App/Sqitch/Engine/exasol.pm
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ has dbh => (
my $self = shift;
$self->use_driver;

my $uri = $self->uri;
DBI->connect($uri->dbi_dsn, $self->username, $self->password, {
DBI->connect($self->_dsn, $self->username, $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
8 changes: 5 additions & 3 deletions lib/App/Sqitch/Engine/firebird.pm
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ sub registry_destination {

sub _def_user { $ENV{ISC_USER} }
sub _def_pass { $ENV{ISC_PASSWORD} }
sub _dsn {
my $uri = shift->registry_uri;
return $uri->dbi_dsn . ';ib_dialect=3;ib_charset=UTF8';
}

has dbh => (
is => 'rw',
Expand All @@ -69,11 +73,9 @@ has dbh => (
clearer => '_clear_dbh',
default => sub {
my $self = shift;
my $uri = $self->registry_uri;
$self->use_driver;

my $dsn = $uri->dbi_dsn . ';ib_dialect=3;ib_charset=UTF8';
return DBI->connect($dsn, scalar $self->username, scalar $self->password, {
return DBI->connect($self->_dsn, scalar $self->username, scalar $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
41 changes: 22 additions & 19 deletions lib/App/Sqitch/Engine/mysql.pm
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,30 @@ has _mycnf => (
sub _def_user { $_[0]->_mycnf->{user} || $_[0]->sqitch->sysuser }
sub _def_pass { $ENV{MYSQL_PWD} || shift->_mycnf->{password} }

sub _dsn {
(my $dsn = shift->uri->dbi_dsn) =~ s/\Adbi:mysql/dbi:MariaDB/;
return $dsn;
}

has dbh => (
is => 'rw',
isa => DBH,
lazy => 1,
default => sub {
my $self = shift;
$self->use_driver;
my $uri = $self->registry_uri;
my $dbh = DBI->connect($uri->dbi_dsn, $self->username, $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
mysql_enable_utf8 => 1,
mysql_auto_reconnect => 0,
mysql_use_result => 0, # Prevent "Commands out of sync" error.
HandleError => $self->error_handler,
Callbacks => {
my $dbh = DBI->connect($self->_dsn, $self->username, $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
HandleError => $self->error_handler,
Callbacks => {
connected => sub {
my $dbh = shift;
$dbh->do("SET SESSION $_") or return for (
q{character_set_client = 'utf8'},
q{character_set_server = 'utf8'},
($dbh->{mysql_serverversion} || 0 < 50500 ? () : (q{default_storage_engine = 'InnoDB'})),
($dbh->{mariadb_serverversion} || 0 < 50500 ? () : (q{default_storage_engine = 'InnoDB'})),
q{time_zone = '+00:00'},
q{group_concat_max_len = 32768},
q{sql_mode = '} . join(',', qw(
Expand All @@ -105,15 +106,15 @@ has dbh => (
});

# Make sure we support this version.
my ($dbms, $vnum, $vstr) = $dbh->{mysql_serverinfo} =~ /mariadb/i
my ($dbms, $vnum, $vstr) = $dbh->{mariadb_serverinfo} =~ /mariadb/i
? ('MariaDB', 50300, '5.3')
: ('MySQL', 50100, '5.1.0');
hurl mysql => __x(
'Sqitch requires {rdbms} {want_version} or higher; this is {have_version}',
rdbms => $dbms,
want_version => $vstr,
have_version => $dbh->selectcol_arrayref('SELECT version()')->[0],
) unless $dbh->{mysql_serverversion} >= $vnum;
) unless $dbh->{mariadb_serverversion} >= $vnum;

return $dbh;
}
Expand Down Expand Up @@ -211,17 +212,17 @@ has _fractional_seconds => (
lazy => 1,
default => sub {
my $dbh = shift->dbh;
return $dbh->{mysql_serverinfo} =~ /mariadb/i
? $dbh->{mysql_serverversion} >= 50305
: $dbh->{mysql_serverversion} >= 50604;
return $dbh->{mariadb_serverinfo} =~ /mariadb/i
? $dbh->{mariadb_serverversion} >= 50305
: $dbh->{mariadb_serverversion} >= 50604;
},
);

sub mysql { @{ shift->_mysql } }

sub key { 'mysql' }
sub name { 'MySQL' }
sub driver { 'DBD::mysql 4.018' }
sub driver { 'DBD::MariaDB 1.0' }
sub default_client { 'mysql' }

sub _char2ts {
Expand Down Expand Up @@ -282,6 +283,7 @@ sub _initialize {
# Deploy the registry to the Sqitch database.
$self->run_upgrade( file(__FILE__)->dir->file('mysql.sql') );
$self->_set_initialized(1);
$self->dbh->do('USE ' . $self->dbh->quote_identifier($self->registry));
$self->_register_release;
}

Expand Down Expand Up @@ -478,7 +480,7 @@ sub _prepare_registry_file {

# Strip out 5.5 stuff on earlier versions.
$sql =~ s/-- ## BEGIN 5[.]5.+?-- ## END 5[.]5//ms
if $self->dbh->{mysql_serverversion} < 50500;
if $self->dbh->{mariadb_serverversion} < 50500;
}

if (!$can_create_checkit) {
Expand All @@ -501,11 +503,12 @@ sub _prepare_registry_file {
# determine whether we have binary logging disabled, or trust function
# creators, or have the SUPER privilege.
sub _can_create_immutable_function {
# Use md5() to prevent "Illegal mix of collations" errors.
shift->dbh->selectcol_arrayref(q{
SELECT @@log_bin = 0
OR @@log_bin_trust_function_creators = 1
OR (
SELECT super_priv = 'Y' FROM mysql.user
SELECT md5(super_priv) = md5('Y') FROM mysql.user
WHERE CONCAT(user, '@', host) = current_user
)
})->[0]
Expand Down
3 changes: 1 addition & 2 deletions lib/App/Sqitch/Engine/oracle.pm
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ has dbh => (
my $self = shift;
$self->use_driver;

my $uri = $self->uri;
DBI->connect($uri->dbi_dsn, $self->username, $self->password, {
DBI->connect($self->_dsn, $self->username, $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
3 changes: 1 addition & 2 deletions lib/App/Sqitch/Engine/pg.pm
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,8 @@ has dbh => (
my $self = shift;
$self->use_driver;

my $uri = $self->uri;
local $ENV{PGCLIENTENCODING} = 'UTF8';
DBI->connect($uri->dbi_dsn, $self->username, $self->password, {
DBI->connect($self->_dsn, $self->username, $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
3 changes: 1 addition & 2 deletions lib/App/Sqitch/Engine/snowflake.pm
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,9 @@ has dbh => (
default => sub {
my $self = shift;
$self->use_driver;
my $uri = $self->uri;
my $wh = $self->warehouse;
my $role = $self->role;
DBI->connect($uri->dbi_dsn, $self->username, $self->password, {
DBI->connect($self->_dsn, $self->username, $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
4 changes: 2 additions & 2 deletions lib/App/Sqitch/Engine/sqlite.pm
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ sub key { 'sqlite' }
sub name { 'SQLite' }
sub driver { 'DBD::SQLite 1.37' }
sub default_client { 'sqlite3' }
sub _dsn { shift->registry_uri->dbi_dsn }

has dbh => (
is => 'rw',
Expand All @@ -70,8 +71,7 @@ has dbh => (
my $self = shift;
$self->use_driver;

my $uri = $self->registry_uri;
my $dbh = DBI->connect($uri->dbi_dsn, '', '', {
my $dbh = DBI->connect($self->_dsn, '', '', {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
21 changes: 12 additions & 9 deletions lib/App/Sqitch/Engine/vertica.pm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ has _vsql => (

sub vsql { @{ shift->_vsql } }

sub _dsn {
my $self = shift;
# Set defaults in the URI.
my $uri = $self->uri;
# https://my.vertica.com/docs/5.1.6/HTML/index.htm#2736.htm
$uri->dbname($ENV{VSQL_DATABASE}) if !$uri->dbname && $ENV{VSQL_DATABASE};
$uri->host($ENV{VSQL_HOST}) if !$uri->host && $ENV{VSQL_HOST};
$uri->port($ENV{VSQL_PORT}) if !$uri->_port && $ENV{VSQL_PORT};
return $uri->dbi_dsn;
}

has dbh => (
is => 'rw',
isa => DBH,
Expand All @@ -76,15 +87,7 @@ has dbh => (
my $self = shift;
$self->use_driver;

# Set defaults in the URI.
my $target = $self->target;
my $uri = $self->uri;
# https://my.vertica.com/docs/5.1.6/HTML/index.htm#2736.htm
$uri->dbname($ENV{VSQL_DATABASE}) if !$uri->dbname && $ENV{VSQL_DATABASE};
$uri->host($ENV{VSQL_HOST}) if !$uri->host && $ENV{VSQL_HOST};
$uri->port($ENV{VSQL_PORT}) if !$uri->_port && $ENV{VSQL_PORT};

DBI->connect($uri->dbi_dsn, $self->username, $self->password, {
DBI->connect($self->_dsn, $self->username, $self->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
2 changes: 2 additions & 0 deletions lib/App/Sqitch/Role/DBIEngine.pm
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ after use_driver => sub {
DBI->trace(1) if $_[0]->sqitch->verbosity > 2;
};

sub _dsn { shift->target->uri->dbi_dsn }

sub _dt($) {
require App::Sqitch::DateTime;
return App::Sqitch::DateTime->new(split /:/ => shift);
Expand Down
2 changes: 1 addition & 1 deletion po/fr_FR.po
Original file line number Diff line number Diff line change
Expand Up @@ -1618,7 +1618,7 @@ msgstr "L'email utilisateur ne peut contenir \">\""
#~ msgstr "Cible de déploiement inconnue : \"{target}\""

#, fuzzy
#~ msgid "DBD::mysql module required to manage MySQL"
#~ msgid "DBD::MariaDB module required to manage MySQL"
#~ msgstr "Module DBD::Pg requis pour gérer PostgreSQL"

#, fuzzy
Expand Down
5 changes: 4 additions & 1 deletion t/dbiengine_role.t
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ can_ok $CLASS, qw(
_in_expr
_register_release
_version_query
_dsn
registry_version
_cid
earliest_change_id
Expand Down Expand Up @@ -72,10 +73,12 @@ can_ok $CLASS, qw(
begin_work
finish_work
rollback_work
_eh
error_handler
);

is App::Sqitch::Role::DBIEngine::_ts_default, 'DEFAULT',
'_ts_default shoudld return DEFAULT';
'_ts_default should return DEFAULT';

# Test various failure modes.
my $role = bless {} => $CLASS;
Expand Down
2 changes: 2 additions & 0 deletions t/firebird.t
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ is $fb->name, 'Firebird', 'Name should be "Firebird"';
is $fb->username, $ENV{ISC_USER}, 'Should have username from environment';
is $fb->password, $ENV{ISC_PASSWORD}, 'Should have password from environment';
is $fb->_limit_default, '18446744073709551615', 'Should have _limit_default';
is $fb->_dsn, 'dbi:Firebird:dbname=sqitch.fdb;ib_dialect=3;ib_charset=UTF8',
'Should append "ib_dialect=3;ib_charset=UTF8" to the DSN';

my $have_fb_client;
if ($have_fb_driver && (my $client = try { $fb->client })) {
Expand Down
2 changes: 1 addition & 1 deletion t/lib/DBIEngineTest.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1773,7 +1773,7 @@ sub run {
ok $engine->wait_lock, 'Should not have to wait for lock';

# Make a second connection to the database.
my $dbh = DBI->connect($engine->uri->dbi_dsn, $engine->username, $engine->password, {
my $dbh = DBI->connect($engine->_dsn, $engine->username, $engine->password, {
PrintError => 0,
RaiseError => 0,
AutoCommit => 1,
Expand Down
Loading

0 comments on commit d17dff9

Please sign in to comment.