OSDN Git Service

libsqlitexxの実装完了に伴い、libsqlitexxの昨日をフルに使った実装に変更し、ソースコードの大幅な圧縮を図った
authorcaprice <caprice@users.sourceforge.jp>
Sun, 20 Apr 2014 13:37:53 +0000 (22:37 +0900)
committercaprice <caprice@users.sourceforge.jp>
Sun, 20 Apr 2014 13:37:53 +0000 (22:37 +0900)
include/database.hpp

index 161cd5a..d359b97 100644 (file)
 
 #include <memory>
 
-#include <sqlite3.h>
-
-#include <boost/system/system_error.hpp>
 #include <boost/filesystem.hpp>
-#include <boost/fusion/include/vector.hpp>
 
 #include "GikoMona.hpp"
-#include "query.hpp"
 
 namespace monazilla { namespace GikoMona { namespace core {
 
-class database;
-
-template <typename ReturnTypeList, typename ArgTypeList>
-class sql_executer final {
-    friend database;
-    
-    typedef ReturnTypeList result_type;
-    typedef ArgTypeList arg_type;
-    typedef ::sqlite3 *db_object_type;
-    typedef ::sqlite3_stmt *sql_stmt_type;
-
-    const ::sqlite3_stmt *stmt;
-        
-    sql_executer(db_object_type db,
-                 const sql_stmt_type stmt,
-                 boost::system::error_code& ec) noexcept {}
-    ~sql_executer() {}
-        
+class database final {
 public:
-    typename <typename T>
-    void bind(const mona_string& param_name, const T& val) {}
-    result_type operator()() {}
-};
-
-class database final : public query {
-public:
-    typedef ::sqlite3 *db_object_type;
     typedef database self_type;
-    typedef query base_type;
 
-    database() : database("") {}
+    database() : database("", boost::system::error_code()) {}
     
     /// @brief すでに存在するデータベースファイルを開く。まだファイルが存在しない場合は、新たに作成する。
-    database(const boost::filesystem::path& db_path) {
-        if(db_path.empty()) {
-            is_opened_db = false;
-        } else {
-            if(!boost::filesystem::exists(db_path)) {
-                create(db_path);
-            } else {
-                open(db_path);
-            }
-        }
-    }
+    database(const boost::filesystem::path& db_path,
+             boost::system::error_code& ec) : db(db_path.c_str(), ec) {}
     
     database(const self_type& other) = delete;
     
-    ~database() { close(); }
-    
-    /// @brief 受け取った SQL を実行する。ただし、実行できる文は引数と返り値が共に無いものに限られる。
-    /**
-     * @return SQL が正常に実行された場合は true、それ以外の場合は false を返す。
-     * @note この関数は SQL の実行結果を返さない。したがって、実行結果が必要な場合は、
-     *       compile_sql() を用いるべきである。
-     */
-    bool run_sql(const mona_string& sql) {
-        return (::sqlite3_exec(db, sql.c_str(), NULL, NULL, NULL) != SQLITE_OK);
-    }
-    
-    /// @brief 受け取った SQL を sql_executer へと変換して返す。
-    /**
-     * @note 返された sql_executer を実行することで、ここで渡した SQL の実行結果を得ることができる。
-     *       実行した SQL の実行結果が不要である (あるいはそもそも実行結果が無い) 場合は、
-     *       run_sql() を用いるべきである。
-     */
-    template <typename ...T>
-    sql_executer<T...> compile_sql(const mona_string& sql) {
-        /**
-         *  @note sqlite3_prepare(db,zSql,nByte,ppStmtpzTail) で nByte に "sql.length() + 1" を
-         *        渡すのはなぜか?詳しくは次を参照 : http://www.sqlite.org/c3ref/prepare.html
-         *        ページ中程、"If the nByte argument is less than zero, ~" の先、関係あるところを
-         *        かいつまんで訳すと「もしも関数を呼び出した側が、zSql が NULL-terminated な文字列
-         *        (\0、\u0 が終端であるような文字列) であることを知っている場合、nByte に文字列のバイト長
-         *        (ただしここで言うバイト長には終端文字である\0または\u0も「含んだ」ものである) を渡すことで、
-         *        若干パフォーマンスが上がる」という記述がある。C++のstd::string::length()/size()は文字列の
-         *        終端文字を除いた長さを返すので、わざわざ1を加えている。
-         */
-        int result = ::sqlite3_prepare_v2(db.get_sqlite3_obj(),
-                                          sql.c_str(),
-                                          sql.length() + 1,
-                                          &stmt,
-                                          NULL);
-        if (result != ::SQLITE_OK && !stmt) {
-            
-        } else {
-            return sql_executer<T...>(sql);
-        }
-    }
-    
-    /**
-     *  @brief
-     *  @retval true insert 操作が成功した
-     *          false insert 操作に失敗した
-     *  @param[in] into どのテーブルのどの要素に対し insertion query を実行するかを記述する。
-     *                  記述の仕方は次の通り:(テーブル名)/[(サブテーブル名)/]*(要素名)
-     *  @param[in] value テーブルに対して代入する値を記述する。
-     *  @note さらに、最大限 multi-threading な環境を考慮しなければならない。
-     */
-    template <typename T, typename U, typename ...ValueType>
-    bool insert(const mona_string& into,
-                const boost::fusion::vector<T, U, ValueType...>& value) {}
-    
-    template <typename T>
-    bool insert(const mona_string& into,
-                const boost::fusion::vector<T>& value) {}
-    
-    template <typename T>
-    bool insert(const mona_string& into,
-                const boost::any& value,
-                base_type::enable_if_T_is_U<T, boost::any>*& = enabler) {}
+    ~database() { db.close(); }
     
-    /**
-     *  @brief query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
-     *  @return 引数で指定したテーブルの要素から、テンプレートで指定した方に変換された値が返される。
-     */
-    template <typename T>
-    T select(const mona_string& column,
-             const mona_string& from) const noexcept {}
-    
-    template <typename T>
-    boost::any select(const mona_string& column,
-                      const mona_string& from,
-                      base_type::enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept {}
-    
-    template <typename ...ValueType>
-    boost::fusion::vector<ValueType...>
-    select_all(const mona_string& from) const noexcept {}
+    sqlite::connection& get_connection() { return db; }
 
     /// @brief データベースの最適化を行う。
     /**
-     * @note 内部では以下のコマンドが実行され、データベースの不要データの圧縮と再構築が行われる。
+     * @note 内部では以下のコマンドが実行され、データベース中の不要なデータの圧縮と再構築が行われる。
      *       VACUUM; REINDEX;
      */
-    void optimize() {
-        run_sql("VACUUM;");
-        run_sql("REINDEX;");
+    void optimize(boost::system::error_code& ec) noexcept {
+        sqlite::execute_statement<>(db, u8"VACUUM;", ec);
+        sqlite::execute_statement<>(db, u8"REINDEX;", ec);
     }
     
-    /// @brief すでに存在するデータベースファイルを開く。
-    bool open(const boost::filesystem::path& db_path) {
-        if (is_opened_db) {
-            close();
-        } else if (!boost::filesystem::exists(db_path)) {
-            is_opened_db = false;
-            return is_opened_db;
-        }
+    void begin_sql_statement() noexcept {
+        sqlite::execute_statement<>(db, u8"BEGIN;", transaction_ec);
         
-        is_opened_db = (::sqlite3_open(db_path.c_str(), &db) != SQLITE_OK);
-        
-        return is_opened_db;
+        if(transaction_ec) { /* logger */ }
     }
     
-    /// @brief まだ存在しないデータベースファイルを新たに作成する。
-    /**
-     * @retval true ファイルが存在せず、かつ新たにデータベースファイルを作成することに成功した
-     *         false ファイルが存在する、あるいは存在しないが新規データベースファイルの作成に失敗した
-     */
-    bool create(const boost::filesystem::path& db_path) {
-        if(boost::filesystem::exists(db_path)) {
-            return false;
+    void end_sql_statement() noexcept {
+        if(!transaction_ec) {
+            sqlite::execute_statement<>(db, "END;");
+        } else {
+            // logger
         }
-        
-        return open(db_path);
     }
     
-    /// @brief 開いていたデータベースファイルを閉じる。
-    void close() noexcept {
-        ::sqlite3_close(db);
-    }
-
 private:
-    db_object_type db;
-    bool is_opened_db;
-    
-    void begin_sql_statement() { run_sql("BEGIN;"); }
-    void end_sql_statement() { run_sql("END;"); }
+    sqlite::connection db;
+    boost::syatem::error_code transaction_ec;
 };
 
-template <>
-struct is_responsible_to_query<database> : public boost::mpl::true_ {};
+struct sql_transaction final {
+    sql_transaction(database& db_) : db(db_) { db.begin_sql_statement(); }
+    ~sql_transaction() { db.end_sql_statement(); }
+private:
+    database db;
+};
 
 } } }