Discussione sull’articolo "SQLite: Gestione nativa dei database SQL in MQL5" - pagina 8

 

E la domanda numero 2:

Cercando di utilizzare le funzioni ATTACH/DETACH per trasferire dati tra database utilizzando il meccanismo integrato di SQLite, il risultato è un errore di transazione 5601...

Quando si esegue la stessa transazione in SQLiteStudio, tutto va bene.

È stato fatto di proposito o c'è qualcosa che non funziona?

   m_db.Create("IndiTemp","indi",m_db_main.GetStruct(),true);
   string db_path=StringFormat("%s\\Files\\%s.sqlite",
                               TerminalInfoString(TERMINAL_COMMONDATA_PATH),
                               "Indi");
                               
   string query=StringFormat("ATTACH DATABASE '%s' AS X; ",db_path),
          tables[];
          
   int total=m_db.GetTables(tables);
   if(total>0)
     {
      for(int i=0; i<total; i++)
         StringAdd(query,StringFormat("INSERT OR IGNORE INTO %s SELECT * FROM X.%s; ",tables[i],tables[i]));
     }
     
   StringAdd(query,"DETACH X; ");
   m_db.TransactionExecute(query);
 
Daniil Kurmyshev esecuzione del programma), probabilmente un errore all'interno della funzione MQL, parte del codice della mia libreria:


Sfortunatamente, la funzione DatabaseExport non ha ricevuto la funzionalità di esportazione della tabella (sebbene questa funzionalità fosse originariamente prevista) e attualmente supporta solo le query.

Per quanto riguarda l'errore 4022, si verifica durante i test, se sì, il tester ha una limitazione sulla dimensione del file di esportazione - 1GB di dimensione totale dei dati scritti su disco?

 
Daniil Kurmyshev SQLite, il risultato è l'errore di transazione 5601...

Quando si esegue la stessa transazione in SQLiteStudio, tutto va bene.

È stato fatto apposta o c'è qualcosa che non funziona?

La query dovrebbe funzionare, verificare che i percorsi siano corretti
 
Ilyas #:

Sfortunatamente, la funzione DatabaseExport non ha mai ottenuto la funzionalità di esportazione delle tabelle (anche se questa funzionalità era prevista in origine) e attualmente supporta solo le query.

Per quanto riguarda l'errore 4022, si verifica durante i test; in caso affermativo, il tester ha una limitazione sulla dimensione del file di esportazione - 1GB di dimensione totale dei dati scritti su disco?

L'errore 4022 appare senza tester, se si specifica la query invece del nome della tabella nella funzione DatabaseExport.

La dimensione del database è inferiore a 10 Mb, e intendevo utilizzare questa funzionalità per copiare i dati dal database su disco al database in memoria.
 
Ilyas #:
La query dovrebbe funzionare, controlla se i percorsi sono corretti.

Grazie, proverò a fornire il percorso in modo diverso, ma in effetti in SQLiteStudio la query sul percorso specificato funziona, ho emesso la query nel log del terminale e poi copiata ed eseguita in SQLiteStudio senza problemi.

Scriverò il risultato.

 
Esiste la possibilità di connettersi alla base in RAM per nome e se utilizzare il parametro della cache generale, so che SQLite ha questa possibilità, ma vorrei sapere se è inclusa in MT5, grazie.
 

Per verificare la scrittura multi-thread nel database, eseguire più copie dello script, ciascuna delle quali può essere etichettata con il parametro expert_id.

#property copyright "Aliaksandr Hryshyn"
#property link      "https://www.mql5.com/it/users/greshnik1"
#property version   "1.00"
#property script_show_inputs

enum e_E
  {
   e_0,
   e_1,
   e_2,
   e_3,
  };
input e_E expert_id=0;
//+------------------------------------------------------------------+
//| Funzione di avvio del programma di script|
//+------------------------------------------------------------------+
void OnStart()
  {
   int db_handle=DatabaseOpen("tmp//test.sqlite",DATABASE_OPEN_READWRITE|DATABASE_OPEN_CREATE|DATABASE_OPEN_COMMON);
   const string sql_create=
      "CREATE TABLE IF NOT EXISTS Demo("
      "Id INTEGER PRIMARY KEY AUTOINCREMENT,"
      "Expert_id INTEGER,"
      "demo_0 TEXT(2000),"
      "demo_1 TEXT(2000),"
      "demo_2 TEXT(2000),"
      "demo_3 TEXT(2000),"
      "demo_4 TEXT(2000),"
      "demo_5 TEXT(2000),"
      "demo_6 TEXT(2000),"
      "demo_7 TEXT(2000)"
      ");";
   const string sql_add=
      "INSERT INTO Demo(Expert_id,demo_%s) VALUES(%s,'%s')";
   if(!DatabaseExecute(db_handle,sql_create))//Creare la tabella se assente
     {
      DatabaseClose(db_handle);
      Print("Errore:",GetLastError());
      Print("Query:",sql_create);
      return;
     }
   string s1;
   string sql;
   int err_counter=100;//Contatore degli errori di aggiunta al record
   for(int i1=0; i1<1000; i1++)
     {
      s1="";
      for(int i2=0; i2<100; i2++)
        {
         s1+=string(MathRand());
        }
      sql=StringFormat(sql_add,string(MathRand()%8),string(expert_id),s1);
      if(DatabaseExecute(db_handle,sql))/Aggiunge un record a una colonna casuale dell'insieme demo_....
        {
         err_counter=100;
        }
      else
        {
         if(err_counter==0)
           {
            DatabaseClose(db_handle);
            Print(expert_id,": end");
            return;
           }
         else
           {
            Print(expert_id,": ",err_counter);
            err_counter--;
            i1--;
           }
        }
      if(IsStopped())
         break;
      Sleep(1);// Un po' di sonno
     }
   DatabaseClose(db_handle);
  }

Tutto viene scritto correttamente:


Ma ricevo errori di blocco:

...
2021.09.18 13:08:05.252 Test_sql (EURUSD,M1)    2: 80
2021.09.18 13:08:05.267 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.267 Test_sql (EURUSD,M1)    2: 79
2021.09.18 13:08:05.283 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.283 Test_sql (EURUSD,M1)    2: 78
2021.09.18 13:08:05.299 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.299 Test_sql (EURUSD,M1)    1: 100
2021.09.18 13:08:05.315 Test_sql (EURUSD,M1)    database error, database is locked
2021.09.18 13:08:05.315 Test_sql (EURUSD,M1)    1: 99
...

Ci dovrebbe essere un meccanismo di inserimento condizionale dei record senza restituire un errore.

 
Ilyas #:
La query dovrebbe funzionare, verificare che i percorsi siano corretti

1. ATTACH DATABASE controllato funziona!

Il problema era il seguente: ho provato ad attaccare la base creata nella RAM, la base fisica in questo caso ATTACH DATABASE non funziona, ma se attacchiamo la base RAM alla base fisica, funziona!

Questo è abbastanza per me per creare una copia della base in RAM, che velocizza i calcoli)))


2. Ho deciso di andare oltre... e verificare un'altra possibilità, ovvero

ATTACH DATABASE 'file:memdb1?mode=memory&cache=shared' AS M;

Secondo l'idea, il database dovrebbe essere creato nella RAM e cessare di esistere dopo la chiusura del thread, ma il suo comportamento è diverso...

In 1, posso unirmi ad esso da qualsiasi programma MQL5, Expert Advisor, indicatore, script, servizio,

Nel 2 i dati in esso contenuti sono salvati per sempre, anche dopo il riavvio, ho già pensato ... che forse il database è creato fisicamente, ma una ricerca con il nome *memdb1*non ha trovato nulla

P.S. Forse perché ho creato la base dall'indicatore, e funziona in un filo comune?


Questa è una funzione interessante, ma vorrei sapere se rimarrà nel terminale nei prossimi aggiornamenti e dopo il mio messaggio in merito:)))).

In questo caso, è possibile trasferire facilmente grandi quantità di dati tra i programmi, senza problemi e ritardi, e non utilizzare variabili globali limitate dalla lunghezza del nome....


In tale esecuzione viene cancellato al termine del programma MQL5:

ATTACH DATABASE ':memory:?cache=shared' AS M;

ATTACH DATABASE ':memory:' AS M;

 

Buon pomeriggio!

Domanda agli sviluppatori di MT, è possibile disabilitare l'attributo Shared della libreria SQLite, per esperienza in altri progetti ha determinato che questa è la causa dell'errore: database error , database is locked.

Se si accede al database da diversi thread, si risolve tutto a livello del database stesso, ovvero eseguendo queste due query subito dopo l'apertura del database:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

ma l'errore di blocco sparirà solo dopo aver reso la base non condivisa, non è possibile farlo con le query.

 
Daniil Kurmyshev progetti ho determinato che questa è la causa dell'errore: database error, database is locked.

Se l'accesso è da diversi thread al database, si risolve tutto a livello del database stesso, cioè eseguendo queste due query subito dopo l'apertura del database:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

ma l'errore di blocco verrà eliminato solo dopo aver reso la base non condivisa, non è possibile farlo con le query.

In questo caso la velocità delle query diminuirà e i requisiti di memoria aumenteranno....

ma tutto va bene :-)

SQLite è progettato per un thread o per uno scrittore e molti lettori. Molti scrittori non ne fanno parte, ma si tratta di altre basi che non sono "leggere".

Non si tratta di MQL - è solo il modo in cui è davvero e ovunque.