summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/sqldbm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/sqldbm.cc')
-rw-r--r--crawl-ref/source/sqldbm.cc279
1 files changed, 279 insertions, 0 deletions
diff --git a/crawl-ref/source/sqldbm.cc b/crawl-ref/source/sqldbm.cc
new file mode 100644
index 0000000000..f3cba77100
--- /dev/null
+++ b/crawl-ref/source/sqldbm.cc
@@ -0,0 +1,279 @@
+/*
+ * File: sqldbm.c
+ * Summary: dbm wrapper for SQLite
+ * Written by: Darshan Shaligram
+ */
+
+#include "AppHdr.h"
+#include "sqldbm.h"
+#include "stuff.h"
+#include <cstring>
+
+#ifdef USE_SQLITE_DBM
+
+SQL_DBM::SQL_DBM(const std::string &dbname, bool do_open)
+ : error(), errc(SQLITE_OK), db(NULL), s_insert(NULL),
+ s_query(NULL), dbfile(dbname)
+{
+ if (do_open && !dbfile.empty())
+ open();
+}
+
+SQL_DBM::~SQL_DBM()
+{
+ close();
+}
+
+int SQL_DBM::ec(int err)
+{
+ if (err == SQLITE_OK)
+ error.clear();
+ else if (db)
+ error = sqlite3_errmsg(db);
+ else
+ error = "Unknown error";
+
+ return (errc = err);
+}
+
+bool SQL_DBM::is_open() const
+{
+ return !!db;
+}
+
+int SQL_DBM::open(const std::string &s)
+{
+ close();
+
+ if (!s.empty())
+ dbfile = s;
+
+ if (!dbfile.empty())
+ {
+ if (dbfile.find(".db") != dbfile.length() - 3)
+ dbfile += ".db";
+
+ if (ec( sqlite3_open(dbfile.c_str(), &db) ) != SQLITE_OK)
+ {
+ std::string saveerr = error;
+ int serrc = errc;
+ close();
+ error = saveerr;
+ errc = serrc;
+ return (errc);
+ }
+
+ init_schema();
+ }
+ else
+ error = "No filename!";
+
+ return (errc);
+}
+
+int SQL_DBM::init_schema()
+{
+ int err = ec(sqlite3_exec(
+ db,
+ "CREATE TABLE dbm (key STRING UNIQUE PRIMARY KEY,"
+ " value STRING);",
+ NULL,
+ NULL,
+ NULL));
+
+ // Turn off auto-commit
+ sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
+ return (err);
+}
+
+void SQL_DBM::close()
+{
+ if (db)
+ {
+ sqlite3_exec(db, "COMMIT;", NULL, NULL, NULL);
+ finalise_query(&s_insert);
+ finalise_query(&s_query);
+ sqlite3_close(db);
+ db = NULL;
+ }
+}
+
+int SQL_DBM::insert(const std::string &key, const std::string &value)
+{
+ if (init_insert() != SQLITE_OK)
+ return (errc);
+
+ ec(sqlite3_bind_text(s_insert, 1, key.c_str(), -1, SQLITE_STATIC));
+ if (errc != SQLITE_OK)
+ return (errc);
+ ec(sqlite3_bind_text(s_insert, 2, value.c_str(), -1, SQLITE_STATIC));
+ if (errc != SQLITE_OK)
+ return (errc);
+
+ ec(sqlite3_step(s_insert));
+ sqlite3_reset(s_insert);
+
+ return (errc);
+}
+
+int SQL_DBM::init_insert()
+{
+ return s_insert? SQLITE_OK :
+ prepare_query(&s_insert, "INSERT INTO dbm VALUES (?, ?)");
+}
+
+std::string SQL_DBM::query(const std::string &key)
+{
+ if (init_query() != SQLITE_OK)
+ return ("");
+
+ if (ec(sqlite3_bind_text(s_query, 1, key.c_str(), -1, SQLITE_TRANSIENT))
+ != SQLITE_OK)
+ {
+ return ("");
+ }
+
+ int err = SQLITE_OK;
+ std::string res;
+ while ((err = ec(sqlite3_step(s_query))) == SQLITE_ROW)
+ res = (const char *) sqlite3_column_text(s_query, 0);
+
+ sqlite3_reset(s_query);
+
+ return (res);
+}
+
+int SQL_DBM::init_query()
+{
+ return s_query? SQLITE_OK :
+ prepare_query(&s_query, "SELECT value FROM dbm WHERE key = ?");
+}
+
+int SQL_DBM::finalise_query(sqlite3_stmt **q)
+{
+ if (!*q)
+ return (SQLITE_OK);
+
+ sqlite3_reset(*q);
+ int ret = ec(sqlite3_finalize(*q));
+ *q = NULL;
+
+ return (ret);
+}
+
+int SQL_DBM::prepare_query(sqlite3_stmt **q, const char *sql)
+{
+ if (*q)
+ finalise_query(q);
+
+ const char *query_tail;
+ return ec(sqlite3_prepare_v2(db, sql, -1, q, &query_tail));
+}
+
+////////////////////////////////////////////////////////////////////////
+
+sql_datum::sql_datum() : dptr(NULL), dsize(0), need_free(false)
+{
+}
+
+sql_datum::sql_datum(const std::string &s) : dptr(NULL), dsize(s.length()),
+ need_free(false)
+{
+ if ((dptr = new char [dsize]))
+ {
+ strcpy(dptr, s.c_str());
+ need_free = true;
+ }
+}
+
+sql_datum::sql_datum(const sql_datum &dat) : dptr(NULL), dsize(0), need_free(false)
+{
+ init_from(dat);
+}
+
+sql_datum::~sql_datum()
+{
+ reset();
+}
+
+sql_datum &sql_datum::operator = (const sql_datum &d)
+{
+ if (&d != this)
+ {
+ reset();
+ init_from(d);
+ }
+ return (*this);
+}
+
+void sql_datum::reset()
+{
+ if (need_free)
+ delete [] dptr;
+
+ dptr = NULL;
+ dsize = 0;
+}
+
+void sql_datum::init_from(const sql_datum &d)
+{
+ dsize = d.dsize;
+ need_free = false;
+ if (d.need_free)
+ {
+ if ((dptr = new char [dsize]))
+ {
+ if (dsize)
+ memcpy(dptr, d.dptr, dsize);
+ need_free = true;
+ }
+ }
+ else
+ {
+ need_free = false;
+ dptr = d.dptr;
+ }
+}
+
+std::string sql_datum::to_str() const
+{
+ return std::string(dptr, dsize);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+SQL_DBM *dbm_open(const char *filename, int, int)
+{
+ SQL_DBM *n = new SQL_DBM(filename, true);
+ if (!n->is_open())
+ {
+ delete n;
+ return (NULL);
+ }
+
+ return (n);
+}
+
+int dbm_close(SQL_DBM *db)
+{
+ delete db;
+ return (0);
+}
+
+sql_datum dbm_fetch(SQL_DBM *db, const sql_datum &key)
+{
+ std::string ans = db->query(std::string(key.dptr, key.dsize));
+ return sql_datum(ans);
+}
+
+int dbm_store(SQL_DBM *db, const sql_datum &key, const sql_datum &value, int)
+{
+ int err = db->insert(key.to_str(), value.to_str());
+ if (err == SQLITE_DONE || err == SQLITE_CONSTRAINT)
+ err = SQLITE_OK;
+ else
+ end(1, false, "%d: %s", db->errc, db->error.c_str());
+ return (err);
+}
+
+#endif