You are not logged in.
@JD - Postgres have many "date" types. You can help a Zeos maintainer ( @EgonHugeist on this forum ) if you provide exactly a type of column (as it visible in DBeaver or pgAdmin).
BTW ODBC will be definitely slower compared to Zeos or SynDBPostgres - they both use a direct libpq binding, while ODBC adds one more layer.
The column is just "DATE". The same table has two "TIMESTAMPZ" columns to track record creation & modification that don't have this problem.
I know about the "slow" ODBC. That is why I very rarely use it. It is often my last resort if nothing else exists/works.
Isn't Zeos the fastest method for accessing external databases? I've been using it since my Delphi days and it is one of the first things I install in Lazarus/FPC. It has always been very reliable.
The last time I had a problem with it was in 2016 https://zeoslib.sourceforge.io/viewtopi … 40&t=41785 (due to my inexperience with PostgreSQL back then when switching from Firebird) and curiously it was SynDBPostgres that saved the day back then too.
This time I think I will keep Zeos & SynDBPostgres options going forward.
Do you think I should post this problem on the Zeos forums also or is it unnecessary since EgonHugeist is here as well?
Thanks,
JD
ODBC is proving a pain to set up. Is what I've done below correct because my mORMot server refuses to start after I compile?
// https://www.connectionstrings.com/postgresql-odbc-driver-psqlodbc/
// Driver={PostgreSQL UNICODE};Server=IP address;Port=5432;Database=myDataBase;Uid=myUsername;Pwd=myPassword;
fDbProps := TODBCConnectionProperties.Create('','Driver=PostgreSQL Unicode'+
{$ifdef CPU64}'(x64)'+{$endif}';Database=testdb;'+
'Server=localhost;Port=5432;UID=testdb;Pwd=testpwd','','');
// To prevent PostgreSQL from hitting the default maximum connection limit of 100
// and after rejecting subsequent connections
TODBCConnectionProperties(fDbProps).ThreadingMode := tmMainConnection;Thanks
JD
What is the type of date_sanction columnus in database? Is SynDBPostgres works as expected ?
The "date_sanction" column is a simple date column.
I just tested SynDBPostgres and it works as expected. All dates were in the JSON result.
But soon as I changed back to a Zeos connection, I lost all but the first date. So the problem may be from Zeos.
I will try ODBC as soon as I can and report my findings.
JD
Which database are you using?
Did you try with another provider (e.g. ODBC)?
PostgreSQL 11.7 and I have not tried ODBC yet. I will do so and let you know my findings.
Hi there everyone,
I just noticed a wierd behavior relating to dates with the FetchAllAsJson function. When I run a query I get a JSON array result where only the first object has dates. All the other objects have empty date values. Here is a sample JSON result I got from my query.
{
"result": [
[
{
"numero_sanction": 5,
"numero_accueilli": 43,
"date_sanction": "2019-07-07",
"type_sanction": "Avertissement écrit",
},
{
"numero_sanction": 4,
"numero_accueilli": 43,
"date_sanction": "",
"type_sanction": "Mise à pied",
},
{
"numero_sanction": 1,
"numero_accueilli": 23,
"date_sanction": "",
"type_sanction": "Avertissement écrit",
},
{
"numero_sanction": 2,
"numero_accueilli": 23,
"date_sanction": "",
"type_sanction": "Avertissement écrit",
},
{
"numero_sanction": 3,
"numero_accueilli": 23,
"date_sanction": "",
"type_sanction": "Avertissement écrit",
}
]
],
"id": 9
}This is not correct because it is impossible to save the records without a valid date. This was confirmed when I queried the PostgreSQL 11.7 database directly getting the expected result below:
numero_sanction|numero_accueilli|date_sanction|type_sanction |
---------------|----------------|-------------|-------------------|
5| 43| 2019-07-07|Avertissement écrit|
4| 43| 2020-01-21|Mise à pied |
1| 23| 2018-03-21|Avertissement écrit|
3| 23| 2018-08-28|Avertissement écrit|
2| 23| 2018-08-28|Avertissement écrit|This is the same for all my queries not just this one and this behaviour is recent. It was never like this before. I don't know if the problem is from mORMot or from ZeosLib.
Any assistance with resolving this problem will be appreciated.
Thanks,
JD
Hi there ab,
Sorry for the late reply. I have to apologize because I found the cause of the problem. It was a compiler directive that I disabled and had forgotten about in one of the source files. The end result was that the client and server were not using the same protocols. Everything now works perfectly.
Thank you very much for your time and for the suggestions you gave me.
JD
Here are the Heaptrc dump images from the server
Did you try to disable Compression := [hcSynShaAes] ?
I just tried it. It did not work either. Can I upload the Heaptrc dump images? There are just 2 of them.
JD
Hi ab,
This is what I did
fHTTPServer := TSQLHttpServer.Create(AnsiString(fServerSettings.Port), [fRestServer], '+', {HTTP_DEFAULT_MODE} useHttpSocket, 32, TSQLHttpServerSecurity.secSynShaAes);
THttpServer(fHTTPServer.HttpServer).WaitStarted();It didn't work.
I can call my interface based services using my browser or an application like Postman but I can no longer connect to the server using a Lazarus client. This is what was happening even before the addition of THttpServer.WaitStarted.
JD
Hi there ab,
I ran TestSQL3 and some assertions failed. Here are the relevant messages:
1.2. Low level types:
- RTTI: 1,340 assertions passed 1.71ms
- Url encoding: 200 assertions passed 1.31ms
- Encode decode JSON: 429,322 assertions passed 2.47s
- Wiki markdown to html: 56 assertions passed 492us
- Variants: 88 assertions passed 386us
- Mustache renderer: 153 assertions passed 1.03s
- TDocVariant: 91,785 assertions passed 235.03ms
! - TDecimal128: 22 / 17,446 FAILED 21.26ms
- BSON: 245,068 assertions passed 18.98ms
100000 TBSONObjectID.ComputeNew in 8.79ms i.e. 11,372,682/s, aver. 0us
- TSynTableStatement: 221 assertions passed 8.40ms
- TSynMonitorUsage: 1,202 assertions passed 3.26ms
Total failed: 22 / 786,881 - Low level types FAILED 3.82s
.........
.........
Windows 10 64bit (10.0.18363) (cp1252)
4 x Intel(R) Core(TM) i3-3240 CPU @ 3.40GHz (x86)
Using mORMot 1.18.5960
TSQLite3LibraryStatic 3.31.0 with internal MM
Generated with: Free Pascal 3.2 32 bit compiler
Time elapsed for all tests: 3m25
Performed 2020-04-23 00:26:57 by JD on DESKTOP-NPLKN1D
Total assertions failed for all test suits: 22 / 44,408,725
! Some tests FAILED: please correct the code.JD
Hi there everyone,
I just updated to the latest version of mORMot dated 22/04/2020. I recompiled my principal mORMot project and to my surprise, I can no longer connect to the Lazarus server from a Lazarus client.
My code is as follows:
Client side:
fClient := TSQLHttpClient.Create(AnsiString(fClientSettings.HostOrIP), AnsiString(fClientSettings.Port), fModel, false, '', '', fConnectionSettings.SendTimeout, fConnectionSettings.ReceiveTimeout, fConnectionSettings.ConnectTimeout);
TSQLHttpClient(fClient).Compression := [hcSynShaAes];The values above are:
fConnectionSettings.SendTimeout = 15000
fConnectionSettings.ReceiveTimeout = 15000
fConnectionSettings.ConnectTimeout = 20000
Server side:
fHTTPServer := TSQLHttpServer.Create(AnsiString(fServerSettings.Port), [fRestServer], '+', {HTTP_DEFAULT_MODE} useHttpSocket, 32, TSQLHttpServerSecurity.secSynShaAes);
THttpServer(fHTTPServer.HttpServer).ServerKeepAliveTimeOut := CONNECTION_TIMEOUT;This code works perfectly with older versions of mORMot. It is patterned after the example of George, in the list of mORMot examples. I have no idea why it no longer works.
I would appreciate any help in the resolution of this problem.
By the way, I am using Lazarus 2.1/fpc 3.2 rc1 Win32.
Cheers,
JD
Thanks a lot everyone. It worked.
JD
Hi there everyone,
I just updated my mORMot version yesterday (19/04/2020) & I want to upgrade my two projects using mORMot. However as I tried to recompile one of the projects, I got an error in the SynDBZeos file on line 886 saying Error: identifier idents no member "StartTransaction". The compilation messages relating to only SynDBZeos.pas are shown below:
.....
.....
SynDBZeos.pas(707,30) Hint: Variable "Tables" of a managed type does not seem to be initialized
SynDBZeos.pas(734,64) Hint: Variable "Fields" of a managed type does not seem to be initialized
SynDBZeos.pas(886,13) Error: identifier idents no member "StartTransaction"
SynDBZeos.pas(962,17) Hint: Local variable "ndx" does not seem to be initializedAny ideas what I can do to correct this problem?
Thanks a lot in advance for your assistance
JD
PS: I am using Lazarus 2.0.7/fpc 3.2 svn 62681 (Win 32) on Windows 10 Professionnal (x64)
Thanks a lot for the tip Esteban. It works properly now.
JD
Hi there everyone,
I have a mORMot REST server and I'm trying to send requests to it from a Java application.
Java strings are UTF16 by default and I want to get a list of users from the backend database by
sending query parameters in JSON format to the REST server.
I send a JSON string like this to the mORMot server:
{"etat":"Comptes activés"}
The mORMot server truncates the JSON string as follows:
{"etat":"Comptes
I made some changes and I noticed that the JSON string is not truncated when I send the
string with an underscore between the two words as follows:
{"etat":"Comptes_activés"}
The mORMot REST method looks like this
function TRESTMethods.Utilisateurs(Params: RawUTF8): RawJSON;
var
Res: ISQLDBRows;
Ctxt: TServiceRunningContext;
vParams: Variant;
begin
// Get the parameters - Java strings are UTF-16 by default so a convertion to
// UTF-8 is necessary here
vParams := _JsonFast(StringToUTF8(Params));
// NOTE vParams is empty when I send {"etat":"Comptes activés"} but it is OK
// when I send {"etat":"Comptes_activés"} with an underscore between 'Comptes'
// and 'activés'
// Set the current service context
Ctxt := CurrentServiceContext;
//
try
// more code here
finally
Res := nil;
end;
end;Can anybody please help me resolve this problem.
Thanks a lot,
JD
Why are you marshaling by hand the parameters?
Because at one time, the values sent by the client did not seem to be getting to the server. Why? I don't know. So I inserted all the UrlDecodeValue code to test it and I kind of left it like that. It works OK now though.
JD
Hi there ab,
I am interested in this also. How do I implement it? I am not using any authentication at all and my REST server is a memory server like this
fModel := TSQLModel.Create([], ROOT_NAME);
fRestServer := TSQLRestServerFullMemory.Create(fModel, false);In addition, my interface methods have the following format:
function TRESTMethods.Partenaires(ID, List, DTO, Mfd, ContentType: RawUTF8): RawJSON;
var
Res: ISQLDBRows;
aObj: TSQLPartenaire;
Ctxt: TServiceRunningContext;
begin
Result := '';
//
if aServer.fDBProps = nil then
raise Exception.Create(SQLCONNECTIONINACTIVE);
// Set the current service context
Ctxt := CurrentServiceContext;
// Get/set the parameter values
UrlDecodeValue(Ctxt.Request.Parameters, 'id=', ID);
UrlDecodeValue(Ctxt.Request.Parameters, 'list=', List);
if List = EmptyStr
then List := 'Y';
UrlDecodeValue(Ctxt.Request.Parameters, 'dto=', DTO);
UrlDecodeValue(Ctxt.Request.Parameters, 'mfd=', Mfd);
if Mfd = EmptyStr
then Mfd := 'Non';
// REST OF THE CODE HERE
end;Thanks a lot in advance.
JD
Thanks for the tip. I was wondering why it was no longer possible to compile the sample as it was in the past versions of mORMot.
Hi there everyone,
I'm trying to compile some old code that requires the use of the DateTimeToSQL function. I thought it was in SynCommons.pas but it no longer seems to be the case.
Where is this function located now?
Thanks,
JD
I finally got it to work. This time I stopped encoding the JSON array before sending it to the REST server and it now works in the Lazarus clients as well as when I call the function from an SQL tool or even from my browser.
Thanks a lot,
JD
Hi there everyone,
(a) BACKGROUND
I've been struggling with this problem for a couple of days. I have a mORMot REST interface application server in front of a PostgreSQL 10.5 server. It is working very well for a while now.
I just wrote a function in the PostgreSQL server that generates and returns work/planning schedules as a JSON text output to clients. The PostgreSQL function has the following signature:
CREATE OR REPLACE FUNCTION public.agg_planning_json(id_json text, date_debut date, date_fin date)The function expects the id_json parameter to have the following format:
{"ID": [20,19]}I have tested this function directly in the PostgrSQL server and it works well. I can even call the function from any browser or REST client after encoding the JSON input parameter like this
http://localhost:8088/service/myapi/rapportplanning?schema=public&idlist=%7B%22ID%22%3A%20%5B19%2C20%5D%7D&datedebut='2018-01-01'&datefin='2018-04-30'and it works.
The mORMot REST server code that handles these requests looks like this:
Res := aServer.fDbProps.Execute(Format('select * from %s.agg_planning_json(%s, %s, %s)',
[Schema, QuotedStr(IDList), QuotedStr(DateDebut), QuotedStr(DateFin)]), []);
while Res.Step do
Result := Res.ColumnUTF8('agg_planning_json');(b) THE PROBLEM
My problem is with the Lazarus clients. I send the request to the server after encoding the JSON array as follows:
ARestThread.Post(sqlPlanningSalarie, '', '', [UrlEncode(strIDList), SQLDate(dtDateDebut.Date), SQLDate(dtDateFin.Date)]);This ALWAYS fails with the error below:
Project server raised exception class 'Unknown' with message
SQL Error: ERREUR: syntaxe en entrée invalide pour le type json
DETAIL: le jeton << % >> n'est pas valide
CONTEXT: données JSON, ligne %1 : %...
instruction SQL << SELECT * FROM json_array_elements_text(id_json::json -> 'ID') >>
.....The PostgreSQL function seems to be complaining about the format of the JSON parameter. I noticed that the Lazarus client sends the parameters to the server with each parameter in double quotes " ". Could this be the source of the problem? Is this normal? How do I correct this problem?
Thanks a lot for your assistance,
JD
Do you guys use fpcupdeluxe? I have never been able to install anything with that, I always do it manually.
I use fpcupdeluxe to test trunk builds and sometimes to install NewPascal. I did not use it in my most recent install because FPC trunk is now 3.3.1 and some have said in this thread that it does not compile the latest mORMot.
That is why I chose to install Lazarus 1.9/FPC 3.2.0 Beta instead which is more recent than NewPascal and does not seem to have the problem associated with FPC trunk.
JD
I had the same problem. I keep two versions of Lazarus: NewPascal (with FPC 3.1.1) and Lazarus 1.8.4/FPC 3.0.4 stable on my system. This was OK for me until the Lazarus 1.8.4/FPC 3.0.4 could no longer handle the new TypeInfo changes in the latest version of mORMot (SynFPCTypInfo.pas).
Luckily, I saw on the Lazarus forum a new package Lazarus 1.9/FPC 3.2.0 Beta.
http://forum.lazarus-ide.org/index.php/ … ajilg0#new
https://sourceforge.net/projects/lazaru … ndow%2032/
https://sourceforge.net/projects/lazaru … ndow%2064/
I installed this and it compiled the latest mORMot releases flawlessly; I guess because the FPC compiler is more recent and so has the RTTI changes that NewPascal was created to handle. It also compiled the old code I was keeping Lazarus 1.8.4/FPC 3.0.4 around for.
So it looks like I may move ALL my projects to Lazarus 1.9/FPC 3.2.0 Beta and get rid of my existing NewPascal & Lazarus 1.8.4/FPC 3.0.4 combo.
I encourage you to try it. It may be the solution to your problem.
I can confirm that the line
Line 56267: ParamName := @VMP^.Name; is compiled properly
Cheers,
JD
I have the same problem. My server is developed using NewPascal BUT the client was developed using Lazarus/FPC 1.8.4; I have to do that because NewPascal cannot compile certain components that I'm using client-side.
NewPascal compiles the newest mORMot but Lazarus/FPC 1.8.4 does not because of the new typeinfo code
type
/// some type definition to avoid inclusion of TypInfo in main SynCommons.pas
PRecInitData = TypInfo.PRecInitData;Is there any way to use say {$define} to smartly get around this constraint.
Thanks a million,
JD
I fully understand where you all are coming from. There is so much to learn in mORMot and I started toying with it in 2015. mORMot has the largest user documentation I've ever encountered outside of PostgreSQL user documentation. It took me over a year before I was able to build a mORMot application. I only know about 40% of mORMot. I completely ignored the ORM/SQLite part and my mORMot server talks to a PostgreSQL database using Zeos.
I was finally able to get going thanks to George's Third Party demo
https://github.com/synopse/mORMot/tree/ … EST-tester
That in addition to the demos referenced by edwinsn in earlier in this thread helped me build my application. My requirements were simple; I wanted
a) an interface based application
b) service oriented architecture (SOA)
b) working over HTTP
c) using JSON to move data from the server to the clients
d) my PostgreSQL database handles user authentication (I don't use the ORM authentication part of mORMot OR any ORM features at all)
These requirements helped me streamline my research and I now have a working application thanks also to the wonderful advice I got from this forum. I still have work to do because I have not succeeded in encrypting the JSON data in transit. I can compress it but I have not yet fathomed how to move from HTTP to WebSockets.
So I would advice you to start small, streamline your needs and let them guide your research. You'll discover that it will be worth your efforts in the long run because I've discovered that using SOA with mORMot allows me to add new functionalities/services very quickly without breaking existing services. That is a very important issue for me. So, all the best.
Cheers,
JD
Hi JD,
{$if defined(ZEOS73UP) and defined(USE_SYNCOMMONS)} fResultSet.ColumnsToJSON(WR); {$ELSE} ...as Arnaud wrote: the IZResultSet.ColumnsToJSON is part of Zeos, defined in ZDbcIntfs.pas.
It skips the interface calling chain and brings best performance per driver to write the JSON contents.I wonder about your regression. As the define shows, you can use the procedure only if both defines are enabled.
The ZEOS73UP define is located in Zeos.inc (included in SynDBZeos.pas) and available only in the 7.3 branches.
Secondary define is your choice to define it in your Project.Check old revisions of zeos on your computer. It looks to me like your mixing old files somewhere. Check the USE_SYNCOMMONS define too.
@hnb
great news for Zeos, thank to all.
Hi there Michael,
I am talking about 3 separate computers here. My Windows 7 laptop has the newest NewPascal, mORMot and Zeos, that is the one on which I am trying to get ColumnsToJSON to work.
My Windows 7 desktop has older versions of all three, all is well over there as it does not use ColumnsToJSON (I checked it)
. On my desktop the line 61 of Zeos.inc was undefined by default.
I have a third Linux laptop with older versions where compilation is OK there too.
I still persist in saying I did not define USE_SYNCOMMONS in line 61 of Zeos.inc of the Zeos version I downloaded this morning.
Cheers,
JD
EDIT: Sorry I reported your post by mistake ![]()
This was some time ago, when I was part of FPC core team and NewPascal was almost integrated with official FPC page... Now I have ban in FPC core mailing list and I don't have access to trunk anymore - there is no rational reason for my banishment... I am not able to provide any updates, bug fixes nor new features into FPC trunk. Political decision and revenge of one person in core team...
Anyway still nothing wrong with using FPC trunk instead of NewPascal - individual decision
.
I read what you posted on the Lazarus forum and I was not happy. We are a small community and we need each other so that the project can move forward and stay alive.
Maybe you should accept Thaddy's offer of mediation so that we can get over this speedbump and move forward.
JD
ColumnsToJSON is part of Zeos, not mORMot.
You enabled it by defining the conditional.As side effect, it will be faster, since Zeos will directly generate the JSON for you.
Hi there ab,
I did not define the conditional. It was defined in the most recent version of Zeos that I downloaded from NewPascal GitHub. I have an older version of Zeos 7.3 alpha where it was undefined. I just verified that.
So what do I do now, I like the extra speed gains ColumnsToJSON will bring to my server? ![]()
Should we bring EgonHugeist/Michael into the picture?
Cheers,
JD
Probably you need latest Zeos (I am not sure here), you can download proper/newest version of Zeos here : https://github.com/newpascal-ccr/zeos
Zeos will be part of next release of NewPascal like mORMot
.
There is still a problem somewhere. I did as you suggested and got Zeos from the link you provided but the result was the same.
I got the following error message as before in SynDBZeos.pas:
SynDBZeos.pas(1248,14) Error: identifier idents no member "ColumnsToJSON"The line with the problem is as follows:
{$if defined(ZEOS73UP) and defined(USE_SYNCOMMONS)}
fResultSet.ColumnsToJSON(WR);
{$ELSE}However, when I edited line 61 of Zeos.inc and undefined USE_SYNCOMMONS like this:
{.$DEFINE USE_SYNCOMMONS} //enable JSON content support by using SynCommons.pas from Synopse projectI was then able to compile my project. So it looks like the problem comes from how Zeos 7.3 and above are supposed to use SynCommons.pas.
I was unable to locate the method ColumnsToJSON in SynCommons.pas so where is this method located?
Ideally, I would prefer to be able to export resultsets to JSON using ColumnsToJSON as expected.
While this "workaround" enabled me to compile my project, what are the side-effects in terms of speed of the REST server's
handling of queries?
Cheers,
JD
Hi all,
I'm going with NewPascal option 2 for the moment.
a) I used fpcupdeluxe to download and build NewPascal (07/05/2018)
b) I got a new version of mORMot from GitHub (07/05/2018)
c) I set everything up and compiled TestSQL3 successfully
d) I now went back to my project and tried to recompile it
I got the following error message in SynDBZeos.pas:
SynDBZeos.pas(1248,14) Error: identifier idents no member "ColumnsToJSON"The line with the problem is as follows:
{$if defined(ZEOS73UP) and defined(USE_SYNCOMMONS)}
fResultSet.ColumnsToJSON(WR);
{$ELSE}The OPM tells me I'm using Zeos 7.3. How do I correct this problem?
Cheers,
JD
Ah! that is the problem. My mORMotWrappers.pas line 724 is different from what AOG posted.
Mine looks like this:
FillDescriptionFromSource(fDescriptions,fSourcePath[i]+unitName+'.pas');In addition, my project refers to mORMot stored in its own directory somewhere where it can be shared between NewPascal, Lazarus & Delphi.
So I guess the way forward would be to remove this external references/configuration and rely solely on the preconfigured NewPascal version (at least for future NewPascal projects).
JD
Hi there Maciej. Is mORMot integrated into NewPascal or can I continue to update mORMot using its regular download link?
If mORMot is in NewPascal, in what directory can i find it?
Thanks,
JD
Hi there Don Alfredo. I have an older version of mORMot on my system. Does this mean I have to update mORMot too?
Hi there everyone,
I want to thank everyone that has made mORMot a wonderful framework for Delphi/Lazarus development. I've been using NewPascal 1.7 to develop a mORMot server for my Lazarus based clients.
Today I just used fpcupdeluxe to update my old NewPascal (with Lazarus IDE version I.7) to NewPascal (with Lazarus IDE version 1.9) and when I tried to recompile my program, I got the following error on line 724 in mORMotWrappers.pas
mORMotWrappers.pas(724,75) Error: Incompatible type for arg no. 2: Got "Variant", expected "TFileName"I can no longer compile anything in mORMot because of this error. Even compiling the example programs fails.
Can anyone please help me get around this problem?
Cheers,
JD
This is as expected. Check the doc: there is a "magic" character at the beginning of the field.
Then, when it is bound to the statement, it will use BindDateTime() with the raw value.I have added Iso8601ToSQL() function yesterday, so you need to update the mORMot source code.
Hi there ab,
Thanks for your suggestions. I'm afraid it still does not work. I now keep getting this error
SQL Error: ERROR: invalid input syntax for type timestamp: “ ”
The input is still the same, it is a timestamp like the following
2017-12-11T14:00:00
2017-12-11T16:00:00I have even replaced the 'T' with a blank space, to no avail. I keep getting the same error.
Please help!!!
JD
Iso8601ToDateTime() is part of SynCommons.pas.
Ensure you have the latest unstable version of the framework, i.e. 1.18.4068.
Thanks for your reply ab. Sorry, I meant to say Iso8601ToSQL() function.
I changed StrToDateTime() to Iso8601ToDateTime() and tried again with
aServer.fDbProps.ExecuteNoResult(
'INSERT INTO tvp_event (starttime, endtime) ' +
'VALUES (?,?) ',
[DateTimeToSQL(Iso8601ToDateTime(VariantToUTF8(vJSEvents.Value(0).StartTime))),
DateTimeToSQL(Iso8601ToDateTime(VariantToUTF8(vJSEvents.Value(0).EndTime)));This time I got the following exception which was thrown on line 705 of ZDbcPostgreSqlUtils.pas
EZSQLException with message: SQL Error: ERROR invalid entry syntax for the type timestamp << >>
I then used ShowMessage to see what the DateTimeToSQL functions above were returning and I saw the following
□2017-12-11T14:00:00
□2017-12-11T16:00:00The function is returning text with small rectangles in fromt of the text! The decimal 9633 (or the hexadecimal u25A1).
How do I fix this?
JD
I guess this is because you are using Delphi RTL's StrToDateTime() which does not support ISO-8601 encoded date time.
Try with SynCommons' Iso8601ToDateTime() instead.
Or, for your specific case, directly the Iso8601ToSQL() function.
Where is the Iso8601ToDateTime() function? It does not seem to be in SynCommons.pas. It is only mentioned on line 357 in the statement below:
- new DateToSQL(), DateTimeToSQL() and Iso8601ToSQL() functions, returning
a string with a JSON_SQLDATE_MAGIC prefix and proper UTF-8/ISO-8601 encoding
to be inlined as ? bound parameter in any SQL query (allow binding of
date/time parameters as request by some external database engine
which does not accept ISO-8601 text in this case)Thanks,
JD
Hi there everyone,
I'm trying to update some fields in an external PostgreSQL database that I connect to using mORMot/Zeos. The fields that are causing problems are of type timestamp. The DateTimeToSQL function is not working for me.
A client sends a timestamp value of say "2017-12-11T15:30:00" to my mORMot server. I try to insert it into the PostgreSQL table using
aServer.fDbProps.ExecuteNoResult(
'INSERT INTO %s.tvp_event (starttime, endtime) ' +
'VALUES (?,?) ',
[DateTimeToSQL(StrToDateTime(VariantToUTF8(vJSEvents.Value(0).StartTime))),
DateTimeToSQL(StrToDateTime(VariantToUTF8(vJSEvents.Value(0).EndTime)))]);I got an error saying "2017-12-11T15:30:00" is not a valid time
I then used StringReplace to remove the 'T' and replace it with a blank space. I tried again with
aServer.fDbProps.ExecuteNoResult(
'INSERT INTO %s.tvp_event (starttime, endtime) ' +
'VALUES (?,?) ',
[DateTimeToSQL(StrToDateTime(StringReplace(VariantToUTF8(vJSEvents.Value(0).StartTime), 'T', ' ', [rfReplaceAll]))),
DateTimeToSQL(StrToDateTime(StringReplace(VariantToUTF8(vJSEvents.Value(0).EndTime), 'T', ' ', [rfReplaceAll])))]);This time, I got an error saying "2017-12-11" is not a valid date format
What am I doing wrong?
Thanks,
JD
The Atozed forum has been offline for more than a year.
The active Indy forum is in the Winsock section of the Embarcadero forum at https://forums.embarcadero.com/forum.jspa?forumID=74
JD
Okay, okay, I will add it!
Thanks a lot!
I fully agree and I would love to see this functionality
Hi there,
I can answer part 2 because I just got it to work for me. The small server-side method below inserts a new record in the country table. Note that fDbProps is of type TSQLDBConnectionProperties so you can use its Execute or ExecuteNoResult among other to execute pure SQL commands
function TRESTMethods.Country(aSchema: string; const aID: string; aDTO: RawJSON): RawJSON;
var
Res: ISQLDBRows;
aObj: TSQLCountry;
begin
aObj := TSQLCountry.Create;
try
ObjectLoadJSON(aObj, aDTO); // Load JSON into object
Res := aServer.fDbProps.Execute(Format('INSERT INTO %s.country (name) VALUES (?) RETURNING country_id', [aSchema]), [aObj.Name]);
while Res.Step do
Result := Format('{"ID": "%s"}', [VariantSaveJSON(Res['country_id'], twNone)]);
finally
aObj.Free;
end;
end;See https://stackoverflow.com/a/22078557/458259 for an example of how to call it with HTTP post
Hope it helps,
JD
How?
It will depend on which library you are using for the client...Using SynCrtSock.pas it is as simple as calling the Post() method.
See e.g. https://stackoverflow.com/a/22078557/458259
Eureka! That's it. Thanks a lot ab. That was what I was looking for.
JD
I am not sure that I understand what you mean, and where your problem is, sorry...
Instead of sending JSON parameters in the URI to an interface based mORMot server, I want to send it in the message body. I essence, how do you do the following in a mORMot client (taken from mORMot documentation section 16.8.6.1.1.4. Sending a JSON object)?
POST /root/Calculator.Add
(...)
[1,2] That POST sends [1,2] in the message body. How? I would love to see sample code.
Thanks
JD
Use the cross platform units to create your Indy client.
See the documentation.
I already have a working client. I am porting a large application to mORMot. I'm not using the ORM part of mORMot. I've decided to start with rewriting the existing Indy server using mORMot interface based services and that is moving along fine. On the client side, there is a GUI and a transport layer. The transport layer is Indy based and is what sends and receives data from the server. I don't intend to change the client side GUI since it is agnostic (it does not know how data is sent/received). It is the transport layer that I'm trying to rewrite using mORMot. At present, the following have been implemented client-side
a) sending requests (querying PostgreSQL tables) to the new mORMot server
b) modifying data in the remote tables (the catch here is that the data is sent in the URI respecting the limits of URI length)
The mORMot documentation says the following
Note that there is a known size limitation when passing some data with the URI over HTTP. Official RFC
2616 standard advices to limit the URI size to 255 characters, whereas in practice, it sounds safe to
transmit up to 2048 characters within the URI. If you want to get rid of this limitation, just use the
default transmission of a JSON array as request body.This is the catch ..... just use the default transmission of a JSON array as request body.
My BIG TO-DO
- some requests are to be made on some large tables. SELECT * will waste bandwidth and will be slow. Selecting ONLY the needed columns is the best strategy but the URI will be too long. So I HAVE to send the SQL via the request body like I've already done with Indy.
The problem is I do not know how to read/write to the URI request body, and I've not seen an example of it yet though I'm still searching Section 16.8.6.1.1. REST mode in the documentation is not clear to me as to how it can be done
The phrase request body occurs only 2 times in the mORMot documentation. The first one is cited above while the second one is
procedure ProcessRequest; virtual;
Method triggered to calculate the response
- expect fRequestHeaders, fRequestMethod, fRequestBody and fRequestURL properties as input
- update fResponseHeaders and fResponseContent properties as output Conclusion
I am hoping to use solely a service interface based mORMot server. Is it possible to pass parameters to the interfaces via the request body? If so how do I do it? Or must I mix service methods with service interfaces and then use the Ctxt parameter of service methods to access the message body?
Thanks a lot,
JD
Put the parameters as a JSON object in the body of a POST request.
Hi there ab,
That is just what I need to know. My interface method signature is
function TRESTMethods.Country(aSchema: string; const aID: string; aDTO: RawJSON): RawJSON;In body of the function, if aDTO is an empty string, it is treated as a GET request and if aDTO is not empty, it is treated as a POST/PUT request. Using the contents of aDTO has helped me remove the dependence on HTTP verbs. I know how to send a POST request in the URI on one line when the function is called on the client side like this
Client.Country('public', ' ', '{"id":"0","name","Barbados"}');and it works!
I want to know how to add the JSON object {"id":"0","name","Barbados"} to the request body so that I don't end up having long URIs.
For example in Indy 10, I can do this https://mikejustin.wordpress.com/2015/0 … ttps-post/ or this https://stackoverflow.com/questions/422 … https-post
Indy 10's HTTP.Post is an overloaded function/procedure that can be used to send requests and receive responses. What is the equivalent of this in mORMot for interface based services? I've been looking at HTTPClient but I still have not found it.
Thanks a lot,
JD
Thanks for your reply ab. I've modified the method and removed its dependence on REST/HTTP verbs. Now it works as it should.
However since URI size is limited to 255 characters, can you please show me how I can send parameters as a JSON object or array in the request body. 16.8.6.1.1.4? Sending a JSON object in the documentation does not provide an example.
Thanks a lot,
JD
Hi there,
I'm a little confused about how to perform HTTP GET/POST from Delphi/Lazarus clients. I've been going through the documentation but it is still not very clear to me. I am using ServiceContext.Request.Method to distinguish between the two commands in an interface method. The REST method is as shown below (I tried to keep it as short and readable as possible to not break forum rules):
function TRESTMethods.Country(aSchema: string; const aID: string; aDTO: RawJSON): RawJSON;
var
Res: ISQLDBRows;
aObj: TSQLCountry;
begin
case ServiceContext.Request.Method of
mGET:
begin
Res := aServer.fDbProps.Execute(Format('select id, name from %s.country where id=?', [aSchema]), [aID])
Result := Res.FetchAllAsJSON(True);
end;
mPOST:
begin
aObj := TSQLCountry.Create;
try
ObjectLoadJSON(aObj, aDTO); // Load JSON into object
Res := aServer.fDbProps.Execute(Format('INSERT INTO %s.country (name) VALUES (?) RETURNING country_id', [aSchema]), [aObj.Name]);
while Res.Step do
Result := Format('{"ID": "%s"}', [VariantSaveJSON(Res['country_id'], twNone)]);
finally
aObj.Free;
end;
end;
end;
end;The problem is that when I call it from a browser or from a REST client using
http://localhost:888/service/myapi/country?aschema=publicthe code under mGET is executed as expected.
But when I try to call it from a Lazarus client using
if Client.Services['MyAPI'].Get(I) then
Memo1.Lines.Add(I.Country('public', '', ''));it tries to execute the mPOST portion of the code and fails obviously.
Questions
a) how do I send GET/POST and other HTTP commands like PUT & DELETE from a Lazarus client to my REST method above
b) I would prefer to send POST and PUT information via the message body instead of the URI. How can I do this from a Lazarus client?
Thanks a lot for your kind assistance
JD
Hi there,
I just want to report that I'm currently testing mORMot (using SynDBZeos) with the recently released PostgreSQL 10. And my mORMot test application is working smoothly without problems.
JD