Below is the file 'src/lsi/sql.c' from this revision. You can also download the file.

/* sql.c */

#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#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;
}