Possible bug with WideMemo command parameters

We’ve been trying to track down a problem and have come across what looks like a bug.
We’re using DA 9.4.109.1375 on Delphi 10.2.3 Enterprise, against an MSSQL database using FireDAC.

The problem occurs where we have table columns of type nvarchar(max). We create a command in the schema to retrieve values from such columns via an out parameter, which is set to a type of WideMemo, which should be the correct type for such columns.

Depending on exactly what data is in these columns, we are seeing erratic behaviour. Sometimes it works fine, sometimes the resulting text is truncated, sometimes corrupted and sometimes the whole app just locks up and times out.

I’ve managed to reproduce this and am attaching a small example which illustrates the problem. There’s an SQL script in there which will create the simple test database with a single table with one record in it, containing some random text taken from a licence agreement.

The client app calls a service function on the server which executes a schema command to retrieve the data from two columns. Simply running both server and client and clicking the button causes the whole thing to completely lock up when I test it here.

We’ve tried it with other large blocks of text and sometimes it truncates, sometimes corrupts, sometimes repeated clicking will return increasingly random snippets of text. It’s all very bizarre.

Can you try this yourself and see what you find? Thanks.
WideMemoTest.rar (26.1 KB)

Hi,

open FireDAC.Stan.Util.pas at 998 line and set breakpoint at that line:

function TFDBuffer.Extend(ASrcDataLen: LongWord;
  var ADestDataLen: LongWord; ASrcType, ADestType: TFDDataType): Pointer;
..
  Result := Check(uiLen); //<<< here
end;

launch server under debugger and press button on client. after debugger will stop at this line, Press F7 few times until you will here:

function TFDBuffer.Check(ALen: LongWord = 0): Pointer;
...
    ReallocMem(FOrigBuffer, FBufferSize); //<<<< here

after pressing F8, you will see

---------------------------
Debugger Exception Notification
---------------------------
Project WideMemoTestServer.exe raised exception class $C0000005 with message 'access violation at 0x00405863: write of address 0x00630069'.
---------------------------
Break   Continue   Help   
---------------------------

call-stack will be

:00405863 System::RemoveMediumFreeBlock(APMediumFreeBlock=????)
System.RemoveMediumFreeBlock(???)
System.SysReallocMem(???,???)
:0a746365

after pressing F7:

FireDAC.Phys.ODBCBase.TFDPhysODBCCommand.InternalExecute(???,???,0)
FireDAC.Phys.Process_HandleSystemFailure(1,0,-1,False)
FireDAC.Phys.Process_SingleRow
FireDAC.Phys.TFDPhysCommand.ExecuteBase(1,0)
FireDAC.Phys.TFDPhysCommandAsyncExecute.Execute
FireDAC.Stan.Async.TFDStanAsyncExecutor.ExecuteOperation(False)
FireDAC.Stan.Async.TFDStanAsyncExecutor.Run
FireDAC.Phys.TFDPhysCommand.ExecuteTask(TFDPhysCommandAsyncExecute($4A1F4F0) as IFDStanAsyncOperation,TFDCommand($517CD40) as IFDStanAsyncHandler,False)
FireDAC.Phys.TFDPhysCommand.Execute(???,???,False)
FireDAC.Comp.Client.TFDCustomCommand.InternalExecute(0,0,False)
FireDAC.Comp.Client.TFDCustomCommand.Execute(0,0,False)
FireDAC.Comp.Client.TFDAdaptedDataSet.DoExecuteSource(0,0)
FireDAC.Comp.DataSet.TFDDataSet.Execute(0,0)
FireDAC.Comp.Client.TFDCustomQuery.ExecSQL
uDAFireDACDriver.TDAEFireDACQuery.DoExecute

so something is wrong in FireDAC itself.

I think, it can be reproduced with pure Delphi w/o DA too.

Thanks for the debugging. If it is a bug in FireDAC then I’m not sure where I go from here.

Hi,

try to replace Part_GetPartcodeDescription command with usual select - this issue can disappear.

Do you mean this is only related to commands and not general datatable access?

Surely, under the hood, both are just issuing SELECT statements via FireDAC?

Hi,

Yep. usual select works as expected:

Ok at least that reduces the scope of the problem within our application but isn’t the difference between a database and command only at the DA level? Don’t they both issue the same type of SELECT to the FireDAC driver? The command is using a SELECT statement after all.

for Execute (i.e. command), FireDAC calls TFDPhysODBCCommand.GetParamValues that finally causes

---------------------------
Debugger Exception Notification
---------------------------
Project WideMemoTestServer.exe raised exception class $C0000005 with message 'access violation at 0x00405863: write of address 0x00630069'.
---------------------------
Break   Continue   Help   
---------------------------

for Open (i.e. select), above method doesn’t fired.

that is “all” difference

Ok thanks. The problem only seems to occur with nvarchar(max) columns & widememo parameters so I’ll focus on instances of those

I think, you can create a simple testcase w/o DA and log this issue on their Quality Central for fixing this case in future versions of Delphi.

I’ve never used FireDAC directly so wouldn’t know where to start but I’ll have a look into it.

try to use code like

procedure TServerForm.Button2Click(Sender: TObject);
var
  c: TFDConnection;
  q : TFDQuery;
begin
  c := TFDConnection.Create(nil);

  c.Params.Add('Server=WKS1');
  c.Params.Add('OSAuthent=Yes');
  c.Params.Add('Database=talk20731');
  c.Params.Add('DriverID=MSSQL');

  q := TFDQuery.Create(nil);
  q.Connection := c;
  try
    q.SQL.Text := 'SELECT :Partcode = Partcode, '+
                  ':Description = Description '+
                  'FROM Part '+
                  'WHERE Id = :ID';
    with q.Params[0] do begin
      DataType := ftWideString;
      Size := 200;
      ParamType := ptOutput;
    end;
    with q.Params[1] do begin
      DataType := ftWideMemo;
      ParamType := ptOutput;
    end;
    q.Params[2].AsInteger :=1;

    q.Command.CommandKind := skExecute;
    q.ExecSQL;
  finally
    q.Free;
    c.Free;
  end;
end;

Thanks