Problem when updating the same record twice - FIXED!

The alpha/beta tester's forum for ZeosLib 7.0.x series

Report problems concerning our Delphi 2009+ version and new Zeoslib 7.0 features here.

This is a forum that will be removed once the 7.X version goes into stable!!

Moderators: gto, EgonHugeist, olehs

User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Problem when updating the same record twice - FIXED!

Post by Prometeus »

Hello,



I have a situation where, sometime, I need change the data of two register of same type, the second just after the first. The problem arises on the second update as it looks like Zeos is replicating the value of ALL field when they are NULL. The code is like below:

Code: Select all

with SQLTest do
    begin
      Close;
      SQL.Clear;
      SQL.Add('UPDATE test_table SET field1 = :field1, field2 = :field2, field3 = :field3,');
      SQL.Add('date_test = :date_test, state_test = :state_test');
      SQL.Add('WHERE (cod_testtable = :cod_testtable)');
      if TwoUpdatesCheckBox.Checked then
        begin
          ParamByName('FIELD1').AsInteger := 44;
          ParamByName('FIELD2').Clear;
          ParamByName('FIELD3').AsInteger := 45;
          ParamByName('DATE_TEST').AsDateTime := Now;
          ParamByName('STATE_TEST').AsString := 'D';
          ParamByName('COD_TESTTABLE').AsInteger := 2;
          ExecSQL;
        end;
      ParamByName('FIELD1').AsInteger := StrToInt(Field1.Text);
      ParamByName('FIELD2').AsInteger := StrToInt(Field2.Text);
      ParamByName('FIELD3').AsInteger := StrToInt(Field3.Text);
      ParamByName('DATE_TEST').AsDateTime := Now;
      ParamByName('STATE_TEST').AsString := 'A';
      ParamByName('COD_TESTTABLE').AsInteger := 3;
      ExecSQL;
    end;
In the above code, no matter what you put in 'Field2' for the second update it will get the NULL value of the first one. Why is this happening? If needed I can put the above sample as a project and the script for creating the test database.

I am using TESTING_REV679 version.

Thank you.
Last edited by Prometeus on 28.01.2010, 18:49, edited 3 times in total.
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Hello,


This bug still persists on TESTING_REV692.
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Hello,


Could someone confirm whether this is a bug or not? A reported this to ZEOS bug tracker but no answer as well.


Thank you.
User avatar
mdaems
Zeos Project Manager
Zeos Project Manager
Posts: 2766
Joined: 20.09.2005, 15:28
Location: Brussels, Belgium
Contact:

Post by mdaems »

Prometeus,

I saw you filed this as a bug report as well. Unfortunately I seem to be the only one looking at bug reports and all other issues, so I didn't try your test case yet.

However, as far as I can understand your example code, this looks like a genuine bug.

The only way to get this problem solved quicker is to debug and submit a patch using the bug tracker, I'm afraid.

Mark
Image
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Hello, Mark!


Ok, I'll try do that.
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Hello, Mark,



I tried follow the bug (that persists in TESTING_REV713) but to no avail. Can you or anyone else give me a clue to where should I look for it?

It's unbelievible that this bug did not happen to other user.


Thanks for any help.

BTW: I am using Delphi 7. A saw that Zeos uses ancestors from Delphi VCL. May the bug be on VCL? Can someone using newer Delphi version test the case that I put on SVN bugtracker? Thanks.
cariad
Junior Boarder
Junior Boarder
Posts: 36
Joined: 20.10.2005, 14:07

Post by cariad »

Confirmed in Delphi 2010.
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Thanks, Cariad!


So the bug seems to be in Zeos indeed.
seawolf
Zeos Dev Team *
Zeos Dev Team *
Posts: 385
Joined: 04.06.2008, 19:50
Contact:

Post by seawolf »

unit ZDbcInterbase6Utils;

procedure TZParamsSQLDA.UpdateInt(const Index: Integer; Value: Integer);
var
SQLCode: SmallInt;
begin
CheckRange(Index);
SetFieldType(Index, sizeof(Integer), SQL_LONG + 1, 0);
{$R-}
with FXSQLDA.sqlvar[Index] do
begin
if (sqlind <> nil) and (sqlind^ = -1) then
Exit;
SQLCode := (sqltype and not(1));

if (sqlscale < 0) then
begin
case SQLCode of
SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale];
SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale];
SQL_INT64,
SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale];
SQL_DOUBLE : PDouble(sqldata)^ := Value;
else
raise EZIBConvertError.Create(SUnsupportedDataType);
end;
end
else
case SQLCode of
SQL_DOUBLE : PDouble(sqldata)^ := Value;
SQL_LONG : PInteger(sqldata)^ := Value;
SQL_D_FLOAT,
SQL_FLOAT : PSingle(sqldata)^ := Value;
SQL_BOOLEAN : PSmallint(sqldata)^ := Value;
SQL_SHORT : PSmallint(sqldata)^ := Value;
SQL_INT64 : PInt64(sqldata)^ := Value;
SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value)));
SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value)));
else
raise EZIBConvertError.Create(SUnsupportedDataType);
end;
end;
if (sqlind <> nil) then
sqlind^ := 0; // not null

{$IFOPT D+}
{$R+}
{$ENDIF}
end;

Second time sqlind^ = -1 and must be set to 0 in order to write the field
to the db
User avatar
mdaems
Zeos Project Manager
Zeos Project Manager
Posts: 2766
Joined: 20.09.2005, 15:28
Location: Brussels, Belgium
Contact:

Post by mdaems »

seawolf,

Did you compile this? I get "Error: Undeclared identifier: 'sqlind'"

Mark
Image
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Seawolf and Mdaems,



The "Error: Undeclared identificer: 'sqlind'" may be bypassed if you reference it before like this:

...
with FXSQLDA.sqlvar[Index] do
if (sqlind <> nil) then
sqlind^ := 0; // not null
...

However the bug still persists on my test case. Watching the code for updating of other types on that unit it looks like the bug exists in all of them, as the code is virtually the same for all of them. The fix, when found, must be applied to all data types, isn't?

Lets keep trying throw this bug away...
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Hello,


The bug still persists on TESTING_REV725. This is a serious bug when you have a list of values to be UPDATEd on any DB table and some of the fields must be NULL for some reason in the loop. The next iteration of that field will be NULL as well what may raise a 'ghost' effect on that table. I realized I have an application in such a situation and I couldn't figure out where was the bug. I tought it could be on Firebird but after Seawolf post I realized the problem was the same of other application I have whose situation is like the test case I created on bug tracker.

I am trying to fix this bug but to no avail until now. I guess there are other people with this bug in their applications and, probably, they do not know where else to look for because of this 'ghost' effect the bug introduces on the application.

Well, back to try finding out a solution.
Last edited by Prometeus on 23.11.2009, 19:21, edited 2 times in total.
seawolf
Zeos Dev Team *
Zeos Dev Team *
Posts: 385
Joined: 04.06.2008, 19:50
Contact:

Post by seawolf »

Sorry for the long delay .. after your post I check one more time and, to be honest, problem is not located in that function. I made some changes in a different function and I'm really close to resolve it. Unfortunately past week I was very busy. Now I have some free time to fix definetely that problem and post the solution.
User avatar
Prometeus
Senior Boarder
Senior Boarder
Posts: 56
Joined: 29.10.2005, 01:25

Post by Prometeus »

Hello Seawolf,


Oh, good news! Glad to know you are close to fix it!! Can you confirm whether this bug affects other data type other then Integer?


Thank you!
seawolf
Zeos Dev Team *
Zeos Dev Team *
Posts: 385
Joined: 04.06.2008, 19:50
Contact:

Post by seawolf »

Problem is located in dbc\ZDbcInterbase6Statement.pas
If the first time a param is set null, after cannot be set as not null
This change cannot affect any data type.
Please test it (it works to me)

procedure TZInterbase6PreparedStatement.BindInParameters;
var
I: Integer;
TempBlob: IZBlob;
TempStream: TStream;
begin
if InParamCount <> FParamSQLData.GetFieldCount then
raise EZSQLException.Create(SInvalidInputParameterCount);

{$R-}
for I := 0 to FParamSQLData.GetFieldCount - 1 do
begin
FParamSQLData.UpdateNull(I,
DefVarManager.IsNull(InParamValues));
if DefVarManager.IsNull(InParamValues)then
Continue
else
case InParamTypes of
stBoolean:
FParamSQLData.UpdateBoolean(I,
SoftVarManager.GetAsBoolean(InParamValues));
stByte:
FParamSQLData.UpdateByte(I,
SoftVarManager.GetAsInteger(InParamValues));
stShort:
FParamSQLData.UpdateShort(I,
SoftVarManager.GetAsInteger(InParamValues));
stInteger:
FParamSQLData.UpdateInt(I,
SoftVarManager.GetAsInteger(InParamValues));
stLong:
FParamSQLData.UpdateLong(I,
SoftVarManager.GetAsInteger(InParamValues));
stFloat:
FParamSQLData.UpdateFloat(I,
SoftVarManager.GetAsFloat(InParamValues));
stDouble:
FParamSQLData.UpdateDouble(I,
SoftVarManager.GetAsFloat(InParamValues));
stBigDecimal:
FParamSQLData.UpdateBigDecimal(I,
SoftVarManager.GetAsFloat(InParamValues[I]));
stString:
FParamSQLData.UpdateString(I,
SoftVarManager.GetAsString(InParamValues[I]));
stUnicodeString:
FParamSQLData.UpdateString(I,
SoftVarManager.GetAsUnicodeString(InParamValues[I]));
stBytes:
FParamSQLData.UpdateBytes(I,
StrToBytes(SoftVarManager.GetAsString(InParamValues[I])));
stDate:
FParamSQLData.UpdateDate(I,
SoftVarManager.GetAsDateTime(InParamValues[I]));
stTime:
FParamSQLData.UpdateTime(I,
SoftVarManager.GetAsDateTime(InParamValues[I]));
stTimestamp:
FParamSQLData.UpdateTimestamp(I,
SoftVarManager.GetAsDateTime(InParamValues[I]));
stAsciiStream,
stUnicodeStream,
stBinaryStream:
begin
TempBlob := DefVarManager.GetAsInterface(InParamValues[I]) as IZBlob;
if not TempBlob.IsEmpty then
begin
TempStream := TempBlob.GetStream;
try
FParamSQLData.WriteBlob(I, TempStream);
finally
TempStream.Free;
end;
end;
end;
else
raise EZIBConvertError.Create(SUnsupportedParameterType);
end;
end;
{$IFOPT D+}
{$R+}
{$ENDIF}
inherited BindInParameters;
end;
Locked