You are not logged in.
I have now installed a new version of fpc and lazarus following your instructions.
And now the testSQLite3 and my testapp works as it should.
Easy solved but hard to find ![]()
I got the same revision.. very strange when you can't reproduce it. Can it be something with Lazarus?
Free Pascal Compiler version 3.3.1-r41736 [2019/03/19] for x86_64An immedite answer here, I'm just try to debug the "TestSQL3" app. It fails with access violation and it seems to be in the same code part as in my app.
What's common is that when a call result in a cqrsStatus <> cqrsSuccess and it tries to create the JSON formatted response it crasches.
It is very hard for me to understand what's really happends here and I've been trying to find out by debugging. So far I have not find it.
It should be simple though to reproduce it by running TestSQL3 with the same FPC-compiler 3.3.1 as I use.
The first test that fails is this:
Check(service.StartEmailValidation(template,'toto','toto@toto .com')=cqrsDDDValidationFailed);This test is made to give an error status and that causes the crasch.
Is it enough to put the code into paste.bin, all code in one file or...?
Ok,
I'm using a Lazarus installation, installed by using fpcupDeluxe choosing the trunk version and got fpc-3.3.1 and Lazarus-2.1.0. I included mORMot in the installation.
I also installed ZEOS (7.2.4-stable build at 2018-03-25 11:08:27).
I also installed the latest WAMP-server to get MySQL together with a convenient environment.
To test that I could use MySQL and ZEOS in future programming I created a simple simple application to test all this.
First I had both server and client in the same application but later I splited it into one client and one server application but the result is the same.
It has no problem adding new records in the database table and it can also read them back without any problem. But,
if I want to read them all by using the function "ORMGetNextAggregate" I get all records delivered but at the end, when this function tries to read beyond the last record,
it gets the cqrsStatuscode=cqrsSuccessWithMoreData. So far so good but then it tries to create the JSON-message to be sent back to the client it goes wrong.
It looks like it doesn't know when to stop the process so it goes to far and get garbage data.
The "PPropInfo^PropType^.Kind the point outside it's buffer and returns a value to the TTextKind variable Kind that is outside its definition.
Maybe it can be in the function listed below:
function InternalClassProp(ClassType: TClass): PClassProp;
{$ifdef FPC}
begin
with GetFPCTypeData(pointer(ClassType.ClassInfo))^ do
result := AlignToPtr(@UnitName[ord(UnitName[0])+1]);
{$else}
{$ifdef PUREPASCAL}
var PTI: PTypeInfo;
begin // code is a bit abstract, but compiles very well
PTI := PPointer(PtrInt(ClassType)+vmtTypeInfo)^;
if PTI<>nil then // avoid GPF if no RTTI available for this class
with PTI^, PClassType(@Name[ord(Name[0])+1])^ do
result := PClassProp(@UnitName[ord(UnitName[0])+1]) else
result := nil;
{$else}
asm // this code is the fastest possible
mov eax, [eax + vmtTypeInfo]
test eax, eax
jz @z // avoid GPF if no RTTI available for this class
movzx edx, byte ptr[eax].TTypeInfo.Name
lea eax, [eax + edx].TTypeInfo.Name[1]
movzx edx, byte ptr[eax].TClassType.UnitName
lea eax, [eax + edx].TClassType.UnitName[1].TClassProp
@z:
{$endif PUREPASCAL}
{$endif FPC}
end;The delphi version returns NIL when it don't find the classtype but the fpc version just returns the result from: AlignToPtr(@UnitName[ord(UnitName[0])+1]);
I failed to check what this function ( or isn't it a function?) returns.
I'm totally stuck here and if I don't solve this soon, there is nothing more than to leave this project I'm afraid.
I have struggled for days trying to solve this but now I understand I can't get any further without help. ![]()
Still not solved, I've no idea how to proceed.. Help needed.
Here it crashes: https://pastebin.com/0fxPPnEB
I found the missing part myself. I had to put all tables in the "VirtualTableExternalRegister" procedure.
I was fooled by the fact that you didn't need to put these tables (TSQLAuthUser, TSQLAuthGroup) into the model as do that automatically in the background, so I never thought about putting these tables into the VirtualTableExternalRegister procedure.
VirtualTableExternalRegister(Model, [TTicket, TSQLAuthUser, TSQLAuthGroup], Props);As simple as this:
TDTOTicket = class(TSQLRecord)
protected
fticketNo: integer; // TTicketNo
fdescription: RawUTF8; // TDescription
fdateCreated: TDateTime; // TDateTime
fdateOpened: TDateTime; // TDateTime
fdateSolved: TDateTime; // TDateTime
published
/// maps TTicket.ticketNo (TTicketNo)
property ticketNo: integer read fticketNo write fticketNo;
/// maps TTicket.description (TDescription)
property description: RawUTF8 read fdescription write fdescription;
/// maps TTicket.dateCreated
property dateCreated: TDateTime read fdateCreated write fdateCreated;
/// maps TTicket.dateOpened
property dateOpened: TDateTime read fdateOpened write fdateOpened;
/// maps TTicket.dateSolved
property dateSolved: TDateTime read fdateSolved write fdateSolved;
end;The server is running in the same program as the client, to simplify testing.
The server looks like this:
constructor TTicketServer.create(const aObserver: IErrorObserver);
begin
DBConnect(rseZeosMySQL, 'zdbc:mysql://localhost:3306', 'test_mormot', 'root', 'gT7Wqa96S');
Model := CreateTicketModel;
VirtualTableExternalRegister(Model, [TTicket], Props);
DBServer := TSQLRestServerDB.Create(Model, true); // true -> Authorization used
try
DBServer.CreateMissingTables;
DBServer.ServiceContainer.InjectResolver([TInfraRepoTicketFactory.create(DBServer)], false);
DBServer.ServiceDefine(TInfraRepoTicket, [IDomTicketCommand], sicClientDriven);
httpServer := TSQLHttpServer.Create(PORT_NAME, [DBServer], '+', HTTP_DEFAULT_MODE);
try
httpServer.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
CodeHalted := true;
while CodeHalted do begin
Application.ProcessMessages;
sleep(1000);
end;
finally
httpServer.Free;
end;
finally
DBServer.Free;
end;
end;TTicket is defined as:
TTicket = class(TSQLRecord)
private
fTicketNo: TTicketNo;
fDescription : TDescription;
fDateCreated: TDateTime;
fDateModified: TDateTime;
fDateOpened: TDateTime;
fDateSolved: TDateTime;
fCategory: TTicketCategory;
function getTicketID: TTicketID;
published
property ticketNo: TTicketNo read fTicketNo write fTicketNo;
property description: TDescription read fDescription write fDescription;
property dateCreated: TDateTime read fDateCreated write fDateCreated;
property dateOpened: TDateTime read fDateOpened write fDateOpened;
property dateSolved: TDateTime read fDateSolved write fDateSolved;
end;ianxevcd, I tried that before and I tried again - it didn't change anything. The parameter I used is, as what I understand, just a version number. Don't know where it is used but as my ticket table is created with or without this parameter, I can't see that it have something with db modification to do. But what do I know?
I will try to debug that function a bit more later on if no other solution comes up.
In unit mORMot:
procedure TCQRSService.InternalCqrsSetResult(Error: TCQRSResult; var Result: TCQRSResult);
procedure TJSONSerializer.WriteObject(Value: TObject; Options: TTextWriterWriteObjectOptions);
procedure WriteProp(P: PPropInfo);
Kind := P^.PropType^.Kind;
case Kind of <<<< Kind is 28 (TSQLRecordTableDeletedClass)
===== Raises exception External: SIGSEGV
tkInt64{$ifdef FPC}, tkQWord{$endif}: begin
This happends when I call the function ORMGetNextAggregate when there is no data left and when
it sets the cqrsStatus via InternalCqrsSetResult.
The code sequence in my testapp looks like:
ticketServer.DBServer.Services.Resolve(IDomTicketCommand,IDTC);
theTicket := TDTOTicket.Create;
theTicket.ticketNo := 199;
cqrsStatus := IDTC.Add(theTicket);
IDTC.Commit;
try
cqrsStatus := IDTC.SelectAll;
if cqrsStatus in [cqrsSuccess, cqrsSuccessWithMoreData] then begin
while cqrsStatus in [cqrsSuccessWithMoreData, cqrsSuccess] do
begin
cqrsStatus := IDTC.getNext(theTicket);What can I do here? Is it a system bug or am I the bug? ![]()
I have already tested that and I did it again but only the ticket.table is created.
I'm using fpc, zeos and lazarus and I have had a lot of problems making it work can it be something with this configuration? I've tested with delphi in another project and that was easier but then I also used MSSQL.
Setting up the server with authorization doesn't work as expected.
I expected the two tables would be created automatically when I set the parameter of "TSQLRestServerDB.Create" to true.
The table "Ticket" is created
constructor TTicketServer.create;
begin
TDDDRepositoryRestFactory.ComputeSQLRecord([TTicket]);
DBConnect(rseZeosMySQL, 'zdbc:mysql://localhost:3306', 'test_mormot', 'root', '');
Model := CreateTicketModel;
VirtualTableExternalRegister(Model, [TTicket], Props);
DBServer := TSQLRestServerDB.Create(Model, true); // Require authorization
try
DBServer.CreateMissingTables(0);
DBServer.ServiceContainer.InjectResolver([TInfraRepoTicketFactory.create(DBServer)], true);
DBServer.ServiceDefine(TInfraRepoTicket, [IDomTicketCommand], sicClientDriven);
httpServer := TSQLHttpServer.Create(PORT_NAME, [DBServer], '+', HTTP_DEFAULT_MODE);
function createTicketModel: TSQLModel;
begin
result := TSQLModel.Create([TTicket],'root');
end;
procedure TTicketServer.DBConnect(aEngine: TRemoteSQLEngine; const aServerName,
aDatabaseName, aUserID, aPassWord: RawUTF8);
const
TYPES: array[TRemoteSQLEngine] of TSQLDBConnectionPropertiesClass = (TSQLDBZEOSConnectionProperties,TOleDBConnectionProperties, TODBCConnectionProperties, TSQLDBOracleConnectionProperties, TSQLDBSQLite3ConnectionProperties, nil, TOleDBMSSQL2008ConnectionProperties);
begin
if Props <> nil then
raise Exception.Create('Connect called more than once');
if TYPES[aEngine] = nil then
raise Exception.CreateFmt('aEngine=%s is not supported', [GetEnumName(TypeInfo(TRemoteSQLEngine), ord(aEngine))^]);
Props := TYPES[aEngine].Create(aServerName, aDatabaseName, aUserID, aPassWord);
end;What am I missing?
Ok, I understand. I'll skip that part of the sample to get forward.
I'm new to mORMot and it's not an easy beast to tame so I feel that I'm not ready yet to come with any proposal here. Maybe in the future ![]()
Trying to make sample 16 to work with Lazarus and are stopped out by synTaskDialog which are used by mORMotUILogin.
I found that in mORMotUILogin there is a compiler switch that refer to:
{$ifdef FPC}
SynTaskDialog in '.\Samples\ThirdPartyDemos\Ondrej\SynTaskDialog4Lazarus\SynTaskDialog.pas',
{$else}
SynTaskDialog,But I can see that it is the version of synTaskDialog from the ordinary mORMot library that is used and that one won't compile with FPC.
I find it very odd to have a standard library unit that refer to a sample third party unit. Is that good programming?
Ok, that's that.. but isn't it possible to have FPC work with this fundamental unit?
I thought I made it work but it was only an coincidence:
Baby := TSQLBaby.Create;
if aClient.Retrieve('', Baby, 'min(BirthDate)') then
Memo1.lines.Add(Format('zzzz %s - %s ',[Baby.Name, Baby.Address])+' // '+FormatDateTime('yyyy-mm-dd', Baby.BirthDate)); <<-- Gives an empty Baby
if aClient.Retrieve('', Baby, '') then
Memo1.lines.Add(Format('yyyyy %s - %s ',[Baby.Name, Baby.Address])+' // '+FormatDateTime('yyyy-mm-dd', Baby.BirthDate)); <<-- Gives the first record created (it happened to be the one I searched for)I'm sure I do something wrong but after I have tested so many different things... it looks impossible to make it work.
Well I did got a hit but the Baby object was empty in return so all strings was empty and the date was '1899-12-30'.
I did like this:
Baby := TSQLBaby.Create;
if aClient.Retrieve('', Baby, 'min(Birthdate)') thenI feel that I'm missing something but what?
Finally I found why I got the Access violation. That's because I didn't created the Baby object first.
I needed to do like this:
if aClient.Retrieve(ID,Baby) then
Memo1.lines.Add(Format('WWWW %s - %s ',[Baby.Name, Baby.Address])+' // '+FormatDateTime('yyyy-mm-dd', Baby.BirthDate));But I still don't know how I should do to use "Retrieve" to get the post with oldest date.
Of course I can do like this:
if aClient.Retrieve('BirthDate = (SELECT MIN(BirthDate) FROM Baby)',Baby) then
Memo1.lines.Add(Format('WWWW %s - %s ',[Baby.Name, Baby.Address])+' // '+FormatDateTime('yyyy-mm-dd', Baby.BirthDate));But as I understod from ab, this is not the best way to do it... am I wright/wrong?
Ok, that solved some mystery about this. I have declared BirthDate as TDate and that result as FLOAT in SQLite3. When I changed to TDateTime I got TEXT in SQLite3.
Strange that TDate and TDateTime is not treated the same here.
That solved everything about this and if I had choosen TDateTime from the begining, this topic would not been created ![]()
Finally it worked ![]()
I could also reduce it to:
Baby := TSQLBaby.CreateAndFillPrepare( aClient, 'BirthDate=?',[double(dt)]);So you may ask... Why all this about using DateToSQL and DateTimeToSQL when you should cast it to a double?
It has to be some other situations when you need to use them but when?
Thank's !
PS
Is there any Convention how to mark a thread solved here ?
DS
Sorry, but that didn't work either.
Can there be any more solutions to test? ![]()
I use SQLIteStudio 3.2.1
which gives the following output:
ID Name Address BirthDate Sex
310 Fredrik Stockholm 43259.5122240741 1
311 Kristina Lund 43294.5122242593 0
312 Kurt Lindesberg 43103 1The last line is the line I searched for which is 2018-01-03.
I just tested that, but, sorry ... no hit.
Date seems to be a problem in mORMot.
Maybe it could also depend on SQLite3? I never had any such problems in Delphi with firedac and MSSQL.
It doesn't matter if I change to DateTimeToSQL. Still no hit.
You only get hits when using :
Baby := TSQLBaby.CreateAndFillPrepare( aClient, 'BirthDate <> ?',[DateTimeToSQL(dt)]);or whenever you use '<' or '>' but thats not what I want in this case. I want hits on a certain date.
Maybe this wont work with fpc and lazarus? But I thought it would.
I'm running on Windows10.
Still hope on some help or explanation
I have tried your suggestion but failed, I've probably not understand what you mean so I need more help.
Note that I use Lazarus-2.1 and fpc-3.3.1
I've tried hard to find out how I should use the retrieve-function but totaly failed.
if aClient.Retrieve('BirthDate = ?',[],['Select min(BirthDate)'],Baby,'') thenand even this will not work,
if aClient.Retrieve('BirthDate = ?',[],['2019-01-01'],Baby) thenI get access violation in mormot.pas at the last line in the dump below:
function TSQLModel.GetTableIndex(aTable: TSQLRecordClass): integer;
var i: PtrInt;
Props: TSQLRecordProperties;
c: PSQLRecordClass;
begin
if (self<>nil) and (aTable<>nil) then begin
Props := PPointer(PtrInt(aTable)+vmtAutoTable)^;
if (Props<>nil) and (Props.fModelMax<fTablesMax) thenThe following does not work as I expected:
Baby := TSQLBaby.Create;
Baby.name := 'Kurt';
Baby.Sex := sMale;
dt := encodeDate(2018,01,03);
Baby.BirthDate := dt;
Baby.Address := 'Lindesberg';
aClient.Add(Baby, true);
Baby.Free;
Baby := TSQLBaby.CreateAndFillPrepare( aClient, 'BirthDate = ?',[DateToSQL(dt)]);
while Baby.FillOne do
begin
Memo1.lines.Add(Format('>>>>>>>>>> %s - %s ',[Baby.Name, Baby.Address])+' // '+FormatDateTime('yyyy-mm-dd', Baby.BirthDate));
end;BirthDate and dt is clearly the same date so why didn't I get a hit from the query?
I'm new to mORMot and trying to learn.
In this case I have a problem finding the oldest record (birthDate) in table Baby.
I reused the example from the documentation to test ORM.
What I want to do is execute the following SQL-code
BirthDate = (SELECT MIN(BirthDate) FROM Baby)This is how I solved it:
Baby.Free;
Baby := TSQLBaby.CreateAndFillPrepare( aClient, 'BirthDate = (SELECT MIN(BirthDate) FROM Baby)',[]);
while Baby.FillOne do
begin
Memo1.lines.Add(Format('%s - %s ',[Baby.Name, Baby.Address]));
end;As you can see I have the "Bounds"-parameter empty[] because I couldn't make it work so I had to put the complete SQL in the "FormatSQLWhere"-parameter.
Is there any other aproach that you recommend to be used?
That made it! ![]()
Thanks a lot, both of you.
Now I can get rid of the Indy components that require a lot of bugfixes, I had to do myself, to make https work.
Thanks again.
I've been very busy this week will still be for a while. After all, I tried to test your suggestion, but I can't make it work. I have no idea how to use this.
I tried this but it won't do a thing.
cl := TWinHttp.Create('localhost', '4430', false);
authResponse := cl.Post('localhost/authenticate/',AuthData,'Key: Content-Type, Value: application/json',true,HDRResponse);
I tried to begin without using https and also on a localhost server to minimize error sources.
I debugged the code and it seems that cl.post won't care about what I did in create.
Any idea of what I missing?
We want to create an application calling an existing web service with https.
The first service call will be authentication, parameters are username and password.
On success, we will get a token that is saved to be used in future calls of other service functions.
Responses will be in JSON.
I'm new to mORMot and not yet especially familiar with all functions and need some help finding the key functions.
I've been searching for a while but not found any that sound's to fit in. I'm sure there is but would be grateful to any help.
Looked at the sample code of "Project06ClientMain" and found "Client := TSQLRestClientURINamedPipe.Create(Model,'RestService');". But this uses NamedPipes and I need https.
Also, it uses "model" and wonder if it necessary to create a TSQLRecord here or if there is possible to pick the items from JSON directly here?
I've made it work already with some Delphi components but are very interested in mORMot and want to use it as much as possible.