I think I have found why it errors.
In DBGrids there is this code
Code: Pascal [Select]
if FGrid.DataSource.DataSet=FDataset then
exit;
FDataset := FGrid.DataSource.DataSet;
// Note.
//
// Some dataset descendants do not implement CompareBookmarks, for these we
// use MyCompareBookmarks in the hope the allocated bookmark memory is used
// to hold some kind of record index.
FUseCompareBookmarks := TMethod(@FDataset.CompareBookmarks).Code<>pointer(@TDataset.CompareBookmarks);
// Note.
//
// fpc help say CompareBookmarks should return -1, 0 or 1 ... which imply that
// bookmarks should be a sorted array (or list). In this scenario binary search
// is the prefered method for finding a bookmark.
//
// The problem here is that TBufDataset and TSQLQuery (and thus TCustomSQLQuery
// and TCustomBufDataset) CompareBookmarks only return 0 or -1 (some kind of
// is this a valid bookmark or not), the result is that it appears as an unsorted
// list (or array) and binary search should not be used.
//
// The weird thing is that if we use MyCompareBookmarks which deals with comparing
// the memory reserved for bookmarks in the hope bookmarks are just some kind of
// reocord indexes, currently work fine for TCustomBufDataset derived datasets.
// however using CompareBookmarks is always the right thing to use where implemented.
//
// As Dbgrid should be TDataset implementation agnostic this is a way I found
// to know if the dataset is derived from TCustomBufDataset or not.
// Once TCustomBufDataset is fixed, remove this ugly note & hack.
case FDataset.ClassName of
'TSQLQuery','TBufDataset','TCustomSQLQuery','TCustomBufDataset':
FCanDoBinarySearch := false;
else
FCanDoBinarySearch := true;
end;
Which suggests that TSQLQuery is a funny dataset and doesn't comply with the CompareBookmarks return values (see comments). But TMethod does return True.
So at the end of this routine, FUseCOmpareBookmarks is True and FCanDoBinarySearch is False.
In the TBookmarklist.Find routine there is this code
Code: Pascal [Select]
procedure VisitAll;
begin
AIndex := 0;
i := 0;
while i<FList.Count do begin
if FCanDoBinarySearch then
//if FUseCompareBookmarks then
CompareRes := FDataset.CompareBookmarks(Item, TBookmark(FList))
else
CompareRes := MyCompareBookmarks(FDataset, pointer(Item), FList);
if CompareRes=0 then begin
result := true;
AIndex := i;
exit;
end;
inc(i);
end;
end;
begin
{$ifdef dbgDBGrid}
DebugLn('%s.Find', [ClassName]);
{$endif}
Result := False;
if Item=nil then
Exit;
if FCanDoBinarySearch then
BinarySearch
else
VisitAll;
end;
The main part of the routine checks whether we can do a binary sourt or not and for a TSQLQuery we should so we call VisitAll.
However in VisitAll it then uses FCanDoBinarySearch (which is true) to call the FDataset.COmpareBookmarks routine, but we had already established that this didn't work for a TSQLQuery.
So changing the If condition to FUseCompareBookmarks to get it to go to MyCompareBookmarks works and we don't get an error.
However, it still doesn't work correctly as each time I call the ShowModal form the bookmarklist is now what appears to be random.
Just to clarify what I'm doing. I have create a Form with a DBGrid on it which I'm using for a Filter selection a bit like the MS Access filter selection. The form is opened with a procedural call which specifies which column of the main DBGrid should be filtered.
So it closes the local SQLQuery, changes the select to the required column and opens it again. It also makes sure that a seperate Bookmarklist is used (I have an array of bookmarks corresponding to the column index).
The problem appears to be in the closing of the SQLQuery whcih I think calls TBookmarkList.Clear somewhere along the line, but can't see where.
Can anyone take this a further as I've about exhausted my knowledge of what is going on, I'm not clear how Bookmarks work.
I do have a work around and that is to have a separate Bookmarklist AND SQLQuery for each column that might be filtered, but I'd like to get some answer on this problem just for knowledge.
Thanks
Dave