#1 Re: mORMot 2 » EOleSysError "Class not registered" » 2024-05-30 09:52:59

Bo

That is great, looking forward to next one.

I have found out that it is a bug in 2.2 stable in TSqlDBOleDBMSSQL2018ConnectionProperties which you have fixed in master commit

Revision: 8e0ecde3ba26324e9d270493c58c16393355afb4
Author: Arnaud Bouchez <ab@synopse.info>
Date: 25/1/2024 01:45:48
Message:
fixed TSqlDBOleDBMSSQL2018ConnectionProperties
as reported by https://github.com/synopse/mORMot2/issues/238
----
Modified: src/db/mormot.db.sql.oledb.pas
Modified: src/mormot.commit.inc

#2 Re: mORMot 2 » EOleSysError "Class not registered" » 2024-05-30 00:14:10

Bo

I will use master until you get next stable one. I just need to find a way to stop rebuild my app when there is an update in master.

#3 Re: mORMot 2 » EOleSysError "Class not registered" » 2024-05-29 04:58:51

Bo

This happens to another machine too. The same application and same machine work okay if the application is compiled with master branch of mORMot 2. Does 2.2 stable support driver behind TSqlDBOleDBMSSQL2018ConnectionProperties?

#4 mORMot 2 » EOleSysError "Class not registered" » 2024-05-28 12:30:10

Bo
Replies: 6

I use one of mORMot 2's great features which is "CreateMissingTables" to not writing db scripts for updating my MS SQL database, initially I used master branch for developing and then wanted to use 2.2 stable for production, but I found 2.2 stable did not work and got the exception per title when calling rest server's CreateMissingTables, I used the sample project "ex\ThirdPartyDemos\martin-doyle\05-HttpDaemonORM\src\Project05HttpDaemon.dproj" to verify it and it failed with 2.2 stable too, below is the modified code to use MS SQL:

procedure TSampleDaemon.Start;
var
  Props: TSqlDBOleDBConnectionProperties;
begin
  Props := TSqlDBOleDBMSSQL2018ConnectionProperties.Create('localhost','mormot','','');

  SQLite3Log.Enter(self);
  Model := CreateSampleModel;
  VirtualTableExternalRegister(Model,[TOrmSample],Props);
//  SampleServer := TSampleServer.Create(Model, ChangeFileExt(Executable.ProgramFileName,'.db'));
  SampleServer := TSampleServer.Create(Model, ':memory:');
  SampleServer.DB.Synchronous := smOff;
  SampleServer.DB.LockingMode := lmExclusive;
  SampleServer.Server.CreateMissingTables; //<-- throw exception: EOleSysError "Class not registered"
  HttpServer := TRestHttpServer.Create(HttpPort,[SampleServer],'+',HTTP_DEFAULT_MODE,4 );
  HttpServer.AccessControlAllowOrigin := '*';
  SQLite3Log.Add.Log(sllInfo, 'HttpServer started at Port: ' + HttpPort);
end;

There was also a following exception:

Fatal exception ESqlite3Exception raised with message
  Error SQLITE_ERROR (1) [Step] using 3.44.2 - Class not registered

Do I have to use master or there is a quick fix ?

#5 Re: mORMot 2 » How do I speed up initial access with external db to MS SQL » 2024-05-21 12:39:55

Bo

Looks like the problem is solved by using ip address instead of machine name, i.e.,

 Props := TSqlDBOleDBMSSQL2018ConnectionProperties.Create('192.168.0.101','Training','sa','123');

#6 Re: mORMot 2 » How do I speed up initial access with external db to MS SQL » 2024-05-21 12:35:31

Bo

@ttomas
I did use SQL profiler on SQL server and I could see the execute time is quite normal.

#7 Re: mORMot 2 » How do I speed up initial access with external db to MS SQL » 2024-05-21 12:18:38

Bo

@ab
Added port number to the connection string, but it didn't work for me.

#8 Re: mORMot 2 » How do I speed up initial access with external db to MS SQL » 2024-05-13 12:55:56

Bo

tried with TADOConnection  with 'Provider=SQLOLEDB;Data Source=...', it had the similar speed number, i.e., some time it went up to above 3s, but haven't seen as this slow in SQL studio which also running from my laptop and connect to same db on another PC. Will try ODBC next time.

#9 mORMot 2 » How do I speed up initial access with external db to MS SQL » 2024-05-12 11:45:50

Bo
Replies: 8

I used example projects from "ex\ThirdPartyDemos\martin-doyle\05-HttpDaemonORM" as the base and connect it to MS SQL by using TSqlDBOleDBMSSQL2018ConnectionProperties like below

 Props := TSqlDBOleDBMSSQL2018ConnectionProperties.Create('MyAnotherPC','Training','sa','123');
 SQLite3Log.Enter(self);
 Model := CreateSampleModel;
 VirtualTableExternalRegister(Model,[TOrmSample],Props);
 SampleServer := TSampleServer.Create(Model, ':memory:'); 

The server and client were running on my laptop and the SQL server was running on another PC, these two machines were connected to the same Wifi network which I believe is 300M network.
Below server log shows it took 1s+ for reading the last ID and 3s+ for insert a record, is this normal (I have tried many times and it looks to me that it always like that after server is start up) or there is something I can tune up it to speed up?

20240512 11100250  " DB         mormot.db.sql.oledb.TSqlDBOleDBStatement(027c6f70) Prepare t=1.08s q=select max(ID) from dbo.Sample
20240512 11100250  " SQL        mormot.db.sql.oledb.TSqlDBOleDBStatement(027c6f70) Execute t=1.09s q=select max(ID) from dbo.Sample
20240512 11100251  " DB         mormot.db.sql.oledb.TSqlDBOleDBStatement(027c7090) Prepare t=38us q=insert into dbo.Sample (ID,Name,Question,Time) values (?,?,?,?)
20240512 11100251  " SQL        mormot.db.sql.oledb.TSqlDBOleDBStatement(027c7090) Execute t=11.49ms wr=1 q=insert into dbo.Sample (ID,Name,Question,Time) values (3,'','',135846605441)
20240512 11100252  " srvr         Write POST root/Sample=201 out=0 B in 1.12s
20240512 11100252  "  -    01.128.548
20240512 11122835  #  +    server.TSampleServer(02ac9b20).URI POST root/Sample in=54 B
20240512 11122835  #  +         mormot.db.sql.oledb.TSqlDBOleDBConnection(0283bb70).Create
20240512 11122835  #  -         00.002.040
20240512 11122835  #  +         mormot.db.sql.oledb.TSqlDBOleDBConnection(0283bb70).Connect
20240512 11123143  #  -         03.122.602
20240512 11123143  # DB         mormot.db.sql.oledb.TSqlDBOleDBStatement(027c71b0) Prepare t=3.12s q=insert into dbo.Sample (ID,Name,Question,Time) values (?,?,?,?)
20240512 11123144  # SQL        mormot.db.sql.oledb.TSqlDBOleDBStatement(027c71b0) Execute t=3.13s wr=1 q=insert into dbo.Sample (ID,Name,Question,Time) values (4,'','',135846605596)
20240512 11123144  # srvr         Write POST root/Sample=201 out=0 B in 3.15s
20240512 11123144  #  -    03.153.490

but some time following reading could be much faster:

20240512 11202701  % DB         mormot.db.sql.oledb.TSqlDBOleDBStatement(027c73f0) Prepare t=1.14s q=select top(1) ID,Name,Question,Time from dbo.Sample where Name=?
20240512 11202702  % SQL        mormot.db.sql.oledb.TSqlDBOleDBStatement(027c73f0) Execute t=1.14s q=select top(1) ID,Name,Question,Time from dbo.Sample where Name=''
20240512 11202702  % srvr         Read GET root=200 out=62 B in 1.17s
20240512 11202703  % ret        mormot.rest.server.TRestServerRoutingRest(02a478f0) [{"ID":5,"Name":"m2","Question":"tst 1","Time":135846606086}]
20240512 11202703  %  -    01.179.860
20240512 11203207  "  +    server.TSampleServer(02ac9b20).URI GET root in=68 B
20240512 11203207  " DB         mormot.db.sql.oledb.TSqlDBOleDBStatement(027c7510) Prepare t=119us q=select top(1) ID,Name,Question,Time from dbo.Sample where Name=?
20240512 11203208  " SQL        mormot.db.sql.oledb.TSqlDBOleDBStatement(027c7510) Execute t=8.94ms q=select top(1) ID,Name,Question,Time from dbo.Sample where Name=''
20240512 11203208  " srvr         Read GET root=200 out=62 B in 21.97ms
20240512 11203209  " ret        mormot.rest.server.TRestServerRoutingRest(02a478f0) [{"ID":5,"Name":"m2","Question":"tst 1","Time":135846606086}]
20240512 11203210  "  -    00.056.932
20240512 11204361  #  +    server.TSampleServer(02ac9b20).URI POST root/Sample in=52 B
20240512 11204361  # SQL        mormot.db.sql.oledb.TSqlDBOleDBStatement(027c71b0) Execute t=8.03ms wr=1 q=insert into dbo.Sample (ID,Name,Question,Time) values (6,'','',135846606123)
20240512 11204361  # srvr         Write POST root/Sample=201 out=0 B in 20.70ms
20240512 11204361  #  -    00.021.199

#10 Re: Low level and performance » Delphi doesn't like multi-core CPUs (or the contrary) » 2022-06-24 07:12:39

Bo

It seems a problem in TIdTCPServer component, in its OnExecute event handler, if I use ReadLn to wait for the pack starter,  in some cases (in my cases, hited by multiple packs at the same time and cut the connection in the middle etc.), it will keep firing OnExecute event even there is no connectioin at all (i.e., close the sender applications), change it from ReadLn to WaitFor seems can avoid the infinite loop:

        conn.IOHandler.ReadLn(mllp_header, -2 {IdTimeoutInfinite}, conn.IOHandler.MaxLineLength); ==> conn.IOHandler.WaitFor(mllp_header);

Thanks for being helping me.

#11 Re: Low level and performance » Delphi doesn't like multi-core CPUs (or the contrary) » 2022-06-24 03:25:06

Bo

I now can reproduce the issue on my dev PC, but there is something I don't understand. The new problem is that so far I can only reproduce it if I run the application via Windows Run, after it becomes 100% CPU0, if I attach Delphi debugger to it, CPU0 dropped immediately to normal and stay like that after I continue running it, and after attached to the debugger, I could not reproduce it any more, neither if I run the application start from debugger, so I am now have to add debugging string/log to trace it instead of debugging it within the debugger.

#12 Re: Low level and performance » Delphi doesn't like multi-core CPUs (or the contrary) » 2022-06-23 12:01:16

Bo

The customer's VM was created as 4 vCPUs in Azure, running CPU Get NumberOfCores, NumberOfLogicalProcessers /Format:List returns
    NumberOfCores=2
    NumberOfLogicalProcessors=4

Now I can reproduce on my own test VM which is half of customer's core, i.e., NumberOfCores=1, NumberOfLogicalProcessors=2.

With Process Explorer from Sysinternals tool set, I can see there are two threads using 100% of CPU0, even I suspend one of them the remained one still uses 100% CPU0.

Maybe next step is to see if I can reproduce it on a real PC.

#13 Re: Low level and performance » Delphi doesn't like multi-core CPUs (or the contrary) » 2022-06-21 01:02:27

Bo

Greate to know that recent CPUs have improved on this issue and that sounds correct as my application had been running okay for years in an on-premise VM until it moved to Azure VM and it started to have this 100$ CPU0 and non-responsive issue.
Is Azure VM not friendly to (Delphi) multi-thread application? Do you know if we need to do any optimization for Delphi application to run okay on Azure VM?

#14 Re: Low level and performance » Delphi doesn't like multi-core CPUs (or the contrary) » 2022-06-20 05:46:47

Bo

Hi ab,

I have an application compiled by Dephi 2007, it is a multi-thread application, but when it is busy, it seems only uses one core, i.e., CPU0 will be used 100% but the others are sitll very low usage, and thus the box (a Windows 2019 server VM) becomes no response, do you think this sympton (only one core is used 100%) is also related to the same LOCK issue in Delphi?

#15 Re: Source Code repository » Introducing enhanced logging mechanism » 2018-07-25 23:16:18

Bo
mpv wrote:

You can add some exceptions to be ignored to LogFamily.ExceptionIgnore list

Isn't that globally ignore that type of exception? But I just want to ignore in that function.

#16 Re: Source Code repository » Introducing enhanced logging mechanism » 2018-07-25 06:05:03

Bo

Hi AB,

How do I not to log the exception I explicitly want them to be silent somewhere but do not want this type of exception globally silent:

try
  TryLoadAsFormat1(data);
  // no exception, is format 1
  // do some thing here
except
// do nothing,  silent the exception, but the ISynLog will log this exception which I don't need
end;

Thanks,

#17 Re: mORMot 1 » How do I get every name:value pair from a Json? » 2017-08-30 02:21:48

Bo

I replace

    try
      LVal := TDocVariantData(LDoc.Values[i]); //conversion is failed when the value is an integer
    except
      LIdx := TSQLResourceIndex.Create;
      LIdx.JPath := AParentPath + '.' + LDoc.Names[i];
      LIdx.JValue := LDoc.Values[i];
      LPathValues.Add(LIdx);
      Continue;
    end;

with

      LVal := _Safe(LDoc.Values[i])^;   

and it seems working fine.

FYI, I then updated database (Sqlite) with the list of LIdx (TSQLResourceIndex), it took about 4~5 seconds to insert 35 records, I did not satisfy the performance but then I found the Batch updating in the performance sample, I switched to the batch updating and bang, it only took <200ms! Amazing, great work ab.

#18 Re: mORMot 1 » How do I get every name:value pair from a Json? » 2017-08-28 22:48:18

Bo

Hi ab,

Thanks for your reply.

I filled up JDoc by using _Json function and then cast  it to a TDocVariantData:

var
  v : Variant;
  l  : TList<TSQLResourceIndex>;
begin
  v := _Json('{"abc":123,"b":"c", "c": {"d":"e"}, "e": [1,2,3]}');
  l := GetPathAndValue(TDocVariantData(v));

#19 mORMot 1 » How do I get every name:value pair from a Json? » 2017-08-28 10:59:00

Bo
Replies: 5

Hi,

After I get the variant from _Json, how do I get every name:value pair down to the very most deep ones in the hierarchy of a Json?
For example:

var
  v : Variant;
begin
  v := _Json('{"abc":123,"b":"c", "c": {"d":"e"}, "e": [1,2,3]}');

then I want to list the name(Json path):value pair of the most deep ones (leaves in the hierarchy):

$.abc:123
$.b:c
$.c.d:e
$.e[0]:1
$.e[1]:2
$.e[2]:3

here is my code:

function GetPathAndValue( JDOC: TDocVariantData; AParentPath: string ='$'): TList<TSQLResourceIndex>;
var
  LPathValues: TList<TSQLResourceIndex>;
  LDoc : TDocVariantData;
  i, j: Integer;
  LVal : TDocVariantData;
  LIdx, LNewIdx : TSQLResourceIndex;
  LList : TList<TSQLResourceIndex>;
begin
  LDoc := JDOC;
  LPathValues := TList<TSQLResourceIndex>.Create;
  for i := 0 to LDoc.Count -1 do
  begin
    try
      LVal := TDocVariantData(LDoc.Values[i]); //conversion is failed when the value is an integer
    except
      LIdx := TSQLResourceIndex.Create;
      LIdx.JPath := AParentPath + '.' + LDoc.Names[i];
      LIdx.JValue := LDoc.Values[i];
      LPathValues.Add(LIdx);
      Continue;
    end;
    if LVal.Kind = dvObject then
    begin
      LList := GetPathAndValue(LVal, AParentPath+'.'+LDoc.Names[i]) ;
      for LIdx in LList do
      begin
        LNewIdx := TSQLResourceIndex.Create;
        LNewIdx.JPath := LIdx.JPath;
        LNewIdx.JValue := LIdx.JValue;
        LPathValues.Add(LNewIdx);
      end;
      LList.Free;
    end
    else if (Lval.Kind = dvArray) then
    begin
      for j := 0 to LVal.Count -1 do
      begin
        LList := GetPathAndValue(TDocVariantData(LVal.Values[j]),AParentPath+'.'+LDoc.Names[i]);
        for LIdx in LList do
        begin
          LNewIdx := TSQLResourceIndex.Create;
          LNewIdx.JPath := LIdx.JPath;
          LNewIdx.JValue := LIdx.JValue;
          LPathValues.Add(LNewIdx);
        end;
        LList.Free;
      end;
    end
    else begin
      LIdx := TSQLResourceIndex.Create;
      LIdx.JPath := AParentPath + '.' + LDoc.Names[i];
      LIdx.JValue := LDoc.Values[i];
      LPathValues.Add(LIdx);
    end;
  end;
  Result := LPathValues;
end;

GetPathAndValue(TDocVariantData(v));

Although above code does the job, but I was wondering if there is a better code for checking what is in the value, instead of doing

    try
      LVal := TDocVariantData(LDoc.Values[i]); //conversion is failed when the value is an integer
    except
    ...
    end;

#20 Re: mORMot 1 » Different query result of two equivalent queries » 2017-08-06 09:53:44

Bo
ab wrote:

The SQlite3 engine is expected to run in exclusive mode.
So if two processes (a mORMot server and SynDBExplorer) do access the very same database at the same time, the cache between the two is inconsistent.
This is as expected.

To consult the database in real time, expose the SQlite3 main mORMot instance using e.g. the mORMotDDD remote administration interface.

Don't know the "administration interface" yet, but I have made a little change to the explorer. Instead of generating "SELECT * ..." query when a table on the left list is double clicked, I make the double click to generate the complete list of the column in the SELECT query, like what SQL Studio does.

procedure TDBExplorerFrame.ListTableDblClick(Sender: TObject);
var
  i, j: integer;
  Fields: TSQLDBColumnDefineDynArray;
  LField: TSQLDBProcColumnDefine;
  LSQL : string;
begin
  i := ListTable.ItemIndex;
  if i>=0 then
  begin
    Props.GetFields(S2U(ListTable.Items[i]),Fields);
    LSQL := 'SELECT ' + Fields[0].ColumnName ;
    for j:=1 to Length(Fields) -1 do
    begin
      LSQL := LSQL + ', ' + Fields[j].ColumnName
    end;
    LSQL := LSQL + ' FROM ' + StringToUTF8(ListTable.Items[i]);

    AddSQL(UTF8ToString(LSQL),
      true,ssShift in fListTableShiftState);
  end;
end;

#21 Re: mORMot 1 » Different query result of two equivalent queries » 2017-08-05 12:53:02

Bo

Tested with data change (i.e., inserted records from out of SynDB Explorer), the "select * ..." query did returned new records, so it seems only the columns are cached some where. Where do I disable the caching for this situation?

#22 mORMot 1 » Different query result of two equivalent queries » 2017-08-05 09:37:29

Bo
Replies: 4

I created a class:

 TSQLIntegerDataTypes = class (TSQLRecord)
  private
    fByte : Byte ;   
  published
    property AByte: Byte read fByte write fByte;    
  end;

Ran the application and  a Sqlite db file created, opened SynDB Explorer and connect it to the db, executed  query "select * from IntegerDataTypes", I got column ID and AByte in the result.

While kept SynDB Explorer running, then I upgraded the class to add one more property as following code:

 TSQLIntegerDataTypes = class (TSQLRecord)
  private
    fByte : Byte ;
    fShortInt :  ShortInt;
  published
    property AByte: Byte read fByte write fByte;
    property AShortInt: ShortInt read fShortInt write fShortInt;
  end;

Compiled and ran the application again, the db was now updated, went to SynDB Explorer and executed the same query again, I got the same result without column AShortInt, but if I executed this equivalent query "select ID,AByte, AShortInt from IntegerDataTypes", I got the column AShortInt!

Is this a bug or a feature?

#23 Re: mORMot 1 » HttpGet failed in TestSQL3 » 2017-05-24 06:46:21

Bo

Tried today's Github's copy, still failed.

Checked Delphi's TNetHTTPClient and TNetHTTPRequest, they are using winhttp.dll as well.

I also try to call functions of WinHTTP directly:

procedure TDetailViewForm.Button1Click(Sender: TObject);
var
  hSession : HINTERNET;
  hConnect : HINTERNET;
  hRequest : HINTERNET;
  hResult : Boolean;
  dwSize : DWord;
begin
//  memo1.Text :=  HttpGet(Edit1.Text);
  hSession := WinHttpOpen('Mozilla/5.0 (Windows; mORMot 1.18 TWinHTTP)',WINHTTP_ACCESS_TYPE_NO_PROXY,'','',0);
  if (hSession=nil) then raise Exception.Create('Failed to create session');
  hConnect := WinHttpConnect(hSession,'shop.global-health.com',443,0);
  if (hConnect=nil) then raise Exception.Create('Failed to connect');
  hRequest := WinHttpOpenRequest(hConnect,'GET','/',nil,nil,nil,8388864);
  if (hRequest=nil) then raise Exception.Create('Failed to open request');
  if not WinHttpSendRequest(hRequest,nil,0,0,0,0,0) then
  begin
    raise Exception.Create(IntToStr(GetLastError()))
  end;
  hResult := WinHttpReceiveResponse(hRequest,nil);
  if not hResult then raise Exception.Create('Failed to receive data, error:' + inttostr(GetLastError()));

end;

the value of parameters to the function calls are copied from debuging HttpGet, these code has not failure with "WINHTTP_ACCESS_TYPE_NO_PROXY", but will get error 12029 when calling WinHttpSendRequest if change it to WINHTTP_ACCESS_TYPE_DEFAULT_PROXY.

I then change code in SynCrtSock (line 8266 of 24/5/2017) from

if fProxyName='' then
    OpenType := WINHTTP_ACCESS_TYPE_DEFAULT_PROXY else
    OpenType := WINHTTP_ACCESS_TYPE_NAMED_PROXY;

to

if fProxyName='' then
    OpenType := WINHTTP_ACCESS_TYPE_NO_PROXY else
    OpenType := WINHTTP_ACCESS_TYPE_NAMED_PROXY;

and it works for my machine.

But why? Is it a bug or I should change my system/network settings?

#24 Re: mORMot 1 » HttpGet failed in TestSQL3 » 2017-05-22 23:38:03

Bo

No proxy, but could be firewall as it runs OK outside of firewall, but what settings could be?

I then wrote a simple test application with RAD 10.2:

One form with two buttons, one button call mORMot's HttpGet, another one use TNetHttpRequest which comes with RAD 10.2,

code behind mORMot's button:   

procedure TDetailViewForm.Button1Click(Sender: TObject);
begin
  memo1.Text :=  HttpGet(Edit1.Text);
end;

code behind TNetHTTPRequest button: 

procedure TDetailViewForm.Button2Click(Sender: TObject);
begin
  NetHttpRequest1.URL := Edit1.Text;
  NetHttpRequest1.Execute();
end;

code for response from TNetHTTPRequest:

procedure TDetailViewForm.NetHTTPRequest1RequestCompleted(const Sender: TObject;
  const AResponse: IHTTPResponse);
begin
  Memo1.Text := AResponse.ContentAsString();
end;

Ran on a machine with URL "https://shop.global-health.com", mORMot button did not get response, but TNetHTTPRequest did. If URL changed to "http://shop.global-health.com", both worked.

If we bought an application developed in mORMot and it has this problem, what can our IT guy do to find out what issue could be in the company's firewall/network settings?

#25 mORMot 1 » HttpGet failed in TestSQL3 » 2017-05-22 03:54:14

Bo
Replies: 5

Strangely, all HttpGet failed in SynSelfTest unit when I ran TestSQL3 compiled with Berlin 10.2 Starter and Delphi 2007 Enterprise. The URL's corresponding json file needs to be delete to get the HttpGet line executed.

The error is "Project TestSQL3.exe raised exception class EWinHTTP with message 'winhttp.dll error 12029 (A connection with the server could not be established)'.

The URLs are all fine if open them with browser. Also tested URLs with PostMan and AdvancedREST Client, two of them need to specify header "User-Agent", otherwise all fine.

HttpGet seems working with "http" version of the URLs instead of "https" version.

Any pointer?

#26 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2017-02-12 12:22:47

Bo
mpv wrote:

Actual issue is inside mainForm.toLog function. Fixed by [70cc3773fb]

This fix does stop the AV, it would be nice if it can actual tell the script author that the variable passed in is undefined.

Also, I have noticed that there is another set of TSMEngineManager and TSMEngine etc in units SynSM, and they use Spider Monkey v24 instead of v45 in SyNode,
what are the main differences? What are the different using scenarios?

#27 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2017-02-09 11:46:06

Bo

Hi mpv,

Re: SyNode Sample 02, I have found that if the code was referring to a non-existed property of the main form (wrong spelling or capitalized etc.), it raised an generic AV which is not helpful at all, for example, this line of code "mainForm.toLog(mainForm.Caption);" will raise an AV in which does not tell  you the line no, what type of error etc., but "mainForm.ToLog(mainForm.caption);" does. What can we do to improve catching/avoid this type of error?

#28 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2017-02-09 10:40:49

Bo
mpv wrote:

@Bo In this case end users should program his scripts as a module - see how modules work
User script myCalculation.js:

const fs = require('fs')
...
function onInit(){ ....}
function onDone(){..}
function doCalculation(){...}
module.exports = doCalculation
// another way is to export a several methods
//  module.exports.onInit = onInit; module.exports.onDone = onDone; module.exports.doCalculation = doCalculation;

Your code

FEngine.Evaluate('require("myCalculation")()', 'eval.js', 1, res)

Modules (user code in your case) are wrapped in closure by require function - you can see this in debugger

This will be the equivalent of specifying an entry function in using MSScript.ocx as the script engine wrapper.

#29 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2017-02-08 22:31:20

Bo
mpv wrote:

There is no way to "clear" the module once it is loaded (like there is no way to "un-uses" unit in Delphi ). And normally you never need such.
Sample 02 execute only selected lines, so to read file twice (for example) in first time select end execute
...
In any case module required only once

The solution you provided is OK in this sample (i.e., interactive), what if the engine is pooled and its script is loaded from script files which are written by the end users (for example, an integration engine runs customized scripts for data processing)? How the end users should program the scripts to avoid "redefine" issue we are talking here?

#30 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2017-02-08 22:19:56

Bo
markzql wrote:

I also want know how to clear the moudles loaded, I just used it Free every times and Create a New TSMEngine...

How did you do it?

Initially, I used following code and it threw AVs:

// evaluate a text from mSource memo
  FEngine := FSMManager.ThreadSafeEngine(nil);
  try

    if mSource.SelText <> '' then
      FEngine.Evaluate(mSource.SelText, 'mSourceSelected.js', 1, res)
    else
      FEngine.Evaluate(mSource.lines.Text, 'mSource.js', 1, res);

  finally
    FreeAndNil(FEngine);   
  end;

Then I change the way it freed and it seemed OK now:

// evaluate a text from mSource memo
  FEngine := FSMManager.ThreadSafeEngine(nil);
  try

    if mSource.SelText <> '' then
      FEngine.Evaluate(mSource.SelText, 'mSourceSelected.js', 1, res)
    else
      FEngine.Evaluate(mSource.lines.Text, 'mSource.js', 1, res);

  finally
    //FreeAndNil(FEngine);   
    FSMManager.ReleaseCurrentThreadEngine();
  end;

#31 Re: SyNode » Beta release of SyNode - ES6 JavaScript + NPM modules » 2017-02-08 02:29:00

Bo

Hi mpv,

It seems that the script cannot be run more than once in "SyNode\Samples\02 - Bindings ", the error is "redeclaration of const fs.",
I guess the question is how to clear the script before next calling to FEngine.Evaluate?

#32 Re: synopse.info » Blog not reachable » 2017-02-05 13:03:56

Bo

Strange, the blog.synopse.info is not reachable from my desktop computer with all browsers, but it is reachable from my mobile phone with Chrome.

What should I look into to fix the desktop computer?

#33 Re: synopse.info » Blog not reachable » 2017-01-30 05:14:55

Bo

I was experiencing the same problem a few days ago, it was the Chrome and Edge that could not open the blog, IE was fine. I now can confirm that it works fine again on Chrome.

#34 mORMot 1 » A bug in SynDBExplorer » 2017-01-16 23:55:07

Bo
Replies: 1

Hi Ab,

There is a bug on line 275 in SynDBExplorerMain.pas. It should only free the connection if it is created for setting up a new connection, otherwise it throws an AV if an update connection is cancelled.

So the line should be something like

  if res=100 then
    FreeAndNil(C);

#35 Re: mORMot 1 » how to check whether server uses the same model » 2017-01-04 03:00:32

Bo

@EMartin,

I guess what juwo wanted to know was what happen if a client connect to a server on which was running on a different "Data Model" in which had slightly different TSQLRecords (different fields, different field type etc.). For example, the server and the clients were all on the version 1.0, and then the server was upgraded to 2.0, but not all of the clients were upgraded to 2.0, thus some of them would be using a different version of "Data Model", is there a way to avoid this situation or it has been guarded by the mORMot already?

#36 Re: mORMot 1 » Could not run Websocket Sample 31: Simple Echo Server » 2016-12-10 13:31:17

Bo

Another test case:
Running echo server on Windows 10, running browser locally, both Chrome and Edge are failed to connect, but IE can connect and gets echos.

Does Synopse Websocket only support IE?

#37 Re: mORMot 1 » Could not run Websocket Sample 31: Simple Echo Server » 2016-12-10 13:06:50

Bo

Here is another issue:

I ran the echo server on a Windows Server 2003 R2 Standard Edition, and ran the test html in both Chrome and Edge, got different result:
Chrome: could not connect at all.
Edge: the server reported it was connected, but not the browser, and then the connection dropped automatically after a while.

What can I check why the echo server cannot be connected? And why the behavior are different between Chrome and Edge?

#38 Re: mORMot 1 » Could not run Websocket Sample 31: Simple Echo Server » 2016-12-05 05:54:52

Bo
ab wrote:

Usually, this is a port issue.
The port you expect to bind is already used by some service or program.

but I believe this is not the case for me as I created the NodeJS echo server on the same port, if I forgot to stop NodeJS one, the sample echo server could not started until I closed the NodeJS one.

#39 Re: mORMot 1 » Could not run Websocket Sample 31: Simple Echo Server » 2016-12-04 10:39:35

Bo

Followed this link (http://cjihrig.com/blog/websockets-in-n … windows-7/) and created a websocket echo server by using Nodejs, it worked with the test html, so it looks like the Synopse sample echo server has something wrong, anybody else has encountered this before?

#40 Re: mORMot 1 » Could not run Websocket Sample 31: Simple Echo Server » 2016-12-03 13:41:44

Bo

Tried another machine, did work.

So the problem could be the machine's environment, but what could affect a websocket server? As the browser is working with other websocket echo server.

#41 mORMot 1 » Could not run Websocket Sample 31: Simple Echo Server » 2016-12-03 12:16:43

Bo
Replies: 8

Hi,

I am trying to run the sample "Project31SimpleEchoServer", but it seems not working.

Loaded the html, got following in the text area:

WebSocket - status 0
onerror - code:undefined, reason:undefined, wasClean:undefined, status:3
onclose - code:1006, reason:, wasClean:false, status:3


Checked it in the Developer Tools, got following error:

Project31SimpleEchoServer.html:18 WebSocket connection to 'ws://desktop-emq701g/' failed: HTTP Authentication failed; no valid credentials available
init @ Project31SimpleEchoServer.html:18
onload @ Project31SimpleEchoServer.html:72

What do I need to config to be able to run this sample? I did not see other people here reported this.

#42 Re: mORMot 1 » httpd.sys and SSL » 2016-11-15 11:06:49

Bo
erick wrote:

I have been struggling for hours trying to get HTTPD.SYS to work with SSL under Windows 10

...

I'm guessing it doesn't like the GUID?  People seem to just make up a GUID and it works for them.  Any suggestions?

Erick

The GUID does not play an important role at all, I made up one too. Most likely would be certificate's issue. I tried self-sign certificate by following the step's in the document but was not successful, then I reused the set of certificates from a production server and it worked immediately since then.

#43 Re: mORMot 1 » Implement RESTful with specification already designed » 2016-11-04 12:31:57

Bo

Hi ab,

I have read the framework document again regarding "send the parameters as a JSON object body" and response format, I believe that what you have suggested is doable. But I have not found how to return errors as http status code, because my specification requests it to return http 400 error when parameter validation failed. How do I achieve that?

Thanks,

#44 Re: mORMot 1 » Implement RESTful with specification already designed » 2016-11-03 23:17:31

Bo
ab wrote:

You can send the parameters as a JSON object body, even with interface based services.
You may define e.g. IAdmin interface and the corresponding method:

  procedure User(const adminUserId, adminPassword, orgUserid, orgPassword, orgName, orgTelephone, orgCorrespondenceEmail, orgAddress: RawUTF8);

Then you can override the routing class to match your expectations at URI level.
...

Thanks ab, I will try "JSON object body".

#45 mORMot 1 » Implement RESTful with specification already designed » 2016-11-03 00:03:52

Bo
Replies: 3

Is it possible to implement following RESTful API specification with mORMot? (please note this is not a database application, and the RESTful API is already published)


To create a user:

POST root/api/admin/user

with request Body:
{
"adminUserid" : "joe",
"adminPassword" : "password",
"orgUserid" : "GHRestOrg" ,
"orgPassword" : "password123" ,
"orgName" : "Test Rest Organisation" ,
"orgTelephone" : "04-345-1234",
"orgCorrespondenceEmail" : "info@test.com" ,
"orgAddress" : "Plato Towers, No 300/10" ,
}

I guess what I wanted to know is if there is a way to use custom URI and JSON format of request and response.
As far as I am aware, mORMot's interface based/method based services have different URI and JSON schema compare to above specification.

#46 Re: mORMot 1 » SynDB Explorer failed to execute query generated by Query Builder » 2016-10-25 12:14:58

Bo

It is a quick fix in SynDBExplorer, but I think the root cause is in IsSelect function.

MS SQL has no problem with line feeds, the problem is IsSelect failed to check the Select statement which has line feeds immediately after 'select', thus SynDBExplorer executes the select statement as no result SQL and seems to me that it is failed to run the query.

#47 mORMot 1 » SynDB Explorer failed to execute query generated by Query Builder » 2016-10-25 00:45:52

Bo
Replies: 3

I was playing with SynDB Explorer and trying with Query Builder, but strangely, the query generated by Query Builder did not return anything, even a simplest query like:

select
  lastuid.*
from
 lastuid

but the same query ran correctly in SQL Studio with lines of data returned (SynDB Explorer was connecting to a MS SQL database).

After a few tries, I found if I merge the lines to one line then the query runs OK with data returned:

select  lastuid.* from lastuid

With some debugging, I now narrow it down to following check will failed:

Check(isSelect('select'+#13#10+ ' * from toto'));

Looks like it does not treat #13#10 as separator.

#48 Re: Low level and performance » Re: How function results are allocated » 2016-10-22 05:17:55

Bo

Hi Ab,

Now I can reproduce your result. The difference is the "s" must not be a global variable.

#49 Re: Low level and performance » Re: How function results are allocated » 2016-10-20 10:57:02

Bo
ab wrote:

With Delphi 7 and Delphi 10.1, the last s is 'toto', as expected.

result=test
s=toto

This is strange, mine running result did not get "result=test" either!!!

Same result with XE5 and 2007.

open?id=0B8uyyClosvkAclFGR240YV9VTjA

#50 Low level and performance » Re: How function results are allocated » 2016-10-19 23:43:23

Bo
Replies: 3

Hi Ab,

I am reading your blog "How function results are allocated" (http://blog.synopse.info/post/2012/04/1 … -allocated) and running the code you provided in the blog to understand the problem, but what I have found is that the result is different, it was still 'test' instead of 'toto'. I am running code in Berlin 10.1 as following:

function GetString: string;
// is compiled as procedure GetString(var result: string);
begin
  if result='' then
    result := 'test' else
  writeln('result=',result);
end;
function GetRaise: string;
// is compiled as procedure GetRaise(var result: string);
begin
  result := 'toto';
  raise Exception.Create('Problem');
end;

var s: string;
begin
  // here s=''
  s := GetString; // called as GetString(s);
  // here s='test'
  s := GetString; // called as GetString(s);
  // will write 'result=test' on the console
  try
    s := GetRaise; // called as GetRaise(s);
  finally
    // here s='toto'
    writeln('s=',s);
    Readln(s);
  end;
end.

Have something changed in Delphi since you wrote the blog or have I done something wrong?

Board footer

Powered by FluxBB