Page 1 of 1
AV when local order is case insensitive
Posted: Mon 04 Jun 2012 08:15
by zeltron73
Hello,
I use MyDAC 7.1.6 with source code under Windows 7 and Delphi 5.
When I set .IndexFieldNames using case insensitive order, I get an Assertion exception (MemData.pas line 2666) or an Access Violation in dac50.bpl when I retrieve data. If I use case sensitive, the exception disappears... It is difficult to reproduce the problem, because the exception is the result of heap corruption (the content of a TFieldDesc object is corrupted) and appears randomly.
I noticed that you must set Connection.Options.DefaultSortType := stCaseInsensitive after connection has been established, if not, SortColumn.SortType will always be stCaseSensitive...
Has anybody the same problem ?
Thanks for your help.
Re: AV when local order is case insensitive
Posted: Tue 05 Jun 2012 15:08
by AndreyZ
Hello,
I cannot reproduce the problem. Please try creating a small sample to demonstrate the problem and send it to me, including a script to create and fill a table. Also please specify the exact version of MySQL server and client. You can learn it from the Info sheet of TMyConnection Editor.
Re: AV when local order is case insensitive
Posted: Wed 06 Jun 2012 07:31
by zeltron73
Hello Andrey,
I have found the cause of the error which is very odd indeed and drives me crazy since a couple of days... And here is the code to reproduce it.
Create a new project and add a TMyConnection and a TMyQuery component on the form; add a button and copy the code below in the OnClick event handler :
Code: Select all
procedure TForm1.Button1Click(Sender: TObject);
begin
Connection.Options.Charset := 'latin1';
Connection.Connect;
// if you comment the next line, the AV disappears
Connection.Options.DefaultSortType := stCaseInsensitive;
Query.SQL.Text := 'SELECT * FROM (' +
'(SELECT 1 AS Field1, "BBB" AS Field2) UNION ' +
'(SELECT 2, "AAA")) t ' +
'WHERE &Condition';
Query.MacroByName('Condition').Value := 'TRUE';
Query.IndexFieldNames := 'Field2';
Query.Open;
Query.LocateEx('Field2', 'AAA', [lxCaseInsensitive]);
Query.RecNo := 2;
Query.MacroByName('Condition').Value := 'Field1 > 0';
Query.IndexFieldNames := '';
Query.Open;
Query.RecNo := 2; // raise an Access Violation exception
end;
Explanation: when the second "Query.MacroByName('Condition').Value" is called, the dataset will be closed, which calls TMemData.FreeData. But TMemData.FRecordNoCache continues to reference items that have just been released.
To correct the bug, I suggest to add the following line in the TMemData.InitData method just after BlockMan.FirstFree:
SetLength(FRecordNoCache, 0); // to clear the cache
I discover another dysfunction, the .Options.DefaultSortType is only taken into account only if the connection is opened (idem for DisconnectedMode, EnableBCD, EnableFmtBCD). Why these options are not set when the connection is opened ?
Regards.
Re: AV when local order is case insensitive
Posted: Wed 06 Jun 2012 08:55
by zeltron73
If the exception didn't appear, add this unit at the first place in the "uses" of your .dpr file
Code: Select all
unit MemMgr;
interface
implementation
uses
Windows;
{ Memory Management }
const
HEAP_MAX_SIZE = $100000;
HEAP_GENERATE_EXCEPTIONS = $00000004;
HEAP_NO_SERIALIZE = $00000001;
HEAP_ZERO_MEMORY = $00000008;
var
PrivateHeap: THandle;
SavedMemoryManager: TMemoryManager;
function InternalGetMem(Size: Integer): Pointer;
begin
Result := HeapAlloc(PrivateHeap, HEAP_GENERATE_EXCEPTIONS or HEAP_NO_SERIALIZE or HEAP_ZERO_MEMORY, Size);
end;
function InternalFreeMem(P: Pointer): Integer;
begin
Result := Integer(not HeapFree(PrivateHeap, HEAP_NO_SERIALIZE, P))
end;
function InternalReallocMem(P: Pointer; Size: Integer): Pointer;
begin
Result := HeapReAlloc(PrivateHeap, HEAP_GENERATE_EXCEPTIONS or HEAP_NO_SERIALIZE or HEAP_ZERO_MEMORY, P, Size)
end;
const
MemoryManager: TMemoryManager = (
GetMem: InternalGetMem;
FreeMem: InternalFreeMem;
ReallocMem: InternalReallocMem
);
initialization
PrivateHeap := HeapCreate(HEAP_GENERATE_EXCEPTIONS or HEAP_NO_SERIALIZE, 0, HEAP_MAX_SIZE);
GetMemoryManager(SavedMemoryManager);
SetMemoryManager(MemoryManager);
finalization
HeapDestroy(PrivateHeap);
SetMemoryManager(SavedMemoryManager);
end.
and the following code will raise the AV...
Code: Select all
procedure TForm1.Button1Click(Sender: TObject);
begin
Connection.Options.Charset := 'latin1';
Connection.Connect;
Connection.Options.DefaultSortType := stCaseInsensitive;
Query.SQL.Text := 'SELECT * FROM (' +
'(SELECT 1 AS Field1, "BBB" AS Field2) UNION ' +
'(SELECT 2, "AAA")) t ' +
'WHERE &Condition';
Query.MacroByName('Condition').Value := 'TRUE';
Query.IndexFieldNames := 'Field2';
Query.Open;
Query.LocateEx('Field2', 'AAA', [lxCaseInsensitive]);
Query.RecNo := 2;
Query.MacroByName('Condition').Value := 'Field1 > 0';
StringOfChar(' ', 4096); // to use the heap
Query.IndexFieldNames := '';
StringOfChar(' ', 4096);
Query.Open;
StringOfChar(' ', 4096);
Query.RecNo := 2;
end;
Regards.
Re: AV when local order is case insensitive
Posted: Wed 06 Jun 2012 10:26
by AndreyZ
Thank you for the information. We have fixed the problem with setting the DefaultSortType property. This fix will be included in the next MyDAC build.
We have reproduced the problem with AV and the investigation is in progress. We will notify you when we get any results.
Re: AV when local order is case insensitive
Posted: Wed 13 Jun 2012 09:17
by AndreyZ
We have fixed the problem. This fix will be included in the next MyDAC build.