diff --git a/src/lsi/sql.c b/src/lsi/sql.c new file mode 100644 index 0000000..b9e3671 --- /dev/null +++ b/src/lsi/sql.c @@ -0,0 +1,99 @@ +/* sql.c */ + +#include +#include +#include +#include +#include +#include "sqlite3.h" +#include "vm.h" + +sqlite3 *sql_db; +int sql_initialised = 0; + +#define SQL_FILENAME ".lsdata" + +void sql_error(char *msg) +{ + fprintf(stderr, "sql error: %s: %s\n", msg, sqlite3_errmsg(sql_db)); +} + +int sql_init(void) +{ + if (sqlite3_open(SQL_FILENAME, &sql_db) != SQLITE_OK) { + sql_error("can't open sql database"); + sql_initialised = 0; + return 0; + } + + sql_initialised = 1; + + return 1; +} + +void sql_close(void) +{ + sqlite3_close(sql_db); + /* + * XXX technically, this could return SQLITE_BUSY, which we ought + * to deal with + */ + sql_initialised = 0; +} + +/* + * We return 0 for failure, 1 for query with no rows, 2 for query with + * a valid return value. + */ +int sql_query(char *query, int qlen, int *result) +{ + sqlite3_stmt *stmt; + const char *ztail; + int done; + int rows; + + if (!sql_initialised) + return 0; + + *result = 0; + done = 0; + rows = 0; + + if (sqlite3_prepare_v2(sql_db, query, qlen, &stmt, &ztail) + != SQLITE_OK) { + sql_error("error from sqlite3_prepare"); + return 0; + } + + while (1) { + int rv = sqlite3_step(stmt); + + if (rv == SQLITE_DONE) { + done = 1; + break; + } + if (rv == SQLITE_ROW) { + /* XXX we just deal with one return value for now */ + *result = sqlite3_column_int(stmt, 0); + rows++; + continue; + } + if (rv == SQLITE_OK) + continue; + break; + } + + if (!done) { + sql_error("error after sqlite3_step"); + } + if (sqlite3_finalize(stmt) != SQLITE_OK) { + sql_error("error from sqlite3_finalize"); + return 0; + } + + if (done) + return (rows ? 2 : 1); + + return 0; +} + diff --git a/src/lsi/sql.h b/src/lsi/sql.h new file mode 100644 index 0000000..477259d --- /dev/null +++ b/src/lsi/sql.h @@ -0,0 +1,5 @@ +/* sql.h */ + +int sql_init(void); +void sql_close(void); +int sql_query(char *query, int qlen, int *result);