Discussão do artigo "SQLite: trabalho nativo com bancos de dados SQL em MQL5" - página 8

 

E a pergunta nº 2:

Ao tentar usar as funções ATTACH/DETACH para transferir dados entre bancos de dados usando o mecanismo interno do SQLite, o resultado é um erro de transação 5601...

Ao executar a mesma transação no SQLiteStudio, tudo fica bem.

Isso é feito de propósito ou há algo que não está funcionando?

   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 execução do programa), provavelmente um erro dentro da função MQL, parte do código da minha biblioteca:


Infelizmente, a função DatabaseExport não recebeu a funcionalidade de exportar a tabela (embora essa funcionalidade tenha sido originalmente planejada) e atualmente suporta apenas consultas.

Sobre o erro 4022, você o recebe durante o teste? Se sim, o testador tem uma limitação no tamanho do arquivo de exportação - tamanho total de 1 GB de dados gravados no disco?

 
Daniil Kurmyshev SQLite, o resultado é o erro de transação 5601...

Ao executar a mesma transação no SQLiteStudio, tudo está bem.

Isso é feito de propósito ou há algo que não está funcionando?

A consulta deve funcionar, verifique se os caminhos estão corretos
 
Ilyas #:

Infelizmente, a função DatabaseExport nunca obteve a funcionalidade de exportação de tabelas (embora essa funcionalidade tenha sido originalmente planejada) e atualmente só oferece suporte a consultas.

Quanto ao erro 4022, você o recebe durante o teste? Se sim, o testador tem uma limitação no tamanho do arquivo de exportação - tamanho total de 1 GB de dados gravados no disco?

O erro 4022 aparece sem o testador, se você especificar a consulta em vez do nome da tabela na função DatabaseExport.

O tamanho do banco de dados é inferior a 10 Mb, e eu estava planejando usar essa funcionalidade para copiar dados do banco de dados no disco para o banco de dados na memória.
 
Ilyas #:
A consulta deve funcionar, verifique se os caminhos estão corretos

Obrigado, tentarei fornecer o caminho de forma diferente, mas, de fato, no SQLiteStudio, a consulta no caminho especificado funciona, eu gerei a consulta no log do terminal e, em seguida, copiei e executei no SQLiteStudio sem problemas.

Vou escrever sobre o resultado.

 
Existe a possibilidade de se conectar à base na RAM pelo nome e de usar o parâmetro de cache geral? Sei que o SQLite tem essa possibilidade, mas gostaria de saber se ela está habilitada no MT5.
 

Teste a gravação multi-threaded no banco de dados, execute várias cópias do script, cada cópia pode ser rotulada com o parâmetro expert_id.

#property copyright "Aliaksandr Hryshyn"
#property link      "https://www.mql5.com/pt/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;
//+------------------------------------------------------------------+
//| Função de início do programa de 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))/Criar tabela se estiver ausente
     {
      DatabaseClose(db_handle);
      Print("Erro:",GetLastError());
      Print("Query:",sql_create);
      return;
     }
   string s1;
   string sql;
   int err_counter=100;/Contador de erros de adição de registros
   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))/Adicione um registro a uma coluna aleatória do conjunto 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);// Um pouco de sono
     }
   DatabaseClose(db_handle);
  }

Tudo é gravado corretamente:


Mas recebo erros sobre bloqueio:

...
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
...

Deve haver um mecanismo de inserção de registro condicional sem retornar um erro.

 
Ilyas #:
A consulta deve funcionar, mas verifique se os caminhos estão corretos

1. Verifiquei que o ATTACH DATABASE funciona!

O problema foi o seguinte: tentei anexar à base criada na RAM, a base física, nesse caso, o ATTACH DATABASE não funciona, mas se anexarmos a base RAM à base física, ele funciona!

Isso é suficiente para que eu crie uma cópia da base na RAM, o que acelera os cálculos)))


2. Decidi ir além... e verificar mais uma possibilidade, a saber:

ATRIBUIR BANCO DE DADOS 'file:memdb1?mode=memory&cache=shared' COMO M;

De acordo com a ideia, o banco de dados deve ser criado na RAM e deixar de existir depois que o thread for fechado, mas seu comportamento é diferente...

Em 1, posso entrar nele a partir de qualquer programa MQL5, Expert Advisor, indicador, script, serviço,

No 2, os dados nele contidos são salvos para sempre, mesmo após a reinicialização, já pensei... que talvez o banco de dados seja criado fisicamente, mas uma pesquisa pelo nome *memdb1*não encontrou nada

P.S. Talvez porque eu tenha criado a base a partir do indicador e ela funcione em um thread comum?


Esse é um recurso interessante, mas eu gostaria de saber se ele permanecerá no terminal nas próximas atualizações e depois da minha mensagem sobre isso:)))).

Nesse caso, você pode transferir facilmente grandes quantidades de dados entre programas, sem problemas e atrasos, e não usar variáveis globais limitadas pelo comprimento do nome....


Em tal execução, ela é excluída após o término do programa MQL5:

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

ATTACH DATABASE ':memory:' AS M;

 

Boa tarde!

Pergunta para os desenvolvedores do MT, é possível desativar o atributo Shared da biblioteca SQLite, pois a experiência em outros projetos determinou que essa é a causa do erro: database error , database is locked.

Se estiver acessando o banco de dados de diferentes threads, tudo será resolvido no nível do próprio banco de dados, ou seja, executando essas duas consultas imediatamente após abrir o banco de dados:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

mas o erro de bloqueio só será eliminado depois que você tornar a base não compartilhada, não é possível fazer isso com consultas.

 
Daniil Kurmyshev projetos determinei que essa é a causa do erro: database error, database is locked.

Se o acesso ao banco de dados for feito por threads diferentes, tudo será resolvido no nível do próprio banco de dados, ou seja, executando essas duas consultas imediatamente após a abertura do banco de dados:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

mas o erro de bloqueio só desaparecerá depois que você tornar a base não compartilhada; não é possível fazer isso com consultas.

Nesse caso, a velocidade das consultas cairá e os requisitos de memória aumentarão....

mas está tudo bem :-)

O SQLite foi projetado para uma thread ou um escritor e muitos leitores. Muitos escritores não se preocupam com isso, mas com outras bases que não são "leves".

Não se trata de MQL - é assim que as coisas são na realidade e em toda parte.