1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
/**
* To implement sorting, we will use sqlite, create a table for each CSV file and run "select * order by ..."
*/
#include "external/sqlite3/sqlite3_csv_vtab-mem.h"
static int zsv_compare_sort_prep_table(struct zsv_compare_data *data, const char *fname, char **err_msg,
unsigned int table_ix) {
#define ZSV_COMPARE_MAX_TABLES 1000
char *sql = NULL;
if (table_ix > ZSV_COMPARE_MAX_TABLES)
return -1;
sql = sqlite3_mprintf("CREATE VIRTUAL TABLE data%i USING csv(filename=%Q)", table_ix, fname);
if (!sql)
return -1;
int rc = sqlite3_exec(data->sort_db, sql, NULL, NULL, err_msg);
sqlite3_free(sql);
return rc;
}
static int zsv_compare_sort_stmt_prep(sqlite3 *db, sqlite3_stmt **stmtp, struct zsv_compare_key *keys, unsigned ix) {
sqlite3_str *select_clause = sqlite3_str_new(db);
if (!select_clause) {
fprintf(stderr, "Out of memory!\n");
return -1;
}
sqlite3_str_appendf(select_clause, "select * from data%i order by ", ix);
for (struct zsv_compare_key *key = keys; key; key = key->next)
sqlite3_str_appendf(select_clause, "%s\"%w\"", key == keys ? "" : ", ", key->name);
int rc = sqlite3_prepare_v2(db, sqlite3_str_value(select_clause), -1, stmtp, NULL);
if (rc != SQLITE_OK)
fprintf(stderr, "%s: %s\n", sqlite3_errstr(rc), sqlite3_str_value(select_clause));
sqlite3_free(sqlite3_str_finish(select_clause));
return rc;
}
static enum zsv_compare_status input_init_sorted(struct zsv_compare_data *data, struct zsv_compare_input *input,
struct zsv_opts *opts, struct zsv_prop_handler *custom_prop_handler) {
char *err_msg = NULL;
if (!sqlite3_zsv_list_add(input->path, opts, custom_prop_handler))
input->added = 1;
int rc = zsv_compare_sort_prep_table(data, input->path, &err_msg, input->index);
if (err_msg) {
fprintf(stderr, "%s\n", err_msg);
sqlite3_free(err_msg);
}
if (rc == SQLITE_OK)
rc = zsv_compare_sort_stmt_prep(data->sort_db, &input->sort_stmt, data->keys, input->index);
return rc == SQLITE_OK ? zsv_compare_status_ok : zsv_compare_status_error;
}
static enum zsv_status zsv_compare_next_sorted_row(struct zsv_compare_input *input) {
if (sqlite3_step(input->sort_stmt) == SQLITE_ROW)
return zsv_status_row;
// to do: check if error; if so return zsv_status_error
return zsv_status_done;
}
static struct zsv_cell zsv_compare_get_sorted_colname(struct zsv_compare_input *input, unsigned ix) {
struct zsv_cell c = {
.str = (unsigned char *)sqlite3_column_name(input->sort_stmt, (int)ix),
.quoted = 1,
};
c.len = c.str ? strlen((const char *)c.str) : 0;
return c;
}
static unsigned zsv_compare_get_sorted_colcount(struct zsv_compare_input *input) {
int col_count = sqlite3_column_count(input->sort_stmt);
if (col_count >= 0)
return (unsigned)col_count;
return 0;
}
static struct zsv_cell zsv_compare_get_sorted_cell(struct zsv_compare_input *input, unsigned ix) {
struct zsv_cell c = {
.str = (unsigned char *)sqlite3_column_text(input->sort_stmt, (int)ix),
.quoted = 1,
};
c.len = c.str ? sqlite3_column_bytes(input->sort_stmt, (int)ix) : 0;
if (c.len)
c.str = (unsigned char *)zsv_strtrim(c.str, &c.len);
return c;
}
|