Today I encountered the same problem. (Lazarus 3.4 + ZeosLib 8.0)
I am using TZQuery and TDBGrid to display a query result, and I implemented the sorting functionality by clicking the header of the TDBGrid control.
My query results include a series of fields from the database table as well as three calculated fields. When I click the header of these three calculated fields, a memory access error occurs (clicking non-calculated fields works fine).
The error comes from TZRowAccessor.SetNull() :
Code: Select all
procedure TZRowAccessor.SetNull(ColumnIndex: Integer);
var Data: PPointer;
begin
{$IFNDEF DISABLE_CHECKING}
CheckColumnIndex(ColumnIndex);
{$ENDIF}
{$R-}
if (FBuffer.Columns[FColumnOffsets[ColumnIndex{$IFNDEF GENERIC_INDEX} - 1{$ENDIF}]] = bIsNotNull) then begin
Data := @FBuffer.Columns[FColumnOffsets[ColumnIndex{$IFNDEF GENERIC_INDEX} - 1{$ENDIF}] + 1];
FBuffer.Columns[FColumnOffsets[ColumnIndex{$IFNDEF GENERIC_INDEX} - 1{$ENDIF}]] := bIsNull;
{$IFDEF RangeCheckEnabled}{$R+}{$ENDIF}
case FColumnTypes[ColumnIndex{$IFNDEF GENERIC_INDEX} - 1{$ENDIF}] of
stAsciiStream, stBinaryStream, stUnicodeStream:
PIZLob(Data)^ := nil;
stBytes, stString, stUnicodeString:
if Data^ <> nil then begin
System.FreeMem(Data^); <----- Error come from this line.
Data^ := nil;
end;
{$IFDEF WITH_CASE_WARNING}else ;{$ENDIF}
end;
end;
end;
Error comes from "
System.FreeMem(Data^);"
Here is the sorting code:
Code: Select all
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
bm: TBookmark;
G: TDBGrid;
Q: TZQuery;
S: string;
imgIdx: integer;
begin
G := Column.Grid as TDBGrid;
Q := G.DataSource.DataSet as TZQuery;
if (Q = nil) or not Q.Active or Q.IsEmpty then exit;
if (Column.Field.DataType in [ftUnknown, ftBytes, ftVarBytes, ftBLOB,
ftMemo, ftGraphic, ftFmtMemo, ftWideMemo]) then
exit;
bm := Q.GetBookmark;
Q.DisableControls;
try
s := Q.IndexFieldNames;
if POS(Column.FieldName + ' Desc', s) = 0 then
begin
Q.IndexFieldNames := Column.FieldName + ' Desc';
imgIdx := 1;
end
else
begin
Q.IndexFieldNames := Column.FieldName;
imgIdx := 0;
end;
Column.Title.ImageIndex := imgIdx;
if (G.Tag > 0) and (G.Tag <> Column.Index + 1) then
G.Columns[G.Tag - 1].Title.ImageIndex := -1;
G.Tag := column.Index + 1;
finally
Q.GotoBookmark(bm);
Q.FreeBookmark(bm);
Q.EnableControls;
end;
end;
I spent an entire afternoon experimenting with why this error occurs, but unfortunately, I couldn't find the cause of the problem.
In the end, I tried to set up TZQuery in the following steps, and it seems that this avoids the memory access error:
1. Add the three calculated fields in TZQuery;
2. Add the SQL query statement in TZQuery.SQL;
3. Set TZQuery.Active=True;
4. Add all the fields from the query results to TZQuery;
5. Setup TDatasource and TDBGrid.
The key step here is Step 1, where all calculated fields must be added first.