Fixed Access Violation when setting Sort Fields in SQLite3 DB
Posted: 11.12.2021, 01:02
unit ZDbcCache;
I was getting an access violation when I set the SortIndexFields value to two fields in a table. I tracked it down to the function CompareUnicodeCLob_Asc and discovered it was happening only when it was trying to compare a field with itself. I added an extra check to verify if the two pointers being passed were the same (shown bracketed in {KJS Added} through {KJS END ADD} which seems to solve the problem.
However, it does imply that the sort is not as efficient as it could be as it really shouldn't be comparing two copies of the same field.
I was getting an access violation when I set the SortIndexFields value to two fields in a table. I tracked it down to the function CompareUnicodeCLob_Asc and discovered it was happening only when it was trying to compare a field with itself. I added an extra check to verify if the two pointers being passed were the same (shown bracketed in {KJS Added} through {KJS END ADD} which seems to solve the problem.
However, it does imply that the sort is not as efficient as it could be as it really shouldn't be comparing two copies of the same field.
Code: Select all
function CompareUnicodeCLob_Asc(const Null1, Null2: Boolean; const V1, V2): Integer;
var
Blob1, Blob2: IZBlob;
{$IFDEF MSWINDOWS}
ValuePtr1, ValuePtr2: Pointer;
{$ENDIF}
begin
{KJS ADDED}
if (PPointer(V1)^=PPointer(V2)^) then
begin
result:=0;
exit;
end;
{KJS END ADD}
Result := NullsCompareMatrix[Null1, Null2];
if Result = BothNotNull then
begin
// Both values not null
Blob1 := IZBlob(PPointer(V1)^);
Blob2 := IZBlob(PPointer(V2)^);
Result := NullsCompareMatrix[(Blob1 = nil) or (Blob1.IsEmpty), (Blob2 = nil) or (Blob2.IsEmpty)];
if Result <> BothNotNull then Exit;
if Blob1.IsClob and Blob2.IsClob then
begin
{$IFDEF MSWINDOWS}
ValuePtr1 := Blob1.GetPWideChar;
ValuePtr2 := Blob2.GetPWideChar;
SetLastError(0);
Result := CompareStringW(LOCALE_USER_DEFAULT, 0,
ValuePtr1, Blob1.Length, ValuePtr2, Blob2.Length) - 2{CSTR_EQUAL};
end;
if GetLastError <> 0 then RaiseLastOSError;
{$ELSE}
{$IFDEF UNICODE}
Result := AnsiCompareStr(Blob1.GetUnicodeString, Blob2.GetUnicodeString);
{$ELSE}
Result := WideCompareStr(Blob1.GetUnicodeString, Blob2.GetUnicodeString);
{$ENDIF}
{$ENDIF}
end
else
Result := ZMemLComp(Blob1.GetBuffer, Blob2.GetBuffer, Max(Blob1.Length, Blob2.Length));
end;
end;