jhthorsen / mojo-mysql

Mojolicious and Async MySQL

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Are domain sockets supported, as described in the POD?

jplindstrom opened this issue · comments

This is the POD:

  # Username, domain socket and database
  $mysql->from_string('mysql://batman@%2ftmp%2fmysql.sock/db4');

I try to use Mojo::mysql with Minion, using this dsn string:

mysql://root@%2ftmp%2fN0ThIghu3o%2ftmp%2fmysql.sock/coordinator

But I get this error:

SQL error: DBI connect('dbname=coordinator;host=/tmp/N0ThIghu3o/tmp/mysql.sock','root',...) failed:
Unknown MySQL server host '/tmp/N0ThIghu3o/tmp/mysql.sock' (0) at /home/MYAPP/local/lib/perl5/Mojo/mysql.pm line 90.

(different run, different temp socket file)

It looks like the socket format is to escape the / in the path, but I can't see any code dealing with that (to set the DBD mysql_socket option).

This looks like a bug, but there's a test for it:

is $mysql->dsn, 'dbi:mysql:dbname=test4;host=/tmp/mysql.sock', 'right data source';

From my understanding, this should be "mysql_socket" and not "host"...?

https://metacpan.org/pod/DBD::mysql#mysql_socket

@jplindstrom: Can you help me out testing if it will work with the change I suggested?

TL;DR: mysql_socket does work, but Mojo::URL parsing is broken with an empty password in the connect string.

Here's some code to test that it works to connect with a socket using Test::mysqld

use Mojo::Base -strict;
use Test::More;
use Mojo::mysql;

use Carp;
use Test::mysqld;
use URI::Encode;

my $mysqld = Test::mysqld->new(
    my_cnf => { "skip-networking" => "" } # no TCP socket
) or confess($Test::mysqld::errstr);

my $database_name = "tm_db";
my $dsn = $mysqld->dsn( dbname => $database_name );

# e.g. DBI:mysql:dbname=tm_db;mysql_socket=/tmp/TvvrQclsm1/tmp/mysql.sock;user=root
$dsn =~ /user=(\w+)\b/
    or confess("Could not find a username in ($dsn)");
my $username = $1;
$dsn =~ /mysql_socket=(.+?)(;|$)/
    or confess("Could not find a mysql_socket in ($dsn)");
my $mysql_socket = $1;
my $encoded_mysql_socket = URI::Encode->new({
    encode_reserved => 1,
})->encode($mysql_socket);

my $password = "";



note "socket($mysql_socket) ($encoded_mysql_socket), username($username), password($password)";

my $mysql;
my $options;
my $mojo_connect_string = "mysql://$username:$password\@$encoded_mysql_socket/$database_name?PrintError=1&RaiseError=0";
note "connect string($mojo_connect_string)";

# Connection string with unix domain socket and options
$mysql = Mojo::mysql->new($mojo_connect_string);
is $mysql->dsn,      "dbi:mysql:dbname=$database_name;mysql_socket=$mysql_socket", 'right data source';
is $mysql->username, $username,                                          'right username';
is $mysql->password, $password,                                          'right password';
$options = {mysql_enable_utf8 => 1, AutoCommit => 1, AutoInactiveDestroy => 1, PrintError => 1, RaiseError => 0};
is_deeply $mysql->options, $options, 'right options';

# Blows up, because of the empty username
$mysql->db->query(
    "create table names (id integer auto_increment primary key, name text)"
);

done_testing();

Now, this doesn't work, because with Test::mysqld you get back user "root" and password "". And if you plug the empty password into Mojo::URL it doesn't parse out the username correctly (so that needs fixing too).

But this now fails for the good reason that the username is wrong, so it did in fact connect to the running server correctly:

DBI connect('dbname=tm_db;mysql_socket=/tmp/X3pFbA772G/tmp/mysql.sock','',...) failed: Access denied for user ''@'localhost' to database 'tm_db' at /home/coordinator/srv/mojo-mysql/lib/Mojo/mysql.pm line 98.

So mysql_socket does work and does the right thing.

I tested this by locally changing Mojo::mysql->from_string like this (may not be the best way to do it, I don't know):

  if (my $host = $url->host) {
      if ($host =~ m|/|) {
          $dsn .= ";mysql_socket=$host";
      }
      else {
          $dsn .= ";host=$host"
      }
  }

@jhthorsen Was this what you had in mind?

I think master has a fix for sockets now. Can you try it out?

cpanm https://github.com/jhthorsen/mojo-mysql/archive/master.tar.gz

I ran the test code above with the 1.07 version. The socket syntax works!