4

All work fine if I use custom main ( void main() instead of shared static this() ).

With default main I am getting "Access Violation" error. It's look like MySQL not allow connecting to it from localhost, but in my.ini I added string:

bind-address = 127.0.0.1

code, if it's help:

import std.stdio;
import std.path;
import std.file;
import std.string;

import dini;
import vibe.d;
import colorize;
import ddbc.all;

shared static this()
{
    auto settings = new HTTPServerSettings;
    settings.port = 8080;
    settings.bindAddresses = ["::1", "127.0.0.1"];
    listenHTTP(settings, &hello);

    auto parseconfig = new ParseConfig();
    auto db = new DBConnect(parseconfig);
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
    res.writeBody("Hello, World!");
}


class ParseConfig
{
    string dbname;
    string dbuser;
    string dbpass;
    string dbhost;
    string dbport;

this()
    {
        try
        {
            //getcwd do not return correct path if run from task shoulder
            string confpath = buildPath((thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]), "config.ini");
            //writefln(thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]); // get path without extention +1 is for getting last slash

            //string confpath = buildPath(thisExePath, "config.ini");
            if (!exists(confpath)) 
                {
                    writeln("ERROR: config.ini do not exists");
                }
            auto config = Ini.Parse(confpath);
            try
            {
                this.dbname = config.getKey("dbname");
                this.dbuser = config.getKey("dbuser");
                this.dbpass = config.getKey("dbpass");
                this.dbhost = config.getKey("dbhost");
                this.dbport = config.getKey("dbport");

            }
            catch (Exception msg)
            {
                cwritefln("ERROR: Can't parse config: %s".color(fg.red), msg.msg);
            }       
        }
        catch(Exception msg)
        {
            cwriteln(msg.msg.color(fg.red));
            core.thread.Thread.sleep( dur!("msecs")(1000));
        }   
    }


}


class DBConnect
{
    Statement stmt;
    ParseConfig parseconfig;

    this(ParseConfig parseconfig)
    {
        try
            {
                this.parseconfig = parseconfig;
                MySQLDriver driver = new MySQLDriver();
                string url = MySQLDriver.generateUrl(parseconfig.dbhost, to!short(parseconfig.dbport), parseconfig.dbname);
                string[string] params = MySQLDriver.setUserAndPassword(parseconfig.dbuser, parseconfig.dbpass);

                DataSource ds = new ConnectionPoolDataSourceImpl(driver, url, params);

                auto conn = ds.getConnection();
                scope(exit) conn.close();

                stmt = conn.createStatement();
                writefln("\n[Database connection OK]");
            }
        catch (Exception ex)
        {
            writefln(ex.msg);
            writeln("Could not connect to DB. Please check settings");
        }

    }   
}

Also I run next command:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; FLUSH PRIVILEGES;

also I tried different bind-address like: 0.0.0.0 and localhost but without result. After every new binding I did restart of MySQL service.

I am using this driver http://code.dlang.org/packages/ddbc

What's wrong?

Suliman
  • 1,469
  • 3
  • 13
  • 19
Dmitry Bubnenkov
  • 9,415
  • 19
  • 85
  • 145
  • After the grant, have you `flush privileges;`? – Mad Dog Tannen May 18 '15 at 11:52
  • yes I did `flush privileges;` – Dmitry Bubnenkov May 18 '15 at 13:11
  • `GRANT ... @'127.0.0.1'...` – Rick James May 18 '15 at 18:56
  • 2
    Could you run that into a 'runTask' ? (http://vibed.org/api/vibe.core.core/runTask) Currently you are trying to connect to the DB **before** the event loop starts, which happens once all module constructors returns. Things like listenHTTP (which seems blocking at first sight) does nothing more than register a server context on a global list (https://github.com/rejectedsoftware/vibe.d/blob/a731634db880f7efb4482f094e92b403da6c38d4/source/vibe/http/server.d#L92). – Geod24 May 18 '15 at 19:59
  • Ok, I will try it's now. But why you say that I connecting **before** I thought even loop start with `static this()`. Because if even loop can start only after all function constructors return it's hard to understand how it can do other tasks. Or I do not understand something? – Dmitry Bubnenkov May 19 '15 at 11:10
  • And could you show code example? – Dmitry Bubnenkov May 19 '15 at 11:18

2 Answers2

3

To continue on my comment ( Can't connect to MySQL/MariaDB database from vibed app ).

I just tested, and it's definitely the event loop ;)

Instead of:

auto parseconfig = new ParseConfig();
auto db = new DBConnect(parseconfig);

Just do:

runTask({
    auto parseconfig = new ParseConfig();
    auto db = new DBConnect(parseconfig);
});

Worked for me (DMD 2.067.0 / Vibe 0.7.23 / ddbc 0.2.24 / colorize & dini master).

To answer your comment ( Can't connect to MySQL/MariaDB database from vibed app) : the event loop starts inside the main function. What happens when you launch a D application ? The entry point is a C main inside the runtime, which initialize it (the runtime), including module constructor, run the unittest (if you've compiled with -unittest), then call your main (which name is "_Dmain" - useful to know if you want to set a breakpoint with GDB). When Vibe.d's main is called, it parses command line argument, an optional config file, and finally, starts the event loop. Any code that wish to run once the event loop has started should use runTask and similar, or createTimer. They should not call the code directly from the static constructor (it's actually one of the most common mistake when starting with Vibe.d).

Community
  • 1
  • 1
Geod24
  • 883
  • 6
  • 14
  • What is "C main inside the runtime"? I thought main is just startup address. "then call your main (which name is "_Dmain" ". Again I thought that there is only one main and it's address "They should not call the code directly from the static constructor " what would be if they will call from constructor? Why it is error? – Dmitry Bubnenkov May 21 '15 at 14:05
  • Or you mean that this is run before main and it is entry point and after run and complete all code inside it (including all other function) start main()? – Dmitry Bubnenkov May 21 '15 at 14:23
  • The entry point of a D program is `_d_run_main` at the moment. This function is located inside the runtime : https://github.com/D-Programming-Language/druntime/blob/6e55b7aaff7566d374c2f253f831d3489e7fd1a5/src/rt/dmain2.d#L290 The runtime is initialized inside of this function, [here](https://github.com/D-Programming-Language/druntime/blob/6e55b7aaff7566d374c2f253f831d3489e7fd1a5/src/rt/dmain2.d#L470). If you look at `rt_init()`, you can see various thing being initialized, the last 2 items being `rt_moduleCtor` and `rt_moduleTlsCtor`. – Geod24 May 22 '15 at 14:57
  • [Continuing...] Relevant link: https://github.com/D-Programming-Language/druntime/blob/6e55b7aaff7566d374c2f253f831d3489e7fd1a5/src/rt/dmain2.d#L175 `rt_moduleCtor` initialize `shared static this`, and `rt_moduleTlsCtor` initialize `static this`. So if you have a blocking code inside one of your constructor, your main is never called. That's why you should use `runTask` in Vibe.d: It just stores the delegate to be performed in the event loop. – Geod24 May 22 '15 at 15:00
  • Sorry for big delay, but I just back to home. I tried your solution, but I getting error `Task terminated with unhandled exception: Access Violation object.Error@(0): Access Violation` after SELECT from DB. – Suliman Jun 05 '15 at 19:14
0

I ran into an issue that could be related while developing mysql-lited, an alternative MySQL/MariaDB driver.

The issue I think is related to a module initialization order bug in phobos/SHA1, which I believe is still open in 2.067.1. The suggested work-around is to use VibeCustomMain instead, and define your own main(). You can just copy the defaul main() from appmain.d and use that.

Alternatively you could try mysql-lited and see if that works better for you.