#1 2015-06-09 19:13:50

martin.suer
Member
Registered: 2013-12-15
Posts: 76

Interface based services using TSQLRecord with nested records as param

Hi Arnaud,

I am heavily making use of nested (Delphi-) records in my TSQLRecord descendants as published properties like this:

  TLand = packed record
    LKZ, LandName: RawUTF8;
  end;

  TAdresse = packed record
    Name, Zusatz, Strasse, Plz, Ort: RawUTF8;
    Land: TLand;
  end;
  
  TSQLMandant = class(TSQLRecord)
  private
    FMandantCode: RawUTF8;
    FAdresse: TAdresse;
  published
    property MandantCode: RawUTF8 read FMandantCode write FMandantCode;
    property Adresse: TAdresse read FAdresse write FAdresse;
  end;

I am using Windows8.1 with Delphi XE5 in this case.
Everything worked fine with the ORM Part of the framework.

Once I started to make more and more use of interface based services I came across a weired bug.

I assumed I could pass every TSQLRecord as an out parameter in an interface based service method.
Unfortunately it turns out that this is not true for TSQLRecord datastructures which contain
nested records.

Example interface:

  IServiceMandant = interface(IInvokable)
    ['{C1108544-FB6C-4582-A947-C9E3844C3CB6}']
    procedure GetMandant(MandantID: RawUTF8; out Mandant: TSQLMandant);
  end;

After some time of debugging I have found the following issue:

The remote method is executed correctly, the result is correctly serialized to JSON and passed back to the client which starts
to deserialize the result to the TSQLRecord-Object. At some Point the
method JSONToObject in mORMot.pas calls RecordLoadJSON in line 40562.

RecordLoadJSON in SynCommons.pas itself calls Reader:

    JSON := Reader(JSON,Rec,wasValid);
    if not wasValid then
      exit;
    if (JSON<>nil) and (JSON^<>#0) then begin
      EndOfObj := JSON^;
      inc(JSON);
    end else
      EndOfObj := #0;

The Reader already has moved the JSON pointer after the last character of the JSON-record-content at this point
but now the inc(JSON) moves it an additional character forward.

In my case the closing '}' of the TSQLRecord which contained the nested (Delphi-) record was skipped.

In Line 40687 in JSONToObject of mORMot.pas the EndOfObject Pointer is checked...

Valid := (EndOfObject='}');

That then leads to a false Valid flag which later causes the method InternalProcess to raise an exception in line 44663ff

            R := JSONToObject(V^,R,valid);
            if not valid then
              RaiseError('returned object',[]);

When I uncomment the inc(JSON) in RecordLoadJSON in SynCommons.pas I mentioned earlier, my TSQLRecord Objects which contain nested records can also
successfully be used as parameters in interface based service methods.

I don't know if this really is a valid fix for all situations or has any unwanted sideeffects where the inc(JSON) must be there and the issue
must be fixed somehow differently.

Offline

#2 2015-06-09 19:17:43

martin.suer
Member
Registered: 2013-12-15
Posts: 76

Re: Interface based services using TSQLRecord with nested records as param

Line numbers match:    [b4a222bad7] {1446}

Offline

#3 2015-06-10 14:33:22

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

Re: Interface based services using TSQLRecord with nested records as param

Offline

#4 2015-06-10 15:09:26

martin.suer
Member
Registered: 2013-12-15
Posts: 76

Re: Interface based services using TSQLRecord with nested records as param

have tested my app with that branch and it does work for me

Offline

#5 2015-06-10 15:12:02

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

Re: Interface based services using TSQLRecord with nested records as param

I suspect fixing at ObjectToJSON() level is the way to go.

Thanks for your feedback!

Offline

#6 2015-06-10 15:18:04

martin.suer
Member
Registered: 2013-12-15
Posts: 76

Re: Interface based services using TSQLRecord with nested records as param

you mean at JSONToObject() level I guess... wink

Offline

#7 2015-06-10 15:20:03

martin.suer
Member
Registered: 2013-12-15
Posts: 76

Re: Interface based services using TSQLRecord with nested records as param

btw. thanks for all the efforts you put in this great framework

Offline

#8 2015-06-10 15:53:53

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

Re: Interface based services using TSQLRecord with nested records as param

Thanks!

cool

Offline

Board footer

Powered by FluxBB