You are not logged in.
We tried to install a service at a customer wich we testet and programmed on Windows MySQL 5.6
CreateMissingTables works as expected.
No we installed it at a customer and he has MySQL 5.5 on Linux
CreateMissingTables makes Errors:
1. it creates the Table in the Database
2. After Restart it can not find the former created Tables nor the fields in it.
here is some Log Output from the Linux Server
20141015 10585206 + TSQLDatabase(0288CD58).00AD13EA
20141015 10585206 SQL CREATE VIRTUAL TABLE kVASYAuftraegeRecord USING External(kVASy_AuftragID TEXT COLLATE SYSTEMNOCASE, TODO TEXT COLLATE SYSTEMNOCASE, Status TEXT COLLATE SYSTEMNOCASE, TSYSAufgabenID INTEGER, CreationDate TEXT COLLATE ISO8601, LastChangeDate TEXT COLLATE ISO8601);
20141015 10585206 + TSQLDBUniDACStatement(03235F60).00AC9EF1
20141015 10585206 + TSQLDBUniDACConnection(0288CD00).Connect to ProviderName=MySQL Database=manthey_turnus_schwerte on Server=192.168.101.231
20141015 10585206 DB Connected to MySQL (5.5.35-0ubuntu0.12.04.2)
20141015 10585206 - 00.001.373
20141015 10585206 - 00.001.464
20141015 10585206 + TSQLDBUniDACStatement(03235F60).00ACA045
20141015 10585206 SQL TSQLDBUniDACStatement(03235F60) SELECT NOW()
20141015 10585206 - 00.000.455
20141015 10585206 + TSQLDBUniDACStatement(032360E0).00AC9EF1
20141015 10585206 - 00.000.123
20141015 10585206 + TSQLDBUniDACStatement(032360E0).00ACA045
20141015 10585206 SQL TSQLDBUniDACStatement(032360E0) CREATE TABLE kVASYAuftraegeRecord (ID INT NOT NULL,kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE,TODO varchar(50) character set UTF8,Status varchar(50) character set UTF8,TSYSAufgabenID bigint,CreationDate datetime,LastChangeDate datetime, PRIMARY KEY(ID))
20141015 10585206 EXC EMySqlException ("\r\n#42S01Table 'kVASYAuftraegeRecord' already exists") at 008103D2 stack trace 00831ADF 00832212 0083225F 00687DAF 0083345A 00833526 0065543D 007F8888 006557D6 00655930 0040A2F7 0040A322 00ACD17C 00ACA1FA 00ABDAB8 00ABDACD 00ADA43C 00AD6903 00AE6067 00AE6294
20141015 10585206 EXC EMyError ("\r\n#42S01Table 'kVASYAuftraegeRecord' already exists") at 0082B6A8 stack trace API 00535998 0040B0D0 771CB46B 77180133 0082B6A8 0082D2AF 00832212 00687DAF 0065543D 006557D6 00ACD17C 00ADA43C 00AD6903 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF
20141015 10585206 EXC EMyError ("\r\n#42S01Table 'kVASYAuftraegeRecord' already exists") at 0082B6A8 stack trace API 00535998 0040B0D0 771CB46B 77180133 0082B6A8 0082D2AF 00832212 00687DAF 0065543D 006557D6 00ACD17C 00ADA43C 00AD6903 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF
20141015 10585206 EXC EMyError ("\r\n#42S01Table 'kVASYAuftraegeRecord' already exists") at 0082B6A8 stack trace API 00535998 0040B0D0 771CB46B 77180133 0082B6A8 0082D2AF 00832212 00687DAF 0065543D 006557D6 00ACD17C 00ADA43C 00AD6903 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF
20141015 10585207 EXC EUniError ("\r\n#42S01Table 'kVASYAuftraegeRecord' already exists") at 007F0FAC stack trace 00655930 0040A2F7 0040A322 00ACD17C 00ACA1FA 00ABDAB8 00ABDACD 00ADA43C 00AD6903 00AE6067 00AE6294 005174C6 008A5AB0 00AE6338 00406FAE 00AE0EF7 00406FAE 0040BD78 00ADFED6 00AE0F3D
20141015 10585207 EXC EUniError ("\r\n#42S01Table 'kVASYAuftraegeRecord' already exists") at 007F0FAC stack trace 00AD6903 00AE6067 00AE6294 005174C6 008A5AB0 00AE6338 00406FAE 00AE0EF7 00406FAE 0040BD78 00ADFED6 00AE0F3D 00B2B8BE 00B2BC5B 00B07125 00B2E763 00B0D794 00406FAE 00AE0EF7 00AE41D7
20141015 10585207 - 00.008.261
20141015 10585207 + TSQLDBUniDACStatement(032360E0).00AC9EF1
20141015 10585207 - 00.000.069
20141015 10585207 + TSQLDBUniDACStatement(032360E0).00ACA045
20141015 10585207 SQL TSQLDBUniDACStatement(032360E0) ALTER TABLE kVASYAuftraegeRecord ADD kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE
20141015 10585207 EXC EMySqlException ("\r\n#42S21Duplicate column name 'kVASy_AuftragID'") at 008103D2 stack trace 00831ADF 00832212 0083225F 00687DAF 0083345A 00833526 0065543D 007F8888 006557D6 00655930 0040A2F7 0040A322 00ACD17C 00ACA1FA 00ABDAB8 00ABDACD 00ADA43C 00AD6A70 00AE6067 00AE6294
20141015 10585207 EXC EMyError ("\r\n#42S21Duplicate column name 'kVASy_AuftragID'") at 0082B6A8 stack trace API 00535998 0040B0D0 771CB46B 77180133 0082B6A8 0082D2AF 00832212 00687DAF 0065543D 006557D6 00ACD17C 00ADA43C 00AD6A70 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF
20141015 10585207 EXC EMyError ("\r\n#42S21Duplicate column name 'kVASy_AuftragID'") at 0082B6A8 stack trace API 00535998 0040B0D0 771CB46B 77180133 0082B6A8 0082D2AF 00832212 00687DAF 0065543D 006557D6 00ACD17C 00ADA43C 00AD6A70 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF
20141015 10585207 EXC EMyError ("\r\n#42S21Duplicate column name 'kVASy_AuftragID'") at 0082B6A8 stack trace API 00535998 0040B0D0 771CB46B 77180133 0082B6A8 0082D2AF 00832212 00687DAF 0065543D 006557D6 00ACD17C 00ADA43C 00AD6A70 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF
20141015 10585207 EXC EUniError ("\r\n#42S21Duplicate column name 'kVASy_AuftragID'") at 007F0FAC stack trace 00655930 0040A2F7 0040A322 00ACD17C 00ACA1FA 00ABDAB8 00ABDACD 00ADA43C 00AD6A70 00AE6067 00AE6294 008A5AB0 00AE6338 00406FAE 00AE0EF7 00406FAE 0040BD78 00ADFED6 00AE0F3D 00B2B8BE
20141015 10585207 EXC EUniError ("\r\n#42S21Duplicate column name 'kVASy_AuftragID'") at 007F0FAC stack trace 00AD6A70 00AE6067 00AE6294 008A5AB0 00AE6338 00406FAE 00AE0EF7 00406FAE 0040BD78 00ADFED6 00AE0F3D 00B2B8BE 00B2BC5B 00B07125 00B2E763 00B0D794 00406FAE 00AE0EF7 00AE41D7 00AE498B
20141015 10585207 - 00.008.558
20141015 10585207 EXC EORMException ("TSQLRestStorageExternal.Create: TSQLkVASYAuftraegeRecord: unable to create external missing field kVASYAuftraegeRecord.kVASy_AuftragID - SQL=\"ALTER TABLE kVASYAuftraegeRecord ADD kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE\"") at 00AD6AFA stack trace API 00535998 0040B0D0 771CB46B 77180133 00AD6AFA 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF 00AD456A 00AD369D 00AD1423 00ADD135 00B51300 00B50F17 00B52479 00B54E5A
20141015 10585207 info TSQLRestStorageExternal.Destroy -> {"TSQLRestStorageExternal(02815EC0)":{}}
20141015 10585207 EXC EORMException ("TSQLRestStorageExternal.Create: TSQLkVASYAuftraegeRecord: unable to create external missing field kVASYAuftraegeRecord.kVASy_AuftragID - SQL=\"ALTER TABLE kVASYAuftraegeRecord ADD kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE\"") at 00AD6AFA stack trace API 00535998 0040B0D0 771CB46B 77180133 00AD6AFA 008A5AB0 00ADFED6 00B2B8BE 00B2BC5B 00B07125 00B004B9 00B005DF 00AD456A 00AD369D 00AD1423 00ADD135 00B51300 00B50F17 00B52479 00B54E5A
20141015 10585207 EXC EORMException ("TSQLRestStorageExternal.Create: TSQLkVASYAuftraegeRecord: unable to create external missing field kVASYAuftraegeRecord.kVASy_AuftragID - SQL=\"ALTER TABLE kVASYAuftraegeRecord ADD kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE\"") at 00AD6AFA stack trace 00AE0F3D 00B2B8BE 00B2BC5B 00B07125 00B2E763 00B0D794 00406FAE 00AE0EF7 00AE41D7 00AE498B 00AE0F69 00AE4FBE 00AFD090 00AFC9D6 00B0DA3B 00B0E589 00B09FFD 00AFD020 00AFCA58 00AE0F69
20141015 10585208 EXC ESQLite3Exception ("Error SQLITE_ERROR (1) - \"TSQLRestStorageExternal.Create: TSQLkVASYAuftraegeRecord: unable to create external missing field kVASYAuftraegeRecord.kVASy_AuftragID - SQL=\"ALTER TABLE kVASYAuftraegeRecord ADD kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE\"QUE\"\"") at 00AD4A6A stack trace 00B51300 00B51270 00B50F17 74E148A1 74E148A1 74E148A1 74E148A1 0052119A 00B52479 00B529AB 00B54E5A 00B5541B 0094BB7D 0094B7BC 0094BBF5 0095F6DB 0095F705 00956073 009560BB 004CE564
20141015 10585208 - 00.027.617
20141015 10585208 + TSQLDatabase(0288CD58).00AD13EA
20141015 10585208 SQL ROLLBACK TRANSACTION;
20141015 10585208 - 00.000.023
20141015 10585208 EXC ESQLite3Exception ("Error SQLITE_ERROR (1) - \"TSQLRestStorageExternal.Create: TSQLkVASYAuftraegeRecord: unable to create external missing field kVASYAuftraegeRecord.kVASy_AuftragID - SQL=\"ALTER TABLE kVASYAuftraegeRecord ADD kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE\"QUE\"\"") at 00AD4A6A stack trace API 00535998 0040B0D0 771CB46B 77180133 00AD4A6A 00AD369D 00AD1423 00ADD135 00B51300 00B50F17 00B52479 00B54E5A 00B5541B 0094B7BC 00956073 0040BC82 758C338A 771A9F72 771A9F45
20141015 10585208 + TSQLRestServerDB(027FC900).Shutdown
20141015 10585208 info CurrentRequestCount=0
20141015 10585209 - 00.010.712
20141015 10585209 info TSQLRestServerDB.Destroy -> {"TSQLRestServerDB(027FC900)":{"NoAJAXJSON":false,"HandleAuthentication":true,"StaticVirtualTableDirect":true}}
20141015 10585209 + 00AD23A0
20141015 10585209 - 00.000.015
20141015 10585209 EXC ESQLite3Exception ("Error SQLITE_ERROR (1) - \"TSQLRestStorageExternal.Create: TSQLkVASYAuftraegeRecord: unable to create external missing field kVASYAuftraegeRecord.kVASy_AuftragID - SQL=\"ALTER TABLE kVASYAuftraegeRecord ADD kVASy_AuftragID varchar(30) character set UTF8 NOT NULL UNIQUE\"QUE\"\"") at 00AD4A6A stack trace 0094BB7D 0094B7BC 0094BBF5 0095F6DB 0095F705 00956073 009560BB 004CE564 0040BC82 758C338A 771A9F72 771A9F45 our UniDAC Version is 5.5.12
I Implemented my Database as Global - Variable now and checked the Reconnect with mysql stop/start - works fine.
@Zeos I don't use Zeos cause i use UniDAC in all of my Projekts and know it well. In normal Projekts i don't thinks it's slow.
Do you know the Reason why UniDAC is slower as ZEOS ? It uses MySQL-Direct Interface to connect to MySQL.
Hi AB ty for your response.
we'll use DocVariantData now to Add Values. Cause we have to Add multiple Values to doc.fehler we have to call the AddValue direkt.
I havent't digged as deep as you in the RTL but would it be more Safe to remove the Pseudo - Functions ?
Solved the Problem with a cast:
DocVariantData(doc.fehler).AddValue('testfehler', true);I found something about pseudo methods in syncommons.pas - But it seem's not to work in release mode on XE7 ?!
Hi AB atm we encounter a serious(german: merkwürdig) Problem using TDocVariant
var
doc : variant;
begin
TDocVariant.New(doc);
doc.Fehler := _Obj([]);
doc.Fehler.Add('testfehler', true);
assert(doc.fehler.testfehler = true, 'Fehler mit TDocVariant');
end;On my developer Computer it works. Now we startet the programm in another computer and the assertion fails.
the Value of doc.fehler.testfehler is false
Very serious is that i get this error also sometimes in my debugger. But i didn't find the reason for this.
May you can help if you tell me how to debug it or where i have to set a breakpoint to inspect code.
Best Regards
Hi AB,
today i tried to optimize my Service which connects to a MySQL - Server with the following Statement
FModel := CreateModel;
FConnection := TSQLDBUniDACConnectionProperties.Create(TSQLDBUniDACConnectionProperties.URI(dMySQL,host + ':' + port), databasename, username, password);
VirtualTableExternalRegisterAll(FModel, fConnection);
FSQLDB := TSQLDatabase.Create(SQLITE_MEMORY_DATABASE_NAME, '');
FDatabase := TSQLRestServerDB.Create(FModel, FSQLDB, true);
FDatabase.CreateMissingTables(0);because it is a service which every 10 min works with the database, i disconnect it after i dont use it.
To increase Perfomance i wanted to call CreateMissingTables only at Servicestart and removed the above line.
In that way:
FModel := CreateModel;
FConnection := TSQLDBUniDACConnectionProperties.Create(TSQLDBUniDACConnectionProperties.URI(dMySQL,host + ':' + port), databasename, username, password);
VirtualTableExternalRegisterAll(FModel, fConnection);
FSQLDB := TSQLDatabase.Create(SQLITE_MEMORY_DATABASE_NAME, '');
FDatabase := TSQLRestServerDB.Create(FModel, FSQLDB, true);
if IsServiceStarted then
FDatabase.CreateMissingTables(0);And here is the Problem:
Now the Connection does not connect to MySQL any more !!!
Allthough FConnection points to a MySQL Database.
Now i think in CreateMissingTable is some code which connects the SQLite Engine with the MySQL one ?!
Line 350ff
SetLength(result, TField(ColumnAttr).DataSize);
// itSDS TField(ColumnAttr).GetData(pointer(result));
TField(ColumnAttr).GetData(TValueBuffer(result));Replace Pointer with TValueBuffer
line 706ff
if aArrayIndex>=0 then
{ itSDS
P.SetBlobData(pointer(VArray[aArrayIndex]),Length(VArray[aArrayIndex])) else
P.SetBlobData(pointer(VData),Length(VData));
}
P.SetBlobData(TValueBuffer(VArray[aArrayIndex]),Length(VArray[aArrayIndex])) else
P.SetBlobData(TValueBuffer(VData),Length(VData));
{$else}GetData and SetBlobData with Pointer as Param are deprecated
ATM i found a solution:
procedure TSQLDBUniDACConnectionProperties.GetFields(
const aTableName: RawUTF8; var Fields: TSQLDBColumnDefineDynArray);
...
if Table='' then begin
Table := Owner;
Owner := '';
end;
// if Owner = '' then
// Owner := MainConnection.Properties.DatabaseName;
meta.Restrictions.Values['SCOPE'] := 'LOCAL';
if Owner<>'' then
meta.Restrictions.Values['TABLE_SCHEMA'] := UTF8ToString(UpperCase(Owner));
meta.Restrictions.Values['TABLE_NAME'] := UTF8ToString(UpperCase(Table));
...Setting SCOPE to LOCAL forces UniDAC to set SCHEMA to DATABASE() (for MySQL - didn't test yet for other DB-Server)
The other Alternative is to set:
Owner := MainConnection.Properties.DatabaseName;
What do you think about it
Given : 1 MySQL Server with 2 Databases (Base1, Base2)
1. I connected my mORMot EXE to Base1 and called CreateMissingTables - Everything works fine
2. I connected my mORMot EXE to Base2 and called CreateMissingTables - Get Error Message: Table not found. This is correct, the Table is not in Base2 but in Base1.
After Some Debugging i found the Error:
You Call Metadata for 'columns' in UniDAC without giving the Schema name In my Case Base1 or Base2
The Result is that you retrieve the Columns from Base1
The Second Metadata you select is Indexes and here the Error comes with Table not found.
Can you fix this please.
Place of error (SynDBUniDAC):
meta := (MainConnection as TSQLDBUniDACConnection).fDatabase.CreateMetaData;
try
FA.Init(TypeInfo(TSQLDBColumnDefineDynArray),Fields,@n);
FA.Compare := SortDynArrayAnsiStringI; // FA.Find() case insensitive
FillChar(F,sizeof(F),0);
meta.MetaDataKind := 'Columns';
Split(aTableName,'.',Owner,Table);
if Table='' then begin
Table := Owner;
Owner := '';
end;
if Owner<>'' then
meta.Restrictions.Values['TABLE_SCHEMA'] := UTF8ToString(UpperCase(Owner));
meta.Restrictions.Values['TABLE_NAME'] := UTF8ToString(UpperCase(Table));
meta.Open;
hasSubType := meta.FindField('DATA_SUBTYPE')<>nil;
while not meta.Eof do beginOwner is not set (I don't know where i can set Owner ?). For MySQL the Owner is the databasename which i set to base1/base2
Just tested it and it works.
Hi ab,
i updated to UniDAC 5.5.11 yesterday and get an Error Message Connecting to MySQL.
In UniDAC there is a new Validation Function which checks the SpecificOptions if you add / modify any.
Server and Port is no valid Option for this.
so i Modified SynDBUniDAC.pas a little
constructor TSQLDBUniDACConnection.Create(aProperties: TSQLDBConnectionProperties);
var options: TStrings;
PortNumber : Integer;
begin
inherited Create(aProperties);
fDatabase := TUniConnection.Create(nil);
fDatabase.ProviderName := UTF8ToString(fProperties.ServerName);
case aProperties.DBMS of
dSQLite, dFirebird, dPostgreSQL, dMySQL, dDB2:
fDatabase.Database := UTF8ToString(fProperties.DatabaseName);
else
fDatabase.Server := UTF8ToString(fProperties.DatabaseName);
end;
options := (fProperties as TSQLDBUniDACConnectionProperties).fSpecificOptions;
if fDatabase.Server='' then // see TSQLDBUniDACConnectionProperties.URI()
fDatabase.Server := options.Values['Server'];
if fDatabase.Database='' then
fDatabase.Database := options.Values['Database'];
if (fDatabase.Port=0) and TryStrToInt(options.Values['Port'], PortNumber) then
fDatabase.Port := PortNumber;
fDatabase.Username := UTF8ToString(fProperties.UserID);
fDatabase.Password := UTF8ToString(fProperties.PassWord);
// BUGFIX s.d. UniDAC 5.5.11 Überprüft ungültige Parameter
// fDatabase.SpecificOptions.AddStrings(options);
end;I removed the last line cause Server and Port where the only Options.
Pls Check if there could be any unknown consequences i did not see.
Ticket created ![]()
atm i switched to RawUTF8(38) instead of TGUID
With this modification it works.
Hi AB,
atm i want to add a record to a table wich contains a TGUID stored AS_UNIQUE.
This is not possible with the CrossPlatform Client.
In SynCrossPlattformJSON.GetInstanceProp the Code for tkRecord is missing.
Pls Help
The Server reply is:
{
"ErrorCode":400,
"ErrorText":"Bad Request"
}IDEA:
May be i could have found my error easier if the error was not "bad request".
Is it possible to give error Messages like "unknown user", or "wrong password" ?
sry ab i found the Error: SetUser is case sensitive and i wrote user not User as username ![]()
Hi AB i tried to connect an universal firemonkey Client to one of my mORMot Servers but the connection was refused.
i found this article: http://synopse.info/forum/viewtopic.php?id=1976
it seems to have the same Problem.
Under normal Windows Client this code works to connect to the Server:
CompressShaAesSetKey('xyz');
FDatabase := TSQLHttpClient.Create(Server,APort,FModel);
FDatabase.Compression := [hcSynShaAes];
FDatabase.SetUser('User','synopse');on Server Side i register the Database with this code:
DB := TSQLRestServerDB.Create(Model,AppPath + 'database.db3',true);
AddToServerWrapperMethod(DB, ['..\..\..\CrossPlatform\templates']);
CompressShaAesSetKey('xyz');
Server := TSQLHttpServer.Create('5001',[DB],'+',useHttpApiRegisteringURI, 32, secSynShaAes);How can i connect to this Server with the generated code ?
atm i'm using:
Client := GetClient('myurl.url', 'user', 'synopse');Have i to remove the encryption on Server Side ?
I think best way would be to generate code which could connect automatically.
Hi AB,
yesterday i run TestSQL3 witn XE7 and it worked as in XE6
good work ![]()
I think this post is going into the wrong direction...
What i want to do with mORMot is to write a http - WebSite with login.
After Login every logged in user should see its specific data.
Simultaneous login from multiple clients should be possible.
For Login i dont want to create the wheel again and use TAuthUser/Group (or a derived class)
Is it possible you create a little sample http - WebServer(service) which shows this ?
It would show how to login with http and would show the mormot session handling.
Thank you very much
Sry for the delay, had to look in the sources...
Yes in low-level SynCrtSock as in Indy. If cookies are necessary i don't know. I only want to create support a self generated "web-site" and the mORMot functionality in one service-exe.
The web-site (delphi part) should connect to the database as the client which snchronises with the service-data.
Hi AB,
i have an Idea and want to know what you are thinking about it.
ATM i'm using IndyHttpServer für a little WebServer service. Now i'm enhancing this service with mORMot and think about replacing the IndyhttpServer Komponent with the mORMot one.
The only thing I'm missing is some Session Handling Stuff as in Indy.
ATM i create a Session Object in TIdHttpSession to store some Session Data.
Would it be interesting / Possible to include some Session Handling in mormot http server ?
Thank you Arnaud
can you please tell me which method to override where i can extend the select statement from the Clients ?
ATM I'm thinking about a Problem where i don't know exactly if mormot supports it or where i have to implement it.
I'm Starting with example Projekt 4 and add the Option to log in as different Users to the Client.
(Using : TSQLHttpClient(Form1.Database).SetUser('User','synopse');)
Now my wish is that every AuthUser has its own Data. I think adding a field UserID to SampleRecord would fullfill my needs.
Now my Problem / Question :
where on Server Side can i modify the Query to include "userid = authuser.id" ?
Test 1.4 Synopse PDF failed
Exception at
Check(Hash32(MS.Memory,MS.Position)=Hash[embed]); 1.4. Synopse PDF:
! - TPdfDocument: 1 / 4 FAILED 9.47s
- TPdfDocumentGDI: 8 assertions passed 1.57s
Total failed: 1 / 12 - Synopse PDF FAILED 11.05sThat was the clue, I set the PUBLISHRECORD OPtion an removed the InternalRegister... functions. Now it works.
No, atm only xe6 supports RTTI for TGUID.
I tried the code unter XE5 with InternalRegisterCustomProperties but InternalRegisterCustomProperties is not called before the RTTI is needed as i wrote in this thread on 21.5.2014
I tested TGUID - Custom Property again today. The Exception still exists.
I think there must something be changed in TSQLRecordProperties.Create
The function AddParentsFirst throws an Exception cause of the GUID - Field before the Function InternalRegisterCustomProperties is called.
In my opinion custom properties should be made available and then you should create the field - List.
Hopefully you understand what i mean smile
Hi AB testet the feature today with XE5 but got same error as on 24.4.2014 (XE6 is working perfect)
Just as Addon concerning 0-Based Indexes:
The XE6 Debugger ignores the 0-Base and shows the Content of e.g. String-Buffers with 1 Based Index
I really don't like that 0-Base feature of Embacadero
I see you use this Compiler OPTION. In some other Part of my Software i didn't use it and got an error which i fixed as decribed in my former Post.
http://docwiki.embarcadero.com/RADStudi … s_(Delphi)
as decribed here it should not be used as global define only at little Subroutines.
Im just testing NEXTGEN Code with iOS and found a big Problem concerning:
http://docwiki.embarcadero.com/RADStudi … sktop_Apps
0-based index
procedure DoubleQuoteStr(var text: string);
var i,j: integer;
tmp: string;
begin
{$if CompilerVersion < 27)}
i := pos('"',text);
if i=0 then begin
text := '"'+text+'"';
exit;
end;
tmp := '"'+copy(text,1,i)+'"';
for j := i+1 to length(text) do
if text[j]='"' then
tmp := tmp+'""' else
AppendChar(tmp,text[j]);
{$else}
i := text.indexof('"');
if i < 0 then begin
text := '"'+text+'"';
exit;
end;
inc(i);
tmp := '"'+text.Substring(0,i)+'"';
for j := i+1 to text.Length - 1 do
if text.Chars[j] = '"' then
tmp := tmp + '""'
else
tmp := tmp + text.Chars[j];
{$ifend}
text := tmp+'"';
end;i just rewrote this func as Example, but there a lot lines of code where you assume s[1] = s[1] but it is s[0] ![]()
br Stefan
Hi Arnaud,
I just want to switch from SQLite to MySQL in my REST - Server.
I wrote this code, but I'm not Sure if it is correct to pass a SQLITE_MEMORY_DATABASE_NAME to TSQLRestServerDB.Create as i did.
Model1 := CreateModel1;
Model2 := CreateModel2;
fConnection := TSQLDBUniDACConnectionProperties.Create(TSQLDBUniDACConnectionProperties.URI(dMySQL,'localhost:3306'),'test','root','');
VirtualTableExternalRegisterAll(Model1, fConnection);
VirtualTableExternalRegisterAll(Model2, fConnection);
SQLDB1 := TSQLDatabase.Create(SQLITE_MEMORY_DATABASE_NAME,'');
// SQLDB1.UseCache := True;
Model1DB := TSQLRestServerDB.Create(Model1,lSQLDB,false);
Model1DB.CreateMissingTables(0);
SQLDB2 := TSQLDatabase.Create(SQLITE_MEMORY_DATABASE_NAME,'');
// SQLDB2.UseCache := True;
Model2DB := TSQLRestServerDB.Create(TSJobsDataModel,jSQLDB,false);
Model2.CreateMissingTables(0);
Server := TSQLHttpServer.Create('8080',[Model1DB, Model2DB],'+',useHttpApiRegisteringURI, 32, secNone);
Server.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queriesCan you please look at this code an optimize it ?
Thank you Arnaud it works ![]()
From my Third Person Point of view i Realy can't See any Reason why Arnaud should spent Time in brook or is anyone else here who is in Need of mormot to brook Support ?
I read your discussion, and just wan't to say something to prevent you all running in the wrong direction.
I'm writing Software for a long period of time now and use Delphi since Version 3
As you all know the prefered systems of the most clients in the world are Windows, Android, iOS, i don't know anyone who is using LINUX in practice.
May be I'm wrong but if you think as me you'll recognize that the mORMot System is optimal an does not really need fpc support.
But the CrossPlatform is very important to write Clients for mORMot.
I think come's time and the errors AB recognized in FPC are fixed, then its time to write on FPC if there is any who really is in need of it.
I personally don't need FPC support. And i don't need Brook atm ![]()
You're right I fixed it using SynCommons.Utf8ToString.
Very good work. I put it in one of my Programs instead of JSON unit. And works fine.
ATM i have a Problem with the German Umlaute: öäüßÖÄÜ
I store them in a TDocVariant on the Server. Retrieve it with TSQLRecord. But after Loading the TDocVariant Field into TJSONVariantData with Init.
The ä has changed to : ä
It seems the ä is converted to UTF8 Representation of ä but after loading the UTF8 representation ist converted to Single Unicode Chars.
Can you give me a clue how to deal best with this ?
Should i Convert the "umlaute" to something else like ä# or do you have something in your lib ?
I tested TGUID - Custom Property again today. The Exception still exists.
I think there must something be changed in TSQLRecordProperties.Create
The function AddParentsFirst throws an Exception cause of the GUID - Field before the Function InternalRegisterCustomProperties is called.
In my opinion custom properties should be made available and then you should create the field - List.
Hopefully you understand what i mean ![]()
line 13898
raise EORMException.CreateFmt('Unhandled %s/%s type for property %s',Hi Edwin,
i think every Developer has its own style. If i want to read Arnauds code i use the feature of Rad Studio to reformat the Sourcecode.
Hardware: Macbook Pro (i7-2.8GHz) with Windows 8.1 in VMWare VM
32Bit DEBUG
JSON benchmarking
-------------------
1. Small content
1.1. Synopse record:
- Read: 50,000 assertions passed 172.87ms 289,231/s
- Access: 100,000 assertions passed 914us 54,704,595/s
- Write: 50,000 assertions passed 113.53ms 440,381/s
Total failed: 0 / 200,000 - Synopse record PASSED 288.73ms
1.2. Synopse variant:
- Read: 50,000 assertions passed 260.27ms 192,101/s
- Access direct: 100,000 assertions passed 52.18ms 958,184/s
- Access late binding: 100,000 assertions passed 163.41ms 305,971/s
- Write: 50,000 assertions passed 172.68ms 289,541/s
Total failed: 0 / 300,000 - Synopse variant PASSED 651.15ms
1.3. X super object record:
- Read: 50,000 assertions passed 20.66s 2,419/s
- Access: 100,000 assertions passed 911us 54,884,742/s
- Write: 50,000 assertions passed 4.03s 12,400/s
Total failed: 0 / 200,000 - X super object record PASSED 24.69s
1.4. X super object properties:
- Read: 50,000 assertions passed 16.30s 3,067/s
- Access: 100,000 assertions passed 585.54ms 85,390/s
- Write: 50,000 assertions passed 782.88ms 63,866/s
Total failed: 0 / 200,000 - X super object properties PASSED 17.67s
1.5. dws JSON:
- Read: 50,000 assertions passed 308.65ms 161,993/s
- Access: 100,000 assertions passed 77.20ms 647,626/s
- Write: 50,000 assertions passed 312.43ms 160,031/s
Total failed: 0 / 200,000 - dws JSON PASSED 700.71ms
1.6. DBXJSON:
- Read: 50,000 assertions passed 3.79s 13,161/s
- Access: 100,000 assertions passed 41.85ms 1,194,486/s
- Write: 50,000 assertions passed 566.02ms 88,335/s
Total failed: 0 / 200,000 - DBXJSON PASSED 4.40s
2. Big content
2.1. Depth content:
- Download files if necessary: no assertion 781us
- Synopse read variant: 1 assertion passed 265.45ms 188,357/s 337 KB
- Synopse read to BSON: 2 assertions passed 3.17ms 15,762,925/s 175 KB
- dws JSON read: 1 assertion passed 8.29ms 6,030,635/s 307 KB
- DBXJSON read: 1 assertion passed 87.47ms 571,598/s 679 KB
Total failed: 0 / 5 - Depth content PASSED 370.94ms
2.2. Table content:
- Download files if necessary: no assertion 753us 10,926,958/s
- Synopse parse: 1 assertion passed 4.68ms 1,756,779/s 1.2 MB
- Synopse ORM loop: 41,135 assertions passed 7.77ms 1,058,135/s 1.2 MB
- Synopse ORM list: 41,135 assertions passed 8.63ms 953,191/s 952 KB
- Synopse table direct: 41,135 assertions passed 31.49ms 261,182/s 1.1 MB
- Synopse table variant: 41,135 assertions passed 29.99ms 274,324/s 1.1 MB
- Synopse doc variant: 41,137 assertions passed 49.79ms 165,210/s 4.6 MB
- Synopse late binding: 41,137 assertions passed 38.64ms 212,864/s 4.6 MB
- Synopse to BSON: 2 assertions passed 10.39ms 791,819/s 1.1 MB
- dws JSON: 41,136 assertions passed 33.89ms 242,720/s 4.7 MB
- DBXJSON: 41,136 assertions passed 215.80ms 38,123/s 9.9 MB
Total failed: 0 / 329,089 - Table content PASSED 446.50ms
2.3. Huge content:
- Download files if necessary: no assertion 733us
- Synopse read record: 4 assertions passed 2.45s 84,247/s 122.6 MB
- Synopse read variant: 2 assertions passed 3.37s 61,151/s 512.9 MB
- Synopse read to BSON: 3 assertions passed 2.12s 97,275/s 168.1 MB
- dws JSON read: 2 assertions passed 3.50s 59,005/s 672.7 MB
- DBXJSON read: no assertion 615us 81,300,813/s
DBXJSON will raise EOutOfMemory for 185 MB JSON in Win32 -> skip
Total failed: 0 / 11 - Huge content PASSED 11.81s
Generated with: Delphi XE6 compiler
Time elapsed for all tests: 61.06s
Tests performed at 18.05.2014 12:32:17
Total assertions failed for all test suits: 0 / 1,629,105
! All tests passed successfully.32Bit Release
JSON benchmarking
-------------------
1. Small content
1.1. Synopse record:
- Read: 50,000 assertions passed 126.96ms 393,800/s
- Access: 100,000 assertions passed 988us 50,607,287/s
- Write: 50,000 assertions passed 74.86ms 667,886/s
Total failed: 0 / 200,000 - Synopse record PASSED 204.75ms
1.2. Synopse variant:
- Read: 50,000 assertions passed 201.74ms 247,841/s
- Access direct: 100,000 assertions passed 50.88ms 982,685/s
- Access late binding: 100,000 assertions passed 159.65ms 313,173/s
- Write: 50,000 assertions passed 103.98ms 480,824/s
Total failed: 0 / 300,000 - Synopse variant PASSED 518.63ms
1.3. X super object record:
- Read: 50,000 assertions passed 20.40s 2,450/s
- Access: 100,000 assertions passed 984us 50,813,008/s
- Write: 50,000 assertions passed 3.88s 12,883/s
Total failed: 0 / 200,000 - X super object record PASSED 24.29s
1.4. X super object properties:
- Read: 50,000 assertions passed 16.07s 3,111/s
- Access: 100,000 assertions passed 530.41ms 94,265/s
- Write: 50,000 assertions passed 716.42ms 69,790/s
Total failed: 0 / 200,000 - X super object properties PASSED 17.32s
1.5. dws JSON:
- Read: 50,000 assertions passed 224.79ms 222,428/s
- Access: 100,000 assertions passed 64.19ms 778,864/s
- Write: 50,000 assertions passed 159.79ms 312,893/s
Total failed: 0 / 200,000 - dws JSON PASSED 451.24ms
1.6. DBXJSON:
- Read: 50,000 assertions passed 4.09s 12,218/s
- Access: 100,000 assertions passed 42.63ms 1,172,855/s
- Write: 50,000 assertions passed 531.19ms 94,126/s
Total failed: 0 / 200,000 - DBXJSON PASSED 4.66s
2. Big content
2.1. Depth content:
- Download files if necessary: no assertion 758us
- Synopse read variant: 1 assertion passed 69.91ms 715,133/s 337 KB
- Synopse read to BSON: 2 assertions passed 2.60ms 19,208,605/s 175 KB
- dws JSON read: 1 assertion passed 5.79ms 8,634,087/s 307 KB
- DBXJSON read: 1 assertion passed 83.36ms 599,764/s 679 KB
Total failed: 0 / 5 - Depth content PASSED 166.82ms
2.2. Table content:
- Download files if necessary: no assertion 758us 10,854,881/s
- Synopse parse: 1 assertion passed 3.43ms 2,394,353/s 1.2 MB
- Synopse ORM loop: 41,135 assertions passed 7.10ms 1,157,428/s 1.2 MB
- Synopse ORM list: 41,135 assertions passed 5.43ms 1,513,428/s 952 KB
- Synopse table direct: 41,135 assertions passed 22.68ms 362,694/s 1.1 MB
- Synopse table variant: 41,135 assertions passed 26.37ms 311,900/s 1.1 MB
- Synopse doc variant: 41,137 assertions passed 40.31ms 204,062/s 4.6 MB
- Synopse late binding: 41,137 assertions passed 32.77ms 251,006/s 4.6 MB
- Synopse to BSON: 2 assertions passed 8.97ms 916,249/s 1.1 MB
- dws JSON: 41,136 assertions passed 30.23ms 272,146/s 4.7 MB
- DBXJSON: 41,136 assertions passed 234.10ms 35,143/s 9.9 MB
Total failed: 0 / 329,089 - Table content PASSED 426.91ms
2.3. Huge content:
- Download files if necessary: no assertion 666us
- Synopse read record: 4 assertions passed 1.23s 167,382/s 122.6 MB
- Synopse read variant: 2 assertions passed 2.16s 95,524/s 512.9 MB
- Synopse read to BSON: 3 assertions passed 1.66s 124,376/s 168.1 MB
- dws JSON read: 2 assertions passed 3.42s 60,266/s 672.7 MB
- DBXJSON read: no assertion 335us 149,253,731/s
DBXJSON will raise EOutOfMemory for 185 MB JSON in Win32 -> skip
Total failed: 0 / 11 - Huge content PASSED 8.86s
Generated with: Delphi XE6 compiler
Time elapsed for all tests: 56.91s
Tests performed at 18.05.2014 12:36:06
Total assertions failed for all test suits: 0 / 1,629,105
! All tests passed successfully.64Bit Release
JSON benchmarking
-------------------
1. Small content
1.1. Synopse record:
- Read: 50,000 assertions passed 168.00ms 297,619/s
- Access: 100,000 assertions passed 1.85ms 26,910,656/s
- Write: 50,000 assertions passed 84.16ms 594,049/s
Total failed: 0 / 200,000 - Synopse record PASSED 255.94ms
1.2. Synopse variant:
- Read: 50,000 assertions passed 244.35ms 204,620/s
- Access direct: 100,000 assertions passed 48.51ms 1,030,651/s
- Access late binding: 100,000 assertions passed 153.71ms 325,287/s
- Write: 50,000 assertions passed 111.38ms 448,909/s
Total failed: 0 / 300,000 - Synopse variant PASSED 560.17ms
1.3. dws JSON:
- Read: 50,000 assertions passed 260.82ms 191,698/s
- Access: 100,000 assertions passed 69.11ms 723,411/s
- Write: 50,000 assertions passed 161.97ms 308,699/s
Total failed: 0 / 200,000 - dws JSON PASSED 493.75ms
1.4. DBXJSON:
- Read: 50,000 assertions passed 2.89s 17,266/s
- Access: 100,000 assertions passed 45.87ms 1,089,870/s
- Write: 50,000 assertions passed 493.61ms 101,294/s
Total failed: 0 / 200,000 - DBXJSON PASSED 3.43s
2. Big content
2.1. Depth content:
- Download files if necessary: no assertion 596us
- Synopse read variant: 1 assertion passed 145.50ms 343,642/s 458 KB
- Synopse read to BSON: 2 assertions passed 2.76ms 18,115,942/s 155 KB
- dws JSON read: 1 assertion passed 5.61ms 8,912,655/s 414 KB
- DBXJSON read: 1 assertion passed 53.63ms 932,157/s 877 KB
Total failed: 0 / 5 - Depth content PASSED 213.25ms
2.2. Table content:
- Download files if necessary: no assertion 590us 13,945,762/s
- Synopse parse: 1 assertion passed 2.95ms 2,784,094/s 1.4 MB
- Synopse ORM loop: 41,135 assertions passed 5.99ms 1,372,310/s 1.3 MB
- Synopse ORM list: 41,135 assertions passed 7.79ms 1,054,878/s 1.3 MB
- Synopse table direct: 41,135 assertions passed 16.75ms 491,046/s 1.3 MB
- Synopse table variant: 41,135 assertions passed 20.81ms 395,319/s 1.3 MB
- Synopse doc variant: 41,137 assertions passed 40.20ms 204,651/s 7.0 MB
- Synopse late binding: 41,137 assertions passed 32.70ms 251,544/s 7.0 MB
- Synopse to BSON: 2 assertions passed 11.24ms 731,548/s 1.2 MB
- dws JSON: 41,136 assertions passed 34.23ms 240,295/s 6.7 MB
- DBXJSON: 41,136 assertions passed 195.13ms 42,161/s 16.6 MB
Total failed: 0 / 329,089 - Table content PASSED 382.61ms
2.3. Huge content:
- Download files if necessary: no assertion 185us
- Synopse read record: 4 assertions passed 2.07s 99,706/s 148.7 MB
- Synopse read variant: 2 assertions passed 3.52s 58,559/s 766.1 MB
- Synopse read to BSON: 3 assertions passed 1.97s 104,480/s 170.0 MB
- dws JSON read: 2 assertions passed 7.64s 27,015/s 1.0 GB
- DBXJSON read: 2 assertions passed 35.37s 5,839/s 3.0 GB
Total failed: 0 / 13 - Huge content PASSED 51.07s
Generated with: Delphi XE6 64 bit compiler
Time elapsed for all tests: 56.42s
Tests performed at 18.05.2014 12:39:35
Total assertions failed for all test suits: 0 / 1,229,107
! All tests passed successfully.I just tried the new Version - but get Exception:
Unhandled sftUnknown/tkRecord for property xyzID
the class function InternalRegisterCustomProperties was not called before the Error !
Also i get memory fault after in TSQLModel.Destroy i just added 1 line of code
destructor TSQLModel.Destroy;
var
i,j: integer;
begin
for i := 0 to fTablesMax do begin
// >>> ADDED
if assigned(TableProps[i]) then
// <<< ADDED
with TableProps[i].Props do begin
EnterCriticalSection(fLock); // may be called from several threads at onceYes you are right. In TSQLPropInfoRTTI.CreateFrom
the aType.Kind = tkRecord and aType.Name = 'TGUID'
aSQLFieldType = sftUnknown
You're right the TRestClient is undocumented by Embarcadero and you have to dig through the source code and Example to understand.
It is based on Indy and has a JSON decoder integrated.
There is a Problem in XE6 with registering the TGUID as described in the Handbook 1.18.
It throws Exception unhandled type for ... in TSQLPropInfoRTTI.CreateFrom
To test add
TSQLRecordCustomProps in SynSelfTests.pas ~ Line 8571 TSQLModel.Create(...., TSQLRecordCustomProps);
After reading a lot in the Forum i think this Post fits best here.
I try to develop a pure delphi app for iOS and Android with XE6, FMX.
For native Data Storage i use UniDac Components.
For Client/Server Communication Sync / Dataexchange i prefer to use mORMot.
I'll write a native mORMot Server with a Port opened to the internet.
This should be secured with ssl and authentication.
ATM im confused which Client Strategy to use.
- How far is the mORMot Client ?
- Is there an Example for the propesed Indy - Client to Access mORMot Server ?
- Since XE5 there is a new Component in Delphi: TRestClient - which works on Android and iOS.
I have Problems to integrate the mORMot - Authentication is this Component - without Authentication it works. I need some hints (maybe example or Links) to program this.
Thanks for the answer, i changed add -> batchadd but my real Problem still persists.
It is not easy to explain for me in english. But i try with an example.
I have 2 Programm
One is the Server as in Example 004.
This Programm i start from Windows.
The Second Programm is the one I'm developing on. Lets call it Client.
I start Client and set Breakpoint in the "BatchAdd" - Loop in AddTestRecord....
As Breakpoint is reached i stop debugging with STRG+F2.
The Server does not get Rollback nor Commit.
I start Debugging again with Server running from prior test.
Now StartTransaction results in false.
Why this - the Client was restartet ?! Session is broken ?!
As Consequence i have to restart the Server. This is not good. In Practice there may be the same Problem if Client loses Connection in the loop.
The Point and my Question is how to debug without restarting the Server ?
Is there a Rollback for prior open Transactions or anything else ?
Or other Question I only use Transaction to speed it up - is this neccessary ?
tyvm everything works fine now.
One more Question concerning this task.
Is it possible to interpret the Result from google directly with mORMot. Actual i use Indy to retrieve the http - Stream
Stream := TStringStream.Create(res);
try
Str := TIDUri.UrlEncode(STR_WEB + AAdresse + '&sensor=false');
IdHTTP.Get(Str, Stream);
Infos := Stream.DataString;
U := AnsiString(Infos);
JSON := RecordLoadJSON(Cache,@U[1],TypeInfo(TGoogleGeoCodeJSON));
if assigned(JSON) then tryI think i have to provide my original piece of code to find the error:
i try to decode google geocode - Data.
This is my Structure
TGoogleAdressComponentsJSON = packed record
long_name, short_name : RawUTF8;
types : array of RawUTF8;
end;
TGoogleLocationJSON = packed record
lat, lng : double;
end;
TGoogleViewportJSON = packed record
northeast : TGoogleLocationJSON;
southwest : TGoogleLocationJSON;
end;
TGoogleGeometryJSON = packed record
location : TGoogleLocationJSON;
location_type : RawUTF8;
viewport : TGoogleViewportJSON;
end;
TGoogleAdressJSON = packed record
addess_components : array of TGoogleAdressComponentsJSON;
formatted_address : RawUTF8;
geometry : TGoogleGeometryJSON;
partial_match : boolean;
types : array of RawUTF8;
end;
TGoogleGeoCodeJSON = packed record
results : array of TGoogleAdressJSON;
status : RawUTF8;
end;
const
__TGoogleGeocodeJSON = 'results ['+
'address_components [long_name RawUTF8 short_name RawUTF8 types array of RawUTF8] '+
'formatted_address RawUTF8 ' +
'geometry {location {lat, lng double} '+
'location_type RawUTF8 '+
'viewport {northeast {lat, lng double} southwest {lat, lng double}}} '+
'partial_match boolean '+
'types array of RawUTF8'+
'] '+
'status RawUTF8';I modified ProcessValue in SymCommons.pas
ptArray: begin
if P^<>'[' then
exit; // we expect a true array here
repeat inc(P) until P^<>' ';
// allocate nested array at once
ArrayLen := JSONArrayCount(P);
if ArrayLen<0 then
exit; // invalid JSON array
Prop.AllocateNestedArray(PPtrUInt(Data)^,ArrayLen);
// read array content
if ArrayLen>0 then begin
DynArray := PPointer(Data)^;
for j := 1 to ArrayLen do begin
{$ifdef ALIGNCUSTOMREC}
BegDynArray := DynArray; // for 8 byte alignment of arrays
{$endif}
if Prop.NestedProperty[0].PropertyName='' then begin
// array of integer/string/array/custom...
if not ProcessValue(Prop.NestedProperty[0],P,DynArray) or (P=nil) then
exit;
end else // array of record
if not Prop.ReadOneLevel(P,DynArray,Options) or (P=nil) then
exit;
{$ifdef ALIGNCUSTOMREC}
inc(DynArray,(PtrUInt(DynArray)-PtrUInt(BegDynArray)) and 7);
{$endif}
if P^=',' then
inc(P);
end;
end;
if P=nil then
exit;
P := GotoNextNotSpace(P);
>> INSERTED
if (EndOfObject = ']') and (P^='}') then begin
EndOfObject := '}';
inc(P);
end else
<< INSERTED
if (P^=']') or (Prop.NestedProperty[0].PropertyName<>'') then begin
if (P^<>']') then
exit; // we expect a true array here
repeat inc(P) until not(P^ in [#1..' ']);
EndOfObject := P^;
if P^<>#0 then //if P^=',' then
inc(P);
end;
end;and the parser work now.
(Now its working fine !)
Thank you the Preparation now works fine,
but in ReadOneLevel / ParseValue is an Error in parsing the array.
EndElement is set to ] not to } as expected from the parser after parsing the String array
"types" : [ "testtype_1" ]the Parser exits with error.
Example :
{
"test" : [
{
"name1" : "name1_1",
"name2" : "name2_1",
"types" : [ "testtype_1" ]
},
{
"name1" : "name1_2",
"name2" : "name2_2",
"types" : [ "testtype_2" ]
}
]
}