Recent

Author Topic: [SOLVED] connect to a database using an IP address contained in an ini file  (Read 2043 times)

pjtuloup

  • New Member
  • *
  • Posts: 45
Hi all,

I have a small problem again... and need to call you...

I put in an ini file the IP address of the server to which my program must connect:

[Server]
IP=10.0.0.7

This address is read by  IpServer :=INI.ReadString(Section,'IP','');

Where Section is a constant declared Section = 'Server'; and IpServer is a declared string

All this works perfectly well; I know this because I display IpServer to check its value, and it displays 10.0.07.

But I try to assign IpServer to SQLConnection1.Hostname by  SQLConnection1.Hostname :=IpServer;

then the program stops with the error "Exception ESQLDatabaseError [...] Server Connect failed"

However, when I put SQLConnection1.Hostname :='10.0.0.7' it works perfectly!

What is the problem ? Thanks in advance !
« Last Edit: June 23, 2024, 09:17:47 pm by pjtuloup »

Handoko

  • Hero Member
  • *****
  • Posts: 5379
  • My goal: build my own game engine using Lazarus
Re: connect to a database using an IP address contained in an ini file
« Reply #1 on: June 21, 2024, 06:32:04 pm »
There can be many possibilities. Without inspect into your source code not much I can say. But I saw an inconsistency in your post:

All this works perfectly well; I know this because I display IpServer to check its value, and it displays 10.0.07.

However, when I put SQLConnection1.Hostname :='10.0.0.7' it works perfectly!

pjtuloup

  • New Member
  • *
  • Posts: 45
Re: connect to a database using an IP address contained in an ini file
« Reply #2 on: June 21, 2024, 07:24:43 pm »
There can be many possibilities. Without inspect into your source code not much I can say. But I saw an inconsistency in your post:

All this works perfectly well; I know this because I display IpServer to check its value, and it displays 10.0.07.

Yes it was a typo, I forgott one "."... Please read "All this works perfectly well; I know this because I display IpServer to check its value, and it displays 10.0.0.7"
[/quote]

Handoko

  • Hero Member
  • *****
  • Posts: 5379
  • My goal: build my own game engine using Lazarus
Re: connect to a database using an IP address contained in an ini file
« Reply #3 on: June 21, 2024, 08:01:19 pm »
You didn't get it. I'm sorry my previous post was too 'cryptic', it had a hidden message.

Here let me explain it. Humans are careless, so are programmers. In your previous post I saw you forgot a dot. And now you had an extra 't'.

Yes it was a typo, I forgott one "."...

Because you know how to do client/server SQL connection and using TInfiFile, sure you are not a newbie. The bug shouldn't be the logic of your code but mistake of your carelessness. It seems you're not able to find the culprit, that's why in my previous post I asked you to show us the code, so we can help to find the culprit.

pjtuloup

  • New Member
  • *
  • Posts: 45
Re: connect to a database using an IP address contained in an ini file
« Reply #4 on: June 21, 2024, 09:13:28 pm »
Sorry, I didn't understand, actually! I'm not an English speaker and my English is terrible...
I have good experience in C++ Builder but I abandoned it because the licenses are overpriced and I very recently turned to Lazarus although I know nothing about Pascal.
But I think I understand the problem: it's a variable scope problem.
It's going to take up a lot of space but here is my code (unfortunately with variable names in French)

Master unit:

Code: Pascal  [Select][+][-]
  1. unit Maitre;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ActnList, Menus, Unit1,UIdentification;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     MenuGen: TMainMenu;
  16.     MenuItem1: TMenuItem;
  17.     MenuItem10: TMenuItem;
  18.     MenuItem11: TMenuItem;
  19.     MenuItem12: TMenuItem;
  20.     MenuItem13: TMenuItem;
  21.     MenuItem14: TMenuItem;
  22.     MenuItem15: TMenuItem;
  23.     MenuItem16: TMenuItem;
  24.     MenuItem17: TMenuItem;
  25.     MenuItem18: TMenuItem;
  26.     MenuItem19: TMenuItem;
  27.     MenuItem2: TMenuItem;
  28.     MenuItem3: TMenuItem;
  29.     MenuItem4: TMenuItem;
  30.     MenuItem5: TMenuItem;
  31.     MenuItem6: TMenuItem;
  32.     MenuItem7: TMenuItem;
  33.     MenuItem8: TMenuItem;
  34.     MenuItem9: TMenuItem;
  35.     Retour: TMenuItem;
  36.     procedure FormActivate(Sender: TObject);
  37.     procedure FormCreate(Sender: TObject);
  38.     procedure MenuItem10Click(Sender: TObject);
  39.     procedure MenuItem9Click(Sender: TObject);
  40.   private
  41.  
  42.   public
  43.  
  44.   end;
  45.  
  46. var
  47.   Form1: TForm1;
  48.  
  49. implementation
  50.  
  51. {$R *.lfm}
  52.  
  53. { TForm1 }
  54.  
  55. procedure TForm1.FormCreate(Sender: TObject);
  56. begin
  57.  
  58. end;
  59.  
  60. procedure TForm1.FormActivate(Sender: TObject);
  61. begin
  62.   FormIdentif.Show;
  63. end;
  64.  
  65. procedure TForm1.MenuItem10Click(Sender: TObject);
  66. begin
  67. Application.MainForm.Close;
  68. end;
  69.  
  70. procedure TForm1.MenuItem9Click(Sender: TObject);
  71. begin
  72.   FormAPropos.Show;
  73. end;
  74.  
  75. end.


uoutils (uTools) where global variables are defined

Code: Pascal  [Select][+][-]
  1. unit uoutils;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils;
  9.  
  10. var
  11. IpServeur           :String;
  12. NomBase             :String;
  13. iniPath             :String;
  14.  
  15. implementation
  16.  
  17. end.  

Unit uidentification where variables are assigned from the contents of the ini file

Code: Pascal  [Select][+][-]
  1. unit uIdentification;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, IniFiles, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,uoutils;
  9.  
  10. type
  11.  
  12.   { TFormIdentif }
  13.  
  14.   TFormIdentif = class(TForm)
  15.     Button1: TButton;
  16.     Button2: TButton;
  17.     Button3: TButton;
  18.     SaisUser: TEdit;
  19.     SaisMdp: TEdit;
  20.     Edit3: TEdit;
  21.     Edit4: TEdit;
  22.     GroupBox1: TGroupBox;
  23.     GroupBox2: TGroupBox;
  24.     GroupBox3: TGroupBox;
  25.     GroupBox4: TGroupBox;
  26.     GroupBox5: TGroupBox;
  27.     Label1: TLabel;
  28.     Label2: TLabel;
  29.     Panel1: TPanel;
  30.     procedure Button1Click(Sender: TObject);
  31.     procedure Button2Click(Sender: TObject);
  32.     procedure FormCreate(Sender: TObject);
  33.     function iniRead(s : string) : string;
  34.   private
  35.  
  36.   public
  37.  
  38.   end;
  39.  
  40. const
  41.   Section =   'Serveur';
  42. var
  43.   FormIdentif: TFormIdentif;
  44.   INI                 :TINIFile;
  45.   Ok : Boolean = false;
  46.  
  47. implementation
  48.  
  49. {$R *.lfm}
  50.  
  51. { TFormIdentif }
  52.  
  53. procedure TFormIdentif.Button2Click(Sender: TObject);
  54. begin
  55.   Application.MainForm.Close;
  56. end;
  57.  
  58. procedure TFormIdentif.FormCreate(Sender: TObject);
  59.   var
  60.   callResult : String;
  61. begin
  62.    iniPath           := Application.Location;
  63.    callResult        := iniRead(iniPath);
  64. end;
  65.  
  66.  
  67. function TFormIdentif.iniRead(s : string) : string;
  68. var
  69.    str: string;
  70. begin
  71.    INI :=TINIFile.Create('Luges.ini');
  72.    try
  73.      IpServeur  :=INI.ReadString(Section,'IP','');
  74.      NomBase  :=INI.ReadString(Section,'Base','');
  75.    finally
  76.      INI.Free;
  77.      str := 'Process Worked';
  78.      Result := str;
  79.    end;
  80. end;
  81.  
  82. procedure TFormIdentif.Button1Click(Sender: TObject);
  83. begin
  84.   if (SaisUser.Text='') and (SaisMdp.Text='')  then
  85.      begin
  86.      Application.MessageBox('Veuillez saisir votre nom d utilisateur et votre mot de passe!', 'Alerte Utilisateur');
  87.      end
  88.   else
  89.      begin
  90.      if SaisUser.Text='' then
  91.         begin
  92.         Application.MessageBox('Veuillez saisir votre nom d utilisateur', 'Alerte Utilisateur');
  93.         end;
  94.      if SaisMdp.Text='' then
  95.         begin
  96.           Application.MessageBox('Veuillez saisir votre mot de passe!', 'Alerte Utilisateur');
  97.         end;
  98.      end
  99. end;
  100.  
  101. end.
  102.  

unit1 (unit About...) where certain variables (IpServeur) are displayed after assigning the contents of the ini file

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, uoutils;
  9.  
  10. type
  11.  
  12.   { TFormAPropos }
  13.  
  14.   TFormAPropos = class(TForm)
  15.     ShowPath: TEdit;
  16.     GroupBox5: TGroupBox;
  17.     ShowIpServ: TEdit;
  18.     ShowNomBase: TEdit;
  19.     GroupBox2: TGroupBox;
  20.     Base: TGroupBox;
  21.     Panel4: TPanel;
  22.     ShowDateCompil: TEdit;
  23.     GroupBox1: TGroupBox;
  24.     GroupBox3: TGroupBox;
  25.     GroupBox4: TGroupBox;
  26.     Label4: TLabel;
  27.     Label6: TLabel;
  28.     Label7: TLabel;
  29.     Label8: TLabel;
  30.     Label9: TLabel;
  31.     Panel1: TPanel;
  32.     Panel2: TPanel;
  33.     Panel3: TPanel;
  34.     procedure FormActivate(Sender: TObject);
  35.   private
  36.  
  37.   public
  38.  
  39.   end;
  40.  
  41. var
  42.   FormAPropos: TFormAPropos;
  43.  
  44.  
  45. implementation
  46.  
  47. {$R *.lfm}
  48.  
  49. { TFormAPropos }
  50.  
  51. procedure TFormAPropos.FormActivate(Sender: TObject);
  52. begin
  53.   ShowDateCompil.Text :=DateTimeToStr(FileDateToDateTime(FileAge('Luges4.exe')));
  54.   ShowIpServ.Text     :=IpServeur;
  55.   ShowNomBase.Text    :=NomBase;
  56.   ShowPath.Text       := iniPath;
  57. end;
  58.  
  59. end.
  60.  

Unit DataAccess where the connection to the database is made

 
Code: Pascal  [Select][+][-]
  1.  unit DataAccess;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, mysql80conn, SQLDB, Dialogs,db,uoutils;
  9.  
  10. type
  11.  
  12.   { TDataModule1 }
  13.  
  14.   TDataModule1 = class(TDataModule)
  15.     SQLConnection1: TMySQL80Connection;
  16.     SQLTransaction: TSQLTransaction;
  17.     procedure DataModuleCreate(Sender: TObject);
  18.   private
  19.  
  20.   public
  21. function Login: Boolean;
  22. procedure Logoff;
  23.   end;
  24.  
  25. var
  26.   DataModule1: TDataModule1;
  27.  
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. { TDataModule1 }
  34.  
  35. procedure TDataModule1.DataModuleCreate(Sender: TObject);
  36. begin
  37.   If not Login then
  38.       begin
  39.         Login;
  40.         end;
  41. end;
  42.  
  43. function TDataModule1.Login: Boolean;
  44.  
  45. begin
  46. Result := true;
  47. //IpServeur:='10.0.0.7';
  48. ShowMessage('IP: ' + IpServeur);
  49. SQLConnection1.Hostname := IpServeur;
  50. SQLConnection1.DatabaseName := '######';
  51. SQLConnection1.UserName := '######';
  52. SQLConnection1.Password := '######';
  53. try
  54.   SQLConnection1.Connected := true;
  55.   SQLTransaction.Active := true;
  56. except
  57.   on e : ESQLDatabaseError do
  58.   begin
  59.     MessageDlg('Erreur de connexion à la base :'#10#10#13 + IntToStr(e.ErrorCode) + ' : ' + e.Message + #10#10#13'Application terminée.',mtError,[mbOK],0);
  60.     Result := false;;
  61.   end;
  62.   on e : EDatabaseError do
  63.   begin
  64.     MessageDlg('Erreur de connexion à la base :'#10#10#13'Application terminée.',mtError,[mbOK],0);
  65.     Result := false;;
  66.   end;
  67. end;
  68. if Result = true then
  69.    MessageDlg('Base Luges disponible!',mtError,[mbOK],0);
  70. end;
  71. procedure TDataModule1.Logoff;
  72. begin
  73. if SQLTransaction.Active then
  74.    SQLTransaction.Active := false;
  75. if SQLConnection1.Connected  then
  76.     SQLConnection1.Connected := false;
  77. end;
  78.  
  79. end.

The problem is that the global variables assigned to the contents of the ini file do not pass their contents to DataAccess, although they pass them to Unit1.Why ?

dbannon

  • Hero Member
  • *****
  • Posts: 3156
    • tomboy-ng, a rewrite of the classic Tomboy
Re: connect to a database using an IP address contained in an ini file
« Reply #5 on: June 22, 2024, 03:05:46 am »
pjtuloup, I suspect you have a timing problem.  With quite a convoluted unit structure, its not clear to me when your DataAccess unit is created, no other unit seems to 'use' it ?

So, I wonder if its being created before the unit that reads the ini file is ?

If you are using Linux, a debugln() in the important parts of those units would easily tell you the order that things are happening. Otherwise, set some debugger break points and see which one pops up first.

Davo

Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Handoko

  • Hero Member
  • *****
  • Posts: 5379
  • My goal: build my own game engine using Lazarus
Re: connect to a database using an IP address contained in an ini file
« Reply #6 on: June 22, 2024, 05:09:55 am »
I believe that was calling order issue.

Normally, we expect this order to happen:
  • FormIdentif.iniRead is called by FormIdentif.FormCreate.
  • DataModule1.Login (which needs data from iniRead) is called by DataModuleCreate.
Because DataModule1.Login needs data provided by iniRead, FormIdentif.FormCreate has to be called before DataModuleCreate. Are you sure your program will run with that order?

You can try to check and reorder them by doing this:
Lazarus main menu > Project > Project Options > Forms

af0815

  • Hero Member
  • *****
  • Posts: 1380
Re: connect to a database using an IP address contained in an ini file
« Reply #7 on: June 22, 2024, 07:36:35 am »
Best way is, to control the lifetime of datamoduls by Programm and not accidently by the Project options.

Make shure, no DM has a active connection at its creation and control the open and close only by your code. So the Programms will be deterministic an you are to have all under your control. You can read your parameters from the ini, set the correct parameters, control the connection and all is stable working, no race condition can pop up.

In my apps, I create only one form and this control everything. So all creation and destroying is under programmatically control.
« Last Edit: June 22, 2024, 07:38:42 am by af0815 »
regards
Andreas

Handoko

  • Hero Member
  • *****
  • Posts: 5379
  • My goal: build my own game engine using Lazarus
Re: connect to a database using an IP address contained in an ini file
« Reply #8 on: June 22, 2024, 08:00:48 am »
+1 for ad0815's suggestions.

egsuh

  • Hero Member
  • *****
  • Posts: 1494
Re: connect to a database using an IP address contained in an ini file
« Reply #9 on: June 22, 2024, 08:34:52 am »
Why don't you put  variables IpServeur etc., and procedure TFormIdentif.iniRead in the DataAccess unit? I don't think you will need those variables and initializing procedure at other than DataAccess unit.

pjtuloup

  • New Member
  • *
  • Posts: 45
Re: connect to a database using an IP address contained in an ini file
« Reply #10 on: June 22, 2024, 11:41:52 am »
Thanks to all ! I will study all your suggestions during this week-end.I will keep you informed...

dseligo

  • Hero Member
  • *****
  • Posts: 1422
Re: connect to a database using an IP address contained in an ini file
« Reply #11 on: June 22, 2024, 12:25:55 pm »
I would also check it like this:
Code: Pascal  [Select][+][-]
  1. ...
  2. //IpServeur:='10.0.0.7';
  3. //ShowMessage('IP: ' + IpServeur);
  4.  
  5. If IpServeur = '10.0.0.7' then
  6.   ShowMessage('Same')
  7. else
  8.   ShowMessage('Not same');
  9.  
  10. SQLConnection1.Hostname := IpServeur;
  11. SQLConnection1.DatabaseName := '######';
  12.  
  13. ...

pjtuloup

  • New Member
  • *
  • Posts: 45
Re: connect to a database using an IP address contained in an ini file
« Reply #12 on: June 23, 2024, 09:17:12 pm »
I believe that was calling order issue.

Normally, we expect this order to happen:
  • FormIdentif.iniRead is called by FormIdentif.FormCreate.
  • DataModule1.Login (which needs data from iniRead) is called by DataModuleCreate.
Because DataModule1.Login needs data provided by iniRead, FormIdentif.FormCreate has to be called before DataModuleCreate. Are you sure your program will run with that order?

You can try to check and reorder them by doing this:
Lazarus main menu > Project > Project Options > Forms

Thanks to everyone and especially to Handoko, who was right: it was indeed a problem with the order of calls. Everything works fine now!

Sorry to respond so late but unfortunately I broke my screen panel and working became very uncomfortable.

 

TinyPortal © 2005-2018