xetra11
xetra11

Reputation: 8835

Sqlite3 - trying to fill a structure within callback

I have following struct:

typedef struct {
    char *username;
    char *score;
} Highscore;

Using it as followed:

static int callback(void* data, int argc, char** argv, char** colName) {
  Highscore* highscore = (Highscore*)data;

  highscore->username = argv[0];
  highscore->score = argv[1];

  return 0;
}

And the database orchestration is being used here with the struct:

Highscore* getHighscore()
{
  sqlite3* db_handle;
  int rc;
  char* zErrMsg;
  Highscore* highscore = malloc(sizeof(Highscore));
  /* highscore->username = malloc(sizeof(100)); */
  /* highscore->score = malloc(sizeof(100)); */

  //Datenbankverbindung oeffnen
  rc = sqlite3_open(DATABASE_FILE, &db_handle);

  char* sSqlString = sqlite3_mprintf
    ("select U.Username, H.Punkte from Highscore H join User U on U.B_ID = H.B_ID order by Punkte desc limit 10");

  //SQL Statement ausfuehren
  rc = sqlite3_exec(db_handle, sSqlString, callback, highscore, &zErrMsg);

  //Datenverbindung schliessen und Speicher leeren
  sqlite3_free(sSqlString);
  rc = sqlite3_close(db_handle);

  return highscore;

}

The problem which now occurs is that within the callback scope the Highscore struct has assigned fields "username" and "score" the way it should be. I debugged at that position and everything was fine.

But as I get back into the scope of "getHighscore" the Highscore struct's fields have arbitrary values in it. I do not realize whats happening? I have allocated the struct before giving it to the callback with "malloc". And I have checked if it's the same address the after the callback - it is. So why are the values corrupted?

Upvotes: 1

Views: 438

Answers (2)

i486
i486

Reputation: 6563

You keep only pointers in Highscore structure and real values are overwritten. Try this:

static int callback(void* data, int argc, char** argv, char** colName)
{
  Highscore* highscore = (Highscore*)data;

  highscore->username = malloc( strlen( argv[0] ) + 1 );
  strcpy( highscore->username, argv[0] );
  highscore->score = malloc( strlen( argv[1] ) + 1 );
  strcpy( highscore->score, argv[1] );

  return 0;
}

Don't forget to free score and username at the end (before free-ing highscore).

Upvotes: 1

CL.
CL.

Reputation: 180070

The sqlite3_exec() documentation says:

The 3rd argument to the sqlite3_exec() callback is an array of pointers to strings obtained as if from sqlite3_column_text(), one for each column.

The sqlite3_column_text() documentation says:

The pointers returned are valid until a type conversion occurs as described above, or until sqlite3_step() or sqlite3_reset() or sqlite3_finalize() is called

… which happens before sqlite3_exec() returns.

You have to copy the strings to your own buffers. Better use a language that has dynamic strings.

Upvotes: 0

Related Questions