#1 mORMot 2 » Any videos of EKON? » 2024-01-20 08:19:42

Replies: 1

Hi Arnaud,
Are there any videos from the sessions you did at last years EKON conference?
I'm particularly interested in the one titled 'Embracing mORMot 2.1'.

#2 mORMot 2 » postgresql » 2023-12-01 11:39:50

Replies: 0


could this be useful to Mormot?

#4 mORMot 1 » SQLite respect » 2022-05-10 08:31:29

Replies: 1

Does anyone have an opinion on when not to use SQLite instead something like of Postgres? I guess it's when there's a large amount of users or data. My question was triggered by this article:


#5 Re: mORMot 1 » Loading & Creating from a TRestHttpClient Definition file ? » 2021-11-23 21:33:44

Re: 'Any good link\articles\Books' the 1970's book by Niklaus Wirth 'Algorithms+Data Structures=Programs' is still worth a read.

#6 mORMot 1 » Blog » 2021-01-20 18:39:27

Replies: 2

btw the blog page seems to be down.

#7 Re: mORMot 1 » mORMot 2 proposal: rename RawUTF8 type to Utf8 ? » 2021-01-01 23:56:28

I’m not sure that what Utf-
8 is called matters that
much. Happy New Year!

#8 mORMot 1 » Fast MM5 » 2020-04-30 10:04:28

Replies: 106


May be of interest to mORMot users.

#10 mORMot 1 » Vatican » 2020-03-02 07:39:33

Replies: 1

@ab are you involved in the release of archives from the Vatican today?

#11 Re: mORMot 1 » basilique project from ekon » 2020-01-01 23:11:36

Would it make sense to have a ‘todo’ list? It could encourage contributions.

#12 Re: mORMot 1 » Store PDF as Blobs in SQlite - performance issues? » 2019-12-10 07:09:32

If you use numbers to name the files create a set of folders numbered 1-9 and file the files depending on the first digit of the file name. Or something like that.

#13 mORMot 1 » Scared mormot! » 2019-10-16 03:35:16

Replies: 3

Poor mormot - who won a wildlife prize just now

#14 Re: mORMot 1 » CBOR data format » 2019-08-05 20:59:17

Thanks for the answers.
JSON does seem more KISS smile

#15 mORMot 1 » CBOR data format » 2019-08-04 07:56:20

Replies: 3

Could it make sense for mORMot to support CBOR in the future?
It seems a more compact data format than JSON for sending data. But I've only skimmed the RFC.
see cbor.io

#16 Re: mORMot 1 » [Solved] Inconsistency in returned json and cache problems » 2019-05-15 18:25:03

I had this problem ages ago with a JavaScript client and just looked for both (ID || RowID). But that doesn’t probably help here.

#17 Re: mORMot 1 » auxiliary Rtree columns » 2018-11-04 15:43:53

I've had another look at this and found a better way to remove the '_'.

@ab please could you have a look at this pull request


#18 mORMot 1 » TSQLRestServer.OnAuthenticationUserRetrieve Problem » 2018-10-03 10:25:16

Replies: 0

I'm using a custom TSQLAuthUser record which adds an email address field and then uses TSQLRestServer.OnAuthenticationUserRetrieve to allow a user to use their username or email to login with.

This works except TSQLRestServerAuthenticationDefault.CheckPassword always uses the username to calculate the salt. I think it needs changing from:

function TSQLRestServerAuthenticationDefault.CheckPassword(Ctxt: TSQLRestServerURIContext;
  User: TSQLAuthUser; const aClientNonce, aPassWord: RawUTF8): boolean;
var aSalt: RawUTF8;
  aSalt := aClientNonce+User.LogonName+User.PasswordHashHexa;
  result := IsHex(aPassword,SizeOf(THash256)) and
    (IdemPropNameU(aPassWord,SHA256(fServer.Model.Root+CurrentServerNonce(false)+aSalt)) or
     // if current nonce failed, tries with previous 5 minutes' nonce


function TSQLRestServerAuthenticationDefault.CheckPassword(Ctxt: TSQLRestServerURIContext;
  User: TSQLAuthUser; const aClientNonce, aUserName, aPassWord: RawUTF8): boolean;
var aSalt: RawUTF8;
  aSalt := aClientNonce+aUserName+User.PasswordHashHexa;
  result := IsHex(aPassword,SizeOf(THash256)) and
    (IdemPropNameU(aPassWord,SHA256(fServer.Model.Root+CurrentServerNonce(false)+aSalt)) or
     // if current nonce failed, tries with previous 5 minutes' nonce

i.e. passing the acutual username used

#19 Re: mORMot 1 » FTS5 records » 2018-09-14 19:08:51

Incidentally TSQLRecordFTS5Unicode61 saves a few % in DB size compared to TSQLRecordFTS4 with the simple tokenizer.

#20 Re: mORMot 1 » FTS5 records » 2018-09-14 15:14:02

in TSQLRecord.GetSQLCreate in mORMot.pas changing

tokenizer := 'simple';


if Props.Kind = rFTS5 then
  tokenizer := 'unicode61'
  tokenizer := 'simple';

should fix it.
Also in the comments it mentions 'unicode64' a few times - I assume that's a typo.

#21 mORMot 1 » FTS5 records » 2018-09-14 12:20:45

Replies: 2

TSQLRecordFTS5 is causing an error in createMissingTables. The simple tokenizer seems to have been removed from FTS


#22 Re: mORMot 1 » sqlite3fts.obj » 2018-09-04 12:10:20

Free Text Search is now included by default

#23 Re: mORMot 1 » auxiliary Rtree columns » 2018-08-15 08:46:13

Finally got round to looking at this again. These changes to mORMot.pas seem to fix it:
line 33916:

       if Props.SimpleFields[i].Name[1] = '_' then    
        result := result+copy(Props.SimpleFields[i].Name,2,MaxInt)+','
        result := result+Props.SimpleFields[i].Name+','; // valid simple fields

  at line 33947 the following check needs removing

    if (Props.RTreeCoordBoundaryFields<2) or
       (Props.RTreeCoordBoundaryFields>RTREE_MAX_DIMENSION*2) or
       (Props.RTreeCoordBoundaryFields and 2<>0) then
      raise EModelException.CreateUTF8('% has % fields: RTREE expects 2,4,6..% boundary columns',

line 51273/4

if F.Name[1] = '_' then begin
          fSQLTableSimpleFieldsNoRowID := fSQLTableSimpleFieldsNoRowID+copy(F.Name,2,MaxInt)+',';
          fSQLTableRetrieveAllFields := fSQLTableRetrieveAllFields+','+copy(F.Name,2,MaxInt);
        end else begin
          fSQLTableSimpleFieldsNoRowID := fSQLTableSimpleFieldsNoRowID+F.Name+',';
          fSQLTableRetrieveAllFields := fSQLTableRetrieveAllFields+','+F.Name;

line 51485

if Fields.List[W.Fields[i]].Name[1] = '_' then
      W.ColNames[n] := copy(Fields.List[W.Fields[i]].Name, 2, MaxInt)
      W.ColNames[n] := Fields.List[W.Fields[i]].Name;

the comma in 32526 isn't needed

  result := FormatUTF8('%+% %',[result,copy(Name,2,maxInt),Props.Props.SQLFieldTypeToSQL(i)]) else

Please could you review this?

#24 Re: mORMot 1 » auxiliary Rtree columns » 2018-07-24 21:18:51

I think the '_' gets changed to a '+' by mORMot which sqlite swallows returning just the field name. I'll look more.

Thanks for https://synopse.info/fossil/info/c96db70ed9 but it still adds an extra comma at the end ('%+% %,') which sqlite seems to ignore.

Thanks for your work!

#25 Re: mORMot 1 » auxiliary Rtree columns » 2018-07-24 17:53:32

Another problem... RTREE_MAX_DIMENSION in mORMot.pas becomes invalid if auxiliary columns are used hmm

#26 Re: mORMot 1 » auxiliary Rtree columns » 2018-07-24 09:49:08

I've found another problem auxiliary columns. Because the underscore gets removed CreateMissingTables() always thinks the model has changed. This causes an sqlite error saying virtual tables can't be edited. Any suggestions on a solution?

#27 mORMot 1 » auxiliary Rtree columns » 2018-07-24 07:17:44

Replies: 6

I get errors creating rtree tables with auxillary columns. Changing line 32526 of mormot.pas from:

  if Name[1]='_' then // auxiliary columns for SQlite3 >= 3.24.0
    result := FormatUTF8('%+% %,',[result,@Name[2],Props.Props.SQLFieldTypeToSQL(i)]) else


  if Name[1]='_' then // auxiliary columns for SQlite3 >= 3.24.0
    result := FormatUTF8('%+% %',[result,copy(Name,2,MaxInt),Props.Props.SQLFieldTypeToSQL(i)]) else

seems to fix it.

#29 Re: mORMot 1 » CreateMissingTables question » 2018-07-06 07:27:27

if you add logging to your project:

TSynLog.Family.Level := LOG_VERBOSE;

The logs will show the SQL created by CreateMissingTables.

#30 Re: mORMot 1 » slight problem with mORMotUI.pas » 2018-05-23 12:00:42

I've tried putting mORMotUI.pas both at the start and end of the uses clause and it still gives the same error (using delphi 2007).

#31 mORMot 1 » slight problem with mORMotUI.pas » 2018-05-23 11:09:36

Replies: 2

If I'm using mORMotUI with a form I can't set any VCL controls' align properties to alRight at run-time. Delphi gives the error:

[DCC Error] Unit1.pas(281): E2010 Incompatible types: 'TAlign' and 'TSQLTableToGridAlign'

As a workaround I've used TAlign(4) instead of alRight. Is there a better way?

#32 Re: mORMot 1 » Beginner needs guidance - Lazarus HTTPS REST Server » 2018-05-03 16:44:29

Isn't DasBoot better? I expect mORMot can do it but it may take more reading of the docs...

#33 Re: mORMot 1 » Pattern match failed » 2018-02-24 21:46:50

+1 for splitting SynCommons

#34 Re: mORMot 1 » bug with JSON parsing » 2018-01-30 10:54:47

Maybe defining a record then an array would help

#35 mORMot 1 » TLS and recaptcha » 2018-01-08 10:11:11

Replies: 1

Thank you for adding TLS support. I've tried google's recaptcha and gmail and it seems to work fine. Only thing I've noticed is that when sending emails only port 465 works and not 587.

In case it's useful to anyone below is some code that processes a simple html feedback form with a recaptcha:

  Trecaptcha = packed record
    success: boolean;
    challenge_ts: RawUTF8;
    hostname: RawUTF8;

procedure TMyServer.sendFeedback(cTxt: TSQLRestServerURIContext);
  feedbackEmail, feedbackMessage, gRecaptchaResponse: RawUTF8;
  recaptchaSocket: THttpClientSocket;
  P: PUTF8Char;
  response: Trecaptcha;
  Server: TSMTPConnection;
  P := PUTF8Char(cTxt.Call.InBody);
  if UrlDecodeNeedParameters(P, 'EMAIL,MESSAGE,G-RECAPTCHA-RESPONSE') then begin
    while P<>nil do begin
      UrlDecodeValue(P,'EMAIL=', feedbackEmail);
      UrlDecodeValue(P,'MESSAGE=', feedbackMessage);
      UrlDecodeValue(P,'G-RECAPTCHA-RESPONSE=', gRecaptchaResponse, @P);
    if (feedbackEmail = '') or (feedbackMessage = '') or (gRecaptchaResponse = '') then
      Ctxt.Error('Missing Parameter')
    else begin
      recaptchaSocket:= THttpClientSocket.Open(
           'www.google.com','443',cslTCP, 10000, true);
          gRecaptchaResponse + '&remoteip=' + Ctxt.RemoteIP, 'application/x-www-form-urlencoded');
        RecordLoadJSON(response, pointer(recaptchaSocket.Content), TypeInfo(Trecaptcha));
        if response.success then begin
          if SendEmail('smtp.gmail.com', 'me@me.net',
            'Feedback Form From: ' + feedbackEmail, feedbackMessage, '',
            'me@me.net','xxx', '465', '', true)
            Ctxt.Error('Sorry, message sending failure');
        end else
          Ctxt.Error('recaptcha error');
  end else
    Ctxt.Error('Missing Parameter');

  __recaptcha = 'success: boolean; challenge_ts: RawUTF8; hostname: RawUTF8;';


#37 mORMot 1 » function TPrecisionTimer.Time: RawUTF8; » 2017-12-20 20:19:28

Replies: 2

I'm using TPrecisionTimer to time a long running procedure. Would it be possible to change the Time function to return hours and minutes as well?

Changing MicroSecToString in SynCommons.pas seems to work:

function MicroSecToString(Micro: QWord): RawUTF8;
  function TwoDigitToString(value: cardinal): RawUTF8;
  var L: integer;
    L := length(result);
    if L=1 then
      result := '0.0'+result else // '3' -> '0.03'
    if L=2 then
      result := '0.'+result else // '35' -> '0.35'
      insert('.',result,L-1); // '103' -> '1.03'
  var seconds: Cardinal;
  if Micro<=0 then
    result := '0us' else
  if Micro<1000 then
    result := SmallUInt32UTF8[Micro]+'us' else
  if Micro<1000*1000 then
    result := TwoDigitToString(Int64Rec(Micro).Lo div 10)+'ms' else
  if Micro<1000*1000*60 then
    result := TwoDigitToString(Micro div (10*1000))+'s' else
    seconds := Micro div (1000*1000);
    if seconds < 60*60 then
      result := UInt32ToUtf8(seconds div 60)+'m '+UInt32ToUtf8(seconds mod 60)+'s'
      result := UInt32ToUtf8(seconds div (60*60))+'h '+
                UInt32ToUtf8((seconds mod (60*60)) div 60)+'m '+
                UInt32ToUtf8(seconds mod 60)+'s'

#39 Re: mORMot 1 » Help for new user » 2017-12-08 10:27:11

rather ironically the link above hangs on my iphone5 chrome browser when I scroll down to 'Too much documentation can kill the documentation!'.
It's really convenient to have online documentation but would there be any way to divide up the html pages to make it more responsive?

#40 Re: mORMot 1 » SessionGroup and authentication » 2017-12-03 19:01:33

Sorry, I misread undefined in the comments as uninitialised.

#41 mORMot 1 » SessionGroup and authentication » 2017-12-03 10:41:53

Replies: 2

I want to create a method based service which works for both logged in and anonymous users. Is it safe to do something like this?:

procedure TMySQLRestServer.search(cTxt: TSQLRestServerURIContext);
  if cTxt.SessionGroup = 0 then
    //return results for anonymous users
    //return results for logged in users

I only ask as the code comments

/// the corresponding TAuthSession.User.GroupRights.ID value
  // - is undefined if Session is 0 or 1 (no authentication running)
  SessionGroup: integer;

but it seems that I can rely on SessionGroup being 0 rather than undefined if no authentication is running.

#43 Re: mORMot 1 » I need help again... » 2017-10-24 19:21:24

If you use JSON1 remember to call TSQLDataBase.CacheFlush() after edits to keep the ORM cache in sync. I got caught out by that!

#44 Re: mORMot 1 » Lazarus can no longer create SQLite3 databases using TSQLRestServerDB » 2017-10-05 11:49:46

My tuppence worth is that haven't found a javascript framework that's helpful. I prefer to code as much as possible by hand. Admittedly I do use jQuery and Bootstrap (by twitter) for a modern UI (don't much like dealing with css). There is also fuelux if you want some fancy controls like a datepicker.

#45 Re: mORMot 1 » Understanding TTextWriter » 2017-10-01 12:14:40

Thanks, I should have spotted that.

I got confused by using ObjectToJSON() in syncommons as an example. It seems to use the class constructor in an unusual way.

#46 mORMot 1 » Understanding TTextWriter » 2017-10-01 09:09:00

Replies: 3

I'm trying to use TTextWriter with a simple test:

procedure test;
  tw: TTextWriter;
  with tw.CreateOwnedStream do


This gives an Access Violation. but if I declare the TTextWriter globally like:

  tw : TTextWriterClass = TTextWriter;

it works. Do TTextWriter vars need to be declared globally or am I missing something?

#49 Re: mORMot 1 » Invalid Timestamp » 2017-08-30 11:39:27

Great, thanks for the quick response!

#50 mORMot 1 » Invalid Timestamp » 2017-08-30 08:47:54

Replies: 2

I'm having a problem with invalid timestamps when making two requests in quick succession after logging in. The first request succeeds but the second one fails.

In the logs I've got: Invalid TimeStamp: expected >=-8, got 142

The problem seems to be in line 51786 of mormot.pas when result.fLastTimeStamp is less than fTimeStampCoherencyTicks, I assume causing an overflow:

if HexDisplayToCardinal(PTimeStamp,aTimeStamp) and
     (fNoTimeStampCoherencyCheck or (result.fLastTimeStamp=0) or
      (aTimeStamp>=result.fLastTimeStamp-fTimeStampCoherencyTicks)) then begin

could using abs() could be a solution?:

  (aTimeStamp>=abs(result.fLastTimeStamp-fTimeStampCoherencyTicks))) then begin

Also in line 51803 it's failing to log the timestamp value and looks like it should be:

Ctxt.Log.Log(sllUserAuth,'Invalid TimeStamp: expected >=%, got %',
      [result.fLastTimeStamp-fTimeStampCoherencyTicks,Int64(aTimeStamp)],self);  //<<< added Int64(aTimeStamp)

Board footer

Powered by FluxBB