Как сформулировать вывод из SQLite3 в массив типа const char *list[]?

Ну собственно вопрос. Вот такой код, он, как видно, добывает из таблицы данные, list.c:

#include <sqlite3.h>
#include <stdio.h>
#include <libintl.h>

int list_cb_1(void *, int, char **, char **);

int list_cb_2(void *count, int argc, char **argv, char **azColName)
{
    
    int *c = count;
    
    *c = atoi(argv[0]);
    
    return 0;
    
}

int list(void)
{

    sqlite3 *db;
    
    char *err_msg = 0;

    char sql[100];

    int count = 0;

    int rc = sqlite3_open("plants.db", &db);

    if (rc != SQLITE_OK)
    {

        fprintf(stderr, "Cannot open database: %s\n", 
        sqlite3_errmsg(db));
        sqlite3_close(db);

        return 1;
    }

    sprintf(sql, "SELECT id, number, familia, taxon FROM numbers");

    rc = sqlite3_exec(db, sql, list_cb_1, 0, &err_msg);

    sprintf(sql, "SELECT COUNT(*) FROM numbers");

    rc = sqlite3_exec(db, sql, list_cb_2, &count, &err_msg);

    if (rc != SQLITE_OK )
    {

        fprintf(stderr, "Failed to select data\n");
        fprintf(stderr, "SQL error: %s\n", err_msg);

        sqlite3_free(err_msg);
        sqlite3_close(db);

        return 1;
    }

    printf("\n---------------------------------------\n");

    printf("Total Numbers: %d\n", count);

    sqlite3_close(db);

    return 0;
}

int list_cb_1(void *NotUsed, int argc, char **argv, char **azColName)
{

    NotUsed = 0;

    for (int i = 0; i < argc; i++)
    {

        printf("%s\t ", argv[i]);

    }

    printf("\n");

    return 0;
}

Это вызов в report.c:

const char *report_1 (void)
{

    list();

}

...

HPDF_Page_ShowText (page, report_1());

Ответы (1 шт):

Автор решения: avp

У меня нет sqllite, поэтому не проверял, но думаю, вам надо написать какой-то такой callback:
(я предполагаю, что при каждом вызове он получает очередную строку вывода sql-запроса, в параметре argc передается количество колонок, в argv их значения, а в azColName их названия)

struct sqlres {  // структура, которую запоняет callback
  size_t n_rows,
    n_cols;
  char **col_names;
  char ***list;
};

// вспомогательные функции
static void
copy_strings (char **dst, char **src, int n)
{
  for (int i = 0; i < n; i++)
    dst[i] = strdup(src[i]);
}

static void
free_strings (char **a, int n)
{
  for (int i = 0; i < n; i++)
    free(a[i]);
}

void
free_sqlres (struct sqlres *p)
{
  if (p->col_names) {
    free_strings(p->col_names, p->n_cols);
    free(p->col_names);
  }
  if (p->list) {
    for (int i = 0; i < p->n_rows; i++) {
      free_strings(p->list[i], p->n_cols);
      free(p->list[i]);
    }
    free(p->list);
  }
  memset(p, 0, sizeof(*p));
}

// callback
int
list_cb_2(void *p, int argc, char **argv, char **azColName)
{
  struct sqlres *r = (struct sqlres *)p;

  if (r->n_rows == 0) { // fill only on first call
    r->n_cols = argc;
    r->col_names = malloc(argc * sizeof(char *));
    copy_strings(r->col_names, azColName, argc);
  }

  r->list = realloc(r->list, sizeof(void *) * (r->n_rows + 1));
  r->list[r->n_rows] = malloc(argc * sizeof(char *));
  copy_strings(r->list[r->n_rows], argv, argc);
  
  r->n_rows++;

  return 0;
}

И вызывать его так:

 struct sqlres sr = {0, 0, 0, 0};  // init result list data header

   ....

 rc = sqlite3_exec(db, sql, list_cb_2, &sr, &err_msg);

   ....
 // print sql result
 // print columns title
 for (int i = 0; i < sr.n_cols; i++)
   printf("| %s ", s.col_names[i]);
 puts("\n-----------------");

 // print columns values
 for (int i = 0; i < sr.n_rows; i++) {
   char **as = sr.list[i];
   for (int j = 0; j < sr.n_cols; j++) 
     printf("| %s ", as[j]);
   puts("");  // need if last value not have '\n'
 }
   ...
 free_sqlres(&sr);
   ...
→ Ссылка