From 198b0d886817f2c5bc97cfd11857d4b314dffae3 Mon Sep 17 00:00:00 2001 From: deva Date: Thu, 10 Jun 2010 07:03:06 +0000 Subject: Add transaction support on database pr. pracro session. Makes it possible to discard all edited macros. --- server/configure.in | 2 +- server/src/database.h | 55 ++++++++++-- server/src/environment.cc | 6 +- server/src/environment.h | 4 +- server/src/journalwriter.cc | 27 +++++- server/src/journalwriter.h | 3 + server/src/pracrodao.h | 26 ++++-- server/src/pracrodaopgsql.cc | 184 ++++++++++++++++++++++++++++----------- server/src/pracrodaopgsql.h | 30 +++++-- server/src/pracrodaotest.h | 20 ++++- server/src/saxparser.cc | 1 + server/src/session.cc | 23 +++++ server/src/session.h | 3 + server/src/sessionparser.cc | 17 +++- server/src/sessionparser.h | 3 + server/src/sessionserialiser.cc | 27 ++++-- server/src/transactionhandler.cc | 31 +++++-- server/src/xml_encode_decode.cc | 13 ++- 18 files changed, 380 insertions(+), 95 deletions(-) (limited to 'server') diff --git a/server/configure.in b/server/configure.in index 23a7172..3469af2 100644 --- a/server/configure.in +++ b/server/configure.in @@ -1,7 +1,7 @@ # Filename: configure.in AC_INIT(src/pracrod.cc) -AM_INIT_AUTOMAKE( pracrod, 1.1.0 ) +AM_INIT_AUTOMAKE( pracrod, 2.0.0-beta2 ) dnl ====================== dnl Compile with debug options diff --git a/server/src/database.h b/server/src/database.h index f253ba5..9b08801 100644 --- a/server/src/database.h +++ b/server/src/database.h @@ -37,31 +37,45 @@ class Database { public: - Database(std::string _backend, std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname); + Database(std::string _backend, std::string _host, + std::string _port, std::string _user, + std::string _passwd, std::string _dbname); ~Database(); // Make a commit to the db - void commitTransaction(std::string user, std::string patientid, Macro ¯o, Fields &fields, time_t now = time(NULL)) { + void commitTransaction(std::string user, + std::string patientid, + Macro ¯o, + Fields &fields, + time_t now = time(NULL)) { if(!dao) return; mutex.lock(); - PRACRO_DEBUG(db, "%s, %s, %s,...\n", user.c_str(), patientid.c_str(), macro.attributes["name"].c_str()); + PRACRO_DEBUG(db, "%s, %s, %s,...\n", + user.c_str(), patientid.c_str(), + macro.attributes["name"].c_str()); dao->commitTransaction(user, patientid, macro, fields, now); mutex.unlock(); } // Get a list of values from the db - Values getValues(std::string patientid, Fieldnames &fieldnames, time_t oldest = 0) { + Values getValues(std::string patientid, + Fieldnames &fieldnames, + time_t oldest = 0) { if(!dao) return Values(); mutex.lock(); - PRACRO_DEBUG(db, "%s, <%u fieldnames>, %ld\n", patientid.c_str(), fieldnames.size(), oldest); + PRACRO_DEBUG(db, "%s, <%u fieldnames>, %ld\n", + patientid.c_str(), fieldnames.size(), oldest); Values values = dao->getLatestValues(patientid, NULL, fieldnames, oldest); mutex.unlock(); return values; } // Check if a macro has been committed. - bool checkMacro(std::string patientid, std::string macro, time_t oldest = 0) { - PRACRO_DEBUG(db, "%s, %s, %ld\n", patientid.c_str(), macro.c_str(), oldest); + bool checkMacro(std::string patientid, + std::string macro, + time_t oldest = 0) { + PRACRO_DEBUG(db, "%s, %s, %ld\n", + patientid.c_str(), macro.c_str(), oldest); if(!dao) return false; mutex.lock(); bool res = dao->nrOfCommits(patientid, macro, oldest) > 0; @@ -71,7 +85,8 @@ public: // Get latest resume of a given macro std::string getResume(std::string patientid, Macro ¯o, time_t oldest) { - PRACRO_DEBUG(db, "%s, %s, %ld\n", patientid.c_str(), macro.attributes["name"].c_str(), oldest); + PRACRO_DEBUG(db, "%s, %s, %ld\n", + patientid.c_str(), macro.attributes["name"].c_str(), oldest); if(!dao) return ""; Fieldnames fn; fn.push_back("journal.resume"); @@ -111,6 +126,30 @@ public: return fieldnames; } + void commit() + { + if(!dao) return; + return dao->commit(); + } + + void discard() + { + if(!dao) return; + return dao->discard(); + } + + std::string serialise() + { + if(!dao) return ""; + return dao->serialise(); + } + + void restore(const std::string &data) + { + if(!dao) return; + return dao->restore(data); + } + private: PracroDAO *dao; Mutex mutex; diff --git a/server/src/environment.cc b/server/src/environment.cc index 9904afc..f1e035e 100644 --- a/server/src/environment.cc +++ b/server/src/environment.cc @@ -34,11 +34,12 @@ Environment::Environment() : macrolist(Conf::xml_basedir + "/macros"), templatelist(Conf::xml_basedir + "/templates") { + /* for(int i = 0; i < Conf::database_poolsize; i++) { dbpool.add(new Database(Conf::database_backend, Conf::database_addr, "", Conf::database_user, Conf::database_passwd, "")); } - + */ for(int i = 0; i < Conf::artefact_poolsize; i++) { atfpool.add(new Artefact); } @@ -46,6 +47,7 @@ Environment::Environment() Environment::~Environment() { + /* // Remove, but wait until resources are released std::list dblst = dbpool.clear(false); std::list::iterator i = dblst.begin(); @@ -53,7 +55,7 @@ Environment::~Environment() delete *i; i++; } - + */ // Remove, but wait until resources are released std::list atflst = atfpool.clear(false); std::list::iterator j = atflst.begin(); diff --git a/server/src/environment.h b/server/src/environment.h index a7b9677..3e2ac95 100644 --- a/server/src/environment.h +++ b/server/src/environment.h @@ -28,7 +28,7 @@ #ifndef __PRACRO_ENVIRONMENT_H__ #define __PRACRO_ENVIRONMENT_H__ -#include "database.h" +//#include "database.h" #include "artefact.h" #include "connectionpool.h" #include "session.h" @@ -40,7 +40,7 @@ public: Environment(); ~Environment(); - ConnectionPool dbpool; + // ConnectionPool dbpool; ConnectionPool atfpool; Sessions sessions; MacroList macrolist; diff --git a/server/src/journalwriter.cc b/server/src/journalwriter.cc index 4b2b4be..5858de4 100644 --- a/server/src/journalwriter.cc +++ b/server/src/journalwriter.cc @@ -217,7 +217,7 @@ void JournalWriter::addEntry(Transaction &transaction, Commit &commit, void JournalWriter::addEntry(std::string resume, std::string macro, int index) { // Strip trailing whitespace, and add newlines. - std::string r = stripTrailingWhitepace(addNewlines(resume, 60)); + std::string r = resume; std::string m = macro; ResumeEntry re; @@ -235,7 +235,7 @@ void JournalWriter::commit() while(i != entrylist.end()) { if(resume != "") resume += "\n\n"; // resume += i->macro + "\n"; - resume += i->second.resume; + resume += stripTrailingWhitepace(addNewlines(i->second.resume, 60)); i++; } @@ -247,6 +247,29 @@ void JournalWriter::commit() resume.c_str(), resume.size()); } +std::string JournalWriter::getEntry(std::string macro) +{ + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); + while(i != entrylist.end()) { + if(i->second.macro == macro) return i->second.resume; + i++; + } + return ""; +} + +void JournalWriter::removeEntry(std::string macro) +{ + std::map< int, ResumeEntry >::iterator i = entrylist.begin(); + while(i != entrylist.end()) { + if(i->second.macro == macro) { + entrylist.erase(i); + break; + } + i++; + } +} + + #ifdef TEST_JOURNALWRITER //deps: debug.cc journal_commit.cc //cflags: -I.. diff --git a/server/src/journalwriter.h b/server/src/journalwriter.h index 2cd191d..ea1b514 100644 --- a/server/src/journalwriter.h +++ b/server/src/journalwriter.h @@ -48,6 +48,9 @@ public: void commit(); + std::string getEntry(std::string macro); + void removeEntry(std::string macro); + private: std::string host; unsigned short int port; diff --git a/server/src/pracrodao.h b/server/src/pracrodao.h index 1ef9686..7825dee 100644 --- a/server/src/pracrodao.h +++ b/server/src/pracrodao.h @@ -38,17 +38,33 @@ class PracroDAO { public: - PracroDAO(std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname); + PracroDAO(std::string _host, std::string _port, + std::string _user, std::string _passwd, std::string _dbname); virtual ~PracroDAO(); - virtual void commitTransaction(std::string user, std::string patientid, Macro ¯o, Fields &fields, time_t now) = 0; - virtual Values getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest) = 0; - virtual unsigned nrOfCommits(std::string patientid, std::string macroname, time_t oldest) = 0; + virtual void commitTransaction(std::string user, + std::string patientid, + Macro ¯o, + Fields &fields, + time_t now) = 0; + virtual Values getLatestValues(std::string patientid, + Macro *macro, + Fieldnames &fieldnames, + time_t oldest) = 0; + virtual unsigned nrOfCommits(std::string patientid, + std::string macroname, + time_t oldest) = 0; - virtual void addFieldname(std::string name, std::string description) = 0; + virtual void addFieldname(std::string name, + std::string description) = 0; virtual void delFieldname(std::string name) = 0; virtual std::vector getFieldnames() = 0; + virtual void commit() = 0; + virtual void discard() = 0; + virtual std::string serialise() = 0; + virtual void restore(const std::string &data) = 0; + protected: std::string host; std::string port; diff --git a/server/src/pracrodaopgsql.cc b/server/src/pracrodaopgsql.cc index d1ba517..6d7afe8 100644 --- a/server/src/pracrodaopgsql.cc +++ b/server/src/pracrodaopgsql.cc @@ -34,7 +34,9 @@ * CREATE SEQUENCE 'trseq'; * SELECT setval('trseq', (SELECT MAX(oid) FROM transactions)); * UPDATE transactions SET uid = oid; - * INSERT INTO fieldnames (name, description, timestamp) VALUES ('journal.resume', 'Journal resume text', (SELECT EXTRACT(EPOCH FROM now())::integer)); + * INSERT INTO fieldnames (name, description, timestamp) + * VALUES ('journal.resume', 'Journal resume text', + * (SELECT EXTRACT(EPOCH FROM now())::integer)); */ #include @@ -44,7 +46,9 @@ #include "debug.h" -PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname) +PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, + std::string _user, std::string _passwd, + std::string _dbname) : PracroDAO(_host, _port, _user, _passwd, _dbname) { conn = NULL; @@ -56,6 +60,15 @@ PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, std::string cs += " dbname=" + (dbname.size() ? dbname : "pracro"); try { conn = new pqxx::connection(cs); + W = new pqxx::work(*conn); + + std::string ts; + try { + ts = "BEGIN;"; + PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); + pqxx::result R = W->exec(ts); + } catch(...) { + } } catch(std::exception &e) { PRACRO_ERR_LOG(db, "Postgresql init failed: %s\n", e.what()); conn = NULL; @@ -66,12 +79,23 @@ PracroDAOPgsql::PracroDAOPgsql(std::string _host, std::string _port, std::string PracroDAOPgsql::~PracroDAOPgsql() { - if(conn) delete conn; + if(conn) { + if(W) delete W; + delete conn; + } } -void PracroDAOPgsql::commitTransaction(std::string user, std::string patientid, Macro &_macro, Fields &fields, time_t now) +void PracroDAOPgsql::commitTransaction(std::string user, + std::string patientid, + Macro &_macro, + Fields &fields, + time_t now) { - PRACRO_DEBUG(db, "(%s, %s, %s, <%u fields>, %ld)\n", user.c_str(), patientid.c_str(), _macro.attributes["name"].c_str(), fields.size(), now); + PRACRO_DEBUG(db, "(%s, %s, %s, <%u fields>, %ld)\n", + user.c_str(), patientid.c_str(), + _macro.attributes["name"].c_str(), + fields.size(), now); + if(!conn) PRACRO_DEBUG(db, "No pgsql connection\n"); if(fields.size() == 0) return; @@ -81,54 +105,66 @@ void PracroDAOPgsql::commitTransaction(std::string user, std::string patientid, std::string ts; try { - pqxx::work W(*conn); - ts = "INSERT INTO transactions (uid, patientid, macro, version, \"timestamp\", \"user\") VALUES (" + ts = "INSERT INTO transactions (uid, patientid, macro, version," + " \"timestamp\", \"user\") VALUES (" " nextval('trseq'), " - " '" + W.esc(patientid) + "', " - " '" + W.esc(macro) + "', " - " '" + W.esc(version) + "', " - " '" + W.esc(timestamp.str()) + "', " - " '" + W.esc(user) + "' " - ")" + " '" + W->esc(patientid) + "', " + " '" + W->esc(macro) + "', " + " '" + W->esc(version) + "', " + " '" + W->esc(timestamp.str()) + "', " + " '" + W->esc(user) + "' " + ");" ; PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); - pqxx::result R = W.exec(ts); + pqxx::result R = W->exec(ts); + statements += ts + "\n"; if(fields.size() > 0) { // field table lookup ts = "SELECT name FROM fieldnames WHERE name IN ( "; std::map< std::string, std::string >::iterator i = fields.begin(); - ts += "'" + W.esc(i->first) + "'"; + ts += "'" + W->esc(i->first) + "'"; i++; while(i != fields.end()) { - ts += ", '" + W.esc(i->first) + "'"; + ts += ", '" + W->esc(i->first) + "'"; i++; } - ts += ")"; + ts += ");"; PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); - R = W.exec(ts); - PRACRO_DEBUG(db, "input fields: %d, output fields: %lu\n", fields.size(), R.size()); + R = W->exec(ts); + // statements += ts + "\n"; + + PRACRO_DEBUG(db, "input fields: %d, output fields: %lu\n", + fields.size(), R.size()); // Store known fields pqxx::result::const_iterator ri = R.begin(); if(ri != R.end()) { std::string name = (*ri)[0].c_str(); - PRACRO_DEBUG(db, "Storing: %s with value %s\n", name.c_str(), fields[name].c_str()); - ts = "INSERT INTO fields (transaction, name, value) VALUES ( currval('trseq'), '" + W.esc(name) + "', '" + W.esc(fields[name]) + "')"; + PRACRO_DEBUG(db, "Storing: %s with value %s\n", + name.c_str(), fields[name].c_str()); + ts = "INSERT INTO fields (transaction, name, value) " + "VALUES ( currval('trseq'), '" + W->esc(name) + "', '" + + W->esc(fields[name]) + "')"; ri++; while(ri != R.end()) { name = (*ri)[0].c_str(); - PRACRO_DEBUG(db, "Storing: %s with value %s\n", name.c_str(), fields[name].c_str()); + PRACRO_DEBUG(db, "Storing: %s with value %s\n", + name.c_str(), fields[name].c_str()); - ts += ", (currval('trseq'), '" + W.esc(name) + "', '" + W.esc(fields[name]) + "')"; + ts += ", (currval('trseq'), '" + W->esc(name) + "', '" + + W->esc(fields[name]) + "')"; ri++; } + ts += ";"; PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); - W.exec(ts); + W->exec(ts); + statements += ts + "\n"; + } } - W.commit(); + // W->commit(); } catch(std::exception &e) { PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); } @@ -156,9 +192,15 @@ void PracroDAOPgsql::commitTransaction(std::string user, std::string patientid, * AND tt.uid = ff.transaction * AND tt.patientid = '1505050505' */ -Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest) +Values PracroDAOPgsql::getLatestValues(std::string patientid, + Macro *macro, + Fieldnames &fieldnames, + time_t oldest) { - PRACRO_DEBUG(db, "(%s, %s, <%u fieldnames>, %ld)\n", patientid.c_str(), macro ? macro->attributes["name"].c_str() : "(null)", fieldnames.size(), oldest); + PRACRO_DEBUG(db, "(%s, %s, <%u fieldnames>, %ld)\n", + patientid.c_str(), + macro ? macro->attributes["name"].c_str() : "(null)", + fieldnames.size(), oldest); if(!conn) PRACRO_DEBUG(db, "No pgsql connection\n"); Values values; @@ -167,13 +209,12 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel try { std::string namecond; - pqxx::work W(*conn); if(fieldnames.size() > 0) { std::vector< std::string >::iterator i = fieldnames.begin(); - namecond += " AND f.name IN ('" + W.esc(*i) + "'"; + namecond += " AND f.name IN ('" + W->esc(*i) + "'"; i++; while(i != fieldnames.end()) { - namecond += ", '" + W.esc(*i) + "'"; + namecond += ", '" + W->esc(*i) + "'"; i++; } namecond += ')'; @@ -182,7 +223,7 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel // Begin inner query " (SELECT f.name, MAX(t.timestamp) AS ts FROM fields f, transactions t " " WHERE t.uid = f.transaction AND t.timestamp >= " + soldest.str() + - " AND t.patientid = '" + W.esc(patientid) + "' " + " AND t.patientid = '" + W->esc(patientid) + "' " + namecond; if(macro) { query += " AND t.macro = '" + macro->attributes["name"] + "'"; @@ -195,7 +236,7 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel " WHERE xx.ts = tt.timestamp " " AND xx.name = ff.name " " AND tt.uid = ff.transaction " - " AND tt.patientid = '" + W.esc(patientid) + "' " + " AND tt.patientid = '" + W->esc(patientid) + "' " ; if(macro) { query += " AND tt.macro = '" + macro->attributes["name"] + "'"; @@ -204,7 +245,7 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel } PRACRO_DEBUG(sql, "Query: %s\n", query.c_str()); - pqxx::result R = W.exec(query); + pqxx::result R = W->exec(query); pqxx::result::const_iterator ri = R.begin(); while(ri != R.end()) { Value v; @@ -221,25 +262,27 @@ Values PracroDAOPgsql::getLatestValues(std::string patientid, Macro *macro, Fiel } -unsigned PracroDAOPgsql::nrOfCommits(std::string patientid, std::string macroname, time_t oldest) +unsigned PracroDAOPgsql::nrOfCommits(std::string patientid, + std::string macroname, + time_t oldest) { std::string query; std::stringstream soldest; soldest << oldest; try { - pqxx::work W(*conn); query = "SELECT count(*) FROM transactions " - " WHERE patientid = '" + W.esc(patientid) + "' " - " AND macro = '" + W.esc(macroname) + "' " + " WHERE patientid = '" + W->esc(patientid) + "' " + " AND macro = '" + W->esc(macroname) + "' " " AND timestamp >= " + soldest.str() ; PRACRO_DEBUG(sql, "Query: %s\n", query.c_str()); - pqxx::result R = W.exec(query); + pqxx::result R = W->exec(query); if(R.size() != 1) { PRACRO_ERR_LOG(db, "No result set; expected one row with one column\n"); return 0; } unsigned n = (unsigned)atol((*R.begin())[0].c_str()); - PRACRO_DEBUG(db, "Found %u commits for %s(%s) from %ld\n", n, patientid.c_str(), macroname.c_str(), oldest); + PRACRO_DEBUG(db, "Found %u commits for %s(%s) from %ld\n", + n, patientid.c_str(), macroname.c_str(), oldest); return n; } catch (std::exception &e) { PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), query.c_str()); @@ -253,16 +296,15 @@ void PracroDAOPgsql::addFieldname(std::string name, std::string description) std::stringstream timestamp; timestamp << time(NULL); std::string ts; try { - pqxx::work W(*conn); ts = "INSERT INTO fieldnames (name, description, \"timestamp\") VALUES (" - " '" + W.esc(name) + "', " - " '" + W.esc(description) + "', " - " '" + W.esc(timestamp.str()) + "' " + " '" + W->esc(name) + "', " + " '" + W->esc(description) + "', " + " '" + W->esc(timestamp.str()) + "' " ")" ; PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); - pqxx::result R = W.exec(ts); - W.commit(); + pqxx::result R = W->exec(ts); + W->commit(); } catch (std::exception &e) { PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); } @@ -272,12 +314,11 @@ void PracroDAOPgsql::delFieldname(std::string name) { std::string ts; try { - pqxx::work W(*conn); ts = "DELETE FROM fieldnames WHERE name=" - "'" + W.esc(name) + "' "; + "'" + W->esc(name) + "' "; PRACRO_DEBUG(sql, "Query: %s\n", ts.c_str()); - pqxx::result R = W.exec(ts); - W.commit(); + pqxx::result R = W->exec(ts); + W->commit(); } catch (std::exception &e) { PRACRO_ERR_LOG(db, "Query failed: %s: %s\n", e.what(), ts.c_str()); } @@ -290,10 +331,9 @@ std::vector PracroDAOPgsql::getFieldnames() std::string query; try { - pqxx::work W(*conn); query = "SELECT * FROM fieldnames"; PRACRO_DEBUG(sql, "Query: %s\n", query.c_str()); - pqxx::result R = W.exec(query); + pqxx::result R = W->exec(query); pqxx::result::const_iterator ri = R.begin(); while(ri != R.end()) { Fieldname f; @@ -310,6 +350,45 @@ std::vector PracroDAOPgsql::getFieldnames() return fieldnames; } +void PracroDAOPgsql::commit() +{ + std::string ts; + try { + W->commit(); + statements = ""; + } catch (std::exception &e) { + PRACRO_ERR_LOG(db, "Commit failed: %s: %s\n", e.what(), ts.c_str()); + } +} + +void PracroDAOPgsql::discard() +{ + std::string ts; + try { + W->abort(); + statements = ""; + } catch (std::exception &e) { + PRACRO_ERR_LOG(db, "Abort (rollback) failed: %s: %s\n", + e.what(), ts.c_str()); + } +} + +std::string PracroDAOPgsql::serialise() +{ + return statements; +} + +void PracroDAOPgsql::restore(const std::string &data) +{ + std::string ts; + try { + PRACRO_DEBUG(sql, "Restore: %s\n", data.c_str()); + pqxx::result R = W->exec(data); + statements = data; + } catch( ... ) { + } +} + #endif/*WITHOUT_DB*/ #ifdef TEST_PRACRODAOPGSQL @@ -321,7 +400,8 @@ int main() { #ifndef WITHOUT_DB try { - PracroDAOPgsql db(Conf::database_addr, "", Conf::database_user, Conf::database_passwd, ""); + PracroDAOPgsql db(Conf::database_addr, "", Conf::database_user, + Conf::database_passwd, ""); } catch(Exception &e) { printf("ERROR: %s\n", e.what()); return 1; diff --git a/server/src/pracrodaopgsql.h b/server/src/pracrodaopgsql.h index b226cfd..b3e0c86 100644 --- a/server/src/pracrodaopgsql.h +++ b/server/src/pracrodaopgsql.h @@ -32,25 +32,45 @@ #ifndef WITHOUT_DB -#include "pracrodao.h" +#include #include +#include "pracrodao.h" + class PracroDAOPgsql : public PracroDAO { public: - PracroDAOPgsql(std::string _host, std::string _port, std::string _user, std::string _passwd, std::string _dbname); + PracroDAOPgsql(std::string _host, std::string _port, + std::string _user, std::string _passwd, std::string _dbname); ~PracroDAOPgsql(); - void commitTransaction(std::string user, std::string patientid, Macro ¯o, Fields &fields, time_t now); - Values getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest); - unsigned nrOfCommits(std::string patientid, std::string macroname, time_t oldest); + void commitTransaction(std::string user, + std::string patientid, + Macro ¯o, + Fields &fields, + time_t now); + Values getLatestValues(std::string patientid, + Macro *macro, + Fieldnames &fieldnames, + time_t oldest); + unsigned nrOfCommits(std::string patientid, + std::string macroname, + time_t oldest); void addFieldname(std::string name, std::string description); void delFieldname(std::string name); std::vector getFieldnames(); + void commit(); + void discard(); + std::string serialise(); + void restore(const std::string &data); + private: pqxx::connection *conn; + pqxx::work *W; + + std::string statements; }; #endif/*WITHOUT_DB*/ diff --git a/server/src/pracrodaotest.h b/server/src/pracrodaotest.h index 8dd4655..9278b3f 100644 --- a/server/src/pracrodaotest.h +++ b/server/src/pracrodaotest.h @@ -77,14 +77,28 @@ public: PracroDAOTest(Data &data, bool ignore_fieldnames = false); ~PracroDAOTest(); - void commitTransaction(std::string user, std::string patientid, Macro ¯o, Fields &fields, time_t now); - Values getLatestValues(std::string patientid, Macro *macro, Fieldnames &fieldnames, time_t oldest); - unsigned nrOfCommits(std::string patientid, std::string macroname, time_t oldest); + void commitTransaction(std::string user, + std::string patientid, + Macro ¯o, + Fields &fields, + time_t now); + Values getLatestValues(std::string patientid, + Macro *macro, + Fieldnames &fieldnames, + time_t oldest); + unsigned nrOfCommits(std::string patientid, + std::string macroname, + time_t oldest); void addFieldname(std::string name, std::string description); void delFieldname(std::string name); std::vector getFieldnames(); + void commit() {} + void discard() {} + std::string serialise() { return ""; } + void restore(const std::string &data) {} + private: Data data; bool ignore_fieldnames; diff --git a/server/src/saxparser.cc b/server/src/saxparser.cc index f26c965..6861fab 100644 --- a/server/src/saxparser.cc +++ b/server/src/saxparser.cc @@ -79,6 +79,7 @@ SAXParser::SAXParser() return; } + // XML_SetEncoding(p, "UTF-8"); XML_SetUserData(p, this); XML_UseParserAsHandlerArg(p); XML_SetElementHandler(p, start_hndl, end_hndl); diff --git a/server/src/session.cc b/server/src/session.cc index 803a515..e53565b 100644 --- a/server/src/session.cc +++ b/server/src/session.cc @@ -36,6 +36,7 @@ #include #include "journalwriter.h" +#include "database.h" #include "configuration.h" #include "connectionpool.h" #include "sessionserialiser.h" @@ -44,11 +45,13 @@ Session::Session(std::string sessionid) { _id = sessionid; _journal = NULL; + _database = NULL; } Session::~Session() { if(_journal) delete _journal; + if(_database) delete _database; } std::string Session::id() @@ -73,6 +76,11 @@ void Session::commit() delete _journal; _journal = NULL; } + if(_database != NULL) { + _database->commit(); + delete _database; + _database = NULL; + } } void Session::discard() @@ -81,6 +89,11 @@ void Session::discard() delete _journal; _journal = NULL; } + if(_database != NULL) { + _database->discard(); + delete _database; + _database = NULL; + } } JournalWriter *Session::journal() @@ -92,6 +105,16 @@ JournalWriter *Session::journal() return _journal; } +Database *Session::database() +{ + if(_database == NULL) { + _database = + new Database(Conf::database_backend, Conf::database_addr, "", + Conf::database_user, Conf::database_passwd, ""); + } + return _database; +} + Sessions::Sessions() { } diff --git a/server/src/session.h b/server/src/session.h index 6c614c7..cd13aa8 100644 --- a/server/src/session.h +++ b/server/src/session.h @@ -33,6 +33,7 @@ #include "mutex.h" +class Database; class JournalWriter; class Session { @@ -49,9 +50,11 @@ public: void discard(); JournalWriter *journal(); + Database *database(); private: JournalWriter *_journal; + Database *_database; std::string _id; Mutex mutex; }; diff --git a/server/src/sessionparser.cc b/server/src/sessionparser.cc index ba3693d..0edb26a 100644 --- a/server/src/sessionparser.cc +++ b/server/src/sessionparser.cc @@ -34,6 +34,7 @@ SessionParser::SessionParser() done = false; totalbytes = 0; inresume = false; + indatabase = false; } SessionParser::~SessionParser() @@ -45,6 +46,10 @@ void SessionParser::characterData(std::string &data) if(inresume) { entries[entries.size()-1].resume += data; } + + if(indatabase) { + database += data; + } } void SessionParser::startTag(std::string name, @@ -61,6 +66,11 @@ void SessionParser::startTag(std::string name, userid = attributes["userid"]; } + if(name == "database") { + dbtype = attributes["type"]; + indatabase = true; + } + if(name == "entry") { Entry e; e.index = atoi(attributes["index"].c_str()); @@ -78,6 +88,9 @@ void SessionParser::endTag(std::string name) if(name == "resume") { inresume = false; } + if(name == "database") { + indatabase = false; + } } void SessionParser::parseError(const char *buf, size_t len, @@ -87,11 +100,13 @@ void SessionParser::parseError(const char *buf, size_t len, lineno, error.c_str()); std::string xml; - xml.append(buf, len); + if(buf && len) xml.append(buf, len); PRACRO_ERR(sessionparser, "\tBuffer %u bytes: [%s]\n", len, xml.c_str()); + fflush(stderr); + throw std::exception(); } diff --git a/server/src/sessionparser.h b/server/src/sessionparser.h index 37899aa..f364a28 100644 --- a/server/src/sessionparser.h +++ b/server/src/sessionparser.h @@ -47,6 +47,8 @@ public: std::string sessionid; std::string patientid; std::string userid; + std::string database; + std::string dbtype; class Entry { public: @@ -59,6 +61,7 @@ public: private: bool inresume; + bool indatabase; }; #endif/*__PRACRO_SESSIONPARSER_H__*/ diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc index 10d449d..2c35d2a 100644 --- a/server/src/sessionserialiser.cc +++ b/server/src/sessionserialiser.cc @@ -30,6 +30,9 @@ #include "journalwriter.h" #include "sessionparser.h" +#include "database.h" + +#include "xml_encode_decode.h" #include #include @@ -54,19 +57,25 @@ SessionSerialiser::SessionSerialiser(std::string path, Session *session) this->path = path; } +#define XENC(s) xml_encode(s) +#define XDEC(s) xml_decode(s) + void SessionSerialiser::loadStr(const std::string &xml) { // SessionAutolock lock(*session); SessionParser parser; parser.parse(xml.data(), xml.length()); + JournalWriter *j = session->journal(); - j->currentuser = parser.userid; - j->currentcpr = parser.patientid; + j->currentuser = XDEC(parser.userid); + j->currentcpr = XDEC(parser.patientid); std::vector::iterator i = parser.entries.begin(); while(i != parser.entries.end()) { - j->addEntry(i->resume, i->macro, i->index); + j->addEntry(XDEC(i->resume), xml_decode(i->macro), i->index); i++; } + + session->database()->restore(XDEC(parser.database)); } std::string SessionSerialiser::saveStr() @@ -81,8 +90,8 @@ std::string SessionSerialiser::saveStr() JournalWriter *journal = session->journal(); - xml += " currentcpr + - "\" userid=\"" + journal->currentuser + "\">\n"; + xml += " currentcpr) + + "\" userid=\"" + XENC(journal->currentuser) + "\">\n"; std::map< int, JournalWriter::ResumeEntry >::iterator i = journal->entrylist.begin(); @@ -90,13 +99,19 @@ std::string SessionSerialiser::saveStr() xml += " first) + "\"" " macro=\"" + i->second.macro + "\">\n"; - xml += " " + i->second.resume + "\n"; + xml += " " + XENC(i->second.resume) + "\n"; xml += " \n"; i++; } xml += " \n"; + + std::string dbtype = "pgsql"; + xml += " "+ + XENC(session->database()->serialise())+ + "\n"; + xml += "\n"; return xml; diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc index c9c58b6..1658713 100644 --- a/server/src/transactionhandler.cc +++ b/server/src/transactionhandler.cc @@ -54,8 +54,9 @@ static std::string handleCommits(Transaction &transaction, Environment &env, std::string answer; if(transaction.commits.size() > 0) { - AutoBorrower borrower(env.dbpool); - Database *db = borrower.get(); + // AutoBorrower borrower(env.dbpool); + // Database *db = borrower.get(); + Database *db = session.database(); Commits::iterator i = transaction.commits.begin(); while(i != transaction.commits.end()) { @@ -93,8 +94,9 @@ static std::string handleRequest(Transaction &transaction, Environment &env, if(transaction.requests.size() > 0) { - AutoBorrower borrower(env.dbpool); - Database *db = borrower.get(); + // AutoBorrower borrower(env.dbpool); + // Database *db = borrower.get(); + Database *db = session.database(); Requests::iterator i = transaction.requests.begin(); while(i != transaction.requests.end()) { @@ -218,10 +220,25 @@ static std::string handleRequest(Transaction &transaction, Environment &env, } if(completed) { - answer += " "; - answer += xml_encode(db->getResume(transaction.cpr, + std::string jresume = + session.journal()->getEntry(macro.attributes["name"]); + + std::string state = "old"; + std::string resume = db->getResume(transaction.cpr, macro, - time(NULL) - Conf::db_max_ttl)); + time(NULL) - Conf::db_max_ttl); + + if(resume == jresume) state = "new"; + + if(jresume != "" && resume != jresume) { + state = "dirty"; + session.journal()->removeEntry(macro.attributes["name"]); + } + + if(jresume == "" && resume != jresume) state = "old"; + + answer += " "; + answer += xml_encode(resume); answer += "\n"; } diff --git a/server/src/xml_encode_decode.cc b/server/src/xml_encode_decode.cc index 5ed61f2..427e451 100644 --- a/server/src/xml_encode_decode.cc +++ b/server/src/xml_encode_decode.cc @@ -26,7 +26,7 @@ */ #include "xml_encode_decode.h" #include - +/* char xml_map[][2][16] = { { "&", "&" }, // & must be first @@ -36,6 +36,17 @@ char xml_map[][2][16] = { "<", "<" }, { "", "" } // End marker }; +*/ + +char xml_map[][2][16] = + { + { "&", "&" }, // & must be first + { "\'", "'" }, + { "\"", """ }, + { ">", ">" }, + { "<", "<" }, + { "", "" } // End marker + }; #define MAX_MAPS 5 -- cgit v1.2.3