Page 1 of 1
Connect / Disconnect corrupting Application
Posted: 13.01.2025, 14:25
by agamelas
Hello Everyone,
Has anybody faced this issue before? I'm looking for some help with the situation below:
I have an application POS developed with Delphi 7 + Zeos 7.1.4 with a SQLite Database which has been working for over a year in dozens of stations,
We recently made the update of Zeos Version to the newest (8.0.0) and shortly after that we started seeing Access Violation Errors. Even after applying all patches from SVN, the errors remain.
Starting from the moment the first error happens, you have to logout of the App and Login again. And the error does not happen immediately. It takes a while, usually on the 10 sales mark. Give or take a few.
After debugging, we found out that the error happens when you try to set a String as a parameter of a Query as show below:
zqrDel.ParamByName('NIDTIPO').AsString := CNIDTIPO_USUARIO;
It doesn't always happen on the same query, but always when you try to set a Value of type String to a parameter.
Digging deeper, we found the exact point in Zeos where the error happens:
Its on the file: ZDatasetParam.pas - On the Class TZParam - On the Method: procedure TZParam.SetAsStrings(Index: Cardinal; const Value: String);
The line where the error happens is:
If ((FConSettings <> nil) or SetConsettings) and (FConSettings.ClientCodePage.Encoding = ceUTF16) then begin
More precisely, its when the application evaluates the variable FConSettings
It is NOT Null, but it contains a value that points to a place in memory with garbage.
After more investigations, we found out what was causing this variable corruption. The App, between sales, for security reasons, disconnects from the Database, makes a copy from the Database and connects again.
procedure SafeBackup;
begin
zDBMov.Disconnect;
DoBackupDBMOV;
zDBMov.Connect;
end;
After commenting the call to procedure SafeBackup, the app has not had any problems so far. And the problem only happens after this is called several times.
Any Hint or Workaround ?
Re: Connect / Disconnect corrupting Application
Posted: 13.01.2025, 20:42
by marsupilami
Hello,
hunting down memory bugs like this is hard.
You might want to check the
VACUUM INTO command to see if you can live without deconnecting.
Best regards,
Jan
Re: Connect / Disconnect corrupting Application
Posted: 14.01.2025, 23:06
by agamelas
Hi Jan
Thanks for your help / Hint. In this specific case it solves the problem.
However we have another application where we need to connect and disconnect from time to time in the Database and in this case I can not avoid the Connect/Disconnect cycle.
I know that this kind of bug is very hard to find and fix, BUT I managed to replicate the BUG with a very, very simple application.
I create a SQLite Databse with just one table:
The application has just TWO querys and one Method:
function TDMZeos.InsertRecord( nValor: double; sStatus: string): Boolean;
var
nMax : integer;
begin
ZDB.Connect;
try
qrMax.Close;
qrMax.Open;
nMax := qrMaxNFCFICHA.AsInteger + 1;
qrMax.Close;
with qrInsReg do begin
Close;
ParamByName('NFCFICHA').AsInteger := nMax;
ParamByName('CAIFICHA').AsInteger := nMax;
ParamByName('NFCVALOR').AsFloat := nValor;
ParamByName('NFCSTATUS').AsString := sStatus;
ParamByName('NFCDATA').AsDateTime := now;
ParamByName('NFCOBSERVACAO').AsString := 'Inserido em ' + FormatDateTime('dd/mm/yyy - hh:NN:ss', now);
ExecSQL;
end;
except
on E: Exception do begin
ShowMessage(E.Message);
end;
end;
ZDB.Disconnect;
end;
SQL querys:
qrMax -> S3L3CT coal3sce( MAX(NFCFICHA),0) AS NFCFICHA FROM NFCUPOM
qrInsReg -> INS3RT INT0 NFCUPOM (NFCFICHA, CAIFICHA, NFCVALOR, NFCSTATUS, NFCDATA, NFCOBSERVACAO)
VALU3S ( :NFCFICHA, :CAIFICHA, :NFCVALOR, :NFCSTATUS, :NFCDATA, :NFCOBSERVACAO);
** I had to obfuscate the Sql Code to avoid being blocked
Calling the method InsertRecord twice triggers the error:
If you comment the line -> ZDB.Disconnect;, the error goes away
If you wish, I can send you the Delphi7 apllication source code:
Re: Connect / Disconnect corrupting Application
Posted: 15.01.2025, 08:44
by marsupilami
Hello,
yes - please send the test program and the test database.
Best regards,
Jan
Re: Connect / Disconnect corrupting Application
Posted: 15.01.2025, 15:13
by agamelas
Hi Jan
Attached is the source code of the application. Its in Delphi 7. Just compile and click the button many times and the error will pop-up.
If you have any questions I will be glad to help.
Thanks for your attention.
Alvaro Gamelas (from Brazil)
Re: Connect / Disconnect corrupting Application
Posted: 15.01.2025, 17:44
by miab3
Hi agamelas,
I tried clicking 100 times and the error didn't occur.
Delphi 10.3-Win32; SQlite 3.47.2; zeosdbo-8.0.0-stable(07.04.2024)
I added:
procedure TFMain.Button1Click(Sender: TObject);
var i : integer;
begin
for i:=0 to 999 do
bInserirClick(Self);
end;
Zerro errors. And there are 1000 records added.
Michal
Re: Connect / Disconnect corrupting Application
Posted: 15.01.2025, 19:47
by agamelas
Hi.
Thanks Michal for your prompt reply.
I am using Windows 11. We work with many third-part components (Jedi, Infopower, 1st Class, Teechart, etc).
So I picked up a new, clean machine with Windows 10 (64 bits) and made a fresh install of Delphi 7 from the original CD.
And I installed ONLY the Zeos Lib with the newest Sqlite.dll (3.48.0.0)
I compiled the sample application that I sent you and the error persists.
A friend of mine that is a programmer too, said that the problem is that you are using a Delphi 10 that HAS Unicode support. Delphi 7 DOES NOT have Unicode support.
So the code that is causing the problem is not even being compiled by your compiler.
If you see the source code of ZDataSetParam.pas the procedure that is being called when the line -> ParamByName('NFCSTATUS').AsString := sStatus; is executed is:
TZParam.SetAsString which calls TZParam.SetAsStrings as you can see in the source code that has a Conditional compilation clause {$IFNDEF UNICODE}
***************************
{$IFNDEF UNICODE}
procedure TZParam.SetAsString(const Value: String);
begin
SetAsStrings(Cardinal(-1), Value);
end;
{$ENDIF UNICODE}
{$IFNDEF UNICODE}
procedure TZParam.SetAsStrings(Index: Cardinal; const Value: String);
****************************
In your delphi version, which has Unicode support, its calling another method.
You can debug in the source code of ZDataSetParam.pas to see which method is called when you set a String Parameter of a query
I think that to see the error in action you have to use Delphi 7.
Thanks again for your Help.
Alvaro Gamelas (from Brazil)
Re: Connect / Disconnect corrupting Application
Posted: 15.01.2025, 23:13
by miab3
Hi agamelas,
Indeed, in Delphi7 this error occurs, but not in Delphi 2007.
Michal
Re: Connect / Disconnect corrupting Application
Posted: 15.01.2025, 23:31
by agamelas
Ok Michal. Thanks for your confirmation.
What is the next step now ? (I don't know what to do now)
Alvaro Gamelas
Re: Connect / Disconnect corrupting Application
Posted: 16.01.2025, 12:10
by marsupilami
Hello Alvaro,
agamelas wrote: ↑15.01.2025, 23:31
What is the next step now ? (I don't know what to do now)
My suggestion is:
- Go back to Zeos 7.2
- Migrate your application to a modern Delphi or alternatively Lazarus
- Migrate to Zeos 8
Supporting Delphi 7 is a pain. I really liked Delphi 6 and Delphi 7 back in 2000 but now we have more and more problems because we have to work around bugs in a compiler that is not supported anymore. If you move to a Unicode compiler, you also have the benefit that more people use the unicode parts of Zeos and that more people test it.
You could try to see if the same problem comes up in FPC/Lazarus. Then it is more easy to debug, I guess.
Also you could try to reevaluate, if you really need to disconnect from the database. I wonder about your use case - normally SQLite can work with different applications accessing the same database.
I am sure sooner or later I will debug into this problem. But I am not even sure, if my Delphi 7 installation still works.
Best regards,
Jan
Re: Connect / Disconnect corrupting Application
Posted: 16.01.2025, 12:27
by marsupilami
A note from EgonHugeist:
Starting with Delphi 2007 Delphi uses FastMM. You could try to see, if your problem gets hidden again if you use FastMM for Delphi 7.
Best regards,
Jan
Re: Connect / Disconnect corrupting Application
Posted: 16.01.2025, 16:12
by agamelas
Hi Jan
I really need the connect/disconnect feature. But I made a workaround that may solve the problem.
What is happening is that when we disconnect/Connect the variable FConSettings does not change and is pointing to an invalid address. (Is pointing to the older position in memory)
What I did. In the beginning of the method -> procedure TZParam.SetAsStrings(Index: Cardinal; const Value: String);, I set the value of FConSettings to nil always. After that it began to work flawless. (As the method tests if FConSettings is nil it calls SetConsettings )
I dont know if always setting FConSettings to nil has other consequences in another methods. (besides making the program slower)
Thanks again,
Alvaro Gamelas (from Brazil)
Re: Connect / Disconnect corrupting Application
Posted: 17.01.2025, 11:38
by marsupilami
Hello Alvaro,
I think this might lead to a memory leak that makes your application consume more and more memory. So if your program runs for a long time, you might get in trouble.
Best regards,
Jan
Re: Connect / Disconnect corrupting Application
Posted: 17.01.2025, 22:56
by agamelas
Hi Jan
Thanks again for your patience in my case.
I tried to Debug again my sample application to see if I can solve the problem. After all I may contribute for the Zeos Library
As I don't know too much about the internals of the library I am posting here what I found to see if I am on the right track
What I discover is when you Call the method disconnect of the TZConnection it calls a method: TZAbstractConnection.CloseAllLinkedComponents;
Inside this method:
for i := FLinkedComponents.Count -1 downto 0 do begin
AComp := TComponent(FLinkedComponents);
if AComp.InheritsFrom(TZAbstractMemTable) then
continue
else begin
if AComp.InheritsFrom(TZAbstractRODataset) then begin
if not TZProtectedAbstractRODataset(AComp).Active or not TZProtectedAbstractRODataset(AComp).TryKeepDataOnDisconnect then try
TZAbstractRODataset(AComp).Close;
TZAbstractRODataset(AComp).UnPrepare;
I am using a TZReadOnlyQuery. Debugging this method it calls TZAbstractRODataset(AComp).Close; which in turn should call TZAbstractRODataset.InternalClose; I presume
but the InternalClose method of the TZAbstractRODataset IS NOT being called.
What I did (just to see if it COULD be the problem). I changed the visibility of the InternalClose method to public (just for testing) and add the line as:
for i := FLinkedComponents.Count -1 downto 0 do begin
AComp := TComponent(FLinkedComponents);
if AComp.InheritsFrom(TZAbstractMemTable) then
continue
else begin
if AComp.InheritsFrom(TZAbstractRODataset) then begin
if not TZProtectedAbstractRODataset(AComp).Active or not TZProtectedAbstractRODataset(AComp).TryKeepDataOnDisconnect then try
TZAbstractRODataset(AComp).Close;
TZAbstractRODataset(AComp).InternalClose; <----- Added this call
TZAbstractRODataset(AComp).UnPrepare;
After this the error goes away.
Maybe this gives you a shed of light in the BUG
Hope that I have contributed a bit to Zeos library
Alvaro Gamelas (from Brazil)