[SOLUCIONADO] EOF found reading column header. En la segunda query.

Buenos días, siempre solucione todos mis problemas leyendo, pero no consigo aclararme con este, tengo claro que es un error fácil de concepto y que mi pésimo ingles también tiene la culpa. Este es mi primer post y espero cumplir con todas las normas. :smiley:

Estoy usando el módulo ESP8266 y la librería MySQL connector, necesito acceder a tres tablas de una misma BD para seleccionar parámetros en el setup().

Se conecta perfectamente, y lee cada query por separado sin problema. Pero si realizo dos seguidas muestra el error:

12:22:37.464 ->  Iniciando UDP 
12:22:37.464 ->  Puerto local: 8888
12:22:37.464 ->  esperando sincronización 
12:22:37.513 -> ...trying...
12:22:38.345 -> Connected to server version 5.6.40
12:22:38.392 -> Conectados a la BD.
12:22:38.430 -> Primer execute relizado.
12:22:38.477 -> Primer get_columns relizado.
12:22:38.515 -> 530 
12:22:38.515 -> 1649 
12:22:38.515 -> 2359 
12:22:38.515 -> Segudo execute relizado.
12:22:38.562 -> Bad mojo. EOF found reading column header.
12:22:38.615 -> Segundo execute relizado.
12:22:38.615 -> ERROR: You must read the columns first!
12:22:38.662 -> 
12:22:38.662 -> Disconnected.

En el setup() simplemente llamo a cada función una detrás de otra. Adjunto código de las funciones.

   ////////////////////////////////////   
  //// Leemos las Horas Inicio de cada Ciclo
  //////////////////////////////////
  
void LeerCiclos(){

  String query;
  MySQL_Cursor *cur_Duracion = new MySQL_Cursor(&conn);
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  row_values   *row = NULL;
  column_names *columns = NULL;

  query = "SELECT Ciclo, Hora FROM qaer661.Ciclos";
  
  cur_mem->execute(query.c_str());
  Serial.println("Primer execute relizado.");
  columns = cur_mem->get_columns();
  Serial.println("Primer get_columns relizado.");
  
  for (int i=0; i<3; i++) {
    row = cur_mem->get_next_row();
    Hora_Inicio[i]=atol(row->values[1]);
  }
  for (int i=0; i<3; i++) {
    Serial.print(Hora_Inicio[i]);Serial.println(" "); 
  }
  delete cur_mem;
}   
 
   ////////////////////////////////////   
  //// Leemos las Horas Inicio de cada Ciclo
  //////////////////////////////////

void LeerDuracionZona(){

  String query;
  MySQL_Cursor *cur_Duracion = new MySQL_Cursor(&conn);
  MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);
  row_values   *row = NULL;
  column_names *columns = NULL;

  query = "SELECT Ciclo, Zona, Tiempo FROM qaer661.DuracionZona";
  
  cur_mem->execute(query.c_str());
  Serial.println("Segudo execute relizado.");
  columns = cur_mem->get_columns();
  Serial.println("Segundo get_columns relizado.");
  
  do {
     row = cur_mem->get_next_row();
     if (row != NULL) { Serial.print(row->values[0]);Serial.print(" ");Serial.print(row->values[1]);Serial.print(" ");Serial.print(row->values[2]);Serial.println(""); }
     else  Serial.println("");
   } while (row != NULL);

    delete cur_mem;
}

Como veis en el segundo get_columns() da el error: “Bad mojo. EOF found reading column header.” Y luego al recuperar las filas “ERROR: You must read the columns first!”.
Gracias de antemano por vuestra ayuda.

Se solucionó abriendo y cerrando la BD en cada consulta. Son tres Select muy concretos para recoger parámetros en el SetUp que no afecta para nada al rendimiento.

Bueno, no se de este problema pero si traducimos EOF es End Of File o fin de archivo. Te esta diciendo que se ha alcanzado el final del archivo y por lo tanto la segunda consulta no es posible porque no encuentra columna para leer.
Entonces que haría yo.
Intentaría obligar a que se posicione al comienzo. No digo que cierres la DB que sería la forma dura y cruda que ambos sabemos que funcionaría porque de hecho cuando preguntas por la primera no tiene problemas, pero si que intentes con algun comando ir al comienzo.

Saludos, el código que has colocado no corresponde con las salidas de texto que muestras, porque ofrece diferentes mensajes de texto, así que no se puede saber seguro a qué corresponde.

Recuerda que en SQL el concepto de abrir y cerrar es duro, no debes hacerlo y cuando realizas un nuevo query no es necesario posicionarse en un sitio específico porque no es un fichero secuencial, tampoco veo las instrucciones para crear la BD, así que no sabemos el comportamiento exigido a las tablas, pero el mensaje no puede ser más claro:

ERROR: You must read the columns first!

Primero debes leer las columnas!

Lees las columnas en colums y luego no la vuelves a utilizar para nada, pides leer las filas, vale que sean punteros pero no son mágicos, creo que te estás perdiendo con el manejo del SQL

Gracias por vuestras respuestas.

Efectivamente como bien dice TonyDiana, estoy un poco perdido con el manejo del SQL. Llevo más de 15 sin programar, pero lo estuve haciendo durante más de 20 y siempre que accedía a base de datos se hacía a nivel de fila (modificar, insertar, consultar; parte o toda la fila) pero tener que consultar antes el nombre de las columnas nunca hizo falta. De hecho, no me hace falta ya que conozco hasta las filas que va a contener la tabla, sólo quiero el contenido de estas. Sólo accedo a las columnas porque es requerido según la documentación. Pero no encuentro ningún ejemplo en donde se realicen dos consultas.

TonyDiana: Los mensajes coinciden con el código. Pero antes de llamar a las funciones con los “select” me conecto a la Base de datos sin mas y esa parte del código no la he puesto. Si puede ser importante la adjunto.

if (WiFi.status() == WL_CONNECTED) { 
  if (!conn.connect(server_addr, 3306, UsuarioBD, PassBD))
      Serial.println("Connecting to SQL...  FAILED.");
  else {
    DatosLeidosOK=1;
    Serial.println("Conectados a la BD.");
  } 
  LeerCiclos();
  LeerDuracionZona();

A qué te refieres con “abrir y cerrar”? Son dos accesos distintos para leer la tabla entera, la primera tabla tendrá 3 filas y la segunda 24.

La BD ya está creada, solo necesito leerla. Y efectivamente leo las columnas para nada, pero si no hago esa primera lectura, no puedo acceder a las filas que es lo que necesito.

Limpiare mi mente y volveré a leer la documentación a ver si se me ha pasado algo por alto con mi pésimo inglés. Pero lo de leer las columnas me tiene descolocado y tu comentario “vale que sean punteros pero no son mágicos” me parece buenísimo, pero me descolocó aun mas, nunca lo estudié con las gafas de ver punteros ;D.

Gracias mil por vuestros comentarios, voy a darle otra vuelta.
Un saludo.

Otra cosa, eres de los mios, jejejeje si necesitas guardar 4 cosas, no mates moscas a cañonazos, SQL es genial para que varias plataformas accedan a datos en varios lenguajes con concurrencia, relacionabilidad y seguridad, pero si nó, ¿para qué un sql? hay alternativas más sencillas

Últimamente todo el mundo usa las bases de datos como camiones de transporte para llevar las lechugas de la compra del super

Pues se admiten sugerencias, a lo mejor me regañan por iniciar un nuevo hilo.

Tengo ya montado mi riego automático con 8 zonas de riego, 3 ciclos posibles por día y a elegir que día de la semana regar. Que sustituirá, en cuanto el tiempo lo permita, a mi actual y carísimo programador con mil funciones que no uso, un menú criptográfico y sin acceso web.

Y le voy haciendo mejoras según voy aprendiendo, je je. Manejo lo básico por Blynk con el móvil.

Tenía pendiente poder parametrizar los tiempos de riegos de alguna manera sencilla, probé con MySQL connector que funcionó sin complicaciones y me permitía cambiar la BD desde el ordenador y el móvil, sin tocar el programador. El problema vino cuando hice dos “select” y me dice que lea las columnas o fin de fichero… puffffff

Estoy abierto a sugerencias para leer parámetros del exterior, que pueda modificar sentado en mi silla a distancia. Y sigo con mi problema de acceso a BD, que no pienso parar hasta tenerlo controlado. Cualquier ayuda será bienvenida.

Un saludo.

Si ya tienes algo funcionando, arregla el select es más sencillo, debes ver paso a pas oque te ocurre

Pues no doy con ello, y estoy un poco colapsado. Lo dejo una temporada y ya volveré sobre ello en otro momento, me pongo a estudiar interrupciones que tengo tres pulsadores que puedo mejorar.

Como sólo consulto los datos en setup() , al final abro y cierro la BD en cada "select" que no me da problemas, aunque no queda muy elegante.

Gracias por vuestra ayuda.

Por lo que anduve leyendo creo, si no entendí mal, que como no haces nada con los datos de columna hay que vaciar el buffer para poder hacer otra lectura. Por eso la primera pasa pero la segunda te da error.

El tema es que no encuentro donde lo leí para pasarte el comando… :roll_eyes:

@gatul, que atinado, es justo eso, por eso al abrir la base de datos de nuevo se limpia, eres un krac

Naah...
Simplemente googlee "Bad mojo..." y lei algunos de los resultados. :wink:

Supongo que te refieres a free_columns_buffer() y free_row_buffer(). Pero soy incapaz de invocarlas me aparecen errores al compilar, en el include de la librería aparecen como privadas. Me puse a modificar la librería, al final monté tal follón que tuve que volverla a instalar.

Al cerrar la base de datos lo que hace es llamar a esas dos funciones y supongo que efectivamente This is the way… Pero no doy con ello

Gracias por el interés.

Si, a ese comando me refería.
Se supone que en tu caso debería ser

cur_mem.free_columns_buffer();

Tal vez @TonyDiana pueda orientarte más, yo llegué a mi limite.

Saludos

No la he usado, realmente, así que no sé seguro cómo funciona, le echaré un vistazo, pero ya comenzaron las clases y voy con menos tiempo

Rectifico
https://translate.google.com/translate?sl=auto&tl=es&u=https://github.com/ChuckBell/MySQL_Connector_Arduino/issues/86

Es problema de la librería, ese mae se construyó la suya

¿Solución simple?

Función que conecte a la base de datos y lea y la invocas cuando la necesites

Si, ya estuve leyendo eso… Bueno, no hago más drama, lo dejo cerrando y abriendo la BD en cada consulta, aunque no sea lo mas elegante. Y en otro momento retomaré el tema, si logro otra solución, lo notificaré por si alguien relee esto.

Gracias a todos por vuestro tiempo.

A otra cosa:

ToniDiana, en un comentario me sugerías otras alternativas, “más sencillas”, al SQL para leer datos. ¿Me puedes indicar algunas que te parezcan interesantes???

Un saludo a todos.

Yo ahora estoy usando TinyDB, porque puedo usar BD en memoria, JSON y YAML con la misma base de datos, pero no sé si funciona en Arduino, lo uso en Python

Otra opción es la magnífica librería de Json que hay para Arduino

Y si no, archivos de datos de toda la vida

SQL es muy grande para algunas cosas, demasiadas implicaciones y más si tienes que tener un servicio activo para que todo funcione

Hago un consulta desde la total ignorancia...
¿No se podrían leer los elementos de columna y asignarlos a una variable "boba" a fin de vaciar el buffer y sortear el error?

Es una opción, pero en Arduino, mejor no desaprovechar la memoria, yo tendría en memoria sólo lo que necesite, pero es posible.

Lo ideal en Arduino para mi son archivos json ASCII en tarjeta SD, tiras millas con eso´

Aquí un documento académico del tema

Claro en todo momento se me ha olvidado preguntar una cosa, @warriorsoto ¿Qué sostiene los datos, cuál plataforma?

Si lo de la memoria lo pensé, pero la variable seria siempre la misma y se blanquería después de las lecturas, su uso sería temporal.
Me parecía una solución más pintoresca que cerrar la base y para no caer en imprimir (mandar al serial, bah) como vi en la mayoría de las soluciones.

Saludos

@gatul hay que probarlo, pero insisto ¿qué hay al otro lado? ¿quién soporta el MySQL?