You are not logged in.
As you can see Trace=0 works as expected. The Other have Delays.
The 15s Delay is at another Place in the Program where the Stack / Memory Usage is much bigger
Here my Results, made 4 Tests
1. Default Settings
15.03.2022 20:04:57.688 Trace 1 Program wurde gestartet
15.03.2022 20:04:57.688 Error 1 Error1
15.03.2022 20:04:59.608 Error 1 Error2
15.03.2022 20:05:00.976 Error 1 Error3
15.03.2022 20:05:03.656 Enter 1 After Error32. OnlyApi
15.03.2022 20:05:45.944 Trace 1 Program wurde gestartet
15.03.2022 20:05:45.944 Error 1 Error1
15.03.2022 20:05:47.784 Error 1 Error2
15.03.2022 20:05:48.992 Error 1 Error3
15.03.2022 20:05:51.240 Enter 1 After Error33. OnlyManual
15.03.2022 20:06:18.304 Trace 1 Program wurde gestartet
15.03.2022 20:06:18.304 Error 1 Error1
15.03.2022 20:06:19.784 Error 1 Error2
15.03.2022 20:06:21.112 Error 1 Error3
15.03.2022 20:06:23.288 Enter 1 After Error34. StackTraceLevel=0
15.03.2022 20:09:37.144 Trace 1 Program wurde gestartet
15.03.2022 20:09:37.144 Error 1 Error1
15.03.2022 20:09:37.144 Error 1 Error2
15.03.2022 20:09:37.144 Error 1 Error3
15.03.2022 20:09:38.592 Enter 1 After Error3Example Code
TSynLog.Family.Level := LOG_VERBOSE;
if AppHasParam('StackTraceLevel0') then
TSynLog.Family.StackTraceLevel := 0;
if SameText(GetAppParamValue('StackTraceUse'), 'OnlyApi') then
TSynLog.Family.StackTraceUse := stOnlyApi;
if SameText(GetAppParamValue('StackTraceUse'), 'OnlyManual') then
TSynLog.Family.StackTraceUse := stOnlyManual;
TSynLog.Family.HighResolutionTimeStamp := true;
TSynLog.Family.LocalTimeStamp := true;
TSynLog.Family.FileExistsAction := acAppend;
TSynLog.Family.PerThreadLog := ptIdentifiedInOnFile;
TSynLog.Family.RotateFileCount := 100; // ca. 3 Monate
TSynLog.Family.RotateFileSizeKB := 5000 * 1024;
TSynLog.Family.RotateFileDailyAtHour := 23;
TSynLog.Family.IncludeComputerNameInFileName := true;
TSynLog.Family.DestinationPath := TPath.Combine(ExtractFilePath(Application.ExeName), 'Logs');
TDirectory.CreateDirectory(TSynLog.Family.DestinationPath);
TSynLog.Add.Log(sllTrace, 'Program wurde gestartet');
TSynLog.Add.Log(sllError, 'Error1');
TSynLog.Add.Log(sllError, 'Error2');
TSynLog.Add.Log(sllError, 'Error3');
---
After Error 3 - Later in codewin32 Executable (mORMot2)
I'll try
Hi Arnaud,
Logging on a Standard Windows 11 Computer took a long time (much longer than on my develop maschine)
After looking in the Log i found the sllError Line takes 15 second.
The only Reason i found could be the StackTrace - Routines
I set StackTraceLevel to 0 an the delay disappeared (It disabled the StackTrace Option)
as i do not need the StackTrace at this log its not important for me.
But do you have an Idea what i have to do to avoid the delay on active StackTrace ? Is there a Windows - Option ? Does the Windows User afford som special rights ?
I wrote a derived Class from TInterfaceFactory which does not evaluate the Methods...
In my Case its 0
Hi Arnaud,
today i got an exception in this method:
My Bugfix is here: can you pls add it to repo
function TServiceContainer.AddServiceInternal(aService: TServiceFactory): PtrInt;
var
MethodIndex: integer;
procedure AddOne(const aInterfaceDotMethodName: RawUtf8);
var
p: PServiceContainerInterfaceMethod;
begin
p := fInterfaceMethods.AddUniqueName(aInterfaceDotMethodName);
p^.InterfaceService := aService;
p^.InterfaceMethodIndex := MethodIndex;
inc(MethodIndex);
end;
var
aUri: RawUtf8;
internal: TServiceInternalMethod;
m: PtrInt;
begin
if (self = nil) or
(aService = nil) then
raise EServiceException.CreateUtf8(
'%.AddServiceInternal(%)', [self, aService]);
// add TServiceFactory to the internal list
if ExpectMangledUri then
aUri := aService.fInterfaceMangledUri
else
aUri := aService.fInterfaceUri;
PServiceContainerInterface(fInterfaces.AddUniqueName(aUri, @result))^.
Service := aService;
// add associated methods - first SERVICE_PSEUDO_METHOD[], then from interface
aUri := aUri + '.';
MethodIndex := 0;
for internal := Low(internal) to High(internal) do
AddOne(aUri + SERVICE_PSEUDO_METHOD[internal]);
// BUGFIX here
for m := 0 to (integer(aService.fInterface.MethodsCount)-1) do /// <<<---- Wrong Subtraction MethodsCount is Cardinal and mc-1 is also cardinal.
AddOne(aUri + aService.fInterface.Methods[m].Uri);
end;Today I had another problem in the Wrapper Generator.
The generated ContractID is different between mORMot2 and mORMot.
However, after I inserted the one generated by mORMot, the data transfer still works.
Hi Arnaud,
i like to move completely to mORMot2. But this feature is a show stopper atm.
I tested and debugged the Problem now for hours but can not solve it.
I just have some new hints and things i found out.
I use the same Sample as above. Slightly enhanced. if you like i can send you the code or show the Problem by Teamviewer.
i Compared the mORMot and mORMot2 by debugging TWrapperContent. And added some TSynLog Stuff to dig in the deep.
The Following Errors are in mORMot2:
1. Nested Records are expanded the reason is in the used new rtti props in ContextOneProperty function
for mORMot Version prop.PropertyType is ptCustom and for mORMot2 prop.Value.Parser is ptRecord
(generally it is a ptRecord but i do not know where mORMot generates the ptCustom where mORMot2 has a ptRecord.)
this adds additional nestedRecord in the structure. which is wrong.
2. Second BUG is a DynArray of (Record or simple Type e.g. String)
in mORMot the Code is correct
in M2 You internally map ptDynArray to Blob which results in wrong code. The Wrong Conversion occurs for example in ContextFromRTTI in
typ := TYPES_ORM[GetOrmFieldType(rtti.Info)];Hopefully you have an idea to fix the Wrapper Generator with this info
Hi Arnaud
atm im struggling with an external Oracle DB - I used both ConnectionProperties: TSqlDBOracleConnectionProperties and TSQLDBUniDACConnectionProperties (for Oracle)
i use code like this:
var LVariant := RestModel.RetrieveDocVariantArray(TSQLEOR_SomeRecord,'',
'trunc(DateTimeField) = trunc(sysdate)' , // <-- SQLite Error Oracle SQL Function sysdate unknown
[] ,
'ID, DateTimeField, Field1, Field2, Field3,')Example for other Oracle functions not working:
to_char( datetimefield, 'YYYY-MM-DD' ) = '2021-12-01' // SQLite Error: to_char unkown
trunc( datetimefield ) = to_date('2021-12-01', 'YYYY-MM-DD')"); // SQLite Error: to_date unknown
trunc is also unkown ![]()
Is there a possibilty to let SQLite know the functions or to get the Query run
Why does SQLite have to know the functions ?
Best Regards
thank you - yes i used a piece of code with mORMot2 and then with mORMot and under mORMot my Objekt was freed in Support...
Hi Arnaud. i tried to upload this patch to github. But my credentials are rejected
diff --git a/SQLite3/mORMot.pas b/SQLite3/mORMot.pas
index 5b692f78..30d00b67 100644
--- a/SQLite3/mORMot.pas
+++ b/SQLite3/mORMot.pas
@@ -58447,10 +58447,11 @@ begin
else
result := fImplementationClass.Create;
end;
+ inc(TInterfacedObjectHooked(result).FRefCount); // >0 to call Support() in event
if Assigned(TSQLRestServer(Rest).OnServiceCreateInstance) then
TSQLRestServer(Rest).OnServiceCreateInstance(self,result);
- if AndIncreaseRefCount then
- IInterface(result)._AddRef; // allow passing self to sub-methods
+ if not AndIncreaseRefCount then
+ dec(TInterfacedObjectHooked(result).FRefCount);
end;
procedure TServiceFactoryServer.OnLogRestExecuteMethod(Sender: TServiceMethodExecute;Hi Arnaud
i found the following "bug" between DEBUG and RELEASE Version in mORMot2:
I get lot's of Exception (> 200) at this line of code:
mORMot.rest.client: 2460 (InternalLog('% % returned % (%) with message %', [method, url, Call.OutStatus, StatusMsg, fLastErrorMessage], sllError);)only in RELEASE Mode - not in DEBUG Mode !
so it was a bit tricky to get the cause for the Exceptions.
The Source for the Exceptions is in mormot.core.log: AddStackTrace in LogTrailer (sllError is in fLevelStackTrace) around line 5416
your are ignoring the Exceptions but they are displayed in the LogFile - and on console Screen.
As WorkAround i added this piece of code to my "Log Initialisation Code"
{$if defined(RELEASE)}
TSynLog.Family.LevelStackTrace := TSynLog.Family.LevelStackTrace - [sllError];
{$endif}There are other Log Levels in LevelStackTrace wich may rise the same Exceptions
May be you have an Idea what's the Problem.
in mORMot the Problem does not exists - but i saw that you did a big rework in TSynLog
ty it works ![]()
k next time i try the correct way
Hi AB i use mORMot2 with Oracle and got error in GetFields.
Hier is my Patch for this
procedure TSqlDBUniDACConnectionProperties.GetFields(const aTableName: RawUtf8;
out Fields: TSqlDBColumnDefineDynArray);
var
meta: TDAMetaData;
n: integer;
F: TSqlDBColumnDefine;
FA: TDynArray;
hasSubType: boolean;
Owner, Table: RawUtf8;
begin
meta := (MainConnection as TSqlDBUniDACConnection).fDatabase.CreateMetaData;
try
FA.Init(TypeInfo(TSqlDBColumnDefineDynArray), Fields, @n);
FA.Compare := SortDynArrayAnsiStringI; // FA.Find() case insensitive
FillCharFast(F, sizeof(F), 0);
meta.MetaDataKind := 'Columns';
Split(aTableName, '.', Owner, Table);
if Table = '' then
begin
Table := Owner;
Owner := '';
end;
// PATCH
if (Owner = '') and
(fDBMS <> dOracle) then
Owner := MainConnection.Properties.DatabaseName; // itSDS
// PATCH
if Owner <> '' then
meta.Restrictions.Values['TABLE_SCHEMA'] := Utf8ToString(UpperCase(Owner))
else
meta.Restrictions.Values['SCOPE'] := 'LOCAL';
meta.Restrictions.Values['TABLE_NAME'] := Utf8ToString(UpperCase(Table));
meta.Open;
hasSubType := meta.FindField('DATA_SUBTYPE') <> nil;
while not meta.Eof do
begin
F.ColumnName := StringToUtf8(meta.FieldByName('COLUMN_NAME').AsString);
F.ColumnTypeNative := StringToUtf8(meta.FieldByName('DATA_TYPE').AsString);
if hasSubType then
F.ColumnTypeNative := F.ColumnTypeNative +
StringToUtf8(meta.FieldByName('DATA_SUBTYPE').AsString);
F.ColumnLength := meta.FieldByName('DATA_LENGTH').AsInteger;
F.ColumnScale := meta.FieldByName('DATA_SCALE').AsInteger;
F.ColumnPrecision := meta.FieldByName('DATA_PRECISION').AsInteger;
F.ColumnType := ColumnTypeNativeToDB(F.ColumnTypeNative, F.ColumnScale);
if F.ColumnType = ftUnknown then
begin
// UniDAC metadata failed -> use SQL
Fields := nil;
inherited GetFields(aTableName, Fields);
exit;
end;
FA.Add(F);
meta.Next;
end;
Setlength(Fields, n);
GetIndexesAndSetFieldsColumnIndexed(aTableName, Fields);
finally
meta.Free;
end;
end;as Solution you should not overload the function and instead rename the second Function e.g to Utf8ToStringP
/// convert any UTF-8 encoded String into a generic VCL Text
// - it's prefered to use TLanguageFile.Utf8ToString() in mORMoti18n,
// which will handle full i18n of your application
// - it will work as is with Delphi 2009+ (direct unicode conversion)
// - under older version of Delphi (no unicode), it will use the
// current RTL codepage, as with WideString conversion (but without slow
// WideString usage)
function Utf8ToString(const Text: RawUtf8): string; // itSDS overload;
{$ifdef HASINLINE}inline;{$endif}
/// convert any UTF-8 encoded String into a generic VCL Text
procedure Utf8ToStringP(const Text: RawUtf8; var result: string); // overload;
{$ifdef HASINLINE}inline;{$endif}what do you think
i testet something:
there was a former Version of mormot.core.unicode.pas without generating the error:
/// convert any UTF-8 encoded String into a generic VCL Text
// - it's prefered to use TLanguageFile.Utf8ToString() in mORMoti18n,
// which will handle full i18n of your application
// - it will work as is with Delphi 2009+ (direct unicode conversion)
// - under older version of Delphi (no unicode), it will use the
// current RTL codepage, as with WideString conversion (but without slow
// WideString usage)
function Utf8ToString(const Text: RawUtf8): string;
{$ifdef HASINLINE}inline;{$endif}
/// convert any UTF-8 encoded buffer into a generic VCL TextThere is a problem compiling 32Bit mORMot2 with Rad Studio 10.4.2
Errror: [dcc32 Fehler] xxxx.pas(196): E2251 Doppeldeutiger überladener Aufruf von 'UTF8ToString'
System.pas(40375): Verwandte Methode: function UTF8ToString(const RawByteString): string;
mormot.core.unicode.pas(3896): Verwandte Methode: function Utf8ToString(const UTF8String): string;
actual i put mormot.core.unicode.UTF8ToString( in my code but i have a lot of code with UTF8ToString
Is there a easy solution ?
System.pas is included in any unit or ?
hi Arnaud,
i had a look in the Source code and compared the Units "mORMotWrappers" and "mORMot.soa.codegen"
the TWrapperContext.ContextOneProperty seems to produce different structure.
But i have no idea how to fix it and where exactly the Problem is.
But in mORMot2 the nestedRecord Property is filled and in mORMot not for the same "TResultRec"
mORMot2:
{
"typeWrapper": "wRecord",
"typeSource": "TresultRec",
"typeDelphi": "TresultRec",
"typePascal": "TresultRec",
"typeCS": "TresultRec",
"typeJava": "TresultRec",
"typeTS": "TresultRec",
"typeSwagger": "TresultRec",
"isRecord": true,
"toVariant": "TresultRec2Variant",
"fromVariant": "Variant2TresultRec",
"propName": "resultRec",
"fullPropName": "resultRec",
"isSimple": null,
"nestedRecord": {
"nestedRecord": null,
"fields": [
{
"typeWrapper": "wRawUtf8",
"typeSource": "UTF8String",
"typeDelphi": "RawUtf8",
"typePascal": "String",
"typeCS": "string",
"typeJava": "String",
"typeTS": "string",
"typeSwagger": "{\"type\":\"string\"}",
"propName": "erfolgJN",
"fullPropName": "resultRec.erfolgJN",
"nestedIdentation": " ",
"isSimple": true
},
{
"typeWrapper": "wRawUtf8",
"typeSource": "UTF8String",
"typeDelphi": "RawUtf8",
"typePascal": "String",
"typeCS": "string",
"typeJava": "String",
"typeTS": "string",
"typeSwagger": "{\"type\":\"string\"}",
"propName": "fehlertext",
"fullPropName": "resultRec.fehlertext",
"nestedIdentation": " ",
"isSimple": true
},
{
"typeWrapper": "wRawUtf8",
"typeSource": "UTF8String",
"typeDelphi": "RawUtf8",
"typePascal": "String",
"typeCS": "string",
"typeJava": "String",
"typeTS": "string",
"typeSwagger": "{\"type\":\"string\"}",
"propName": "hinweistext",
"fullPropName": "resultRec.hinweistext",
"nestedIdentation": " ",
"isSimple": true
},
{
"typeWrapper": "wInteger",
"typeSource": "Integer",
"typeDelphi": "Integer",
"typePascal": "Integer",
"typeCS": "integer",
"typeJava": "int",
"typeTS": "number",
"typeSwagger": "{\"type\":\"integer\"}",
"propName": "resultcount",
"fullPropName": "resultRec.resultcount",
"nestedIdentation": " ",
"isSimple": true
}
]
}
}mORMot:
{
"typeWrapper": "wRecord",
"typeSource": "TresultRec",
"typeDelphi": "TresultRec",
"typePascal": "TresultRec",
"typeCS": "TresultRec",
"typeJava": "TresultRec",
"typeTS": "TresultRec",
"typeSwagger": "TresultRec",
"isRecord": true,
"toVariant": "TresultRec2Variant",
"fromVariant": "Variant2TresultRec",
"propName": "resultRec",
"fullPropName": "resultRec",
"isSimple": null
}My be you have an idea how to fix it ?! It would be a great help. Ty
Yes i like it ![]()
I applied the same Patch to mORMot V2. (mormot.rest.http.server.pas - Line 1010)
Hi Arnaud, late feedback.
I testet it now and there is a little change i made to the Option:
In Line 927 of MORMotHttpServer i added a '/' slash in front of the serv.model.root, because else there's a kind of recursion generting wrong url (It repeats the serv.Model.Root serveral Times)
if fRedirectServerRootUriForExactCase and (match=rmMatchWithCaseChange) then begin
// force redirection to exact Server.Model.Root case sensitivity
call.OutStatus := HTTP_TEMPORARYREDIRECT;
call.OutHead := 'Location: /'+serv.Model.Root+ /// <<<---- SLASH ADDED !
copy(call.Url,length(serv.Model.Root)+1,maxInt);
end else begin@flydev the Problem is here with nestet Records and Array of...
Here is a link to download my sample
for mORMot2 define USE_MORMOTV2 in the options
i didn't dig in the deep - yet. No proposals atm.
If i generate the Wrapper with mORMot and the SOA Service with mORMot2 it works ![]()
Same Code with mORMot
unit mORMotClient;
{
WARNING:
This unit has been generated by a mORMot 1.18.6262 server.
Any manual modification of this file may be lost after regeneration.
Synopse mORMot framework. Copyright (C) 2021 Arnaud Bouchez
Synopse Informatique - http://synopse.info
This unit is released under a MPL/GPL/LGPL tri-license,
and therefore may be freely included in any application.
This unit would work on Delphi 6 and later, under all supported platforms
(including MacOSX, and NextGen iPhone/iPad), and the Free Pascal Compiler.
}
interface
uses
SynCrossPlatformJSON,
SynCrossPlatformSpecific,
SynCrossPlatformREST;
type // define some enumeration types, used below
TPeopleSexe = (sFemale, sMale);
TRecordEnum = (reOne, reTwo, reLast);
type // define some record types, used as properties below
TresultRec = record
erfolgJN: String;
fehlertext: String;
hinweistext: String;
end;
TTestCustomJSONArraySimpleArray = record
F: String;
F1: TresultRec;
G: array of String;
H: record
H1: Integer;
H2: String;
H3: record
H3a: Boolean;
H3b: TSQLRawBlob;
end;
end;
I: TDateTime;
J: array of record
J1: Byte;
J2: TGUID;
J3: TRecordEnum;
end;
end;
TResultRecord = record
resultRec: record
erfolgJN: String;
fehlertext: String;
hinweistext: String;
end;
FResult1: String;
FResult2: String;
FResult3: String;
FResult4: String;
end;
TSimpleRecord = record
A: Integer;
B: Integer;
C: String;
end;Example from mORMot2
unit mORMotClient;
{
WARNING:
This unit has been generated by a mORMot 2.0.1 server.
Any manual modification of this file may be lost after regeneration.
Synopse mORMot framework. Copyright (C) 2021 Arnaud Bouchez
Synopse Informatique - http://synopse.info
This unit is released under a MPL/GPL/LGPL tri-license,
and therefore may be freely included in any application.
This unit would work on Delphi 6 and later, under all supported platforms
(including MacOSX, and NextGen iPhone/iPad), and the Free Pascal Compiler.
}
interface
uses
SynCrossPlatformJSON,
SynCrossPlatformSpecific,
SynCrossPlatformREST;
type // define some enumeration types, used below
TPeopleSexe = (sFemale, sMale);
type // define some record types, used as properties below
TresultRec = record
erfolgJN: String;
fehlertext: String;
hinweistext: String;
end;
00e21f50 = record
H3a: Boolean;
H3b: RawBlob;
end;
00e21ea0 = record
H1: Integer;
H2: String;
H3: 00e21f50;record
H3a: Boolean;
H3b: RawBlob;
end;
end;
TTestCustomJSONArraySimpleArray = record
F: String;
F1: TresultRec;record
erfolgJN: String;
fehlertext: String;
hinweistext: String;
end;
G: RawBlob;
H: 00e21ea0;record
H1: Integer;
H2: String;
H3: 00e21f50;record
H3a: Boolean;
H3b: RawBlob;
end;
end;
I: TDateTime;
J: RawBlob;
end;
00e213a0 = record
erfolgJN: String;
fehlertext: String;
hinweistext: String;
end;Hi Arnaud, i generated a soa interface for a new service and created the CrossPlatform Wrappers for an app.
But the generated pas - Sourcecode ist broken. I send you an example via EMail.
@ab i also have a question,
i compile my sqlite.obj sqlite.o with bcc32/64 from Rad Studio 10.4.2 and they work, is there a reason not to do this ?
Hi AB today i update mORMot to the actual Version and testet it
We use SynDBUniDAC.
But some of the changes from matkov throw unexpected SQL Errors with MySQL and MSSQL
I had to revert SynDBUniDac to the "old" Version.
MySQL Error:
Erste Gelegenheit für Exception bei $76A4A8B2. Exception-Klasse EMySqlException mit Meldung '#HY000Unerlaubte Mischung von Sortierreihenfolgen (latin1_german2_ci, IMPLICIT) und (utf8_general_ci, COERCIBLE) für Operation '=''. Prozess imsys.exe (7000)
with Query:
delete from tabellenbeziehungen where (beziehungsart = :("MZ_MDELizenzen"):) and (referenztabelle = :("monteure"):) and (referenzfeld = :("monteurid"):) and (bezug = :("DFCloud.Lizenzen"):) and (bezugsfeld = :("Lizenzcode"):) and (referenzwert = :(53):)MS-SQL Error:
Erste Gelegenheit für Exception bei $76A4A8B2. Exception-Klasse EUniError mit Meldung 'Operandentypkollision: nvarchar(max) ist inkompatibel mit sql_variant'. Prozess imsys.exe (7000)
with Query:
SELECT stammdatenid f0, parentID f1, kategorie f2, auswahl f3, anzeigen f4, feld01 f5, hostwert f6, unplausibel_meldungstext f7, extrem_unplausibel_meldungstext f8 FROM stammdaten where (kategorie = :("Vorgangsgrund"):) order by stammdatenid
(and other select queries)Removing the Prepare in line 768:
function TSQLDBUniDACStatement.DatasetPrepare(const aSQL: string): boolean;
begin
(fQuery as TUniQuery).SQL.Text := aSQL;
// TUniQuery(fQuery).Prepare;
fQueryParams := TUniQuery(fQuery).Params;
result := fQueryParams<>nil;
end;solves the Problem also, but as i don't know what matkov used to do with the patch, i reverted complete to the former SynDBUniDAC.pas - i think i don't need the patch
ty i'll try your ideas
Interesting work.
i would like to test it on RS 10.4 do you think it will work ?
Using an SQL Server for Example MySQL with mORMot TSQLRecords i have the Problem at a Customer:
We need 1 mORMot in DMZ and 1 internal but using the same SQL Server.
Both Client insert in the same TSQLRecord.
now wi get duplicate key errors.
Is it possible (by option) that both Client get the latest free key before inserting ?
I made it a little "Smarter" ![]()
procedure TSQLDBUniDACStatement.DataSetBindSQLParam(const aArrayIndex, aParamIndex: integer; const aParam: TSQLDBParam);
var
P : TDAParam;
begin
// SynDBLog.Enter('DataSetBindSQLParam(%, %, %)', [aArrayIndex, AParamIndex, Length(aParam.VData)], Self);
if fQueryParams[aParamIndex] is TDAParam then begin
with aParam do begin
P := TDAParam(fQueryParams[aParamIndex]);
P.ParamType := SQLParamTypeToDBParamType(VInOut);
if VinOut <> paramInOut then
case VType of
SynTable.ftBlob: begin
{$ifdef UNICODE}
if aArrayIndex>=0 then
P.SetBlobData(Pointer(VArray[aArrayIndex]),Length(VArray[aArrayIndex]))
else
P.SetBlobData(Pointer(VData),Length(VData));
{$else}
if aArrayIndex>=0 then
P.AsString := VArray[aArrayIndex]
else
P.AsString := VData;
{$endif}
exit;
end;
end;
end;
end;
inherited DataSetBindSQLParam(aArrayIndex, aParamIndex, aParam);
end;I just made a copy and fixed the BLOB Part - But its possible to only change the BLOB Part for sure.
sry ab didn't think about the size
Hi AB,
today i found the real Solution for the BUG.
My Previuosly change is not correct and can be removed.
UniDAC has overriden the TParam with TDAParam in DBAccess.
Your TSQLDBDatasetStatement.DataSetBindSQLParam uses TParam.SetBlobData function and does not check that TDAParam has another Implementation for SetBlobData (Its not overrride / virtual)
As Solution i added TSQLDBUniDACStatement.DataSetBindSQLParam which checks wether TParam is a TDAParam and then calls the correct SetBlobData function.
Pls change my BUG FIX as follows:
SynDBUniDAC.pas
class declaration:
/// implements a statement via a UniDAC connection
TSQLDBUniDACStatement = class(TSQLDBDatasetStatement)
protected
/// initialize and set fQuery: TUniQuery internal field as expected
procedure DatasetCreate; override;
/// set fQueryParams internal field as expected
function DatasetPrepare(const aSQL: string): boolean; override;
/// execute underlying TUniQuery.ExecSQL
procedure DatasetExecSQL; override;
procedure DataSetBindSQLParam(const aArrayIndex, aParamIndex: integer; const aParam: TSQLDBParam); override;
public
end;procedure TSQLDBUniDACStatement.DataSetBindSQLParam(const aArrayIndex, aParamIndex: integer; const aParam: TSQLDBParam);
var P: TDAParam;
I64: Int64;
tmp: RawUTF8;
begin
// SynDBLog.Enter('DataSetBindSQLParam(%, %, %)', [aArrayIndex, AParamIndex, Length(aParam.VData)], Self);
if fQueryParams[aParamIndex] is TDAParam then begin
with aParam do begin
P := TDAParam(fQueryParams[aParamIndex]);
P.ParamType := SQLParamTypeToDBParamType(VInOut);
if VinOut <> paramInOut then
case VType of
SynTable.ftNull: begin
P.Clear;
{$ifdef UNICODE}
P.AsBlob := nil; // avoid type errors when a blob field is adressed
{$else}
P.AsString := '';
{$endif}
end;
SynTable.ftInt64: begin
if aArrayIndex>=0 then
I64 := GetInt64(pointer(VArray[aArrayIndex])) else
I64 := VInt64;
{$ifdef UNICODE}
P.AsLargeInt := I64;
{$else}
if (PInt64Rec(@I64)^.Hi=0) or (PInt64Rec(@I64)^.Hi=Cardinal(-1)) then
P.AsInteger := I64 else
if TSQLDBDatasetConnectionProperties(Connection.Properties).
fForceInt64AsFloat then
P.AsFloat := I64 else
P.Value := I64;
{$endif}
end;
SynTable.ftDouble:
if aArrayIndex>=0 then
P.AsFloat := GetExtended(pointer(VArray[aArrayIndex])) else
P.AsFloat := unaligned(PDouble(@VInt64)^);
SynTable.ftCurrency:
if aArrayIndex>=0 then
P.AsCurrency := StrToCurrency(pointer(VArray[aArrayIndex])) else
P.AsCurrency := PCurrency(@VInt64)^;
SynTable.ftDate:
if aArrayIndex>=0 then begin
UnQuoteSQLStringVar(pointer(VArray[aArrayIndex]),tmp);
P.AsDateTime := Iso8601ToDateTime(tmp);
end else
P.AsDateTime := PDateTime(@VInt64)^;
SynTable.ftUTF8:
if aArrayIndex>=0 then
if (VArray[aArrayIndex]='') and
fConnection.Properties.StoreVoidStringAsNull then
P.Clear else begin
UnQuoteSQLStringVar(pointer(VArray[aArrayIndex]),tmp);
if fForceUseWideString then
P.Value := UTF8ToWideString(tmp) else
P.AsString := UTF8ToString(tmp);
end else
if (VData='') and fConnection.Properties.StoreVoidStringAsNull then
P.Clear else
if fForceUseWideString then
P.Value := UTF8ToWideString(VData) else
P.AsString := UTF8ToString(VData);
SynTable.ftBlob:
{$ifdef UNICODE}
if aArrayIndex>=0 then
P.SetBlobData(Pointer(VArray[aArrayIndex]),Length(VArray[aArrayIndex]))
else
P.SetBlobData(Pointer(VData),Length(VData));
{$else}
if aArrayIndex>=0 then
P.AsString := VArray[aArrayIndex] else
P.AsString := VData;
{$endif}
else
raise ESQLDBDataset.CreateFmt(
'%.DataSetBindSQLParam: Invalid type % on bound parameter #%d',
[self,ord(VType),aParamIndex+1]);
end;
end;
end else
inherited DataSetBindSQLParam(aArrayIndex, aParamIndex, aParam);
end;I made some more modifications to SynDBUniDac. i will send it to you by mail.
Hi AB i found a litte BUG in NewStatementPrepared:
see the line with // itSDS
function TSQLDBConnection.NewStatementPrepared(const aSQL: RawUTF8;
ExpectResults, RaiseExceptionOnError, AllowReconnect: Boolean): ISQLDBStatement;
var Stmt: TSQLDBStatement;
ToCache: boolean;
ndx,altern: integer;
cachedSQL: RawUTF8;
procedure TryPrepare(doraise: boolean);
var Stmt: TSQLDBStatement;
begin
Stmt := nil;
try
InternalProcess(speActive);
try
Stmt := NewStatement;
Stmt.Prepare(aSQL,ExpectResults);
if ToCache then begin
if fCache=nil then
fCache := TRawUTF8List.Create([fObjectsOwned,fNoDuplicate,fCaseSensitive]);
if fCache.AddObject(aSQL,Stmt)>=0 then // itSDS
Stmt._AddRef else // will be owned by fCache.Objects[]
SynDBLog.Add.Log(sllWarning,'NewStatementPrepared: unexpected '+
'cache duplicate for %',[Stmt.SQLWithInlinedParams],self);
end;
result := Stmt;
finally
InternalProcess(speNonActive);
end;
except
on E: Exception do begin
with SynDBLog.Add do
if [sllSQL,sllDB,sllException,sllError]*Family.Level<>[] then
LogLines(sllSQL,pointer(Stmt.SQLWithInlinedParams),self,'--');
Stmt.Free;
result := nil;
StringToUTF8(E.Message,fErrorMessage);
fErrorException := PPointer(E)^;
if doraise then
raise;
end;
end;
end;the former used cachedSQL - Value is sometimes empty
Results: After a while of Debugging in found that the Problem is in UNIDAC. I get the same error with MySQL / MSSQL - Provider.
I reproduced the behavior every time. The Problem with mORMot i have only with the SynCrossPlatform Client. Here SynDBUniDAC is used. As a Workaround i modified TSQLDBUniDACConnectionProperties.
My Code is not perfect normally i should set
UseCache := false
in Create.
function TSQLDBUniDACConnectionProperties.IsCachable(P: PUTF8Char): boolean;
// UNIDAC Probleme mit Update - Statements mit BLOB Parametern.
// Bei gecachten Statement wird der BLOB immer aus dem "Cache" genommen
begin
result := not IdemPChar(P,'UPDATE ');
if result then
result := inherited IsCachable(P);
end;There is some Strange Behavior in UniDAC, where i could not find the error. SetBlobParam set's the Blob correctly, but TCustomDASQL.AssignParamValue( seems to use a wrong Value from "i don't know where" it is taken.
Actually i use synoledb for test i ll post my results
I have a Problem with Updating a TSQLRecord's Blob Data. The Problem is visible in this Picture (Screen from LOG Viewer)
I update 3 "BinaerdatenRecord" after i insert them. I update 2 fields, BLOB Field Binaerdaten and Integer Field GroesseinBytes
In the First Call mORMot / UniDAC calls Prepare for the Update Statement.
In the following calls the Prepared Statement is used.
As you can see in the violet boxes the BLOB - Data has different sizes 143.5 / 119.2 and 100.4KB
the Blob Parameter is 110210 Byte
The Error is:
All 3 Database Records are filled with the Same BLOB - Data
Now my Question:
Is it a mORMot or a UniDAC Problem ? As Database Server i Use MS-SQL 2012
Is it Possible to disable Prepared Statement for Queries with BLOB Parameter
I like your upgrade thoughts and filled out the survey
What i was missing is : will complete CrossPlatform support available with 10.4 ? (They change something with arc ?)
Hi mpv i used the syndboledb before, but offen i get Exception that free was called from wrong thread in disconnect.
and we have customer in great business where the installation of sqlncli is not possible.
Wih new UniDAC 8.1.2 i wanted to give Unidac a try with SQL Server.Provider=prDirect where no extra Software ist needed.
Yesterday i found the solution for the UniDAC Connect "lag":
Just set SQL Server.ConnectionTimeout to 0 in Specialoptions.
Hi i use UniDAC 8.1.2 for SQL Server 11 with mORMot's SynDBUniDAC.
Here i made some Speedtests and compared the divers SQL Server.Provider Options.
The Queries itself are nearly with the same Speed. But in the first Connect Part of any ServerRequest the prDirect Option uses 120ms on my System to Connect. the prAuto only 10ms that is 12times slower.
We use mORMot as Rest/Soa Service, for every Rest Request the Connection is newly opened.
Some Heavily transfers use 2seconds with prAuto and 10s with prDirect.
The Reason ist the 120ms Connection Time.
Does anybody have a idea why direct connect is that slower ?
I think it will not work cause the TID as int64 is essential for mORMot and massivly used internally
Hi Arnaud,
i try to select some SQLRecord from External MS-SQL Database.
we wan't to select all record where the field (Messzeitpunkt : TDateTime) = date
i tried a lot of valid ms-sql statements, but every time the mORMot Parser makes errors:
Version1:
whereStatement = convert(date, GETDATE()) = convert(date, Messzeitpunkt)
20190801 22095955 2 warn mORMotDB.TSQLRestStorageExternal(02c45990) TSQLRestStorageExternal.AdaptSQLForEngineList: statement too complex -> would use SQLite3 virtual engine [SELECT ID,CreationDate,LastEditDate,AuftragStartEventID,Gruppierung,Ursprung,IPAdresse,Port,Messzeitpunkt,Barcode,Drehmoment,DrehmomentErgebnis,Drehwinkel,DrehwinkelErgebnis,GesamtErgebnis,Daten,SpindelTag,ControllerName,TighteningID,TorqueUnits,BatchCount,BatchSize,BatchStatus,CountOfScrewSteps,Screwprogram,Torquehighlimit,Torquelowlimit,Anglehighlimit,Anglelowlimit,ResultUniqueID,EORTimeStamp FROM EOR_QSYSOpenProtocolRecord WHERE convert(date, GETDATE()) = convert(date, Messzeitpunkt)]
Verstion 2:
whereStatement = CONVERT(nvarchar(max), messzeitpunkt, 23)=?, ['2019-08-01']
Error:
mORMotDB.TSQLRestStorageExternal(02ab5990) TSQLRestStorageExternal.AdaptSQLForEngineList: unsupported function CONVERT() for [SELECT ID,CreationDate,LastEditDate,AuftragStartEventID,Gruppierung,Ursprung,IPAdresse,Port,Messzeitpunkt,Barcode,Drehmoment,DrehmomentErgebnis,Drehwinkel,DrehwinkelErgebnis,GesamtErgebnis,Daten,SpindelTag,ControllerName,TighteningID,TorqueUnits,BatchCount,BatchSize,BatchStatus,CountOfScrewSteps,Screwprogram,Torquehighlimit,Torquelowlimit,Anglehighlimit,Anglelowlimit,ResultUniqueID,EORTimeStamp FROM EOR_QSYSOpenProtocolRecord WHERE CONVERT(nvarchar(max), messzeitpunkt, 23)=:('2019-08-01'):]
do you have an idea how to get the desired records ?
Is it a bug or do i use it wrong ?
yes i'm in contact with bruneau from embarcadero who found the reason in sqlite.c. SQLite 3.29 includes math.h but 3.28 does not.
if you have access to the embarcadero discourse page you can read about it
Hi AB, just to close this issue.
the external symbol __ieee_32_p_inf is defined in math.h if INFINITY is not defined
in 3.28 there seems to be INFINTY defined (i can not find out where ..)
in 3.29 it is not defined resulting in using the definition from math.h
in Line 30821 of 3.29 sqlite.c it is used. In 3.28 the constant and in 3.29 the external definition.
As work around in changed the code to use the constant in 3.29 as in 3.28 - Now i can link it again.
}else{
// #ifdef INFINITY // auskommentiert by itSDS
// result = INFINITY*s; // auskommentiert by itSDS
//#else // auskommentiert by itSDS
result = 1e308*1e308*s; /* Infinity */
//#endif // auskommentiert by itSDS
}Oh nothing wrong with, but i build them by myself because i also build the 64Bit Versions
But i do not get this error using compiled SQLite 3.28 obj. It came with 3.29.
Normally i would say that the linker is missing a lib file with the named function...
Embarcadero made a lot changes to bcc in 10.3.2 and it may be a solution to use an older Version but why - if its only a missing function ?