Recent

Author Topic: Are there some type errors in this StrToBoolEx function in Zeoslib?  (Read 316 times)

vfclists

  • Hero Member
  • *****
  • Posts: 1146
    • HowTos Considered Harmful?
Although it is from the Zeoslib issue I think the fault I'm seeing comes from the FreePascal, or it may due to some effects from the defines, string-handling or maybe due to changes in the FPC compile.

On further inspection the call doesn't seem to match the function signatures, so it may be another definition in another file I may have to check.

The full file is at https://github.com/marsupilami79/zeoslib/blob/7.2.14-stable/src/core/ZSysUtils.pas

The actual file

Code: Pascal  [Select][+][-]
  1. function StrToBoolEx(const Str: RawByteString; const CheckInt: Boolean = True): Boolean; overload;
  2.  
  3. {**
  4.   Converts a zero terminated raw buffer into boolean value.
  5.   @param Str a PAnsiChar value.
  6.   @param CheckInt Check for "0" char too?
  7.   @param IgnoreTrailingSaces Ignore trailing spaces for fixed char fields f.e.
  8.   @return <code>True</code> is Str = 'Y'/'YES'/'T'/'TRUE'/'ON'/<>0
  9. }
  10. function StrToBoolEx(Str: PAnsiChar; const CheckInt: Boolean = True;
  11.   const IgnoreTrailingSaces: Boolean = True): Boolean; overload;
  12.  
  13. {**
  14.   Converts a string into boolean value.
  15.   @param Str a ZWideString value.
  16.   @return <code>True</code> is Str = 'Y'/'YES'/'T'/'TRUE'/'ON'/<>0
  17. }
  18. function StrToBoolEx(const Str: ZWideString; const CheckInt: Boolean = True): Boolean; overload;
  19.  
  20. {**
  21.   Converts a zero terminated UTF16 buffer into boolean value.
  22.   @param Str a PWideChar value.
  23.   @param CheckInt Check for "0" char too?
  24.   @param IgnoreTrailingSaces Ignore trailing spaces for fixed char fields f.e.
  25.   @return <code>True</code> is Str = 'Y'/'YES'/'T'/'TRUE'/'ON'/<>0
  26. }
  27. function StrToBoolEx(Str: PWideChar; const CheckInt: Boolean = True;
  28.   const IgnoreTrailingSaces: Boolean = True): Boolean; overload;
  29.  
  30. {**
  31.   Converts a boolean into string value.
  32.   @param Bool a boolean value.
  33.   @return <code>"True"</code> or <code>"False"</code>
  34. }
  35.  

It is used in the function below, primarily in this section.


The problem line seems to be
Code: Pascal  [Select][+][-]
  1. lValidateUpdateCount := (SQL = '') or StrToBoolEx(SQL);
fails to return False when SQL='-1' and I think its definition as string is the cause in the help it is displayed as

Tool tip info during debugging

SQL = ANSISTRING($00007FE14AB85618)^: '-1'
var SQL: string
/home/vfclists/Lazarus/Configs/Lazarus-3.0.0-2023-12-23/onlinepackagemanager/packages/zeosdbo/src/dbc/ZDbcGenericResolver.pas(797,3)
Package
zdbc


The problem section

Line 5 (below, Line 81 in the full function) are where the failure occurs.

Code: Pascal  [Select][+][-]
  1.   // if Property ValidateUpdateCount isn't set : assume it's true
  2.   SenderStatement := Sender.GetStatement;
  3.   if Assigned(SenderStatement) then begin
  4.     SQL := SenderStatement.GetParameters.Values['ValidateUpdateCount'];
  5.     lValidateUpdateCount := (SQL = '') or StrToBoolEx(SQL);
  6.   end else begin
  7.     lValidateUpdateCount := true;
  8.   end;
  9.  
  10.   lUpdateCount := Statement.ExecuteUpdatePrepared;
  11.   {$IFDEF WITH_VALIDATE_UPDATE_COUNT}
  12.   if  (lValidateUpdateCount) and (lUpdateCount <> 1   ) then
  13.     raise EZSQLException.Create(Format(SInvalidUpdateCount, [lUpdateCount]));
  14.   {$ENDIF}
  15.  


On further inspection the call doesn't seem to match the function signatures, so it may be another definition in another file I may have check.

The function that calls StrToBoolEx(param: string)
 
Code: Pascal  [Select][+][-]
  1. {**
  2.   Posts updates to database.
  3.   @param Sender a cached result set object.
  4.   @param UpdateType a type of updates.
  5.   @param OldRowAccessor an accessor object to old column values.
  6.   @param NewRowAccessor an accessor object to new column values.
  7. }
  8. procedure TZGenericCachedResolver.PostUpdates(Sender: IZCachedResultSet;
  9.   UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor);
  10. var
  11.   Statement            : IZPreparedStatement;
  12.   SQL                  : string;
  13.   SQLParams            : TObjectList;
  14.   lUpdateCount         : Integer;
  15.   lValidateUpdateCount : Boolean;
  16.   TempKey              : IZAnyValue;
  17.   SenderStatement      : IZStatement;
  18. begin
  19.   if (UpdateType = utDeleted) and (OldRowAccessor.RowBuffer.UpdateType = utInserted) then
  20.     Exit;
  21.  
  22.   case UpdateType of
  23.     utInserted:
  24.       begin
  25.         if InsertStatement = nil then begin
  26.           SQL := FormInsertStatement(FInsertParams, NewRowAccessor);
  27.           InsertStatement := CreateResolverStatement(SQL);
  28.           Statement := InsertStatement;
  29.         end;
  30.         Statement := InsertStatement;
  31.         SQLParams := FInsertParams;
  32.       end;
  33.     utDeleted:
  34.       begin
  35.         if not FWhereAll then begin
  36.           If DeleteStatement = nil then begin
  37.             SQL := FormDeleteStatement(FDeleteParams, OldRowAccessor);
  38.             DeleteStatement := CreateResolverStatement(SQL);
  39.           end;
  40.           Statement := DeleteStatement;
  41.           SQLParams := FDeleteParams;
  42.         end else begin
  43.           FDeleteParams.Clear;  //EH: where columns propably are cached after 1. call
  44.           SQL := FormDeleteStatement(FDeleteParams, OldRowAccessor);
  45.           if SQL = '' then Exit;
  46.           TempKey := TZAnyValue.CreateWithInteger(Hash(SQL));
  47.           Statement := FStatements.Get(TempKey) as IZPreparedStatement;
  48.           If Statement = nil then begin
  49.             Statement := CreateResolverStatement(SQL);
  50.             FStatements.Put(TempKey, Statement);
  51.           end;
  52.           SQLParams := FDeleteParams;
  53.         end;
  54.       end;
  55.     utModified:
  56.       begin
  57.         FUpdateParams.Clear;  //EH: where columns propably are cached after 1. call
  58.         //now what's faster?: caching stmts too by using a hashmap or recreate always
  59.         //first of all: we need the new command-stmt
  60.         SQL := FormUpdateStatement(FUpdateParams, OldRowAccessor, NewRowAccessor);
  61.         If SQL = '' then exit;// no fields have been changed
  62.         TempKey := TZAnyValue.CreateWithInteger(Hash(SQL));
  63.         UpdateStatement := FStatements.Get(TempKey) as IZPreparedStatement;
  64.         If UpdateStatement = nil then begin
  65.           UpdateStatement := CreateResolverStatement(SQL);
  66.           FStatements.Put(TempKey, UpdateStatement);
  67.         end;
  68.         Statement := UpdateStatement;
  69.         SQLParams := FUpdateParams;
  70.       end;
  71.     else
  72.       Exit;
  73.   end;
  74.  
  75.   FillStatement(Statement, SQLParams, OldRowAccessor, NewRowAccessor);
  76.  
  77.   // if Property ValidateUpdateCount isn't set : assume it's true
  78.   SenderStatement := Sender.GetStatement;
  79.   if Assigned(SenderStatement) then begin
  80.     SQL := SenderStatement.GetParameters.Values['ValidateUpdateCount'];
  81.     lValidateUpdateCount := (SQL = '') or StrToBoolEx(SQL);
  82.   end else begin
  83.     lValidateUpdateCount := true;
  84.   end;
  85.  
  86.   lUpdateCount := Statement.ExecuteUpdatePrepared;
  87.   {$IFDEF WITH_VALIDATE_UPDATE_COUNT}
  88.   if  (lValidateUpdateCount) and (lUpdateCount <> 1   ) then
  89.     raise EZSQLException.Create(Format(SInvalidUpdateCount, [lUpdateCount]));
  90.   {$ENDIF}
  91. end;
Lazarus 3.0/FPC 3.2.2

tetrastes

  • Hero Member
  • *****
  • Posts: 600
Re: Are there some type errors in this StrToBoolEx function in Zeoslib?
« Reply #1 on: October 01, 2024, 07:16:19 pm »

The problem line seems to be
Code: Pascal  [Select][+][-]
  1. lValidateUpdateCount := (SQL = '') or StrToBoolEx(SQL);
fails to return False when SQL='-1'


Why do you think it must return false?
StrToBoolEx('-1') evaluates to the line 1909 of ZSysUtils.pas:
Code: Pascal  [Select][+][-]
  1. Result := CheckInt and (RawToIntDef(Str, 0) <> 0);
CheckInt = true by default (as you don't explicitly set it to false), RawToIntDef('-1', 0) = -1, so Result = true.


Try
Code: Pascal  [Select][+][-]
  1. lValidateUpdateCount := (SQL = '') or StrToBoolEx(SQL, false);

vfclists

  • Hero Member
  • *****
  • Posts: 1146
    • HowTos Considered Harmful?
Re: Are there some type errors in this StrToBoolEx function in Zeoslib?
« Reply #2 on: October 01, 2024, 08:56:16 pm »

The problem line seems to be
Code: Pascal  [Select][+][-]
  1. lValidateUpdateCount := (SQL = '') or StrToBoolEx(SQL);
fails to return False when SQL='-1'


Why do you think it must return false?
StrToBoolEx('-1') evaluates to the line 1909 of ZSysUtils.pas:
Code: Pascal  [Select][+][-]
  1. Result := CheckInt and (RawToIntDef(Str, 0) <> 0);
CheckInt = true by default (as you don't explicitly set it to false), RawToIntDef('-1', 0) = -1, so Result = true.


Try
Code: Pascal  [Select][+][-]
  1. lValidateUpdateCount := (SQL = '') or StrToBoolEx(SQL, false);

You are right. I was following a forum post on fixing problem and didn't go too deep into checking it. It was all rather ambiguous.

The guidance should have said ValidateUpdateCount should be set to zero 0 or 'False'.
Lazarus 3.0/FPC 3.2.2

Thaddy

  • Hero Member
  • *****
  • Posts: 16199
  • Censorship about opinions does not belong here.
Re: Are there some type errors in this StrToBoolEx function in Zeoslib?
« Reply #3 on: October 02, 2024, 03:40:39 pm »
it is not ambiguous: false (0) is always true.
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018