AV when local order is case insensitive

Discussion of open issues, suggestions and bugs regarding MyDAC (Data Access Components for MySQL) for Delphi, C++Builder, Lazarus (and FPC)
Post Reply
zeltron73
Posts: 20
Joined: Mon 04 Jun 2012 07:46

AV when local order is case insensitive

Post by zeltron73 » Mon 04 Jun 2012 08:15

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.

AndreyZ

Re: AV when local order is case insensitive

Post by AndreyZ » Tue 05 Jun 2012 15:08

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.

zeltron73
Posts: 20
Joined: Mon 04 Jun 2012 07:46

Re: AV when local order is case insensitive

Post by zeltron73 » Wed 06 Jun 2012 07:31

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.
Last edited by zeltron73 on Tue 19 Jun 2012 08:43, edited 2 times in total.

zeltron73
Posts: 20
Joined: Mon 04 Jun 2012 07:46

Re: AV when local order is case insensitive

Post by zeltron73 » Wed 06 Jun 2012 08:55

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.

AndreyZ

Re: AV when local order is case insensitive

Post by AndreyZ » Wed 06 Jun 2012 10:26

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.

AndreyZ

Re: AV when local order is case insensitive

Post by AndreyZ » Wed 13 Jun 2012 09:17

We have fixed the problem. This fix will be included in the next MyDAC build.

Post Reply