You are not logged in.
Yes, you are absolutely right
So far I confirm it works with PostgreSQL, but SQLite3 breaks again at utf8-encoded Name values.
More changes should be good to be done so far:
1. Add uADPhysPG in conditional uses in PerfTest
2. Override SQLAddIndex at TSQLDBFireDACConnectionProperties in order to add "IF NOT EXISTS". Annoying things are unnecessary exceptions.
Thanks you, ab.
Needed changes to run PerfTests at my environment are:
SynDBFireDAC:
498: P.AsWideStrings[i] := UTF8ToString(tmp);
515: P.AsWideString := UTF8ToString(VData);
P.S. It is working in PostgreSQL, but not in FireDAC's SQLite3 (maybe some firedac sqlite driver settings needed?). Same Name value error with sqlite3.
Windows system locale set to "Bulgarian (Bulgaria)"
Exactly
Test(TSQLDBFireDACConnectionProperties,FIREDAC_PROVIDER[dSQLite],'','','',' SQlite3',true,smFull);
is what breaks
Delphi XE4, FireDAC 8.0.3.
Building Win32
"ForceUseWideString := true" is taken into force only if UNICODE is not defined, as far as I see.
same problem:
Executing PerfTest.exe tuned for PostgresSQL gives:
'FireDAC PostgreSQL read failure: Value.FirstName=ValueFirstName[ i ] "Name 2"<>"Namé 2"'
In fact, same error with FireDAC's SQLite3:
'FireDAC SQlite3 read failure: Value.FirstName=ValueFirstName[ i ] "Name 2"<>"Namé 2"'
BCD handling is also not well (in case of currency represented as numeric(19,4) and value of 1)
json for the retrieved row contains: '"amount":01', which on behalf breaks TSQLRecord.FillFrom at Value := GetJSONField(P,P,@wasString) returning nil.
Delphi XE4, FireDAC 8.0.3.
Just changed some TADParam assignments in SynDBFireDAC.pas (in case of UNICODE defined)
P.AsString => P.AsWideString
P.AsStrings => P.AsWideStrings;
In case of .AsString assignment, FireDAC at some point issue VarAsType(<UTF8 encoded value>, varString) which seem converts the string in default code page, AFAIK.
After the changes UTF8 insertions seem correct, but other assert occur at PerfTest ValueCheck, but this may be due to postgresql specific field type/content handling.
I do not think this change is right, but just a quick fix in order to go forward.
Haven't dig a lot, but seems there is an issue using utf8 with FireDAC.
Trying to run PerfTest it does not insert properly Name value.
This cannot be changed, as that may break backward compatibility.
If you need to assign a "real" Unicode string, then use AsWideString.
Check here: http://www.da-soft.com/forums/anydac-ge … icode.html
Thanks a lot
Just starting to migrate a real-life server-side application using mORMot with FireDAC/PostgreSQL, as SQLite is becoming a bottleneck even in test environment.
This should be some kind of test.
Will let you know when problems faced.
About UTF8 initialization of new databases, it make sense, since it is highly recommended by postgresql community.
UTF8 client connection should be suitable for most of the cases.
Thanks again.
Hi ab,
As you know PostgreSQL is open source enterprise MVCC database, and I think it will be great addition to mORMot.
Yes, I will be glad if can be in any help coding/testing/donating. Simple guide(code examples) through such process will be needed.
Have several years experience using PostgreSQL on production.
Thanks.
Is it possible, to use PostgreSql as database backend for mORMot REST server using FireDac?
Thanks
It will be good to add RegExp functionality into SynDBExplorer in case of SQLite3 connection
If you really need to access the db file from other processes (in read-only mode, e.g. only for query) in sync with mORMot process, you can set sqlite3 file in WAL mode.
Probably you wish to create and destroy TIniData at inside your REST server, which will be done once.
And use threadvar ServiceContext inside your interface service.
Or define any method to be called inside TServiceRemoteLiveServerStandard, do all "create try finaly destroy" operations.
Sample 14 - "14 - Interface based services" may help you.
I would like to share my use case which can be implemented as part of the framework, probably property at REST server level.
I use to return JSON response to the clients (in my case browsers) using method based services generating custom and dynamic json response.
Browsers query the server at high rate (every second) to catch and display any data change which may occur.
Simple function called on every content response:
procedure ReturnContent(var aCtxt: TSQLRestServerCallBackParams; const aContent: RawUTF8);
var
clientETag: RawUTF8;
serverETag: RawUTF8;
begin
clientETag := FindIniNameValue(pointer(aCtxt.Call.InHead),'IF-NONE-MATCH: ');
serverETag := '"' + CardinalToHex(Hash32(@aContent[1], Length(aContent))) + '"';
if clientETag = serverETag then
aCtxt.Returns('', 304)
else
aCtxt.Returns(aContent, 200, JSON_CONTENT_TYPE_HEADER + #13#10 + 'ETag: ' + serverETag);
end;
Any decent browser will handle 304 Not Modified result and resent ETag according HTML specifications.
But actual transfer of data will not occur, which is big benefit if handling a lot of clients and they need to query the server at high rate.
Unfortunately, still the response will take server resources to generate the response content in order to build its ETag.
That is great, ab.
Thanks a lot, definitely will help.
Hi ab,
Yes, I already use sorting by one field index. It is pretty fast.
I use to store arbitrary TSQLRecords (not fully coming from sql database) in TSQLTable and return its json content.
But usually, common data is needed sorted by multiple fields, just like you expect if it is coming from sql-like storage (but in my case it is not).
Can I request a TSQLTable feature.
It would be really good if one be able to sort using multiple fields in asc/desc order.
Thank ab,
And sorry for disturbing you on Sunday
Thanks ab.
It worth everytime a text column is part of an index.
Maybe passing @Value[1], length(Value) is more correct.
If this column is involved within index or is part of not null constraint, the logic brokes.
Also, if you try to .Retrieve such a record passing "" (not null) property you will miss previously inserted same record, due to sqlite3 affinity.
In SynSQLite3 TSQLRequest.Bind() if I do this:
const
C_EMPTY: PUTF8Char = #0;
(..)
if pointer(value) = nil then
sqlite3_check(RequestDB, sqlite3.bind_text(Request, Param, C_EMPTY, 0, SQLITE_TRANSIENT)) // make private copy of the data
else
sqlite3_check(RequestDB,sqlite3.bind_text(Request,Param,pointer(Value), length(Value),SQLITE_TRANSIENT)); // make private copy of the data
works as expected, no NULL added for empty RawUTF8 published property to the database.
Actually any not nil pointer passed to bind_text will work.
But is adding NULL for empty RawUTF8 published properties "by design" for mORMot framework?
Just a quick question.
Have simple SQLRecord, setting RawUTF8 property to "" (empty) string and use TSQLRestServerDB.Add() to store it.
I see it is bound using sqlite3_bind_text with pointer(value) = nil and length of zero.
Is it normal sqlite to interpret it as null and store null in the database instead of just an empty text, as far as parameter is not bound using sqlite3_bind_null()?
Thanks.
After some debugging I am here
In TSQLRestServerStaticInMemory.FindWhereEqual (at the time when EngineDeleteWhere occur):
1. TSQLRestServerStaticInMemory.FindWhereEqual: ndx := Find(fSearchRec)
2. TObjectHash.Find(): result := HashFind(Hash(Item),Item);
3. TObjectHash.HashFind: if fHashs=nil then HashInit(Count);
4. TObjectHash.HashInit:
O := Get(i); <-- return nil
H := Hash(O); //Hash on nil object
5. TListFieldHash.Hash(nil): result := fProp.GetHash(Item,CaseInsensitive); <-- here AV occur on nil object
Here is the scenario.
I have two threads.
1 thread: doing RestClient.Retrieve and if not found RestClient.Add for StaticInMemory
2 thread. doing RestClient.Delete
Retrieve() is done by searching for int64 stored false hashed property.
Delete() is done by sqlrecord id
when 2nd thread delete a record and 1st thread try to retrieve and than add same record values following stack trace happens after many iterations:
20130313 20083522 EXCOS EAccessViolation (C0000005) at 00174C79 mORMot.GetInt64Prop (10718) stack trace 00009A3C System.@NewAnsiString 000058D6 System.@FreeMem 00184CF2 mORMot.TSQLRestClientURI.ExecuteList (20431) 0000A2F6 System.@LStrCat 0018524B mORMot.TSQLRestClientURI.InternalListJSON (20567) 001834BF mORMot.TSQLRest.Retrieve (19526) 00183687 mORMot.TSQLRest.Retrieve (19589)
...
20130313 20083736 EXC ESynException ("HashInit found dup") at 0015F278 SynCommons.TObjectHash.HashInit (21350) stack trace 0000A448 System.@LStrCatN 00186D8A mORMot.TSQLRestClientURI.EngineAdd (21115) 0019105E mORMot.TSQLRestClient.Add (25307)
...
code line numbers may differ from official source codes in mormot units.
Tried to Lock/Unlock EngineDeleteWhere, but no success.
Accessing object data inside TSQLRestServerStaticInMemory.EngineDeleteWhere is not protected with Lock/UnLock.
This leads to AV in heavy usage of TSQLRestServerStaticInMemory including Delete.
Yes, latest sources I am using.
Proposal for ClassInstanceCreate(aClass: TClass)
I see it checks whenever aClass is TSQLRecord, TInterfacedCollection, TCollection, ... in order proper class constructor to be called upon object creation.
It will be good TObjectList to be named there, and TObjectList constructor to be called, as it set FOwnsObjects to True. This is default behavior for TObjectList.
This will prevent memory leaks when TObjectList transmitted as a interface service parameter. Parameters are auto-freed, but one have to cycle all contained TObjectList in parameter and manually set OwnsItems to True.
Other case - unexpected memory leaks.
Ok, it seems not well formatted JSON for JSONToNewObject, as it does not start with '{'.
Tried with JSONToObject, same valid False result.
TMyClass instance created well and added to MyClassList. But new instance created contains nil for MyContainedClassList field and processing json fails.
Workaround is to manually create MyContainedClassList field on AfterConstruction, so nasted call to JSONToObject will have valid ObjectInstance as parameter.
Consider having classes defined like this:
TMyContainedClass = class
(...)
published
property Name: RawUTF8 read write;
end;
TMyContainedClassList = TObjectList;
TMyClass = class
(...)
published
property Name: RawUTF8 read write;
property MyContainedClassList: TMyContainedClassList read write;
end;
TMyClassList = TObjectList;
Having one objects in the lists I do serialization to Json string using ObjectToJSON().
As far as I see, instance of TMyClassList is correctly serialized.
Unfortunately, trying to de-serialize using TObjectList(JSONToNewObject(jsonPtr, valid)) set valid to False and returns nil
Is it correct behavior?
Is it only me or trying to open .log file leads to AV in LogView.exe when .log file used to be written with HighResolutionTimeStamp=True?
Yes, already written the APIs, and simple implementation, but not ready to open the sources.
Will contribute them soon. Along with required websocket server test scenarios (using winhttp websocket* api as a client) and further fixes which will come after the tests
Thanks ab,
Like a lot slim read/write locks. From years I use them, introduced in Windows Vista and Server 2008.
Very fast multi read exclusive write. Only one drawback - one thread should not try to reacquire it.
Matter of code design, but think in web server worker threads it is not a big issue. Critical Sections are good, but read-locking a peace of data for all threads, like session data or user context is waste of resources, I think.
Why use an abstract class, and not just an interface, to be implemented optionally by the main HTTP Server class?
You mean usage of abstract class for WebSocket common API or transport abstraction?
I agree interfaces will be more suitable in both cases.
Tried to abstract the usage, further step can be to interface it.
Very first version of WebSocket server is available at google code: https://code.google.com/p/dwsockets/
It is based on Eric's http.sys 2 implementation, which on behalf implements mORMot http.sys server logic.
WebSocket Server uses abstract transport and is not dependent on the http.sys server implementation.
Can be used on the top of other transport (ex. custom tcp connection, pipes)
Windows 8 or Server 2012 is required (for Windows WebSocket Protocol API), and added library paths to mORMot and DWScript.
Precompiled WebSocket Echo Server is available in Downloads section along with simple html/javascript client.
ab, why you think "Socket" server will be more suitable? compatibility?
Yes, works.
dwsDirectoryNotifier.pas:
{$if CompilerVersion < 24.0} // XE3
completionKey : DWORD;
{$else}
completionKey : ULONG_PTR;
{$ifend}
DSimpleDWScript.pas
{$if CompilerVersion < 24.0} // XE3
procMask, systemMask : Cardinal;
{$else}
procMask, systemMask : DWORD_PTR;
{$ifend}
Also, in XE3 many TCriticalSection, TObjectList, etc. methods are declared as inline for good, and relevant units should be declared in uses list in order compiler to inline the calls.
This is related to both DWS and mORMot. Annoying thousands compiler hints occur.
I can provide support for XE3.
Do you plan to add WebSockets support on HttpSys2 server side?
Do not know if here is the place to report, but know Eric will see it.
Eric, in order to compile the server (Delphi XE3) I have to correct following:
according MSDN,
at DSimpleDWScript.pas: procedure TSimpleDWScript.SetCPUAffinity(), variables procMask, systemMask used in calling GetProcessAffinityMask() should be PDWORD_PTR (in Delphi DWORD_PTR=>ULONG_PTR=>NativeUInt)
at dwsDirectoryNotifier.pas: procedure TdwsFileNotifier.Execute, variable completionKey used in calling GetQueuedCompletionStatus() should be PULONG_PTR (ULONG_PTR=>NativeUInt)
Great work!
Last time I tried to use synopse services implementation (a few months ago) they did not work for me and finally I ended up with native embarcadero implementation, which looks nice.
One world: awesome!
Feel like new era of server side programming is coming ...
I think it is time SMS to make effort for client side mORMot compatibility.
There is .NET 4.5 implementation. Although you can use .NET 4.5 on many win OS, using WebSockets namespace work only on Win8+.
So I think it can be done using win apis. This is what I am going to try these days.
Microsoft does not plan to change http.sys implementation on old platforms so far.
It was not compatible with http.sys. Starting Win8+ it is.
http://nbevans.wordpress.com/2011/12/20 … ws-server/
Introducing HTTP_SEND_RESPONSE_FLAG_OPAQUE.
Hello,
For my current needs I would like to implement support for async WinHTTP client along with new Windows 8 only native support for WinHttpWebSocket* calls.
For server side planning to develop http.sys server with WebSocket functionality (windows8+).
Having http.sys server supporting WebSockets protocol, can be big advantage, as every modern browser (including mobile ones) supports WebSocket protocol.
I also think such functionality will be great benefit to mORMot framework in many aspects.
If someone find it useful and/or have any experience with new Win8 Net api's and want to collaborate with me is welcome.
In Synopse.inc you have following:
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
But for my purposes I need following directive:
{$RTTI INHERIT METHODS([vcPublic]) PROPERTIES([vcPublic]) FIELDS([vcPublic])}
If I define it in my class declaration unit seems to work so far.
It may worth to know, that your code change the default behavior of compilator regarding RTTI generation and if anyone starts using mORMot units in existing project, default RTTI behavior may be broken. Like my case
Anyway, sorry for bothering you, hope it may help others too.
Hi ab,
I use RTTI for my classes. I experience following case as explained here:
http://stackoverflow.com/questions/9499 … attributes
This is when I include mORMot SynCommons and SQLite3Commons in my uses before I try to access TRttiType's GetProperties method. Other RTTI information is also kind of broken.
If I use to build the whole project, run, AV raise at System.rtti ConstructAttributes, sub function FindCtor at line imp := PPPointer(p)^^; It seems p (CtorAddr) is not a valid pointer.
If I modify only my unit, recompile (not rebuild), already build dcus used (along with mORMot dcus).
In second case FindCtor() function exits on very begining:
for Result in AttrType.GetMethods do
if Result.CodeAddress = CtorAddr then
Exit;
If seems now we have valid CtorAddr, no AV, result as expected.
I use Delphi XE2 Upd1. The author of the stackoverflow.com used Delphi XE. Do you have any clue why this happens? Googling does point me at any solutions. Can this problem be related to mORMot RTTI hacks?
Thanks.
Surely it will be shared, I would love to, just give me a few weeks to tune up my existing code within mORMot framework.
I am driven from my use cases, but I am sure they can suit most of developer needs.
There are two use cases I need to cover.
First is handling big amount of data, second is decoupling user interface from the data, even of very intensive insert/update/delete operation over the data. User interface may not react to every single data change. But finally, they will be in sync.
1.
Lets imagine we have a big amount of business data. "Big amount" is abstract for every user. Lets say we have a table, containing a few millions of records.
We expose this table to our customers. It can be read only to them, but not to the editors of the data. But every reader will need to see the changes made by the "editors" on demand.
First problem is, how to show millions of records to every reader?
Google approach is to show nothing at front page, than put a search, will see paginated match of query.
But in custom application, human mind will feel more comfortable if it see a virtual table (list) containing all the records, than filter the records by its criteria, than filter again, result may contain also a millions of records, but he will keep filtering till find what is searching for. And most important, the user will see all the result in one table, being able to scroll and preview all the result data, just scrolling the table, not paginating. This will not help much finding exact match, but it is an advantage from human philosophical point of view.
TVirtualTree is good example how we can show initially big amount of rows (records) and initialize the nodes on demand. Nodes initialized by request from user interface.
This data is most common to persist.
2.
Viewing "real-time" statistic data, which is changed very intensive. Very few rows, let say 50, fitting on one screen. Statistic information which may change hundreds of time per seconds. So much that it is not suitable for user-interface to react to every change.
This data is most common to not persist.
When showing data in virtual table view, we will need to couple the data "row" id and table row index. Just like you do with IDToIndex in TSQLRestServerStaticInMemory.
This is where I define three Virtual "Proxy" Tables. I use proxy word in context of proxy to memory, proxy to db, and proxy to cached db, just like TSQLRestServer do using TSQLRestCache.
1. Proxy to memory:
Little count of rows, which will not need to persists, can be updated very intensive.
2.Proxy to db:
Big amount of on-disk persistent data, which will be not so fast, update more rarely but will be safe.
3.
Proxy to cached db, mix of 1 and 2:
Big amount of on-disk persistent data, little set of which will be updated very intensive. Will persist, but in case of failure last updates may not have a chance to persist.
All three cases are implemented using VirtualTables.
You may say all of this is currently implemented in mORMot framework.
What I will add over current implementation is:
1. All virtual tables will expose virtual methods for functions like GetFieldVarData(), SetFieldVarData() or CopyObject(), so if one like to gain extra speed will implement them knowing what kind of TSQLRecord descendant is dealing with.
2. Will let client to subscribe to listen/notify channel over tables/records of interest. Currently and unfortunately not transaction aware. Will track all changes, consolidate them, stream to the client on request.
In a simple example it may look like this:
1. Client request to listen to TSQLBigData table of records.
2. Client receive thread safe records count.
3. Client request TSQLBigData records from index 0 to 20, for the needs of user-interface.
4. As client scroll, it will need other TSQLBigData records, located at view index position. Returned rows will be according current client view state. Ex. If client request row idx 15 for view, have not still received changes from the server, but record 10 is already deleted and logged as delete event, the server will know that it should return record idx 14 because when the client process deletion of record 10, the requested row 15 will be at position 14.
5. Client will be notified for table count change, inserts, deletes, updates, only for the data, which is already requested in view. It will be up to the client to define the UI refresh interval.
6. Client may change (inset/delete/update) the set. Every other listening client, which have focus on changing record will be notified for the change.
It will be transparent to client how big the data is, how often it is updated, does it persists, etc.
Client will be able to show both big data sources and high intensive ones.
All low-level functionality already done and in production. I can not write here about all implementation details, aspects and use-cases. This post is already too long. But I would like to see them in mORMot framework, hoping they will help other users too.
Thank you very much ab,
Will give the new build a try tomorrow.
Hi ab,
I would like to implement TSQLVirtualTable, TSQLRestServerStatic and TSQLVirtualTableCursorIndex descendants. Just like TSQLVirtualTableJSON do for example.
So far everything is going well.
I am overriding TSQLVirtualTable's:
function Delete(aRowID: Int64): boolean; override;
and at some point would like to do:
Static.Owner.fCache.NotifyDeletion(Static.StoredClass, aRowID); //pasted from TSQLVirtualTableJSON.Delete()
fCache can be accessed from public TSQLRest.Cache property, but protected TSQLRestCache's method NotifyDeletion and whole protected Notify* family methods are not accessible.
Solution may be to implement my descendants in SQLite3Commons unit, so protected RestCache methods will be accessible. But I prefer to not mess with framework code and define my classes in other units.
I would like to recommend moving the needed methods from protected to public section of the TSQLRestCache class, so everyone will be able to control the Rest Cache implementing custom Virtual Table.
Thanks.
Ab,
I think there is nothing to deal with framework access rights. Same security rules apply to the client, whenever he is delphi client, browser, javascript or whatever the developer wish to use to access the framework over HTTP.
Browser, for example, will receive the response from mORMot (taking care of current security) but there is no way the calling javascript function to be notified of receiving the response.
Here is how I implement it, but I think it is not the right place. TSQLRestServer.URI() is better I think, anyway:
"_TJSONP" is callback parameter SmartMobileStudio use, but should be customizable.
function TKVSQLite3HttpServerHelper.Request(const InURL, InMethod, InHeaders, InContent,
InContentType: TSockData; out OutContent, OutContentType, OutCustomHeader: TSockData): cardinal;
const
C_CALLBACK_PARAM: RawUTF8 = '_TJSONP';
var
p: Integer;
newURL: TSockData;
begin
p := PosEx(C_CALLBACK_PARAM, InURL, 1);
if p > 0 then
begin
newURL := Copy(InURL, 1, p - 1);
Result := inherited Request(newURL, InMethod, InHeaders, InContent, InContentType, OutContent, OutContentType, OutCustomHeader);
OutContent := Copy(InURL, p, Length(InURL)) + '(' + OutContent + ');';
end
else
Result := inherited Request(InURL, InMethod, InHeaders, InContent, InContentType, OutContent, OutContentType, OutCustomHeader);
end;
But SmartMobileStudio does not use good practices using jsonp url notation.
Most common is to specify:
http://<host>:<port>/<modelroot>/<table/method>[?params[,..]]&_callback=MyJavascriptCallBackFunction
Than the mORMot Rest Server will return same json response, but wrapped as javascript function call:
"MyJavascriptCallBackFunction(<here comes json content from the server>);"
This way calling javascript function can be notified for the response.
P.S. I think esmondb is meaning that if he deploy mORMot server on windows machine and use to develop client javascript librabry accessing the server from other machine (developer for ex.), the javascipt is only able to access the server using jsonp requests. But currently URI() does not wrap the response, so there is no way his javascript callback function to be notified for the response.
Hi ab,
I would like to propose TSQLRestServer functionality.
If calling server methods from javascript client, it is common to use JSONP calls.
It will be nice if TSQLRestServer expose a property for url callback parameter.
URI() can check whenever this url parameter exists, and if yes to wrap the Resp as javascript function call to url callback parameter value.