diff options
Diffstat (limited to 'fbreader/src/database')
58 files changed, 5612 insertions, 0 deletions
diff --git a/fbreader/src/database/booksdb/BooksDB.cpp b/fbreader/src/database/booksdb/BooksDB.cpp new file mode 100644 index 0000000..bf6d2b3 --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDB.cpp @@ -0,0 +1,503 @@ +/* + * 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 <ZLibrary.h> +#include <ZLFile.h> +#include <ZLDir.h> +#include <ZLLanguageUtil.h> + +#include "BooksDB.h" +#include "BooksDBQuery.h" + +#include "../../library/Book.h" +#include "../../library/Author.h" +#include "../../library/Tag.h" + +#include "../sqldb/implsqlite/SQLiteFactory.h" + +shared_ptr<BooksDB> BooksDB::ourInstance = 0; + +const std::string BooksDB::DATABASE_NAME = "books.db"; +const std::string BooksDB::STATE_DATABASE_NAME = "state.db"; + +BooksDB &BooksDB::Instance() { + if (ourInstance.isNull()) { + ZLFile dir(databaseDirName()); + dir.directory(true); + ZLFile file(databaseDirName() + ZLibrary::FileNameDelimiter + DATABASE_NAME); + ourInstance = new BooksDB(file.physicalFilePath()); + ourInstance->initDatabase(); + } + return *ourInstance; +} + +BooksDB::BooksDB(const std::string &path) : SQLiteDataBase(path), myInitialized(false) { + initCommands(); +} + +BooksDB::~BooksDB() { +} + +bool BooksDB::initDatabase() { + if (isInitialized()) { + return true; + } + + if (!open()) { + return false; + } + + myInitialized = true; + + ZLFile stateFile(databaseDirName() + ZLibrary::FileNameDelimiter + STATE_DATABASE_NAME); + shared_ptr<DBCommand> cmd = SQLiteFactory::createCommand(BooksDBQuery::PREINIT_DATABASE, connection(), "@stateFile", DBValue::DBTEXT); + ((DBTextValue&)*cmd->parameter("@stateFile").value()) = stateFile.physicalFilePath(); + if (!cmd->execute()) { + myInitialized = false; + close(); + return false; + } + + shared_ptr<DBRunnable> runnable = new InitBooksDBRunnable(connection()); + if (!executeAsTransaction(*runnable)) { + myInitialized = false; + close(); + return false; + } + + return true; +} + +void BooksDB::initCommands() { + myLoadBook = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOK, connection(), "@file_id", DBValue::DBINT); + myGetFileSize = SQLiteFactory::createCommand(BooksDBQuery::GET_FILE_SIZE, connection(), "@file_id", DBValue::DBINT); + mySetFileSize = SQLiteFactory::createCommand(BooksDBQuery::SET_FILE_SIZE, connection(), "@file_id", DBValue::DBINT, "@size", DBValue::DBINT); + myFindFileName = SQLiteFactory::createCommand(BooksDBQuery::FIND_FILE_NAME, connection(), "@file_id", DBValue::DBINT); + myFindAuthorId = SQLiteFactory::createCommand(BooksDBQuery::FIND_AUTHOR_ID, connection(), "@name", DBValue::DBTEXT, "@sort_key", DBValue::DBTEXT); + + myLoadBooks = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOKS, connection()); + + myLoadBookStateStack = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOK_STATE_STACK, connection(), "@book_id", DBValue::DBINT); + + myGetPalmType = SQLiteFactory::createCommand(BooksDBQuery::GET_PALM_TYPE, connection(), "@file_id", DBValue::DBINT); + mySetPalmType = SQLiteFactory::createCommand(BooksDBQuery::SET_PALM_TYPE, connection(), "@file_id", DBValue::DBINT, "@type", DBValue::DBTEXT); + + myLoadStackPos = SQLiteFactory::createCommand(BooksDBQuery::LOAD_STACK_POS, connection(), "@book_id", DBValue::DBINT); + mySetStackPos = SQLiteFactory::createCommand(BooksDBQuery::SET_STACK_POS, connection(), "@book_id", DBValue::DBINT, "@stack_pos", DBValue::DBINT); + + myLoadBookState = SQLiteFactory::createCommand(BooksDBQuery::LOAD_BOOK_STATE, connection(), "@book_id", DBValue::DBINT); + mySetBookState = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOK_STATE, connection(), "@book_id", DBValue::DBINT, "@paragraph", DBValue::DBINT, "@word", DBValue::DBINT, "@char", DBValue::DBINT); + + myInsertBookList = SQLiteFactory::createCommand(BooksDBQuery::INSERT_BOOK_LIST, connection(), "@book_id", DBValue::DBINT); + myDeleteBookList = SQLiteFactory::createCommand(BooksDBQuery::DELETE_BOOK_LIST, connection(), "@book_id", DBValue::DBINT); + myCheckBookList = SQLiteFactory::createCommand(BooksDBQuery::CHECK_BOOK_LIST, connection(), "@book_id", DBValue::DBINT); + + mySaveTableBook = new SaveTableBookRunnable(connection()); + mySaveAuthors = new SaveAuthorsRunnable(connection()); + mySaveSeries = new SaveSeriesRunnable(connection()); + mySaveTags = new SaveTagsRunnable(connection()); + mySaveBook = new SaveBookRunnable(*mySaveTableBook, *mySaveAuthors, *mySaveSeries, *mySaveTags); + mySaveFileEntries = new SaveFileEntriesRunnable(connection()); + + myFindFileId = new FindFileIdRunnable(connection()); + + myLoadFileEntries = new LoadFileEntriesRunnable(connection()); + + myLoadRecentBooks = new LoadRecentBooksRunnable(connection()); + mySaveRecentBooks = new SaveRecentBooksRunnable(connection()); + + mySaveBookStateStack = new SaveBookStateStackRunnable(connection()); + + myDeleteBook = new DeleteBookRunnable(connection()); +} + +bool BooksDB::clearDatabase() { + if (!isInitialized()) { + return false; + } + shared_ptr<DBRunnable> runnable = new ClearBooksDBRunnable(connection()); + return executeAsTransaction(*runnable); +} + +shared_ptr<Book> BooksDB::loadBook(const std::string &fileName) { + if (!isInitialized()) { + return 0; + } + + myFindFileId->setFileName(fileName); + if (!myFindFileId->run()) { + return 0; + } + ((DBIntValue&)*myLoadBook->parameter("@file_id").value()) = myFindFileId->fileId(); + shared_ptr<DBDataReader> reader = myLoadBook->executeReader(); + + if (reader.isNull() || !reader->next() || + reader->type(0) != DBValue::DBINT /* book_id */) { + return 0; + } + const int bookId = reader->intValue(0); + + shared_ptr<Book> book = Book::createBook( + ZLFile(fileName), bookId, + reader->textValue(1, Book::AutoEncoding), + reader->textValue(2, ZLLanguageUtil::OtherLanguageCode), + reader->textValue(3, std::string()) + ); + + loadSeries(*book); + loadAuthors(*book); + loadTags(*book); + + return book; +} + + +bool BooksDB::saveBook(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveBook->setBook(book); + return executeAsTransaction(*mySaveBook); +} + +bool BooksDB::saveAuthors(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveAuthors->setBook(book); + return executeAsTransaction(*mySaveAuthors); +} + +bool BooksDB::saveSeries(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveSeries->setBook(book); + return executeAsTransaction(*mySaveSeries); +} + +bool BooksDB::saveTags(const shared_ptr<Book> book) { + if (!isInitialized()) { + return false; + } + mySaveTags->setBook(book); + return executeAsTransaction(*mySaveTags); +} + +int BooksDB::getFileSize(const std::string fileName) { + if (!isInitialized()) { + return -1; + } + myFindFileId->setFileName(fileName); + if (!myFindFileId->run()) { + return 0; + } + ((DBIntValue&)*myGetFileSize->parameter("@file_id").value()) = myFindFileId->fileId(); + + shared_ptr<DBValue> fileSize = myGetFileSize->executeScalar(); + + if (fileSize.isNull()) { + return -1; + } + if (fileSize->type() == DBValue::DBNULL) { + return 0; + } + if (fileSize->type() != DBValue::DBINT) { + return -1; + } + return ((DBIntValue&)*fileSize).value(); +} + +bool BooksDB::setFileSize(const std::string fileName, int size) { + if (!isInitialized()) { + return false; + } + myFindFileId->setFileName(fileName, true); + if (!executeAsTransaction(*myFindFileId)) { + return false; + } + ((DBIntValue&)*mySetFileSize->parameter("@file_id").value()) = myFindFileId->fileId(); + ((DBIntValue&)*mySetFileSize->parameter("@size").value()) = size; + return mySetFileSize->execute(); +} + +bool BooksDB::setEncoding(const Book &book, const std::string &encoding) { + if (!isInitialized()) { + return false; + } + + shared_ptr<DBCommand> command = SQLiteFactory::createCommand(BooksDBQuery::SET_ENCODING, connection()); + + command->parameters().push_back(DBCommandParameter("@book_id", new DBIntValue(book.bookId()))); + command->parameters().push_back(DBCommandParameter("@encoding", new DBTextValue(encoding))); + + return command->execute(); +} + +bool BooksDB::loadFileEntries(const std::string &fileName, std::vector<std::string> &entries) { + myLoadFileEntries->setFileName(fileName); + if (!myLoadFileEntries->run()) { + return false; + } + myLoadFileEntries->collectEntries(entries); + return true; +} + +bool BooksDB::saveFileEntries(const std::string &fileName, const std::vector<std::string> &entries) { + if (!isInitialized()) { + return false; + } + mySaveFileEntries->setEntries(fileName, entries); + return executeAsTransaction(*mySaveFileEntries); +} + +bool BooksDB::loadRecentBooks(std::vector<std::string> &fileNames) { + std::vector<int> fileIds; + if (!myLoadRecentBooks->run()) { + return false; + } + myLoadRecentBooks->collectFileIds(fileIds); + for (std::vector<int>::const_iterator it = fileIds.begin(); it != fileIds.end(); ++it) { + const int fileId = *it; + const std::string fileName = getFileName(fileId); + fileNames.push_back(fileName); + } + return true; +} + +bool BooksDB::saveRecentBooks(const BookList &books) { + if (!isInitialized()) { + return false; + } + mySaveRecentBooks->setBooks(books); + return executeAsTransaction(*mySaveRecentBooks); +} + +std::string BooksDB::getFileName(int fileId) { + std::string fileName; + DBIntValue &findFileId = (DBIntValue&)*myFindFileName->parameter("@file_id").value(); + findFileId = fileId; + while (true) { + shared_ptr<DBDataReader> reader = myFindFileName->executeReader(); + if (reader.isNull() || !reader->next()) { + return std::string(); + } + const std::string namePart = reader->textValue(0, std::string()); + switch (reader->type(1)) { /* parent_id */ + default: + return std::string(); + case DBValue::DBNULL: + return namePart + ZLibrary::FileNameDelimiter + fileName; + case DBValue::DBINT: + if (fileName.empty()) { + fileName = namePart; + } else { + fileName = namePart + BooksDBQuery::ArchiveEntryDelimiter + fileName; + } + findFileId = reader->intValue(1); + break; + } + } +} + +bool BooksDB::loadBooks(BookList &books) { + shared_ptr<DBDataReader> reader = myLoadBooks->executeReader(); + + books.clear(); + std::map<int,shared_ptr<Book> > bookMap; + + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT || /* book_id */ + reader->type(4) != DBValue::DBINT) { /* file_id */ + return false; + } + const int bookId = reader->intValue(0); + const int fileId = reader->intValue(4); + const std::string fileName = getFileName(fileId); + + shared_ptr<Book> book = Book::createBook( + ZLFile(fileName), + bookId, + reader->textValue(1, Book::AutoEncoding), + reader->textValue(2, ZLLanguageUtil::OtherLanguageCode), + reader->textValue(3, std::string()) + ); + books.push_back(book); + bookMap[bookId] = book; + } + + loadSeries(bookMap); + loadAuthors(bookMap); + loadTags(bookMap); + + return true; +} + +bool BooksDB::loadBookStateStack(const Book &book, std::deque<ReadingState> &stack) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myLoadBookStateStack->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = myLoadBookStateStack->executeReader(); + if (reader.isNull()) { + return false; + } + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT /* paragraph */ + || reader->type(1) != DBValue::DBINT /* word */ + || reader->type(2) != DBValue::DBINT /* char */) { + return false; + } + const int paragraph = reader->intValue(0); + const int word = reader->intValue(1); + const int character = reader->intValue(2); + stack.push_back(ReadingState(paragraph, word, character)); + } + return true; +} + +bool BooksDB::saveBookStateStack(const Book &book, const std::deque<ReadingState> &stack) { + if (!isInitialized() || book.bookId() == 0) { + return false; + } + mySaveBookStateStack->setState(book.bookId(), stack); + return executeAsTransaction(*mySaveBookStateStack); +} + + +bool BooksDB::removeBook(const Book &book) { + if (!isInitialized() || book.bookId() == 0) { + return false; + } + myDeleteBook->setFileName(book.file().path()); + return executeAsTransaction(*myDeleteBook); +} + +std::string BooksDB::getPalmType(const std::string &fileName) { + if (!isInitialized()) { + return ""; + } + myFindFileId->setFileName(fileName); + if (!myFindFileId->run()) { + return ""; + } + ((DBIntValue&)*myGetPalmType->parameter("@file_id").value()) = myFindFileId->fileId(); + shared_ptr<DBValue> value = myGetPalmType->executeScalar(); + if (value.isNull() || value->type() != DBValue::DBTEXT) { + return ""; + } + return ((DBTextValue&)*value).value(); +} + +bool BooksDB::setPalmType(const std::string &fileName, const std::string &type) { + if (!isInitialized()) { + return false; + } + myFindFileId->setFileName(fileName, true); + if (!myFindFileId->run()) { + return ""; + } + ((DBIntValue&)*mySetPalmType->parameter("@file_id").value()) = myFindFileId->fileId(); + ((DBTextValue&)*mySetPalmType->parameter("@type").value()) = type; + return mySetPalmType->execute(); +} + +bool BooksDB::loadBookState(const Book &book, ReadingState &state) { + state.Paragraph = state.Word = state.Character = 0; + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myLoadBookState->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = myLoadBookState->executeReader(); + if (reader.isNull()) { + return false; + } + if (!reader->next() + || reader->type(0) != DBValue::DBINT /* paragraph */ + || reader->type(1) != DBValue::DBINT /* word */ + || reader->type(2) != DBValue::DBINT /* char */) { + return false; + } + state.Paragraph = reader->intValue(0); + state.Word = reader->intValue(1); + state.Character = reader->intValue(2); + return true; +} + +bool BooksDB::setBookState(const Book &book, const ReadingState &state) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*mySetBookState->parameter("@book_id").value()) = book.bookId(); + ((DBIntValue&)*mySetBookState->parameter("@paragraph").value()) = state.Paragraph; + ((DBIntValue&)*mySetBookState->parameter("@word").value()) = state.Word; + ((DBIntValue&)*mySetBookState->parameter("@char").value()) = state.Character; + return mySetBookState->execute(); +} + +int BooksDB::loadStackPos(const Book &book) { + if (book.bookId() == 0) { + return 0; + } + ((DBIntValue&)*myLoadStackPos->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBValue> stackPosValue = myLoadStackPos->executeScalar(); + if (stackPosValue.isNull() + || stackPosValue->type() != DBValue::DBINT) { + return 0; + } + return ((DBIntValue&)*stackPosValue).value(); +} + +bool BooksDB::setStackPos(const Book &book, int stackPos) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*mySetStackPos->parameter("@book_id").value()) = book.bookId(); + ((DBIntValue&)*mySetStackPos->parameter("@stack_pos").value()) = stackPos; + return mySetStackPos->execute(); +} + +bool BooksDB::insertIntoBookList(const Book &book) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myInsertBookList->parameter("@book_id").value()) = book.bookId(); + return myInsertBookList->execute(); +} + +bool BooksDB::deleteFromBookList(const Book &book) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myDeleteBookList->parameter("@book_id").value()) = book.bookId(); + return myDeleteBookList->execute(); +} + +bool BooksDB::checkBookList(const Book &book) { + if (book.bookId() == 0) { + return false; + } + ((DBIntValue&)*myCheckBookList->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBValue> res = myCheckBookList->executeScalar(); + if (res.isNull() || res->type() != DBValue::DBINT) { + return false; + } + const int checkRes = ((DBIntValue&)*res).value(); + return checkRes > 0; +} diff --git a/fbreader/src/database/booksdb/BooksDB.h b/fbreader/src/database/booksdb/BooksDB.h new file mode 100644 index 0000000..634b31b --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDB.h @@ -0,0 +1,174 @@ +/* + * 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 __BOOKSDB_H__ +#define __BOOKSDB_H__ + +#include <set> +#include <map> +#include <deque> + +#include "../sqldb/implsqlite/SQLiteDataBase.h" +#include "DBRunnables.h" + +#include "../../fbreader/ReadingState.h" + +class Book; + +class BooksDB : public SQLiteDataBase { + +public: + static const std::string DATABASE_NAME; + static const std::string STATE_DATABASE_NAME; + static const std::string NET_DATABASE_NAME; + + static BooksDB &Instance(); + +private: + static shared_ptr<BooksDB> ourInstance; + + BooksDB(const std::string &path); + +public: + virtual ~BooksDB(); + +public: + bool initDatabase(); + bool isInitialized() const; + bool clearDatabase(); + + shared_ptr<Book> loadBook(const std::string &fileName); + bool saveBook(const shared_ptr<Book> book); + bool saveAuthors(const shared_ptr<Book> book); + bool saveSeries(const shared_ptr<Book> book); + bool saveTags(const shared_ptr<Book> book); + + int getFileSize(const std::string fileName); + bool setFileSize(const std::string fileName, int size); + + bool setEncoding(const Book &book, const std::string &encoding); + + bool loadFileEntries(const std::string &fileName, std::vector<std::string> &entries); + bool saveFileEntries(const std::string &fileName, const std::vector<std::string> &entries); + + bool loadRecentBooks(std::vector<std::string> &fileNames); + bool saveRecentBooks(const BookList &books); + + bool loadBooks(BookList &books); + + bool loadBookStateStack(const Book &book, std::deque<ReadingState> &stack); + bool saveBookStateStack(const Book &book, const std::deque<ReadingState> &stack); + + bool removeBook(const Book &book); + + std::string getPalmType(const std::string &fileName); + bool setPalmType(const std::string &fileName, const std::string &type); + + bool loadBookState(const Book &book, ReadingState &state); + bool setBookState(const Book &book, const ReadingState &state); + + int loadStackPos(const Book &book); + bool setStackPos(const Book &book, int stackPos); + + bool insertIntoBookList(const Book &book); + bool deleteFromBookList(const Book &book); + bool checkBookList(const Book &book); + +private: +public: + shared_ptr<Tag> getTagById(int id) const; + void loadAllTagsById() const; + +private: + void loadSeries(Book &book); + void loadSeries(const std::map<int,shared_ptr<Book> > &books); + void loadAuthors(Book &book); + void loadAuthors(const std::map<int,shared_ptr<Book> > &books); + void loadTags(Book &book); + void loadTags(const std::map<int,shared_ptr<Book> > &books); + + std::string getFileName(int fileId); + +private: + void initCommands(); + +private: + bool myInitialized; + + shared_ptr<SaveTableBookRunnable> mySaveTableBook; + shared_ptr<SaveAuthorsRunnable> mySaveAuthors; + shared_ptr<SaveSeriesRunnable> mySaveSeries; + shared_ptr<SaveTagsRunnable> mySaveTags; + shared_ptr<SaveBookRunnable> mySaveBook; + shared_ptr<SaveFileEntriesRunnable> mySaveFileEntries; + + shared_ptr<FindFileIdRunnable> myFindFileId; + + shared_ptr<LoadFileEntriesRunnable> myLoadFileEntries; + + shared_ptr<LoadRecentBooksRunnable> myLoadRecentBooks; + shared_ptr<SaveRecentBooksRunnable> mySaveRecentBooks; + + shared_ptr<SaveBookStateStackRunnable> mySaveBookStateStack; + + shared_ptr<DeleteBookRunnable> myDeleteBook; + + shared_ptr<DBCommand> myLoadNetworkLinks; + shared_ptr<DBCommand> myFindNetworkLinkId; + shared_ptr<DBCommand> myDeleteNetworkLink; + shared_ptr<DBCommand> myDeleteNetworkLinkUrls; + shared_ptr<DBCommand> myLoadNetworkLinkUrls; + + shared_ptr<DBCommand> myLoadBook; + + shared_ptr<DBCommand> myGetFileSize; + shared_ptr<DBCommand> mySetFileSize; + + shared_ptr<DBCommand> myFindFileName; + + shared_ptr<DBCommand> myFindAuthorId; + + shared_ptr<DBCommand> myLoadBooks; + + shared_ptr<DBCommand> myLoadBookStateStack; + + shared_ptr<DBCommand> myGetPalmType; + shared_ptr<DBCommand> mySetPalmType; + + shared_ptr<DBCommand> myGetNetFile; + shared_ptr<DBCommand> mySetNetFile; + + shared_ptr<DBCommand> myLoadStackPos; + shared_ptr<DBCommand> mySetStackPos; + shared_ptr<DBCommand> myLoadBookState; + shared_ptr<DBCommand> mySetBookState; + + shared_ptr<DBCommand> myInsertBookList; + shared_ptr<DBCommand> myDeleteBookList; + shared_ptr<DBCommand> myCheckBookList; + +private: // disable copying + BooksDB(const BooksDB &); + const BooksDB &operator = (const BooksDB &); +}; + + +inline bool BooksDB::isInitialized() const { return myInitialized; } + +#endif /* __BOOKSDB_H__ */ diff --git a/fbreader/src/database/booksdb/BooksDBQuery.cpp b/fbreader/src/database/booksdb/BooksDBQuery.cpp new file mode 100644 index 0000000..134e43b --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDBQuery.cpp @@ -0,0 +1,327 @@ +/* + * 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 <ZLibrary.h> + +#include "BooksDBQuery.h" + +const std::string BooksDBQuery::ArchiveEntryDelimiter = ":"; + +const std::string BooksDBQuery::PREINIT_DATABASE = \ + "ATTACH @stateFile AS State; "; + +const std::string BooksDBQuery::INIT_DATABASE = \ + "CREATE TABLE IF NOT EXISTS Files ( " \ + " file_id INTEGER PRIMARY KEY, " \ + " name TEXT NOT NULL, " \ + " parent_id INTEGER REFERENCES Files (file_id), " \ + " size INTEGER, " \ + " CONSTRAINT Files_Unique UNIQUE (name, parent_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Books ( " \ + " book_id INTEGER PRIMARY KEY, " \ + " encoding TEXT, " \ + " language TEXT, " \ + " title TEXT NOT NULL, " \ + " file_id INTEGER UNIQUE NOT NULL REFERENCES Files (file_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Authors ( " \ + " author_id INTEGER PRIMARY KEY, " \ + " name TEXT NOT NULL, " \ + " sort_key TEXT NOT NULL, " \ + " CONSTRAINT Authors_Unique UNIQUE (name, sort_key) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Series ( " \ + " series_id INTEGER PRIMARY KEY, " \ + " name TEXT UNIQUE NOT NULL " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS Tags ( " \ + " tag_id INTEGER PRIMARY KEY, " \ + " name TEXT NOT NULL, " \ + " parent_id INTEGER REFERENCES Tags (tag_id), " \ + " CONSTRAINT Tags_Unique UNIQUE (parent_id, name) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS BookAuthor ( " \ + " author_id INTEGER NOT NULL REFERENCES Authors (author_id), " \ + " book_id INTEGER NOT NULL REFERENCES Books (book_id), " \ + " author_index INTEGER NOT NULL, " \ + " CONSTRAINT BookAuthor_Unique0 UNIQUE (author_id, book_id), " \ + " CONSTRAINT BookAuthor_Unique1 UNIQUE (book_id, author_index) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS BookSeries ( " \ + " book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id), " \ + " series_id INTEGER NOT NULL REFERENCES Series (series_id), " \ + " book_index INTEGER " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS BookTag ( " \ + " book_id INTEGER NOT NULL REFERENCES Books (book_id), " \ + " tag_id INTEGER NOT NULL REFERENCES Tags (tag_id), " \ + " CONSTRAINT BookTag_Unique UNIQUE (book_id, tag_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.RecentBooks ( " \ + " book_index INTEGER PRIMARY KEY, " \ + " book_id INTEGER UNIQUE REFERENCES Books (book_id) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.BookStateStack ( " \ + " book_id INTEGER NOT NULL REFERENCES Books (book_id), " \ + " position INTEGER NOT NULL, " \ + " paragraph INTEGER NOT NULL, " \ + " word INTEGER NOT NULL, " \ + " char INTEGER NOT NULL, " \ + " CONSTRAINT BookStateStack_Unique UNIQUE (book_id, position) " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS PalmType ( " \ + " file_id INTEGER UNIQUE REFERENCES Files (file_id), " \ + " type TEXT NOT NULL " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.StackPosition ( " \ + " book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id), " \ + " stack_pos INTEGER NOT NULL " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS State.BookList ( " \ + " book_id INTEGER UNIQUE NOT NULL REFERENCES Books (book_id) " \ + "); "; + +const std::string BooksDBQuery::SECOND_INIT_DATABASE = \ + "CREATE TRIGGER IF NOT EXISTS Books_Delete BEFORE DELETE " \ + "ON Books FOR EACH ROW " \ + "BEGIN " \ + " DELETE FROM BookAuthor WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookSeries WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookTag WHERE book_id = OLD.book_id; " \ + " DELETE FROM StackPosition WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookStateStack WHERE book_id = OLD.book_id; " \ + " DELETE FROM RecentBooks WHERE book_id = OLD.book_id; " \ + " DELETE FROM BookList WHERE book_id = OLD.book_id; " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Delete BEFORE DELETE " \ + "ON Files FOR EACH ROW " \ + "BEGIN " \ + " DELETE FROM Books WHERE file_id = OLD.file_id; " \ + " DELETE FROM PalmType WHERE file_id = OLD.file_id; " \ + "END; " \ + " " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Unique_Insert BEFORE INSERT " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.parent_id IS NULL AND f.name = NEW.name) " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"columns name, parent_id are not unique\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Directory_Insert BEFORE INSERT " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Directory entry\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_ArchEntry_Insert BEFORE INSERT " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NOT NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.file_id = NEW.parent_id AND f.parent_id IS NOT NULL) " \ + " AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Archive Entry entry\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Unique_Update BEFORE UPDATE " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.parent_id IS NULL AND f.name = NEW.name AND f.file_id != NEW.file_id) " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"columns name, parent_id are not unique\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_Directory_Update BEFORE UPDATE " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NULL AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Directory entry\"); " \ + "END; " \ + " " \ + "CREATE TRIGGER IF NOT EXISTS Files_ArchEntry_Update BEFORE UPDATE " \ + "ON Files FOR EACH ROW " \ + "WHEN NEW.parent_id IS NOT NULL " \ + " AND 0 != (SELECT count(*) FROM Files AS f WHERE f.file_id = NEW.parent_id AND f.parent_id IS NOT NULL) " \ + " AND NEW.size IS NOT NULL " \ + "BEGIN " \ + " SELECT RAISE(ABORT, \"size is not null for Archive Entry entry\"); " \ + "END; "; + +const std::string BooksDBQuery::CLEAR_DATABASE = \ + "DROP TRIGGER Books_Delete " \ + "DROP TRIGGER Files_Delete " \ + "DROP TRIGGER Files_Unique_Insert " \ + "DROP TRIGGER Files_Directory_Insert " \ + "DROP TRIGGER Files_ArchEntry_Insert " \ + "DROP TRIGGER Files_Unique_Update " \ + "DROP TRIGGER Files_Directory_Update " \ + "DROP TRIGGER Files_ArchEntry_Update " \ + " " \ + "DROP TABLE State.BookList; " \ + "DROP TABLE State.StackPosition; " \ + "DROP TABLE PalmType; " \ + "DROP TABLE State.BookStateStack; " \ + "DROP TABLE State.RecentBooks; " \ + "DROP TABLE BookTag; " \ + "DROP TABLE BookSeries; " \ + "DROP TABLE BookAuthor; " \ + "DROP TABLE Tags; " \ + "DROP TABLE Series; " \ + "DROP TABLE Authors; " \ + "DROP TABLE Books; " \ + "DROP TABLE Files; "; + + +const std::string BooksDBQuery::LOAD_BOOK = \ + "SELECT " \ + " b.book_id AS book_id, " \ + " b.encoding AS encoding, " \ + " b.language AS language, " \ + " b.title AS title, " \ + " b.file_id AS file_id " \ + "FROM Books AS b " \ + "WHERE b.file_id = @file_id; "; + +const std::string BooksDBQuery::ADD_BOOK = \ + "INSERT INTO Books (encoding, language, title, file_id) " \ + " VALUES ( " \ + " nullif(@encoding,\"auto\"), " \ + " nullif(@language,\"other\"), " \ + " @title, " \ + " @file_id " \ + " ); " \ + " " \ + "SELECT last_insert_rowid() AS book_id; "; + +const std::string BooksDBQuery::UPDATE_BOOK = \ + "UPDATE Books SET " \ + " encoding = nullif(@encoding,\"auto\"), " \ + " language = nullif(@language,\"other\"), " \ + " title = @title " \ + "WHERE " \ + " book_id = @book_id; "; + + + +const std::string BooksDBQuery::SET_BOOK_AUTHOR = \ + "INSERT OR REPLACE INTO BookAuthor (author_id, book_id, author_index) VALUES (@author_id, @book_id, @author_index); "; + +const std::string BooksDBQuery::TRIM_BOOK_AUTHORS = \ + "DELETE FROM BookAuthor WHERE book_id = @book_id AND author_index > @authors_number; "; + +const std::string BooksDBQuery::FIND_AUTHOR_ID = "SELECT author_id FROM Authors WHERE name = @name AND sort_key = @sort_key; "; + +const std::string BooksDBQuery::ADD_AUTHOR = \ + "INSERT INTO Authors (name, sort_key) VALUES (@name, @sort_key); " \ + "SELECT last_insert_rowid() AS author_id; "; + + +const std::string BooksDBQuery::SET_BOOKSERIES = \ + "INSERT OR REPLACE INTO BookSeries (book_id, series_id, book_index) VALUES (" \ + " @book_id, " \ + " @series_id, " \ + " nullif(@book_index, \"\") " \ + "); "; + +const std::string BooksDBQuery::DELETE_BOOKSERIES = \ + "DELETE FROM BookSeries " \ + "WHERE " \ + " book_id = @book_id; "; + +const std::string BooksDBQuery::FIND_SERIES_ID = "SELECT series_id FROM Series WHERE name = @name; "; + +const std::string BooksDBQuery::ADD_SERIES = \ + "INSERT INTO Series (name) VALUES (@name); " \ + "SELECT last_insert_rowid() AS series_id; "; + + +const std::string BooksDBQuery::GET_FILE_SIZE = "SELECT size FROM Files WHERE file_id = @file_id"; +const std::string BooksDBQuery::SET_FILE_SIZE = "UPDATE Files SET size = @size WHERE file_id = @file_id"; + +const std::string BooksDBQuery::SET_ENCODING = "UPDATE Books SET encoding = @encoding WHERE book_id = @book_id; "; + +const std::string BooksDBQuery::LOAD_FILE_ENTRIES = "SELECT name FROM Files WHERE coalesce(parent_id, 0) = @file_id; "; + +const std::string BooksDBQuery::INVALIDATE_BOOKS = "UPDATE Books SET title = \"\" WHERE file_id = @file_id; "; + + +const std::string BooksDBQuery::DELETE_FILE = "DELETE FROM Files WHERE file_id = @file_id; "; + +const std::string BooksDBQuery::DELETE_FILE_ENTRIES = "DELETE FROM Files WHERE parent_id = @file_id; "; + +const std::string BooksDBQuery::LOAD_FILE_ENTRY_IDS = "SELECT file_id FROM Files WHERE coalesce(parent_id, 0) = @file_id; "; + +const std::string BooksDBQuery::FIND_BOOK_ID = "SELECT book_id FROM Books WHERE file_id = @file_id; "; + + +const std::string BooksDBQuery::LOAD_RECENT_BOOKS = \ + "SELECT b.file_id " \ + "FROM Books AS b " \ + " INNER JOIN RecentBooks AS rb ON b.book_id = rb.book_id " \ + "ORDER BY rb.book_index; "; + +const std::string BooksDBQuery::CLEAR_RECENT_BOOKS = "DELETE FROM RecentBooks; "; + +const std::string BooksDBQuery::INSERT_RECENT_BOOKS = "INSERT INTO RecentBooks (book_id) VALUES (@book_id); "; + +const std::string BooksDBQuery::FIND_FILE_NAME = "SELECT name, parent_id FROM Files WHERE file_id = @file_id; "; + +const std::string BooksDBQuery::LOAD_BOOKS = "SELECT book_id, encoding, language, title, file_id FROM Books; "; + +const std::string BooksDBQuery::UPDATE_AUTHOR = \ + "UPDATE Authors SET " \ + " name = @newName, " \ + " sort_key = @newSortKey " \ + "WHERE name = @oldName " \ + " AND sort_key = @oldSortKey; "; + +const std::string BooksDBQuery::UPDATE_BOOKS_AUTHOR = "UPDATE OR REPLACE BookAuthor SET author_id = @newAuthorId WHERE author_id = @oldAuthorId; "; + +const std::string BooksDBQuery::LOAD_BOOK_STATE_STACK = "SELECT paragraph, word, char FROM BookStateStack WHERE book_id = @book_id AND position > 0 ORDER BY position; "; +const std::string BooksDBQuery::TRIM_BOOK_STATE_STACK = "DELETE FROM BookStateStack WHERE book_id = @book_id AND position > @stackSize; "; +const std::string BooksDBQuery::SET_BOOK_STATE_STACK = "INSERT OR REPLACE INTO BookStateStack(book_id, position, paragraph, word, char) VALUES (@book_id, @position, @paragraph, @word, @char); "; + +const std::string BooksDBQuery::SET_PALM_TYPE = "INSERT OR REPLACE INTO PalmType (file_id, type) VALUES (@file_id, @type); "; +const std::string BooksDBQuery::GET_PALM_TYPE = "SELECT type FROM PalmType WHERE file_id = @file_id; "; + +const std::string BooksDBQuery::LOAD_STACK_POS = "SELECT stack_pos FROM StackPosition WHERE book_id = @book_id; "; +const std::string BooksDBQuery::SET_STACK_POS = "INSERT OR REPLACE INTO StackPosition(book_id, stack_pos) VALUES (@book_id, @stack_pos); "; + +const std::string BooksDBQuery::LOAD_BOOK_STATE = "SELECT paragraph, word, char FROM BookStateStack WHERE book_id = @book_id AND position = 0; "; +const std::string BooksDBQuery::SET_BOOK_STATE = "INSERT OR REPLACE INTO BookStateStack(book_id, position, paragraph, word, char) VALUES (@book_id, 0, @paragraph, @word, @char); "; + +const std::string BooksDBQuery::INSERT_BOOK_LIST = "INSERT OR IGNORE INTO BookList(book_id) VALUES (@book_id); "; +const std::string BooksDBQuery::DELETE_BOOK_LIST = "DELETE FROM BookList WHERE book_id = @book_id; "; +const std::string BooksDBQuery::CHECK_BOOK_LIST = "SELECT COUNT(*) FROM BookList WHERE book_id = @book_id; "; diff --git a/fbreader/src/database/booksdb/BooksDBQuery.h b/fbreader/src/database/booksdb/BooksDBQuery.h new file mode 100644 index 0000000..c202dea --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDBQuery.h @@ -0,0 +1,99 @@ +/* + * 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 __BOOKSDBQUERY_H__ +#define __BOOKSDBQUERY_H__ + +#include <string> + +class BooksDBQuery { + +public: + static const std::string ArchiveEntryDelimiter; + +public: + static const std::string PREINIT_DATABASE; + static const std::string INIT_DATABASE; + static const std::string SECOND_INIT_DATABASE; + static const std::string CLEAR_DATABASE; + + static const std::string LOAD_BOOK; + + static const std::string ADD_BOOK; + static const std::string UPDATE_BOOK; + + static const std::string FIND_AUTHOR_ID; + static const std::string ADD_AUTHOR; + + static const std::string GET_BOOK_AUTHORS_NUMBER; + static const std::string TRIM_BOOK_AUTHORS; + static const std::string SET_BOOK_AUTHOR; + + static const std::string DELETE_BOOKSERIES; + static const std::string FIND_SERIES_ID; + static const std::string ADD_SERIES; + static const std::string SET_BOOKSERIES; + + static const std::string GET_FILE_SIZE; + static const std::string SET_FILE_SIZE; + + static const std::string SET_ENCODING; + + static const std::string LOAD_FILE_ENTRIES; + + static const std::string INVALIDATE_BOOKS; + + static const std::string DELETE_FILE; + static const std::string DELETE_FILE_ENTRIES; + static const std::string LOAD_FILE_ENTRY_IDS; + + static const std::string FIND_BOOK_ID; + + static const std::string LOAD_RECENT_BOOKS; + static const std::string CLEAR_RECENT_BOOKS; + static const std::string INSERT_RECENT_BOOKS; + + static const std::string FIND_FILE_NAME; + + static const std::string LOAD_BOOKS; + + static const std::string UPDATE_AUTHOR; + static const std::string UPDATE_BOOKS_AUTHOR; + + static const std::string LOAD_BOOK_STATE_STACK; + static const std::string TRIM_BOOK_STATE_STACK; + static const std::string SET_BOOK_STATE_STACK; + + static const std::string GET_PALM_TYPE; + static const std::string SET_PALM_TYPE; + + static const std::string LOAD_BOOK_STATE; + static const std::string SET_BOOK_STATE; + static const std::string LOAD_STACK_POS; + static const std::string SET_STACK_POS; + + static const std::string INSERT_BOOK_LIST; + static const std::string DELETE_BOOK_LIST; + static const std::string CHECK_BOOK_LIST; + +private: // disable creation Instances + BooksDBQuery(); +}; + +#endif /* __BOOKSDBQUERY_H__ */ diff --git a/fbreader/src/database/booksdb/BooksDBUtil.cpp b/fbreader/src/database/booksdb/BooksDBUtil.cpp new file mode 100644 index 0000000..3a7de96 --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDBUtil.cpp @@ -0,0 +1,184 @@ +/* + * 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 <ZLFile.h> +#include <ZLDir.h> +#include <ZLStringUtil.h> + +#include "BooksDBUtil.h" +#include "BooksDB.h" + +#include "../../library/Book.h" +#include "../../library/Tag.h" +#include "../../library/Author.h" + +shared_ptr<Book> BooksDBUtil::getBook(const std::string &filePath, bool checkFile) { + const std::string physicalFilePath = ZLFile(filePath).physicalFilePath(); + + ZLFile file(physicalFilePath); + if (checkFile && !file.exists()) { + return 0; + } + + if (!checkFile || checkInfo(file)) { + shared_ptr<Book> book = loadFromDB(filePath); + if (!book.isNull() && isBookFull(*book)) { + return book; + } + } else { + if (physicalFilePath != filePath) { + resetZipInfo(file); + } + saveInfo(file); + } + + shared_ptr<Book> book = Book::loadFromFile(ZLFile(filePath)); + if (book.isNull()) { + return 0; + } + BooksDB::Instance().saveBook(book); + return book; +} + +bool BooksDBUtil::getRecentBooks(BookList &books) { + std::vector<std::string> fileNames; + if (!BooksDB::Instance().loadRecentBooks(fileNames)) { + return false; + } + for (std::vector<std::string>::const_iterator it = fileNames.begin(); it != fileNames.end(); ++it) { + shared_ptr<Book> book = getBook(*it /*, true OR false ? */); // TODO: check file ??? + if (!book.isNull()) { + books.push_back(book); + } + } + return true; +} + +bool BooksDBUtil::getBooks(std::map<std::string, shared_ptr<Book> > &booksmap, bool checkFile) { + BookList books; + if (!BooksDB::Instance().loadBooks(books)) { + return false; + } + for (BookList::iterator it = books.begin(); it != books.end(); ++it) { + Book &book = **it; + const std::string physicalFilePath = book.file().physicalFilePath(); + ZLFile file(physicalFilePath); + if (!checkFile || file.exists()) { + if (!checkFile || checkInfo(file)) { + if (isBookFull(book)) { + booksmap.insert(std::make_pair(book.file().path(), *it)); + continue; + } + } else { + if (physicalFilePath != book.file().path()) { + resetZipInfo(file); + } + saveInfo(file); + } + shared_ptr<Book> bookptr = Book::loadFromFile(book.file()); + if (!bookptr.isNull()) { + BooksDB::Instance().saveBook(bookptr); + booksmap.insert(std::make_pair(book.file().path(), bookptr)); + } + } + } + return true; +} + +bool BooksDBUtil::isBookFull(const Book &book) { + return + !book.title().empty() && + !book.encoding().empty(); +} + +shared_ptr<Book> BooksDBUtil::loadFromDB(const std::string &filePath) { + if (filePath.empty()) { + return 0; + } + return BooksDB::Instance().loadBook(filePath); +} + +bool BooksDBUtil::checkInfo(const ZLFile &file) { + return BooksDB::Instance().getFileSize(file.path()) == (int) file.size(); +} + +void BooksDBUtil::saveInfo(const ZLFile &file) { + BooksDB::Instance().setFileSize(file.path(), file.size()); +} + +void BooksDBUtil::listZipEntries(const ZLFile &zipFile, std::vector<std::string> &entries) { + entries.clear(); + BooksDB::Instance().loadFileEntries(zipFile.path(), entries); + if (entries.empty()) { + resetZipInfo(zipFile); + BooksDB::Instance().loadFileEntries(zipFile.path(), entries); + } +} + +void BooksDBUtil::resetZipInfo(const ZLFile &zipFile) { + shared_ptr<ZLDir> zipDir = zipFile.directory(); + if (!zipDir.isNull()) { + std::vector<std::string> entries; + zipDir->collectFiles(entries, false); + BooksDB::Instance().saveFileEntries(zipFile.path(), entries); + } +} + +bool BooksDBUtil::canRemoveFile(const std::string &filePath) { + ZLFile bookFile(filePath); + std::string physicalPath = bookFile.physicalFilePath(); + if (filePath != physicalPath) { + ZLFile zipFile(physicalPath); + shared_ptr<ZLDir> zipDir = zipFile.directory(); + if (zipDir.isNull()) { + return false; + } + std::vector<std::string> entries; + zipDir->collectFiles(entries, false); // TODO: replace with BooksDB call??? + if (entries.size() != 1) { + return false; + } + if (zipDir->itemPath(entries[0]) != filePath) { + return false; + } + } + return ZLFile(physicalPath).canRemove(); +} + +void BooksDBUtil::addTag(shared_ptr<Book> book, shared_ptr<Tag> tag) { + if (book->addTag(tag)) { + BooksDB::Instance().saveTags(book); + } +} + +void BooksDBUtil::renameTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (book->renameTag(from, to, includeSubTags)) { + BooksDB::Instance().saveTags(book); + } +} + +void BooksDBUtil::cloneTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags) { + if (book->cloneTag(from, to, includeSubTags)) { + BooksDB::Instance().saveTags(book); + } +} + +void BooksDBUtil::removeAllTags(shared_ptr<Book> book) { + book->removeAllTags(); +} diff --git a/fbreader/src/database/booksdb/BooksDBUtil.h b/fbreader/src/database/booksdb/BooksDBUtil.h new file mode 100644 index 0000000..8d55e1c --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDBUtil.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 __BOOKSDBUTIL_H__ +#define __BOOKSDBUTIL_H__ + +#include <map> + +#include <shared_ptr.h> + +#include "../../library/Lists.h" + +class Book; +class ZLFile; + +class BooksDBUtil { + +public: + static shared_ptr<Book> getBook(const std::string &fileName, bool checkFile = true); + + static bool getBooks(std::map<std::string, shared_ptr<Book> > &booksmap, bool checkFile = true); + + static bool getRecentBooks(BookList &books); + +public: + static void addTag(shared_ptr<Book> book, shared_ptr<Tag> tag); + static void renameTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + static void cloneTag(shared_ptr<Book> book, shared_ptr<Tag> from, shared_ptr<Tag> to, bool includeSubTags); + static void removeAllTags(shared_ptr<Book> book); + + static bool checkInfo(const ZLFile &file); + static void saveInfo(const ZLFile &file); + + static void listZipEntries(const ZLFile &zipFile, std::vector<std::string> &entries); + static void resetZipInfo(const ZLFile &zipFile); + + static bool isBookFull(const Book &book); + + static bool canRemoveFile(const std::string &fileName); + +private: + static shared_ptr<Book> loadFromDB(const std::string &fileName); +}; + +#endif /* __BOOKSDBUTIL_H__ */ diff --git a/fbreader/src/database/booksdb/BooksDB_BookAuthor.cpp b/fbreader/src/database/booksdb/BooksDB_BookAuthor.cpp new file mode 100644 index 0000000..8cdc2a4 --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDB_BookAuthor.cpp @@ -0,0 +1,76 @@ +/* + * 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 <string> + +#include "BooksDB.h" +#include "../../library/Book.h" +#include "../../library/Author.h" +#include "../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string LOAD_AUTHORS_QUERY = + "SELECT Authors.name, Authors.sort_key" \ + " FROM BookAuthor" \ + " INNER JOIN Authors ON Authors.author_id = BookAuthor.author_id" \ + " WHERE BookAuthor.book_id = @book_id" \ + " ORDER BY BookAuthor.author_index;"; +static const std::string LOAD_ALL_AUTHORS_QUERY = + "SELECT Authors.name, Authors.sort_key, BookAuthor.book_id" \ + " FROM BookAuthor" \ + " INNER JOIN Authors ON Authors.author_id = BookAuthor.author_id" \ + " ORDER BY BookAuthor.author_index;"; + +void BooksDB::loadAuthors(Book &book) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_AUTHORS_QUERY, connection(), "@book_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = command->executeReader(); + + book.removeAllAuthors(); + + while (reader->next()) { + book.addAuthor( + reader->textValue(0, std::string()), + reader->textValue(1, std::string()) + ); + } +} + +void BooksDB::loadAuthors(const std::map<int,shared_ptr<Book> > &books) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_AUTHORS_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + + for (std::map<int,shared_ptr<Book> >::const_iterator it = books.begin(); it != books.end(); ++it) { + it->second->removeAllAuthors(); + } + + while (reader->next()) { + std::map<int,shared_ptr<Book> >::const_iterator it = + books.find((reader->type(2) == DBValue::DBINT) ? reader->intValue(2) : 0); + if (it != books.end()) { + it->second->addAuthor( + reader->textValue(0, std::string()), + reader->textValue(1, std::string()) + ); + } + } +} diff --git a/fbreader/src/database/booksdb/BooksDB_BookSeries.cpp b/fbreader/src/database/booksdb/BooksDB_BookSeries.cpp new file mode 100644 index 0000000..a9b860b --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDB_BookSeries.cpp @@ -0,0 +1,83 @@ +/* + * 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 <string> + +#include "BooksDB.h" +#include "../../library/Book.h" +#include "../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string LOAD_SERIES_QUERY = + "SELECT Series.name, BookSeries.book_index" \ + " FROM BookSeries" \ + " INNER JOIN Series ON Series.series_id = BookSeries.series_id" \ + " WHERE BookSeries.book_id = @book_id;"; +static const std::string LOAD_ALL_SERIES_QUERY = + "SELECT Series.name, BookSeries.book_index, BookSeries.book_id" \ + " FROM BookSeries" \ + " INNER JOIN Series ON Series.series_id = BookSeries.series_id"; + +static Number getSeriesIndex(shared_ptr<DBDataReader> reader) { + Number seriesIndex; + if (reader->type(1) == DBValue::DBTEXT) { + seriesIndex = Number(reader->textValue(1, std::string())); + } else if (reader->type(1) == DBValue::DBREAL){ //for old database scheme + seriesIndex = Number((int)reader->realValue(1)); + } else { //for old database scheme + seriesIndex = Number(reader->intValue(1)); + } + return seriesIndex; +} + +void BooksDB::loadSeries(Book &book) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_SERIES_QUERY, connection(), "@book_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = command->executeReader(); + + if (reader->next()) { + std::string seriesTitle = reader->textValue(0, std::string()); + if (!seriesTitle.empty()) { + book.setSeries( + seriesTitle, + getSeriesIndex(reader) + ); + } + } +} + +void BooksDB::loadSeries(const std::map<int,shared_ptr<Book> > &books) { + shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_SERIES_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + + while (reader->next()) { + std::string seriesTitle = reader->textValue(0, std::string()); + std::map<int,shared_ptr<Book> >::const_iterator it = + books.find((reader->type(2) == DBValue::DBINT) ? reader->intValue(2) : 0); + if (!seriesTitle.empty() && it != books.end()) { + it->second->setSeries( + seriesTitle, + getSeriesIndex(reader) + ); + } + } +} diff --git a/fbreader/src/database/booksdb/BooksDB_BookTag.cpp b/fbreader/src/database/booksdb/BooksDB_BookTag.cpp new file mode 100644 index 0000000..a3d36fe --- /dev/null +++ b/fbreader/src/database/booksdb/BooksDB_BookTag.cpp @@ -0,0 +1,246 @@ +/* + * 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 <string> +#include <algorithm> + +#include "BooksDB.h" +#include "DBRunnables.h" +#include "../../library/Book.h" +#include "../../library/Tag.h" +#include "../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string LOAD_BOOK_TAGS_QUERY = + "SELECT tag_id FROM BookTag WHERE book_id = @book_id"; +static const std::string LOAD_ALL_BOOK_TAGS_QUERY = + "SELECT tag_id, book_id FROM BookTag"; +static const std::string LOAD_SINGLE_TAG_QUERY = + "SELECT name, parent_id FROM Tags WHERE tag_id = @tag_id"; +static const std::string LOAD_ALL_TAGS_QUERY = + "SELECT name, parent_id, tag_id FROM Tags ORDER BY tag_id"; +static const std::string ADD_BOOKTAG = + "INSERT INTO BookTag (book_id, tag_id) VALUES (@book_id, @tag_id)"; +static const std::string DELETE_BOOKTAG = + "DELETE FROM BookTag WHERE book_id = @book_id AND tag_id = @tag_id"; +static const std::string FIND_TAG_ID = + "SELECT tag_id FROM Tags" \ + " WHERE name = @name AND coalesce(parent_id, 0) = @parent_id"; +static const std::string ADD_TAG = + "INSERT INTO Tags (name, parent_id) VALUES (@name, nullif(@parent_id, 0));" \ + " SELECT last_insert_rowid() AS tag_id"; + +void BooksDB::loadTags(Book &book) { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_BOOK_TAGS_QUERY, connection(), "@book_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@book_id").value()) = book.bookId(); + shared_ptr<DBDataReader> reader = command->executeReader(); + + book.removeAllTags(); + while (reader->next()) { + book.addTag(getTagById(reader->intValue(0))); + } +} + +void BooksDB::loadTags(const std::map<int,shared_ptr<Book> > &books) { + loadAllTagsById(); + + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_BOOK_TAGS_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + + for (std::map<int,shared_ptr<Book> >::const_iterator it = books.begin(); it != books.end(); ++it) { + it->second->removeAllTags(); + } + + while (reader->next()) { + std::map<int,shared_ptr<Book> >::const_iterator it = + books.find((reader->type(1) == DBValue::DBINT) ? reader->intValue(1) : 0); + if (it != books.end()) { + it->second->addTag(getTagById(reader->intValue(0))); + } + } +} + +shared_ptr<Tag> BooksDB::getTagById(int id) const { + if (id == 0) { + return 0; + } + + shared_ptr<Tag> tag = Tag::getTagById(id); + if (!tag.isNull()) { + return tag; + } + + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_SINGLE_TAG_QUERY, connection(), "@tag_id", DBValue::DBINT + ); + ((DBIntValue&)*command->parameter("@tag_id").value()) = id; + shared_ptr<DBDataReader> reader = command->executeReader(); + if (!reader->next()) { + return 0; + } + const std::string name = reader->textValue(0, std::string()); + const int parentId = (reader->type(1) == DBValue::DBINT) ? + reader->intValue(1) : 0; + reader.reset(); + + return Tag::getTag(name, getTagById(parentId), id); +} + +void BooksDB::loadAllTagsById() const { + static shared_ptr<DBCommand> command = SQLiteFactory::createCommand( + LOAD_ALL_TAGS_QUERY, connection() + ); + shared_ptr<DBDataReader> reader = command->executeReader(); + while (reader->next()) { + if (reader->type(2) != DBValue::DBINT) { + continue; + } + const int id = reader->intValue(2); + if (!Tag::getTagById(id).isNull()) { + continue; + } + Tag::getTag( + reader->textValue(0, std::string()), + Tag::getTagById( + (reader->type(1) == DBValue::DBINT) ? reader->intValue(1) : 0 + ), + id + ); + } +} + +SaveTagsRunnable::SaveTagsRunnable(DBConnection &connection) { + myDeleteBookTag = SQLiteFactory::createCommand( + DELETE_BOOKTAG, connection, + "@book_id", DBValue::DBINT, + "@tag_id", DBValue::DBINT + ); + myFindTagId = SQLiteFactory::createCommand( + FIND_TAG_ID, connection, + "@name", DBValue::DBTEXT, + "@parent_id", DBValue::DBINT + ); + myAddTag = SQLiteFactory::createCommand( + ADD_TAG, connection, + "@name", DBValue::DBTEXT, + "@parent_id", DBValue::DBINT + ); + myAddBookTag = SQLiteFactory::createCommand( + ADD_BOOKTAG, connection, + "@book_id", DBValue::DBINT, + "@tag_id", DBValue::DBINT + ); + myLoadBookTags = SQLiteFactory::createCommand( + LOAD_BOOK_TAGS_QUERY, connection, "@book_id", DBValue::DBINT + ); +} + +bool SaveTagsRunnable::run() { + if (myBook->bookId() == 0) { + return false; + } + + ((DBIntValue&)*myDeleteBookTag->parameter("@book_id").value()) = myBook->bookId(); + DBIntValue &delTagId = (DBIntValue&)*myDeleteBookTag->parameter("@tag_id").value(); + ((DBIntValue&)*myAddBookTag->parameter("@book_id").value()) = myBook->bookId(); + DBIntValue &addTagId = (DBIntValue&)*myAddBookTag->parameter("@tag_id").value(); + + TagList dbTags; + + ((DBIntValue&)*myLoadBookTags->parameter("@book_id").value()) = myBook->bookId(); + shared_ptr<DBDataReader> reader = myLoadBookTags->executeReader(); + + while (reader->next()) { + shared_ptr<Tag> tag = BooksDB::Instance().getTagById(reader->intValue(0)); + if (!tag.isNull()) { + dbTags.push_back(tag); + } + } + + TagList tags = myBook->tags(); // make copy of vector + + for (TagList::const_iterator it = dbTags.begin(); it != dbTags.end(); ++it) { + shared_ptr<Tag> tag = (*it); + findTagId(tag); + TagList::iterator jt = std::find(tags.begin(), tags.end(), tag); + if (jt == tags.end()) { + // Tag `tag` must be removed from BookTag table. + delTagId.setValue(tag->tagId()); + if (!myDeleteBookTag->execute()) { + return false; + } + } else { + // This tag is already in DataBase => need not to be inserted. + tags.erase(jt); + } + } + + for (TagList::const_iterator it = tags.begin(); it != tags.end(); ++it) { + int tableTagId = findTagId(*it); + if (tableTagId == 0) { + return false; + } + addTagId.setValue(tableTagId); + if (!myAddBookTag->execute()) { + return false; + } + } + return true; +} + + +int SaveTagsRunnable::findTagId(shared_ptr<Tag> tag) { + int tagId = tag->tagId(); + if (tagId != 0) { + return tagId; + } + int parentId = 0; + if (!tag->parent().isNull()) { + parentId = findTagId(tag->parent()); + if (parentId == 0) { + return 0; + } + } + + DBIntValue &findParent = (DBIntValue&)*myFindTagId->parameter("@parent_id").value(); + DBTextValue &findName = (DBTextValue&)*myFindTagId->parameter("@name").value(); + DBIntValue &addParent = (DBIntValue&)*myAddTag->parameter("@parent_id").value(); + DBTextValue &addName = (DBTextValue&)*myAddTag->parameter("@name").value(); + + findParent.setValue(parentId); + findName.setValue(tag->name()); + shared_ptr<DBValue> tableTagId = myFindTagId->executeScalar(); + if (tableTagId.isNull() || tableTagId->type() != DBValue::DBINT || ((DBIntValue&)*tableTagId).value() == 0) { + addParent.setValue(parentId); + addName.setValue(tag->name()); + tableTagId = myAddTag->executeScalar(); + if (tableTagId.isNull() || tableTagId->type() != DBValue::DBINT || ((DBIntValue&)*tableTagId).value() == 0) { + return 0; + } + } + Tag::setTagId(tag, ((DBIntValue&)*tableTagId).value()); + return ((DBIntValue&)*tableTagId).value(); +} + +void SaveTagsRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/fbreader/src/database/booksdb/DBRunnables.h b/fbreader/src/database/booksdb/DBRunnables.h new file mode 100644 index 0000000..4baee65 --- /dev/null +++ b/fbreader/src/database/booksdb/DBRunnables.h @@ -0,0 +1,311 @@ +/* + * 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 __DBRUNNABLES_H__ +#define __DBRUNNABLES_H__ + +#include <deque> +#include <vector> + +#include "../../fbreader/ReadingState.h" + +#include "../sqldb/DBConnection.h" +#include "../sqldb/DBCommand.h" +#include "../sqldb/DBRunnable.h" + +#include "BooksDBQuery.h" + +#include "../../library/Lists.h" + +class FindFileIdRunnable; +class LoadFileEntriesRunnable; +class DeleteFileEntriesRunnable; + +/* + * Save Runnables + */ + + +class InitBooksDBRunnable : public DBRunnable { + +public: + InitBooksDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class ClearBooksDBRunnable : public DBRunnable { + +public: + ClearBooksDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class SaveTableBookRunnable : public DBRunnable { + +public: + SaveTableBookRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + bool addTableBook(const shared_ptr<Book> book, int fileId); + bool updateTableBook(const shared_ptr<Book> book); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> myFindBookId; + + shared_ptr<DBCommand> myAddBook; + shared_ptr<DBCommand> myUpdateBook; + + shared_ptr<FindFileIdRunnable> myFindFileId; +}; + +class SaveAuthorsRunnable : public DBRunnable { + +public: + SaveAuthorsRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> mySetBookAuthor; + shared_ptr<DBCommand> myTrimBookAuthors; + + shared_ptr<DBCommand> myFindAuthorId; + shared_ptr<DBCommand> myAddAuthor; +}; + +class SaveTagsRunnable : public DBRunnable { + +public: + SaveTagsRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + int findTagId(shared_ptr<Tag> tag); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> myAddBookTag; + shared_ptr<DBCommand> myDeleteBookTag; + + shared_ptr<DBCommand> myFindTagId; + shared_ptr<DBCommand> myAddTag; + + shared_ptr<DBCommand> myLoadBookTags; +}; + + +class SaveSeriesRunnable : public DBRunnable { + +public: + SaveSeriesRunnable(DBConnection &connection); + bool run(); + void setBook(shared_ptr<Book> book); + +private: + shared_ptr<Book> myBook; + + shared_ptr<DBCommand> mySetBookSeries; + shared_ptr<DBCommand> myDeleteBookSeries; + + shared_ptr<DBCommand> myFindSeriesId; + shared_ptr<DBCommand> myAddSeries; +}; + +class SaveBookRunnable : public DBRunnable { +public: + SaveBookRunnable(SaveTableBookRunnable &saveTableBook, SaveAuthorsRunnable &saveAuthors, + SaveSeriesRunnable &saveSeries, SaveTagsRunnable &saveTags); + + bool run(); + void setBook(shared_ptr<Book> book); + +private: + SaveTableBookRunnable &mySaveTableBook; + SaveAuthorsRunnable &mySaveAuthors; + SaveSeriesRunnable &mySaveSeries; + SaveTagsRunnable &mySaveTags; +}; + +class SaveFileEntriesRunnable : public DBRunnable { + +public: + SaveFileEntriesRunnable(DBConnection &connection); + bool run(); + void setEntries(const std::string &fileName, const std::vector<std::string> &entries); + +private: + std::string myFileName; + std::vector<std::string> myEntries; + + shared_ptr<DBCommand> myAddFile; + + shared_ptr<FindFileIdRunnable> myFindFileId; + shared_ptr<DeleteFileEntriesRunnable> myDeleteFileEntries; +}; + +class SaveRecentBooksRunnable : public DBRunnable { + +public: + SaveRecentBooksRunnable(DBConnection &connection); + bool run(); + void setBooks(const BookList &books); + +private: + BookList myBooks; + + shared_ptr<DBCommand> myClearRecentBooks; + shared_ptr<DBCommand> myInsertRecentBooks; +}; + +class SaveBookStateStackRunnable : public DBRunnable { + +public: + SaveBookStateStackRunnable(DBConnection &connection); + bool run(); + void setState(int bookId, const std::deque<ReadingState > &stack); + +private: + int myBookId; + std::deque<ReadingState > myStack; + + shared_ptr<DBCommand> myTrimBookStateStack; + shared_ptr<DBCommand> mySetBookStateStack; +}; + +class DeleteFileEntriesRunnable : public DBRunnable { + +public: + DeleteFileEntriesRunnable(DBConnection &connection); + bool run(); + void setFileId(int fileId); + +private: + bool doDelete(int fileId); + +private: + int myFileId; + + shared_ptr<DBCommand> myDeleteFileEntries; + shared_ptr<DBCommand> myLoadFileEntryIds; +}; + +class DeleteBookRunnable : public DBRunnable { + +public: + DeleteBookRunnable(DBConnection &connection); + bool run(); + void setFileName(const std::string &fileName); + +private: + std::string myFileName; + + shared_ptr<FindFileIdRunnable> myFindFileId; + shared_ptr<DBCommand> myDeleteFile; +}; + + +inline InitBooksDBRunnable::InitBooksDBRunnable(DBConnection &connection) : myConnection(connection) {} +inline ClearBooksDBRunnable::ClearBooksDBRunnable(DBConnection &connection) : myConnection(connection) {} + +inline void SaveFileEntriesRunnable::setEntries(const std::string &fileName, const std::vector<std::string> &entries) { + myFileName = fileName; + myEntries = entries; // copy vector +} + +inline void SaveBookStateStackRunnable::setState(int bookId, const std::deque<ReadingState > &stack) { + myBookId = bookId; + myStack = stack; // copy deque +} + +inline void DeleteFileEntriesRunnable::setFileId(int fileId) { myFileId = fileId; } + +inline void DeleteBookRunnable::setFileName(const std::string &fileName) { myFileName = fileName; } + +/* + * Load & Modify Runnables + */ + +class FindFileIdRunnable : public DBRunnable { + +public: + FindFileIdRunnable(DBConnection &connection); + bool run(); + void setFileName(const std::string &fileName, bool add = false); + + int fileId() const; + +private: + std::string myFileName; + bool myAdd; + int myFileId; + + shared_ptr<DBCommand> myFindFileId; + shared_ptr<DBCommand> myAddFile; +}; + + +/* + * Load Runnables + */ + +class LoadFileEntriesRunnable : public DBRunnable { + +public: + LoadFileEntriesRunnable(DBConnection &connection); + bool run(); + void setFileName(const std::string &fileName); + void collectEntries(std::vector<std::string> &entries); + +private: + std::string myFileName; + std::vector<std::string> myEntries; + + shared_ptr<FindFileIdRunnable> myFindFileId; + + shared_ptr<DBCommand> myLoadFileEntries; +}; + +class LoadRecentBooksRunnable : public DBRunnable { + +public: + LoadRecentBooksRunnable(DBConnection &connection); + bool run(); + void collectFileIds(std::vector<int> &fileIds); + +private: + std::vector<int> myFileIds; + + shared_ptr<DBCommand> myLoadRecentBooks; +}; + +#endif /* __DBRUNNABLES_H__ */ diff --git a/fbreader/src/database/booksdb/runnables/ClearBooksDBRunnable.cpp b/fbreader/src/database/booksdb/runnables/ClearBooksDBRunnable.cpp new file mode 100644 index 0000000..c0c9063 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/ClearBooksDBRunnable.cpp @@ -0,0 +1,46 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool ClearBooksDBRunnable::run() { + shared_ptr<DBCommand> cmd; + + cmd = SQLiteFactory::createCommand(BooksDBQuery::CLEAR_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(BooksDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(BooksDBQuery::SECOND_INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + return true; +} + + diff --git a/fbreader/src/database/booksdb/runnables/DeleteBookRunnable.cpp b/fbreader/src/database/booksdb/runnables/DeleteBookRunnable.cpp new file mode 100644 index 0000000..e9e2c14 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/DeleteBookRunnable.cpp @@ -0,0 +1,37 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +DeleteBookRunnable::DeleteBookRunnable(DBConnection &connection) { + myFindFileId = new FindFileIdRunnable(connection); + myDeleteFile = SQLiteFactory::createCommand(BooksDBQuery::DELETE_FILE, connection, "@file_id", DBValue::DBINT); +} + +bool DeleteBookRunnable::run() { + myFindFileId->setFileName(myFileName, true); + if (!myFindFileId->run()) { + return false; + } + + (DBIntValue &) *myDeleteFile->parameter("@file_id").value() = myFindFileId->fileId(); + return myDeleteFile->execute(); +} + diff --git a/fbreader/src/database/booksdb/runnables/DeleteFileEntriesRunnable.cpp b/fbreader/src/database/booksdb/runnables/DeleteFileEntriesRunnable.cpp new file mode 100644 index 0000000..065a4c2 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/DeleteFileEntriesRunnable.cpp @@ -0,0 +1,60 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +DeleteFileEntriesRunnable::DeleteFileEntriesRunnable(DBConnection &connection) { + myDeleteFileEntries = SQLiteFactory::createCommand(BooksDBQuery::DELETE_FILE_ENTRIES, connection, "@file_id", DBValue::DBINT); + myLoadFileEntryIds = SQLiteFactory::createCommand(BooksDBQuery::LOAD_FILE_ENTRY_IDS, connection, "@file_id", DBValue::DBINT); +} + +bool DeleteFileEntriesRunnable::run() { + return doDelete(myFileId); +} + +bool DeleteFileEntriesRunnable::doDelete(int fileId) { + (DBIntValue &) *myLoadFileEntryIds->parameter("@file_id").value() = fileId; + shared_ptr<DBDataReader> reader = myLoadFileEntryIds->executeReader(); + if (reader.isNull()) { + return false; + } + + std::vector<int> fileIds; + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT /* file_id */ ) { + reader->close(); + return false; + } + fileIds.push_back(reader->intValue(0)); + } + reader->close(); + + if (fileIds.empty()) { + return true; + } + for (std::vector<int>::const_iterator it = fileIds.begin(); it != fileIds.end(); ++it) { + if (!doDelete(*it)) { + return false; + } + } + (DBIntValue &) *myDeleteFileEntries->parameter("@file_id").value() = fileId; + return myDeleteFileEntries->execute(); +} + diff --git a/fbreader/src/database/booksdb/runnables/FindFileIdRunnable.cpp b/fbreader/src/database/booksdb/runnables/FindFileIdRunnable.cpp new file mode 100644 index 0000000..4461c4f --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/FindFileIdRunnable.cpp @@ -0,0 +1,123 @@ +/* + * 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 <ZLibrary.h> +#include <ZLFile.h> + +#include "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +static const std::string FIND_FILE_ID = + "SELECT file_id FROM Files" \ + " WHERE name = @name AND coalesce(parent_id, 0) = @parent_id;"; + +static const std::string ADD_FILE = + "INSERT INTO Files (name, parent_id, size)" \ + " VALUES(@name, nullif(@parent_id, 0), nullif(@size, 0));" \ + " SELECT last_insert_rowid() AS file_id;"; + +FindFileIdRunnable::FindFileIdRunnable(DBConnection &connection) { + myFindFileId = SQLiteFactory::createCommand(FIND_FILE_ID, connection, "@name", DBValue::DBTEXT, "@parent_id", DBValue::DBINT); + myAddFile = SQLiteFactory::createCommand(ADD_FILE, connection, "@name", DBValue::DBTEXT, "@parent_id", DBValue::DBINT, "@size", DBValue::DBINT); +} + +bool FindFileIdRunnable::run() { + const std::string resolvedPath = ZLFile(myFileName).resolvedPath(); + const std::string physPath = ZLFile(resolvedPath).physicalFilePath(); + const std::string dirName = physPath.substr(0, physPath.rfind(ZLibrary::FileNameDelimiter)); + + DBTextValue &findName = (DBTextValue &) *myFindFileId->parameter("@name").value(); + DBIntValue &findParent = (DBIntValue &) *myFindFileId->parameter("@parent_id").value(); + + DBTextValue &addName = (DBTextValue &) *myAddFile->parameter("@name").value(); + DBIntValue &addParent = (DBIntValue &) *myAddFile->parameter("@parent_id").value(); + ((DBIntValue &) *myAddFile->parameter("@size").value()) = 0; + + std::size_t index = dirName.length() + 1; + findName = dirName; + findParent = 0; + while (true) { + shared_ptr<DBValue> physId = myFindFileId->executeScalar(); + if (physId.isNull() || physId->type() != DBValue::DBINT || ((DBIntValue &) *physId).value() == 0) { + if (!myAdd) { + return false; + } + addName = findName.value(); + addParent = findParent.value(); + physId = myAddFile->executeScalar(); + if (physId.isNull() || physId->type() != DBValue::DBINT || ((DBIntValue &) *physId).value() == 0) { + return false; + } + } + if (index == 0) { + myFileId = ((DBIntValue &) *physId).value(); + return true; + } + std::size_t index2 = resolvedPath.find(BooksDBQuery::ArchiveEntryDelimiter, index); + findName = resolvedPath.substr(index, index2 - index); + index = index2 + 1; + findParent = ((DBIntValue &) *physId).value(); + } +} + +void FindFileIdRunnable::setFileName(const std::string &fileName, bool add) { + myFileName = fileName; + myAdd = add; + myFileId = 0; +} + +int FindFileIdRunnable::fileId() const { + return myFileId; +} + +SaveFileEntriesRunnable::SaveFileEntriesRunnable(DBConnection &connection) { + myAddFile = SQLiteFactory::createCommand(ADD_FILE, connection, "@name", DBValue::DBTEXT, "@parent_id", DBValue::DBINT, "@size", DBValue::DBINT); + + myFindFileId = new FindFileIdRunnable(connection); + myDeleteFileEntries = new DeleteFileEntriesRunnable(connection); +} + +bool SaveFileEntriesRunnable::run() { + myFindFileId->setFileName(myFileName, true); + if (!myFindFileId->run()) { + return false; + } + + myDeleteFileEntries->setFileId(myFindFileId->fileId()); + if (!myDeleteFileEntries->run()) { + return false; + } + + DBTextValue &addName = (DBTextValue &) *myAddFile->parameter("@name").value(); + ((DBIntValue &) *myAddFile->parameter("@parent_id").value()) = myFindFileId->fileId(); + ((DBIntValue &) *myAddFile->parameter("@size").value()) = 0; + + for (std::vector<std::string>::const_iterator it = myEntries.begin(); it != myEntries.end(); ++it) { + const std::string &entry = (*it); + if (entry.empty()) { + continue; + } + addName = entry; + if (!myAddFile->execute()) { + return false; + } + } + return true; +} + diff --git a/fbreader/src/database/booksdb/runnables/InitBooksDBRunnable.cpp b/fbreader/src/database/booksdb/runnables/InitBooksDBRunnable.cpp new file mode 100644 index 0000000..b8a4b01 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/InitBooksDBRunnable.cpp @@ -0,0 +1,40 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool InitBooksDBRunnable::run() { + shared_ptr<DBCommand> cmd; + cmd = SQLiteFactory::createCommand(BooksDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(BooksDBQuery::SECOND_INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + return true; +} + + diff --git a/fbreader/src/database/booksdb/runnables/LoadFileEntriesRunnable.cpp b/fbreader/src/database/booksdb/runnables/LoadFileEntriesRunnable.cpp new file mode 100644 index 0000000..3668b83 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/LoadFileEntriesRunnable.cpp @@ -0,0 +1,68 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +LoadFileEntriesRunnable::LoadFileEntriesRunnable(DBConnection &connection) { + myLoadFileEntries = SQLiteFactory::createCommand(BooksDBQuery::LOAD_FILE_ENTRIES, connection, "@file_id", DBValue::DBINT); + + myFindFileId = new FindFileIdRunnable(connection); +} + +bool LoadFileEntriesRunnable::run() { + DBCommand &cmd = *myLoadFileEntries; + + myFindFileId->setFileName(myFileName); + if (!myFindFileId->run()) { + return false; + } + ((DBIntValue &) *cmd.parameter("@file_id").value()) = myFindFileId->fileId(); + + shared_ptr<DBDataReader> reader = cmd.executeReader(); + + if (reader.isNull()) { + return false; + } + + myEntries.clear(); + + bool res = true; + while (reader->next()) { + if (reader->type(0) != DBValue::DBTEXT /* name */) { + res = false; + continue; + } + myEntries.push_back( + myFileName + BooksDBQuery::ArchiveEntryDelimiter + + reader->textValue(0, std::string()) + ); + } + reader->close(); + return res; +} + +void LoadFileEntriesRunnable::setFileName(const std::string &fileName) { + myFileName = fileName; +} + +void LoadFileEntriesRunnable::collectEntries(std::vector<std::string> &entries) { + myEntries.swap(entries); + myEntries.clear(); +} diff --git a/fbreader/src/database/booksdb/runnables/LoadRecentBooksRunnable.cpp b/fbreader/src/database/booksdb/runnables/LoadRecentBooksRunnable.cpp new file mode 100644 index 0000000..06e6f79 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/LoadRecentBooksRunnable.cpp @@ -0,0 +1,51 @@ +/* + * 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 "../DBRunnables.h" +#include "../../../library/Author.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +LoadRecentBooksRunnable::LoadRecentBooksRunnable(DBConnection &connection) { + myLoadRecentBooks = SQLiteFactory::createCommand(BooksDBQuery::LOAD_RECENT_BOOKS, connection); +} + +bool LoadRecentBooksRunnable::run() { + shared_ptr<DBDataReader> reader = myLoadRecentBooks->executeReader(); + if (reader.isNull()) { + return false; + } + myFileIds.clear(); + + bool res = true; + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT /* file_id */) { + res = false; + continue; + } + const int fileId = reader->intValue(0); + myFileIds.push_back(fileId); + } + reader->close(); + return res; +} + +void LoadRecentBooksRunnable::collectFileIds(std::vector<int> &fileIds) { + myFileIds.swap(fileIds); + myFileIds.clear(); +} diff --git a/fbreader/src/database/booksdb/runnables/SaveAuthorsRunnable.cpp b/fbreader/src/database/booksdb/runnables/SaveAuthorsRunnable.cpp new file mode 100644 index 0000000..7336a74 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/SaveAuthorsRunnable.cpp @@ -0,0 +1,75 @@ +/* + * 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 <algorithm> + +#include "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../../library/Author.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveAuthorsRunnable::SaveAuthorsRunnable(DBConnection &connection) { + mySetBookAuthor = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOK_AUTHOR, connection, "@author_id", DBValue::DBINT, "@book_id", DBValue::DBINT, "@author_index", DBValue::DBINT); + myTrimBookAuthors = SQLiteFactory::createCommand(BooksDBQuery::TRIM_BOOK_AUTHORS, connection, "@book_id", DBValue::DBINT, "@authors_number", DBValue::DBINT); + myFindAuthorId = SQLiteFactory::createCommand(BooksDBQuery::FIND_AUTHOR_ID, connection, "@name", DBValue::DBTEXT, "@sort_key", DBValue::DBTEXT); + myAddAuthor = SQLiteFactory::createCommand(BooksDBQuery::ADD_AUTHOR, connection, "@name", DBValue::DBTEXT, "@sort_key", DBValue::DBTEXT); +} + +bool SaveAuthorsRunnable::run() { + if (myBook->bookId() == 0) { + return false; + } + const AuthorList &bookAuthors = myBook->authors(); // save link to vector + + ((DBIntValue &) *mySetBookAuthor->parameter("@book_id").value()) = myBook->bookId(); + DBIntValue &setAuthorId = (DBIntValue &) *mySetBookAuthor->parameter("@author_id").value(); + DBIntValue &setAuthorIndex = (DBIntValue &) *mySetBookAuthor->parameter("@author_index").value(); + DBTextValue &findAuthor = (DBTextValue &) *myFindAuthorId->parameter("@name").value(); + DBTextValue &findSortKey = (DBTextValue &) *myFindAuthorId->parameter("@sort_key").value(); + DBTextValue &addAuthor = (DBTextValue &) *myAddAuthor->parameter("@name").value(); + DBTextValue &addSortKey = (DBTextValue &) *myAddAuthor->parameter("@sort_key").value(); + + int index = 0; + for (AuthorList::const_iterator it = bookAuthors.begin(); it != bookAuthors.end(); ++it) { + const Author &author = **it; + findAuthor.setValue( author.name() ); + findSortKey.setValue( author.sortKey() ); + shared_ptr<DBValue> tableAuthorId = myFindAuthorId->executeScalar(); + if (tableAuthorId.isNull() || tableAuthorId->type() != DBValue::DBINT || ((DBIntValue &) *tableAuthorId).value() == 0) { + addAuthor.setValue( author.name() ); + addSortKey.setValue( author.sortKey() ); + tableAuthorId = myAddAuthor->executeScalar(); + if (tableAuthorId.isNull() || tableAuthorId->type() != DBValue::DBINT || ((DBIntValue &) *tableAuthorId).value() == 0) { + return false; + } + } + setAuthorId = ((DBIntValue &) *tableAuthorId).value(); + setAuthorIndex = ++index; + if (!mySetBookAuthor->execute()) { + return false; + } + } + ((DBIntValue &) *myTrimBookAuthors->parameter("@book_id").value()) = myBook->bookId(); + ((DBIntValue &) *myTrimBookAuthors->parameter("@authors_number").value()) = index; + return myTrimBookAuthors->execute(); +} + +void SaveAuthorsRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/fbreader/src/database/booksdb/runnables/SaveBookRunnable.cpp b/fbreader/src/database/booksdb/runnables/SaveBookRunnable.cpp new file mode 100644 index 0000000..7cf8dff --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/SaveBookRunnable.cpp @@ -0,0 +1,43 @@ +/* + * 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 "../DBRunnables.h" +#include "../../../library/Book.h" + +SaveBookRunnable::SaveBookRunnable(SaveTableBookRunnable &saveTableBook, SaveAuthorsRunnable &saveAuthors, + SaveSeriesRunnable &saveSeries, SaveTagsRunnable &saveTags) : + mySaveTableBook(saveTableBook), + mySaveAuthors(saveAuthors), + mySaveSeries(saveSeries), + mySaveTags(saveTags) { +} + +bool SaveBookRunnable::run() { + return mySaveTableBook.run() + && mySaveAuthors.run() + && mySaveSeries.run() + && mySaveTags.run(); +} + +void SaveBookRunnable::setBook(shared_ptr<Book> book) { + mySaveTableBook.setBook(book); + mySaveAuthors.setBook(book); + mySaveTags.setBook(book); + mySaveSeries.setBook(book); +} diff --git a/fbreader/src/database/booksdb/runnables/SaveBookStateStackRunnable.cpp b/fbreader/src/database/booksdb/runnables/SaveBookStateStackRunnable.cpp new file mode 100644 index 0000000..85d4a89 --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/SaveBookStateStackRunnable.cpp @@ -0,0 +1,56 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + + +SaveBookStateStackRunnable::SaveBookStateStackRunnable(DBConnection &connection) { + myTrimBookStateStack = SQLiteFactory::createCommand(BooksDBQuery::TRIM_BOOK_STATE_STACK, connection, "@book_id", DBValue::DBINT, "@stackSize", DBValue::DBINT); + mySetBookStateStack = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOK_STATE_STACK, connection, "@book_id", DBValue::DBINT, "@position", DBValue::DBINT, "@paragraph", DBValue::DBINT, "@word", DBValue::DBINT, "@char", DBValue::DBINT); +} + +bool SaveBookStateStackRunnable::run() { + ((DBIntValue &) *myTrimBookStateStack->parameter("@book_id").value()) = myBookId; + ((DBIntValue &) *myTrimBookStateStack->parameter("@stackSize").value()) = myStack.size(); + + if (!myTrimBookStateStack->execute()) { + return false; + } + + ((DBIntValue &) *mySetBookStateStack->parameter("@book_id").value()) = myBookId; + + DBIntValue &savePosition = (DBIntValue &) *mySetBookStateStack->parameter("@position").value(); + DBIntValue &saveParagraph = (DBIntValue &) *mySetBookStateStack->parameter("@paragraph").value(); + DBIntValue &saveWord = (DBIntValue &) *mySetBookStateStack->parameter("@word").value(); + DBIntValue &saveChar = (DBIntValue &) *mySetBookStateStack->parameter("@char").value(); + + for (std::size_t i = 0; i < myStack.size(); ++i) { + const ReadingState &pos = myStack[i]; + savePosition = i + 1; + saveParagraph = pos.Paragraph; + saveWord = pos.Word; + saveChar = pos.Character; + if (!mySetBookStateStack->execute()) { + return false; + } + } + return true; +} + diff --git a/fbreader/src/database/booksdb/runnables/SaveRecentBooksRunnable.cpp b/fbreader/src/database/booksdb/runnables/SaveRecentBooksRunnable.cpp new file mode 100644 index 0000000..1c355ed --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/SaveRecentBooksRunnable.cpp @@ -0,0 +1,49 @@ +/* + * 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 "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveRecentBooksRunnable::SaveRecentBooksRunnable(DBConnection &connection) { + myClearRecentBooks = SQLiteFactory::createCommand(BooksDBQuery::CLEAR_RECENT_BOOKS, connection); + myInsertRecentBooks = SQLiteFactory::createCommand(BooksDBQuery::INSERT_RECENT_BOOKS, connection, "@book_id", DBValue::DBINT); +} + +bool SaveRecentBooksRunnable::run() { + if (!myClearRecentBooks->execute()) { + return false; + } + DBIntValue &insertBookId = (DBIntValue &) *myInsertRecentBooks->parameter("@book_id").value(); + for (BookList::const_iterator it = myBooks.begin(); it != myBooks.end(); ++it) { + shared_ptr<Book> book = (*it); + if (book->bookId() == 0) { + return false; + } + insertBookId = book->bookId(); + if (!myInsertRecentBooks->execute()) { + return false; + } + } + return true; +} + +void SaveRecentBooksRunnable::setBooks(const BookList &books) { + myBooks = books; // copy vector +} diff --git a/fbreader/src/database/booksdb/runnables/SaveSeriesRunnable.cpp b/fbreader/src/database/booksdb/runnables/SaveSeriesRunnable.cpp new file mode 100644 index 0000000..e56777b --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/SaveSeriesRunnable.cpp @@ -0,0 +1,58 @@ +/* + * 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 "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveSeriesRunnable::SaveSeriesRunnable(DBConnection &connection) { + mySetBookSeries = SQLiteFactory::createCommand(BooksDBQuery::SET_BOOKSERIES, connection, "@book_id", DBValue::DBINT, "@series_id", DBValue::DBINT, "@book_index", DBValue::DBTEXT); + myDeleteBookSeries = SQLiteFactory::createCommand(BooksDBQuery::DELETE_BOOKSERIES, connection, "@book_id", DBValue::DBINT); + myFindSeriesId = SQLiteFactory::createCommand(BooksDBQuery::FIND_SERIES_ID, connection, "@name", DBValue::DBTEXT); + myAddSeries = SQLiteFactory::createCommand(BooksDBQuery::ADD_SERIES, connection, "@name", DBValue::DBTEXT); +} + +bool SaveSeriesRunnable::run() { + if (myBook->bookId() == 0) { + return false; + } + + if (myBook->seriesTitle().empty()) { + ((DBIntValue &) *myDeleteBookSeries->parameter("@book_id").value()) = myBook->bookId(); + return myDeleteBookSeries->execute(); + } + + ((DBTextValue &) *myFindSeriesId->parameter("@name").value()) = myBook->seriesTitle(); + shared_ptr<DBValue> tableSeriesId = myFindSeriesId->executeScalar(); + if (tableSeriesId.isNull() || tableSeriesId->type() != DBValue::DBINT || ((DBIntValue &) *tableSeriesId).value() == 0) { + ((DBTextValue &) *myAddSeries->parameter("@name").value()) = myBook->seriesTitle(); + tableSeriesId = myAddSeries->executeScalar(); + if (tableSeriesId.isNull() || tableSeriesId->type() != DBValue::DBINT || ((DBIntValue &) *tableSeriesId).value() == 0) { + return false; + } + } + ((DBIntValue &) *mySetBookSeries->parameter("@book_id").value()) = myBook->bookId(); + mySetBookSeries->parameter("@series_id").setValue( tableSeriesId ); + ((DBTextValue &) *mySetBookSeries->parameter("@book_index").value()) = myBook->indexInSeries().value(); + return mySetBookSeries->execute(); +} + +void SaveSeriesRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/fbreader/src/database/booksdb/runnables/SaveTableBookRunnable.cpp b/fbreader/src/database/booksdb/runnables/SaveTableBookRunnable.cpp new file mode 100644 index 0000000..770963e --- /dev/null +++ b/fbreader/src/database/booksdb/runnables/SaveTableBookRunnable.cpp @@ -0,0 +1,80 @@ +/* + * 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 "../DBRunnables.h" +#include "../../../library/Book.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveTableBookRunnable::SaveTableBookRunnable(DBConnection &connection) { + myFindBookId = SQLiteFactory::createCommand(BooksDBQuery::FIND_BOOK_ID, connection, "@file_id", DBValue::DBINT); + + myAddBook = SQLiteFactory::createCommand(BooksDBQuery::ADD_BOOK, connection, "@encoding", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@title", DBValue::DBTEXT, "@file_id", DBValue::DBINT); + myUpdateBook = SQLiteFactory::createCommand(BooksDBQuery::UPDATE_BOOK, connection, "@encoding", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@title", DBValue::DBTEXT, "@book_id", DBValue::DBINT); + + myFindFileId = new FindFileIdRunnable(connection); +} + +bool SaveTableBookRunnable::run() { + if (myBook->bookId() != 0) { + return updateTableBook(myBook); + } + + myFindFileId->setFileName(myBook->file().path(), true); + if (!myFindFileId->run()) { + return false; + } + const int fileId = myFindFileId->fileId(); + + ((DBIntValue &) *myFindBookId->parameter("@file_id").value()) = fileId; + shared_ptr<DBValue> dbBookId = myFindBookId->executeScalar(); + + if (dbBookId.isNull() || dbBookId->type() != DBValue::DBINT || ((DBIntValue &) *dbBookId).value() == 0) { + return addTableBook(myBook, fileId); + } else { + myBook->setBookId( ((DBIntValue &) *dbBookId).value() ); + return updateTableBook(myBook); + } +} + +bool SaveTableBookRunnable::addTableBook(const shared_ptr<Book> book, int fileId) { + + ((DBTextValue &) *myAddBook->parameter("@encoding").value()) = book->encoding(); + ((DBTextValue &) *myAddBook->parameter("@language").value()) = book->language(); + ((DBTextValue &) *myAddBook->parameter("@title").value()) = book->title(); + ((DBIntValue &) *myAddBook->parameter("@file_id").value()) = fileId; + shared_ptr<DBValue> dbBookId = myAddBook->executeScalar(); + + if (dbBookId.isNull() || dbBookId->type() != DBValue::DBINT || ((DBIntValue &) *dbBookId).value() == 0) { + return false; + } + book->setBookId(((DBIntValue&)*dbBookId).value()); + return true; +} + +bool SaveTableBookRunnable::updateTableBook(const shared_ptr<Book> book) { + ((DBTextValue&)*myUpdateBook->parameter("@encoding").value()) = book->encoding(); + ((DBTextValue&)*myUpdateBook->parameter("@language").value()) = book->language(); + ((DBTextValue&)*myUpdateBook->parameter("@title").value()) = book->title(); + ((DBIntValue&)*myUpdateBook->parameter("@book_id").value()) = book->bookId(); + return myUpdateBook->execute(); +} + +void SaveTableBookRunnable::setBook(shared_ptr<Book> book) { + myBook = book; +} diff --git a/fbreader/src/database/networkdb/DBRunnables.h b/fbreader/src/database/networkdb/DBRunnables.h new file mode 100644 index 0000000..e9633f6 --- /dev/null +++ b/fbreader/src/database/networkdb/DBRunnables.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2004-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 __DBRUNNABLES_H__ +#define __DBRUNNABLES_H__ + +#include "../sqldb/DBConnection.h" +#include "../sqldb/DBCommand.h" +#include "../sqldb/DBRunnable.h" + +#include "NetworkDBQuery.h" + +#include "../../network/NetworkLink.h" +#include "../../network/opds/OPDSLink.h" + +class InitNetworkDBRunnable : public DBRunnable { + +public: + InitNetworkDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class ClearNetworkDBRunnable : public DBRunnable { + +public: + ClearNetworkDBRunnable(DBConnection &connection); + bool run(); + +private: + DBConnection &myConnection; +}; + +class SaveNetworkLinkRunnable : public DBRunnable { + +public: + SaveNetworkLinkRunnable(DBConnection &connection); + bool run(); + void setNetworkLink(shared_ptr<NetworkLink> link); + +private: + bool addNetworkLink(); + bool updateNetworkLink(int linkId); + bool updateNetworkLinkUrls(int linkId); + +private: + shared_ptr<NetworkLink> myNetworkLink; + + shared_ptr<DBCommand> myFindNetworkLinkId; + shared_ptr<DBCommand> myAddNetworkLink; + shared_ptr<DBCommand> myUpdateNetworkLink; + + shared_ptr<DBCommand> myFindNetworkLinkUrls; + shared_ptr<DBCommand> myAddNetworkLinkUrl; + shared_ptr<DBCommand> myUpdateNetworkLinkUrl; + shared_ptr<DBCommand> myDeleteNetworkLinkUrl; + +}; + +inline InitNetworkDBRunnable::InitNetworkDBRunnable(DBConnection &connection) : myConnection(connection) {} +inline ClearNetworkDBRunnable::ClearNetworkDBRunnable(DBConnection &connection) : myConnection(connection) {} + +#endif /* __DBRUNNABLES_H__ */ diff --git a/fbreader/src/database/networkdb/NetworkDB.cpp b/fbreader/src/database/networkdb/NetworkDB.cpp new file mode 100644 index 0000000..f422643 --- /dev/null +++ b/fbreader/src/database/networkdb/NetworkDB.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2004-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 <ZLibrary.h> +#include <ZLDir.h> + +#include "NetworkDB.h" + +shared_ptr<NetworkDB> NetworkDB::ourInstance = 0; + +const std::string NetworkDB::DATABASE_NAME = "network.db"; + +NetworkDB &NetworkDB::Instance() { + if (ourInstance.isNull()) { + ZLFile dir(databaseDirName()); + dir.directory(true); + ZLFile file(databaseDirName() + ZLibrary::FileNameDelimiter + DATABASE_NAME); + ourInstance = new NetworkDB(file.physicalFilePath()); + ourInstance->initDatabase(); + } + return *ourInstance; +} + +NetworkDB::NetworkDB(const std::string &path) : SQLiteDataBase(path), myInitialized(false) { + initCommands(); +} + +NetworkDB::~NetworkDB() { +} + +bool NetworkDB::initDatabase() { + if (isInitialized()) { + return true; + } + + if (!open()) { + return false; + } + + myInitialized = true; + + shared_ptr<DBRunnable> runnable = new InitNetworkDBRunnable(connection()); + if (!executeAsTransaction(*runnable)) { + myInitialized = false; + close(); + return false; + } + + return true; +} + +void NetworkDB::initCommands() { + myLoadNetworkLinks = SQLiteFactory::createCommand(NetworkDBQuery::LOAD_NETWORK_LINKS, connection()); + myLoadNetworkLinkUrls = SQLiteFactory::createCommand(NetworkDBQuery::LOAD_NETWORK_LINKURLS, connection(), "@link_id", DBValue::DBINT); + myFindNetworkLinkId = SQLiteFactory::createCommand(NetworkDBQuery::FIND_NETWORK_LINK_ID, connection(), "@site_name", DBValue::DBTEXT); + myDeleteNetworkLinkUrls = SQLiteFactory::createCommand(NetworkDBQuery::DELETE_NETWORK_LINKURLS, connection(), "@link_id", DBValue::DBINT); + myDeleteNetworkLink = SQLiteFactory::createCommand(NetworkDBQuery::DELETE_NETWORK_LINK, connection(), "@link_id", DBValue::DBINT); + + mySaveNetworkLink = new SaveNetworkLinkRunnable(connection()); +} + +bool NetworkDB::clearDatabase() { + if (!isInitialized()) { + return false; + } + shared_ptr<DBRunnable> runnable = new ClearNetworkDBRunnable(connection()); + return executeAsTransaction(*runnable); +} + + +bool NetworkDB::saveNetworkLink(shared_ptr<NetworkLink> link) { + if (!isInitialized()) { + return false; + } + mySaveNetworkLink->setNetworkLink(link); + bool result = executeAsTransaction(*mySaveNetworkLink); + return result; +} + +bool NetworkDB::loadNetworkLinks(std::vector<shared_ptr<NetworkLink> >& links) { + shared_ptr<DBDataReader> reader = myLoadNetworkLinks->executeReader(); + + links.clear(); + + while (reader->next()) { + if (reader->type(0) != DBValue::DBINT) {/* link_id */ + return false; + } + std::map<std::string,std::string> linkUrls; + ((DBIntValue &) *myLoadNetworkLinkUrls->parameter("@link_id").value()) = reader->intValue(0); + shared_ptr<DBDataReader> urlreader = myLoadNetworkLinkUrls->executeReader(); + long t = 0; + while (urlreader->next()) { + linkUrls[urlreader->textValue(0, std::string())] = urlreader->textValue(1, std::string()); + t = urlreader->intValue(2); + } + shared_ptr<ATOMUpdated> atomUpdated = new ATOMUpdated(); + atomUpdated->setLongSeconds_stupid(t); + std::string iconUrl; + if (linkUrls .count("icon") != 0) { + iconUrl = linkUrls["icon"]; + linkUrls.erase("icon"); + } + std::string siteName = reader->textValue(2, std::string()); + std::string predId = reader->textValue(5, std::string()); + std::string title = reader->textValue(1, std::string()); + std::string summary = reader->textValue(3, std::string()); + std::string language = reader->textValue(4, std::string()); + bool isEnabled = reader->intValue(6) == 1; + + shared_ptr<NetworkLink> link = new OPDSLink(siteName); + link->setTitle(title); + link->setSummary(summary); + link->setLanguage(language); + link->setIcon(iconUrl); + link->setLinks(linkUrls); + link->setPredefinedId(predId); + link->setEnabled(isEnabled); + link->setUpdated(atomUpdated); + links.push_back(link); + } + return true; +} + +bool NetworkDB::deleteNetworkLink(const std::string &siteName){ + ((DBTextValue &) *myFindNetworkLinkId->parameter("@site_name").value()) = siteName; + shared_ptr<DBDataReader> reader = myFindNetworkLinkId->executeReader(); + if (reader.isNull() || !reader->next()) { + return false; + } + int linkId = reader->intValue(0); + ((DBIntValue &) *myDeleteNetworkLink->parameter("@link_id").value()) = linkId; + ((DBIntValue &) *myDeleteNetworkLinkUrls->parameter("@link_id").value()) = linkId; + return myDeleteNetworkLinkUrls->execute() && myDeleteNetworkLink->execute(); + +} diff --git a/fbreader/src/database/networkdb/NetworkDB.h b/fbreader/src/database/networkdb/NetworkDB.h new file mode 100644 index 0000000..d4761a6 --- /dev/null +++ b/fbreader/src/database/networkdb/NetworkDB.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004-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 __NETWORKDB_H__ +#define __NETWORKDB_H__ + +#include <set> +#include <map> +#include <deque> + +#include "../sqldb/implsqlite/SQLiteDataBase.h" +#include "DBRunnables.h" + +class NetworkDB : public SQLiteDataBase { + +public: + static const std::string DATABASE_NAME; + + static NetworkDB &Instance(); + +private: + static shared_ptr<NetworkDB> ourInstance; + + NetworkDB(const std::string &path); + +public: + virtual ~NetworkDB(); + +public: + bool initDatabase(); + bool isInitialized() const; + bool clearDatabase(); + + bool saveNetworkLink(shared_ptr<NetworkLink> link); + bool loadNetworkLinks(std::vector<shared_ptr<NetworkLink> >& links); + bool deleteNetworkLink(const std::string &siteName); + +private: + void initCommands(); + +private: + bool myInitialized; + + shared_ptr<DBCommand> myLoadNetworkLinks; + shared_ptr<DBCommand> myFindNetworkLinkId; + shared_ptr<DBCommand> myDeleteNetworkLink; + shared_ptr<DBCommand> myDeleteNetworkLinkUrls; + shared_ptr<DBCommand> myLoadNetworkLinkUrls; + + shared_ptr<SaveNetworkLinkRunnable> mySaveNetworkLink; + +private: // disable copying + NetworkDB(const NetworkDB &); + const NetworkDB &operator = (const NetworkDB &); +}; + + +inline bool NetworkDB::isInitialized() const { return myInitialized; } + +#endif /* __NETWORKDB_H__ */ diff --git a/fbreader/src/database/networkdb/NetworkDBQuery.cpp b/fbreader/src/database/networkdb/NetworkDBQuery.cpp new file mode 100644 index 0000000..a8771cb --- /dev/null +++ b/fbreader/src/database/networkdb/NetworkDBQuery.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004-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 "NetworkDBQuery.h" + +const std::string NetworkDBQuery::INIT_DATABASE = \ + " CREATE TABLE IF NOT EXISTS Links( " \ + " link_id INTEGER PRIMARY KEY, " \ + " title TEXT NOT NULL, " \ + " site_name TEXT NOT NULL, " \ + " summary TEXT, " \ + " language TEXT, " \ + " predefined_id TEXT, " \ + " is_enabled INTEGER " \ + "); " \ + " " \ + "CREATE TABLE IF NOT EXISTS LinkUrls( " \ + " key TEXT NOT NULL, " \ + " link_id INTEGER NOT NULL REFERENCES Links(link_id), " \ + " url TEXT, " \ + " update_time INTEGER, " \ + " CONSTRAINT LinkUrls_PK PRIMARY KEY (key, link_id) " \ + "); "; + +const std::string NetworkDBQuery::CLEAR_DATABASE = \ + "DROP TABLE Links; " \ + "DROP TABLE LinkUrls; "; + + +const std::string NetworkDBQuery::FIND_NETWORK_LINK_ID = "SELECT link_id, predefined_id FROM Links WHERE site_name = @site_name; "; +const std::string NetworkDBQuery::ADD_NETWORK_LINK = \ + "INSERT INTO Links (title, site_name, summary, language, predefined_id, is_enabled) " \ + " VALUES ( " \ + " @title, " \ + " @site_name, " \ + " @summary, " \ + " nullif(@language,\"\"), " \ + " nullif(@predefined_id,\"\"), " \ + " @is_enabled " \ + " ); " \ + " " \ + "SELECT last_insert_rowid() AS link_id; "; + +const std::string NetworkDBQuery::DELETE_NETWORK_LINK = \ + "DELETE FROM Links WHERE link_id = @link_id; "; + +const std::string NetworkDBQuery::UPDATE_NETWORK_LINK = \ + "UPDATE Links SET " \ + " title = @title, " \ + " summary = @summary, " \ + " language = nullif(@language,\"\"), " \ + " predefined_id = nullif(@predefined_id,\"\"), " \ + " is_enabled = @is_enabled " \ + "WHERE " \ + " link_id = @link_id; "; + +const std::string NetworkDBQuery::ADD_NETWORK_LINKURL = \ + "INSERT INTO LinkUrls (key, link_id, url, update_time) " \ + " VALUES ( " \ + " @key, " \ + " @link_id, " \ + " @url, " \ + " @update_time " \ + " ); "; + +const std::string NetworkDBQuery::FIND_NETWORK_LINKURLS = "SELECT key, url, update_time FROM LinkUrls WHERE link_id = @link_id; "; + +const std::string NetworkDBQuery::UPDATE_NETWORK_LINKURL = \ + "UPDATE LinkUrls SET " \ + " url = @url, " \ + " update_time = @update_time " \ + "WHERE " \ + " link_id = @link_id AND key = @key; "; + +const std::string NetworkDBQuery::DELETE_NETWORK_LINKURLS = \ + "DELETE FROM LinkUrls " \ + "WHERE " \ + " link_id = @link_id; "; + +const std::string NetworkDBQuery::DELETE_NETWORK_LINKURL = \ + "DELETE FROM LinkUrls " \ + "WHERE " \ + " link_id = @link_id AND key = @key; "; + +const std::string NetworkDBQuery::LOAD_NETWORK_LINKS = "SELECT link_id, title, site_name, summary, language, predefined_id, is_enabled FROM Links; "; + +const std::string NetworkDBQuery::LOAD_NETWORK_LINKURLS = "SELECT key, url, update_time FROM LinkUrls WHERE link_id = @link_id; "; diff --git a/fbreader/src/database/networkdb/NetworkDBQuery.h b/fbreader/src/database/networkdb/NetworkDBQuery.h new file mode 100644 index 0000000..931705e --- /dev/null +++ b/fbreader/src/database/networkdb/NetworkDBQuery.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2004-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 __NETWORKDBQUERY_H__ +#define __NETWORKDBQUERY_H__ + +#include <string> + +class NetworkDBQuery { + +public: + static const std::string INIT_DATABASE; + static const std::string CLEAR_DATABASE; + + static const std::string FIND_NETWORK_LINK_ID; + static const std::string ADD_NETWORK_LINK; + static const std::string UPDATE_NETWORK_LINK; + static const std::string DELETE_NETWORK_LINK; + + static const std::string ADD_NETWORK_LINKURL; + static const std::string DELETE_NETWORK_LINKURLS; + static const std::string FIND_NETWORK_LINKURLS; + static const std::string DELETE_NETWORK_LINKURL; + static const std::string UPDATE_NETWORK_LINKURL; + + static const std::string LOAD_NETWORK_LINKS; + static const std::string LOAD_NETWORK_LINKURLS; + +private: // disable creation Instances + NetworkDBQuery(); +}; +#endif /* __NETWORKDBQUERY_H__ */ diff --git a/fbreader/src/database/networkdb/runnables/ClearNetworkDBRunnable.cpp b/fbreader/src/database/networkdb/runnables/ClearNetworkDBRunnable.cpp new file mode 100644 index 0000000..fe79ed3 --- /dev/null +++ b/fbreader/src/database/networkdb/runnables/ClearNetworkDBRunnable.cpp @@ -0,0 +1,39 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool ClearNetworkDBRunnable::run() { + shared_ptr<DBCommand> cmd; + + cmd = SQLiteFactory::createCommand(NetworkDBQuery::CLEAR_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + cmd = SQLiteFactory::createCommand(NetworkDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + + return true; +} + + diff --git a/fbreader/src/database/networkdb/runnables/InitNetworkDBRunnable.cpp b/fbreader/src/database/networkdb/runnables/InitNetworkDBRunnable.cpp new file mode 100644 index 0000000..d0730b7 --- /dev/null +++ b/fbreader/src/database/networkdb/runnables/InitNetworkDBRunnable.cpp @@ -0,0 +1,30 @@ +/* + * 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 "../DBRunnables.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +bool InitNetworkDBRunnable::run() { + shared_ptr<DBCommand> cmd; + cmd = SQLiteFactory::createCommand(NetworkDBQuery::INIT_DATABASE, myConnection); + if (!cmd->execute()) { + return false; + } + return true; +} diff --git a/fbreader/src/database/networkdb/runnables/SaveNetworkLinkRunnable.cpp b/fbreader/src/database/networkdb/runnables/SaveNetworkLinkRunnable.cpp new file mode 100644 index 0000000..4c80499 --- /dev/null +++ b/fbreader/src/database/networkdb/runnables/SaveNetworkLinkRunnable.cpp @@ -0,0 +1,138 @@ +/* + * 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 "../DBRunnables.h" +#include "../../../network/NetworkLink.h" +#include "../../sqldb/implsqlite/SQLiteFactory.h" + +SaveNetworkLinkRunnable::SaveNetworkLinkRunnable(DBConnection &connection) { + myFindNetworkLinkId = SQLiteFactory::createCommand(NetworkDBQuery::FIND_NETWORK_LINK_ID, connection, "@site_name", DBValue::DBTEXT); + myAddNetworkLink = SQLiteFactory::createCommand(NetworkDBQuery::ADD_NETWORK_LINK, connection, "@title", DBValue::DBTEXT, "@site_name", DBValue::DBTEXT, "@summary", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@predefined_id", DBValue::DBTEXT, "@is_enabled", DBValue::DBINT); + myUpdateNetworkLink = SQLiteFactory::createCommand(NetworkDBQuery::UPDATE_NETWORK_LINK, connection, "@title", DBValue::DBTEXT, "@summary", DBValue::DBTEXT, "@language", DBValue::DBTEXT, "@predefined_id", DBValue::DBTEXT, "@is_enabled", DBValue::DBINT, "@link_id", DBValue::DBINT); + + myFindNetworkLinkUrls = SQLiteFactory::createCommand(NetworkDBQuery::FIND_NETWORK_LINKURLS, connection, "@link_id", DBValue::DBINT); + myAddNetworkLinkUrl = SQLiteFactory::createCommand(NetworkDBQuery::ADD_NETWORK_LINKURL, connection, "@key", DBValue::DBTEXT, "@link_id", DBValue::DBINT, "@url", DBValue::DBTEXT, "@update_time", DBValue::DBINT); + myUpdateNetworkLinkUrl = SQLiteFactory::createCommand(NetworkDBQuery::UPDATE_NETWORK_LINKURL, connection, "@key", DBValue::DBTEXT, "@link_id", DBValue::DBINT, "@url", DBValue::DBTEXT, "@update_time", DBValue::DBINT); + myDeleteNetworkLinkUrl = SQLiteFactory::createCommand(NetworkDBQuery::DELETE_NETWORK_LINKURL, connection, "@key", DBValue::DBTEXT, "@link_id", DBValue::DBINT); +} + +bool SaveNetworkLinkRunnable::run() { + if (myNetworkLink.isNull()) { + return false; + } + ((DBTextValue &) *myFindNetworkLinkId->parameter("@site_name").value()) = myNetworkLink->getSiteName(); + shared_ptr<DBDataReader> reader = myFindNetworkLinkId->executeReader(); + if (reader.isNull() || !reader->next()) { + return addNetworkLink(); + } else if (myNetworkLink->isPredefined()) { + return updateNetworkLink(reader->intValue(0)) && updateNetworkLinkUrls(reader->intValue(0)); + } else { + //TODO implement for custom links + return false; + } + return false; +} + +bool SaveNetworkLinkRunnable::addNetworkLink() { + ((DBTextValue &) *myAddNetworkLink->parameter("@title").value()) = myNetworkLink->getTitle(); + ((DBTextValue &) *myAddNetworkLink->parameter("@site_name").value()) = myNetworkLink->getSiteName(); + ((DBTextValue &) *myAddNetworkLink->parameter("@summary").value()) = myNetworkLink->getSummary(); + ((DBTextValue &) *myAddNetworkLink->parameter("@language").value()) = myNetworkLink->getLanguage(); + ((DBTextValue &) *myAddNetworkLink->parameter("@predefined_id").value()) = myNetworkLink->getPredefinedId(); + ((DBIntValue &) *myAddNetworkLink->parameter("@is_enabled").value()) = myNetworkLink->isEnabled(); + shared_ptr<DBValue> dbLinkId = myAddNetworkLink->executeScalar(); + if (dbLinkId.isNull() || dbLinkId->type() != DBValue::DBINT || ((DBIntValue &) *dbLinkId).value() == 0) { + return false; + } + + bool allExecuted = true; + std::map<std::string,std::string> tempLinks = myNetworkLink->getLinks(); + if (myNetworkLink->getIcon() != std::string()) { + tempLinks["icon"] = myNetworkLink->getIcon(); + } + long t = 0; + if (myNetworkLink->getUpdated() != 0) { + t = myNetworkLink->getUpdated()->getLongSeconds_stupid(); + } + for (std::map<std::string,std::string>::iterator it = tempLinks.begin(); it != tempLinks.end(); ++it) { + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@key").value()) = it->first; + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@url").value()) = it->second; + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@link_id").value()) = ((DBIntValue &) *dbLinkId).value(); + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@update_time").value()) = t; + allExecuted = allExecuted && myAddNetworkLinkUrl->execute(); + } + return allExecuted; +} + +bool SaveNetworkLinkRunnable::updateNetworkLink(int linkId) { + ((DBTextValue &) *myUpdateNetworkLink->parameter("@title").value()) = myNetworkLink->getTitle(); + ((DBTextValue &) *myUpdateNetworkLink->parameter("@summary").value()) = myNetworkLink->getSummary(); + ((DBTextValue &) *myUpdateNetworkLink->parameter("@language").value()) = myNetworkLink->getLanguage(); + ((DBTextValue &) *myUpdateNetworkLink->parameter("@predefined_id").value()) = myNetworkLink->getPredefinedId(); + ((DBIntValue &) *myUpdateNetworkLink->parameter("@is_enabled").value()) = myNetworkLink->isEnabled(); + ((DBIntValue &) *myUpdateNetworkLink->parameter("@link_id").value()) = linkId; + + return myUpdateNetworkLink->execute(); +} + +bool SaveNetworkLinkRunnable::updateNetworkLinkUrls(int linkId) { + bool allExecuted = true; + ((DBIntValue &) *myFindNetworkLinkUrls->parameter("@link_id").value()) = linkId; + shared_ptr<DBDataReader> reader = myFindNetworkLinkUrls->executeReader(); + std::map<std::string,std::string> linksToCheck = myNetworkLink->getLinks(); + if (!myNetworkLink->getIcon().empty()) { + linksToCheck["icon"] = myNetworkLink->getIcon(); + } + long t = 0; + if (!myNetworkLink->getUpdated().isNull()) { + t = myNetworkLink->getUpdated()->getLongSeconds_stupid(); + } + while (reader->next()) { + if (reader->type(0) != DBValue::DBTEXT || reader->type(1) != DBValue::DBTEXT) { + return false; + } + std::string key = reader->textValue(0, std::string()); +// std::string url = reader->textValue(1, std::string()); + if (linksToCheck.count(key) == 0) { + ((DBTextValue &) *myDeleteNetworkLinkUrl->parameter("@key").value()) = key; + ((DBIntValue &) *myDeleteNetworkLinkUrl->parameter("@link_id").value()) = linkId; + allExecuted = allExecuted && myDeleteNetworkLinkUrl->execute(); + } else { + ((DBTextValue &) *myUpdateNetworkLinkUrl->parameter("@key").value()) = key; + ((DBTextValue &) *myUpdateNetworkLinkUrl->parameter("@url").value()) = linksToCheck[key]; + ((DBIntValue &) *myUpdateNetworkLinkUrl->parameter("@link_id").value()) = linkId; + ((DBIntValue &) *myUpdateNetworkLinkUrl->parameter("@update_time").value()) = t; + linksToCheck.erase(key); + allExecuted = allExecuted && myUpdateNetworkLinkUrl->execute(); + } + } + + for (std::map<std::string,std::string>::iterator it = linksToCheck.begin(); it != linksToCheck.end(); ++it) { + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@key").value()) = it->first; + ((DBTextValue &) *myAddNetworkLinkUrl->parameter("@url").value()) = it->second; + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@link_id").value()) = linkId; + ((DBIntValue &) *myAddNetworkLinkUrl->parameter("@update_time").value()) = t; + allExecuted = allExecuted && myAddNetworkLinkUrl->execute(); + } + return allExecuted; +} + +void SaveNetworkLinkRunnable::setNetworkLink(shared_ptr<NetworkLink> link) { + myNetworkLink = link; +} diff --git a/fbreader/src/database/sqldb/DBCommand.cpp b/fbreader/src/database/sqldb/DBCommand.cpp new file mode 100644 index 0000000..8986401 --- /dev/null +++ b/fbreader/src/database/sqldb/DBCommand.cpp @@ -0,0 +1,59 @@ +/* + * 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 "DBCommand.h" +#include <algorithm> + +DBCommand::DBCommand(const std::string &command, DBConnection &connection) + : myParameters() + , myCommandString(command) + , myConnection(connection) { +} + +DBCommand::~DBCommand() { +} + + +class ParameterPredicate { + +public: + ParameterPredicate(const std::string &name); + bool operator () (const DBCommandParameter &p); +private: + const std::string &myName; +}; + +ParameterPredicate::ParameterPredicate(const std::string &name) : myName(name) {} + +bool ParameterPredicate::operator () (const DBCommandParameter &p) { + return p.name() == myName; +} + + +DBCommandParameter &DBCommand::parameter(const std::string &name) { + std::vector<DBCommandParameter>::iterator it = std::find_if(myParameters.begin(), myParameters.end(), ParameterPredicate(name)); + return *it; +} + +const DBCommandParameter &DBCommand::parameters(const std::string &name) const { + std::vector<DBCommandParameter>::const_iterator it = std::find_if(myParameters.begin(), myParameters.end(), ParameterPredicate(name)); + return *it; +} + diff --git a/fbreader/src/database/sqldb/DBCommand.h b/fbreader/src/database/sqldb/DBCommand.h new file mode 100644 index 0000000..2ac9ade --- /dev/null +++ b/fbreader/src/database/sqldb/DBCommand.h @@ -0,0 +1,69 @@ +/* + * 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 __DBCOMMAND_H__ +#define __DBCOMMAND_H__ + +#include "DBCommandParameter.h" +#include "DBDataReader.h" +#include "DBConnection.h" + +class DBCommand { + +public: + DBCommand(const std::string &command, DBConnection &connection); + virtual ~DBCommand(); + + std::vector<DBCommandParameter> ¶meters(); + const std::vector<DBCommandParameter> ¶meters() const; + + DBCommandParameter ¶meter(const std::string &name); + const DBCommandParameter ¶meters(const std::string &name) const; + + const std::string &commandString() const; + +protected: + const DBConnection &connection() const; + +public: // to implement: + virtual bool execute() = 0; + virtual shared_ptr<DBValue> executeScalar() = 0; + virtual shared_ptr<DBDataReader> executeReader() = 0; + +private: // against copying: + DBCommand(const DBCommand &); + const DBCommand &operator = (const DBCommand &); + +private: + std::vector<DBCommandParameter> myParameters; + const std::string myCommandString; + const DBConnection &myConnection; +}; + + +inline std::vector<DBCommandParameter> &DBCommand::parameters() { return myParameters; } +inline const std::vector<DBCommandParameter> &DBCommand::parameters() const { return myParameters; } + +inline const std::string &DBCommand::commandString() const { return myCommandString; } +inline const DBConnection &DBCommand::connection() const { return myConnection; } + + +#endif /* __DBCOMMAND_H__ */ + diff --git a/fbreader/src/database/sqldb/DBCommandParameter.cpp b/fbreader/src/database/sqldb/DBCommandParameter.cpp new file mode 100644 index 0000000..d8ec08a --- /dev/null +++ b/fbreader/src/database/sqldb/DBCommandParameter.cpp @@ -0,0 +1,63 @@ +/* + * 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 "DBCommandParameter.h" + + +DBCommandParameter::DBCommandParameter() + : myName(""), myValue(DBValue::create(DBValue::DBNULL)) { +} + +DBCommandParameter::DBCommandParameter(const std::string &name) + : myName(name), myValue(DBValue::create(DBValue::DBNULL)) { +} + +DBCommandParameter::DBCommandParameter(DBValue::ValueType type) + : myName(""), myValue(DBValue::create(type)) { +} + +DBCommandParameter::DBCommandParameter(const std::string &name, DBValue::ValueType type) + : myName(name), myValue(DBValue::create(type)) { +} + +DBCommandParameter::DBCommandParameter(shared_ptr<DBValue> value) + : myName(""), myValue(value) { + if (value.isNull()) { + myValue = DBValue::create(DBValue::DBNULL); + } +} + +DBCommandParameter::DBCommandParameter(const std::string &name, shared_ptr<DBValue> value) + : myName(name), myValue(value) { + if (value.isNull()) { + myValue = DBValue::create(DBValue::DBNULL); + } +} + +DBCommandParameter::DBCommandParameter(const DBCommandParameter ¶meter) + : myName(parameter.name()), myValue(parameter.value()) { +} + +const DBCommandParameter &DBCommandParameter::operator = (const DBCommandParameter ¶meter) { + myName = parameter.name(); + myValue = parameter.value(); + return *this; +} + diff --git a/fbreader/src/database/sqldb/DBCommandParameter.h b/fbreader/src/database/sqldb/DBCommandParameter.h new file mode 100644 index 0000000..2e3c8ae --- /dev/null +++ b/fbreader/src/database/sqldb/DBCommandParameter.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 __DBCOMMANDPARAMETERS_H__ +#define __DBCOMMANDPARAMETERS_H__ + +#include <vector> + +#include "DBValues.h" + + +class DBCommandParameter { + +public: + // create anonymous parameter with DBNULL value: + DBCommandParameter(); + + // create named parameter with DBNULL value: + DBCommandParameter(const std::string &name); + + // create anonymous parameter with default value of specified type: + DBCommandParameter(DBValue::ValueType type); + + // create named parameter with default value of specified type: + DBCommandParameter(const std::string &name, DBValue::ValueType type); + + // create anonymous parameter with specified value: + DBCommandParameter(shared_ptr<DBValue> value); + + // create named parameter with specified value: + DBCommandParameter(const std::string &name, shared_ptr<DBValue> value); + +public: + const std::string &name() const; + void setName(const std::string &name); + + shared_ptr<DBValue> value() const; + void setValue(shared_ptr<DBValue> value); + + DBValue::ValueType type() const; + + bool hasName() const; + +public: // implement copying: + DBCommandParameter(const DBCommandParameter &par); + const DBCommandParameter &operator = (const DBCommandParameter &par); + +private: + std::string myName; + DBValue::ValueType myType; + shared_ptr<DBValue> myValue; +}; + + +inline const std::string &DBCommandParameter::name() const { return myName; } +inline void DBCommandParameter::setName(const std::string &name) { myName = name; } +inline shared_ptr<DBValue> DBCommandParameter::value() const { return myValue; } +inline void DBCommandParameter::setValue(shared_ptr<DBValue> value) { myValue = value; } +inline DBValue::ValueType DBCommandParameter::type() const { return myValue->type(); } +inline bool DBCommandParameter::hasName() const { return myName != ""; } + + +#endif /* __DBCOMMANDPARAMETERS_H__ */ + diff --git a/fbreader/src/database/sqldb/DBConnection.cpp b/fbreader/src/database/sqldb/DBConnection.cpp new file mode 100644 index 0000000..20f4402 --- /dev/null +++ b/fbreader/src/database/sqldb/DBConnection.cpp @@ -0,0 +1,28 @@ +/* + * 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 "DBConnection.h" + +DBConnection::DBConnection() { +} + +DBConnection::~DBConnection() { +} + diff --git a/fbreader/src/database/sqldb/DBConnection.h b/fbreader/src/database/sqldb/DBConnection.h new file mode 100644 index 0000000..2345ddf --- /dev/null +++ b/fbreader/src/database/sqldb/DBConnection.h @@ -0,0 +1,40 @@ +/* + * 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 __DBCONNECTION_H__ +#define __DBCONNECTION_H__ + +class DBConnection { +public: + DBConnection(); + virtual ~DBConnection(); + +public: // to implement: + virtual bool open() = 0; + virtual bool close() = 0; + virtual bool isOpened() const = 0; + +private: // against copying: + DBConnection(const DBConnection &); + const DBConnection &operator = (const DBConnection &); +}; + +#endif /* __DBCONNECTION_H__ */ + diff --git a/fbreader/src/database/sqldb/DBDataReader.cpp b/fbreader/src/database/sqldb/DBDataReader.cpp new file mode 100644 index 0000000..7c40b03 --- /dev/null +++ b/fbreader/src/database/sqldb/DBDataReader.cpp @@ -0,0 +1,26 @@ +/* + * 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 "DBDataReader.h" + +DBDataReader::DBDataReader() { +} + +DBDataReader::~DBDataReader() { +} diff --git a/fbreader/src/database/sqldb/DBDataReader.h b/fbreader/src/database/sqldb/DBDataReader.h new file mode 100644 index 0000000..f07b323 --- /dev/null +++ b/fbreader/src/database/sqldb/DBDataReader.h @@ -0,0 +1,58 @@ +/* + * 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 __DBDATAREADER_H__ +#define __DBDATAREADER_H__ + +#include "DBValues.h" + +class DBDataReader { + +public: + DBDataReader(); + virtual ~DBDataReader(); + +public: // to implement: + virtual bool next() = 0; + virtual bool reset() = 0; + virtual void close() = 0; + + virtual std::size_t columnsNumber() const = 0; + + virtual DBValue::ValueType type(std::size_t column) const = 0; + virtual shared_ptr<DBValue> value(std::size_t column) const = 0; + + virtual int intValue(std::size_t column) const = 0; + virtual double realValue(std::size_t column) const = 0; + virtual std::string textValue(std::size_t column, const std::string &defaultValue) const = 0; + +public: + bool isDBNull(std::size_t column) const; + bool isInt(std::size_t column) const; + bool isReal(std::size_t column) const; + bool isText(std::size_t column) const; +}; + +inline bool DBDataReader::isDBNull(std::size_t column) const { return type(column) == DBValue::DBNULL; } +inline bool DBDataReader::isInt(std::size_t column) const { return type(column) == DBValue::DBINT; } +inline bool DBDataReader::isReal(std::size_t column) const { return type(column) == DBValue::DBREAL; } +inline bool DBDataReader::isText(std::size_t column) const { return type(column) == DBValue::DBTEXT; } + +#endif /* __DBDATAREADER_H__ */ + diff --git a/fbreader/src/database/sqldb/DBIntValue.cpp b/fbreader/src/database/sqldb/DBIntValue.cpp new file mode 100644 index 0000000..cd3e900 --- /dev/null +++ b/fbreader/src/database/sqldb/DBIntValue.cpp @@ -0,0 +1,37 @@ +/* + * 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 "DBValues.h" + + +DBIntValue::DBIntValue() + : myValue(0) { +} + +DBIntValue::DBIntValue(int value) + : myValue(value) { +} + +DBIntValue::~DBIntValue() { +} + +DBValue::ValueType DBIntValue::type() const { + return DBINT; +} + diff --git a/fbreader/src/database/sqldb/DBNullValue.cpp b/fbreader/src/database/sqldb/DBNullValue.cpp new file mode 100644 index 0000000..cd6ab1c --- /dev/null +++ b/fbreader/src/database/sqldb/DBNullValue.cpp @@ -0,0 +1,34 @@ +/* + * 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 "DBValues.h" + +const shared_ptr<DBValue> DBNullValue::Instance = new DBNullValue(); + + +DBNullValue::DBNullValue() { +} + +DBNullValue::~DBNullValue() { +} + +DBValue::ValueType DBNullValue::type() const { + return DBNULL; +} + diff --git a/fbreader/src/database/sqldb/DBRealValue.cpp b/fbreader/src/database/sqldb/DBRealValue.cpp new file mode 100644 index 0000000..eb849e5 --- /dev/null +++ b/fbreader/src/database/sqldb/DBRealValue.cpp @@ -0,0 +1,37 @@ +/* + * 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 "DBValues.h" + + +DBRealValue::DBRealValue() + : myValue(0.0) { +} + +DBRealValue::DBRealValue(double value) + : myValue(value) { +} + +DBRealValue::~DBRealValue() { +} + +DBValue::ValueType DBRealValue::type() const { + return DBREAL; +} + diff --git a/fbreader/src/database/sqldb/DBRunnable.h b/fbreader/src/database/sqldb/DBRunnable.h new file mode 100644 index 0000000..8e44a67 --- /dev/null +++ b/fbreader/src/database/sqldb/DBRunnable.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2004-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 __DBRUNNABLE_H__ +#define __DBRUNNABLE_H__ + + +class DBRunnable { + +public: + virtual ~DBRunnable() {} + + virtual bool run() = 0; +}; + +#endif /* __DBRUNNABLE_H__ */ diff --git a/fbreader/src/database/sqldb/DBTextValue.cpp b/fbreader/src/database/sqldb/DBTextValue.cpp new file mode 100644 index 0000000..27b4d96 --- /dev/null +++ b/fbreader/src/database/sqldb/DBTextValue.cpp @@ -0,0 +1,48 @@ +/* + * 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 "DBValues.h" + + +DBTextValue::DBTextValue() + : myValue("") { +} + +DBTextValue::DBTextValue(const std::string &value) + : myValue(value) { +} + +DBTextValue::~DBTextValue() { +} + +DBValue::ValueType DBTextValue::type() const { + return DBTEXT; +} + + +DBTextValue::DBTextValue(const DBTextValue &value) + : DBValue() + , myValue(value.myValue) { +} + +const DBTextValue &DBTextValue::operator = (const DBTextValue &value) { + myValue = value.myValue; + return *this; +} + diff --git a/fbreader/src/database/sqldb/DBValue.cpp b/fbreader/src/database/sqldb/DBValue.cpp new file mode 100644 index 0000000..75c4376 --- /dev/null +++ b/fbreader/src/database/sqldb/DBValue.cpp @@ -0,0 +1,42 @@ +/* + * 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 "DBValues.h" + + +DBValue::DBValue() { +} + +DBValue::~DBValue() { +} + +shared_ptr<DBValue> DBValue::create(ValueType type) { + switch (type) { + case DBNULL: + return DBNullValue::Instance; + case DBINT: + return new DBIntValue(); + case DBREAL: + return new DBRealValue(); + case DBTEXT: + return new DBTextValue(); + } + return 0; +} + diff --git a/fbreader/src/database/sqldb/DBValues.h b/fbreader/src/database/sqldb/DBValues.h new file mode 100644 index 0000000..eb64d56 --- /dev/null +++ b/fbreader/src/database/sqldb/DBValues.h @@ -0,0 +1,145 @@ +/* + * 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 __DBVALUES_H__ +#define __DBVALUES_H__ + +#include <string> +#include <shared_ptr.h> + + +class DBValue { + +public: + enum ValueType { + DBNULL, + DBINT, + DBREAL, + DBTEXT, + }; + + static shared_ptr<DBValue> create(ValueType type); + +public: + DBValue(); + virtual ~DBValue(); + +public: // to implement: + virtual ValueType type() const = 0; +}; + +class DBNullValue : public DBValue { + +friend class DBValue; + +public: + static const shared_ptr<DBValue> Instance; // the only Instance of DBNullValue class + +private: + DBNullValue(); + ~DBNullValue(); + +public: + ValueType type() const; +}; + +class DBIntValue : public DBValue { + +friend class DBValue; + +protected: + DBIntValue(); + +public: + DBIntValue(int value); + ~DBIntValue(); + + ValueType type() const; + + int value() const; + void setValue(int value); + const DBIntValue &operator = (int value); + +private: + int myValue; +}; + +class DBRealValue : public DBValue { + +friend class DBValue; + +protected: + DBRealValue(); + +public: + DBRealValue(double value); + ~DBRealValue(); + + ValueType type() const; + + double value() const; + void setValue(double value); + const DBRealValue &operator = (double value); + +private: + double myValue; +}; + +class DBTextValue : public DBValue { + +friend class DBValue; + +protected: + DBTextValue(); + +public: + DBTextValue(const std::string &value); + ~DBTextValue(); + + ValueType type() const; + + const std::string &value() const; + void setValue(const std::string &value); + const DBTextValue &operator = (const std::string &value); + +public: + DBTextValue(const DBTextValue &value); + const DBTextValue &operator = (const DBTextValue &value); + +private: + std::string myValue; +}; + + + +inline int DBIntValue::value() const { return myValue; } +inline void DBIntValue::setValue(int value) { myValue = value; } +inline const DBIntValue &DBIntValue::operator = (int value) { myValue = value; return *this; } + +inline double DBRealValue::value() const { return myValue; } +inline void DBRealValue::setValue(double value) { myValue = value; } +inline const DBRealValue &DBRealValue::operator = (double value) { myValue = value; return *this; } + +inline const std::string &DBTextValue::value() const { return myValue; } +inline void DBTextValue::setValue(const std::string &value) { myValue = value; } +inline const DBTextValue &DBTextValue::operator = (const std::string &value) { myValue = value; return *this; } + +#endif /* __DBVALUES_H__ */ + diff --git a/fbreader/src/database/sqldb/DataBase.cpp b/fbreader/src/database/sqldb/DataBase.cpp new file mode 100644 index 0000000..e1d0b3f --- /dev/null +++ b/fbreader/src/database/sqldb/DataBase.cpp @@ -0,0 +1,31 @@ +/* + * 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 <ZLibrary.h> + +#include "DataBase.h" + +std::string DataBase::databaseDirName() { + return ZLibrary::ApplicationWritableDirectory(); +} + +DataBase::~DataBase() { +} + + diff --git a/fbreader/src/database/sqldb/DataBase.h b/fbreader/src/database/sqldb/DataBase.h new file mode 100644 index 0000000..33430aa --- /dev/null +++ b/fbreader/src/database/sqldb/DataBase.h @@ -0,0 +1,55 @@ +/* + * 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 __DATABASE_H__ +#define __DATABASE_H__ + +#include <shared_ptr.h> + +#include "DBConnection.h" +#include "DBRunnable.h" + +class DataBase { + +public: + static std::string databaseDirName(); + +public: + DataBase(shared_ptr<DBConnection> connection); + virtual ~DataBase(); + + DBConnection &connection() const; + +protected: + virtual bool executeAsTransaction(DBRunnable &runnable) = 0; + +private: + shared_ptr<DBConnection> myConnection; + +private: // against copying: + DataBase(const DataBase &); + const DataBase &operator = (const DataBase &); +}; + +inline DataBase::DataBase(shared_ptr<DBConnection> connection) : myConnection(connection) { } + +inline DBConnection &DataBase::connection() const { return *myConnection; } + +#endif /* __DATABASE_H__ */ 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__ */ |