Как сформулировать вывод из 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);
...