Linux/Mysql

I have created a linux apache module for SQLite, which works as per example. When I change the database to Mysql, I get the error:

Syntax error on line 1 of /etc/apache2/mods-enabled/xdata.load: API module structure 'xdata_module' in file /home/maarten/PAServer/scratch-dir/maartenhennekam-Ubuntu/mod_xdata/libmod_xdata.so is garbled - expected signature 41503234 but saw 00000000 - perhaps this is not an Apache module DSO, or was compiled for a different Apache version?

The only difference is the database driver from Firedac sqlite to Firedac MySql.
Mysql is working fine on the server. Compilation is also normal.
Part of the source:

initialization
  FireDacMySqlConnection := TFireDacMySqlConnection.Create(nil);
  Server := TWebBrokerServer.Create;
  TDatabaseManager.Update(TFireDacMySqlConnection.CreateConnection);
  Server.Dispatcher.AddModule(TXDataServerModule.Create(
     'http://udelphi/helpdesk/db', TFireDacMySqlConnection.CreateConnection
  ));

  Server.Dispatcher.AddModule(TAnonymousServerModule.Create(
    procedure(const C:THTTPServerContext)
    begin
       C.Response.StatusCode := 200;
       C.Response.ContentType := 'text/plain';
       C.Response.Close(Tencoding.UTF8.GetBytes('This is a Data server! Do not try to connect directly!'))
    end
  ));
Finalization
  Server.Free;
  FireDacMySqlConnection.Free;
end.

Although the strange error, I think this is a "normal" error from the code. Either the MySQL connection is not being established, or the code is not correct. 

Do you mind posting the full code?
You can also try to run the same code (at least the initialization code) in a regular Linux console application so you can see better what's going on and also have the opportunity to debug it.

I will try the linux app way. Here is the code. 


library mod_xdata;

uses
  {$IFDEF MSWINDOWS}
  Winapi.ActiveX,
  {$ENDIF }
  Web.WebBroker,
  Web.ApacheApp,
  Web.HTTPD24Impl,
  WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule},
  ConnectionModule in 'ConnectionModule.pas' {FireDacMySqlConnection: TDataModule};

{$R .res}

// httpd.conf entries:
//
(
 LoadModule xdata_module modules/mod_xdata.dll

 <Location /xyz>
    SetHandler mod_xdata-handler
 </Location>
*)
//
// These entries assume that the output directory for this project is the apache/modules directory.
//
// httpd.conf entries should be different if the project is changed in these ways:
//   1. The TApacheModuleData variable name is changed.
//   2. The project is renamed.
//   3. The output directory is not the apache/modules directory.
//   4. The dynamic library extension depends on a platform. Use .dll on Windows and .so on Linux.
//

// Declare exported variable so that Apache can access this module.
var
  GModuleData: TApacheModuleData;
exports
  GModuleData name 'xdata_module';

begin
{$IFDEF MSWINDOWS}
  CoInitFlags := COINIT_MULTITHREADED;
{$ENDIF}
  Web.ApacheApp.InitApplication(@GModuleData);
  Application.Initialize;
  Application.WebModuleClass := WebModuleClass;
  Application.CreateForm(TFireDacMySqlConnection, FireDacMySqlConnection);
  Application.Run;
end.


unit WebModuleUnit1;

interface

uses
  System.SysUtils, System.Classes, Web.HTTPApp,ConnectionModule;

type
  TWebModule1 = class(TWebModule)
    procedure WebModule1DefaultHandlerAction(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  WebModuleClass: TComponentClass = TWebModule1;

implementation

uses
  Sparkle.WebBroker.Server,
  Sparkle.WebBroker.Adapter,
  Sparkle.HTTPServer.Module, Sparkle.HTTPServer.Context, XData.server.module,
  Aurelius.Engine.DatabaseManager;

{%CLASSGROUP 'System.Classes.TPersistent'}

{$R *.dfm}

var
  Server: TWebBrokerServer;

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
  Adapter: IWebBrokerAdapter;
begin
  Adapter := TWebBrokerAdapter.Create(Request, Response);
  Server.DispatchRequest(Adapter);
end;



initialization
  FireDacMySqlConnection := TFireDacMySqlConnection.Create(nil);
  Server := TWebBrokerServer.Create;
  TDatabaseManager.Update(TFireDacMySqlConnection.CreateConnection);
  Server.Dispatcher.AddModule(TXDataServerModule.Create(
     'http://udelphi/helpdesk/db', TFireDacMySqlConnection.CreateConnection
  ));

  Server.Dispatcher.AddModule(TAnonymousServerModule.Create(
    procedure(const C:THTTPServerContext)
    begin
       C.Response.StatusCode := 200;
       C.Response.ContentType := 'text/plain';
       C.Response.Close(Tencoding.UTF8.GetBytes('This is a Data server! Do not try to connect directly!'))
    end
  ));
Finalization
  Server.Free;
  FireDacMySqlConnection.Free;
end.

unit ConnectionModule;

interface

uses
  Aurelius.Drivers.Interfaces,
  Aurelius.Drivers.FireDac,  
  FireDAC.Dapt,
  System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async,
  FireDAC.Phys, FireDAC.Phys.MySQL, FireDAC.Phys.MySQLDef, FireDAC.ConsoleUI.Wait, Aurelius.Sql.MySQL, Aurelius.Schema.MySQL, Aurelius.Comp.Connection, Data.DB, FireDAC.Comp.Client;

type
  TFireDacMySqlConnection = class(TDataModule)
    Connection: TFDConnection;
    AureliusConnection1: TAureliusConnection;
  private
  public
    class function CreateConnection: IDBConnection;
    class function CreateFactory: IDBConnectionFactory;
    
  end;

var
  FireDacMySqlConnection: TFireDacMySqlConnection;

implementation

{%CLASSGROUP 'System.Classes.TPersistent'}

uses 
  Aurelius.Drivers.Base;

{$R *.dfm}

{ TMyConnectionModule }

class function TFireDacMySqlConnection.CreateConnection: IDBConnection;
begin 
  Result := FireDacMySqlConnection.AureliusConnection1.CreateConnection; 
end;

class function TFireDacMySqlConnection.CreateFactory: IDBConnectionFactory;
begin
  Result := TDBConnectionFactory.Create(
    function: IDBConnection
    begin
      Result := CreateConnection;
    end
  );
end;



end.

Ok, two suggestions. First create the XDataModule using the factory.




  Server.Dispatcher.AddModule(TXDataServerModule.Create(
     'http://udelphi/helpdesk/db', TFireDacMySqlConnection.CreateFactory
  ));


Second, you are creating FireDacMySqlConnection twice. It's better to remove this line from dpr:


  Application.CreateForm(TFireDacMySqlConnection, FireDacMySqlConnection);

Thanks,

Will test and revert.

I removed the line from the dpi.

The lines:
  Server.Dispatcher.AddModule(TXDataServerModule.Create(
     'http://udelphi/helpdesk/db', TFireDacMySqlConnection.CreateFactory
  ));

give the following error:
[DCC Error] WebModuleUnit1.pas(50): E2250 There is no overloaded version of 'Create' that can be called with these arguments

Sorry, this is the correct code:




  Module := TXDataServerModule.Create(
     'http://udelphi/helpdesk/db',
     TDBConnectionPool.Create(20, TFireDacMySqlConnection.CreateFactory)
  );


TDBConnectionPool is declared in unit XData.Aurelius.ConnectionPool.

I still get the same error. The source is now:

unit WebModuleUnit1;

interface

uses
    System.SysUtils, System.Classes, Web.HTTPApp, ConnectionModule, XData.Aurelius.ConnectionPool;

type
    TWebModule1 = class(TWebModule)
        procedure WebModule1DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
    private
        { Private declarations }
    public
        { Public declarations }
    end;

var
    WebModuleClass: TComponentClass = TWebModule1;

implementation

uses
    Sparkle.WebBroker.Server,
    Sparkle.WebBroker.Adapter,
    Sparkle.HTTPServer.Module, Sparkle.HTTPServer.Context, XData.Server.Module,
    Aurelius.Engine.DatabaseManager;

{%CLASSGROUP 'System.Classes.TPersistent'}
{$R *.dfm}

var
    Server: TWebBrokerServer;
    Module: TXDataServerModule;

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
    Adapter: IWebBrokerAdapter;
begin
    Adapter := TWebBrokerAdapter.Create(Request, Response);
    Server.DispatchRequest(Adapter);
end;

initialization

FireDacMySqlConnection := TFireDacMySqlConnection.Create(nil);
Server                 := TWebBrokerServer.Create;
TDatabaseManager.Update(TFireDacMySqlConnection.CreateConnection);

Module := TXDataServerModule.Create('http://udelphi/helpdesk/db', TDBConnectionPool.Create(20, TFireDacMySqlConnection.CreateFactory));
Server.Dispatcher.AddModule(Module);

Server.Dispatcher.AddModule(TAnonymousServerModule.Create('http://udelphi/helpdesk',
    procedure(const C: THTTPServerContext)
    begin
        C.Response.StatusCode := 200;
        C.Response.ContentType := 'text/plain';
        C.Response.Close(Tencoding.UTF8.GetBytes('This is a Data server! Do not try to connect directly!'))
    end));

Finalization

Server.Free;
FireDacMySqlConnection.Free;

end.

unit ConnectionModule;

interface

uses
  Aurelius.Drivers.Interfaces,
  Aurelius.Drivers.FireDac,  
  FireDAC.Dapt,
  System.SysUtils, System.Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async,
  FireDAC.Phys, FireDAC.Phys.MySQL, FireDAC.Phys.MySQLDef, FireDAC.ConsoleUI.Wait, Aurelius.Sql.MySQL, Aurelius.Schema.MySQL, Aurelius.Comp.Connection, Data.DB, FireDAC.Comp.Client;

type
  TFireDacMySqlConnection = class(TDataModule)
    Connection: TFDConnection;
    AureliusConnection1: TAureliusConnection;
  private
  public
    class function CreateConnection: IDBConnection;
    class function CreateFactory: IDBConnectionFactory;
    
  end;

var
  FireDacMySqlConnection: TFireDacMySqlConnection;

implementation

{%CLASSGROUP 'System.Classes.TPersistent'}

uses 
  Aurelius.Drivers.Base;

{$R .dfm}

{ TMyConnectionModule }

class function TFireDacMySqlConnection.CreateConnection: IDBConnection;
begin 
  Result := FireDacMySqlConnection.AureliusConnection1.CreateConnection; 
end;

class function TFireDacMySqlConnection.CreateFactory: IDBConnectionFactory;
begin
  Result := TDBConnectionFactory.Create(
    function: IDBConnection
    begin
      Result := CreateConnection;
    end
  );
end;



end.

library mod_xdata;

uses
  {$IFDEF MSWINDOWS}
  Winapi.ActiveX,
  {$ENDIF }
  Web.WebBroker,
  Web.ApacheApp,
  Web.HTTPD24Impl,
  WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule},
  ConnectionModule in 'ConnectionModule.pas' {FireDacMySqlConnection: TDataModule};

{$R .res}

// httpd.conf entries:
//
(
 LoadModule xdata_module modules/mod_xdata.dll

 <Location /xyz>
    SetHandler mod_xdata-handler
 </Location>
)
//
// These entries assume that the output directory for this project is the apache/modules directory.
//
// httpd.conf entries should be different if the project is changed in these ways:
//   1. The TApacheModuleData variable name is changed.
//   2. The project is renamed.
//   3. The output directory is not the apache/modules directory.
//   4. The dynamic library extension depends on a platform. Use .dll on Windows and .so on Linux.
//

// Declare exported variable so that Apache can access this module.
var
  GModuleData: TApacheModuleData;
exports
  GModuleData name 'xdata_module';

begin
{$IFDEF MSWINDOWS}
  CoInitFlags := COINIT_MULTITHREADED;
{$ENDIF}
  Web.ApacheApp.InitApplication(@GModuleData);
  Application.Initialize;
  Application.WebModuleClass := WebModuleClass;
  //Application.CreateForm(TFireDacMySqlConnection, FireDacMySqlConnection);
  Application.Run;
end.

The code looks ok. Could you please send the whole project to us so that we can compile and fix it here?

will do.

Hi Maarten,

Thank you for sending the source code via e-mail. Note that this suggestion was useful for you:


Apache modules are hard to debug and sometimes hard to indicate the correct error message. Testing the initialization code in a Linux console will give you the error.
The problem was with Firedac, it was requiring that you drop the component TFDGUIxWaitCursor component so it could proper do some internal initialization. Once this was done, everything worked fine here.

Here is the reference:


http://docwiki.embarcadero.com/RADStudio/Rio/en/General_(FireDAC)

Thans for this! Will try this out. I have a fmx version running but I prefer the apache module.

I still get the same error.... This is very unstable...

What I don't get is that sqlite works without any issues.  I have include libmysqlclient.so in the deployment, but no luck

Which mysql version are you using?

For this test I used MySQL 5.5.

Again, have you tried to run a console app connecting to MySQL Server using FireDAC?
That's the very first step you should do.

I can run a FMX app without any problems. Data is working fine with this.

Are you using FMXLinux? Because there is no builtin support for FMX for Linux in Delphi.

Try to move all the code from initialization section to the WebModule1DefaultHandlerAction, at least you should have your Apache module running and you will get the error when you try to request data from it - probably the error will be more detailed.

I found the cause of the problem:

The line: TDatabaseManager.Update(TFireDacMySqlConnection.CreateConnection) is causing the problem. When I remove this line, it works.
I will try to move the code and see if this also works.

I moved the line TDatabaseManager.Update(TFireDacMySqlConnection.CreateConnection)  to the defaulthanfler action and it works.