Discusión sobre el artículo "SQLite: trabajo nativo con bases de datos en SQL en MQL5" - página 8

 

Y pregunta #2:

Intentando usar las funciones ATTACH/DETACH para transferir datos entre bases de datos usando el mecanismo incorporado de SQLite, el resultado es un error de transacción 5601...

Al ejecutar la misma transacción en SQLiteStudio, todo va bien.

¿Esto se hace a propósito o hay algo que no funciona?

   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 ejecución del programa), probablemente error dentro de la función MQL, parte del código de mi librería:


Desafortunadamente, la función DatabaseExport no ha recibido la funcionalidad para exportar la tabla (aunque esta funcionalidad estaba prevista originalmente) y actualmente sólo admite consultas.

En el error 4022, ¿lo obtiene durante las pruebas, si es así, el probador tiene una limitación en el tamaño del archivo de exportación - 1 GB de tamaño total de los datos escritos en el disco?

 
Daniil Kurmyshev SQLite, el resultado es el error de transacción 5601...

Al ejecutar la misma transacción en SQLiteStudio, todo va bien.

¿Esto está hecho a propósito o hay algo que no funciona?

La consulta debería funcionar, comprueba si las rutas son correctas
 
Ilyas #:

Lamentablemente, la función DatabaseExport nunca llegó a tener la funcionalidad de exportación de tablas (aunque esta funcionalidad estaba prevista en un principio) y actualmente sólo admite consultas.

En cuanto al error 4022, ¿lo obtiene durante las pruebas? En caso afirmativo, el comprobador tiene una limitación en el tamaño del archivo de exportación: 1 GB de tamaño total de los datos escritos en el disco.

El error 4022 aparece sin probador, si especifica consulta en lugar de nombre de tabla en la función DatabaseExport.

El tamaño de la base de datos es inferior a 10 Mb, pensaba utilizar esta función para copiar datos de la base de datos en disco a la base de datos en memoria.
 
Ilyas #:
La consulta debería funcionar, comprueba si las rutas son correctas

Gracias, voy a tratar de proporcionar la ruta de otra manera, pero de hecho en SQLiteStudio la consulta en la ruta especificada funciona, la salida de la consulta en el registro de terminal y luego copiado y ejecutado en SQLiteStudio sin problemas.

Voy a escribir sobre el resultado.

 
Existe la posibilidad de conectarse a la base en RAM por nombre y si utilizar el parámetro de la caché general, se que SQLite tiene dicha posibilidad, pero me gustaría saber si está incluida en MT5, gracias.
 

Prueba de escritura multihilo en la base de datos, ejecuta múltiples copias del script, cada copia puede ser etiquetada con el parámetro expert_id.

#property copyright "Aliaksandr Hryshyn"
#property link      "https://www.mql5.com/es/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;
//+------------------------------------------------------------------+
//| Función de inicio del 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))//Crear tabla si no hay
     {
      DatabaseClose(db_handle);
      Print("Error:",GetLastError());
      Print("Consulta:",sql_create);
      return;
     }
   string s1;
   string sql;
   int err_counter=100;//Contador de errores de adición
   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))/Agregar un registro a una columna aleatoria del 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);// Un poco de sueño
     }
   DatabaseClose(db_handle);
  }

Todo se escribe correctamente:


Pero obtengo errores de bloqueo:

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

Debería haber un mecanismo de inserción condicional de registros sin devolver un error.

 
Ilyas #:
La consulta debería funcionar, asegúrese de que las rutas son correctas

1. ¡Comprobado ATTACH DATABASE funciona!

El problema estaba en lo siguiente, intenté adjuntar a la base creada en RAM, la base física en este caso ATTACH DATABASE no funciona, pero si adjuntamos la base RAM a la base física, ¡ funciona!

Esto me basta para crear una copia de la base en RAM, lo que acelera los cálculos))).


2. Decidí ir más allá... y comprobar una posibilidad más, a saber

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

Según la idea, la base de datos debería crearse en RAM y dejar de existir tras el cierre del hilo, pero su comportamiento es diferente...

En 1 puedo unirme a ella desde cualquier programa MQL5, Asesor Experto, indicador, script, servicio,

En 2 los datos en ella se guardan para siempre, incluso después de reiniciar, ya pensé ... que tal vez la base de datos se crea físicamente, pero una búsqueda por el nombre *memdb1*no encontró nada

P.D. ¿Quizás porque he creado la base desde el indicador, y funciona en un hilo común?


Es una funcionalidad muy chula, pero me gustaría saber si se mantendrá en el terminal en las próximas actualizaciones y después de mi mensaje al respecto:)))).

En este caso, usted puede transferir fácilmente grandes cantidades de datos entre programas, sin problemas y retrasos, y no utilizar variables globales limitadas por la longitud del nombre....


En tal ejecución se elimina después de que el programa MQL5 ha terminado:

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

ATTACH DATABASE ':memory:' AS M;

 

¡Buenas tardes!

Pregunta para los desarrolladores de MT, es posible deshabilitar el atributo Shared de la librería SQLite, por experiencia en otros proyectos se determinó que esta es la causa del error: database error , database is locked.

Si estás accediendo a la base de datos desde diferentes hilos, todo se soluciona a nivel de la propia base de datos, es decir, ejecutando estas dos consultas inmediatamente después de abrir la base de datos:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

pero el error de bloqueo desaparecerá sólo después de hacer que la base no sea Compartida, no se puede hacer con consultas.

 
Daniil Kurmyshev proyectos se determinó que esta es la causa del error: database error, database is locked.

Si el acceso es desde diferentes hilos a la base de datos, todo se soluciona a nivel de la propia base de datos, es decir ejecutando estas dos consultas inmediatamente después de abrir la base de datos:

1. PRAGMA journal_mode = WAL;

2. PRAGMA busy_timeout = 1000;

pero el error de bloqueo desaparecerá sólo después de hacer la base no compartida, no se puede hacer con las consultas.

En este caso la velocidad de las consultas caerá y los requerimientos de memoria aumentarán....

pero todo esta bien :-)

SQLite está diseñado para un hilo o un escritor y muchos lectores. Muchos escritores no se tratan de eso, se trata de otras bases que no son "ligeras".

no se trata de MQL - es sólo la forma en que es realmente y en todas partes.