diff options
Diffstat (limited to 'fbreader/src/database/sqldb/implsqlite')
10 files changed, 1210 insertions, 0 deletions
diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteCommand.cpp b/fbreader/src/database/sqldb/implsqlite/SQLiteCommand.cpp new file mode 100644 index 0000000..58d90f6 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteCommand.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <iostream> +#include <algorithm> + +#include <ZLLogger.h> +#include <ZLStringUtil.h> + +#include "SQLiteCommand.h" + +#include "SQLiteConnection.h" +#include "SQLiteDataReader.h" + + +std::string SQLiteCommand::packCommand(const std::string &command) { + static const char _spaces[] = " \t\n"; + std::string stripped = command; + ZLStringUtil::stripWhiteSpaces(stripped); + + std::size_t pos = 0; + while (true) { + pos = stripped.find_first_of(_spaces, pos); + if (pos == std::string::npos) { + break; + } + stripped[pos++] = ' '; + const std::size_t next = stripped.find_first_not_of(_spaces, pos); + if (pos != std::string::npos && next > pos) { + stripped.erase(pos, next - pos); + } + } + return stripped; +} + + +SQLiteCommand::~SQLiteCommand() { + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (con.isOpened() && myStatements.size() != 0) { + finalizeStatements(); + } +} + + +bool SQLiteCommand::execute() { + ZLLogger::Instance().println("sqlite", "execute: " + commandString()); + + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (!con.isOpened()) { + myStatements.clear(); + return false; + } + if (!prepareStatements(con)) { + return false; + } + std::vector<sqlite3_stmt *>::iterator it = myStatements.begin(); + std::vector<sqlite3_stmt *>::iterator end = myStatements.end(); + while (true) { + int res = sqlite3_step(*it); + switch (res) { + case SQLITE_DONE: + if (++it == end) { + resetStatements(); + return true; + } + break; + case SQLITE_OK: + case SQLITE_ROW: + break; + default: + dumpError(); + finalizeStatements(); + return false; + } + } +} + +shared_ptr<DBValue> SQLiteCommand::executeScalar() { + ZLLogger::Instance().println("sqlite", "executeScalar: " + commandString()); + + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (!con.isOpened()) { + myStatements.clear(); + return 0; + } + if (!prepareStatements(con)) { + return 0; + } + std::vector<sqlite3_stmt *>::iterator it = myStatements.begin(); + std::vector<sqlite3_stmt *>::iterator end = myStatements.end(); + while (true) { + int res = sqlite3_step(*it); + switch (res) { + case SQLITE_DONE: + if (++it == end) { + resetStatements(); + return 0; + } + break; + case SQLITE_OK: + break; + case SQLITE_ROW: { + shared_ptr<DBValue> val = SQLiteDataReader::makeDBValue(*it, /* column = */ 0); + resetStatements(); + return val; + } + default: + dumpError(); + finalizeStatements(); + return 0; + } + } +} + +shared_ptr<DBDataReader> SQLiteCommand::executeReader() { + ZLLogger::Instance().println("sqlite", "executeReader: " + commandString()); + + SQLiteConnection &con = (SQLiteConnection &) connection(); + if (!con.isOpened()) { + myStatements.clear(); + return 0; + } + if (!prepareStatements(con)) { + return 0; + } + myLocked = true; + return new SQLiteDataReader(*this); +} + + +bool SQLiteCommand::prepareStatements(SQLiteConnection &conn) { + sqlite3 *db = conn.database(); + if (myLocked) { + return false; + } + if (myStatements.size() != 0) { + const std::size_t size = myStatements.size(); + int res = SQLITE_OK; + for (std::size_t i = 0; i < size && res == SQLITE_OK; ++i) { + res = sqlite3_reset(myStatements[i]); + } + if (res == SQLITE_OK) { + bindParameters(); + return true; + } + finalizeStatements(); + } + const std::string sql = commandString(); + const int length = -1; + const char *tail = sql.c_str(); + while (true) { + sqlite3_stmt *statement; + int res = sqlite3_prepare_v2(db, tail, length, &statement, &tail); + if (res != SQLITE_OK) { + dumpError(); + finalizeStatements(); + return false; + } + if (statement == 0) { + break; + } + myStatements.push_back(statement); + conn.addStatement(statement); + } + if (!bindParameters()) { + finalizeStatements(); + return false; + } + return true; +} + + +void SQLiteCommand::prepareBindContext() { + if (myBindContext.size() > 0) { + return; + } + + std::size_t number = 0; + + for (std::size_t i = 0; i < myStatements.size(); ++i) { + sqlite3_stmt *statement = myStatements[i]; + const int count = sqlite3_bind_parameter_count(statement); + for (int j = 1; j <= count; ++j) { + ++number; + const char *name = sqlite3_bind_parameter_name(statement, j); + if (name == 0) { + myBindContext.push_back(BindParameter(number)); + } else { + const std::string namestr(name); + if (std::find_if(myBindContext.begin(), myBindContext.end(), BindParameterComparator(namestr)) == myBindContext.end()) { + myBindContext.push_back(BindParameter(number, namestr)); + } + } + } + } +} + + +bool SQLiteCommand::bindParameters() { + prepareBindContext(); + + std::vector<DBCommandParameter> ¶ms = parameters(); + + bool res = true; + const std::size_t size = params.size(); + for (std::size_t i = 0; i < size; ++i) { + DBCommandParameter &p = params[i]; + if (p.hasName()) { + const std::string &name = p.name(); + if (!bindParameterByName(name, p.value())) { + res = false; + } + } else if (i < myBindContext.size()) { + BindParameter &bp = myBindContext[i]; + if (myBindContext[i].hasName()) { + if (!bindParameterByName(bp.Name, p.value())) { + res = false; + } + } else { + if (!bindParameterByIndex(bp.Position, p.value())) { + res = false; + } + } + } else { + res = false; + } + } + return res; +} + + +bool SQLiteCommand::bindParameterByName(const std::string &name, shared_ptr<DBValue> value) { + const std::size_t size = myStatements.size(); + bool res = true; + bool binded = false; + for (std::size_t i = 0; i < size; ++i) { + sqlite3_stmt *statement = myStatements[i]; + const int index = sqlite3_bind_parameter_index(statement, name.c_str()); + if (index == 0) { + continue; + } + binded = true; + if (!bindParameter(statement, index, value)) { + res = false; + } + } + if (!binded) { + dumpError("parameter \"" + name + "\" is not found"); + } + return res; +} + +bool SQLiteCommand::bindParameterByIndex(std::size_t index, shared_ptr<DBValue> value) { + if (index == 0) { + return true; + } + const std::size_t size = myStatements.size(); + int number = index; + for (std::size_t i = 0; i < size; ++i) { + sqlite3_stmt *statement = myStatements[i]; + const int count = sqlite3_bind_parameter_count(statement); + if (number > count) { + number -= count; + continue; + } + return bindParameter(statement, number, value); + } + return true; +} + +bool SQLiteCommand::bindParameter(sqlite3_stmt *statement, int number, shared_ptr<DBValue> value) { + DBValue::ValueType type = (value.isNull()) ? (DBValue::DBNULL) : (value->type()); + int res; + switch (type) { + case DBValue::DBNULL: + res = sqlite3_bind_null(statement, number); + break; + case DBValue::DBINT: + res = sqlite3_bind_int(statement, number, ((DBIntValue &) *value).value()); + break; + case DBValue::DBREAL: + res = sqlite3_bind_double(statement, number, ((DBRealValue &) *value).value()); + break; + case DBValue::DBTEXT: + res = sqlite3_bind_text(statement, number, ((DBTextValue &) *value).value().c_str(), -1 /* zero-terminated string */, SQLITE_TRANSIENT); + break; + default: + return false; + } + if (res != SQLITE_OK) { + dumpError(); + } + return res == SQLITE_OK; +} + + +void SQLiteCommand::finalizeStatements() { + SQLiteConnection &con = (SQLiteConnection &) connection(); + const std::size_t size = myStatements.size(); + for (std::size_t i = 0; i < size; ++i) { + sqlite3_stmt *statement = myStatements[i]; + con.removeStatement(statement); + const int res = sqlite3_finalize(statement); + if (res != SQLITE_OK) { + dumpError(); + } + } + myStatements.clear(); +} + + +void SQLiteCommand::dumpError() const { + static const std::size_t cmdlimit = 114; + ((SQLiteConnection &) connection()).dumpError(); + const std::string &cmd = commandString(); + if (cmd.length() > cmdlimit) { + std::cerr << "SQLITE IMPLEMENTATION ERROR: in command \"" << cmd.substr(0, cmdlimit - 3) << "...\"" << std::endl; + } else { + std::cerr << "SQLITE IMPLEMENTATION ERROR: in command \"" << cmd << "\"" << std::endl; + } +} + +void SQLiteCommand::dumpError(const std::string &msg) const { + static const std::size_t cmdlimit = 129; + std::cerr << "SQLITE ERROR: " << msg << std::endl; + const std::string &cmd = commandString(); + if (cmd.length() > cmdlimit) { + std::cerr << "SQLITE ERROR: in command \"" << cmd.substr(0, cmdlimit - 3) << "...\"" << std::endl; + } else { + std::cerr << "SQLITE ERROR: in command \"" << cmd << "\"" << std::endl; + } +} + +bool SQLiteCommand::resetStatements() { + if (myStatements.size() == 0) { + return true; + } + const std::size_t size = myStatements.size(); + int res = SQLITE_OK; + for (std::size_t i = 0; i < size && res == SQLITE_OK; ++i) { + res = sqlite3_reset(myStatements[i]); + } + if (res == SQLITE_OK) { + return true; + } + dumpError(); + finalizeStatements(); + return false; +} + diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteCommand.h b/fbreader/src/database/sqldb/implsqlite/SQLiteCommand.h new file mode 100644 index 0000000..395fd30 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteCommand.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#ifndef __SQLITECOMMAND_H__ +#define __SQLITECOMMAND_H__ + +#include <sqlite3.h> + +#include "../DBCommand.h" + +#include "SQLiteConnection.h" + + +/* + * Command can contain parameters with following names: + * ? - anonymous parameter + * @AAA - named parameter + * + * where AAA is alpha-numeric parameter name + */ +class SQLiteCommand : public DBCommand { + +public: + static std::string packCommand(const std::string &command); + +public: + SQLiteCommand(const std::string &command, DBConnection &connection); + ~SQLiteCommand(); + + bool execute(); + shared_ptr<DBValue> executeScalar(); + shared_ptr<DBDataReader> executeReader(); + +public: + void unlock(); + + // TODO: hide sqlite3_stmt object inside + std::vector<sqlite3_stmt *> &statements(); + const std::vector<sqlite3_stmt *> &statements() const; + + void dumpError() const; + void dumpError(const std::string &msg) const; + + bool resetStatements(); + +private: + + struct BindParameter { + std::size_t Position; + std::string Name; + + BindParameter(std::size_t pos) : Position(pos), Name("") {} + BindParameter(std::size_t pos, const std::string &name) : Position(pos), Name(name) {} + + bool hasName() const; + }; + + class BindParameterComparator { + + public: + BindParameterComparator(const std::string &name); + bool operator () (const SQLiteCommand::BindParameter &p) const; + + private: + const std::string myName; + }; + + void prepareBindContext(); + bool bindParameters(); + bool bindParameterByName(const std::string &name, shared_ptr<DBValue> value); + bool bindParameterByIndex(std::size_t index, shared_ptr<DBValue> value); + bool bindParameter(sqlite3_stmt *statement, int number, shared_ptr<DBValue> value); + bool prepareStatements(SQLiteConnection &conn); + + void finalizeStatements(); + +private: + std::vector<sqlite3_stmt *> myStatements; + std::vector<BindParameter> myBindContext; + bool myLocked; + +private: // disable copying: + SQLiteCommand(const SQLiteCommand &); + const SQLiteCommand &operator = (const SQLiteCommand &); +}; + + +inline SQLiteCommand::SQLiteCommand(const std::string &command, DBConnection &connection) + : DBCommand(SQLiteCommand::packCommand(command), connection), myStatements(), myLocked(false) {} + +inline void SQLiteCommand::unlock() { myLocked = false; } +inline std::vector<sqlite3_stmt *> &SQLiteCommand::statements() { return myStatements; } +inline const std::vector<sqlite3_stmt *> &SQLiteCommand::statements() const { return myStatements; } + +inline bool SQLiteCommand::BindParameter::hasName() const { return Name.size() > 0; } + +inline SQLiteCommand::BindParameterComparator::BindParameterComparator(const std::string &name) : myName(name) {} +inline bool SQLiteCommand::BindParameterComparator::operator () (const SQLiteCommand::BindParameter &p) const { return myName == p.Name; } + +#endif /* __SQLITECOMMAND_H__ */ diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteConnection.cpp b/fbreader/src/database/sqldb/implsqlite/SQLiteConnection.cpp new file mode 100644 index 0000000..f1a0f30 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteConnection.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <iostream> + +#include "SQLiteConnection.h" + +SQLiteConnection::SQLiteConnection(const std::string &name) + : DBConnection() + , myName(name) + , myDatabase(0) { +} + +SQLiteConnection::~SQLiteConnection() { + if (isOpened()) { + close(); + } +} + + +bool SQLiteConnection::open() { + if (myDatabase != 0) { + return true; + } + int res = sqlite3_open(myName.c_str(), &myDatabase); + if (res == SQLITE_OK) { + return true; + } + dumpError(); + if (myDatabase != 0) { + sqlite3_close(myDatabase); + myDatabase = 0; + } + return false; +} + +void SQLiteConnection::finalizeOpenedStatements() { + std::size_t size = myStatements.size(); + for (std::size_t i = 0; i < size; ++i) { + const int res = sqlite3_finalize(myStatements[i]); + if (res != SQLITE_OK) { + dumpError(); + } + } + myStatements.clear(); +} + +bool SQLiteConnection::close() { + if (myDatabase == 0) { + return true; + } + + finalizeOpenedStatements(); + + int res = sqlite3_close(myDatabase); + if (res == SQLITE_OK) { + myDatabase = 0; + return true; + } + dumpError(); + return false; +} + +void SQLiteConnection::dumpError() const { + if (myDatabase != 0) { + const std::string msg = sqlite3_errmsg(myDatabase); // TODO: error & message handling + const int code = sqlite3_errcode(myDatabase); // TODO: error & message handling + std::cerr << "SQLITE IMPLEMENTATION ERROR: (" << code << ") " << msg << std::endl; + } +} diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteConnection.h b/fbreader/src/database/sqldb/implsqlite/SQLiteConnection.h new file mode 100644 index 0000000..6854800 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteConnection.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __SQLITECONNECTION_H__ +#define __SQLITECONNECTION_H__ + +#include <sqlite3.h> + +#include <algorithm> +#include <vector> +#include <string> + +#include "../DBConnection.h" + +class SQLiteConnection : public DBConnection { + +public: + SQLiteConnection(const std::string &name); + ~SQLiteConnection(); + + bool open(); + bool close(); + bool isOpened() const; + +public: + const std::string &name() const; + + sqlite3 *database(); // TODO: hide sqlite3 object inside + + void addStatement(sqlite3_stmt *statement); + void removeStatement(sqlite3_stmt *statement); + +public: + void dumpError() const; + +private: + void finalizeOpenedStatements(); + +private: + const std::string myName; + sqlite3 *myDatabase; + std::vector<sqlite3_stmt *> myStatements; + +private: // disable copying: + SQLiteConnection(const SQLiteConnection &); + const SQLiteConnection &operator = (const SQLiteConnection &); +}; + + +inline const std::string &SQLiteConnection::name() const { return myName; } +inline sqlite3 *SQLiteConnection::database() { return myDatabase; } + +inline void SQLiteConnection::addStatement(sqlite3_stmt *statement) { myStatements.push_back(statement); } + +inline void SQLiteConnection::removeStatement(sqlite3_stmt *statement) { + std::vector<sqlite3_stmt *>::iterator it = std::find(myStatements.begin(), myStatements.end(), statement); + if (it != myStatements.end()) { + myStatements.erase(it); + } +} + +inline bool SQLiteConnection::isOpened() const { return myDatabase != 0; } + + +#endif /* __SQLITECONNECTION_H__ */ diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteDataBase.cpp b/fbreader/src/database/sqldb/implsqlite/SQLiteDataBase.cpp new file mode 100644 index 0000000..1cccc0a --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteDataBase.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include <ZLStringUtil.h> + +#include "SQLiteDataBase.h" + +#include "SQLiteConnection.h" +#include "SQLiteCommand.h" + +//----------- Transaction subclass ----------------- + +SQLiteDataBase::Transaction::Transaction(SQLiteDataBase &db) : myDataBase(db), mySuccess(false), myStarted(false), myDepth((unsigned int)-1) { +} + +SQLiteDataBase::Transaction::~Transaction() { + if (myStarted) { + end(mySuccess); + } +} + +bool SQLiteDataBase::Transaction::start() { + myDepth = myDataBase.myTransactionDepth; + if (myDepth == 0) { + myStarted = myDataBase.myBeginTransaction->execute(); + } else { + //((DBTextValue &) *myDataBase.myMakeSavePoint->parameter("@name").value()).setValue(name()); + //myStarted = myDataBase.myMakeSavePoint->execute(); + myStarted = true; + } + if (myStarted) { + ++myDataBase.myTransactionDepth; + } + return myStarted; +} + +void SQLiteDataBase::Transaction::end(bool success) { + --myDataBase.myTransactionDepth; + if (myDepth == 0) { + if (success) { + myDataBase.myCommitTransaction->execute(); + } else { + myDataBase.myRollbackTransaction->execute(); + } + } else { + if (success) { + //((DBTextValue &) *myDataBase.myCommitSavePoint->parameter("@name").value()).setValue(name()); + //myDataBase.myCommitSavePoint->execute(); + } else { + //((DBTextValue &) *myDataBase.myRollbackSavePoint->parameter("@name").value()).setValue(name()); + //myDataBase.myRollbackSavePoint->execute(); + } + } +} + +std::string SQLiteDataBase::Transaction::name() const { + std::string name = "tran"; + ZLStringUtil::appendNumber(name, myDepth); + return name; +} + +//----------- End Transaction subclass ----------------- + + + +SQLiteDataBase::SQLiteDataBase(const std::string &path) : DataBase( new SQLiteConnection(path) ), myTransactionDepth(0) { + myBeginTransaction = SQLiteFactory::createCommand("BEGIN IMMEDIATE TRANSACTION", connection()); + myCommitTransaction = SQLiteFactory::createCommand("COMMIT TRANSACTION", connection()); + myRollbackTransaction = SQLiteFactory::createCommand("ROLLBACK TRANSACTION", connection()); + myMakeSavePoint = SQLiteFactory::createCommand("SAVEPOINT @name", connection(), "@name", DBValue::DBTEXT); + myCommitSavePoint = SQLiteFactory::createCommand("RELEASE @name", connection(), "@name", DBValue::DBTEXT); + myRollbackSavePoint = SQLiteFactory::createCommand("ROLLBACK TO @name; RELEASE @name", connection(), "@name", DBValue::DBTEXT); +} + +SQLiteDataBase::~SQLiteDataBase() { + if (connection().isOpened()) { + connection().close(); + } +} + +bool SQLiteDataBase::executeAsTransaction(DBRunnable &runnable) { + Transaction tran(*this); + if (tran.start() && runnable.run()) { + tran.setSuccessful(); + return true; + } + return false; +} + + diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteDataBase.h b/fbreader/src/database/sqldb/implsqlite/SQLiteDataBase.h new file mode 100644 index 0000000..dce8e5b --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteDataBase.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#ifndef __SQLITEDATABASE_H__ +#define __SQLITEDATABASE_H__ + +#include "../DataBase.h" +#include "../DBCommand.h" + +#include "SQLiteFactory.h" + + +class SQLiteDataBase : public DataBase { + +public: + SQLiteDataBase(const std::string &path); + virtual ~SQLiteDataBase(); + + bool open(); + void close(); + +public: + bool executeAsTransaction(DBRunnable &runnable); + +private: + friend class Transaction; + + class Transaction { + public: + Transaction(SQLiteDataBase &db); + ~Transaction(); + public: + bool start(); + void setSuccessful(); + private: + void end(bool success); + std::string name() const; + private: + SQLiteDataBase &myDataBase; + bool mySuccess; + bool myStarted; + unsigned int myDepth; + }; + +private: // Transaction handling + unsigned int myTransactionDepth; + shared_ptr<DBCommand> myBeginTransaction; + shared_ptr<DBCommand> myCommitTransaction; + shared_ptr<DBCommand> myRollbackTransaction; + shared_ptr<DBCommand> myMakeSavePoint; + shared_ptr<DBCommand> myCommitSavePoint; + shared_ptr<DBCommand> myRollbackSavePoint; + +private: // disable copying: + SQLiteDataBase(const SQLiteDataBase &); + const SQLiteDataBase &operator = (const SQLiteDataBase &); +}; + +inline bool SQLiteDataBase::open() { return connection().open(); } +inline void SQLiteDataBase::close() { connection().close(); } + +inline void SQLiteDataBase::Transaction::setSuccessful() { mySuccess = true; } + + +#endif /* __SQLITEDATABASE_H__ */ diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteDataReader.cpp b/fbreader/src/database/sqldb/implsqlite/SQLiteDataReader.cpp new file mode 100644 index 0000000..3ea4091 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteDataReader.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "SQLiteDataReader.h" + +shared_ptr<DBValue> SQLiteDataReader::makeDBValue(sqlite3_stmt *statement, std::size_t column) { + if (column >= (std::size_t) sqlite3_column_count(statement)) { + return 0; + } + const int type = sqlite3_column_type(statement, column); + switch (type) { + case SQLITE_INTEGER: return new DBIntValue(sqlite3_column_int(statement, column)); + case SQLITE_FLOAT: return new DBRealValue(sqlite3_column_double(statement, column)); + case SQLITE_TEXT: return new DBTextValue((const char *) sqlite3_column_text(statement, column)); + case SQLITE_NULL: return DBValue::create(DBValue::DBNULL); + } + return 0; +} + +SQLiteDataReader::SQLiteDataReader(SQLiteCommand &command) : + myCommand(command), + myCurrentStatement(0), + myLocked(true) { +} + +SQLiteDataReader::~SQLiteDataReader() { + close(); +} + +bool SQLiteDataReader::next() { + const std::vector<sqlite3_stmt *> &statements = myCommand.statements(); + while (true) { + int res = sqlite3_step(statements[myCurrentStatement]); + switch (res) { + case SQLITE_OK: + break; + case SQLITE_ROW: + return true; + case SQLITE_DONE: + if (++myCurrentStatement >= statements.size()) { + return false; + } + break; + default: + myCommand.dumpError(); + return false; + } + } +} + +bool SQLiteDataReader::reset() { + return myCommand.resetStatements(); +} + +void SQLiteDataReader::close() { + if (myLocked) { + reset(); + myCommand.unlock(); + myLocked = false; + } +} + +std::size_t SQLiteDataReader::columnsNumber() const { + sqlite3_stmt *statement = currentStatement(); + return sqlite3_column_count(statement); +} + +DBValue::ValueType SQLiteDataReader::type(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + if (column >= (std::size_t) sqlite3_column_count(statement)) { + return DBValue::DBNULL; + } + const int type = sqlite3_column_type(statement, column); + switch (type) { + case SQLITE_INTEGER: return DBValue::DBINT; + case SQLITE_FLOAT: return DBValue::DBREAL; + case SQLITE_TEXT: return DBValue::DBTEXT; + case SQLITE_NULL: return DBValue::DBNULL; + default: + return DBValue::DBNULL; + } +} + +shared_ptr<DBValue> SQLiteDataReader::value(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + return makeDBValue(statement, column); +} + +int SQLiteDataReader::intValue(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + if (column >= (std::size_t)sqlite3_column_count(statement) || + sqlite3_column_type(statement, column) != SQLITE_INTEGER) { + return 0; + } + return sqlite3_column_int(statement, column); +} + +double SQLiteDataReader::realValue(std::size_t column) const { + sqlite3_stmt *statement = currentStatement(); + if (column >= (std::size_t)sqlite3_column_count(statement) || + sqlite3_column_type(statement, column) != SQLITE_FLOAT) { + return 0; + } + return sqlite3_column_double(statement, column); +} + +std::string SQLiteDataReader::textValue(std::size_t column, const std::string &defaultValue) const { + sqlite3_stmt *statement = currentStatement(); + if (column < (std::size_t)sqlite3_column_count(statement) && + sqlite3_column_type(statement, column) == SQLITE_TEXT) { + const char *result = (const char*)sqlite3_column_text(statement, column); + if (result != 0) { + return result; + } + } + return defaultValue; +} diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteDataReader.h b/fbreader/src/database/sqldb/implsqlite/SQLiteDataReader.h new file mode 100644 index 0000000..b220b39 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteDataReader.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#ifndef __SQLITEDATAREADER_H__ +#define __SQLITEDATAREADER_H__ + +#include "../DBDataReader.h" + +#include "SQLiteCommand.h" +#include "SQLiteConnection.h" + +class SQLiteDataReader : public DBDataReader { + +public: + static shared_ptr<DBValue> makeDBValue(sqlite3_stmt *statement, std::size_t column); + +public: + SQLiteDataReader(SQLiteCommand &command); + ~SQLiteDataReader(); + + bool next(); + bool reset(); + void close(); + + std::size_t columnsNumber() const; + + DBValue::ValueType type(std::size_t column) const; + + shared_ptr<DBValue> value(std::size_t column) const; + + int intValue(std::size_t column) const; + double realValue(std::size_t column) const; + std::string textValue(std::size_t column, const std::string &defaultValue) const; + +private: + sqlite3_stmt *currentStatement() const; + +private: + SQLiteCommand &myCommand; + std::size_t myCurrentStatement; + bool myLocked; +}; + + +inline sqlite3_stmt *SQLiteDataReader::currentStatement() const { return myCommand.statements()[myCurrentStatement]; } + +#endif /* __SQLITEDATAREADER_H__ */ diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteFactory.cpp b/fbreader/src/database/sqldb/implsqlite/SQLiteFactory.cpp new file mode 100644 index 0000000..5054cc9 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteFactory.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include "SQLiteFactory.h" + +#include "SQLiteCommand.h" + + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection) { + return new SQLiteCommand(command, connection); +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, + const std::string &name4, DBValue::ValueType type4) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + cmd->parameters().push_back( DBCommandParameter(name4, type4) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, + const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + cmd->parameters().push_back( DBCommandParameter(name4, type4) ); + cmd->parameters().push_back( DBCommandParameter(name5, type5) ); + + return cmd; +} + +shared_ptr<DBCommand> SQLiteFactory::createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, + const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, + const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5, + const std::string &name6, DBValue::ValueType type6) { + + shared_ptr<DBCommand> cmd = createCommand(command, connection); + cmd->parameters().push_back( DBCommandParameter(name1, type1) ); + cmd->parameters().push_back( DBCommandParameter(name2, type2) ); + cmd->parameters().push_back( DBCommandParameter(name3, type3) ); + cmd->parameters().push_back( DBCommandParameter(name4, type4) ); + cmd->parameters().push_back( DBCommandParameter(name5, type5) ); + cmd->parameters().push_back( DBCommandParameter(name6, type6) ); + + return cmd; +} + diff --git a/fbreader/src/database/sqldb/implsqlite/SQLiteFactory.h b/fbreader/src/database/sqldb/implsqlite/SQLiteFactory.h new file mode 100644 index 0000000..b58b785 --- /dev/null +++ b/fbreader/src/database/sqldb/implsqlite/SQLiteFactory.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#ifndef __SQLITEFACTORY_H__ +#define __SQLITEFACTORY_H__ + +#include "../DBConnection.h" +#include "../DBCommand.h" + +class SQLiteFactory { + +private: + SQLiteFactory(); + +public: + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, const std::string &name4, DBValue::ValueType type4); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5); + + static shared_ptr<DBCommand> createCommand(const std::string &command, DBConnection &connection, + const std::string &name1, DBValue::ValueType type1, const std::string &name2, DBValue::ValueType type2, + const std::string &name3, DBValue::ValueType type3, const std::string &name4, DBValue::ValueType type4, + const std::string &name5, DBValue::ValueType type5, const std::string &name6, DBValue::ValueType type6); +}; + + +#endif /* __SQLITEFACTORY_H__ */ |