Page 1 of 1

Get standard Library name

Posted: 29.12.2022, 12:56
by CharlyTango
Hi,

in the example project ZControlsExample there is a possibility to fill a combobox with all supported protocols.

Code: Select all

procedure TMainForm.FormShow(Sender: TObject);
var
  I, J: Integer;
  Drivers: IZCollection;
  Protocols: TStringDynArray;
begin
  ZProtocol.Clear;
  Drivers := DriverManager.GetDrivers;

  for I := 0 to Drivers.Count - 1 do
  begin
    Protocols := (Drivers.Items[I] as IZDriver).GetSupportedProtocols;
    for J := 0 to High(Protocols) do begin
      ZProtocol.Items.Add(Protocols[J]);
     end;
  end;
  ZProtocol.Sorted := True;
end; 
And selecting the desired protocol was the only thing which was needed to connect to the database.
ZEOS obviously selected the right library name and also the correct bitness (32/64bit).

Could someone give me a hint how (and where in ZEOS) that is done or at least tell me how to get the standard name of a library determined by the selected protocol (under different operating systems).
ZEOS should at least tell me the library names by protocol.

Please put me on track ;-)

Re: Get standard Library name

Posted: 30.12.2022, 12:38
by marsupilami
Hello CharlyTango,

each driver has a list of library names which Zeos tries to load on request. These libraries are listed in the plain driver part of the driver. Taking MySQL as an example:
In ZPlainMySqlDriver.pas there is the following part:

Code: Select all

{$IFDEF MSWINDOWS}
  WINDOWS_DLL_LOCATION = 'libmysql.dll';
  WINDOWS_DLL41_LOCATION = 'libmysql41.dll';
  WINDOWS_DLL41_LOCATION_EMBEDDED = 'libmysqld41.dll';
  WINDOWS_DLL50_LOCATION = 'libmysql50.dll';
  WINDOWS_DLL50_LOCATION_EMBEDDED = 'libmysqld50.dll';
  WINDOWS_DLL51_LOCATION = 'libmysql51.dll';
  WINDOWS_DLL51_LOCATION_EMBEDDED = 'libmysqld51.dll';
  WINDOWS_DLL55_LOCATION = 'libmysql55.dll';
  WINDOWS_DLL55_LOCATION_EMBEDDED = 'libmysqld55.dll';
  WINDOWS_DLL56_LOCATION = 'libmysql56.dll';
  WINDOWS_DLL56_LOCATION_EMBEDDED = 'libmysqld56.dll';
  WINDOWS_DLL57_LOCATION = 'libmysql57.dll';
  WINDOWS_DLL57_LOCATION_EMBEDDED = 'libmysqld57.dll';
{$ELSE}
  LINUX_DLL_LOCATION = 'libmysqlclient'+SharedSuffix;
  LINUX_DLL41_LOCATION = 'libmysqlclient'+SharedSuffix+'.14';
  LINUX_DLL41_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.14';
  LINUX_DLL50_LOCATION = 'libmysqlclient'+SharedSuffix+'.15';
  LINUX_DLL50_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.15';
  LINUX_DLL51_LOCATION = 'libmysqlclient'+SharedSuffix+'.16';
  LINUX_DLL51_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.16';
  LINUX_DLL55_LOCATION = 'libmysqlclient'+SharedSuffix+'.18';
  LINUX_DLL55_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.18';
  LINUX_DLL56_LOCATION = 'libmysqlclient'+SharedSuffix+'.19';
  LINUX_DLL56_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.19';
  LINUX_DLL57_LOCATION = 'libmysqlclient'+SharedSuffix+'.20';
  LINUX_DLL57_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.20';
  LINUX_DLL58_LOCATION = 'libmysqlclient'+SharedSuffix+'.21';
  LINUX_DLL58_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.21';
{$ENDIF}
This part defines the library names to try when connecting to MySQL database. These constants get used upon construction of the relevant plain driver:

Code: Select all

constructor TZMySQLPlainDriver.Create;
begin
  inherited create;
  FLoader := TZNativeLibraryLoader.Create([]);
  FLoader.AddLocation(MARIADB_LOCATION);
  FLoader.AddLocation(DLL_LOCATION_EMBEDDED);
{$IFDEF MSWINDOWS}
  FLoader.AddLocation(WINDOWS_DLL_LOCATION);
  FLoader.AddLocation(WINDOWS_DLL41_LOCATION);
  FLoader.AddLocation(WINDOWS_DLL41_LOCATION_EMBEDDED);
  FLoader.AddLocation(WINDOWS_DLL50_LOCATION);
  FLoader.AddLocation(WINDOWS_DLL50_LOCATION_EMBEDDED);
  FLoader.AddLocation(WINDOWS_DLL51_LOCATION);
  FLoader.AddLocation(WINDOWS_DLL51_LOCATION_EMBEDDED);
  FLoader.AddLocation(WINDOWS_DLL55_LOCATION);
  FLoader.AddLocation(WINDOWS_DLL55_LOCATION_EMBEDDED);
  FLoader.AddLocation(WINDOWS_DLL56_LOCATION);
  FLoader.AddLocation(WINDOWS_DLL56_LOCATION_EMBEDDED);
  FLoader.AddLocation(WINDOWS_DLL57_LOCATION);
  FLoader.AddLocation(WINDOWS_DLL57_LOCATION_EMBEDDED);
{$ELSE}
  FLoader.AddLocation(LINUX_DLL_LOCATION);
  FLoader.AddLocation(LINUX_DLL41_LOCATION);
  FLoader.AddLocation(LINUX_DLL41_LOCATION_EMBEDDED);
  FLoader.AddLocation(LINUX_DLL50_LOCATION);
  FLoader.AddLocation(LINUX_DLL50_LOCATION_EMBEDDED);
  FLoader.AddLocation(LINUX_DLL51_LOCATION);
  FLoader.AddLocation(LINUX_DLL51_LOCATION_EMBEDDED);
  FLoader.AddLocation(LINUX_DLL55_LOCATION);
  FLoader.AddLocation(LINUX_DLL55_LOCATION_EMBEDDED);
  FLoader.AddLocation(LINUX_DLL56_LOCATION);
  FLoader.AddLocation(LINUX_DLL56_LOCATION_EMBEDDED);
  FLoader.AddLocation(LINUX_DLL57_LOCATION);
  FLoader.AddLocation(LINUX_DLL57_LOCATION_EMBEDDED);
  FLoader.AddLocation(LINUX_DLL58_LOCATION);
  FLoader.AddLocation(LINUX_DLL58_LOCATION_EMBEDDED);
{$ENDIF}
  LoadCodePages;
end;
So while Zeos cannot tell you which libraries it uses, you can take a look at the library names it will try to use.

Best regards,

Jan

Re: Get standard Library name

Posted: 02.01.2023, 10:43
by CharlyTango
Hi Jan,

thank you for your explanation.

I think it's great that ZEOS has such sophisticated functions to guess "missing" inputs.

However, I would like to know where and how to place the access libraries under Windows so that they are easily found by zeos.

It would also be nice to be able to determine which library is currently being used to see if the correct one is in use. Of course this would be more a function for an administrator or the programmer to see if everything is running correctly.

Regards,
Karl

Re: Get standard Library name

Posted: 02.01.2023, 12:19
by marsupilami
Hello Karl,
CharlyTango wrote: 02.01.2023, 10:43 However, I would like to know where and how to place the access libraries under Windows so that they are easily found by zeos.
There is no general rule for this. For most databases I suggest to place the libraries alongside the application and use the TZConnection property LibraryLocation. This will keep zeos from guessing and make it try one library only. Usually I distribute the client libraries along with my programs and have a subfolder for them. Something like:
MyProgram\
|-firebird-3.0\
| |-fbclient.dll
| |-...other files
|-MyProgram.exe
|-...other files
In the code of my program I usually do something like:

Code: Select all

procedure TMyDatamodule.OnCreate(Sender: TObject);
begin
  // some initialization code before these lines
  ZeosConnection.LibraryLocation := ExtractFilePath(ParamStr(0)) + 'firebird-3.0\fbclient.dll';
  // more code here
end;
Another idea is to load a library location from an ini file or from the registry.
CharlyTango wrote: 02.01.2023, 10:43 It would also be nice to be able to determine which library is currently being used to see if the correct one is in use.
If you go the above way, you know which library is in use because if you provide a library to use, Zeos will not try to load other libraries.

Best regards,

Jan

Re: Get standard Library name

Posted: 02.01.2023, 22:20
by aehimself
CharlyTango wrote: 02.01.2023, 10:43It would also be nice to be able to determine which library is currently being used to see if the correct one is in use.
It's actually possible, I even posted it on this forum a while ago. Can not find it atm, so here you go:

Code: Select all

If Assigned(ZConnection1.DbcConnection) And
    Assigned(ZConnection1.DbcConnection.GetIZPlainDriver) And
    Assigned(ZConnection1.DbcConnection.GetIZPlainDriver.GetInstance.Loader) Then
  WriteLn(GetModuleName(ZConnection1.DbcConnection.GetIZPlainDriver.GetInstance.Loader.Handle));
Edit:

This post.

Re: Get standard Library name

Posted: 04.01.2023, 09:12
by marsupilami
What do you think about adding that to the TZConnectionobject? Something like

Code: Select all

function TZAbstractConnection.GetLibraryInUse: String;
begin
  Result := '';
  if Active and 
    Assigned(DbcConnection) And
    Assigned(DbcConnection.GetIZPlainDriver) And
    Assigned(DbcConnection.GetIZPlainDriver.GetInstance.Loader) and
    (DbcConnection.GetIZPlainDriver.GetInstance.Loader.Handle <> 0)
  then
    Result := GetModuleName(ZConnection1.DbcConnection.GetIZPlainDriver.GetInstance.Loader.Handle);
end;

Re: Get standard Library name

Posted: 05.01.2023, 04:44
by MJFShark
I vote yes! I use a very similar version and it has always worked well. Mine also checks

Code: Select all

if Assigned(ZConn.DbcConnection.GetIZPlainDriver.GetInstance) then
But maybe that's not needed.

Re: Get standard Library name

Posted: 09.01.2023, 09:12
by Fr0sT
Maybe GetLoadedLibrary?

Re: Get standard Library name

Posted: 10.01.2023, 10:29
by aehimself
MJFShark wrote: 05.01.2023, 04:44But maybe that's not needed.
Afaik it's unnecessary, as GetInstance returns a new instance. As long as there's a plain driver, you'll always get an instance.
I did not check the code right now, though so I might be wrong.

If anyone is about to add this please make sure that it will continue to work if we finally get rid of Zeos's notorious driver library caching :)