2021-03-08 16:59:27 -05:00
|
|
|
/* <https://gist.github.com/enile8/2424514> */
|
2021-03-08 23:16:14 -05:00
|
|
|
#define _POSIX_C_SOURCE 200809L /* strtok_r, strndup */
|
|
|
|
#include <string.h>
|
2021-03-08 16:59:27 -05:00
|
|
|
#include <assert.h> /* assert */
|
|
|
|
#include <sqlite3.h>
|
|
|
|
#include <stdio.h> /* size_t */
|
2021-03-11 17:23:43 -05:00
|
|
|
#include <stdlib.h> /* free */
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
#include "data.h"
|
2021-03-08 23:16:14 -05:00
|
|
|
#include "io.h"
|
2021-03-31 08:47:18 -04:00
|
|
|
#include "i18n.h"
|
2021-03-11 20:48:32 -05:00
|
|
|
#include "unused.h"
|
2021-03-08 16:59:27 -05:00
|
|
|
|
2021-03-31 08:47:18 -04:00
|
|
|
#define FINISH_UP() \
|
|
|
|
rc = sqlite3_reset(stmt); \
|
|
|
|
if (SQLITE_OK != rc) { \
|
|
|
|
fprintf(stderr, string_errmsg_reset, sqlite3_errmsg(db)); \
|
|
|
|
} \
|
|
|
|
rc = sqlite3_clear_bindings(stmt); \
|
|
|
|
if (SQLITE_OK != rc) { \
|
|
|
|
fprintf(stderr, string_errmsg_clear, sqlite3_errmsg(db)); \
|
|
|
|
} \
|
|
|
|
return sqlite3_finalize(stmt)
|
|
|
|
|
|
|
|
static const char string_errmsg_bind[] = _("Error binding parameter: %s\n");
|
|
|
|
static const char string_errmsg_clear[] = _("Error clearing bindings: %s\n");
|
|
|
|
static const char string_errmsg_delete[] = _("Error deleting data: %s\n");
|
|
|
|
static const char string_errmsg_insert[] = _("Error inserting data: %s\n");
|
|
|
|
static const char string_errmsg_prepare[] = _("Error preparing data: %s\n");
|
|
|
|
static const char string_errmsg_readfile[] = _("Error reading file: %s\n");
|
|
|
|
static const char string_errmsg_reset[] = _("Error resetting statement: %s\n");
|
|
|
|
static const char string_errmsg_update[] = _("Error updating data: %s\n");
|
|
|
|
static const char string_null_msg[] = _("(null)\n");
|
|
|
|
static const char string_sqlite_version[] = _("SQLite version: %s\n");
|
|
|
|
static const char string_unmatched_comment[] = _("Unmatched comment: %d\n");
|
|
|
|
|
|
|
|
int run_script_callback(void *NotUsed, int argc, char **argv, char **azColName) {
|
2021-03-08 16:59:27 -05:00
|
|
|
int i;
|
|
|
|
UNUSED(NotUsed);
|
|
|
|
for (i = 0; i < argc; i++) {
|
2021-03-31 08:47:18 -04:00
|
|
|
printf(" => %s = %s\n", azColName[i], (argv[i] ? argv[i] : string_null_msg));
|
2021-03-08 16:59:27 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
return SQLITE_OK;
|
2021-03-08 16:59:27 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
int run_script(sqlite3 * db, int (*callback)(void *, int, char **, char **), const char *script_filename) {
|
|
|
|
int j, rc, incomment;
|
2021-03-11 20:48:32 -05:00
|
|
|
char *statements, *zErrMsg;
|
2021-03-12 12:41:17 -05:00
|
|
|
char *str1, *saveptr1, *token;
|
2021-03-08 16:59:27 -05:00
|
|
|
zErrMsg = 0;
|
2021-03-11 20:48:32 -05:00
|
|
|
if (!(statements = file_read(script_filename, NULL))) {
|
|
|
|
fprintf(stderr, string_errmsg_readfile, script_filename);
|
2021-03-09 01:39:19 -05:00
|
|
|
return -1;
|
2021-03-08 16:59:27 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
incomment = 0;
|
2021-03-11 20:48:32 -05:00
|
|
|
for (j = 1, str1 = statements;; j++, str1 = NULL) {
|
2021-03-08 16:59:27 -05:00
|
|
|
token = strtok_r(str1, "\n", &saveptr1);
|
|
|
|
if (token == NULL)
|
|
|
|
break;
|
2021-03-08 23:16:14 -05:00
|
|
|
if (strlen(token) > 2 && token[0] == '-' && token[1] == '-')
|
2021-03-11 12:48:15 -05:00
|
|
|
continue; /* Comment line; TODO multiline comment */
|
2021-03-31 08:47:18 -04:00
|
|
|
if (strstr(token, "/*")) {
|
|
|
|
incomment = 1;
|
|
|
|
}
|
|
|
|
if (strstr(token, "*/")) {
|
|
|
|
if (!incomment) {
|
|
|
|
fprintf(stderr, string_unmatched_comment, j);
|
|
|
|
}
|
|
|
|
incomment = 0;
|
|
|
|
}
|
|
|
|
if (incomment)
|
|
|
|
continue;
|
2021-03-08 16:59:27 -05:00
|
|
|
printf("%d: %s\n", j, token);
|
2021-03-31 08:47:18 -04:00
|
|
|
rc = sqlite3_exec(db, token, callback, 0, &zErrMsg);
|
2021-03-11 12:48:15 -05:00
|
|
|
if (SQLITE_OK != rc) {
|
2021-03-31 08:47:18 -04:00
|
|
|
fprintf(stderr, "!! SQL error: %s\n", zErrMsg);
|
2021-03-08 16:59:27 -05:00
|
|
|
sqlite3_free(zErrMsg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 20:48:32 -05:00
|
|
|
free(statements);
|
2021-03-08 16:59:27 -05:00
|
|
|
fprintf(stderr, "Bye!\n");
|
2021-03-11 12:48:15 -05:00
|
|
|
return SQLITE_OK;
|
2021-03-08 16:59:27 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
int run_one(sqlite3 * db, int (*callback)(void *, int, char **, char **), const char *query) {
|
|
|
|
int rc = SQLITE_ERROR;
|
|
|
|
char *zErrMsg = NULL;
|
|
|
|
if (SQLITE_OK != (rc = sqlite3_exec(db, query, callback, 0, &zErrMsg))) {
|
|
|
|
fprintf(stderr, "!! SQL error: %s\n", zErrMsg);
|
|
|
|
sqlite3_free(zErrMsg);
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
return rc;
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
int insert_new_definition(sqlite3 * db, const char *channel, const char *name, const char *word, const char *definition) {
|
|
|
|
const char insert_stmt[] = "insert into dictionarydb (date_added , channel , added_by, word , definition ) values (datetime('now'), ?, ?, ?, ?)";
|
2021-03-11 12:48:15 -05:00
|
|
|
int n, rc;
|
|
|
|
sqlite3_stmt *stmt = NULL;
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
rc = sqlite3_prepare_v2(db, insert_stmt, -1, &stmt, 0);
|
|
|
|
if (SQLITE_OK != rc) {
|
2021-03-11 20:48:32 -05:00
|
|
|
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db));
|
2021-03-31 08:47:18 -04:00
|
|
|
goto _out;
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
n = 0;
|
|
|
|
#define S(x) \
|
|
|
|
rc = sqlite3_bind_text(stmt, ++n, x, (int)strnlen(x, 4096), SQLITE_STATIC); \
|
|
|
|
if (SQLITE_OK != rc) { \
|
|
|
|
fprintf(stderr, string_errmsg_bind, sqlite3_errmsg(db)); \
|
|
|
|
goto _out; \
|
|
|
|
}
|
|
|
|
S(channel);
|
|
|
|
S(name);
|
|
|
|
S(word);
|
|
|
|
S(definition);
|
2021-03-11 12:48:15 -05:00
|
|
|
#undef S
|
2021-03-31 08:47:18 -04:00
|
|
|
|
2021-03-11 12:48:15 -05:00
|
|
|
if (SQLITE_DONE != (rc = sqlite3_step(stmt))) {
|
2021-03-31 08:47:18 -04:00
|
|
|
fprintf(stderr, string_errmsg_insert, sqlite3_errmsg(db));
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
_out:
|
|
|
|
FINISH_UP();
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
int delete_from_table_by_rowid(sqlite3 * db, int rowid) {
|
|
|
|
int rc;
|
|
|
|
const char insert_stmt[] = "delete from dictionarydb where rowid = ?";
|
2021-03-11 12:48:15 -05:00
|
|
|
sqlite3_stmt *stmt = NULL;
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
rc = sqlite3_prepare_v2(db, insert_stmt, -1, &stmt, 0);
|
|
|
|
if (SQLITE_OK != rc) {
|
2021-03-11 20:48:32 -05:00
|
|
|
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db));
|
2021-03-31 08:47:18 -04:00
|
|
|
goto _out;
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
rc = sqlite3_bind_int(stmt, 1, rowid);
|
|
|
|
if (SQLITE_OK != rc) {
|
|
|
|
fprintf(stderr, string_errmsg_bind, sqlite3_errmsg(db));
|
|
|
|
goto _out;
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
if (SQLITE_DONE != (rc = sqlite3_step(stmt))) {
|
|
|
|
fprintf(stderr, string_errmsg_delete, sqlite3_errmsg(db));
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
_out:
|
|
|
|
FINISH_UP();
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
2021-03-11 12:48:15 -05:00
|
|
|
int sqlite_version(sqlite3 * db) {
|
|
|
|
int rc;
|
|
|
|
sqlite3_stmt *stmt = NULL;
|
2021-03-31 08:47:18 -04:00
|
|
|
rc = sqlite3_prepare_v2(db, "SELECT SQLITE_VERSION()", -1, &stmt, 0);
|
|
|
|
if (SQLITE_OK != rc) {
|
2021-03-11 20:48:32 -05:00
|
|
|
fprintf(stderr, string_errmsg_prepare, sqlite3_errmsg(db));
|
2021-03-31 08:47:18 -04:00
|
|
|
goto _out;
|
|
|
|
}
|
|
|
|
while (SQLITE_ROW == (rc = sqlite3_step(stmt))) {
|
|
|
|
printf(string_sqlite_version, sqlite3_column_text(stmt, 0));
|
|
|
|
}
|
|
|
|
if (SQLITE_DONE != rc) {
|
|
|
|
fprintf(stderr, string_errmsg_update, sqlite3_errmsg(db));
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
_out:
|
|
|
|
FINISH_UP();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* table_exists(tbl) =>
|
|
|
|
* 0 => table does not exist
|
|
|
|
* 1 => table exists
|
|
|
|
*/
|
|
|
|
int table_exists(sqlite3 * db, int (*callback)(void *, int, char **, char **), const char *table) {
|
|
|
|
int ret, rc;
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
const char table_exists_query[] = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '%s'";
|
|
|
|
char *zErrMsg;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
memset(buf, 0, BUFSIZ);
|
|
|
|
sprintf(buf, table_exists_query, table);
|
|
|
|
rc = sqlite3_exec(db, buf, callback, 0, &zErrMsg);
|
|
|
|
if (SQLITE_OK == rc) {
|
|
|
|
ret = 1;
|
2021-03-11 12:48:15 -05:00
|
|
|
}
|
2021-03-31 08:47:18 -04:00
|
|
|
|
|
|
|
return ret;
|
2021-03-08 16:59:27 -05:00
|
|
|
}
|