Search code examples
mysqlerlangmariadberlang-shell

Erlang failing to connect to mysql/mariadb


I cannot connect to mysql/mariadb with erlang.

The requirements according to this github-page: https://github.com/mysql-otp/mysql-otp

Requirements:

Erlang/OTP version R16B or later
MySQL database version 4.1 or later or MariaDB
GNU Make or Rebar or any other tool for building Erlang/OTP applications

Version:

14> erlang:system_info(otp_release).
"22"

I'm not sure if this requirement is needed anymore but I added this:

[mysqld] default_authentication_plugin=mysql_native_password

to my /etc/my.cnf. But this is probably irrelevant since the error is an undefined function. I can compile the code but I cannot run it. Any help to get this working is much appreciated.

The code:

-module(mydatabase).
-compile(export_all).

connect_to_database() -> 
Conn = mysql:start_link([{host, "localhost"}, {user, "user"},
                       {password, "password"}, {database, "MyDatabase"}]) ,
           
  case Conn of
      {ok, Pid} -> io:fwrite("~w~w~n", [ok,Pid]);
      {error, ConnErr}  -> io:fwrite("error : ~p ~n", [ConnErr])
    end.
              
 start() -> connect_to_database().

mariadb is running:

sudo systemctl status mariadb
[sudo] password for user: 
● mariadb.service - MariaDB 10.4.13 database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor >
   Active: active (running) since Sun 2020-06-28 15:33:50 CEST; 1h 4min ago

The error message:

12> c(mydatabase).     
mydatabase.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,mydatabase}
13> mydatabase:start().
** exception error: undefined function mysql:start_link/1
 in function  mydatabase:connect_to_database/0 (mydatabase.erl, line 1

Solution

  • You forgot about this requirement:

    GNU Make or Rebar or any other tool for building Erlang/OTP applications

    According to the mysql-otp docs:

    MySQL/OTP is a driver for connecting Erlang/OTP applications to MySQL and MariaDB databases.

    An OTP application requires a certain architecture, and the mysql driver needs to be listed as a dependency in the application. Your error is due to the fact that there is no function named mysql:start_link/1 in Erlang. Rather, that's a third party function that your code has to somehow access, hence the Usage as a Dependency section in the docs.

    The following steps can be used to create an OTP application which employs mysql/mariaDB as a dependency:

    1. Install rebar3.

    2. Create a rebar3 app:

      ~/erlang_programs/mysql1$ rebar3 new app myapp
      ===> Writing myapp/src/myapp_app.erl
      ===> Writing myapp/src/myapp_sup.erl
      ===> Writing myapp/src/myapp.app.src
      ===> Writing myapp/rebar.config
      ===> Writing myapp/.gitignore
      ===> Writing myapp/LICENSE
      ===> Writing myapp/README.md
      
    3. Add mysql-otp as a dependency in the rebar.config file:

        ~/erlang_programs/mysql1$ cd myapp
        ~/erlang_programs/mysql1/myapp$ ls
        LICENSE       rebar.config
        README.md src
      

    like this:

        {erl_opts, [debug_info]}.
        {deps, [
    
          {mysql, ".*", {
                          git, "https://github.com/mysql-otp/mysql-otp",
                          {tag, "1.6.0"}
                        }
          }
    
        ]}.
    
        {shell, [
          % {config, "config/sys.config"},
            {apps, [myapp]}
        ]}.
    
    1. Put your source code in the src directory:

       ~/erlang_programs/mysql1/myapp$ cd src
       ~/erlang_programs/mysql1/myapp/src$ ls
       my_mysql.erl    myapp_app.erl
       myapp.app.src   myapp_sup.erl
      

    my_mysql.erl:

    -module(my_mysql).
    -compile(export_all).
    
    do_mysql(Name, Info) ->
        {ok, MysqlPid} = mysql:start_link(
                      [{host, "localhost"}, 
                       {user, "root"},
                       {password, ""}, 
                       {database, "mydb"}
                      ]
                    ),
    
         ok = mysql:query(
               MysqlPid, 
               "INSERT INTO people (name, info) VALUES (?, ?)", [Name, Info]
            ),
    
         {ok, ColumnNames, Rows} = mysql:query(
                    MysqlPid, 
                    <<"SELECT * FROM people">>),
    
         io:format("ColumnNames: ~p~nRows: ~p~n", [ColumnNames, Rows]).
    
    1. Fetch the dependencies and compile all the source code:

       ~/erlang_programs/mysql1/myapp$ rebar3 compile
       ===> Verifying dependencies...
       ===> Fetching mysql ({git,"https://github.com/mysql-otp/mysql-otp",
                                        {tag,"1.6.0"}})
       ===> Compiling mysql
       ===> Compiling myapp
       src/my_mysql.erl:2: Warning: export_all flag enabled - all functions will be exported
      
    2. Launch the shell and automatically construct paths to all your .beam files (in the deeply nested directories that rebar3 puts them):

       ~/erlang_programs/mysql1/myapp$ rebar3 shell
       ===> Verifying dependencies...
       ===> Compiling myapp
       Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [kernel-poll:false]
      
       ===> The rebar3 shell is a development tool; to deploy applications in production, consider using releases (http://www.rebar3.org/docs/releases)
       ===> Booted myapp
       Eshell V9.3  (abort with ^G)
      
    3. Execute your function:

       1> my_mysql:do_mysql("Jeffsy", "2.0").
       ColumnNames: [<<"id">>,<<"name">>,<<"info">>]
       Rows: [[1,<<"7stud">>,<<"abc">>],
              [2,<<"Beth">>,<<"xxx">>],
              [3,<<"Diane">>,<<"xyz">>],
              [4,<<"Kathy">>,<<"xyz">>],
              [5,<<"Kathy">>,<<"xyz">>],
              [6,<<"Dave">>,<<"efg">>],
              [7,<<"Tom">>,<<"zzz">>],
              [8,<<"David">>,<<"abc">>],
              [9,<<"Eloise">>,<<"abc">>],
              [10,<<"Jess">>,<<"xyz">>],
              [11,<<"Jeffsy">>,<<"2.0">>]]
       ok