1

I am trying to display my database data on an OLED LCD using MySQL_Connection.h and MySQL_Cursor.h by ChuckBell.

The link to this library is https://github.com/ChuckBell/MySQL_Connector_Arduino>

I was able to fetch data from mysql database successfully. However, I wish to store the data in a char array so that I can later display them on the OLED LCD. The problem is the value stored always returns garbage value. I know its something to do with char array pointer but after searching for so long, I still couldn't find the correct syntax. Below is the snippet of my code.

Start by setting up Wifi connection and mysql connection.

#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
char query[] = "SELECT * FROM test.assetdemo WHERE RFID = \"048EB25A\"";  //sql query
char* sqldata[11];               //array of char pointer to store the 11 data in the database 

void setup(){
    Serial.begin(115200);
    internetConnect(ssid,pw);                             //connect to Wifi
    conn.connect(server_addr, 3306, user, password);      //connect to mysqldatabase
}

Then begin looping function to store and display the database data.

void loop(){
    Serial.println("\nRunning SELECT and printing results\n");

    MySQL_Cursor *cur_mem = new MySQL_Cursor(&conn);   // Initiate the query class instance
    cur_mem->execute(query);                           // Execute the query

    row_values *row = NULL;                            // Read the rows and print them
    do {
        row = cur_mem->get_next_row();
        if (row != NULL) {
            for (int f = 0; f < cols->num_fields; f++) {
                sqldata[f] = row->values[f];
                Serial.print(f);
                Serial.print("    ");
                Serial.println(sqldata[f]);    /*This works*/
              }
            Serial.println();
          }
     } while (row != NULL);
     Serial.println(sqldata[0]);      /*This return garbage value*/
     delete cur_mem;                   // frees up memory used  
     delay(5000);
}

The output is shown as below Click here or view below. As you can see, the values are displayed correctly (except 8th which is of boolean type which i will change it later) in the do while loop. However, when I exit the loop and print the value again, it returns garbage value . sqldata[0] supposes to return 048EB25A.

Running SELECT and printing results


0    048EB25A
1    Blood Pressure Monitor
2    NA
3    WelchAllyn 503-0054-03
4    010720
5    NA
6    NA
7    Blood Pressure Cuff
8    
9    Yes
10    1

⸮

The code snippet below shows the struct declaration in MySQL_Cursor.h

typedef struct {
  char *db;
  char *table;
  char *name;
} field_struct;

// Structure for storing result set metadata.
typedef struct {
  int num_fields;     // actual number of fields
  field_struct *fields[MAX_FIELDS];
} column_names;

// Structure for storing row data.
typedef struct {
  char *values[MAX_FIELDS];
} row_values;

Part of me knew that sqldata[f] = row->values[f]; is causing the garbage value. The value will change as the pointer only points to the address. How can I store the variable statically so that after the do while, the value will persist? Kind sirs and madams please explain this mystery.

PS: I am confused at array and pointer, even more when they involve struct.

8
  • Try changing "char* sqldata[11]" as "static char* sqldata[11]" and see. Commented Aug 23, 2018 at 9:41
  • Probbaly row = cur_mem->get_next_row(); invalidates the memory filled by the previous row = cur_mem->get_next_row();. Don't copy the pointers but copy the strings. Commented Aug 23, 2018 at 9:54
  • @user846834 that doesn't work =( Still return garbage value. Commented Aug 24, 2018 at 4:18
  • @Jabberwocky Thanks for the advice. After searching for a long time, I finally able to store the strings instead of the pointers. Will update the solution later. Thanks for the help! Commented Aug 24, 2018 at 4:19
  • Don't put an answer into the question and don't put "[SOLVE]" into the title. This site isn't a forum. Commented Aug 24, 2018 at 14:54

3 Answers 3

2

The explanation is that the memory is freed inside get_next_row function https://github.com/ChuckBell/MySQL_Connector_Arduino/blob/master/src/MySQL_Cursor.cpp

/*
  get_next_row - Iterator for reading rows from a result set
  This method returns an instance of a structure (row_values)
  that contains an array of strings representing the row
  values returned from the server.
  The caller can use the values however needed - by first
  converting them to a specific type or as a string.
*/
row_values *MySQL_Cursor::get_next_row() {
  int res = 0;

  free_row_buffer();

  // Read the rows
  res = get_row_values();
  if (res != MYSQL_EOF_PACKET) {
    return &row;
  }
  return NULL;
}

At the second attempt to get rows free_row_buffer is called.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for pointing out the free_row_buffer. Guess I had to figure out how to store the values before the free_row_buffer() is called. Anyway thanks for the help!
0

I was able to find the solution myself thanks to the advices given by @Jabberwocky and @rantan pan. They provided me a direction on where to look for the solution. By editting sqldata as shown below, I was able to store the strings instead of pointer into sqldata.

Re-declare sqldata as shown below.

char **sqldata = new char*[11];     //to store 11 data for each query executed
for ( int i = 0; i < 11; i++ )
{
    sqldata[i] = new char[11];
}

Then replace sqldata[f] = row->values[f]; with strcpy(sqldata[f], (*row).values[f]);

All is working right now. Time to print this crap on an OLED LCD. Thanks again folks!

Comments

0

Solution from @TK Ooi is ok, but as an improvement to it I would go safer with the size of the array where we want to store the data, and thus can be done instead of using

int numberRows = 11;
char **sqldata = new char*[numberRows];
for(int i = 0; i < numberRows; i++ ) {
    sqldata[i] = new char[numberChars];
}
strcpy(sqldata[f], (*row).values[f]);`

better declaring your array of char* as global but doing inside your query function the following:

int numberChars = strlen((*row).values[f]);
sqldata[f] = new char[numberChars]; // implies already extra place for null terminator
snprintf(sqldata[f], strlen(sqldata[f]), "%s", (*row).values[f]);`

This way, we are assigning always the exact length to our array to store the recovered data. Note that using numberChars instead of strlen(sqldata[f]) will fail because you need to pass the length according to the type stored in sqldata: it's not the same for int as for char...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.