#1 2015-02-25 08:38:47

xotox
Member
Registered: 2015-02-07
Posts: 18

Serious bug when passing TRawUTF8DynArray through interfaces?

Hi,
either there's a serious bug when passing TRawUTF8DynArray parameters throug service interfaces, or i'm doing something wrong.

In my interface, I have a function like "function GetData(arr: TRawUTF8DynArray): boolean".

arr contains RawUTF8 values which were encoded using ObjectToJSON(someSQLRecord). When retrieving the array on client-side, the JSON data is broken.
eg. : 

Before sending data arr[0] contains:

{"ID":1,"Title":"Mr.","Name":"Pablo"}

when received, arr[0] contains:

{"ID  1 "Title  "Mr.  "Name  "Pablo  "

What should I do???
Please help!

Edit:
If I pass arr[0] as a simple RawUTF8, it works fine.
How can I pass a list/array of JSON encoded RawUTF8 Strings to the client?

Last edited by xotox (2015-02-25 08:50:32)

Offline

#2 2015-02-25 12:34:31

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: Serious bug when passing TRawUTF8DynArray through interfaces?

Try with GetData(const arr: TRawUTF8DynArray).

Please produce some code to reproduce the issue.

Offline

#3 2015-02-25 13:19:01

xotox
Member
Registered: 2015-02-07
Posts: 18

Re: Serious bug when passing TRawUTF8DynArray through interfaces?

I can not use GetData(const arr: TRawUTF8DynArray), because "arr" is filled by server, then sent to client. Sever has to call SetLength(arr) etc.

I'll provide a demo asap.
Thanks.

Offline

#4 2015-02-25 13:32:42

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 337

Re: Serious bug when passing TRawUTF8DynArray through interfaces?

Maybe you should use GetData(out arr: TRawUTF8DynArray) if the server side fill with data.


Esteban

Offline

#5 2015-02-25 14:09:25

xotox
Member
Registered: 2015-02-07
Posts: 18

Re: Serious bug when passing TRawUTF8DynArray through interfaces?

EMartin wrote:

Maybe you should use GetData(out arr: TRawUTF8DynArray) if the server side fill with data.

Thats exactly how it's implemented right now.

Well I just wrote a test to show the problem, but the Test works as expected!
As far as I can see, the test is doing exactly the same thing my real project does. I'm speechless.

???


Well, here's the Testcode:

program Test;

{$APPTYPE CONSOLE}

uses
  FastMM4,
  SynSQLite3Static,
  SysUtils,
  SynCommons,
  SynSQLite3,
  mORMot,
  mORMotSQLite3,
  mORMotHTTPServer,
  mORMotHTTPClient;

type
  IMyInterface = interface(IInvokable)
  ['{1A664CAB-BD0E-44B3-BB5F-5CAEB425FDB3}']
    procedure GetData(out Arr: TRawUTF8DynArray; out Arr2: TRawUTF8DynArray; out S: RawUTF8);
  end;

  TMyInterface = class(TInterfacedObject, IMyInterface)
  public
    procedure GetData(out Arr: TRawUTF8DynArray; out Arr2: TRawUTF8DynArray; out S: RawUTF8);
  end;

  TSQLRecordBase=class(TSQLRecord)
  private
    fAProp: RawUTF8;
  published
    property AProp: RawUTF8 read fAProp write fAProp;
  end;

  TSQLPerson = class(TSQLRecordbase)
  private
    fFirstname: RawUTF8;
    fLastname: RawUTF8;
  published
    property Firstname: RawUTF8 index 80 read fFirstname write fFirstname;
    property Lastname: RawUTF8 index 80 read fLastname write fLastname;
  end;

  TmyServer = class
  private
    fModel: TSQLModel;
    fRestServer: TSQLRestServerDB;
    fHTTPServer: TSQLHttpServer;
  public
    constructor Create;
    destructor Destroy; override;
  end;

  TmyClient = class
  private
    fHTTPClient: TSQLHttpClient;
    fModel: TSQLModel;
    fmyInterface: ImyInterface;
  public
    constructor Create;
    destructor Destroy; override;
    procedure TestIt;
  end;

function CreateModel: TSQLModel;
begin
  result := TSQLModel.Create([TSQLPerson]);
end;

{ TMyInterface }

procedure TMyInterface.GetData(out Arr: TRawUTF8DynArray; out Arr2: TRawUTF8DynArray; out S: RawUTF8);
const
  count = 10;
var
  i: integer;
  person: TSQLPerson;
begin
  person := TSQLPerson.Create;
  try
    SetLength(Arr, count);
    SetLength(Arr2, count);
    for i:=Low(Arr) to High(Arr) do begin
      person.Firstname := FormatUTF8('Firstname #%', [i]);
      person.Lastname := FormatUTF8('Lastname #%', [i]);
      Arr[i] := ObjectToJSON(person);
      Arr2[i] := ObjectToJSON(person);
    end;
    S := Arr[0];
  finally
    person.Free;
  end;
end;


{ TmyServer }

constructor TmyServer.Create;
begin
  fModel := CreateModel;
  fRestServer := TSQLRestServerDB.Create(fModel, ChangeFileExt(ParamStr(0), '.db'), true);
  with fRestServer do begin
    DB.Synchronous := smNormal;
    DB.LockingMode := lmExclusive;
    CreateMissingTables;
    ServiceRegister(TmyInterface, [TypeInfo(ImyInterface)], sicClientDriven);
  end;
  fHTTPServer := TSQLHttpServer.Create('8080', fRestServer, '+', useHttpApiRegisteringURI);
end;

destructor TmyServer.Destroy;
begin
  fHTTPServer.Free;
  fRestServer.Free;
  fModel.Free;
end;

{ TmyClient }

constructor TmyClient.Create;
begin
  fModel := CreateModel;
  fHTTPClient := TSQLHttpClient.Create('127.0.0.1', '8080', fModel);
  fHTTPClient.SetUser('Admin', 'synopse');
  fHTTPClient.ServiceRegisterClientDriven(TypeInfo(ImyInterface), fmyInterface);
end;

destructor TmyClient.Destroy;
begin
  fmyInterface := nil;
  fHttpClient.Free;
  fModel.Free;
end;

procedure TmyClient.TestIt;
var
  arr, arr2: TRawUTF8DynArray;
  s: RawUTF8;
  //person: TSQLPerson;
  i: integer;
begin
  fmyInterface.GetData(arr, arr2, s);
  writeln(Format('Length(arr): %d', [Length(arr)]));
  if (s=arr[0]) then
    writeln(s=arr[0])
  else begin
    writeln(s);
    writeln(arr[0]);
  end;
  for i:=Low(arr) to high(arr) do
    writeln(arr[i]);
  for i:=Low(arr2) to high(arr2) do
    writeln(arr2[i]);
end;

var
  myServer: TmyServer;
  myClient: TmyClient;

begin
  myServer := TmyServer.Create;
  myClient := TmyClient.Create;
  try
    myClient.TestIt;
    readln;
  finally
    myClient.Free;
    myServer.Free;
  end;
end.

Last edited by xotox (2015-02-25 14:10:56)

Offline

#6 2015-02-25 14:17:49

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 337

Re: Serious bug when passing TRawUTF8DynArray through interfaces?

xotox wrote:

In my interface, I have a function like "function GetData(arr: TRawUTF8DynArray): boolean".

In the "arr" parameter is not defined any type, neither const, neither var or out.


Esteban

Offline

#7 2015-02-25 14:53:40

xotox
Member
Registered: 2015-02-07
Posts: 18

Re: Serious bug when passing TRawUTF8DynArray through interfaces?

Ok guys, sorry for making trouble! The problem was sitting in front of the Monitor smile

In a quite deeply nested procedure inside the client was a code like:

for x:=Low(a1) to High(a1) do pers.FillFrom(Pointer(a1[x]));  

instead of:

  for x:=Low(a1) to High(a1) do pers.FillFrom(a1[x]);

Using Pointer(a1[x]) in FillPrepare changes the TRawUTF8DynArray content to:

{"ID  0 "Firstname  "Firstname 0  "Lastname  "Firstname 0
{"ID  0 "Firstname  "Firstname 1  "Lastname  "Firstname 1
{"ID  0 "Firstname  "Firstname 2  "Lastname  "Firstname 2
{"ID  0 "Firstname  "Firstname 3  "Lastname  "Firstname 3
{"ID  0 "Firstname  "Firstname 4  "Lastname  "Firstname 4
{"ID  0 "Firstname  "Firstname 5  "Lastname  "Firstname 5
{"ID  0 "Firstname  "Firstname 6  "Lastname  "Firstname 6
{"ID  0 "Firstname  "Firstname 7  "Lastname  "Firstname 7
{"ID  0 "Firstname  "Firstname 8  "Lastname  "Firstname 8
{"ID  0 "Firstname  "Firstname 9  "Lastname  "Firstname 9

Thats's it.
But thanks for your help!!!

Offline

#8 2015-02-25 18:42:17

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: Serious bug when passing TRawUTF8DynArray through interfaces?

;-)

Offline

Board footer

Powered by FluxBB