diff options
Diffstat (limited to 'crawl-ref/source/sqldbm.cc')
-rw-r--r-- | crawl-ref/source/sqldbm.cc | 279 |
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 |