#1 mORMot 1 » SQLGetTable and View names » 2020-04-14 09:36:12

mariomoretti
Replies: 1

Hi Arnaud,

I found an errore in SynDB.pas : for MySQL , the sql returned for table and views contain the  keyword concact instead of concat.

I'd also like if GetTableName and GetViewName function could take care of value stored in ForcedSchemaName : actually they always return tables for all schemas.

tx very much and a special greeting in this  sad period.

Mario

#2 Re: mORMot 1 » Iso8601ToTimeLogPUTF8Char doesn't handle ISO8601 times » 2018-10-07 05:21:52

Ok,
for other distracted as me : I have to use Iso8601ToTimePUTF8Char !!!
by

#3 Re: mORMot 1 » Iso8601ToTimeLogPUTF8Char doesn't handle ISO8601 times » 2018-10-03 13:49:36

Sorry but , if I'm not wrong,  Z indicates that the time value is the time in Greenwich, England, or UTC time.

What I was trying to say is that the function doesn't work with simple ISO 8601 time (without date).
Is there another way to handle this ?
Tx very much.

#4 mORMot 1 » Iso8601ToTimeLogPUTF8Char doesn't handle ISO8601 times » 2018-10-03 04:02:35

mariomoretti
Replies: 3

Hi AB,

if I try to convert an ISO8601 time expression (10:30:47.0Z), the function fails because doesn't start with an year (4 digits) but the standard allows this format.

#5 Re: mORMot 1 » tRawByteStringStream » 2018-01-27 18:36:20

No reply , so i opened a ticket...

Result : rejiected because it could break existing code.
I obviously agree wit this concept.
I don't agree with the fact that as is 'well' documented this stream is only for append. There isn't any line in the SAD saying that tRawByteStringStream may not be used as any other one derived from tstream class.

#6 mORMot 1 » tRawByteStringStream » 2018-01-14 06:30:57

mariomoretti
Replies: 2

Hi AB,

sorry but i don't remember how to open a ticket.

The write methof of this object doesn't work well if one want to write before the end of the buffer, changing the stream position to do it.

function TRawByteStringStream.Write(const Buffer; Count: Integer): Longint;
begin
  if Count<=0 then
    Result := 0 else begin
    Result := Count;
    SetLength(fDataString,(fPosition+Result));
    MoveFast(Buffer,PByteArray(fDataString)[fPosition],Result);
    inc(FPosition,Result);
  end;
end;

I have made this change and now seems to be right.

// before 
SeltLength(fDataString,(fPosition + Result))
//after
 if fPosition+Result > Length(fDataString) then SetLength(fDataString,(fPosition+Result));

#7 mORMot 1 » Happy new year » 2018-01-02 05:57:05

mariomoretti
Replies: 2

Somebody sent me this : https://github.com/mariomoretti/GitHub/ … N_ANNO.mp4

Happy new year AB and everybody.

Mario

#8 Re: mORMot 1 » RawUTF8ArrayToCSV & CSVToRawUTF8DynArray » 2017-12-15 11:35:22

Ok,

I've modified as you suggested.

Tx very much

#9 mORMot 1 » RawUTF8ArrayToCSV & CSVToRawUTF8DynArray » 2017-12-15 10:00:12

mariomoretti
Replies: 2

Hi,

I converted this rawutf8  dyn array :

['A'
'B'
''
'C'
''] 

to csv with RawUTF8ArrayToCSV, obtaining  A,B,,C,  as result.

When I call CSVToRawUtf8DynArray , then returned array ignores the blanks element of the array and returns

['A'
'B'
'C']


I have modified the function in Syncommons , excluding the control on s>''. Now it seems to work well, returning the original array;


procedure CSVToRawUTF8DynArray(CSV: PUTF8Char; var Result: TRawUTF8DynArray;
  Sep: AnsiChar; TrimItems: boolean);
var s: RawUTF8;
begin
  while CSV<>nil do begin
    s := GetNextItem(CSV,Sep);
    if TrimItems then
      s := trim(s);
    //if s<>'' then begin
      SetLength(Result,length(Result)+1);
      Result[high(Result)] := s;
    //end;
  end;
end;

#10 Re: mORMot 1 » tSynNameValue method's default options » 2017-07-25 10:20:41

Tx AB,
now it works fine.

My problem was that, with default behavior,  string values containing only digits inserted with asCSV, were returned by initfromcsv with a #13 added at the end. 

1 was returned as 1#13.

#11 mORMot 1 » tSynNameValue method's default options » 2017-07-23 22:02:48

mariomoretti
Replies: 2

tSynNameValue in syncommons has these two methods:

 procedure InitFromCSV(CSV: PUTF8Char; NameValueSep: AnsiChar='=';
      ItemSep: AnsiChar=#10);

and

    function AsCSV(const KeySeparator: RawUtf8='=';
      const ValueSeparator: RawUtf8=#13#10; const IgnoreKey: RawUTF8=''): RawUTF8;

are there reasons to maintain  different default values for itemsep , or is it possible to uniform them ?

tx

#12 Re: mORMot 1 » using sqlite or external database » 2017-06-07 14:09:56

TX AB,

AB wrote:

First of all, what I do currently is not to inherit from TSQLRestServerDB, but use a TSQLRest field and fill it with a TSQLRestServerDB instance - sometimes using a TSQLRestServer field.
To separate logic and storage. You may use for instance a remote DB later on.

Don't create an external SQLite3 database.
TSQLRestServerDB has already a Sqlite3 engine running, and its own database: no need to use SynDB here.

Sorry but I don't understand what you are telling me. I imagine how busy you are, but could you be so kind to show me an example ?

AB wrote:

About transactions, the way to go is to use a TSQLRestBatch, not create manual transactions.

I can't use a tSQLRestBatch because sometimes  , in the same transaction, i need to know the ID of an inserted record to fill a property of another class before inserting it (I've tried to define it as tSQLRecord, but in some circumstances i can't do it). If I have well undertstood the batchsend operates a commit, so, using batch,  it's impossible to grant that all data are persisted togheter.

#13 mORMot 1 » using sqlite or external database » 2017-06-07 05:25:36

mariomoretti
Replies: 2

I've started a project  where you can configure at startup if use a sqlite or an external database.
On server side , i'm using a tSQLRestServerDB to access the data , created using two distinct approach owing to the case :

         fModel := CreateModel(aRoot);
         fProps := nil;
         if aDNS > '' then  // ODBC
         begin
              fProps := TODBCConnectionProperties.Create(aDNS, '',aUser, aPwd);
              VirtualTableExternalRegisterAll(fModel, fProps);
         end
         else fProps := TSQLDBSQLite3ConnectionProperties.Create(aDBFileName,'','','');

         inherited create(fModel, aDBFileName);
         if aDNS > ''  then
         begin
              // optionally execute all external DB requests in a single thread
              AcquireExecutionMode[execORMGet] := amBackgroundORMSharedThread;
              AcquireExecutionMode[execORMWrite] := amBackgroundORMSharedThread;
         end;
         CreateMissingTables(0);

it seems to work , in the sense that the tables are created, updated etc... but , when i started to use an external database i've found some issues :

using server.transactionbegin and commit or rollback doesn't work : on external database transactions are not started.
mainengineretrieve is not called : i have found in mormot.pas  :    /// overridden methods for direct sqlite3 database engine call: 
Obviously I need to override it using sqlite or external tables.

After days I've found a workaround to solve the first using fProp.Mainconnection.StartTransaction /commit/rollback for estrernal db and transactionbegin for sqlite.
But i don't know how to solve the second.

Is there anybody knowing a solution ?

tx very much

#14 Re: mORMot 1 » MormotSqlite3.MainEngineList doesn't rise exception » 2017-05-31 11:02:19

Sounds a very good reason.

I have added a control of StatementLastException after the createandfillprepare nested in transaction : now seems to work ok.

tx very much AB.

#15 Re: mORMot 1 » MormotSqlite3.MainEngineList doesn't rise exception » 2017-05-31 08:20:09

Well,

one thing i have clear , i am totally confused and thick as a brick !!

Sorry to annoying you with newby questions, but i'm trying to put order in my mind :

- a tSQLRestServerDb runs only on server side.
- I'm using a tSQLClientRestURI to run processes from remote.
- so , why a tSQLRestServerDB.CreateAndFillPrepare  doesn't return an exception ?

#16 Re: mORMot 1 » MormotSqlite3.MainEngineList doesn't rise exception » 2017-05-31 07:14:33

Anhoter question please :

on server side , what object, instead of tMySQLRestServerDB, I should better use to access data by ORM?

#18 mORMot 1 » MormotSqlite3.MainEngineList doesn't rise exception » 2017-05-31 06:47:59

mariomoretti
Replies: 7

Hi AB,

in line 1337 of unit in subject there are these istructions .

      except
        on E: ESQLite3Exception do
          GetAndPrepareStatementRelease(E);
      end;

createandfillprepare , in case of exception, returns a null resultset without any advertisement.
This means that i have , every time , to check for tSqlRsetServerDB.StatementLastException to be sure that all worked fine ?
Now i'm only catching  exceptions.

#19 Re: mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2017-05-29 05:55:07

This is the trace of a fServer.TransactionBegin :

MormotSqlite3.TSQLRestServerDB.TransactionBegin


SynSqLite 3.tSQLDataBase.TransactionBegin
SynSqLite 3.tSQLDatabase.EXECUTE('BEGIN TRANSACTION')
SynSqLite 3.TSQLRequest.Execute
SynSqLite 3.tSQLRequest.Prepare

Sqlite3.prepare_v2....

#20 Re: mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2017-05-29 05:17:45

I've tried to put breackpoints in syndbodbc.starttransaction , commit and rollback : they are never called  by fserver.transactionbegin or commit.
I searched for examples without success : please help me.
tx

#21 Re: mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2017-05-28 23:13:12

I'm sorry to return to this issue , but i'm accidentally seen that the problem persists.
This is how i define the connection to a postgres db via odbc on server side:

       fProdConn := tODBCConnectionProperties.create(DNS, '',User, Pwd);
       .....  // add all table to model.
       fModel := CreateModel(HTTPRoot);    
       VirtualTableExternalRegisterAll(fModel, fProdConn);                 
       fServer := tSQLRestServerDB.create(fModel, databasename);  // databse name is the sqlite3 db.

I'm updating db only on server side via the tSQLRestServerDB (clients uses only services via interfaces).
In this example i'm changing the row ID in same tables reding from Jobs the tableindex, oldID and newID.
Every change is immediately visible in db, and even if i change commit with rollback, the db doesn't revert to old state.

fServer.TransactionBegin(tSQLCD_Queue, 1);
try 
   Jobs := tSQLCD_Queue.CreateAndFillPrepare(fServer,'status=1 order by id', []);
   try
      while Jobs.FillOne do
      begin
           aSQLRecordClass := fServer.Model.Tables[Jobs.TIndex];

           aSQLRecord := aSQLRecordClass.create(fServer, Jobs.OrigID);
           try
              // erase original record
              fServer.Delete(aSQLRecordClass, Jobs.OrigID);

              // Insert with new ID
              aSQLRecord.IDValue := Jobs.NewID;
              fServer.Add(aSQLRecord, true, true, False);
            finally
                   aSQLRecord.Free;
            end;
	end;
   finally
	jobs.free;
   end;
finally
	fServer.commit(1, true);
	// fServer.rollback(1);
end;	

Please say me where i'm mistaking.
Tx very much.

#22 Re: mORMot 1 » tablemaxid and external database » 2016-09-26 22:33:34

Hi AB,

sorry for delay and tx very much.

Now it works, but i had to upgrade to last revision. Nothing of bad , except that now i'm encountering another problem in tSQLRestServerDB.Executelist .

This is the line that doesn't work no more on postgres DB via ODBC :

        rows := DataBase.ExecuteList([tSQLCD_Params],'select data from ' + tSQLCD_Params.SQLTableName); 

the error reported is : TODBCStatement.GetCol: "data" column had Indicator=1376

data is a blob and , debugging, i've found that the error is fired because of a modification in function GetDiagField of unit SynDbODBC, line 1848.

Before it was  :

 
     if ODBC.GetDiagRecW(SQL_HANDLE_STMT,StatementHandle,1,
       Sqlstate,NativeError,MessageText,1024,StringLength) = 0 then
     begin
          i := 0;
          while sqlstate[i]> #0 do
          begin
               result := result + sqlstate[i];
               inc(i);
          end;
     end;

GetDiagRecW returned 0.
Now it is :

  if ODBC.GetDiagFieldA(SQL_HANDLE_STMT,StatementHandle,1,SQL_DIAG_SQLSTATE,
     @Status,sizeof(Status),StringLength)=0 then
    SetString(result,PAnsiChar(@Status),StringLength) else
    result := '';
  

The GetDiagFieldA doesn't return 0.

#23 mORMot 1 » tablemaxid and external database » 2016-09-21 05:47:28

mariomoretti
Replies: 2

Hi to all,

tSQLRestServerDB.TableMaxID only works with Sqlite db?
In postgret it returns an error : rowid column doesn't exists.

I suppose that also "limit" could be a problem with some db engines.

tx

#24 Re: mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2016-09-21 05:38:34

Hi,

i solved using transaction only with tsqlrestserverdb.transactionbegin : the complex query are needed only in select statements.

tx.

#25 Re: mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2016-08-17 04:46:06

Ok,

sorry for delay.

i'd like very much to use a single Database.Db instance !

A little resume.

I started project using only sqlite3 and ORM.

When I switched to ODBC , I reailized that some queries were too complex for ORM , so I introduced the TSQLDBConnectionProperties (also for Sqlite, to have a unique way to access data).

This introduced transaction and locking problems owing to the way I created the connection.

Now , thank to you, i've understood how to do it for sqlite3.

Using an external db , via ODBC , i've attempted  various ways, but I cannot resolve how to register the virtual tables before creating the ODBC connection.

Could you , please , tell me how to create the Database without creating , before, the ODBC connection on wich register the virtual tables ? I cannot solve how to do it (i always obtain exception because external engine is unknown).

tx very much

#26 Re: mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2016-08-16 11:03:38

Hi AB,

i'm having trouble using a connection to access database (else sqlite or external).

Certainly i'm doing something of wrong, but cannot resolve the issue, so i've reproduced this little example in which I show how i'm defininig a TSQLDBSQLite3ConnectionProperties, used to access data when queries are too complex  and a TSQLRestServerDB for ORM

Till when I don't fire a select (i.e. till when i don't use directly the connection) , all works fine, but, after the usage of a dbConn.execute, accessing data with ORM results in a unpredictable error : in this example , trying to update a blob field (only a blob) via ORM results in this error : Error SQLITE_BUSY (5) [Step] using 3.13.0 - database is locked, extended errcode=5.
Using ODBC also i've similar problems.

Coud you tell me how i should correctly define this scenario ?
tx very much.


unit Unit1;

interface

uses
  {$ifdef MSWINDOWS}
  Windows,
  Messages,
  Graphics,
  {$endif}
  Classes, SysUtils, Forms, Controls, Dialogs, StdCtrls,
  SynCommons,
  SynDB,
  mORMot,
  mormotsqlite3,
  synDBsqlite3;

type

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
         DBConn : tSQLDBConnectionProperties;
         fConn : TSQLDBSQLite3Connection;
    { private declarations }
  public
    { public declarations }
    Database: TSQLRestServerDB;
    Model: TSQLModel;
  end;

  TSQLSampleRecord = class(TSQLRecord)
  private
    fData     : RawUtf8;
    fBlobData : RAwByteString;
  published
    property Data : Rawutf8 read fData write fData;
    property BlobData : RawByteString read fBlobData write fBlobData;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var Model : tSQLModel;
    s : tSQLSampleRecord;
    rows : isqldbrows;
    V : Variant;
    data : RawByteString;
begin
  model := tSQLModel.Create([tSQLSampleRecord]);
  DataBase := tSQLRestServerDB.Create(model,'test.db3');
  DataBase.CreateMissingTables(0);
  s := tSQLSampleRecord.Create(Database, 1);
  s.Data := 'data';
  s.BlobData := 'blobdata';
  if s.ID = 0 then Database.Add(s, true);
  s.Free;
  dbConn := TSQLDBSQLite3ConnectionProperties.Create('test.db3','','','');
  dbconn.MainConnection.Connect;
end;




procedure TForm1.FormDestroy(Sender: TObject);
var Model : tSQLModel;
    s : tSQLSampleRecord;
    rows : isqldbrows;
    V : Variant;
    d : Rawutf8;
    blobd : rawbytestring;
begin
     // here the select (if not executed, updateblobfields works fine.
     rows := dbconn.execute('select data from ' + tSQLSampleRecord.SQLTableName, [], @V);
     if rows.Step then
        d := rows.ColumnUTF8(0);
     rows := nil;

     s := tSQLSampleRecord.Create(Database, 1);
     s.data := 'òaiosufvbnsliughjwrpt90rp35';
     s.blobdata := 'òaifgdffosufvbnsliughjwrpt90rp35';
     database.update(s);
     database.UpdateBlobFields(s);
     s.free;
     database.Free;
     model.free;
     dbconn.Free;
end;

end.

#27 Re: mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2016-08-15 01:08:33

You are right,i'm using two diverse connection, because  i'm confusing direct sql via the connection and ORM.

I need to use direct sql because the use of queries too complex for ORM.

I'll try to use only one of the two method  in a transaction.

tx very much.

#28 mORMot 1 » TSQLDBSQLite3ConnectionProperties.mainconnection transaction » 2016-08-14 05:54:25

mariomoretti
Replies: 13

Hi,

in my project one can decide to use sqlite or an external db via ODBC.

On server side, to uniform db access , I create a TSQLDBSQLite3ConnectionProperties or a TODBCConnectionProperties to access data and use theirs Mainconnection to start a transaction when needed.

        if Params.ExternalDB then
             fProdConn := TODBCConnectionProperties.Create(Params.DBName, '', Params.DBUser, Params.DBPwd)
        else
            fProdConn := TSQLDBSQLite3ConnectionProperties.Create(StringToUtf8(DataBaseName),'','','');

        fProdconn.MainConnection.Connect;
        fConn := fProdConn.MainConnection;

fConn is the connection used by the server to start a transaction.

The project initially used only sqlite as database, so there was no a connection, but the transactions where started via the TSQLRestServerDb.TransactionBegin, now it uses fConn.StartTransaction.

When installing , the program asks to define where host the tables, then creates and populates some of them with data , in a whole transaction : start a transaction, insert all rows and finally commit.

There are minus then one thousand rows to add and the inserting time was of few seconds using sqlite and TSQLRestServerDb.TransactionBegin.

Now , using fConn.StartTransaction , via ODBC take the same little time, but using sqlite , the inserting time results in more than two minutes and  I've noted that it continuosly creates and deletes DatabaseName.journal on disk.

Probably there is something that i'm wronging , may someone help me ? Tx.

I'm using last revision of the framework.

#29 Re: mORMot 1 » Unexpected array size error in tSqlRestServerDB.ExecuteList » 2016-07-25 06:29:20

Ok AB,

User may decide if use sqlite or odbc, so i've added a control to use the odbc connection or not and all now works fine.

Complex queries are already only on server side and almost all executed at startup.

tx very very much for you proverbial responsiveness.

Mario

#30 mORMot 1 » Unexpected array size error in tSqlRestServerDB.ExecuteList » 2016-07-24 19:31:49

mariomoretti
Replies: 3

Hello everybody,

I switched tables from sqlite to an external db via ODBC.

A statement worked fine in the sqlite engine , but now raise an error calling tSQLRestServer.InternalAdaptSQL.

The statement is (T is  a tSQLTableJSON):

T := aRest.ExecuteList([tSQLCD_Company], 'select ID from ' + tSQLCD_Company.SQLTableName +
                                            ' where ownerco=0 or id in (select id from ' + tSQLCD_Company.SQLTableName +
                                            ' where ownerco=' + inttostr(maincompany.ID)+')');

maincompany.id is 0, so the resulting statement is
   
select ID from CD_Company where ownerco=0 or id in (select id from CD_Company where ownerco=0) (It seems not having a sense, but is only because the table is empty, so maincompany.id is 0 instead to be >0).

ownerco is a  tID field.

The error is raised in TSynTableStatement.Create when processing the second where condition :  id in (select id from CD_Company where Ownerco=0).

I've debugged and found that it seems dued to an unknown type for  (select id from CD_Company where ownerco=0) , but i was not able to arrange it either patching the source or finding a workaround.

May anyone help me ?

Thanks in advance

Mario

#32 mORMot 1 » sqlite db lock » 2016-05-11 18:06:39

mariomoretti
Replies: 2

Hi,

while debugging some routines i normally change a field value in a table using an external tool (sqlitespy), to put in it a value that force the code to do what i expect.

My code used a tSQLRestServerDB to access the database , but now i'd like to use interfaced services.

If I use only ORM methods that access the database by the server instance, I may change the data from sqlitespy, but when i start e client session using tSQLHttpCLient, i cannot more do it. The program returns this error :  Sqlite error 5 - database is locked.

I've posted the code. The lock happens in the line fClient.SetUser('User', 'synopse').

I have submitted this post only to understand if this is normal (the framework works without problems) or if this can be dued to some of wrong done defining server or client or so on.

Thanks in advance to anyone.



     if fClient = nil then
     begin
           fClientModel := tSQLModel.create(servizi.Server.Model);  // clone the server model
          tout := params.HTTPTimeout * 1000;
          fClient := tSQLHTTPClient.Create('localhost', Params.httpport, fClientModel, tout, tout, tout);
          if not fClient.ServerTimeStampSynchronize then
          begin
               result := nil;
               ShowMessage(UTF8ToString(fClient.LastErrorMessage));
               exit;
          end;
          fClient.SetUser('User', 'synopse');
          fClient.ServiceDefine([ICDAnagraphics], sicClientDriven);
          fClient.OnAuthentificationFailed := RetryAfterTimeout;
     end;

#33 mORMot 1 » tsqlrecord.createcopy » 2015-09-01 05:39:41

mariomoretti
Replies: 0

bonjour ab,

problably i'm trying to do something of wrong (as often i do), but i'd like your opinion.

i've defined an ancestor class derived from tSQLRecord : tClass1.
This class is a common ancestor for other classes : tAClass1, tBClass1 etc.
In a unit i've defined some common tasks on tClass1.

I pass to this unit instances of tAClass1, tBClass1 as a  parameter , fData (obviously defined of type tClass1) and the exact derived class type in an other parameter  fDataClass.

All works fine except that when i  do a copy of such instance in this way : fDataCopy := fData.CreateCopy as fDataClass.  On destroying it, i obtain a memory leak.

My question is : i cannot use createcopy in this a way and must define methods on each derived class, using the exact class (instead of fData of type tClass1), or the record destructor should anyway release correctly the data ?

tx

#34 Re: mORMot 1 » sqlrecord properties are assigned as int32 » 2015-08-16 12:51:45

ok ab,

as we know , the documentation of this big framework is BIG.
What about raise an axception on b.A=A.AstSqlRecord if A.ID is greater than maxint? It could avoid any misunderstanding (now , in the db field,  is stored 2147483648!).

#35 Re: mORMot 1 » sqlrecord properties are assigned as int32 » 2015-08-16 08:45:56

I may agree about little search but... i haven't done any search , thinking that record properties should permits to store any record.
Sorry.

#36 mORMot 1 » sqlrecord properties are assigned as int32 » 2015-08-15 21:29:46

mariomoretti
Replies: 5

I've two classes

ClassA = class(tSqlRecord)
protected
   fdesA : rawutf8;
published 
   property desA : rawutf8 read fDes write fDes; 
end;

ClassB = class(tSqlRecord)
protected
   fdesB : rawutf8;
   fA : ClassA; 
published 
   property desB : rawutf8 read fDesB write fDesB; 
   property A : ClassA read fA write fA;
end;
 

In class a there is an instance with ID = maxint + 1 (2147483648).


procedure test;
var a : classa;
      b : classb;
     aID : tID;
begin
        a := classa.create;
        a.desa := 'A';
        a.idvalue :=  2147483648;
        server.add(A, true, true);
        b := classb.create;
        b.desb := 'B';
        b.A := A.Astsqlrecord;
        aID := server.add(b, true);
        b.free;
        b := classb.create(server, aID);
        aID := b.A.ID;    // here an access violation error is returned.
        b.free;
        a.free;
end;

Debugging i've seen that in mormot.pas the assigment of value to property b.A is done using TSQLPropInfoRTTIInt32 class instead of TSQLPropInfoRTTIInt64.

#38 mORMot 1 » audit trail and good old DeLorean! » 2015-08-15 04:27:16

mariomoretti
Replies: 2

Hi AB,

we may agree on fact that audit trail is an half DELorean : it permits to move only to the past.

In some situations i need to determine the future.

So i've thought to do a new class with

   an array storing only properties to be changed , one row for each future date.
   an EndOfValidityDate , storing the last date of validity of properties actually stored in properties.
   a StartOfValidityDate (optional)
   methods to manage them

obviously i need a OnAfterRead event on server side , to verify EndOfValidityDate and , if the case, apply pending changes. It could be fired only for classes with audit trail enabled or, also, be independent from it, but associated to the class, to avoid unneeded calls.
I've looked , without success, for it. Can you help me , please ?
tx

#39 Re: mORMot 1 » server and client in interfaced based service » 2015-08-04 22:29:09

No, httpserver threads end normally : remain only other unnamed threads.
Im investigating....

#40 Re: mORMot 1 » server and client in interfaced based service » 2015-08-04 14:53:10

yes but, the unnamend threads end after one minute, non so do the httpserver worker that stay alive forever : i haven't killed the last process and they are still running.

#42 Re: mORMot 1 » server and client in interfaced based service » 2015-08-04 10:49:47

In thread status  panel stay these threads in state runnable (while destroying form they are in statu stopped)

Main thread :
tSQLHttpServer worker : 32 threads.

sometimes there are other 3 unnnamed  threads (only id).

objects destroy order is :

Client
HttpServer
Server

#43 mORMot 1 » server and client in interfaced based service » 2015-08-04 06:54:40

mariomoretti
Replies: 6

Hi AB,

first of all : finally my interfaced based service works !  tx very much !!!

The server application has a main form wich ownes a tSQLRestServerDB an also a tSQLRestClientURI, created only on need : this to permit some administration customization.

All works fine but, shutting down the process , if I've created and used the interface methods from client, some threads remain active after all objects have been destroyed : consuming over a 30% of cpu resources.

When starting the program , without using the inside client, shutdown works well.

I'm in this situation because initially, the application used vcl objects and direct calls to the server : then , adding services and  permit use of your great tSQLGTableToGrid,   I've introduced the client.

I have to create two distinct program ? The server and a client for administration tasks ?

tx

#45 Re: mORMot 1 » one to many how to » 2015-07-27 08:36:21

AB,

i'm confused.

i've asked you to fix my sample and not to refer to documents i've already read many an many times...

#46 Re: mORMot 1 » one to many how to » 2015-07-27 06:26:05

Hi AB,

sorry but i can't retrieve the data.

After a long period  i'm yet a beginner, so,  i've used a sample project : Sample 02 -Embedded Sqlite3 ORM with these changes :

in Sampledata :

  TSQLSampleRecord = class(TSQLRecord)
  private
    fQuestion: RawUTF8;
    fName: RawUTF8;
    fTime: TModTime;

            fOwner : tSQLSampleRecord;   

  published
    property Time: TModTime read fTime write fTime;
    property Name: RawUTF8 read fName write fName;
    property Question: RawUTF8 read fQuestion write fQuestion;

    	property Owner : tSQLSampleRecord read fOwner write fOwner;

  end;

In Unit1 :


procedure TForm1.AddButtonClick(Sender: TObject);
var Rec [ins], Rec1[/ins]: TSQLSampleRecord;
[ins]    Ok : Boolean;[/ins]
begin
  Rec := TSQLSampleRecord.Create;
  try
    // we use explicit StringToUTF8() for conversion below
    // a real application should use TLanguageFile.StringToUTF8() in mORMoti18n
    Rec.Name := StringToUTF8(NameEdit.Text);
    Rec.Question := StringToUTF8(QuestionMemo.Text);
    if Database.Add(Rec,true)=0 then
      ShowMessage('Error adding the data') else begin


             Rec.Owner := Rec;
             Database.Update(Rec, 'Owner');
             Rec.Free;
             Rec := tSQLSampleRecord.Create(Database, 1);
             Rec1 := tSQLSampleRecord.CreateAndFillPrepare(Database, 'Owner=?',[Rec]);
             Ok := Rec1.Fillone;


      NameEdit.Text := '';
      QuestionMemo.Text := '';
      NameEdit.SetFocus;
    end;
  finally
    Rec.Free;
  end;
end;

Well : this are fields values after  Database.Update :

ID = 1 , Owner = 33247792 : I think  this is normal owing to refrerences and so on…..but , deleting database and reexecuting the code , Owner's value changes everytime, also inserting same values in name and question (???).

However : Fillone returns Ok = False.

The Sql generated by ORM is :

Select ID, Time, Name, Question, Owner from SampeRecord where Owner=:(''tSQLSampleRecord''):


So I've changed query with

Rec1 := tSQLSampleRecord.CreateAndFillPrepare(Database, 'Owner=?',[Rec.ID]);

and deleted database.

Now ID=1 and Owner = 35869232

Fillone returns OK = False.


The Sql generated by ORM is :

Select ID, Time, Name, Question, Owner from SampeRecord where Owner=:(''1''):


AB, please, don't say me to read you huge documentation or posts : at this point  we can assume that  I'm not able to understand  them !

My you correct the lines i've changed to let them  to work as expected ?

Tx very much.

#47 mORMot 1 » one to many how to » 2015-07-23 20:49:39

mariomoretti
Replies: 6

I've two tsqlrecord classes : the second having the first as property.

class1 = class(tsqlrecord)
protected
  fDescription : rawutf8;
published
  property Description : Rawutf8 read fDescription write fDescription;
end;

class2 = class(tsqlrecord)
protected
  fDescription : rawutf8;
  fOwner : class1;
published
  property Description : Rawutf8 read fDescription write fDescription;
  property Owner : class1 read fOwner write fOwner;
end;

class 1 contains some owners.
class 2 contains some children for every owner.

Now i know a class1 instance (Pippo) and i want to display in a grid all class2 children whose Owner is Pippo.

If I code : (aRest is a rest client .., aTable a SQLTable ecc. .)

          aWhere := 'Owner=' + inttostr(Pippo.ID);
          aTable := aRest.List([Class2],
                                       'Description',
                                       aWhere);

aTable (as I expected ) , is empty.

I've change filter in these ways :

            aWhere := 'Owner=' + inttostr(Pippo.recordreference(aRest.model));

aTable is empty.

            aWhere := 'OwnerID=' + inttostr(Pippo.ID); 

catch an sqlite exception. So do :

            aWhere := 'Owner.ID=' + inttostr(Pippo.ID); 

Please , may you help me to do this SIMPLE query ?

Tx very much.

Mario

#48 Re: mORMot 1 » changed properties » 2015-07-16 05:39:42

Hy Ab,

you are right !
I hope it's due to this oppressive heat and not to age....
Tx
Mario

#49 Re: mORMot 1 » changed properties » 2015-07-14 08:45:44

Hy Arnaud,

After a while....

I've changed in mormot tSQLRestClient.BeforeUpdateEvent (and related calls and update methods to eliminate const from CustomFields)

from

    function BeforeUpdateEvent(Value: TSQLRecord): Boolean; virtual;

to

    function BeforeUpdateEvent(Value: TSQLRecord; Var CustomFields : tSQLFieldBits): Boolean; virtual;

then i have overriden the method in my own tSQLRestClient :

function TMySQLRestClient.BeforeUpdateEvent(Value: TSQLRecord; Var CustomFields : tSQLFieldBits): Boolean;
var I : integer;
    Empty : Boolean;
    OldData : tSQLRecord;
    ChgFields : tSQLFieldBits;
begin
     OldData := Value.RecordClass.Create(Self, Value);
     try
        ChgFields := CustomFields;
        Empty := IsZero(CustomFields);
        CustomFields := [];
        Result := false;
        with Value.RecordProps do
             for I := 0 to high(SimpleFields) do
               // compare not TSQLRawBlob/TSQLRecordMany fields
                  with SimpleFields[ I] do
                       if Empty or (I in ChgFields) then
                          if CompareValue(Value, OldData, false)<>0 then
                          begin
                               include(customfields, I);
                               result := true;
                          end;
     finally
            OldData.free;
     end;
end;

Obviously, could be implemented on clients but  so, i don't lock data from clients when reading first and save some bandwidth when reading data before update.
Do you think that could be implemented in mormot ?

Thanks.

regards

Mario.

Board footer

Powered by FluxBB