You are not logged in.
Should be fine now.
Now all fine, thank you very much!
DelphiXE, thanks!
a little compile hit and warning
[DCC Hint] SynTable.pas(4900): H2443 Inline function 'TSynLocker.Lock' has not been expanded because unit 'Windows' is not specified in USES list
[DCC Hint] SynTable.pas(4908): H2443 Inline function 'TSynLocker.UnLock' has not been expanded because unit 'Windows' is not specified in USES list
[DCC Warning] mORMotReport.pas(1664): W1057 Implicit string cast from 'AnsiString' to 'string'
[DCC Warning] mORMotReport.pas(1674): W1057 Implicit string cast from 'AnsiString' to 'string'
thanks!
Please try https://synopse.info/fossil/info/4e5384f8f7
As always, works like a charm, thank you very much!
Hi,
I have a running program, today i update mORMot to last 4322 trunk, from browser get a file will get a EAccessViolation,
i debug found when call function ExistsIniName(P: PUTF8Char; UpperName: PAnsiChar): boolean; parameter P is nil,
procedure TSQLRestServerURIContext.ReturnFile(const FileName: TFileName;
Handle304NotModified: boolean; const ContentType,AttachmentFileName,
Error404Redirect: RawUTF8);
var FileTime: TDateTime;
clientHash, serverHash: RawUTF8;
begin
...
if not ExistsIniName(pointer(Call.OutHead),HEADER_CONTENT_TYPE_UPPER) then begin ==>run into ExistsIniName produce av
...
end;
DelphiXE with 4322 mORMot
thanks!
Such buffer overflows can be tricky to fix.
something need to learn, thank your share!
After test, I confirm AV gone, server is still online.
Wonderful, you are a super man!
thanks!
Further debug, after first "Wrong PUT" error, subsequent BatchUpdate generate av at
function TSQLRequest.Step: integer;
{$ifdef RESETFPUEXCEPTION} // safest to reset x87 exceptions - inlined TSynFPUException
var cw87: word;
{$endif}
begin
if Request=0 then
raise ESQLite3Exception.Create(RequestDB,SQLITE_MISUSE,'Step');
{$ifdef RESETFPUEXCEPTION}
cw87 := Get8087CW;
try
{$endif}
result := sqlite3_check(RequestDB,sqlite3.step(Request),'Step'); //<==== here generate av
{$ifdef RESETFPUEXCEPTION}
finally
Set8087CW(cw87);
end;
{$endif}
end;
can't debug further because my ability, seem all av relative to the first "Wrong PUT" error.
When debug first "Wrong Put" error, follow step also generate some av, and when you close
applicaiton directly, final will have Runtime error 216.
thanks!
The context is unclear...
Is there a "Wrong PUT" error before, or after the AV?
"Wrong PUT" error is first, this is the call stack
:76c85608 KERNELBASE.RaiseException + 0x48
mORMot.TSQLRestServer.EngineBatchSend(nil,'["automaticTransactionPerRow",2147483647,,"PUT@VoyageFee",{"ID":null,"Flag":1,"UpdateBy":"User","UpdateTime":1499911738644,"RemoteIP":"127.0.0.1"},"PUT@VoyageFee",{"ID":3096,"Flag":1,"UpdateBy":"User","UpdateTime":1499911738644,"RemoteIP":"127.0.0.1"},"PUT@VoyageFee",{"ID":3086,"Flag":1,"UpdateBy":"User","UpdateTime":1499911738644,"RemoteIP":"127.0.0.1"},"PUT@VoyageFee",{"ID":3084,"Flag":0,"DoneBill":1,"UpdateBy":"User","UpdateTime":1499911738644,"RemoteIP":"127.0.0.1"},"PUT@VoyageFee",{"ID":3086,"Flag":0,"DoneBill":1,"UpdateBy":"User","UpdateTime":1499911738644,"RemoteIP":"127.0.0.1"},"PUT@VoyageFee",{"ID":3096,"Flag":0,"DoneBill":1,"UpdateBy":"User","UpdateTime":1499911738644,"RemoteIP":"127.0.0.1"},"PUT@VoyageFee",{"ID":null,"Flag":0,"DoneBill":1,"UpdateBy":"User","UpdateTime":1499911738644,"RemoteIP":"127.0.0.1...
mORMot.TSQLRestServer.Batch($221C680)
uShipAgentRestServer.TShipAgentRestServer.ApplyUpdates($221C680)
mORMot.TSQLRestServerURIContext.ExecuteSOAByMethod
mORMot.TSQLRestServerURIContext.ExecuteCommand
mORMot.TSQLRestServer.URI($54CFD80)
mORMotHttpServer.TSQLHttpServer.Request($22B78D8)
SynCrtSock.THttpServerGeneric.Request($22B78D8)
SynCrtSock.THttpServer.Process($22152E0,4,$22CC2F8)
SynCrtSock.THttpServerResp.Execute
:004574b9 ThreadProc + $45
:00407e4a ThreadWrapper + $2A
:76e97c04 KERNEL32.BaseThreadInitThunk + 0x24
:7718ad2f ntdll.RtlInitializeExceptionChain + 0x8f
:7718acfa ntdll.RtlInitializeExceptionChain + 0x5a
after wrong Put, BatchUpdate will error, there have two debug Exception Notification:
when click Break, the first callstack is
:76c85608 KERNELBASE.RaiseException + 0x48
SynSQLite3Static.sqlite3_realloc($2212F78,145)
the second callstack is
:76c85608 KERNELBASE.RaiseException + 0x48
:00407224 NotifyNonDelphiException + $1C
:7716ff13 ;
SynCommons.MoveX87
:7717068f ntdll.KiUserExceptionDispatcher + 0xf
SynLog.TSynMapFile.Log($22CC7D8,6696455,False)
SynLog.TSynLog.AddStackTrace(nil)
SynLog.TSynLog.LogInternal(sllError,'% for % // %',(...),$288E960)
SynLog.TSynLog.Log(sllError,'% for % // %',(...),$288E960)
mORMot.TSQLRest.InternalLog('% for % // %',(...),sllError)
mORMotSQLite3.TSQLRestServerDB.GetAndPrepareStatementRelease($22AD0F8,'')
mORMotSQLite3.TSQLRestServerDB.InternalExecute('UPDATE InvoiceType SET Attribute=:(''5''):,UpdateBy=:(''User''):,UpdateTime=:(1499911820772):,RemoteIP=:(''127.0.0.1''): WHERE RowID=:(4):;',False,nil,nil {''},nil,nil,nil)
mORMotSQLite3.TSQLRestServerDB.EngineExecute('UPDATE InvoiceType SET Attribute=:(''5''):,UpdateBy=:(''User''):,UpdateTime=:(1499911820772):,RemoteIP=:(''127.0.0.1''): WHERE RowID=:(4):;')
mORMot.TSQLRest.ExecuteFmt('UPDATE % SET % WHERE RowID=:(%):;',(...))
mORMotSQLite3.TSQLRestServerDB.MainEngineUpdate(23,4,'{"Attribute":"5","UpdateBy":"User","UpdateTime":1499911820772,"RemoteIP":"127.0.0.1"}')
mORMot.TSQLRestServer.EngineUpdate(23,4,'{"Attribute":"5","UpdateBy":"User","UpdateTime":1499911820772,"RemoteIP":"127.0.0.1"}')
mORMot.TSQLRestServer.EngineBatchSend(nil,'["automaticTransactionPerRow",2147483647,"PUT@InvoiceType'#0#0'{"ID":4{"Attribute":"5","UpdateBy":"User","UpdateTime":1499911820772,"RemoteIP":"127.0.0.1"}]',(304),0)
mORMot.TSQLRestServer.Batch($221C680)
uShipAgentRestServer.TShipAgentRestServer.ApplyUpdates($221C680)
mORMot.TSQLRestServerURIContext.ExecuteSOAByMethod
mORMot.TSQLRestServerURIContext.ExecuteCommand
mORMot.TSQLRestServer.URI($54CFD80)
mORMotHttpServer.TSQLHttpServer.Request($22B78D8)
SynCrtSock.THttpServerGeneric.Request($22B78D8)
SynCrtSock.THttpServer.Process($22152E0,5,$22CC2F8)
SynCrtSock.THttpServerResp.Execute
:004574b9 ThreadProc + $45
:00407e4a ThreadWrapper + $2A
:76e97c04 KERNEL32.BaseThreadInitThunk + 0x24
:7718ad2f ntdll.RtlInitializeExceptionChain + 0x8f
:7718acfa ntdll.RtlInitializeExceptionChain + 0x5a
I use this code make test:
TShipAgentRestServer= class(TSQLRestServerDB)
private
f: boolean;
publshied
procedure ApplyUpdates(Ctx: TSQLRestServerURIContext);
procedure TShipAgentRestServer.ApplyUpdates(Ctx: TSQLRestServerURIContext);
var
tempStr: rawUTF8;
begin
if not f then begin
Tempstr := AnyTextFileToRawUTF8('error.json');
Ctx.Call.InBody := TempStr;
f := True;
end else begin
Tempstr := AnyTextFileToRawUTF8('good.json');
Ctx.Call.InBody := TempStr;
end;
Batch(Ctx);
end;
error.json
["automaticTransactionPerRow", 2147483647, "PUT@VoyageFee", {
"ID": 3084,
"Flag": 1,
"UpdateTime": 1499822856618,
"RemoteIP": "127.0.0.1"
}, "PUT@VoyageFee", {
"ID": 3096,
"Flag": 0,
"UpdateTime": 1499822856618,
"RemoteIP": "127.0.0.1"
}, "PUT@VoyageFee", {
"ID": null,
"Flag": 1,
"UpdateTime": 1499822856618,
"RemoteIP": "127.0.0.1"
}, "PUT@VoyageFee", {
"ID": 3098,
"Flag": 1,
"UpdateTime": 1499822856618,
"RemoteIP": "127.0.0.1"
}]
good.json
["automaticTransactionPerRow", 2147483647, "PUT@VoyageFee", {
"ID": 3084,
"Flag": 1,
"UpdateTime": 1499822856618,
"RemoteIP": "127.0.0.1"
}, "PUT@VoyageFee", {
"ID": 3096,
"Flag": 0,
"UpdateTime": 1499822856618,
"RemoteIP": "127.0.0.1"
}, "PUT@VoyageFee", {
"ID": 3098,
"Flag": 1,
"UpdateTime": 1499822856618,
"RemoteIP": "127.0.0.1"
}]
make a web client, call ApplyUpdates with any success content,
first call trigger error, then subsequent call will error,
Use DelphiXE, mORMot 3705, thanks!
using TSQLRestServerDB, when a error batchupdate cause by "EngineBatchSend: Wrong PUT",
then subsequent batchupdate will generate Server Error 500: Internal Server Error.
Debug find av occur at
function TSQLRestServerDB.InternalExecute(const aSQL: RawUTF8;
if (ValueInt=nil) and (ValueUTF8=nil) then begin
// default execution: loop through all rows
repeat until fStatement^.Step<>SQLITE_ROW; //<====== av occure at here,
//raised exception class EAccessViolation with message 'Access violation at address 006BE19C
thanks!
My mistake, need set the object name
HeaderDoc := Ctx.Request.Server.RetrieveDocVariantArray(TSQLTest,'header','ID IN (' + IDs + ')', [], '*')
Hi, I use below code to generate content, when run will generate ESynException, but if debug step by step, will ok,
var
HeaderTemplate, LineTemplate, IDs, HeaderContent, LineContent: RawUTF8;
Ctx: PServiceRunningContext;
Mustache: TSynMustache;
HeaderDoc, LineDoc: Variant;
begin
...
HeaderDoc := Ctx.Request.Server.RetrieveDocVariantArray(TSQLTest,'','ID IN (' + IDs + ')', [], '*');
Mustache := TSynMustache.Parse(HeaderTemplate);
HeaderContent := Mustache.Render(HeaderDoc); //==>here Generate ESynException
...
where is the problem, any suggestions is welcome, thanks!
Mingda
Have test, confirm it works now,
Can the empty between helper function and variable also support multi space, thanks!
Also If the space before comma can ignore then will Perfect.
I just test Mustache, i found Expression helpers error prone, i want to change date display format,
so use {{datefmt Birthday, "YYYY-MM-DD"}}, but found not success, after debug, i found this is
because there is a space after comma, can enhance to let Mustache auto ignore the space,
end user easy make this mistake, thanks!
Mingda
Are you sure your crypt salt rounds was 10000 ?
In unlock.bat i remove the salt, let input through console, ecc's default salt is 60000,
so this is the problem, after salt rounds change to 10000, test is pass,
Encryption is very interesting, thank you very much!
One of the decryption parameters doesn't match the encryption parameter, I guess.
I start a fresh new test, make applock keys, except issuer, passPhrase of .private, all parameter else is the ecc tool default value,
user@host key, is auto generated by the call ECCAuthorize,
var
S: PShortString;
r: TECCAuthorize;
begin
r := ECCAuthorize(FAppSecret, 0, '', 'abc', '', AppLockPublic64);
S := ToText(r);
ShowMessage(UTF8ToString(ShortStringToUTF8(s^)));
end;
so the parameter is
aSecretDays := 0;
aSecretPass := '';
aDPAPI := 'abc';
aDecryptSalt := '';
aAppLockPublic64 is copy from applock.public's base64 value;
1. call unlock.bat to use applock private key to sign user@host.json,
2. use user@host.public key to crypt user@host.json,
3. copy the new .json.synecc file to the test program,
4. rename it to .unlock file, then run, the same route, not success,
where is wrong, thanks!
I'm learn Application Locking through doc.
Through these step:
1. first make a SelfSigned public and private key
2. make a test program, put a button
procedure TForm1.Button1Click(Sender: TObject);
const
AppLockPublic64 = 'AQD9AP0AagIODCLNMfBnPirgW4w/EasRLQ1h6CyAAAAAAAAAAAAAAA4MIs0.....';
var
S: PShortString;
r: TECCAuthorize;
begin
r := ECCAuthorize(FAppSecret, 0, '', 'abc', '', AppLockPublic64);
S := ToText(r);
ShowMessage(UTF8ToString(ShortStringToUTF8(s^)));
end;
AppLockPublic64 is copy from public key's "Base64" value, run and click button, will get
another two user@host public and private file,
copy user@host.public to app.public directory, and make a user@host.json file, content is :
{
"Root": "TestRoot"
}
run the bat file
@echo off
echo Usage: unlock user@host
echo.
ecc sign -file %1.json
ecc crypt -file %1.json
del %1.json.sign
use user@host.public to crypt, after crypt, rename the user@host.json.synecc file to user@host.unlock,
then copy it to test program's exe directory, click button1, but still show eaInvalidUnlockFile, after debug, the call
decrypt := priv.Decrypt(unlock, json, @signature, nil, nil, aDecryptSalt, 10000);
decrypt return value is ecdDecryptError, what's wrong with my test, thanks!
Mingda
@Junior/RO
I use 3469,
@EMartin
Sorry, I can't reach the google site, only update from ab's
thank you two!
when I do report, i use ExecuteJson to get a sql json resut, then convert to TSynSQLTableDataSet,
json := Client.ExecuteJson([], DataSetSql);
JSONTODataSet(nil, Json),
just found, if there is only one row, if a RawUTF8 string field has 2017-02-27 content,
in the json content look like this, "XXX":"2017-02-27", then report engline use
FValue := DataSet.Value[DataField];
to get value will generate AV '0.42793' is not a valid timestamp, seems the underline
field treat as datetime, how can resolve this.
Any help very thanks!
update:
I think if can manul set the field type, then will ok, I'll test this method.
update2:
Seems the under TSQLTable can SetFieldType, but the TSynSQLTableDataSet's field type
can't change, in
function TSynVirtualDataSet.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
Data := GetRowFieldData(Field,RowIndex,DataLen,OnlyTestForNull);
GetRowFieldData can work, but next run to
ftDateTime:
PDateTimeRec(Dest)^.DateTime := PDateTime(Data)^;
after that has become '0.0' is not a valid timestamp
update 3:
First create a TSQLTable, manual set field type, then use it create DataSet seems resolve the problem.
Mingda
And with https://synopse.info/fossil/info/19d1a8c122 ?
strange, after update, the fastreport connect to the dynamic create dateset, (TSynSQLTableDataSet create by JSONToDataSet in mORMotVCL) still display integer value. (By the way, you are a super man. )
update:
Perhaps i use raw sql to get the result, and column name use alias, in the json result, there is no column type info, like below
DataSetSql := 'select columnA aliasA, columnB aliasB from table';
Json := Client.ExecuteJson([], DataSetSql);
if Json = '' then Continue;
ReportDataSetDynArray[I].Dataset := JSONTODataSet(nil, Json);
Use TUnixTime or TUnixMSTime types.
Just test, JSONToDataSet in mORMotVCL not deal with TUnixMSTime type, still show it's int64 value, -:(
For javascript datetime just integer value for milliseconds since midnight on January 1, 1970, when transmit json, encode just like integer, so i define it like this:
TTimeStamp = type Int64;
TSQLBase = class(TSQLRecord)
private
fEta: TTimeStamp;
published
property Eta: TTimeStamp read fEta write fEta;
this is all ok until now, now i need to generate report, i use
JSONToDataSet in unit mORMotVCL to convert json to TSynSQLTableDataSet,
but the datetime all display it's integer value, is there any method
let the javascript datetime to display ok, any suggest is welcome, thanks!
Mingda
this is perfect, thank you very much!
Can change MAX_SQLFIELDS default value to 128, current 64 everytime after update i need change, thanks!
Also current 3449 builder testSQL3 after run, when close has memory leak report:
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:
85 - 92 bytes: TSynThreadPoolSubThread x 32
thanks!
what's your version , in 2915 TDynArrayHashed has a fix, see http://synopse.info/fossil/info/ddc1dc3 … bb6a4a827a
The problem is indeed "ID":null caused, remove it works, I will update source to test, thank you very much!
use DelphiXE, for multi row insert, every loop EngineAdd return 0, but for single row, return correct ID, thanks!
sqlite3 db, a strange problem, from webclient, use BatchInsert, when only insert one row, in response text, can return the Insert ID, but when insert multi row, in response text, always return 0 ID
'["automaticTransactionPerRow",2147483647,"POST@test",{"ID":null,"Name":"B001","Question":"B001","Time":null}]'
return [87]
'["automaticTransactionPerRow",2147483647,"POST@test",{"ID":null,"Name":"A001","Question":"A001","Time":null},"POST@test",{"ID":null,"Name":"A002","Question":"A002","Time":null},"POST@test",{"ID":null,"Name":"A003","Question":"A003","Time":null}]'
return [0,0,0]
use version 2929
thanks
when reuse a cache statement
procedure TOleDBStatement.Reset;
begin
...
fColumn.Clear;
fColumn.ReHash;
...
end;
seems TDynArrayHashed.ReHash need add fHashsCount := 0
function TDynArrayHashed.ReHash(aHasher: TOnDynArrayHashOne=nil): boolean;
var i, n, cap, ndx: integer;
P: PAnsiChar;
aHashCode: cardinal;
begin
result := false;
fHashs := nil;
fHashsCount := 0; //add this to reset count
n := Count;
if (n=0) or (n<fHashCountTrigger) then
exit; // hash only if needed, and avoid GPF after TDynArray.Clear (Count=0)
in TDynArrayHashed.HashAdd sometimes fHashsCount = 256, but Length(fHashs)=0,
with fHashs[-result-1] do begin // HashFind returned negative index in fHashs[]
Hash := aHashCode;
Index := n;
end;
this cause write fHashs[-result-1] will generate AV(here result=-1),
but not every time this occure, i have a function like this:
function test(const aParam: RawUTF8; aConnection: TSQLDBConnection): Boolean;
var
sql: RawUTF8;
rows, updateStatement: ISQLDBStatement;
begin
rows := aConnection.NewStatementPrepared(sql, true);
if not Assigned(rows) then exit;
rows.Bind([aParam]);
rows.ExecutePrepared;
....
end;
below is log, thanks
20160901 07132747 EXCOS EAccessViolation (C0000005) at 00516473 SynCommons.TDynArrayHashed.HashAdd (42926) stack trace API 0051662B SynCommons.TDynArrayHashed.FindHashedForAdding (42960) 00516689 SynCommons.TDynArrayHashed.AddAndMakeUniqueName (42971) 0055C758 SynOleDB.TOleDBStatement.BindColumns (2215) 0055BDBD SynOleDB.TOleDBStatement.FromRowSet (2024) 0055B89B SynOleDB.TOleDBStatement.ExecutePrepared (1989) 006BF93F
constructor THttpClientSocket.Create(aTimeOut: cardinal);
begin
if aTimeOut = 0 then
inherited Create(aTimeOut) else
inherited Create(HTTP_DEFAULT_RECEIVETIMEOUT);
UserAgent := DefaultUserAgent(self);
end;
perhaps should be
constructor THttpClientSocket.Create(aTimeOut: cardinal);
begin
if aTimeOut = 0 then
inherited Create(HTTP_DEFAULT_RECEIVETIMEOUT) else
inherited Create(aTimeOut);
/*
//or
if aTimeOut = 0 then aTimeOut := HTTP_DEFAULT_RECEIVETIMEOUT;
inherited Create(aTimeOut);
*/
UserAgent := DefaultUserAgent(self);
end;
Merry Christmas to ab and all, wish everyone a safe and happy holiday!
I think you can make a test case for anyone else to trace the problem, let ab debug it easy.
Delphi XE,
just another hit, below new test have 2 not passed test
2.9. External database:
! - DB properties persistence: 2 / 7 FAILED 1.53ms
and current Synopse Library Test not enable in test
procedure TTestSynopsemORMotFramework.SynopseLibraries;
begin
//
exit;
AddCase([TTestLowLevelCommon,
thanks.
2.9. External database:
- TQuery: 2,003 assertions passed 28.40ms
- SynDBRemote: 30,095 assertions passed 822.17ms
! - DB properties persistence: 2 / 7 FAILED 1.53ms
- External records: 2 assertions passed 915us
- Auto adapt SQL: 708 assertions passed 105.48ms
- Crypted database: 253,275 assertions passed 435.42ms
- External via REST: 170,354 assertions passed 2.36s
- External via virtual table: 170,354 assertions passed 3.97s
- External via REST with change tracking: 180,454 assertions passed 6.62s
- JET database: 7,007 assertions passed 2.95s
Total failed: 2 / 814,259 - External database FAILED 17.32s
2.10. Multi thread process:
- Create thread pool: 1 assertion passed 30.42ms
- TSQLRestServerDB: 4,822 assertions passed 252.76ms
1=14324/s 2=9596/s 5=10028/s 10=8694/s 30=13298/s 50=8482/s
- TSQLRestClientDB: 4,822 assertions passed 266.99ms
1=12823/s 2=12215/s 5=12357/s 10=11306/s 30=8394/s 50=5517/s
- TSQLRestClientURINamedPipe: 2,412 assertions passed 1.67s
1=991/s 2=927/s 5=639/s
- TSQLRestClientURIMessage: 3,222 assertions passed 406.55ms
1=3281/s 2=4975/s 5=5341/s 10=3603/s
- Windows API: 4,822 assertions passed 1.65s
1=1256/s 2=1400/s 5=1669/s 10=1758/s 30=1696/s 50=1272/s
- Socket API: 4,822 assertions passed 929.12ms
1=3127/s 2=2939/s 5=3043/s 10=2881/s 30=2592/s 50=1967/s
recent, run Testsql3 multi times, sometimes the test run stop at TTestMultiThreadProcess.Websockets, output like above, and cpu is 100%, but this is not always, sometime just 1 of 5, thanks.
this change in http://synopse.info/fossil/info/612863b … 6fe445c06f cause testsql3 occur av, test DelphiXE, test {726} is ok, thanks.
I also found some problem relative TSQLDBConneciton TSQLDBConnectionProperties and the ClearConnectionPool, I first made this proposal ClearConnectionPool to fix the break connection, but now seem this fix is wrong, for Connection in ConnectionPool, every connection has different thread id, so every connection should free in their owner thread, this is particular for TOleDBMSSQLConnectionProperties, this also make use TSQLDBConnectionProperties.execute in thread should very careful, for RestServer we have EndCurrentThread call to release connection, but if directly use ConnectionProperties, then will no way to release the connection, current i have a backgroud thread to run, just after a day run, will not work, there is no memory leak, so i just change all TSQLDBConnectionProperties.execute to explicit new a Connection, then release it, today will test it, for release connection problem, this example can see this,
unit Unit6;
interface
uses
Classes, SynDB;
type
TTestThread = class(TThread)
private
{ Private declarations }
fProps: TSQLDBConnectionProperties;
protected
procedure Execute; override;
public
procedure SetSQLDBProperties(aProps: TSQLDBConnectionProperties);
end;
implementation
{ TTestThread }
procedure TTestThread.Execute;
begin
{ Place thread code here }
fProps.Execute('select * from test', []);
end;
procedure TTestThread.SetSQLDBProperties(aProps: TSQLDBConnectionProperties);
begin
fProps := aProps;
end;
end.
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SynCommons, SynDB, SynOleDB, StdCtrls, Unit6;
type
TForm5 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
fProps: TSQLDBConnectionProperties;
end;
var
Form5: TForm5;
implementation
{$R *.dfm}
procedure TForm5.Button1Click(Sender: TObject);
begin
Memo1.Text := UTF8ToString(fProps.Execute('select * from test', []).FetchAllAsJSON(true));
end;
procedure TForm5.Button2Click(Sender: TObject);
var
testThread: TTestThread;
begin
testThread := TTestThread.Create(true);
testThread.SetSQLDBProperties(fProps);
testThread.FreeOnTerminate := true;
testThread.Start;
end;
procedure TForm5.Button3Click(Sender: TObject);
begin
fProps.ClearConnectionPool;
end;
procedure TForm5.FormCreate(Sender: TObject);
begin
fProps := TOleDBMSSQLConnectionProperties.Create('localhost', 'testdb', '', '');
end;
procedure TForm5.FormDestroy(Sender: TObject);
begin
fProps.Free;
end;
end.
after you run a thread, then close the program or call ClearConnectionPool will see EAssertionFailed, don't know if your problem is this relative, thanks!
another function need consider, the TSQLRecord current don't have old value, for e.g. a object
TTest = class(TSQLRecord)
published
property column1 rawutf8;
property column2 rawutf8;
property column3 rawutf8;
...
end;
when two user read a object at same time, get the same object {"ID":1,"column1":"value","column2":"value","column3":"value"},
if userA update column1 to "value_updateA",
userB update column2 to "value_updateB",
current if userA update first, userB next, then the finally object value will be {"ID":1,"column1":"value","column2":"value_updateB","column3":"value"}, userA's change is lost,
if TSQLRecord have old value, use the old value generate upate sql,
userA update will generate
update Test set column1 = 'value_updateA' where id = 1 and column1 = 'value',
userB update will generate
update Test set column2 = 'value_updateB' where id = 1 and column2 = 'value',
this solve two problem, 1) update override other column's value 2) multi user update conflict.
for replication, if we have such journal,
1). {"ID":1,"column1":"value","column2":"value","column3":"value"}
2). {"ID":1,"column1":"value_updateA","column2":"value","column3":"value"}
3). {"ID":1,"column1":"value","column2":"value_updateB","column3":"value"}
after the last change merge, we only get the object value:
3). {"ID":1,"column1":"value","column2":"value_updateB","column3":"value"}, this is not expect.
if we have old value, such journal will look like such:
1). {"ID":1,"column1":"value","column2":"value","column3":"value"}
2). {"old record":{"ID":1,"column1":"value","column2":"value","column3":"value"},
"new record":{{"ID":1,"column1":"value_updateA","column2":"value","column3":"value"}}}
3).{"old record":{"ID":1,"column1":"value","column2":"value","column3":"value"},
"new record":{{"ID":1,"column1":"value","column2":"value_updateB","column3":"value"}}}
or we can have the not update empty:
1). {"ID":1,"column1":"value","column2":"value","column3":"value"}
2). {"old record":{"ID":1,"column1":"value","column2":"value","column3":"value"},
"new record":{{"ID":1,"column1":"value_updateA"}}}
3).{"old record":{"ID":1,"column1":"value","column2":"value","column3":"value"},
"new record":{{"ID":1,"column2":"value_updateB"}}}
then we can merge it to
{"ID":1,"column1":"value_updateA","column2":"value_updateB","column3":"value"}
this will greatly reduce conflict, for userA, userB update same column, such change later user
update will get conflict hit, since the update will failed.
just my personal thought, thanks!
Done, feature request at http://synopse.info/fossil/tktview/1d6b … dde1cdc0f6, thanks!
Ideally, if can check procedure contract one by one it would be great,
this will make backward compatible, for a server interface
ITest = interface(IInvokable)
procedure baba1;
procedure baba2;
procedure baba...;
end;
client interface below will all pass check:
ITest = interface(IInvokable)
procedure baba1;
end;
ITest = interface(IInvokable)
procedure baba1;
procedure baba2;
end;
ITest = interface(IInvokable)
procedure baba1;
procedure baba2;
procedure baba...;
end;
I looked source, the parameter aContractExpected can't achieve this effect,
set server and client's aContractExpected a same value will just close the contract check function.
thanks!
first create a interface,
ITest = interface(IInvokable)
procedure baba1;
end;
after server and client register the interface, then use the interface, every is ok.
then we delivery the client, after sometime, we need add procedure to ITest,
so interface looks like this,
ITest = interface(IInvokable)
procedure baba1;
procedure baba2;
procedure baba...;
end;
but when run old client, will generate interface contract check exception,
can make wise since the procedure baba1 parameter is not change, thanks!
For some interface register in application start, will cause application
can not auto update.
Do you have a second mMORmot server-service? Or do you you have a second TSQLRESTServer?
No, a normal application not use mORMot, only use SynDB to connection DB.
another hint, since the TSQLDBConnectionProperties can has some connections in pool, if db server's problem cause one connection break, generally else connection should also break, In my a little background service, if exception occur, i simple clear the connection pool, then every things later will ok, perhaps not need recreate one connection, since other connecitons also possible have breaked.
try
fDMInvoiceAssessment.InvoiceAssessment;
except
fDMInvoiceAssessment.ClearConnectionPool;
HandleException;
end;
procedure TDMInvoiceAssessment.ClearConnectionPool;
begin
fProps.ClearConnectionPool;
end;
Can if after a exception occur, we do a "ping" to check if the connection is break, if break then recreate it else do nothing, this will not affect perform, this method after one client operation failed, then succedent client operation will success, if can monitor exact connection broke exception, then will better, since there are many db connection method, check at TSQlDBConnectionProperties level should conformable.
I think perhaps the pool connection has broke, I has a application not use mORMot but use ADO, even at localhost after sometimes the pool connection possible broke due to various reason, then need restart the server application, see my before post and the interrelated ticket
http://synopse.info/forum/viewtopic.php?id=1630
http://synopse.info/fossil/tktview?name=f024266c08
I have tested, both CR and CRLF worked, thanks!
We may switch back to CRLF, or put an option for it...
What do you think?
This is not a big problem, just keep it simple is ok, for windows CRLF is prefer.
Thank you for the quick fix, TestSQL works now, the exception is gone.
A little problem, the log file content between lines now not have CRLF, only have CR in windows.