You are not logged in.
Pages: 1
Thank you so much—everything is working fine now.
You're right. Thanks for the suggestion—I'm going to modify the program now.
A naming conflict between the `TThreadList` in the latest version of `mormot.core.threads.pas` and FPC's `TThreadList` is causing the project compilation to fail.
Great, the error has indeed disappeared now.
[dcc32 Error] mormot.net.sock.windows.inc(552): E2441 Inline function declared in interface section must not use local symbol 'PSockAddr'
[dcc32 Fatal Error] mormot.net.sock.pas(4163): F2084 Internal Error: D13574My backend service program is using the latest FPC trunk, but my front end is an old project and can only use Delphi 2007. Therefore, we can only hope to use DynArraySaveJsonBase64 in the backend and DynArrayLoadJsonBase64 in the front end.
The problem has been identified. In the above code, simply change "s" to "s := '{"code":200,"orders":["AAACAAAAAAEAAAABAAAAAQAAAAIAAAA="]}';" and there will be no issues. That Base64 string is the binary Base64 encoding of the "orders" array.
It would be much more convenient if the functions DynArraySaveJsonBase64 and DynArrayLoadJsonBase64 could be provided, just like the existing RecordSaveBase64/RecordLoadBase64 functions.
TOrder = record
id: Integer;
amount: Integer;
end;
TOrders = array of TOrder;
s := '{"code":200,"orders":[{"id":1,"amount":1},{"id":2,"amount":2}]}';
V := _Json(s);
DynArrayLoadJson(orders, VariantSaveJson(V.orders), TypeInfo(TOrders));
WriteLn(Length(orders));The code above results in Length(orders)==0 in Delphi 2007, but 2 in Delphi 12 and Lazarus.
I remember it working fine before, but now it suddenly stops working. Even reverting to an older version of the mormot2 repository doesn't work anymore. It's really strange.
Additionally, in Lazarus, VariantSaveJson must be added before V.orders in the DynArrayLoadJson statement above, but not in Delphi.
I understand. Thumbs up!
Could not compile used unit 'mormot.core.unicode.pas' at commit 671855 in delphi 2007 and 12.
[dcc32 Error] mormot.core.unicode.pas(9263): E2250 There is no overloaded version of 'UnCamelCase' that can be called with these arguments
[dcc32 Fatal Error] mormot.net.client.pas(1081): F2063 Could not compile used unit 'mormot.core.unicode.pas'Compiled successfully in Lazarus 4.99 (rev main_4_99-3381-g9ac18157ff) FPC 3.3.1 i386-win32-win32/win64.
Addition:
Compiled successfully at commit 8ef39ea5494e137cae69fe6cee309317f4d5122f in delphi 2007 and 12.
Again:
Compile error at commit a4df3929145701d11cb35bcb8ed3abf27b9c4874 in delphi 2007 and 12.
[dcc32 Error] mormot.core.unicode.pas(9284): E2250 There is no overloaded version of 'UnCamelCase' that can be called with these arguments
[dcc32 Error] mormot.core.unicode.pas(9295): E2250 There is no overloaded version of 'UnCamelCase' that can be called with these arguments
[dcc32 Error] mormot.core.unicode.pas(9297): E2010 Incompatible types: 'PUtf8Char' and 'PAnsiChar'
[dcc32 Error] mormot.core.unicode.pas(9304): E2010 Incompatible types: 'PUtf8Char' and 'PAnsiChar'
[dcc32 Fatal Error] mormot.net.client.pas(1081): F2063 Could not compile used unit 'mormot.core.unicode.pas'Finally:
Compiled successfully at commit 90bf2eb9826e62630e203c643ef6c264db6950c0 in delphi 2007 and 12 and Lazarus.
Compile package mormot2 2.4: Exit code 1, Errors: 5
mormot.net.server.pas(2760,5) Error: Identifier not found "delay"
mormot.net.server.pas(2767,28) Error: Identifier not found "delay"
mormot.net.server.pas(2777,10) Error: Identifier not found "delay"
mormot.net.server.pas(2778,13) Error: Identifier not found "delay"
mormot.net.server.pas(2778,20) Error: Identifier not found "delay"Thank you for your guidance. Everything works fine now when the above record is changed to class.
The following code.
type
{$RTTI EXPLICIT PROPERTIES([vcPublished]) FIELDS([vcPublic]) METHODS([])}
TReq = packed record
id: Cardinal;
desc: UTF8String;
amount: Double;
memo: UTF8String;
end;
{$RTTI EXPLICIT METHODS([]) FIELDS([]) PROPERTIES([])}
var
req: TReq;
s: UTF8String;
begin
with req do begin
id := 1000;
desc := 'test';
end;
SaveJson(req, TypeInfo(TReq), TEXTWRITEROPTIONS_SETASTEXT[False], s, [woDontStoreVoid]);
WriteLn(s);
end.The output is
{"id":1000,"desc":"test","amount":0,"memo":""}instead of
{"id":1000,"desc":"test"}I'm using the latest trunk.
Ok. Thank you very much. I'll give it a try.
rec.Prefix := 'M'; // "char"
rec.Flag := '2'; // char(1)
rec.Start := Time;
rec.Stop := IncMinute(Time, 15);
Rest.Add(rec, True); // <-- not workRest.Add(rec, True) not work.
ESqlDBException {Message:"Invalid TSqlDBPostgresStatement.Bind(2,TSqlDBFieldType(0),77)"
or
ESqlDBPostgres {Message:"TSqlDBPostgresLib Exec failed: 22001 [ERROR: value too long for type character(1)
Does ORM not support postgresql's "char" and char(1)?
TDateTime is Ok.
WriteLn(DateTimeToStr(rec.Start), ' ', DateTimeToStr(rec.Stop));
Output: 1899-12-30 8:30:00 1899-12-30 14:30:00
Time is Ok.
Yes, I try with the latest trunk.
ORM has errors in both the "char" and char(1) columns.
ESqlDBException {Message:"Invalid TSqlDBPostgresStatement.Bind(2,TSqlDBFieldType(0),77)"
or
ESqlDBPostgres {Message:"TSqlDBPostgresLib Exec failed: 22001 [ERROR: value too long for type character(1)
Create the following table.
create table if not exists testtbl (
id int4,
prefix "char",
flag char(1),
start time not null default '08:30:00',
stop time not null default '14:30:00');
insert into testtbl (id, prefix, flag, start, stop) values (1, 'P', '1', '08:30:00', '14:30:00'); Define the following ORM.
TOrmtesttbl = class(TOrm)
private
fPrefix: AnsiChar;
fFlag: AnsiChar;
fStart: TTime;
fStop: TTime;
published
property Prefix: AnsiChar read fPrefix write fPrefix;
property Flag: AnsiChar read fFlag write fFlag;
property Start: TTime read fStart write fStart;
property Stop: TTime read fStop write fStop;
end; The following program has an incorrect running result.
DBProps := TSQLDBPostgresConnectionProperties.Create(
'localhost', 'testdb', 'root', 'pass');
DBProps.ThreadSafeConnection.Connect;
Model := TOrmModel.Create([TOrmtesttbl]);
OrmMapExternal(Model, [TOrmtesttbl], DBProps);
Rest := TRestServerDB.Create(Model);
Rest.Model.Owner := Rest;
Rest.Server.CreateMissingTables;
rec := Tormtesttbl.Create;
if Rest.Retrieve(1, rec) then begin
WriteLn('Prefix: ', rec.Prefix); // print P <-- ok
WriteLn('Flag: ', rec.Flag); // print 1 <-- ok
WriteLn(rec.Start, ' ', rec.Stop); // print 0.0000000000000000E+000 0.0000000000000000E+000 <-- error
end;
rec.Prefix := 'M';
rec.Flag := '2';
rec.Start := Time;
rec.Stop := IncMinute(Time, 15);
Rest.Add(rec, True); // <-- ESqlDBException {Message:"Invalid TSqlDBPostgresStatement.Bind(2,TSqlDBFieldType(0),77)" I found that root can be set to the following form and still work without using routing.
Server := TMyServer.Create('myroot/v1');server output
--- myapi ---
url: myapp/v1/myapi?q=abc&v=123&session_signature=000f36e000014ac1e3a96b48
method: mGET
Parameters: q=abc&v=123&session_signature=000f36e000014ac1e3a96b48
body:{"req": "hello"}URI authentication is also not applicable to the following routes.
HttpServer.Route.Run([urmGet, urmPost], '/app/api', Server.domyapi);URI authentication currently does not work with routing.
If you want to use URI authentication, you cannot use routing.
Ok, sorry, I just saw the forum rules 2 and 7. The post has been edited.
Compile and execute the following program.
client.pas and server.pas
Run the server and client, and the output is as follows:
# client
--- no routed ---
test GET method
r: 200
resp: {"code": 0}
test POST method
r: 200
resp: {"code": 0}
--- routed ---
test GET method
r: 403
resp: {
"errorCode":403,
"errorText":"URI Authentication Failed: Invalid signature (0)"
}
test POST method
r: 403
resp: {
"errorCode":403,
"errorText":"URI Authentication Failed: Invalid signature (0)"
}Great, it was solved so quickly, it works now.
Compile and execute the following program.
// e:\delphi12\bin\dcc32 servertest.pas -ID:\Borland\mORMot2\src -Ud:\Borland\mORMot2\src\core;d:\Borland\mORMot2\src\crypt;d:\Borland\mORMot2\src\db;d:\Borland\mORMot2\src\lib;d:\Borland\mORMot2\src\orm;d:\Borland\mORMot2\src\net;d:\Borland\mORMot2\src\soa;D:\Borland\mORMot2\src\rest -NSSystem;Winapi
program servertest;
{$apptype console}
{$I mormot.defines.inc}
uses
{$I mormot.uses.inc} // use FastMM4 on older versions of Delphi
Windows,
sysutils,
classes,
mormot.core.base,
mormot.core.log,
mormot.core.os,
mormot.core.rtti,
mormot.core.text,
mormot.net.http,
mormot.net.server,
mormot.rest.server,
mormot.rest.memserver,
mormot.rest.http.server;
type
TMyServer = class(TRestServerFullMemory)
public
constructor Create(const pmcRootName: RawUtf8); reintroduce;
published
procedure myapi(Ctxt: TRestServerUriContext);
end;
constructor TMyServer.Create(const pmcRootName: RawUtf8);
begin
CreateWithOwnModel([], FALSE, pmcRootName);
Server.CreateMissingTables;
end;
procedure TMyServer.myapi(Ctxt: TRestServerUriContext);
begin
Writeln('--- myapi ---');
WriteLn('1:', Ctxt.Call.Url);
WriteLn('2: Parameters: ', Ctxt.Parameters);
Ctxt.Returns('{"code": 0}', HTTP_SUCCESS, JSON_CONTENT_TYPE_HEADER_VAR);
end;
const
MYROOT = 'myapp';
procedure Run;
var
HttpServer: TRestHttpServer;
Server: TMyServer;
begin
Server := TMyServer.Create(MYROOT);
try
HttpServer := TRestHttpServer.Create('8888', [Server], '+', useHttpAsync);
try
HttpServer.Route.Get('/app/api', MYROOT + '/myapi');
HttpServer.AccessControlAllowOrigin := '*';
ConsoleWrite('Press [Enter] to quit'#13#10);
ConsoleWaitForEnterKey;
finally
HttpServer.Free;
end;
finally
Server.Free;
end;
end;
begin
with TSynlog.Family do
begin
Level := LOG_VERBOSE;
EchoToConsole := LOG_NFO + [sllDebug,sllDB,sllHTTP];
PerThreadLog := ptIdentifiedInOnFile;
NoFile := True;
end;
try
Run;
except
on E: Exception do
ConsoleShowFatalException(E);
end;
FreeConsole;
end.The results are as follows.
# servertest.exe
......
Press [Enter] to quit
--- myapi ---
1:myapp/myapi <--- routing: curl http://127.0.0.1:8888/app/api?q=abc
2: Parameters:
20251017 10372819 5 srvr mormot.rest.server.TRestServerRoutingRest(035f6390) Method GET myapi=200 out=11 in 940us
--- myapi ---
1:myapp/myapi?q=abc <--- no routing: curl http://127.0.0.1:8888/myapp/myapi?q=abc
2: Parameters: q=abc
20251017 10373228 - srvr mormot.rest.server.TRestServerRoutingRest(035f6390) Method GET myapi=200 out=11 in 1.88msGreat! Everything has been solved. There's no problem with either FPC or Delphi
The results are as follows.
# dbtest
1: 08:30:00-14:30:00 <-- ok
2: 0.35, 0.60 <-- ok
3: 8:30:00-14:30:00 <-- okThank you for your reply.
Is there any solution for R.start and R.stop.
Compile and execute the following program.
e:\delphi12\bin\dcc32 dbtest.pas -ID:\Borland\mORMot2\src;D:\Borland\mORMot2\static\i386-win32 -Ud:\Borland\mORMot2\src\core;d:\Borland\mORMot2\src\crypt;d:\Borland\mORMot2\src\db;d:\Borland\mORMot2\src\net;D:\Borland\mORMot2\src\lib -NSSystem;Winapi
{
create table if not exists testtbl (
id int4,
start time not null default '08:30:00',
stop time not null default '14:30:00');
insert into testtbl (id, start, stop) values (1, '08:30:00', '14:30:00');
}
program dbtest;
{$ifdef FPC}
{$mode delphi}
{$else}
{$APPTYPE CONSOLE}
{$endif}
{$I mormot.defines.inc}
uses
{$I mormot.uses.inc}
{$IFDEF DCC}System.{$ENDIF}Classes, {$IFDEF DCC}System.{$ENDIF}SysUtils,
Variants,
mormot.db.sql.postgres;
var
DBProps: TSQLDBPostgresConnectionProperties;
R: variant;
startstr, stopstr: String;
start, stop: TTime;
begin
DBProps := TSQLDBPostgresConnectionProperties.Create(
'localhost', 'testdb', 'root', '12345678');
try
DBProps.ThreadSafeConnection.Connect;
with DBProps.Execute('select * from testtbl limit 1',[],@R) do
begin
while Step do begin
startstr := ColumnUTF8('start');
stopstr := ColumnUTF8('stop');
WriteLn('1: ', startstr, '-', stopstr);
start := ColumnDateTime('start');
stop := ColumnDateTime('stop');
WriteLn(Format('2: %f, %f', [start, stop]));
WriteLn('3: ', VarToStr(R.start), '-', VarToStr(R.stop));
break;
end;
ReleaseRows;
end;
except
end;
DBProps.Free;
end.The results are as follows.
# dbtest
1: 08:30:00-14:30:00 <-- ok
2: 0.00, 0.00 <-- error
3: 0:00:00-0:00:00 <-- erroryes, {$modeswitch advancedrecords} is not needed.
After testing, delphi enables rtti record by default, and fpc is off by default.
Replace {$RTTI EXPLICIT PROPERTIES([vcPublished]) FIELDS([]) PROPERTIES([])} with {$RTTI EXPLICIT METHODS([]) FIELDS([vcPublic]) METHODS([])},
project.pas compiled by delphi and the results also failed.
You're amazing. Everything is working on the new mormot2.
project1.pas adds the following statement before TEFloor = packed record.
{$RTTI EXPLICIT
PROPERTIES([vcPublished])
FIELDS([vcPublic])
METHODS([])}Recompile and run, everything is fine.
You were amazing.
Thank you for your quick response and quick repair.
System Information
- Operating system: Windows
- Processor architecture: x86-64
- Device: Computer
- FPC version: 3.3.1 [2024/06/26] for i386, Trunk 0c745fb257
- mORMot2 version: master 70e2e9ce
Example Project
program project1;
{$ifdef FPC}
{$mode delphi}
{$else}
{$APPTYPE CONSOLE}
{$endif}
{$I mormot.defines.inc}
uses
{$I mormot.uses.inc}
{$IFDEF DCC}System.{$ENDIF}Classes, {$IFDEF DCC}System.{$ENDIF}SysUtils,
mormot.core.base,
mormot.core.rtti,
mormot.core.variants,
mormot.core.json;
type
{$RTTI EXPLICIT PROPERTIES([vcPublished]) FIELDS([vcPublic]) METHODS([])}
TEFloor = packed record
el: WORD;
fl: array of Byte;
end;
TECtrl = packed record
ecid: WORD;
expd: array of Byte;
efl: array of TEFloor;
icod: UTF8String;
pt: array of Integer;
adv: BYTE;
end;
TECtrls = Array of TECtrl;
var
tmp1, tmp2: UTf8String;
ec: TECtrls;
begin
tmp1 := '[{"ecid":12,"expd":[80,17,18],"efl":[{"el":0,"fl":[1,2]},{"el":1,"fl":[4,5]}],"icod":"123456","pt":[1,2,3],"adv":5}]';
DynArrayLoadJson(ec, tmp1, TypeInfo(TECtrls));
WriteLn(tmp1);
tmp2 := DynArraySaveJson(ec, TypeInfo(TECtrls));
WriteLn(tmp2);
if tmp1 = tmp2 then WriteLn('ok')
else WriteLn('failed');
end.The above programs are compiled with fpc and run as follows.
# fpc project1.pas -Fic:\mORMot2\src -Fuc:\mORMot2\src\core;c:\mORMot2\src\lib -Flc:\mORMot2\static\i386-win32
Free Pascal Compiler version 3.3.1 [2024/06/26] for i386
Copyright (c) 1993-2024 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling project1.pas
Linking project1.exe
895 lines compiled, 0.3 sec, 563504 bytes code, 20004 bytes data
# project1
[{"ecid":12,"expd":[80,17,18],"efl":[{"el":0,"fl":[1,2]},{"el":1,"fl":[4,5]}],"icod":"123456","pt":[1,2,3],"adv":5}]
[]
failedRelevant 3rd party information
The above program is compiled by delphi and the results are as follows
# dcc32 project1.pas -Ic:\mORMot2\src;c:\mORMot2\static\i386-win32 -Uc:\mORMot2\src\core;c:\mORMot2\src\lib -NSSystem;Winapi
Embarcadero Delphi for Win32 compiler version 36.0
Copyright (c) 1983,2024 Embarcadero Technologies, Inc.
c:\mORMot2\src\mormot.defines.inc(792)
c:\mORMot2\src\mormot.uses.inc(50)
project1.pas(56)
897 lines, 0.11 seconds, 1439256 bytes code, 103032 bytes data.
# project1.exe
[{"ecid":12,"expd":[80,17,18],"efl":[{"el":0,"fl":[1,2]},{"el":1,"fl":[4,5]}],"icod":"123456","pt":[1,2,3],"adv":5}]
[{"ecid":12,"expd":[80,17,18],"efl":[{"el":0,"fl":[1,2]},{"el":1,"fl":[4,5]}],"icod":"123456","pt":[1,2,3],"adv":5}]
okI know that using RegisterType and RegisterFromText can solve this problem,
But the latest FPC has supported RTTI record (https://gitlab.com/freepascal.org/fpc/s … sues/40798)
Just request improvements to mORMot2 DynArrayLoadJson in FPC.
May mORMot2 get better and better!
The latest FPC has supported RTTI record (https://gitlab.com/freepascal.org/fpc/s … sues/40798)
Request improvements to mormot2 DynArrayLoadJson in FPC.
Pages: 1